[
  {
    "path": ".cargo/config.toml",
    "content": "[alias]\nlint = \"clippy --workspace --benches --all-features --no-deps -- -D warnings\"\nlint-fix = \"clippy --fix --allow-dirty --workspace --benches --all-features --no-deps -- -D warnings\"\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: hecrj\nko_fi: hecrj_\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG-REPORT.yml",
    "content": "name: I have a problem with the library\ndescription: File a bug report.\nlabels: [\"bug\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n  - type: checkboxes\n    attributes:\n      label: Is your issue REALLY a bug?\n      description: |\n        This issue tracker is for __BUG REPORTS ONLY__.\n\n        It's obvious, right? This is a bug report form, after all! Still, some crazy users seem to forcefully fill out this form just to ask questions and request features.\n\n        The core team does not appreciate that. Don't do it.\n\n        If you want to ask a question or request a feature, please [go back here](https://github.com/iced-rs/iced/issues/new/choose) and read carefully.\n      options:\n      - label: My issue is indeed a bug!\n        required: true\n      - label: I am not crazy! I will not fill out this form just to ask a question or request a feature. Pinky promise.\n        required: true\n  - type: checkboxes\n    attributes:\n      label: Is there an existing issue for this?\n      description: |\n        Please, search [the existing issues] and see if an issue already exists for the bug you encountered.\n\n        [the existing issues]: https://github.com/iced-rs/iced/issues\n      options:\n      - label: I have searched the existing issues.\n        required: true\n  - type: checkboxes\n    attributes:\n      label: Is this issue related to iced?\n      description: |\n        If your application is crashing during startup or you are observing graphical glitches, there is a chance it may be caused by incompatible hardware or outdated graphics drivers.\n\n        Before filing an issue...\n\n        - If you are using `wgpu`, you need an environment that supports Vulkan, Metal, or DirectX 12. Please, make sure you can run [the `wgpu` examples].\n\n        If you have any issues running any of the examples, make sure your graphics drivers are up-to-date. If the issues persist, please report them to the authors of the libraries directly!\n\n        [the `wgpu` examples]: https://github.com/gfx-rs/wgpu/tree/trunk/examples\n        [the `glow` examples]: https://github.com/grovesNL/glow/tree/main/examples\n      options:\n      - label: My hardware is compatible and my graphics drivers are up-to-date.\n        required: true\n  - type: textarea\n    attributes:\n      label: What happened?\n      id: what-happened\n      description: |\n        What problem are you having? Please, also provide the steps to reproduce it.\n\n        If the issue happens with a particular program, please share an [SSCCE].\n\n        [SSCCE]: http://sscce.org/\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: What is the expected behavior?\n      id: what-expected\n      description: What were you expecting to happen?\n    validations:\n      required: true\n  - type: dropdown\n    id: version\n    attributes:\n      label: Version\n      description: |\n        We only offer support for the latest release on crates.io and the `master` branch on this repository. Which version are you using? Please make sure you are using the latest patch available (e.g. run `cargo update`).\n\n        If you are using an older release, please upgrade to the latest one before filing an issue.\n      options:\n        - crates.io release\n        - master\n    validations:\n      required: true\n  - type: dropdown\n    id: os\n    attributes:\n      label: Operating System\n      description: Which operating system are you using?\n      options:\n        - Windows\n        - macOS\n        - Linux\n    validations:\n      required: true\n  - type: textarea\n    id: logs\n    attributes:\n      label: Do you have any log output?\n      description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.\n      render: shell\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: I have a question\n    url: https://iced.zulipchat.com/#narrow/channel/213445-questions\n    about: Ask and learn from others in the Zulip forum.\n  - name: I want to request a feature or start a discussion\n    url: https://iced.zulipchat.com/#narrow/channel/213316-discussions\n    about: Share your idea and gather feedback in the Zulip forum.\n  - name: I want to chat with other users of the library\n    url: https://discord.com/invite/3xZJ65GAhd\n    about: Join the Discord server and get involved with the community!\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "The core team is busy and does not have time to mentor nor babysit new contributors. If a member of the core team thinks that reviewing and understanding your work will take more time and effort than writing it from scratch by themselves, your contribution will be dismissed. It is your responsibility to communicate and figure out how to reduce the likelihood of this!\n\nRead the contributing guidelines for more details: https://github.com/iced-rs/iced/blob/master/CONTRIBUTING.md\n"
  },
  {
    "path": ".github/workflows/audit.yml",
    "content": "name: Audit\non:\n  push: {}\n  pull_request: {}\n  schedule:\n    - cron: '0 0 * * *'\njobs:\n  vulnerabilities:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n    - name: Install cargo-audit\n      run: cargo install cargo-audit\n    - uses: actions/checkout@master\n    - name: Resolve dependencies\n      run: cargo update\n    - name: Audit vulnerabilities\n      run: cargo audit\n\n  # artifacts:\n  #   runs-on: ubuntu-latest\n  #   steps:\n  #   - uses: hecrj/setup-rust-action@v2\n  #   - name: Install cargo-outdated\n  #     run: cargo install cargo-outdated\n  #   - uses: actions/checkout@master\n  #   - name: Delete `web-sys` dependency from `integration` example\n  #     run: sed -i '$d' examples/integration/Cargo.toml\n  #   - name: Find outdated dependencies\n  #     run: cargo outdated --workspace --exit-code 1 --ignore raw-window-handle\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\non:\n  push:\n    branches:\n      - master\njobs:\n  todos_linux:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n    - name: Install cargo-deb\n      run: cargo install cargo-deb\n    - uses: actions/checkout@master\n    - name: Install dependencies\n      run: |\n        export DEBIAN_FRONTED=noninteractive\n        sudo apt-get -qq update\n        sudo apt-get install -y libxkbcommon-dev\n    - name: Build todos binary\n      run: cargo build --verbose --profile release-opt --package todos\n    - name: Archive todos binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: todos-x86_64-unknown-linux-gnu\n        path: target/release-opt/todos\n    - name: Pack todos .deb package\n      run: cargo deb --no-build --profile release-opt --package todos\n    - name: Rename todos .deb package\n      run: mv target/debian/*.deb target/debian/iced_todos-x86_64-debian-linux-gnu.deb\n    - name: Archive todos .deb package\n      uses: actions/upload-artifact@v4\n      with:\n        name: todos-x86_64-debian-linux-gnu\n        path: target/debian/iced_todos-x86_64-debian-linux-gnu.deb\n\n  todos_windows:\n    runs-on: windows-latest\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n    - uses: actions/checkout@master\n    - name: Enable static CRT linkage\n      run: |\n        echo '[target.x86_64-pc-windows-msvc]' >> .cargo/config\n        echo 'rustflags = [\"-Ctarget-feature=+crt-static\"]' >> .cargo/config\n    - name: Run the application without starting the shell\n      run: |\n        sed -i '1 i\\#![windows_subsystem = \\\"windows\\\"]' examples/todos/src/main.rs\n    - name: Build todos binary\n      run: cargo build --verbose --profile release-opt --package todos\n    - name: Archive todos binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: todos-x86_64-pc-windows-msvc\n        path: target/release-opt/todos.exe\n\n  todos_macos:\n    runs-on: macOS-latest\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n    - uses: actions/checkout@master\n    - name: Build todos binary\n      env:\n        MACOSX_DEPLOYMENT_TARGET: 10.14\n      run: cargo build --verbose --profile release-opt --package todos\n    - name: Open binary via double-click\n      run: chmod +x target/release-opt/todos\n    - name: Archive todos binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: todos-x86_64-apple-darwin\n        path: target/release-opt/todos\n\n  todos_raspberry:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n    - uses: actions/checkout@master\n    - name: Install cross\n      run: cargo install cross\n    - name: Build todos binary for Raspberry Pi 3/4 (64 bits)\n      run: cross build --verbose --profile release-opt --package todos --target aarch64-unknown-linux-gnu\n    - name: Archive todos binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: todos-aarch64-unknown-linux-gnu\n        path: target/aarch64-unknown-linux-gnu/release-opt/todos\n    - name: Build todos binary for Raspberry Pi 2/3/4 (32 bits)\n      run: cross build --verbose --profile release-opt --package todos --target armv7-unknown-linux-gnueabihf\n    - name: Archive todos binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: todos-armv7-unknown-linux-gnueabihf\n        path: target/armv7-unknown-linux-gnueabihf/release-opt/todos\n"
  },
  {
    "path": ".github/workflows/check.yml",
    "content": "name: Check\non: [push, pull_request]\njobs:\n  wasm:\n    runs-on: ubuntu-latest\n    env:\n      RUSTFLAGS: --cfg=web_sys_unstable_apis\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n      with:\n        rust-version: stable\n        targets: wasm32-unknown-unknown\n    - uses: actions/checkout@master\n    - name: Run checks\n      run: cargo check --package iced --target wasm32-unknown-unknown\n    - name: Check compilation of `tour` example\n      run: cargo build --package tour --target wasm32-unknown-unknown\n    - name: Check compilation of `todos` example\n      run: cargo build --package todos --target wasm32-unknown-unknown\n\n  widget:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n    - uses: actions/checkout@master\n    - name: Check standalone `iced_widget` crate\n      run: cargo check --package iced_widget --features image,svg,canvas\n"
  },
  {
    "path": ".github/workflows/document.yml",
    "content": "name: Document\non: [push, pull_request]\njobs:\n  all:\n    runs-on: ubuntu-latest\n    concurrency:\n      group: ${{ github.workflow }}-${{ github.ref }}\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n      with:\n        rust-version: nightly-2026-02-20\n    - uses: actions/checkout@v2\n    - name: Generate documentation\n      run: |\n        RUSTDOCFLAGS=\"--cfg docsrs\" \\\n          cargo doc --no-deps --all-features \\\n          -p futures-core \\\n          -p iced_beacon \\\n          -p iced_core \\\n          -p iced_debug \\\n          -p iced_devtools \\\n          -p iced_futures \\\n          -p iced_graphics \\\n          -p iced_highlighter \\\n          -p iced_renderer \\\n          -p iced_runtime \\\n          -p iced_tiny_skia \\\n          -p iced_wgpu \\\n          -p iced_widget \\\n          -p iced_winit \\\n          -p iced_test \\\n          -p iced\n    - name: Write CNAME file\n      run: echo 'docs.iced.rs' > ./target/doc/CNAME\n    - name: Copy redirect file as index.html\n      run: cp docs/redirect.html target/doc/index.html\n    - name: Publish documentation\n      if: github.ref == 'refs/heads/master'\n      uses: peaceiris/actions-gh-pages@v3\n      with:\n        deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}\n        external_repository: iced-rs/docs\n        publish_dir: ./target/doc\n"
  },
  {
    "path": ".github/workflows/format.yml",
    "content": "name: Format\non: [push, pull_request]\njobs:\n  all:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n      with:\n        components: rustfmt\n    - uses: actions/checkout@master\n    - name: Check format\n      run: cargo fmt --all -- --check --verbose\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Lint\non: [push, pull_request]\njobs:\n  all:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n      with:\n        components: clippy\n    - uses: actions/checkout@master\n    - name: Install dependencies\n      run: |\n        export DEBIAN_FRONTED=noninteractive\n        sudo apt-get -qq update\n        sudo apt-get install -y libxkbcommon-dev libgtk-3-dev\n    - name: Check lints\n      run: cargo lint\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\non: [push, pull_request]\njobs:\n  all:\n    runs-on: ${{ matrix.os }}\n    env:\n      RUSTFLAGS: --deny warnings\n      ICED_TEST_BACKEND: tiny-skia\n    strategy:\n      matrix:\n        os: [ubuntu-latest, windows-latest, macOS-latest]\n        rust: [stable, beta, \"1.92\"]\n    steps:\n    - uses: hecrj/setup-rust-action@v2\n      with:\n        rust-version: ${{ matrix.rust }}\n    - uses: actions/checkout@master\n    - name: Install dependencies\n      if: matrix.os == 'ubuntu-latest'\n      run: |\n        export DEBIAN_FRONTED=noninteractive\n        sudo apt-get -qq update\n        sudo apt-get install -y libxkbcommon-dev libgtk-3-dev\n    - name: Run tests\n      run: |\n        cargo test --verbose --workspace\n        cargo test --verbose --workspace -- --ignored\n        cargo test --verbose --workspace --all-features\n"
  },
  {
    "path": ".gitignore",
    "content": "target/\npkg/\n**/*.rs.bk\ndist/\ntraces/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n\n## [0.14.0] - 2025-12-07\n### Added\n- Reactive rendering. [#2662](https://github.com/iced-rs/iced/pull/2662)\n- Time travel debugging. [#2910](https://github.com/iced-rs/iced/pull/2910)\n- `Animation` API for application code. [#2757](https://github.com/iced-rs/iced/pull/2757)\n- Headless mode testing. [#2698](https://github.com/iced-rs/iced/pull/2698)\n- First-class end-to-end testing. [#3059](https://github.com/iced-rs/iced/pull/3059)\n- Input method support. [#2777](https://github.com/iced-rs/iced/pull/2777)\n- Hot reloading. [#3000](https://github.com/iced-rs/iced/pull/3000)\n- Concurrent image decoding and uploading (and more cool stuff). [#3092](https://github.com/iced-rs/iced/pull/3092)\n- `comet` debugger and `devtools` foundations. [#2879](https://github.com/iced-rs/iced/pull/2879)\n- Presentation metrics for `comet`. [#2881](https://github.com/iced-rs/iced/pull/2881)\n- Custom performance metrics for `comet`. [#2891](https://github.com/iced-rs/iced/pull/2891)\n- Smart scrollbars. [#2922](https://github.com/iced-rs/iced/pull/2922)\n- System theme reactions. [#3051](https://github.com/iced-rs/iced/pull/3051)\n- `table` widget. [#3018](https://github.com/iced-rs/iced/pull/3018)\n- `grid` widget. [#2885](https://github.com/iced-rs/iced/pull/2885)\n- `sensor` widget. [#2751](https://github.com/iced-rs/iced/pull/2751)\n- `float` widget and other cool stuff. [#2916](https://github.com/iced-rs/iced/pull/2916)\n- `pin` widget. [#2673](https://github.com/iced-rs/iced/pull/2673)\n- `wrap` method for `column` widget. [#2884](https://github.com/iced-rs/iced/pull/2884)\n- `auto_scroll` support for `scrollable` widget. [#2973](https://github.com/iced-rs/iced/pull/2973)\n- `delay` support for `tooltip` widget. [#2960](https://github.com/iced-rs/iced/pull/2960)\n- `Auto` strategy to `text::Shaping`. [#3048](https://github.com/iced-rs/iced/pull/3048)\n- Incremental `markdown` parsing. [#2776](https://github.com/iced-rs/iced/pull/2776)\n- Customizable markdown rendering and image support. [#2786](https://github.com/iced-rs/iced/pull/2786)\n- Quote support for `markdown` widget. [#3005](https://github.com/iced-rs/iced/pull/3005)\n- Tasklist support for `markdown` widget. [#3022](https://github.com/iced-rs/iced/pull/3022)\n- `crisp` feature for default quad snapping. [#2969](https://github.com/iced-rs/iced/pull/2969)\n- Basic layer merging for `graphics::layer::Stack`. [#3033](https://github.com/iced-rs/iced/pull/3033)\n- Headless mode for `iced_wgpu` and concurrency foundations. [#2857](https://github.com/iced-rs/iced/pull/2857)\n- Primitive culling in `column` and `row` widgets. [#2611](https://github.com/iced-rs/iced/pull/2611)\n- Lazy `Compositor` initialization in `winit` shell. [#2722](https://github.com/iced-rs/iced/pull/2722)\n- Support for `Justified` text alignment. [#2836](https://github.com/iced-rs/iced/pull/2836)\n- Support for double click event to `mouse_area`. [#2602](https://github.com/iced-rs/iced/pull/2602)\n- `Default` implementation for `iced_wgpu::geometry::Cache`. [#2619](https://github.com/iced-rs/iced/pull/2619)\n- `physical_key` field to `KeyReleased` event. [#2608](https://github.com/iced-rs/iced/pull/2608)\n- `total_size` method for `qr_code` widget. [#2606](https://github.com/iced-rs/iced/pull/2606)\n- `PartialEq` implementations for widget styles. [#2637](https://github.com/iced-rs/iced/pull/2637)\n- `Send` marker to `iced_wgpu::Renderer` by using `Arc` in caches. [#2692](https://github.com/iced-rs/iced/pull/2692)\n- Disabled `Status` for `scrollbar` widget. [#2585](https://github.com/iced-rs/iced/pull/2585)\n- `warning` color to `theme::Palette`. [#2607](https://github.com/iced-rs/iced/pull/2607)\n- `maximized` and `fullscreen` fields to `window::Settings`. [#2627](https://github.com/iced-rs/iced/pull/2627)\n- `window` tasks for controlling sizes and resize increments. [#2633](https://github.com/iced-rs/iced/pull/2633)\n- `window` task for drag resizing. [#2642](https://github.com/iced-rs/iced/pull/2642)\n- Helper functions for alignment to `widget` module. [#2746](https://github.com/iced-rs/iced/pull/2746)\n- `time::repeat` subscription. [#2747](https://github.com/iced-rs/iced/pull/2747)\n- Vertical support for `progress_bar`. [#2748](https://github.com/iced-rs/iced/pull/2748)\n- `scale` support for `image` widget. [#2755](https://github.com/iced-rs/iced/pull/2755)\n- `LineEnding` support for `text_editor`. [#2759](https://github.com/iced-rs/iced/pull/2759)\n- `Mul<Transformation>` implementation for `mouse::Cursor` and `mouse::Click`. [#2758](https://github.com/iced-rs/iced/pull/2758)\n- `animation` module support for Wasm target. [#2764](https://github.com/iced-rs/iced/pull/2764)\n- Flake for a dev shell in `DEPENDENCIES`. [#2769](https://github.com/iced-rs/iced/pull/2769)\n- `unfocus` widget operation. [#2804](https://github.com/iced-rs/iced/pull/2804)\n- `sipper` support and some QoL. [#2805](https://github.com/iced-rs/iced/pull/2805)\n- Variable text size for preedit IME window. [#2790](https://github.com/iced-rs/iced/pull/2790)\n- `is_focused` widget operation. [#2812](https://github.com/iced-rs/iced/pull/2812)\n- Notification of `window` pre-presentation to windowing system. [#2849](https://github.com/iced-rs/iced/pull/2849)\n- Customizable vertical `spacing` for wrapped rows. [#2852](https://github.com/iced-rs/iced/pull/2852)\n- Indent and unindent actions for `text_editor`. [#2901](https://github.com/iced-rs/iced/pull/2901)\n- Floating Images. [#2903](https://github.com/iced-rs/iced/pull/2903)\n- `min_size` method to `PaneGrid`. [#2911](https://github.com/iced-rs/iced/pull/2911)\n- Generic key for `sensor` widget. [#2944](https://github.com/iced-rs/iced/pull/2944)\n- `Debug` implementation for `Task`. [#2955](https://github.com/iced-rs/iced/pull/2955)\n- `draw_with_bounds` method to `canvas::Cache`. [#3035](https://github.com/iced-rs/iced/pull/3035)\n- Synchronous `Task` Execution and `RedrawRequested` Consistency. [#3084](https://github.com/iced-rs/iced/pull/3084)\n- `id` method to `text_editor`. [#2653](https://github.com/iced-rs/iced/pull/2653)\n- `horizontal` and `vertical` methods to `Padding`. [#2655](https://github.com/iced-rs/iced/pull/2655)\n- `is_focused` selector and `find` / `find_all` operations. [#2664](https://github.com/iced-rs/iced/pull/2664)\n- `push` and `into_options` methods to `combo_box::State`. [#2684](https://github.com/iced-rs/iced/pull/2684)\n- `Hidden` variant to `mouse::Interaction`. [#2685](https://github.com/iced-rs/iced/pull/2685)\n- `menu_height` method to `pick_list` and `combo_box` widgets. [#2699](https://github.com/iced-rs/iced/pull/2699)\n- `text_color` to `toggler::Style`. [#2707](https://github.com/iced-rs/iced/pull/2707)\n- `text_shaping` method to `combo_box` widget. [#2714](https://github.com/iced-rs/iced/pull/2714)\n- `transparent` field for `window::Settings`. [#2728](https://github.com/iced-rs/iced/pull/2728)\n- `closeable` and `minimizable` fields to `window::Settings`. [#2735](https://github.com/iced-rs/iced/pull/2735)\n- `window::monitor_size` task. [#2754](https://github.com/iced-rs/iced/pull/2754)\n- Division operation for `Size` and `Vector`. [#2767](https://github.com/iced-rs/iced/pull/2767)\n- `hidden` method to `scrollable` widget. [#2775](https://github.com/iced-rs/iced/pull/2775)\n- Support for macOS-specific key shortcuts with `Control` modifier. [#2801](https://github.com/iced-rs/iced/pull/2801)\n- Additional variants to `mouse::Interaction`. [#2815](https://github.com/iced-rs/iced/pull/2815)\n- `vsync` field to `window::Settings`. [#2837](https://github.com/iced-rs/iced/pull/2837)\n- `wgpu-bare` feature flag to disable default `wgpu` features. [#2828](https://github.com/iced-rs/iced/pull/2828)\n- `ratio` method for `Size`. [#2861](https://github.com/iced-rs/iced/pull/2861)\n- Support for `⌘ + Backspace` and `⌘ + Delete` macOS shortcuts. [#2862](https://github.com/iced-rs/iced/pull/2862)\n- Expandable selection-by-word after double click in text editors. [#2865](https://github.com/iced-rs/iced/pull/2865)\n- `x11` and `wayland` feature flags. [#2869](https://github.com/iced-rs/iced/pull/2869)\n- `label` method for `checkbox` widget. [#2873](https://github.com/iced-rs/iced/pull/2873)\n- `shader::Pipeline` trait for easier `wgpu` resource management. [#2876](https://github.com/iced-rs/iced/pull/2876)\n- `select_range` widget operation. [#2890](https://github.com/iced-rs/iced/pull/2890)\n- `grid!` macro helper. [#2904](https://github.com/iced-rs/iced/pull/2904)\n- `warning` style for `container` widget. [#2912](https://github.com/iced-rs/iced/pull/2912)\n- Current toggle state to `toggler::Status::Disabled`. [#2908](https://github.com/iced-rs/iced/pull/2908)\n- Cursor size awareness for input methods. [#2918](https://github.com/iced-rs/iced/pull/2918)\n- `allow_automatic_tabbing` task to `runtime::window`. [#2933](https://github.com/iced-rs/iced/pull/2933)\n- `FromStr` and `Display` implementations for `Color`. [#2937](https://github.com/iced-rs/iced/pull/2937)\n- `text::Renderer` trait in `iced_graphics` with `fill_raw` method. [#2958](https://github.com/iced-rs/iced/pull/2958)\n- `font_maybe` helper for `text` widget. [#2988](https://github.com/iced-rs/iced/pull/2988)\n- `filter_map` method to `Subscription`. [#2981](https://github.com/iced-rs/iced/pull/2981)\n- `repeat` field to `keyboard::Event::KeyPressed`. [#2991](https://github.com/iced-rs/iced/pull/2991)\n- Additional settings to control the fonts used for `markdown` rendering. [#2999](https://github.com/iced-rs/iced/pull/2999)\n- `Rescaled` variant to `window::Event`. [#3001](https://github.com/iced-rs/iced/pull/3001)\n- Environment variable to define `beacon` server listen address. [#3003](https://github.com/iced-rs/iced/pull/3003)\n- `push_under` method to `stack` widget. [#3010](https://github.com/iced-rs/iced/pull/3010)\n- `NONE` constant to `keyboard::Modifiers`. [#3037](https://github.com/iced-rs/iced/pull/3037)\n- `shadow` field to `overlay::menu::Style`. [#3049](https://github.com/iced-rs/iced/pull/3049)\n- `draw_mesh_cache` method in `mesh::Renderer` trait. [#3070](https://github.com/iced-rs/iced/pull/3070)\n- Efficient `is_empty` method for `text_editor::Content`. [#3117](https://github.com/iced-rs/iced/pull/3117)\n- `*Assign` implementations for `Point` and `Vector`. [#3131](https://github.com/iced-rs/iced/pull/3131)\n- Support `Background` instead of `Color` styling for `scrollable`. [#3127](https://github.com/iced-rs/iced/pull/3127)\n- `CornerPreference` window setting for Windows. [#3128](https://github.com/iced-rs/iced/pull/3128)\n- `move_to` method for `Editor` API. [#3125](https://github.com/iced-rs/iced/pull/3125)\n- `Background` and `padding_ratio` support for `toggler` styling. [#3129](https://github.com/iced-rs/iced/pull/3129)\n- More syntaxes for `iced_highlighter`. [#2822](https://github.com/iced-rs/iced/pull/2822)\n- Implement `Sub<Vector>` for `Cursor`. [#3137](https://github.com/iced-rs/iced/pull/3137)\n\n### Changed\n- Replace `Rc` with `Arc` for `markdown` caching. [#2599](https://github.com/iced-rs/iced/pull/2599)\n- Improved `button::Catalog` and `Style` documentation. [#2590](https://github.com/iced-rs/iced/pull/2590)\n- Improved `clock` example to display ticks and numbers. [#2644](https://github.com/iced-rs/iced/pull/2644)\n- Derived `PartialEq` and `Eq` for `mouse::click::Kind`. [#2741](https://github.com/iced-rs/iced/pull/2741)\n- Marked `Color::from_rgb8` and `Color::from_rgba8` as const. [#2749](https://github.com/iced-rs/iced/pull/2749)\n- Replaced unmaintained `directories-next` crate with `directories`. [#2761](https://github.com/iced-rs/iced/pull/2761)\n- Changed `Widget::update` to take `Event` by reference. [#2781](https://github.com/iced-rs/iced/pull/2781)\n- Improved `gallery` example with blurhash previews. [#2796](https://github.com/iced-rs/iced/pull/2796)\n- Replaced `wasm-timer` with `wasmtimer`. [#2780](https://github.com/iced-rs/iced/pull/2780)\n- Tweaked `Palette` Generation. [#2811](https://github.com/iced-rs/iced/pull/2811)\n- Relaxed `Task::perform` bound from `Fn` to `FnOnce`. [#2827](https://github.com/iced-rs/iced/pull/2827)\n- Improved `quad` shader to use a single SDF in `iced_wgpu`. [#2967](https://github.com/iced-rs/iced/pull/2967)\n- Leveraged `Limits::min` directly in `scrollable::layout`. [#3004](https://github.com/iced-rs/iced/pull/3004)\n- Overhauled `theme::Palette` generation by leveraging `Oklch`. [#3028](https://github.com/iced-rs/iced/pull/3028)\n- Mutable `Widget` Methods. [#3038](https://github.com/iced-rs/iced/pull/3038)\n- Prioritized `Shrink` over `Fill` in `layout` logic. [#3045](https://github.com/iced-rs/iced/pull/3045)\n- Replaced `format!` with `concat!` for string literals. [#2695](https://github.com/iced-rs/iced/pull/2695)\n- Replaced `window::run_with_handle` with a more powerful `window::run`. [#2718](https://github.com/iced-rs/iced/pull/2718)\n- Made color helpers in `palette` module public. [#2771](https://github.com/iced-rs/iced/pull/2771)\n- Changed default `PowerPreference` to `HighPerformance` in `iced_wgpu`. [#2813](https://github.com/iced-rs/iced/pull/2813)\n- Made `button::DEFAULT_PADDING` public. [#2858](https://github.com/iced-rs/iced/pull/2858)\n- Replaced `Url` parsing in `markdown` widget with `String` URIs. [#2992](https://github.com/iced-rs/iced/pull/2992)\n- Improved alignment docs of `container`. [#2871](https://github.com/iced-rs/iced/pull/2871)\n- Made `input_method` module public. [#2897](https://github.com/iced-rs/iced/pull/2897)\n- `iced` logo to built-in icons font. [#2902](https://github.com/iced-rs/iced/pull/2902)\n- Made `Layout::children` return an `ExactSizeIterator`. [#2915](https://github.com/iced-rs/iced/pull/2915)\n- Enabled `fancy-regex` instead of `onig` for `syntect`. [#2932](https://github.com/iced-rs/iced/pull/2932)\n- Added `warning` status to `toast` example. [#2936](https://github.com/iced-rs/iced/pull/2936)\n- Improved `scroll_to` and `snap_to` to allow operating on a single axis. [#2994](https://github.com/iced-rs/iced/pull/2994)\n- Disabled `png-format` feature from `iced_tiny_skia`. [#3043](https://github.com/iced-rs/iced/pull/3043)\n- Unified `keyboard` subscriptions into a single `listen` subscription. [#3135](https://github.com/iced-rs/iced/pull/3135)\n- Updated to Rust 2024. [#2809](https://github.com/iced-rs/iced/pull/2809)\n- Updated `wgpu` to `22.0`. [#2510](https://github.com/iced-rs/iced/pull/2510)\n- Updated `wgpu` to `23.0`. [#2663](https://github.com/iced-rs/iced/pull/2663)\n- Updated `wgpu` to `24.0`. [#2832](https://github.com/iced-rs/iced/pull/2832)\n- Updated `wgpu` to `26.0`. [#3019](https://github.com/iced-rs/iced/pull/3019)\n- Updated `wgpu` to `27.0`. [#3097](https://github.com/iced-rs/iced/pull/3097)\n- Updated `image` to `0.25`. [#2716](https://github.com/iced-rs/iced/pull/2716)\n- Updated `cosmic-text` to `0.13`. [#2834](https://github.com/iced-rs/iced/pull/2834)\n- Updated `cosmic-text` to `0.14`. [#2880](https://github.com/iced-rs/iced/pull/2880)\n- Updated `cosmic-text` to `0.15`. [#3098](https://github.com/iced-rs/iced/pull/3098)\n- Updated `resvg` to `0.45`. [#2846](https://github.com/iced-rs/iced/pull/2846)\n- Updated `wasmtimer` to `0.4.2`. [#3012](https://github.com/iced-rs/iced/pull/3012)\n- Updated `dark-light` to `2.0`. [#2724](https://github.com/iced-rs/iced/pull/2724)\n- Updated `openssl` to `0.10.70`. [#2783](https://github.com/iced-rs/iced/pull/2783)\n- Updated our `winit` fork with `0.30.8` fixes. [#2737](https://github.com/iced-rs/iced/pull/2737)\n\n### Fixed\n- Slow `wgpu` documentation. [#2593](https://github.com/iced-rs/iced/pull/2593)\n- Documentation for `open_events`. [#2594](https://github.com/iced-rs/iced/pull/2594)\n- Layout for wrapped `row` with `spacing`. [#2596](https://github.com/iced-rs/iced/pull/2596)\n- Flex layout of `Fill` elements in a `Shrink` cross axis. [#2598](https://github.com/iced-rs/iced/pull/2598)\n- Incorrect triangle mesh counting in `wgpu`. [#2601](https://github.com/iced-rs/iced/pull/2601)\n- Dropped images and meshes when pasting `Frame`. [#2605](https://github.com/iced-rs/iced/pull/2605)\n- `loading_spinners` example skipping part of the animation cycle. [#2617](https://github.com/iced-rs/iced/pull/2617)\n- Window `File*` events not marked as unsupported for Wayland. [#2615](https://github.com/iced-rs/iced/pull/2615)\n- Coupling of `markdown::view` iterator lifetime with resulting `Element`. [#2623](https://github.com/iced-rs/iced/pull/2623)\n- Delete key not working in `text_editor` widget. [#2632](https://github.com/iced-rs/iced/pull/2632)\n- Consecutive clicks triggering independently of distance. [#2639](https://github.com/iced-rs/iced/pull/2639)\n- `pane_grid` losing continuity when adding or removing panes. [#2628](https://github.com/iced-rs/iced/pull/2628)\n- Synthetic keyboard events not being discarded. [#2649](https://github.com/iced-rs/iced/pull/2649)\n- `sort_by` without total ordering in `tiny-skia` damage tracking. [#2651](https://github.com/iced-rs/iced/pull/2651)\n- Outdated docs of `Scrollable::with_direction` and `direction`. [#2668](https://github.com/iced-rs/iced/pull/2668)\n- `button` calling its `on_press` handler unnecessarily. [#2683](https://github.com/iced-rs/iced/pull/2683)\n- `system_information` example getting stuck at boot. [#2681](https://github.com/iced-rs/iced/pull/2681)\n- `tooltip` widget not redrawing when hovered. [#2675](https://github.com/iced-rs/iced/pull/2675)\n- `pane_grid::DragEvent::Canceled` not emitted within deadband. [#2691](https://github.com/iced-rs/iced/pull/2691)\n- Inconsistent positions in window-related operations. [#2688](https://github.com/iced-rs/iced/pull/2688)\n- `text::Wrapping` not being applied to `Paragraph`. [#2723](https://github.com/iced-rs/iced/pull/2723)\n- Broken nested `markdown` lists without empty line. [#2641](https://github.com/iced-rs/iced/pull/2641)\n- Unnecessary cast in `the_matrix` example. [#2731](https://github.com/iced-rs/iced/pull/2731)\n- Incorrect layer counting in `iced_wgpu`. [#2701](https://github.com/iced-rs/iced/pull/2701)\n- `Image` not respecting `viewport` bounds. [#2752](https://github.com/iced-rs/iced/pull/2752)\n- Attempting to draw empty meshes in `iced_wgpu`. [#2782](https://github.com/iced-rs/iced/pull/2782)\n- Input placeholder text not clearing when IME is activated. [#2785](https://github.com/iced-rs/iced/pull/2785)\n- Missing redraw request in `image::Viewer`. [#2795](https://github.com/iced-rs/iced/pull/2795)\n- Wrong position of preedit text on scrolled content. [#2798](https://github.com/iced-rs/iced/pull/2798)\n- Wrong initial candidate position for IME. [#2793](https://github.com/iced-rs/iced/pull/2793)\n- Text spans in IME preedit not being properly cached. [#2806](https://github.com/iced-rs/iced/pull/2806)\n- `cpu_brand` in `system_information` always being empty. [#2797](https://github.com/iced-rs/iced/pull/2797)\n- Horizontal text alignment being ignored on multi-line text. [#2835](https://github.com/iced-rs/iced/pull/2835)\n- Missing redraw request in `mouse_area` when hovered. [#2845](https://github.com/iced-rs/iced/pull/2845)\n- `futures-executor` being pulled even when it's not the default executor. [#2841](https://github.com/iced-rs/iced/pull/2841)\n- WebGPU failing to boot in Chromium. [#2686](https://github.com/iced-rs/iced/pull/2686)\n- Crash when using WebGL due to wrong binding alignment. [#2883](https://github.com/iced-rs/iced/pull/2883)\n- Wrong calculation of rows in `grid` widget when evenly distributed. [#2896](https://github.com/iced-rs/iced/pull/2896)\n- Panic in `combo_box` due to cleared children during `diff`. [#2905](https://github.com/iced-rs/iced/pull/2905)\n- OpenGL backend in `wgpu` interpreting atlas texture as cube map instead of texture array. [#2919](https://github.com/iced-rs/iced/pull/2919)\n- `quad` shader blending without pre-multiplication. [#2925](https://github.com/iced-rs/iced/pull/2925)\n- Inconsistent primitive pixel snapping in `iced_wgpu`. [#2962](https://github.com/iced-rs/iced/pull/2962)\n- Inconsistent `Rectangle::is_within` implementation. [#2966](https://github.com/iced-rs/iced/pull/2966)\n- Text damage calculation in `iced_tiny_skia`. [#2964](https://github.com/iced-rs/iced/pull/2964)\n- Leftover `title` mention in documentation. [#2972](https://github.com/iced-rs/iced/pull/2972)\n- Text bounds cutoff in `iced_wgpu`. [#2975](https://github.com/iced-rs/iced/pull/2975)\n- Rectangle vertices not being snapped to the pixel grid independently. [#2768](https://github.com/iced-rs/iced/pull/2768)\n- Lints for Rust 1.89. [#3030](https://github.com/iced-rs/iced/pull/3030)\n- `debug` builds on macOS Tahoe. [#3056](https://github.com/iced-rs/iced/pull/3056)\n- Typo in documentation comment for `filter_map`. [#3052](https://github.com/iced-rs/iced/pull/3052)\n- `container::Style` not respecting `crisp` feature. [#3112](https://github.com/iced-rs/iced/pull/3112)\n- Incorrect padding in `text_editor`. [#3115](https://github.com/iced-rs/iced/pull/3115)\n- Outdated documentation of `Widget::mouse_interaction`. [#2696](https://github.com/iced-rs/iced/pull/2696)\n- Incorrect render pass viewport in `custom_shader` example. [#2738](https://github.com/iced-rs/iced/pull/2738)\n- Capturing `ButtonReleased` event inside `image::Viewer`. [#2744](https://github.com/iced-rs/iced/pull/2744)\n- Incomplete docs for `on_link_click` in `rich_text`. [#2803](https://github.com/iced-rs/iced/pull/2803)\n- Stale syntax highlighting on `text_editor` after theme changes. [#2818](https://github.com/iced-rs/iced/pull/2818)\n- Wrong background color for `window::Preedit` on translucent themes. [#2819](https://github.com/iced-rs/iced/pull/2819)\n- Panic on Chromium-like browsers when canvas initial size is `(0, 0)`. [#2829](https://github.com/iced-rs/iced/pull/2829)\n- Outdated dev shell templates. [#2840](https://github.com/iced-rs/iced/pull/2840)\n- Missing `derive` feature for `serde` dependency. [#2854](https://github.com/iced-rs/iced/pull/2854)\n- `bezier_tool` listed as an example in the `Widget` trait docs. [#2867](https://github.com/iced-rs/iced/pull/2867)\n- Incomplete doc comment of `Length::is_fill`. [#2892](https://github.com/iced-rs/iced/pull/2892)\n- `scrollable` touch scrolling when out of bounds. [#2906](https://github.com/iced-rs/iced/pull/2906)\n- `Element::explain` being hidden by multi-layer widgets. [#2913](https://github.com/iced-rs/iced/pull/2913)\n- Missing `Shell::request_redraw` on `component`. [#2930](https://github.com/iced-rs/iced/pull/2930)\n- Text clipping in `iced_tiny_skia`. [#2929](https://github.com/iced-rs/iced/pull/2929)\n- Inconsistent naming of `tree` parameter in `Widget` trait. [#2950](https://github.com/iced-rs/iced/pull/2950)\n- `text_editor` syntax highlighting not updating on paste. [#2947](https://github.com/iced-rs/iced/pull/2947)\n- `svg` scaling in `iced_tiny_skia`. [#2954](https://github.com/iced-rs/iced/pull/2954)\n- Stroke bounds calculation and clip transformations in `iced_tiny_skia`. [#2882](https://github.com/iced-rs/iced/pull/2882)\n- Artifacts when drawing small arcs in `canvas` widget. [#2959](https://github.com/iced-rs/iced/pull/2959)\n- Path not being closed in `Path::circle`. [#2979](https://github.com/iced-rs/iced/pull/2979)\n- Incorrect transformation of cached primitives in `iced_tiny_skia`. [#2977](https://github.com/iced-rs/iced/pull/2977)\n- Panic when drawing empty image in `iced_tiny_skia`. [#2986](https://github.com/iced-rs/iced/pull/2986)\n- Incorrect mapping of navigation keys on higher keyboard layers. [#3007](https://github.com/iced-rs/iced/pull/3007)\n- `Status` of `svg` widget not being updated on cursor movement. [#3009](https://github.com/iced-rs/iced/pull/3009)\n- `hover` widget ignoring events in certain conditions. [#3015](https://github.com/iced-rs/iced/pull/3015)\n- OpenGL backend in `iced_wgpu` choosing wrong texture format in `wgpu::image::atlas`. [#3016](https://github.com/iced-rs/iced/pull/3016)\n- Missing redraw request in `geometry` example. [#3020](https://github.com/iced-rs/iced/pull/3020)\n- Buffer presentation logic in `iced_tiny_skia`. [#3032](https://github.com/iced-rs/iced/pull/3032)\n- `combo_box` text not getting cleared on selection. [#3063](https://github.com/iced-rs/iced/pull/3063)\n- `wgpu` surface not being reconfigured on `SurfaceError::Lost` or `Outdated`. [#3067](https://github.com/iced-rs/iced/pull/3067)\n- Incorrect cursor for `slider` widget on Windows . [#3068](https://github.com/iced-rs/iced/pull/3068)\n- `Paragraph::hit_span` returning false positives at end of content. [#3072](https://github.com/iced-rs/iced/pull/3072)\n- Incorrect `Limits::loose` documentation. [#3116](https://github.com/iced-rs/iced/pull/3116)\n- Missing semicolon triggering a `clippy` lint. [#3118](https://github.com/iced-rs/iced/pull/3118)\n- `iced_tiny_skia` using a `Window` instead of a `Display` handle for `softbuffer::Context` creation. [#3090](https://github.com/iced-rs/iced/pull/3090)\n- Missing `fn operate` in `tooltip` widget. [#3132](https://github.com/iced-rs/iced/pull/3132)\n- Panic when rendering problematic `svg`. [#3123](https://github.com/iced-rs/iced/pull/3123)\n- Hotkey combinations not working on non-latin keyboard layouts. [#3134](https://github.com/iced-rs/iced/pull/3134)\n- `keyboard::listen` reporting captured key events. [#3136](https://github.com/iced-rs/iced/pull/3136)\n\n### Removed\n- `is_over` method in `Overlay` trait. [#2921](https://github.com/iced-rs/iced/pull/2921)\n- Short-hand notation support for `color!` macro. [#2592](https://github.com/iced-rs/iced/pull/2592)\n- `surface` argument of `Compositor::screenshot`. [#2672](https://github.com/iced-rs/iced/pull/2672)\n- `once_cell` dependency. [#2626](https://github.com/iced-rs/iced/pull/2626)\n- `winapi` dependency. [#2760](https://github.com/iced-rs/iced/pull/2760)\n- `palette` dependency. [#2839](https://github.com/iced-rs/iced/pull/2839)\n\nMany thanks to...\n- @edwloef\n- @rhysd\n- @DKolter\n- @pml68\n- @andymandias\n- @dtzxporter\n- @tarkah\n- @tvolk131\n- @alex-ds13\n- @B0ney\n- @bbb651\n- @JL710\n- @kenz-gelsoft\n- @mfreeborn\n- @mtkennerly\n- @watsaig\n- @13r0ck\n- @airstrike\n- @bungoboingo\n- @EmmanuelDodoo\n- @karolisr\n- @Remmirad\n- @semiversus\n- @Ultrasquid9\n- @xosxos\n- @Zarthus\n- @7h0ma5\n- @7sDream\n- @Adam-Ladd\n- @AMS21\n- @Atreyagaurav\n- @AustinEvansWX\n- @Azorlogh\n- @berserkware\n- @biglizards\n- @boondocklabs\n- @bradysimon\n- @camspiers\n- @chrismanning\n- @codewing\n- @csmoe\n- @davehorner\n- @DavidAguilo\n- @dcz-self\n- @dejang\n- @dependabot[bot]\n- @EleDiaz\n- @ellieplayswow\n- @Exidex\n- @Fili-pk\n- @flakes\n- @Gobbel2000\n- @GyulyVGC\n- @hammerlink\n- @hydra\n- @ibaryshnikov\n- @ids1024\n- @iMohmmedSA\n- @Integral-Tech\n- @inthehack\n- @jakobhellermann\n- @janTatesa\n- @jbirnick\n- @jcdickinson\n- @Jinderamarak\n- @jsatka\n- @kbjr\n- @kgday\n- @kiedtl\n- @Konsl\n- @Koranir\n- @kosayoda\n- @Krahos\n- @l-const\n- @l4l\n- @laycookie\n- @leo030303\n- @Leonie-Theobald\n- @libkurisu\n- @lmaxyz\n- @mariinkys\n- @max-privatevoid\n- @MichelleGranat\n- @misaka10987\n- @mytdragon\n- @njust\n- @nrjais\n- @nz366\n- @OpenSauce\n- @Ottatop\n- @Redhawk18\n- @rhogenson\n- @rizzen-yazston\n- @rotmh\n- @Rudxain\n- @ryco117\n- @Seppel3210\n- @sgued\n- @sopvop\n- @T-256\n- @tafia\n- @thorn132\n- @tigerros\n- @tsuza\n- @vincenthz\n- @will-lynas\n\n## [0.13.1] - 2024-09-19\n### Added\n- Some `From` trait implementations for `text_input::Id`. [#2582](https://github.com/iced-rs/iced/pull/2582)\n- Custom `Executor` support for `Application` and `Daemon`. [#2580](https://github.com/iced-rs/iced/pull/2580)\n- `rust-version` metadata to `Cargo.toml`. [#2579](https://github.com/iced-rs/iced/pull/2579)\n- Widget examples to API reference. [#2587](https://github.com/iced-rs/iced/pull/2587)\n\n### Fixed\n- Inverted scrolling direction with trackpad in `scrollable`. [#2583](https://github.com/iced-rs/iced/pull/2583)\n- `scrollable` transactions when `on_scroll` is not set. [#2584](https://github.com/iced-rs/iced/pull/2584)\n- Incorrect text color styling in `text_editor` widget. [#2586](https://github.com/iced-rs/iced/pull/2586)\n\nMany thanks to...\n- @dcampbell24\n- @lufte\n- @mtkennerly\n\n## [0.13.0] - 2024-09-18\n### Added\n- Introductory chapters to the [official guide book](https://book.iced.rs/).\n- [Pocket guide](https://docs.rs/iced/0.13.0/iced/#the-pocket-guide) in API reference.\n- `Program` API. [#2331](https://github.com/iced-rs/iced/pull/2331)\n- `Task` API. [#2463](https://github.com/iced-rs/iced/pull/2463)\n- `Daemon` API and Shell Runtime Unification. [#2469](https://github.com/iced-rs/iced/pull/2469)\n- `rich_text` and `markdown` widgets. [#2508](https://github.com/iced-rs/iced/pull/2508)\n- `stack` widget. [#2405](https://github.com/iced-rs/iced/pull/2405)\n- `hover` widget. [#2408](https://github.com/iced-rs/iced/pull/2408)\n- `row::Wrapping` widget. [#2539](https://github.com/iced-rs/iced/pull/2539)\n- `text` macro helper. [#2338](https://github.com/iced-rs/iced/pull/2338)\n- `text::Wrapping` support. [#2279](https://github.com/iced-rs/iced/pull/2279)\n- Functional widget styling. [#2312](https://github.com/iced-rs/iced/pull/2312)\n- Closure-based widget styling. [#2326](https://github.com/iced-rs/iced/pull/2326)\n- Class-based Theming. [#2350](https://github.com/iced-rs/iced/pull/2350)\n- Type-Driven Renderer Fallback. [#2351](https://github.com/iced-rs/iced/pull/2351)\n- Background styling to `rich_text` widget. [#2516](https://github.com/iced-rs/iced/pull/2516)\n- Underline support for `rich_text`. [#2526](https://github.com/iced-rs/iced/pull/2526)\n- Strikethrough support for `rich_text`. [#2528](https://github.com/iced-rs/iced/pull/2528)\n- Abortable `Task`. [#2496](https://github.com/iced-rs/iced/pull/2496)\n- `abort_on_drop` to `task::Handle`. [#2503](https://github.com/iced-rs/iced/pull/2503)\n- `Ferra` theme. [#2329](https://github.com/iced-rs/iced/pull/2329)\n- `auto-detect-theme` feature. [#2343](https://github.com/iced-rs/iced/pull/2343)\n- Custom key binding support for `text_editor`. [#2522](https://github.com/iced-rs/iced/pull/2522)\n- `align_x` for `text_input` widget. [#2535](https://github.com/iced-rs/iced/pull/2535)\n- `center` widget helper. [#2423](https://github.com/iced-rs/iced/pull/2423)\n- Rotation support for `image` and `svg` widgets. [#2334](https://github.com/iced-rs/iced/pull/2334)\n- Dynamic `opacity` support for `image` and `svg`. [#2424](https://github.com/iced-rs/iced/pull/2424)\n- Scroll transactions for `scrollable` widget. [#2401](https://github.com/iced-rs/iced/pull/2401)\n- `physical_key` and `modified_key` to `keyboard::Event`. [#2576](https://github.com/iced-rs/iced/pull/2576)\n- `fetch_position` command in `window` module. [#2280](https://github.com/iced-rs/iced/pull/2280)\n- `filter_method` property for `image::Viewer` widget. [#2324](https://github.com/iced-rs/iced/pull/2324)\n- Support for pre-multiplied alpha `wgpu` composite mode. [#2341](https://github.com/iced-rs/iced/pull/2341)\n- `text_size` and `line_height` properties for `text_editor` widget. [#2358](https://github.com/iced-rs/iced/pull/2358)\n- `is_focused` method for `text_editor::State`. [#2386](https://github.com/iced-rs/iced/pull/2386)\n- `canvas::Cache` Grouping. [#2415](https://github.com/iced-rs/iced/pull/2415)\n- `ICED_PRESENT_MODE` env var to pick a `wgpu::PresentMode`. [#2428](https://github.com/iced-rs/iced/pull/2428)\n- `SpecificWith` variant to `window::Position`. [#2435](https://github.com/iced-rs/iced/pull/2435)\n- `scale_factor` field to `window::Screenshot`. [#2449](https://github.com/iced-rs/iced/pull/2449)\n- Styling support for `overlay::Menu` of `pick_list` widget. [#2457](https://github.com/iced-rs/iced/pull/2457)\n- `window::Id` in `Event` subscriptions. [#2456](https://github.com/iced-rs/iced/pull/2456)\n- `FromIterator` implementation for `row` and `column`. [#2460](https://github.com/iced-rs/iced/pull/2460)\n- `content_fit` for `image::viewer` widget. [#2330](https://github.com/iced-rs/iced/pull/2330)\n- `Display` implementation for `Radians`. [#2446](https://github.com/iced-rs/iced/pull/2446)\n- Helper methods for `window::Settings` in `Application`. [#2470](https://github.com/iced-rs/iced/pull/2470)\n- `Copy` implementation for `canvas::Fill` and `canvas::Stroke`. [#2475](https://github.com/iced-rs/iced/pull/2475)\n- Clarification of `Border` alignment for `Quad`. [#2485](https://github.com/iced-rs/iced/pull/2485)\n- \"Select All\" functionality on `Ctrl+A` to `text_editor`. [#2321](https://github.com/iced-rs/iced/pull/2321)\n- `stream::try_channel` helper. [#2497](https://github.com/iced-rs/iced/pull/2497)\n- `iced` widget helper to display the iced logo :comet:. [#2498](https://github.com/iced-rs/iced/pull/2498)\n- `align_x` and `align_y` helpers to `scrollable`. [#2499](https://github.com/iced-rs/iced/pull/2499)\n- Built-in text styles for each `Palette` color. [#2500](https://github.com/iced-rs/iced/pull/2500)\n- Embedded `Scrollbar` support for `scrollable`. [#2269](https://github.com/iced-rs/iced/pull/2269)\n- `on_press_with` method for `button`. [#2502](https://github.com/iced-rs/iced/pull/2502)\n- `resize_events` subscription to `window` module. [#2505](https://github.com/iced-rs/iced/pull/2505)\n- `Link` support to `rich_text` widget. [#2512](https://github.com/iced-rs/iced/pull/2512)\n- `image` and `svg` support for `canvas` widget. [#2537](https://github.com/iced-rs/iced/pull/2537)\n- `Compact` variant for `pane_grid::Controls`. [#2555](https://github.com/iced-rs/iced/pull/2555)\n- `image-without-codecs` feature flag. [#2244](https://github.com/iced-rs/iced/pull/2244)\n- `container::background` styling helper. [#2261](https://github.com/iced-rs/iced/pull/2261)\n- `undecorated_shadow` window setting for Windows. [#2285](https://github.com/iced-rs/iced/pull/2285)\n- Tasks for setting mouse passthrough. [#2284](https://github.com/iced-rs/iced/pull/2284)\n- `*_maybe` helpers for `text_input` widget. [#2390](https://github.com/iced-rs/iced/pull/2390)\n- Wasm support for `download_progress` example. [#2419](https://github.com/iced-rs/iced/pull/2419)\n- `scrollable::scroll_by` widget operation. [#2436](https://github.com/iced-rs/iced/pull/2436)\n- Enhancements to `slider` widget styling. [#2444](https://github.com/iced-rs/iced/pull/2444)\n- `on_scroll` handler to `mouse_area` widget. [#2450](https://github.com/iced-rs/iced/pull/2450)\n- `stroke_rectangle` method to `canvas::Frame`. [#2473](https://github.com/iced-rs/iced/pull/2473)\n- `override_redirect` setting for X11 windows. [#2476](https://github.com/iced-rs/iced/pull/2476)\n- Disabled state support for `toggler` widget. [#2478](https://github.com/iced-rs/iced/pull/2478)\n- `Color::parse` helper for parsing color strings. [#2486](https://github.com/iced-rs/iced/pull/2486)\n- `rounded_rectangle` method to `canvas::Path`. [#2491](https://github.com/iced-rs/iced/pull/2491)\n- `width` method to `text_editor` widget. [#2513](https://github.com/iced-rs/iced/pull/2513)\n- `on_open` handler to `combo_box` widget. [#2534](https://github.com/iced-rs/iced/pull/2534)\n- Additional `mouse::Interaction` cursors. [#2551](https://github.com/iced-rs/iced/pull/2551)\n- Scroll wheel handling in `slider` widget. [#2565](https://github.com/iced-rs/iced/pull/2565)\n\n### Changed\n- Use a `StagingBelt` in `iced_wgpu` for regular buffer uploads. [#2357](https://github.com/iced-rs/iced/pull/2357)\n- Use generic `Content` in `Text` to avoid reallocation in `fill_text`. [#2360](https://github.com/iced-rs/iced/pull/2360)\n- Use `Iterator::size_hint` to initialize `Column` and `Row` capacity. [#2362](https://github.com/iced-rs/iced/pull/2362)\n- Specialize `widget::text` helper. [#2363](https://github.com/iced-rs/iced/pull/2363)\n- Use built-in `[lints]` table in `Cargo.toml`. [#2377](https://github.com/iced-rs/iced/pull/2377)\n- Target `#iced` container by default on Wasm. [#2342](https://github.com/iced-rs/iced/pull/2342)\n- Improved architecture for `iced_wgpu` and `iced_tiny_skia`. [#2382](https://github.com/iced-rs/iced/pull/2382)\n- Make image `Cache` eviction strategy less aggressive in `iced_wgpu`. [#2403](https://github.com/iced-rs/iced/pull/2403)\n- Retain caches in `iced_wgpu` as long as `Rc` values are alive. [#2409](https://github.com/iced-rs/iced/pull/2409)\n- Use `bytes` crate for `image` widget. [#2356](https://github.com/iced-rs/iced/pull/2356)\n- Update `winit` to `0.30`. [#2427](https://github.com/iced-rs/iced/pull/2427)\n- Reuse `glyphon::Pipeline` state in `iced_wgpu`. [#2430](https://github.com/iced-rs/iced/pull/2430)\n- Ask for explicit `Length` in `center_*` methods. [#2441](https://github.com/iced-rs/iced/pull/2441)\n- Hide internal `Task` constructors. [#2492](https://github.com/iced-rs/iced/pull/2492)\n- Hide `Subscription` internals. [#2493](https://github.com/iced-rs/iced/pull/2493)\n- Improved `view` ergonomics. [#2504](https://github.com/iced-rs/iced/pull/2504)\n- Update `cosmic-text` and `resvg`. [#2416](https://github.com/iced-rs/iced/pull/2416)\n- Snap `Quad` lines to the pixel grid in `iced_wgpu`. [#2531](https://github.com/iced-rs/iced/pull/2531)\n- Update `web-sys` to `0.3.69`. [#2507](https://github.com/iced-rs/iced/pull/2507)\n- Allow disabled `TextInput` to still be interacted with. [#2262](https://github.com/iced-rs/iced/pull/2262)\n- Enable horizontal scrolling without shift modifier for `srollable` widget. [#2392](https://github.com/iced-rs/iced/pull/2392)\n- Add `mouse::Button` to `mouse::Click`. [#2414](https://github.com/iced-rs/iced/pull/2414)\n- Notify `scrollable::Viewport` changes. [#2438](https://github.com/iced-rs/iced/pull/2438)\n- Improved documentation of `Component` state management. [#2556](https://github.com/iced-rs/iced/pull/2556)\n\n### Fixed\n- Fix `block_on` in `iced_wgpu` hanging Wasm builds. [#2313](https://github.com/iced-rs/iced/pull/2313)\n- Private `PaneGrid` style fields. [#2316](https://github.com/iced-rs/iced/pull/2316)\n- Some documentation typos. [#2317](https://github.com/iced-rs/iced/pull/2317)\n- Blurry input caret with non-integral scaling. [#2320](https://github.com/iced-rs/iced/pull/2320)\n- Scrollbar stuck in a `scrollable` under some circumstances. [#2322](https://github.com/iced-rs/iced/pull/2322)\n- Broken `wgpu` examples link in issue template. [#2327](https://github.com/iced-rs/iced/pull/2327)\n- Empty `wgpu` draw calls in `image` pipeline. [#2344](https://github.com/iced-rs/iced/pull/2344)\n- Layout invalidation for `Responsive` widget. [#2345](https://github.com/iced-rs/iced/pull/2345)\n- Incorrect shadows on quads with rounded corners. [#2354](https://github.com/iced-rs/iced/pull/2354)\n- Empty menu overlay on `combo_box`. [#2364](https://github.com/iced-rs/iced/pull/2364)\n- Copy / cut vulnerability in a secure `TextInput`. [#2366](https://github.com/iced-rs/iced/pull/2366)\n- Inadequate readability / contrast for built-in themes. [#2376](https://github.com/iced-rs/iced/pull/2376)\n- Fix `pkg-config` typo in `DEPENDENCIES.md`. [#2379](https://github.com/iced-rs/iced/pull/2379)\n- Unbounded memory consumption by `iced_winit::Proxy`. [#2389](https://github.com/iced-rs/iced/pull/2389)\n- Typo in `icon::Error` message. [#2393](https://github.com/iced-rs/iced/pull/2393)\n- Nested scrollables capturing all scroll events. [#2397](https://github.com/iced-rs/iced/pull/2397)\n- Content capturing scrollbar events in a `scrollable`. [#2406](https://github.com/iced-rs/iced/pull/2406)\n- Out of bounds caret and overflow when scrolling in `text_editor`. [#2407](https://github.com/iced-rs/iced/pull/2407)\n- Missing `derive(Default)` in overview code snippet. [#2412](https://github.com/iced-rs/iced/pull/2412)\n- `image::Viewer` triggering grab from outside the widget. [#2420](https://github.com/iced-rs/iced/pull/2420)\n- Different windows fighting over shared `image::Cache`. [#2425](https://github.com/iced-rs/iced/pull/2425)\n- Images not aligned to the (logical) pixel grid in `iced_wgpu`. [#2440](https://github.com/iced-rs/iced/pull/2440)\n- Incorrect local time in `clock` example under Unix systems. [#2421](https://github.com/iced-rs/iced/pull/2421)\n- `⌘ + ←` and `⌘ + →` behavior for `text_input` on macOS. [#2315](https://github.com/iced-rs/iced/pull/2315)\n- Wayland packages in `DEPENDENCIES.md`. [#2465](https://github.com/iced-rs/iced/pull/2465)\n- Typo in documentation. [#2487](https://github.com/iced-rs/iced/pull/2487)\n- Extraneous comment in `scrollable` module. [#2488](https://github.com/iced-rs/iced/pull/2488)\n- Top layer in `hover` widget hiding when focused. [#2544](https://github.com/iced-rs/iced/pull/2544)\n- Out of bounds text in `text_editor` widget. [#2536](https://github.com/iced-rs/iced/pull/2536)\n- Segfault on Wayland when closing the app. [#2547](https://github.com/iced-rs/iced/pull/2547)\n- `lazy` feature flag sometimes not present in documentation. [#2289](https://github.com/iced-rs/iced/pull/2289)\n- Border of `progress_bar` widget being rendered below the active bar. [#2443](https://github.com/iced-rs/iced/pull/2443)\n- `radii` typo in `iced_wgpu` shader. [#2484](https://github.com/iced-rs/iced/pull/2484)\n- Incorrect priority of `Binding::Delete` in `text_editor`. [#2514](https://github.com/iced-rs/iced/pull/2514)\n- Division by zero in `multitouch` example. [#2517](https://github.com/iced-rs/iced/pull/2517)\n- Invisible text in `svg` widget. [#2560](https://github.com/iced-rs/iced/pull/2560)\n- `wasm32` deployments not displaying anything. [#2574](https://github.com/iced-rs/iced/pull/2574)\n- Unnecessary COM initialization on Windows. [#2578](https://github.com/iced-rs/iced/pull/2578)\n\n### Removed\n- Unnecessary struct from `download_progress` example. [#2380](https://github.com/iced-rs/iced/pull/2380)\n- Out of date comment from `custom_widget` example. [#2549](https://github.com/iced-rs/iced/pull/2549)\n- `Clone` bound for `graphics::Cache::clear`. [#2575](https://github.com/iced-rs/iced/pull/2575)\n\nMany thanks to...\n- @Aaron-McGuire\n- @airstrike\n- @alex-ds13\n- @alliby\n- @Andrew-Schwartz\n- @ayeniswe\n- @B0ney\n- @Bajix\n- @blazra\n- @Brady-Simon\n- @breynard0\n- @bungoboingo\n- @casperstorm\n- @Davidster\n- @derezzedex\n- @DKolter\n- @dtoniolo\n- @dtzxporter\n- @fenhl\n- @Gigas002\n- @gintsgints\n- @henrispriet\n- @IsaacMarovitz\n- @ivanceras\n- @Jinderamarak\n- @JL710\n- @jquesada2016\n- @JustSoup312\n- @kiedtl\n- @kmoon2437\n- @Koranir\n- @lufte\n- @LuisLiraC\n- @m4rch3n1ng\n- @meithecatte\n- @mtkennerly\n- @myuujiku\n- @n1ght-hunter\n- @nrjais\n- @PgBiel\n- @PolyMeilex\n- @rustrover\n- @ryankopf\n- @saihaze\n- @shartrec\n- @skygrango\n- @SolidStateDj\n- @sundaram123krishnan\n- @tarkah\n- @vladh\n- @WailAbou\n- @wiiznokes\n- @woelfman\n- @Zaubentrucker\n\n## [0.12.1] - 2024-02-22\n### Added\n- `extend` and `from_vec` methods for `Column` and `Row`. [#2264](https://github.com/iced-rs/iced/pull/2264)\n- `PartialOrd`, `Ord`, and `Hash` implementations for `keyboard::Modifiers`. [#2270](https://github.com/iced-rs/iced/pull/2270)\n- `clipboard` module in `advanced` module. [#2272](https://github.com/iced-rs/iced/pull/2272)\n- Default `disabled` style for `checkbox` and `hovered` style for `Svg`. [#2273](https://github.com/iced-rs/iced/pull/2273)\n- `From<u16>` and `From<i32>` implementations for `border::Radius`. [#2274](https://github.com/iced-rs/iced/pull/2274)\n- `size_hint` method for `Component` trait. [#2275](https://github.com/iced-rs/iced/pull/2275)\n\n### Fixed\n- Black images when using OpenGL backend in `iced_wgpu`. [#2259](https://github.com/iced-rs/iced/pull/2259)\n- Documentation for `horizontal_space` and `vertical_space` helpers. [#2265](https://github.com/iced-rs/iced/pull/2265)\n- WebAssembly platform. [#2271](https://github.com/iced-rs/iced/pull/2271)\n- Decouple `Key` from `keyboard::Modifiers` and apply them to `text` in `KeyboardInput`. [#2238](https://github.com/iced-rs/iced/pull/2238)\n- Text insertion not being prioritized in `TextInput` and `TextEditor`. [#2278](https://github.com/iced-rs/iced/pull/2278)\n- `iced_tiny_skia` clipping line strokes. [#2282](https://github.com/iced-rs/iced/pull/2282)\n\nMany thanks to...\n\n- @PolyMeilex\n- @rizzen-yazston\n- @wash2\n\n## [0.12.0] - 2024-02-15\n### Added\n- Multi-window support. [#1964](https://github.com/iced-rs/iced/pull/1964)\n- `TextEditor` widget (or multi-line text input). [#2123](https://github.com/iced-rs/iced/pull/2123)\n- `Shader` widget. [#2085](https://github.com/iced-rs/iced/pull/2085)\n- Shadows. [#1882](https://github.com/iced-rs/iced/pull/1882)\n- Vectorial text for `Canvas`. [#2204](https://github.com/iced-rs/iced/pull/2204)\n- Layout consistency. [#2192](https://github.com/iced-rs/iced/pull/2192)\n- Explicit text caching. [#2058](https://github.com/iced-rs/iced/pull/2058)\n- Gradients in Oklab color space. [#2055](https://github.com/iced-rs/iced/pull/2055)\n- `Themer` widget. [#2209](https://github.com/iced-rs/iced/pull/2209)\n- `Transform` primitive. [#2120](https://github.com/iced-rs/iced/pull/2120)\n- Cut functionality for `TextEditor`. [#2215](https://github.com/iced-rs/iced/pull/2215)\n- Primary clipboard support. [#2240](https://github.com/iced-rs/iced/pull/2240)\n- Disabled state for `Checkbox`. [#2109](https://github.com/iced-rs/iced/pull/2109)\n- `skip_taskbar` window setting for Windows. [#2211](https://github.com/iced-rs/iced/pull/2211)\n- `fetch_maximized` and `fetch_minimized` commands in `window`. [#2189](https://github.com/iced-rs/iced/pull/2189)\n- `run_with_handle` command in `window`. [#2200](https://github.com/iced-rs/iced/pull/2200)\n- `show_system_menu` command in `window`. [#2243](https://github.com/iced-rs/iced/pull/2243)\n- `text_shaping` method for `Tooltip`. [#2172](https://github.com/iced-rs/iced/pull/2172)\n- `interaction` method for `MouseArea`. [#2207](https://github.com/iced-rs/iced/pull/2207)\n- `hovered` styling for `Svg` widget. [#2163](https://github.com/iced-rs/iced/pull/2163)\n- `height` method for `TextEditor`. [#2221](https://github.com/iced-rs/iced/pull/2221)\n- Customizable style for `TextEditor`. [#2159](https://github.com/iced-rs/iced/pull/2159)\n- Customizable style for `QRCode`. [#2229](https://github.com/iced-rs/iced/pull/2229)\n- Border width styling for `Toggler`. [#2219](https://github.com/iced-rs/iced/pull/2219)\n- `RawText` variant for `Primitive` in `iced_graphics`. [#2158](https://github.com/iced-rs/iced/pull/2158)\n- `Stream` support for `Command`. [#2150](https://github.com/iced-rs/iced/pull/2150)\n- Access to bounds/content bounds from a `Scrollable` viewport. [#2072](https://github.com/iced-rs/iced/pull/2072)\n- `Frame::scale_nonuniform` method. [#2070](https://github.com/iced-rs/iced/pull/2070)\n- `theme::Custom::with_fn` to generate completely custom themes. [#2067](https://github.com/iced-rs/iced/pull/2067)\n- `style` attribute for `Font`. [#2041](https://github.com/iced-rs/iced/pull/2041)\n- Texture filtering options for `Image`. [#1894](https://github.com/iced-rs/iced/pull/1894)\n- `default` and `shift_step` methods for `slider` widgets. [#2100](https://github.com/iced-rs/iced/pull/2100)\n- `Custom` variant to `command::Action`. [#2146](https://github.com/iced-rs/iced/pull/2146)\n- Mouse movement events for `MouseArea`. [#2147](https://github.com/iced-rs/iced/pull/2147)\n- Dracula, Nord, Solarized, and Gruvbox variants for `Theme`. [#2170](https://github.com/iced-rs/iced/pull/2170)\n- Catppuccin, Tokyo Night, Kanagawa, Moonfly, Nightfly and Oxocarbon variants for `Theme`. [#2233](https://github.com/iced-rs/iced/pull/2233)\n- `From<T> where T: Into<PathBuf>` for `svg::Handle`. [#2235](https://github.com/iced-rs/iced/pull/2235)\n- `on_open` and `on_close` handlers for `PickList`. [#2174](https://github.com/iced-rs/iced/pull/2174)\n- Support for generic `Element` in `Tooltip`. [#2228](https://github.com/iced-rs/iced/pull/2228)\n- Container and `gap` styling for `Scrollable`. [#2239](https://github.com/iced-rs/iced/pull/2239)\n- Use `Borrow` for both `options` and `selected` in PickList. [#2251](https://github.com/iced-rs/iced/pull/2251)\n- `clip` property for `Container`, `Column`, `Row`, and `Button`. #[2252](https://github.com/iced-rs/iced/pull/2252)\n\n### Changed\n- Enable WebGPU backend in `wgpu` by default instead of WebGL. [#2068](https://github.com/iced-rs/iced/pull/2068)\n- Update `glyphon` to `0.4`. [#2203](https://github.com/iced-rs/iced/pull/2203)\n- Require `Send` on stored pipelines. [#2197](https://github.com/iced-rs/iced/pull/2197)\n- Update `wgpu` to `0.19`, `glyphon` to `0.5`, `softbuffer` to `0.4`, `window-clipboard` to `0.4`, and `raw-window-handle` to `0.6`. [#2191](https://github.com/iced-rs/iced/pull/2191)\n- Update `winit` to `0.29`. [#2169](https://github.com/iced-rs/iced/pull/2169)\n- Provide actual bounds to `Shader` primitives. [#2149](https://github.com/iced-rs/iced/pull/2149)\n- Deny warnings in `test` workflow. [#2135](https://github.com/iced-rs/iced/pull/2135)\n- Update `wgpu` to `0.18` and `cosmic-text` to `0.10`. [#2122](https://github.com/iced-rs/iced/pull/2122)\n- Compute vertex positions in the shader. [#2099](https://github.com/iced-rs/iced/pull/2099)\n- Migrate twox-hash -> xxhash-rust and switch to Xxh3 for better performance. [#2080](https://github.com/iced-rs/iced/pull/2080)\n- Add `keyboard` subscriptions and rename `subscription::events` to `event::listen`. [#2073](https://github.com/iced-rs/iced/pull/2073)\n- Use workspace dependencies and package inheritance. [#2069](https://github.com/iced-rs/iced/pull/2069)\n- Update `wgpu` to `0.17`. [#2065](https://github.com/iced-rs/iced/pull/2065)\n- Support automatic style type casting for `Button`. [#2046](https://github.com/iced-rs/iced/pull/2046)\n- Make `with_clip` and `with_save` in `Frame` able to return the data of the provided closure. [#1994](https://github.com/iced-rs/iced/pull/1994)\n- Use `Radians` for angle fields in `Arc` and `arc::Elliptical`. [#2027](https://github.com/iced-rs/iced/pull/2027)\n- Assert dimensions of quads are normal in `iced_tiny_skia`. [#2082](https://github.com/iced-rs/iced/pull/2082)\n- Remove `position` from `overlay::Element`. [#2226](https://github.com/iced-rs/iced/pull/2226)\n- Add a capacity limit to the `GlyphCache` in `iced_tiny_skia`. [#2210](https://github.com/iced-rs/iced/pull/2210)\n- Use pointer equality to speed up `PartialEq` implementation of `image::Bytes`. [#2220](https://github.com/iced-rs/iced/pull/2220)\n- Update `bitflags`, `glam`, `kurbo`, `ouroboros`, `qrcode`, and `sysinfo` dependencies. [#2227](https://github.com/iced-rs/iced/pull/2227)\n- Improve some widget ergonomics. [#2253](https://github.com/iced-rs/iced/pull/2253)\n\n### Fixed\n- Clipping of `TextInput` selection. [#2199](https://github.com/iced-rs/iced/pull/2199)\n- `Paragraph::grapheme_position` when ligatures are present. [#2196](https://github.com/iced-rs/iced/pull/2196)\n- Docs to include missing feature tags. [#2184](https://github.com/iced-rs/iced/pull/2184)\n- `PaneGrid` click interaction on the top edge. [#2168](https://github.com/iced-rs/iced/pull/2168)\n- `iced_wgpu` not rendering text in SVGs. [#2161](https://github.com/iced-rs/iced/pull/2161)\n- Text clipping. [#2154](https://github.com/iced-rs/iced/pull/2154)\n- Text transparency in `iced_tiny_skia`. [#2250](https://github.com/iced-rs/iced/pull/2250)\n- Layout invalidation when `Tooltip` changes `overlay`. [#2143](https://github.com/iced-rs/iced/pull/2143)\n- `Overlay` composition. [#2142](https://github.com/iced-rs/iced/pull/2142)\n- Incorrect GIF for the `progress_bar` example. [#2141](https://github.com/iced-rs/iced/pull/2141)\n- Standalone compilation of `iced_renderer` crate. [#2134](https://github.com/iced-rs/iced/pull/2134)\n- Maximize window button enabled when `Settings::resizable` is `false`. [#2124](https://github.com/iced-rs/iced/pull/2124)\n- Width of horizontal scrollbar in `Scrollable`. [#2084](https://github.com/iced-rs/iced/pull/2084)\n- `ComboBox` widget panic on wasm. [#2078](https://github.com/iced-rs/iced/pull/2078)\n- Majority of unresolved documentation links. [#2077](https://github.com/iced-rs/iced/pull/2077)\n- Web examples not running. [#2076](https://github.com/iced-rs/iced/pull/2076)\n- GIFs and video examples broken. [#2074](https://github.com/iced-rs/iced/pull/2074)\n- `@interpolate(flat)` not used as attribute. [#2071](https://github.com/iced-rs/iced/pull/2071)\n- `Checkbox` and `Toggler` hidden behind scrollbar in `styling` example. [#2062](https://github.com/iced-rs/iced/pull/2062)\n- Absolute `LineHeight` sometimes being `0`. [#2059](https://github.com/iced-rs/iced/pull/2059)\n- Paste while holding ALT. [#2006](https://github.com/iced-rs/iced/pull/2006)\n- `Command<T>::perform` to return a `Command<T>`. [#2000](https://github.com/iced-rs/iced/pull/2000)\n- `convert_text` not called on `Svg` trees. [#1908](https://github.com/iced-rs/iced/pull/1908)\n- Unused `backend.rs` file in renderer crate. [#2182](https://github.com/iced-rs/iced/pull/2182)\n- Some `clippy::pedantic` lints. [#2096](https://github.com/iced-rs/iced/pull/2096)\n- Some minor clippy fixes. [#2092](https://github.com/iced-rs/iced/pull/2092)\n- Clippy docs keyword quoting. [#2091](https://github.com/iced-rs/iced/pull/2091)\n- Clippy map transformations. [#2090](https://github.com/iced-rs/iced/pull/2090)\n- Inline format args for ease of reading. [#2089](https://github.com/iced-rs/iced/pull/2089)\n- Stuck scrolling in `Scrollable` with touch events. [#1940](https://github.com/iced-rs/iced/pull/1940)\n- Incorrect unit in `system::Information`. [#2223](https://github.com/iced-rs/iced/pull/2223)\n- `size_hint` not being called from `element::Map`. [#2224](https://github.com/iced-rs/iced/pull/2224)\n- `size_hint` not being called from `element::Explain`. [#2225](https://github.com/iced-rs/iced/pull/2225)\n- Slow touch scrolling for `TextEditor` widget. [#2140](https://github.com/iced-rs/iced/pull/2140)\n- `Subscription::map` using unreliable function pointer hash to identify mappers. [#2237](https://github.com/iced-rs/iced/pull/2237)\n- Missing feature flag docs for `time::every`. [#2188](https://github.com/iced-rs/iced/pull/2188)\n- Event loop not being resumed on Windows while resizing. [#2214](https://github.com/iced-rs/iced/pull/2214)\n- Alpha mode misconfiguration in `iced_wgpu`. [#2231](https://github.com/iced-rs/iced/pull/2231)\n- Outdated documentation leading to a dead link. [#2232](https://github.com/iced-rs/iced/pull/2232)\n\n\nMany thanks to...\n\n- @akshayr-mecha\n- @alec-deason\n- @arslee07\n- @AustinMReppert\n- @avsaase\n- @blazra\n- @brianch\n- @bungoboingo\n- @Calastrophe\n- @casperstorm\n- @cfrenette\n- @clarkmoody\n- @Davidster\n- @Decodetalkers\n- @derezzedex\n- @DoomDuck\n- @dtzxporter\n- @Dworv\n- @fogarecious\n- @GyulyVGC\n- @hicaru\n- @ids1024\n- @Imberflur\n- @jhannyj\n- @jhff\n- @jim-ec\n- @joshuamegnauth54\n- @jpttrssn\n- @julianbraha\n- @Koranir\n- @lufte\n- @matze\n- @MichalLebeda\n- @MoSal\n- @MrAntix\n- @nicksenger\n- @Nisatru\n- @nyurik\n- @Remmirad\n- @ripytide\n- @snaggen\n- @Tahinli\n- @tarkah\n- @tzemanovic\n- @varbhat\n- @VAWVAW\n- @william-shere\n- @wyatt-herkamp\n\n## [0.10.0] - 2023-07-28\n### Added\n- Text shaping, font fallback, and `iced_wgpu` overhaul. [#1697](https://github.com/iced-rs/iced/pull/1697)\n- Software renderer, runtime renderer fallback, and core consolidation. [#1748](https://github.com/iced-rs/iced/pull/1748)\n- Incremental rendering for `iced_tiny_skia`. [#1811](https://github.com/iced-rs/iced/pull/1811)\n- Configurable `LineHeight` support for text widgets. [#1828](https://github.com/iced-rs/iced/pull/1828)\n- `text::Shaping` strategy selection. [#1822](https://github.com/iced-rs/iced/pull/1822)\n- Subpixel glyph positioning and layout linearity. [#1921](https://github.com/iced-rs/iced/pull/1921)\n- Background gradients. [#1846](https://github.com/iced-rs/iced/pull/1846)\n- Offscreen rendering and screenshots. [#1845](https://github.com/iced-rs/iced/pull/1845)\n- Nested overlays. [#1719](https://github.com/iced-rs/iced/pull/1719)\n- Cursor availability. [#1904](https://github.com/iced-rs/iced/pull/1904)\n- Backend-specific primitives. [#1932](https://github.com/iced-rs/iced/pull/1932)\n- `ComboBox` widget. [#1954](https://github.com/iced-rs/iced/pull/1954)\n- `web-colors` feature flag to enable \"sRGB linear\" blending. [#1888](https://github.com/iced-rs/iced/pull/1888)\n- `PaneGrid` logic to split panes by drag & drop. [#1856](https://github.com/iced-rs/iced/pull/1856)\n- `PaneGrid` logic to drag & drop panes to the edges. [#1865](https://github.com/iced-rs/iced/pull/1865)\n- Type-safe `Scrollable` direction. [#1878](https://github.com/iced-rs/iced/pull/1878)\n- `Scrollable` alignment. [#1912](https://github.com/iced-rs/iced/pull/1912)\n- Helpers to change viewport alignment of a `Scrollable`. [#1953](https://github.com/iced-rs/iced/pull/1953)\n- `scroll_to` widget operation. [#1796](https://github.com/iced-rs/iced/pull/1796)\n- `scroll_to` helper. [#1804](https://github.com/iced-rs/iced/pull/1804)\n- `visible_bounds` widget operation for `Container`. [#1971](https://github.com/iced-rs/iced/pull/1971)\n- Command to fetch window size. [#1927](https://github.com/iced-rs/iced/pull/1927)\n- Conversion support from `Fn` trait to custom theme. [#1861](https://github.com/iced-rs/iced/pull/1861)\n- Configurable border radii on relevant widgets. [#1869](https://github.com/iced-rs/iced/pull/1869)\n- `border_radius` styling to `Slider` rail. [#1892](https://github.com/iced-rs/iced/pull/1892)\n- `application_id` in `PlatformSpecific` settings for Linux. [#1963](https://github.com/iced-rs/iced/pull/1963)\n- Aliased entries in `text::Cache`. [#1934](https://github.com/iced-rs/iced/pull/1934)\n- Text cache modes. [#1938](https://github.com/iced-rs/iced/pull/1938)\n- `operate` method for `program::State`. [#1913](https://github.com/iced-rs/iced/pull/1913)\n- `Viewport` argument to `Widget::on_event`. [#1956](https://github.com/iced-rs/iced/pull/1956)\n- Nix instructions to `DEPENDENCIES.md`. [#1859](https://github.com/iced-rs/iced/pull/1859)\n- Loading spinners example. [#1902](https://github.com/iced-rs/iced/pull/1902)\n- Workflow that verifies `CHANGELOG` is always up-to-date. [#1970](https://github.com/iced-rs/iced/pull/1970)\n- Outdated mentions of `iced_native` in `README`. [#1979](https://github.com/iced-rs/iced/pull/1979)\n\n### Changed\n- Updated `wgpu` to `0.16`. [#1807](https://github.com/iced-rs/iced/pull/1807)\n- Updated `glam` to `0.24`. [#1840](https://github.com/iced-rs/iced/pull/1840)\n- Updated `winit` to `0.28`. [#1738](https://github.com/iced-rs/iced/pull/1738)\n- Updated `palette` to `0.7`. [#1875](https://github.com/iced-rs/iced/pull/1875)\n- Updated `ouroboros` to `0.17`. [#1925](https://github.com/iced-rs/iced/pull/1925)\n- Updated `resvg` to `0.35` and `tiny-skia` to `0.10`. [#1907](https://github.com/iced-rs/iced/pull/1907)\n- Changed `mouse::Button::Other` to take `u16` instead of `u8`. [#1797](https://github.com/iced-rs/iced/pull/1797)\n- Changed `subscription::channel` to take a `FnOnce` non-`Sync` closure. [#1917](https://github.com/iced-rs/iced/pull/1917)\n- Removed `Copy` requirement for text `StyleSheet::Style`. [#1814](https://github.com/iced-rs/iced/pull/1814)\n- Removed `min_width` of 1 from scrollbar & scroller for `Scrollable`. [#1844](https://github.com/iced-rs/iced/pull/1844)\n- Used `Widget::overlay` for `Tooltip`. [#1692](https://github.com/iced-rs/iced/pull/1692)\n\n### Fixed\n- `Responsive` layout not invalidated when shell layout is invalidated. [#1799](https://github.com/iced-rs/iced/pull/1799)\n- `Responsive` layout not invalidated when size changes without a `view` call. [#1890](https://github.com/iced-rs/iced/pull/1890)\n- Broken link in `ROADMAP.md`. [#1815](https://github.com/iced-rs/iced/pull/1815)\n- `bounds` of selected option background in `Menu`. [#1831](https://github.com/iced-rs/iced/pull/1831)\n- Border radius logic in `iced_tiny_skia`. [#1842](https://github.com/iced-rs/iced/pull/1842)\n- `Svg` filtered color not premultiplied. [#1841](https://github.com/iced-rs/iced/pull/1841)\n- Race condition when growing an `image::Atlas`. [#1847](https://github.com/iced-rs/iced/pull/1847)\n- Clearing damaged surface with background color in `iced_tiny_skia`. [#1854](https://github.com/iced-rs/iced/pull/1854)\n- Private gradient pack logic for `iced_graphics::Gradient`. [#1871](https://github.com/iced-rs/iced/pull/1871)\n- Unordered quads of different background types. [#1873](https://github.com/iced-rs/iced/pull/1873)\n- Panic in `glyphon` when glyphs are missing. [#1883](https://github.com/iced-rs/iced/pull/1883)\n- Empty scissor rectangle in `iced_wgpu::triangle` pipeline. [#1893](https://github.com/iced-rs/iced/pull/1893)\n- `Scrollable` scrolling when mouse not over it. [#1910](https://github.com/iced-rs/iced/pull/1910)\n- `translation` in `layout` of `Nested` overlay. [#1924](https://github.com/iced-rs/iced/pull/1924)\n- Build when using vendored dependencies. [#1928](https://github.com/iced-rs/iced/pull/1928)\n- Minor grammar mistake. [#1931](https://github.com/iced-rs/iced/pull/1931)\n- Quad rendering including border only inside of the bounds. [#1843](https://github.com/iced-rs/iced/pull/1843)\n- Redraw requests not being forwarded for `Component` overlays. [#1949](https://github.com/iced-rs/iced/pull/1949)\n- Blinking input cursor when window loses focus. [#1955](https://github.com/iced-rs/iced/pull/1955)\n- `BorderRadius` not exposed in root crate. [#1972](https://github.com/iced-rs/iced/pull/1972)\n- Outdated `ROADMAP`. [#1958](https://github.com/iced-rs/iced/pull/1958)\n\n### Patched\n- Keybinds to cycle `ComboBox` options. [#1991](https://github.com/iced-rs/iced/pull/1991)\n- `Tooltip` overlay position inside `Scrollable`. [#1978](https://github.com/iced-rs/iced/pull/1978)\n- `iced_wgpu` freezing on empty layers. [#1996](https://github.com/iced-rs/iced/pull/1996)\n- `image::Viewer` reacting to any scroll event. [#1998](https://github.com/iced-rs/iced/pull/1998)\n- `TextInput` pasting text when `Alt` key is pressed. [#2006](https://github.com/iced-rs/iced/pull/2006)\n- Broken link to old `iced_native` crate in `README`. [#2024](https://github.com/iced-rs/iced/pull/2024)\n- `Rectangle::contains` being non-exclusive. [#2017](https://github.com/iced-rs/iced/pull/2017)\n- Documentation for `Arc` and `arc::Elliptical`. [#2008](https://github.com/iced-rs/iced/pull/2008)\n\nMany thanks to...\n\n- @a1phyr\n- @alec-deason\n- @AustinMReppert\n- @bbb651\n- @bungoboingo\n- @casperstorm\n- @clarkmoody\n- @Davidster\n- @Drakulix\n- @genusistimelord\n- @GyulyVGC\n- @ids1024\n- @jhff\n- @JonathanLindsey\n- @kr105\n- @marienz\n- @malramsay64\n- @nicksenger\n- @nicoburns\n- @NyxAlexandra\n- @Redhawk18\n- @RGBCube\n- @rs017991\n- @tarkah\n- @thunderstorm010\n- @ua-kxie\n- @wash2\n- @wiiznokes\n\n## [0.9.0] - 2023-04-13\n### Added\n- `MouseArea` widget. [#1594](https://github.com/iced-rs/iced/pull/1594)\n- `channel` helper in `subscription`. [#1786](https://github.com/iced-rs/iced/pull/1786)\n- Configurable `width` for `Scrollable`. [#1749](https://github.com/iced-rs/iced/pull/1749)\n- Support for disabled `TextInput`. [#1744](https://github.com/iced-rs/iced/pull/1744)\n- Platform-specific window settings. [#1730](https://github.com/iced-rs/iced/pull/1730)\n- Left and right colors for sliders. [#1643](https://github.com/iced-rs/iced/pull/1643)\n- Icon for `TextInput`. [#1702](https://github.com/iced-rs/iced/pull/1702)\n- Mouse over scrollbar flag for `scrollable::StyleSheet`. [#1669](https://github.com/iced-rs/iced/pull/1669)\n- Better example for `Radio`. [#1762](https://github.com/iced-rs/iced/pull/1762)\n\n### Changed\n- `wgpu` has been updated to `0.15` in `iced_wgpu`. [#1789](https://github.com/iced-rs/iced/pull/1789)\n- `resvg` has been updated to `0.29` in `iced_graphics`. [#1733](https://github.com/iced-rs/iced/pull/1733)\n- `subscription::run` now takes a function pointer. [#1723](https://github.com/iced-rs/iced/pull/1723)\n\n### Fixed\n- Redundant `on_scroll` messages for `Scrollable`. [#1788](https://github.com/iced-rs/iced/pull/1788)\n- Outdated items in `ROADMAP.md` [#1782](https://github.com/iced-rs/iced/pull/1782)\n- Colons in shader labels causing compilation issues in `iced_wgpu`. [#1779](https://github.com/iced-rs/iced/pull/1779)\n- Re-expose winit features for window servers in Linux. [#1777](https://github.com/iced-rs/iced/pull/1777)\n- Replacement of application node in Wasm. [#1765](https://github.com/iced-rs/iced/pull/1765)\n- `clippy` lints for Rust 1.68. [#1755](https://github.com/iced-rs/iced/pull/1755)\n- Unnecessary `Component` rebuilds. [#1754](https://github.com/iced-rs/iced/pull/1754)\n- Incorrect package name in checkbox example docs. [#1750](https://github.com/iced-rs/iced/pull/1750)\n- Fullscreen only working on primary monitor. [#1742](https://github.com/iced-rs/iced/pull/1742)\n- `Padding::fit` on irregular values for an axis. [#1734](https://github.com/iced-rs/iced/pull/1734)\n- `Debug` implementation of `Font` displaying its bytes. [#1731](https://github.com/iced-rs/iced/pull/1731)\n- Sliders bleeding over their rail. [#1721](https://github.com/iced-rs/iced/pull/1721)\n\n### Removed\n- `Fill` variant for `Alignment`. [#1735](https://github.com/iced-rs/iced/pull/1735)\n\nMany thanks to...\n\n- @ahoneybun\n- @bq-wrongway\n- @bungoboingo\n- @casperstorm\n- @Davidster\n- @ElhamAryanpur\n- @FinnPerry\n- @GyulyVGC\n- @JungleTryne\n- @lupd\n- @mmstick\n- @nicksenger\n- @Night-Hunter-NF\n- @tarkah\n- @traxys\n- @Xaeroxe\n\n## [0.8.0] - 2023-02-18\n### Added\n- Generic pixel units. [#1711](https://github.com/iced-rs/iced/pull/1711)\n- `custom` method to `widget::Operation` trait. [#1649](https://github.com/iced-rs/iced/pull/1649)\n- `Group` overlay. [#1655](https://github.com/iced-rs/iced/pull/1655)\n- Standalone `draw` helper for `image`. [#1682](https://github.com/iced-rs/iced/pull/1682)\n- Dynamic `pick_list::Handle`. [#1675](https://github.com/iced-rs/iced/pull/1675)\n- `Id` support for `Container`. [#1695](https://github.com/iced-rs/iced/pull/1695)\n- Custom `Checkbox` icon support. [#1707](https://github.com/iced-rs/iced/pull/1707)\n- `window` action to change always on top setting. [#1587](https://github.com/iced-rs/iced/pull/1587)\n- `window` action to fetch its unique identifier. [#1589](https://github.com/iced-rs/iced/pull/1589)\n\n### Changed\n- Annotated `Command` and `Subscription` with `#[must_use]`. [#1676](https://github.com/iced-rs/iced/pull/1676)\n- Replaced `Fn` with `FnOnce` in `canvas::Cache::draw`. [#1694](https://github.com/iced-rs/iced/pull/1694)\n- Used `[default]` on enum in `game_of_life` example. [#1660](https://github.com/iced-rs/iced/pull/1660)\n- Made `QRCode` hide when data is empty in `qr_code` example. [#1665](https://github.com/iced-rs/iced/pull/1665)\n- Replaced `Cow` with `Bytes` in `image` to accept any kind of data that implements `AsRef<[u8]>`. [#1551](https://github.com/iced-rs/iced/pull/1551)\n\n### Fixed\n- Blank window on application startup. [#1698](https://github.com/iced-rs/iced/pull/1698)\n- Off-by-one pixel error on `pick_list` width. [#1679](https://github.com/iced-rs/iced/pull/1679)\n- Missing `text_input` implementation in `operation::Map`. [#1678](https://github.com/iced-rs/iced/pull/1678)\n- Widget-driven animations for `Component`. [#1685](https://github.com/iced-rs/iced/pull/1685)\n- Layout translation in `overlay::Group`. [#1686](https://github.com/iced-rs/iced/pull/1686)\n- Missing `is_over` implementation for overlays of `iced_lazy` widgets. [#1699](https://github.com/iced-rs/iced/pull/1699)\n- Panic when overlay event processing removes overlay. [#1700](https://github.com/iced-rs/iced/pull/1700)\n- Panic when using operations with components in certain cases. [#1701](https://github.com/iced-rs/iced/pull/1701)\n- `TextInput` width when using padding. [#1706](https://github.com/iced-rs/iced/pull/1706)\n- `iced_glow` crash on some hardware. [#1703](https://github.com/iced-rs/iced/pull/1703)\n- Height of `overlay::Menu`. [#1714](https://github.com/iced-rs/iced/pull/1714)\n- Size of images in `README`. [#1659](https://github.com/iced-rs/iced/pull/1659)\n- New `clippy` lints. [#1681](https://github.com/iced-rs/iced/pull/1681)\n\nMany thanks to...\n\n- @13r0ck\n- @bungoboingo\n- @casperstorm\n- @frey\n- @greatest-ape\n- @ids1024\n- @Jedsek\n- @nicksenger\n- @Night-Hunter-NF\n- @sdroege\n- @Sn-Kinos\n- @sushigiri\n- @tarkah\n\n## [0.7.0] - 2023-01-14\n### Added\n- Widget-driven animations. [#1647](https://github.com/iced-rs/iced/pull/1647)\n- Multidirectional scrolling support for `Scrollable`. [#1550](https://github.com/iced-rs/iced/pull/1550)\n- `VerticalSlider` widget. [#1596](https://github.com/iced-rs/iced/pull/1596)\n- `Shift+Click` text selection support in `TextInput`. [#1622](https://github.com/iced-rs/iced/pull/1622)\n- Profiling support with the `chrome-trace` feature. [#1565](https://github.com/iced-rs/iced/pull/1565)\n- Customization of the handle of a `PickList`. [#1562](https://github.com/iced-rs/iced/pull/1562)\n- `window` action to request user attention. [#1584](https://github.com/iced-rs/iced/pull/1584)\n- `window` action to gain focus. [#1585](https://github.com/iced-rs/iced/pull/1585)\n- `window` action to toggle decorations. [#1588](https://github.com/iced-rs/iced/pull/1588)\n- `Copy` implementation for `gradient::Location`. [#1636](https://github.com/iced-rs/iced/pull/1636)\n\n### Changed\n- Replaced `Application::should_exit` with a `window::close` action. [#1606](https://github.com/iced-rs/iced/pull/1606)\n- Made `focusable::Count` fields public. [#1635](https://github.com/iced-rs/iced/pull/1635)\n- Added `Dependency` argument to the closure of `Lazy`. [#1646](https://github.com/iced-rs/iced/pull/1646)\n- Switched arguments order of `Toggler::new` for consistency. [#1616](https://github.com/iced-rs/iced/pull/1616)\n- Switched arguments order of `Checkbox::new` for consistency. [#1633](https://github.com/iced-rs/iced/pull/1633)\n\n### Fixed\n- Compilation error in `iced_glow` when the `image` feature is enabled but `svg` isn't. [#1593](https://github.com/iced-rs/iced/pull/1593)\n- Widget operations for `Responsive` widget. [#1615](https://github.com/iced-rs/iced/pull/1615)\n- Overlay placement for `Responsive`. [#1638](https://github.com/iced-rs/iced/pull/1638)\n- `overlay` implementation for `Lazy`. [#1644](https://github.com/iced-rs/iced/pull/1644)\n- Minor typo in documentation. [#1624](https://github.com/iced-rs/iced/pull/1624)\n- Links in documentation. [#1634](https://github.com/iced-rs/iced/pull/1634)\n- Missing comment in documentation. [#1648](https://github.com/iced-rs/iced/pull/1648)\n\nMany thanks to...\n\n- @13r0ck\n- @Araxeus\n- @ben-wallis\n- @bungoboingo\n- @casperstorm\n- @nicksenger\n- @Night-Hunter-NF\n- @rpitasky\n- @rs017991\n- @tarkah\n- @wiktor-k\n\n## [0.6.0] - 2022-12-07\n### Added\n- Support for non-uniform border radius for `Primitive::Quad`. [#1506](https://github.com/iced-rs/iced/pull/1506)\n- Operation to query the current focused widget. [#1526](https://github.com/iced-rs/iced/pull/1526)\n- Additional operations for `TextInput`. [#1529](https://github.com/iced-rs/iced/pull/1529)\n- Styling support for `Svg`. [#1578](https://github.com/iced-rs/iced/pull/1578)\n\n### Changed\n- Triangle geometry using a solid color is now drawn in a single draw call. [#1538](https://github.com/iced-rs/iced/pull/1538)\n\n### Fixed\n- Gradients for WebAssembly target. [#1524](https://github.com/iced-rs/iced/pull/1524)\n- `Overlay` layout cache not being invalidated. [#1528](https://github.com/iced-rs/iced/pull/1528)\n- Operations not working for `PaneGrid`. [#1533](https://github.com/iced-rs/iced/pull/1533)\n- Mapped `widget::Operation` always returning `Outcome::None`. [#1536](https://github.com/iced-rs/iced/pull/1536)\n- Padding of `TextInput` with `Length::Units` width. [#1539](https://github.com/iced-rs/iced/pull/1539)\n- Clipping of `Image` and `Svg` widgets in `iced_glow`. [#1557](https://github.com/iced-rs/iced/pull/1557)\n- Invalid links in documentation. [#1560](https://github.com/iced-rs/iced/pull/1560)\n- `Custom` style of `PickList` widget. [#1570](https://github.com/iced-rs/iced/pull/1570)\n- Scroller in `Scrollable` always being drawn. [#1574](https://github.com/iced-rs/iced/pull/1574)\n\nMany thanks to...\n\n- @bungoboingo\n- @l1Dan\n- @mmstick\n- @mtkennerly\n- @PolyMeilex\n- @rksm\n- @rs017991\n- @tarkah\n- @wash2\n\n## [0.5.0] - 2022-11-10\n### Added\n- __[Stabilization of stateless widgets][stateless]__ (#1393)  \n  The old widget API has been completely replaced by stateless widgets (introduced in #1284). Alongside the new API, there are a bunch of new helper functions and macros for easily describing view logic (like `row!` and `column!`).\n\n- __[First-class theming][theming]__ (#1362)  \n  A complete overhaul of our styling primitives, introducing a `Theme` as a first-class concept of the library.\n\n- __[Widget operations][operations]__ (#1399)  \n  An abstraction that can be used to traverse (and operate on) the widget tree of an application in order to query or update some widget state.\n\n- __[`Lazy` widget][lazy]__ (#1400)  \n  A widget that can call some view logic lazily only when some data has changed. Thanks to @nicksenger!\n\n- __[Linear gradient support for `Canvas`][gradient]__ (#1448)  \n  The `Canvas` widget can draw linear gradients now. Thanks to @bungoboingo!\n\n- __[Touch support for `Canvas`][touch]__ (#1305)  \n  The `Canvas` widget now supports touch events. Thanks to @artursapek!\n\n- __[`Image` and `Svg` support for `iced_glow`][image]__ (#1485)  \n  Our OpenGL renderer now is capable of rendering both the `Image` and `Svg` widgets. Thanks to @ids1024!\n\n[stateless]: https://github.com/iced-rs/iced/pull/1393\n[theming]: https://github.com/iced-rs/iced/pull/1362\n[operations]: https://github.com/iced-rs/iced/pull/1399\n[lazy]: https://github.com/iced-rs/iced/pull/1400\n[gradient]: https://github.com/iced-rs/iced/pull/1448\n[touch]: https://github.com/iced-rs/iced/pull/1305\n[image]: https://github.com/iced-rs/iced/pull/1485\n\n## [0.4.2] - 2022-05-03\n### Fixed\n- `Padding` type not exposed in `iced`.\n\n## [0.4.1] - 2022-05-02\n### Fixed\n- Version number in `README`.\n\n## [0.4.0] - 2022-05-02\n### Added\n- __[Stateless widgets][stateless]__ (#1284)  \n  A brand new widget API that removes the need to keep track of internal widget state. No more `button::State` in your application!\n\n- __[`Component` trait][component]__ (#1131)  \n  A new trait to implement custom widgets with internal mutable state while using composition and [The Elm Architecture].\n\n- __[`Responsive` widget][responsive]__ (#1193)  \n  A widget that is aware of its dimensions and can be used to easily build responsive user interfaces.\n\n- __[Experimental WebGL support][webgl]__ (#1096)  \n  Applications can now be rendered into an HTML `canvas` when targeting Wasm by leveraging the WebGL support in [`wgpu`]. Thanks to @pacmancoder and @kaimast!\n\n- __[Support for Raspberry Pis and older devices][raspberry]__ (#1160)  \n  The compatibility of our OpenGL renderer has been improved and should run on any hardware that supports OpenGL 3.0+ or OpenGL ES 2.0+. Additionally, we started maintaining [Docker images for `aarch64` and `armv7`](https://github.com/orgs/iced-rs/packages) to easily cross-compile `iced` applications and target Raspberry Pis. Thanks to @derezzedex!\n\n- __[Simpler `Renderer` APIs][renderer_apis]__ (#1110)  \n  The surface of the `Renderer` APIs of the library has been considerably reduced. Instead of a `Renderer` trait per widget, now there are only 3 traits that are reused by all the widgets.\n\n[webgl]: https://github.com/iced-rs/iced/pull/1096\n[renderer_apis]: https://github.com/iced-rs/iced/pull/1110\n[component]: https://github.com/iced-rs/iced/pull/1131\n[raspberry]: https://github.com/iced-rs/iced/pull/1160\n[responsive]: https://github.com/iced-rs/iced/pull/1193\n[stateless]: https://github.com/iced-rs/iced/pull/1284\n[The Elm Architecture]: https://guide.elm-lang.org/architecture/\n[`wgpu`]: https://github.com/gfx-rs/wgpu\n\n\n## [0.3.0] - 2021-03-31\n### Added\n- Touch support. [#57] [#650] (thanks to @simlay and @discordance!)\n- Clipboard write access for\n  - `TextInput` widget. [#770]\n  - `Application::update`. [#773]\n- `image::Viewer` widget. It allows panning and scaling of an image. [#319] (thanks to @tarkah!)\n- `Tooltip` widget. It annotates content with some text on mouse hover. [#465] (thanks to @yusdacra!)\n- Support for the [`smol`] async runtime. [#699] (thanks to @JayceFayne!)\n- Support for graceful exiting when using the `Application` trait. [#804]\n- Image format features in [`iced_wgpu`] to reduce code bloat. [#392] (thanks to @unrelentingtech!)\n- `Focused` and `Unfocused` variant to `window::Event`. [#701] (thanks to @cossonleo!)\n- `WGPU_BACKEND` environment variable to configure the internal graphics backend of `iced_wgpu`. [#789] (thanks to @Cupnfish!)\n\n### Changed\n- The `TitleBar` of a `PaneGrid` now supports generic elements. [#657] (thanks to @clarkmoody!)\n- The `Error` type now implements `Send` and `Sync`. [#719] (thanks to @taiki-e!)\n- The `Style` types in `iced_style` now implement `Clone` and `Copy`. [#720] (thanks to @taiki-e!)\n- The following dependencies have been updated:\n  - [`font-kit`] → `0.10` [#669]\n  - [`glutin`] → `0.26` [#658]\n  - [`resvg`] → `0.12` [#669]\n  - [`tokio`] → `1.0` [#672] (thanks to @yusdacra!)\n  - [`winit`] → `0.24` [#658]\n  - [`wgpu`] → `0.7` [#725] (thanks to @PolyMeilex)\n- The following examples were improved:\n  - `download_progress` now showcases multiple file downloads at once. [#283] (thanks to @Folyd!)\n  - `solar_system` uses the new `rand` API. [#760] (thanks to @TriedAngle!)\n\n### Fixed\n- Button events not being propagated to contents. [#668]\n- Incorrect overlay implementation for the `Button` widget. [#764]\n- `Viewport::physical_width` returning the wrong value. [#700]\n- Outdated documentation for the `Sandbox` trait. [#710]\n\n[#57]: https://github.com/iced-rs/iced/pull/57\n[#283]: https://github.com/iced-rs/iced/pull/283\n[#319]: https://github.com/iced-rs/iced/pull/319\n[#392]: https://github.com/iced-rs/iced/pull/392\n[#465]: https://github.com/iced-rs/iced/pull/465\n[#650]: https://github.com/iced-rs/iced/pull/650\n[#657]: https://github.com/iced-rs/iced/pull/657\n[#658]: https://github.com/iced-rs/iced/pull/658\n[#668]: https://github.com/iced-rs/iced/pull/668\n[#669]: https://github.com/iced-rs/iced/pull/669\n[#672]: https://github.com/iced-rs/iced/pull/672\n[#699]: https://github.com/iced-rs/iced/pull/699\n[#700]: https://github.com/iced-rs/iced/pull/700\n[#701]: https://github.com/iced-rs/iced/pull/701\n[#710]: https://github.com/iced-rs/iced/pull/710\n[#719]: https://github.com/iced-rs/iced/pull/719\n[#720]: https://github.com/iced-rs/iced/pull/720\n[#725]: https://github.com/iced-rs/iced/pull/725\n[#760]: https://github.com/iced-rs/iced/pull/760\n[#764]: https://github.com/iced-rs/iced/pull/764\n[#770]: https://github.com/iced-rs/iced/pull/770\n[#773]: https://github.com/iced-rs/iced/pull/773\n[#789]: https://github.com/iced-rs/iced/pull/789\n[#804]: https://github.com/iced-rs/iced/pull/804\n[`smol`]: https://github.com/smol-rs/smol\n[`winit`]: https://github.com/rust-windowing/winit\n[`glutin`]: https://github.com/rust-windowing/glutin\n[`font-kit`]: https://github.com/servo/font-kit\n\n## [0.2.0] - 2020-11-26\n### Added\n- __[`Canvas` interactivity][canvas]__ (#325)  \n  A trait-based approach to react to mouse and keyboard interactions in [the `Canvas` widget][#193].\n\n- __[`iced_graphics` subcrate][opengl]__ (#354)  \n  A backend-agnostic graphics subcrate that can be leveraged to build new renderers.\n\n- __[OpenGL renderer][opengl]__ (#354)  \n  An OpenGL renderer powered by [`iced_graphics`], [`glow`], and [`glutin`]. It is an alternative to the default [`wgpu`] renderer.\n\n- __[Overlay support][pick_list]__ (#444)  \n  Basic support for superpositioning interactive widgets on top of other widgets.\n\n- __[Faster event loop][view]__ (#597)  \n  The event loop now takes advantage of the data dependencies in [The Elm Architecture] and leverages the borrow checker to keep the widget tree alive between iterations, avoiding unnecessary rebuilds.\n\n- __[Event capturing][event]__ (#614)  \n  The runtime now can tell whether a widget has handled an event or not, easing [integration with existing applications].\n\n- __[`PickList` widget][pick_list]__ (#444)  \n  A drop-down selector widget built on top of the new overlay support.\n\n- __[`QRCode` widget][qr_code]__ (#622)  \n  A widget that displays a QR code, powered by [the `qrcode` crate].\n\n[canvas]: https://github.com/iced-rs/iced/pull/325\n[opengl]: https://github.com/iced-rs/iced/pull/354\n[`iced_graphics`]: https://github.com/iced-rs/iced/pull/354\n[pane_grid]: https://github.com/iced-rs/iced/pull/397\n[pick_list]: https://github.com/iced-rs/iced/pull/444\n[error]: https://github.com/iced-rs/iced/pull/514\n[view]: https://github.com/iced-rs/iced/pull/597\n[event]: https://github.com/iced-rs/iced/pull/614\n[color]: https://github.com/iced-rs/iced/pull/200\n[qr_code]: https://github.com/iced-rs/iced/pull/622\n[#193]: https://github.com/iced-rs/iced/pull/193\n[`glutin`]: https://github.com/rust-windowing/glutin\n[`wgpu`]: https://github.com/gfx-rs/wgpu\n[`glow`]: https://github.com/grovesNL/glow\n[the `qrcode` crate]: https://docs.rs/qrcode/0.12.0/qrcode/\n[integration with existing applications]: https://github.com/iced-rs/iced/pull/183\n[The Elm Architecture]: https://guide.elm-lang.org/architecture/\n\n\n## [0.1.1] - 2020-04-15\n### Added\n- `Settings::with_flags` to easily initialize some default settings with flags. [#266]\n- `Default` implementation for `canvas::layer::Cache`. [#267]\n- `Ctrl + Del` support for `TextInput`. [#268]\n- Helper methods in `canvas::Path` to easily draw lines, rectangles, and circles. [#293]\n- `From<Color>` implementation for `canvas::Fill`. [#293]\n- `From<String>` implementation for `canvas::Text`. [#293]\n- `From<&str>` implementation for `canvas::Text`. [#293]\n\n### Changed\n- `new` method of `Radio` and `Checkbox` now take a generic `Into<String>` for the label. [#260]\n- `Frame::fill` now takes a generic `Into<canvas::Fill>`. [#293]\n- `Frame::stroke` now takes a generic `Into<canvas::Stroke>`. [#293]\n- `Frame::fill_text` now takes a generic `Into<canvas::Text>`. [#293]\n\n### Fixed\n- Feature flags not being referenced in documentation. [#259]\n- Crash in some graphics drivers when displaying an empty `Canvas`. [#278]\n- Text measuring when spaces where present at the beginning of a `TextInput` value. [#279]\n- `TextInput` producing a `Clip` primitive when unnecessary. [#279]\n- Alignment of `Text` primitive in `iced_wgpu`. [#281]\n- `CursorEntered` and `CursorLeft` not being generated. [#289]\n\n### Removed\n- Unnecessary `'static` lifetimes in `Renderer` bounds. [#290]\n\n[#259]: https://github.com/iced-rs/iced/pull/259\n[#260]: https://github.com/iced-rs/iced/pull/260\n[#266]: https://github.com/iced-rs/iced/pull/266\n[#267]: https://github.com/iced-rs/iced/pull/267\n[#268]: https://github.com/iced-rs/iced/pull/268\n[#278]: https://github.com/iced-rs/iced/pull/278\n[#279]: https://github.com/iced-rs/iced/pull/279\n[#281]: https://github.com/iced-rs/iced/pull/281\n[#289]: https://github.com/iced-rs/iced/pull/289\n[#290]: https://github.com/iced-rs/iced/pull/290\n[#293]: https://github.com/iced-rs/iced/pull/293\n\n\n## [0.1.0] - 2020-04-02\n### Added\n- __[Event subscriptions]__ (#122)  \n  A declarative way to listen to external events asynchronously by leveraging [streams].\n\n- __[Custom styling]__ (#146)  \n  A simple, trait-based approach for customizing the appearance of different widgets.\n\n- __[`Canvas` widget]__ (#193)  \n  A widget for drawing 2D graphics with an interface inspired by the [Web Canvas API] and powered by [`lyon`].\n\n- __[`PaneGrid` widget]__ (#224)  \n  A widget that dynamically organizes layout by splitting panes that can be resized and drag and dropped.\n\n- __[`Svg` widget]__ (#111)  \n  A widget that renders vector graphics on top of [`resvg`] and [`raqote`]. Thanks to @Maldela!\n\n- __[`ProgressBar` widget]__ (#141)  \n  A widget to notify progress of asynchronous tasks to your users. Thanks to @Songtronix!\n\n- __[Configurable futures executor]__ (#164)  \n  Support for plugging [`tokio`], [`async-std`], [`wasm-bindgen-futures`], or your own custom futures executor to an application.\n\n- __[Compatibility with existing `wgpu` projects]__ (#183)  \n  A bunch of improvements to the flexibility of [`iced_wgpu`] to allow integration in existing codebases.\n\n- __[Text selection for `TextInput`]__ (#202)  \n  Thanks to @FabianLars and @Finnerale!\n\n- __[Texture atlas for `iced_wgpu`]__ (#154)  \n  An atlas on top of [`guillotiere`] for batching draw calls. Thanks to @Maldela!\n\n[Event subscriptions]: https://github.com/iced-rs/iced/pull/122\n[Custom styling]: https://github.com/iced-rs/iced/pull/146\n[`Canvas` widget]: https://github.com/iced-rs/iced/pull/193\n[`PaneGrid` widget]: https://github.com/iced-rs/iced/pull/224\n[`Svg` widget]: https://github.com/iced-rs/iced/pull/111\n[`ProgressBar` widget]: https://github.com/iced-rs/iced/pull/141\n[Configurable futures executor]: https://github.com/iced-rs/iced/pull/164\n[Compatibility with existing `wgpu` projects]: https://github.com/iced-rs/iced/pull/183\n[Clipboard access]: https://github.com/iced-rs/iced/pull/132\n[Texture atlas for `iced_wgpu`]: https://github.com/iced-rs/iced/pull/154\n[Text selection for `TextInput`]: https://github.com/iced-rs/iced/pull/202\n[`lyon`]: https://github.com/nical/lyon\n[`guillotiere`]: https://github.com/nical/guillotiere\n[Web Canvas API]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API\n[streams]: https://docs.rs/futures/0.3.4/futures/stream/index.html\n[`tokio`]: https://github.com/tokio-rs/tokio\n[`async-std`]: https://github.com/async-rs/async-std\n[`wasm-bindgen-futures`]: https://github.com/rustwasm/wasm-bindgen/tree/master/crates/futures\n[`resvg`]: https://github.com/RazrFalcon/resvg\n[`raqote`]: https://github.com/jrmuizel/raqote\n[`iced_wgpu`]: wgpu/\n\n\n## [0.1.0-beta] - 2019-11-25\n### Changed\n- The old `iced` becomes `iced_native`. The current `iced` crate turns into a batteries-included, cross-platform GUI library.\n\n\n## [0.1.0-alpha] - 2019-09-05\n### Added\n- First release! :tada:\n\n[Unreleased]: https://github.com/iced-rs/iced/compare/0.14.0...HEAD\n[0.14.0]: https://github.com/iced-rs/iced/compare/0.13.1...0.14.0\n[0.13.1]: https://github.com/iced-rs/iced/compare/0.13.0...0.13.1\n[0.13.0]: https://github.com/iced-rs/iced/compare/0.12.1...0.13.0\n[0.12.1]: https://github.com/iced-rs/iced/compare/0.12.0...0.12.1\n[0.12.0]: https://github.com/iced-rs/iced/compare/0.10.0...0.12.0\n[0.10.0]: https://github.com/iced-rs/iced/compare/0.9.0...0.10.0\n[0.9.0]: https://github.com/iced-rs/iced/compare/0.8.0...0.9.0\n[0.8.0]: https://github.com/iced-rs/iced/compare/0.7.0...0.8.0\n[0.7.0]: https://github.com/iced-rs/iced/compare/0.6.0...0.7.0\n[0.6.0]: https://github.com/iced-rs/iced/compare/0.5.0...0.6.0\n[0.5.0]: https://github.com/iced-rs/iced/compare/0.4.2...0.5.0\n[0.4.2]: https://github.com/iced-rs/iced/compare/0.4.1...0.4.2\n[0.4.1]: https://github.com/iced-rs/iced/compare/0.4.0...0.4.1\n[0.4.0]: https://github.com/iced-rs/iced/compare/0.3.0...0.4.0\n[0.3.0]: https://github.com/iced-rs/iced/compare/0.2.0...0.3.0\n[0.2.0]: https://github.com/iced-rs/iced/compare/0.1.1...0.2.0\n[0.1.1]: https://github.com/iced-rs/iced/compare/0.1.0...0.1.1\n[0.1.0]: https://github.com/iced-rs/iced/compare/0.1.0-beta...0.1.0\n[0.1.0-beta]: https://github.com/iced-rs/iced/compare/0.1.0-alpha...0.1.0-beta\n[0.1.0-alpha]: https://github.com/iced-rs/iced/releases/tag/0.1.0-alpha\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThank you for considering contributing to Iced! Take a look at [the roadmap] to get an idea of the current state of the library.\n\nThe core team is busy and does not have time to mentor nor babysit new contributors. If a member of the core team thinks that reviewing and understanding your work will take more time and effort than writing it from scratch by themselves, your contribution will be dismissed. It is your responsibility to communicate and figure out how to reduce the likelihood of this!\n\nThe general advice for new contributors is to share your ideas with the community. You can share your ideas and gather feedback in [our Zulip forum]. This is a very important step. It helps to coordinate work, get on the same page, and start building trust. Remember that [Code is the Easy Part] and also [The Hard Parts of Open Source]!\n\nOnce you have started a channel of communication, you must wait until someone from the core team chimes in. If the core team is busy, this can take a long time (maybe months!). Your idea may need a bunch of iteration, or it may turn into something completely different, or it may be completely discarded! You will have to be patient and humble. Remember that open-source is a gift.\n\nBesides directly writing code, there are many other different ways you can contribute. To name a few:\n\n- Writing tutorials or blog posts\n- Improving the documentation\n- Submitting bug reports and use cases\n- Sharing, discussing, researching and exploring new ideas or crates\n\n[the roadmap]: ROADMAP.md\n[our Zulip forum]: https://iced.zulipchat.com/\n[Code is the Easy Part]: https://youtu.be/DSjbTC-hvqQ?t=1138\n[The Hard Parts of Open Source]: https://www.youtube.com/watch?v=o_4EX4dPppA\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"iced\"\ndescription = \"A cross-platform GUI library inspired by Elm\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\nrust-version.workspace = true\n\n[lints]\nworkspace = true\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--cfg\", \"docsrs\"]\nall-features = true\n\n[badges]\nmaintenance = { status = \"actively-developed\" }\n\n[features]\ndefault = [\"wgpu\", \"tiny-skia\", \"crisp\", \"hinting\", \"web-colors\", \"thread-pool\", \"linux-theme-detection\", \"x11\", \"wayland\"]\n# Enables the `wgpu` GPU-accelerated renderer with all its default features (Vulkan, Metal, DX12, OpenGL, and WebGPU)\nwgpu = [\"wgpu-bare\", \"iced_renderer/wgpu\"]\n# Enables the `wgpu` GPU-accelerated renderer with the minimum required features (no backends!)\nwgpu-bare = [\"iced_renderer/wgpu-bare\", \"iced_widget/wgpu\"]\n# Enables the `tiny-skia` software renderer\ntiny-skia = [\"iced_renderer/tiny-skia\"]\n# Enables the `image` widget and image clipboard support\nimage = [\"image-without-codecs\", \"image/default\", \"iced_winit/image\"]\n# Enables the `image` widget, without any built-in codecs of the `image` crate\nimage-without-codecs = [\"iced_widget/image\", \"dep:image\"]\n# Enables the `svg` widget\nsvg = [\"iced_widget/svg\"]\n# Enables the `canvas` widget\ncanvas = [\"iced_widget/canvas\"]\n# Enables the `qr_code` widget\nqr_code = [\"iced_widget/qr_code\"]\n# Enables the `markdown` widget\nmarkdown = [\"iced_widget/markdown\"]\n# Enables lazy widgets\nlazy = [\"iced_widget/lazy\"]\n# Enables debug metrics in native platforms (press F12)\ndebug = [\"iced_winit/debug\", \"dep:iced_devtools\"]\n# Enables time-travel debugging (very experimental!)\ntime-travel = [\"debug\", \"iced_devtools/time-travel\"]\n# Enables hot reloading (very experimental!)\nhot = [\"debug\", \"iced_debug/hot\"]\n# Enables the tester developer tool for recording and playing tests (press F12)\ntester = [\"dep:iced_tester\"]\n# Enables the `thread-pool` futures executor as the `executor::Default` on native platforms\nthread-pool = [\"iced_futures/thread-pool\"]\n# Enables `tokio` as the `executor::Default` on native platforms\ntokio = [\"iced_futures/tokio\"]\n# Enables `smol` as the `executor::Default` on native platforms\nsmol = [\"iced_futures/smol\"]\n# Enables querying system information\nsysinfo = [\"iced_winit/sysinfo\"]\n# Enables broken \"sRGB linear\" blending to reproduce color management of the Web\nweb-colors = [\"iced_renderer/web-colors\"]\n# Enables pixel snapping for crisp edges by default (can cause jitter!)\ncrisp = [\"iced_core/crisp\"]\n# Enables the WebGL backend\nwebgl = [\"iced_renderer/webgl\"]\n# Enables syntax highlighting\nhighlighter = [\"iced_highlighter\", \"iced_widget/highlighter\"]\n# Enables the `widget::selector` module\nselector = [\"iced_runtime/selector\"]\n# Enables the advanced module\nadvanced = [\"iced_core/advanced\", \"iced_widget/advanced\"]\n# Embeds Fira Sans into the final application; useful for testing and Wasm builds\nfira-sans = [\"iced_renderer/fira-sans\"]\n# Enables basic text shaping by default\nbasic-shaping = [\"iced_core/basic-shaping\"]\n# Enables advanced text shaping by default\nadvanced-shaping = [\"iced_core/advanced-shaping\"]\n# Enables rendering hints (e.g. metrics hinting)\nhinting = [\"iced_winit/hinting\"]\n# Enables strict assertions for debugging purposes at the expense of performance\nstrict-assertions = [\"iced_renderer/strict-assertions\"]\n# Redraws on every runtime event, and not only when a widget requests it\nunconditional-rendering = [\"iced_winit/unconditional-rendering\"]\n# Enables support for the `sipper` library\nsipper = [\"iced_runtime/sipper\"]\n# Enables Linux system theme detection\nlinux-theme-detection = [\"iced_winit/linux-theme-detection\"]\n# Enables the Unix X11 backend\nx11 = [\"iced_renderer/x11\", \"iced_winit/x11\"]\n# Enables the Unix Wayland backend\nwayland = [\"iced_renderer/wayland\", \"iced_winit/wayland\"]\n\n[dependencies]\niced_debug.workspace = true\niced_core.workspace = true\niced_futures.workspace = true\niced_renderer.workspace = true\niced_runtime.workspace = true\niced_widget.workspace = true\niced_winit.workspace = true\n\niced_devtools.workspace = true\niced_devtools.optional = true\n\niced_tester.workspace = true\niced_tester.optional = true\n\niced_highlighter.workspace = true\niced_highlighter.optional = true\n\nthiserror.workspace = true\n\nimage.workspace = true\nimage.optional = true\n\n[dev-dependencies]\ncriterion = \"0.5\"\niced_wgpu.workspace = true\n\n[[bench]]\nname = \"wgpu\"\nharness = false\nrequired-features = [\"canvas\"]\n\n[profile.release-opt]\ninherits = \"release\"\ncodegen-units = 1\ndebug = false\nlto = true\nincremental = false\nopt-level = 3\noverflow-checks = false\nstrip = \"debuginfo\"\n\n[workspace]\nmembers = [\n    \"beacon\",\n    \"core\",\n    \"debug\",\n    \"devtools\",\n    \"futures\",\n    \"graphics\",\n    \"highlighter\",\n    \"program\",\n    \"renderer\",\n    \"runtime\",\n    \"selector\",\n    \"test\",\n    \"tester\",\n    \"tiny_skia\",\n    \"wgpu\",\n    \"widget\",\n    \"winit\",\n    \"examples/*\",\n]\n\n[workspace.package]\nversion = \"0.15.0-dev\"\nauthors = [\"Héctor Ramón Jiménez <hector@hecrj.dev>\"]\nedition = \"2024\"\nlicense = \"MIT\"\nrepository = \"https://github.com/iced-rs/iced\"\nhomepage = \"https://iced.rs\"\ncategories = [\"gui\"]\nkeywords = [\"gui\", \"ui\", \"graphics\", \"interface\", \"widgets\"]\nrust-version = \"1.92\"\n\n[workspace.dependencies]\niced = { version = \"0.15.0-dev\", path = \".\" }\niced_beacon = { version = \"0.15.0-dev\", path = \"beacon\" }\niced_core = { version = \"0.15.0-dev\", path = \"core\" }\niced_debug = { version = \"0.15.0-dev\", path = \"debug\" }\niced_devtools = { version = \"0.15.0-dev\", path = \"devtools\" }\niced_futures = { version = \"0.15.0-dev\", path = \"futures\" }\niced_graphics = { version = \"0.15.0-dev\", path = \"graphics\" }\niced_highlighter = { version = \"0.15.0-dev\", path = \"highlighter\" }\niced_program = { version = \"0.15.0-dev\", path = \"program\" }\niced_renderer = { version = \"0.15.0-dev\", path = \"renderer\" }\niced_runtime = { version = \"0.15.0-dev\", path = \"runtime\" }\niced_selector = { version = \"0.15.0-dev\", path = \"selector\" }\niced_test = { version = \"0.15.0-dev\", path = \"test\" }\niced_tester = { version = \"0.15.0-dev\", path = \"tester\" }\niced_tiny_skia = { version = \"0.15.0-dev\", path = \"tiny_skia\", default-features = false }\niced_wgpu = { version = \"0.15.0-dev\", path = \"wgpu\", default-features = false }\niced_widget = { version = \"0.15.0-dev\", path = \"widget\" }\niced_winit = { version = \"0.15.0-dev\", path = \"winit\", default-features = false }\n\narboard = { version = \"3.6\", default-features = false }\nbincode = \"1.3\"\nbitflags = \"2.0\"\nbytemuck = { version = \"1.0\", features = [\"derive\"] }\nbytes = \"1.6\"\ncargo-hot = { version = \"0.1\", package = \"cargo-hot-protocol\" }\ncosmic-text = \"0.18\"\ncryoglyph = { git = \"https://github.com/iced-rs/cryoglyph.git\", rev = \"1d68895e9c4c9b73739f826e81c2e3012c155cce\" }\nfutures = { version = \"0.3\", default-features = false, features = [\"std\", \"async-await\"] }\nglam = \"0.25\"\nguillotiere = \"0.6\"\nhalf = \"2.2\"\nimage = { version = \"0.25\", default-features = false }\nkamadak-exif = \"0.6\"\nkurbo = \"0.10\"\nlilt = \"0.8\"\nlog = \"0.4\"\nlyon = \"1.0\"\nlyon_path = \"1.0\"\nmundy = { version = \"0.2\", default-features = false }\nnom = \"8\"\nnum-traits = \"0.2\"\nouroboros = \"0.18\"\npng = \"0.18\"\npulldown-cmark = \"0.12\"\nqrcode = { version = \"0.13\", default-features = false }\nraw-window-handle = \"0.6\"\nresvg = \"0.45\"\nrfd = \"0.16\"\nrustc-hash = \"2.0\"\nsemver = \"1.0\"\nserde = \"1.0\"\nsha2 = \"0.10\"\nsipper = \"0.1\"\nsmol = \"2\"\nsmol_str = \"0.2\"\nsoftbuffer = { version = \"0.4\", default-features = false }\nsysinfo = \"0.33\"\nthiserror = \"2\"\ntiny-skia = { version = \"0.11\", default-features = false, features = [\"std\", \"simd\"] }\ntokio = \"1.0\"\ntracing = \"0.1\"\ntwo-face = { version = \"0.4\", default-features = false, features = [\"syntect-default-fancy\"] }\nunicode-segmentation = \"1.0\"\nurl = \"2.5\"\nwasm-bindgen-futures = \"0.4\"\nwasmtimer = \"0.4.2\"\nweb-sys = \"=0.3.85\"\nweb-time = \"1.1\"\nwgpu = { version = \"28.0\", default-features = false, features = [\"std\", \"wgsl\"] }\nwinit = { git = \"https://github.com/iced-rs/winit.git\", rev = \"05b8ff17a06562f0a10bb46e6eaacbe2a95cb5ed\", default-features = false, features = [\"rwh_06\"] }\n\n[workspace.lints.rust]\nrust_2018_idioms = { level = \"deny\", priority = -1 }\nmissing_docs = \"deny\"\nunsafe_code = \"deny\"\nunused_results = \"deny\"\n\n[workspace.lints.clippy]\ntype-complexity = \"allow\"\nmap-entry = \"allow\"\nlarge-enum-variant = \"allow\"\nresult_large_err = \"allow\"\nsemicolon_if_nothing_returned = \"deny\"\ntrivially-copy-pass-by-ref = \"deny\"\ndefault_trait_access = \"deny\"\nmatch-wildcard-for-single-variants = \"deny\"\nredundant-closure-for-method-calls = \"deny\"\nfilter_map_next = \"deny\"\nmanual_let_else = \"deny\"\nunused_async = \"deny\"\nfrom_over_into = \"deny\"\nneedless_borrow = \"deny\"\nnew_without_default = \"deny\"\nuseless_conversion = \"deny\"\n\n[workspace.lints.rustdoc]\nbroken_intra_doc_links = \"forbid\"\n"
  },
  {
    "path": "Cross.toml",
    "content": "[target.aarch64-unknown-linux-gnu]\nimage = \"ghcr.io/iced-rs/aarch64:latest\"\nxargo = false\n\n[target.armv7-unknown-linux-gnueabihf]\nimage = \"ghcr.io/iced-rs/armv7:latest\"\nxargo = false\n"
  },
  {
    "path": "DEPENDENCIES.md",
    "content": "# Dependencies\n\nIced requires some system dependencies to work, and not\nall operating systems come with them installed.\n\nYou can follow the provided instructions for your system to\nget them, if your system isn't here, add it!\n\n## NixOS\n\nYou can add this `shell.nix` to your project and use it by running `nix-shell`:\n\n```nix\n{ pkgs ? import <nixpkgs> { } }:\n\nlet\n  dlopenLibraries = with pkgs; [\n    libxkbcommon\n\n    # GPU backend\n    vulkan-loader\n    # libGL\n\n    # Window system\n    wayland\n    # xorg.libX11\n    # xorg.libXcursor\n    # xorg.libXi\n  ];\nin pkgs.mkShell {\n  nativeBuildInputs = with pkgs; [\n    cargo\n    rustc\n  ];\n\n  # additional libraries that your project\n  # links to at build time, e.g. OpenSSL\n  buildInputs = [];\n\n  env.RUSTFLAGS = \"-C link-arg=-Wl,-rpath,${pkgs.lib.makeLibraryPath dlopenLibraries}\";\n}\n```\n\nAlternatively, you can use this `flake.nix` to create a dev shell, activated by `nix develop`:\n\n```nix\n{\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixos-unstable\";\n    systems.url = \"github:nix-systems/default\";\n  };\n\n  outputs = { nixpkgs, systems, ... }:\n    let\n      eachSystem = nixpkgs.lib.genAttrs (import systems);\n      pkgsFor = nixpkgs.legacyPackages;\n    in {\n      devShells = eachSystem (system:\n        let\n          pkgs = pkgsFor.${system};\n          dlopenLibraries = with pkgs; [\n            libxkbcommon\n\n            # GPU backend\n            vulkan-loader\n            # libGL\n\n            # Window system\n            wayland\n            # xorg.libX11\n            # xorg.libXcursor\n            # xorg.libXi\n          ];\n        in {\n          default = pkgs.mkShell {\n            nativeBuildInputs = with pkgs; [\n              cargo\n              rustc\n            ];\n\n            # additional libraries that your project\n            # links to at build time, e.g. OpenSSL\n            buildInputs = [];\n\n            env.RUSTFLAGS = \"-C link-arg=-Wl,-rpath,${nixpkgs.lib.makeLibraryPath dlopenLibraries}\";\n          };\n        });\n    };\n}\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright 2019 Héctor Ramón, Iced contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n\n<img src=\"docs/logo.svg\" width=\"140px\" />\n\n# Iced\n\n[![Documentation](https://docs.rs/iced/badge.svg)][documentation]\n[![Crates.io](https://img.shields.io/crates/v/iced.svg)](https://crates.io/crates/iced)\n[![License](https://img.shields.io/crates/l/iced.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)\n[![Downloads](https://img.shields.io/crates/d/iced.svg)](https://crates.io/crates/iced)\n[![Test Status](https://img.shields.io/github/actions/workflow/status/iced-rs/iced/test.yml?branch=master&event=push&label=test)](https://github.com/iced-rs/iced/actions)\n[![Zulip Chat](https://img.shields.io/badge/chat-on%20Zulip-5e7ce2?logo=zulip&logoColor=white)](https://iced.zulipchat.com/)\n[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)\n\nA cross-platform GUI library for Rust focused on simplicity and type-safety.\nInspired by [Elm].\n\n<a href=\"https://github.com/squidowl/halloy\">\n  <img src=\"https://iced.rs/showcase/halloy.gif\" width=\"460px\">\n</a>\n<a href=\"https://github.com/hecrj/icebreaker\">\n  <img src=\"https://iced.rs/showcase/icebreaker.gif\" width=\"360px\">\n</a>\n\n</div>\n\n## Features\n\n* Simple, easy-to-use, batteries-included API\n* Type-safe, reactive programming model\n* [Cross-platform support] (Windows, macOS, Linux, and the Web)\n* Responsive layout\n* Built-in widgets (including [text inputs], [scrollables], and more!)\n* Custom widget support (create your own!)\n* [Debug tooling with performance metrics and time traveling]\n* First-class support for async actions (use futures!)\n* Modular ecosystem split into reusable parts:\n  * A [renderer-agnostic native runtime] enabling integration with existing systems\n  * Two built-in renderers leveraging [`wgpu`] and [`tiny-skia`]\n    * [`iced_wgpu`] supporting Vulkan, Metal and DX12\n    * [`iced_tiny_skia`] offering a software alternative as a fallback\n  * A [windowing shell]\n\n__Iced is currently experimental software.__ [Take a look at the roadmap] and\n[check out the issues].\n\n[Cross-platform support]: https://raw.githubusercontent.com/iced-rs/iced/master/docs/images/todos_desktop.jpg\n[text inputs]: https://iced.rs/examples/text_input.mp4\n[scrollables]: https://iced.rs/examples/scrollable.mp4\n[Debug tooling with performance metrics and time traveling]: https://github.com/user-attachments/assets/2e49695c-0261-4b43-ac2e-8d7da5454c4b\n[renderer-agnostic native runtime]: runtime/\n[`wgpu`]: https://github.com/gfx-rs/wgpu\n[`tiny-skia`]: https://github.com/RazrFalcon/tiny-skia\n[`iced_wgpu`]: wgpu/\n[`iced_tiny_skia`]: tiny_skia/\n[windowing shell]: winit/\n[Take a look at the roadmap]: ROADMAP.md\n[check out the issues]: https://github.com/iced-rs/iced/issues\n\n## Overview\n\nInspired by [The Elm Architecture], Iced expects you to split user interfaces\ninto four different concepts:\n\n* __State__ — the state of your application\n* __Messages__ — user interactions or meaningful events that you care\n  about\n* __View logic__ — a way to display your __state__ as widgets that\n  may produce __messages__ on user interaction\n* __Update logic__ — a way to react to __messages__ and update your\n  __state__\n\nWe can build something to see how this works! Let's say we want a simple counter\nthat can be incremented and decremented using two buttons.\n\nWe start by modelling the __state__ of our application:\n\n```rust\n#[derive(Default)]\nstruct Counter {\n    value: i32,\n}\n```\n\nNext, we need to define the possible user interactions of our counter:\nthe button presses. These interactions are our __messages__:\n\n```rust\n#[derive(Debug, Clone, Copy)]\npub enum Message {\n    Increment,\n    Decrement,\n}\n```\n\nNow, let's show the actual counter by putting it all together in our\n__view logic__:\n\n```rust\nuse iced::widget::{button, column, text, Column};\n\nimpl Counter {\n    pub fn view(&self) -> Column<'_, Message> {\n        // We use a column: a simple vertical layout\n        column![\n            // The increment button. We tell it to produce an\n            // `Increment` message when pressed\n            button(\"+\").on_press(Message::Increment),\n\n            // We show the value of the counter here\n            text(self.value).size(50),\n\n            // The decrement button. We tell it to produce a\n            // `Decrement` message when pressed\n            button(\"-\").on_press(Message::Decrement),\n        ]\n    }\n}\n```\n\nFinally, we need to be able to react to any produced __messages__ and change our\n__state__ accordingly in our __update logic__:\n\n```rust\nimpl Counter {\n    // ...\n\n    pub fn update(&mut self, message: Message) {\n        match message {\n            Message::Increment => {\n                self.value += 1;\n            }\n            Message::Decrement => {\n                self.value -= 1;\n            }\n        }\n    }\n}\n```\n\nAnd that's everything! We just wrote a whole user interface. Let's run it:\n\n```rust\nfn main() -> iced::Result {\n    iced::run(Counter::update, Counter::view)\n}\n```\n\nIced will automatically:\n\n  1. Take the result of our __view logic__ and layout its widgets.\n  1. Process events from our system and produce __messages__ for our\n     __update logic__.\n  1. Draw the resulting user interface.\n\nRead the [book], the [documentation], and the [examples] to learn more!\n\n## Implementation details\n\nIced was originally born as an attempt at bringing the simplicity of [Elm] and\n[The Elm Architecture] into [Coffee], a 2D game library I am working on.\n\nThe core of the library was implemented during May 2019 in [this pull request].\n[The first alpha version] was eventually released as\n[a renderer-agnostic GUI library]. The library did not provide a renderer and\nimplemented the current [tour example] on top of [`ggez`], a game library.\n\nSince then, the focus has shifted towards providing a batteries-included,\nend-user-oriented GUI library, while keeping the ecosystem modular.\n\n[this pull request]: https://github.com/hecrj/coffee/pull/35\n[The first alpha version]: https://github.com/iced-rs/iced/tree/0.1.0-alpha\n[a renderer-agnostic GUI library]: https://www.reddit.com/r/rust/comments/czzjnv/iced_a_rendereragnostic_gui_library_focused_on/\n[tour example]: examples/README.md#tour\n[`ggez`]: https://github.com/ggez/ggez\n\n## Contributing / Feedback\n\nIf you want to contribute, please read our [contributing guidelines] for more details.\n\nFeedback is also welcome! You can create a new topic in [our Zulip forum] or\ncome chat to [our Discord server].\n\n## Sponsors\n\nThe development of Iced is sponsored by the [Cryptowatch] team at [Kraken.com]\n\n[book]: https://book.iced.rs/\n[documentation]: https://docs.rs/iced/\n[examples]: https://github.com/iced-rs/iced/tree/master/examples#examples\n[Coffee]: https://github.com/hecrj/coffee\n[Elm]: https://elm-lang.org/\n[The Elm Architecture]: https://guide.elm-lang.org/architecture/\n[the current issues]: https://github.com/iced-rs/iced/issues\n[contributing guidelines]: https://github.com/iced-rs/iced/blob/master/CONTRIBUTING.md\n[our Zulip forum]: https://iced.zulipchat.com/\n[our Discord server]: https://discord.gg/3xZJ65GAhd\n[Cryptowatch]: https://cryptowat.ch/charts\n[Kraken.com]: https://kraken.com/\n"
  },
  {
    "path": "ROADMAP.md",
    "content": "# Roadmap\nWe have [a detailed graphical roadmap now](https://whimsical.com/roadmap-iced-7vhq6R35Lp3TmYH4WeYwLM)!\n"
  },
  {
    "path": "beacon/Cargo.toml",
    "content": "[package]\nname = \"iced_beacon\"\ndescription = \"A client/server protocol to monitor and supervise iced applications\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[dependencies]\niced_core.workspace = true\niced_core.features = [\"serde\"]\n\nbincode.workspace = true\nfutures.workspace = true\nlog.workspace = true\nthiserror.workspace = true\n\ntokio.workspace = true\ntokio.features = [\"rt\", \"rt-multi-thread\", \"net\", \"sync\", \"time\", \"io-util\", \"macros\"]\n\nserde.workspace = true\nserde.features = [\"derive\"]\n\nsemver.workspace = true\nsemver.features = [\"serde\"]\n"
  },
  {
    "path": "beacon/src/client.rs",
    "content": "use crate::Error;\nuse crate::core::theme::palette;\nuse crate::core::time::{Duration, SystemTime};\nuse crate::span;\n\nuse semver::Version;\nuse serde::{Deserialize, Serialize};\nuse tokio::io::{self, AsyncReadExt, AsyncWriteExt};\nuse tokio::net;\nuse tokio::sync::{Mutex, mpsc};\nuse tokio::task;\nuse tokio::time;\n\nuse std::sync::Arc;\nuse std::sync::atomic::{self, AtomicBool};\nuse std::thread;\n\n#[derive(Debug, Clone)]\npub struct Client {\n    sender: mpsc::Sender<Action>,\n    is_connected: Arc<AtomicBool>,\n    _handle: Arc<thread::JoinHandle<()>>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub enum Message {\n    Connected {\n        at: SystemTime,\n        name: String,\n        version: Version,\n        theme: Option<palette::Seed>,\n        can_time_travel: bool,\n    },\n    EventLogged {\n        at: SystemTime,\n        event: Event,\n    },\n    Quit {\n        at: SystemTime,\n    },\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub enum Event {\n    ThemeChanged(palette::Seed),\n    SpanStarted(span::Stage),\n    SpanFinished(span::Stage, Duration),\n    MessageLogged { number: usize, message: String },\n    CommandsSpawned(usize),\n    SubscriptionsTracked(usize),\n    LayersRendered(usize),\n}\n\nimpl Client {\n    pub fn log(&self, event: Event) {\n        let _ = self.sender.try_send(Action::Send(Message::EventLogged {\n            at: SystemTime::now(),\n            event,\n        }));\n    }\n\n    pub fn is_connected(&self) -> bool {\n        self.is_connected.load(atomic::Ordering::Relaxed)\n    }\n\n    pub fn quit(&self) {\n        let _ = self.sender.try_send(Action::Send(Message::Quit {\n            at: SystemTime::now(),\n        }));\n    }\n\n    pub fn subscribe(&self) -> mpsc::Receiver<Command> {\n        let (sender, receiver) = mpsc::channel(100);\n        let _ = self.sender.try_send(Action::Forward(sender));\n\n        receiver\n    }\n}\n\n#[derive(Debug, Clone, Default)]\npub struct Metadata {\n    pub name: &'static str,\n    pub theme: Option<palette::Seed>,\n    pub can_time_travel: bool,\n}\n\n#[must_use]\npub fn connect(metadata: Metadata) -> Client {\n    let (sender, receiver) = mpsc::channel(10_000);\n    let is_connected = Arc::new(AtomicBool::new(false));\n\n    let handle = {\n        let is_connected = is_connected.clone();\n\n        std::thread::spawn(move || run(metadata, is_connected, receiver))\n    };\n\n    Client {\n        sender,\n        is_connected,\n        _handle: Arc::new(handle),\n    }\n}\n\nenum Action {\n    Send(Message),\n    Forward(mpsc::Sender<Command>),\n}\n\n#[derive(Debug, Clone, Copy, Serialize, Deserialize)]\npub enum Command {\n    RewindTo { message: usize },\n    GoLive,\n}\n\n#[tokio::main]\nasync fn run(\n    mut metadata: Metadata,\n    is_connected: Arc<AtomicBool>,\n    mut receiver: mpsc::Receiver<Action>,\n) {\n    let version = semver::Version::parse(env!(\"CARGO_PKG_VERSION\")).expect(\"Parse package version\");\n\n    let command_sender = {\n        // Discard by default\n        let (sender, _receiver) = mpsc::channel(1);\n\n        Arc::new(Mutex::new(sender))\n    };\n\n    loop {\n        match _connect().await {\n            Ok(stream) => {\n                is_connected.store(true, atomic::Ordering::Relaxed);\n\n                let (mut reader, mut writer) = stream.into_split();\n\n                let _ = send(\n                    &mut writer,\n                    Message::Connected {\n                        at: SystemTime::now(),\n                        name: metadata.name.to_owned(),\n                        version: version.clone(),\n                        can_time_travel: metadata.can_time_travel,\n                        theme: metadata.theme,\n                    },\n                )\n                .await;\n\n                {\n                    let command_sender = command_sender.clone();\n\n                    drop(task::spawn(async move {\n                        let mut buffer = Vec::new();\n\n                        loop {\n                            match receive(&mut reader, &mut buffer).await {\n                                Ok(command) => {\n                                    match command {\n                                        Command::RewindTo { .. } | Command::GoLive\n                                            if !metadata.can_time_travel =>\n                                        {\n                                            continue;\n                                        }\n                                        _ => {}\n                                    }\n\n                                    let sender = command_sender.lock().await;\n                                    let _ = sender.send(command).await;\n                                }\n                                Err(Error::DecodingFailed(_)) => {}\n                                Err(Error::IOFailed(_)) => break,\n                            }\n                        }\n                    }))\n                };\n\n                while let Some(action) = receiver.recv().await {\n                    match action {\n                        Action::Send(message) => {\n                            if let Message::EventLogged {\n                                event: Event::ThemeChanged(palette),\n                                ..\n                            } = message\n                            {\n                                metadata.theme = Some(palette);\n                            }\n\n                            match send(&mut writer, message).await {\n                                Ok(()) => {}\n                                Err(error) => {\n                                    if error.kind() != io::ErrorKind::BrokenPipe {\n                                        log::warn!(\"Error sending message to server: {error}\");\n                                    }\n\n                                    is_connected.store(false, atomic::Ordering::Relaxed);\n                                    break;\n                                }\n                            }\n                        }\n                        Action::Forward(sender) => {\n                            *command_sender.lock().await = sender;\n                        }\n                    }\n                }\n            }\n            Err(_) => {\n                is_connected.store(false, atomic::Ordering::Relaxed);\n                time::sleep(time::Duration::from_secs(2)).await;\n            }\n        }\n    }\n}\n\n/// Returns the address of the beacon server in this environment.\n///\n/// The value of the `ICED_BEACON_SERVER_ADDRESS` env variable will\n/// be returned, if defined.\n///\n/// Otherwise, a default local server address will be returned.\npub fn server_address_from_env() -> String {\n    const DEFAULT_ADDRESS: &str = \"127.0.0.1:9167\";\n\n    std::env::var(\"ICED_BEACON_SERVER_ADDRESS\").unwrap_or_else(|_| String::from(DEFAULT_ADDRESS))\n}\n\nasync fn _connect() -> Result<net::TcpStream, io::Error> {\n    log::debug!(\"Attempting to connect to server...\");\n    let stream = net::TcpStream::connect(server_address_from_env()).await?;\n\n    stream.set_nodelay(true)?;\n    stream.writable().await?;\n\n    Ok(stream)\n}\n\nasync fn send(stream: &mut net::tcp::OwnedWriteHalf, message: Message) -> Result<(), io::Error> {\n    let bytes = bincode::serialize(&message).expect(\"Encode input message\");\n    let size = bytes.len() as u64;\n\n    stream.write_all(&size.to_be_bytes()).await?;\n    stream.write_all(&bytes).await?;\n    stream.flush().await?;\n\n    Ok(())\n}\n\nasync fn receive(\n    stream: &mut net::tcp::OwnedReadHalf,\n    buffer: &mut Vec<u8>,\n) -> Result<Command, Error> {\n    let size = stream.read_u64().await? as usize;\n\n    if buffer.len() < size {\n        buffer.resize(size, 0);\n    }\n\n    let _n = stream.read_exact(&mut buffer[..size]).await?;\n\n    Ok(bincode::deserialize(buffer)?)\n}\n"
  },
  {
    "path": "beacon/src/error.rs",
    "content": "use std::io;\n\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    #[error(\"input/output operation failed: {0}\")]\n    IOFailed(#[from] io::Error),\n    #[error(\"decoding failed: {0}\")]\n    DecodingFailed(#[from] Box<bincode::ErrorKind>),\n}\n"
  },
  {
    "path": "beacon/src/lib.rs",
    "content": "pub use iced_core as core;\npub use semver::Version;\n\npub mod client;\npub mod span;\n\nmod error;\nmod stream;\n\npub use client::Client;\npub use span::Span;\n\nuse crate::core::theme::palette;\nuse crate::core::time::{Duration, SystemTime};\nuse crate::error::Error;\nuse crate::span::present;\n\nuse futures::{SinkExt, Stream};\nuse tokio::io::{self, AsyncReadExt, AsyncWriteExt};\nuse tokio::net;\nuse tokio::sync::mpsc;\nuse tokio::task;\n\n#[derive(Debug, Clone)]\npub struct Connection {\n    commands: mpsc::Sender<client::Command>,\n}\n\nimpl Connection {\n    pub fn rewind_to<'a>(&self, message: usize) -> impl Future<Output = ()> + 'a {\n        let commands = self.commands.clone();\n\n        async move {\n            let _ = commands.send(client::Command::RewindTo { message }).await;\n        }\n    }\n\n    pub fn go_live<'a>(&self) -> impl Future<Output = ()> + 'a {\n        let commands = self.commands.clone();\n\n        async move {\n            let _ = commands.send(client::Command::GoLive).await;\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum Event {\n    Connected {\n        connection: Connection,\n        at: SystemTime,\n        name: String,\n        version: Version,\n        theme: Option<palette::Seed>,\n        can_time_travel: bool,\n    },\n    Disconnected {\n        at: SystemTime,\n    },\n    ThemeChanged {\n        at: SystemTime,\n        seed: palette::Seed,\n    },\n    SpanFinished {\n        at: SystemTime,\n        duration: Duration,\n        span: Span,\n    },\n    QuitRequested {\n        at: SystemTime,\n    },\n    AlreadyRunning {\n        at: SystemTime,\n    },\n}\n\nimpl Event {\n    pub fn at(&self) -> SystemTime {\n        match self {\n            Self::Connected { at, .. }\n            | Self::Disconnected { at, .. }\n            | Self::ThemeChanged { at, .. }\n            | Self::SpanFinished { at, .. }\n            | Self::QuitRequested { at }\n            | Self::AlreadyRunning { at } => *at,\n        }\n    }\n}\n\npub fn is_running() -> bool {\n    std::net::TcpListener::bind(client::server_address_from_env()).is_err()\n}\n\npub fn run() -> impl Stream<Item = Event> {\n    stream::channel(|mut output| async move {\n        let mut buffer = Vec::new();\n\n        let server = loop {\n            match net::TcpListener::bind(client::server_address_from_env()).await {\n                Ok(server) => break server,\n                Err(error) => {\n                    if error.kind() == io::ErrorKind::AddrInUse {\n                        let _ = output\n                            .send(Event::AlreadyRunning {\n                                at: SystemTime::now(),\n                            })\n                            .await;\n                    }\n                    delay().await;\n                }\n            };\n        };\n\n        loop {\n            let Ok((stream, _)) = server.accept().await else {\n                continue;\n            };\n\n            let (mut reader, mut writer) = {\n                let _ = stream.set_nodelay(true);\n                stream.into_split()\n            };\n\n            let (command_sender, mut command_receiver) = mpsc::channel(1);\n            let mut last_message = String::new();\n            let mut last_update_number = 0;\n            let mut last_tasks = 0;\n            let mut last_subscriptions = 0;\n            let mut last_present_layers = 0;\n            let mut last_prepare = present::Stage::default();\n            let mut last_render = present::Stage::default();\n\n            drop(task::spawn(async move {\n                let mut last_message_number = None;\n\n                while let Some(command) = command_receiver.recv().await {\n                    match command {\n                        client::Command::RewindTo { message } => {\n                            if Some(message) == last_message_number {\n                                continue;\n                            }\n\n                            last_message_number = Some(message);\n                        }\n                        client::Command::GoLive => {\n                            last_message_number = None;\n                        }\n                    }\n\n                    let _ = send(&mut writer, command)\n                        .await\n                        .inspect_err(|error| log::error!(\"Error when sending command: {error}\"));\n                }\n            }));\n\n            loop {\n                match receive(&mut reader, &mut buffer).await {\n                    Ok(message) => {\n                        match message {\n                            client::Message::Connected {\n                                at,\n                                name,\n                                version,\n                                theme,\n                                can_time_travel,\n                            } => {\n                                let _ = output\n                                    .send(Event::Connected {\n                                        connection: Connection {\n                                            commands: command_sender.clone(),\n                                        },\n                                        at,\n                                        name,\n                                        version,\n                                        theme,\n                                        can_time_travel,\n                                    })\n                                    .await;\n                            }\n                            client::Message::EventLogged { at, event } => match event {\n                                client::Event::ThemeChanged(seed) => {\n                                    let _ = output.send(Event::ThemeChanged { at, seed }).await;\n                                }\n                                client::Event::SubscriptionsTracked(amount_alive) => {\n                                    last_subscriptions = amount_alive;\n                                }\n                                client::Event::MessageLogged { number, message } => {\n                                    last_update_number = number;\n                                    last_message = message;\n                                }\n                                client::Event::CommandsSpawned(commands) => {\n                                    last_tasks = commands;\n                                }\n                                client::Event::LayersRendered(layers) => {\n                                    last_present_layers = layers;\n                                }\n                                client::Event::SpanStarted(span::Stage::Update) => {\n                                    last_message.clear();\n                                    last_tasks = 0;\n                                }\n                                client::Event::SpanStarted(_) => {}\n                                client::Event::SpanFinished(stage, duration) => {\n                                    let span = match stage {\n                                        span::Stage::Boot => Span::Boot,\n                                        span::Stage::Update => Span::Update {\n                                            number: last_update_number,\n                                            message: last_message.clone(),\n                                            tasks: last_tasks,\n                                            subscriptions: last_subscriptions,\n                                        },\n                                        span::Stage::View(window) => Span::View { window },\n                                        span::Stage::Layout(window) => Span::Layout { window },\n                                        span::Stage::Interact(window) => Span::Interact { window },\n                                        span::Stage::Draw(window) => Span::Draw { window },\n                                        span::Stage::Prepare(primitive)\n                                        | span::Stage::Render(primitive) => {\n                                            let stage = if matches!(stage, span::Stage::Prepare(_),)\n                                            {\n                                                &mut last_prepare\n                                            } else {\n                                                &mut last_render\n                                            };\n\n                                            let primitive = match primitive {\n                                                present::Primitive::Quad => &mut stage.quads,\n                                                present::Primitive::Triangle => {\n                                                    &mut stage.triangles\n                                                }\n                                                present::Primitive::Shader => &mut stage.shaders,\n                                                present::Primitive::Text => &mut stage.text,\n                                                present::Primitive::Image => &mut stage.images,\n                                            };\n\n                                            *primitive += duration;\n\n                                            continue;\n                                        }\n                                        span::Stage::Present(window) => {\n                                            let span = Span::Present {\n                                                window,\n                                                prepare: last_prepare,\n                                                render: last_render,\n                                                layers: last_present_layers,\n                                            };\n\n                                            last_prepare = present::Stage::default();\n                                            last_render = present::Stage::default();\n                                            last_present_layers = 0;\n\n                                            span\n                                        }\n                                        span::Stage::Custom(name) => Span::Custom { name },\n                                    };\n\n                                    let _ = output\n                                        .send(Event::SpanFinished { at, duration, span })\n                                        .await;\n                                }\n                            },\n                            client::Message::Quit { at } => {\n                                let _ = output.send(Event::QuitRequested { at }).await;\n                            }\n                        };\n                    }\n                    Err(Error::IOFailed(_)) => {\n                        let _ = output\n                            .send(Event::Disconnected {\n                                at: SystemTime::now(),\n                            })\n                            .await;\n                        break;\n                    }\n                    Err(Error::DecodingFailed(error)) => {\n                        log::warn!(\"Error decoding beacon output: {error}\")\n                    }\n                }\n            }\n        }\n    })\n}\n\nasync fn receive(\n    stream: &mut net::tcp::OwnedReadHalf,\n    buffer: &mut Vec<u8>,\n) -> Result<client::Message, Error> {\n    let size = stream.read_u64().await? as usize;\n\n    if buffer.len() < size {\n        buffer.resize(size, 0);\n    }\n\n    let _n = stream.read_exact(&mut buffer[..size]).await?;\n\n    Ok(bincode::deserialize(buffer)?)\n}\n\nasync fn send(\n    stream: &mut net::tcp::OwnedWriteHalf,\n    command: client::Command,\n) -> Result<(), io::Error> {\n    let bytes = bincode::serialize(&command).expect(\"Encode input message\");\n    let size = bytes.len() as u64;\n\n    stream.write_all(&size.to_be_bytes()).await?;\n    stream.write_all(&bytes).await?;\n    stream.flush().await?;\n\n    Ok(())\n}\n\nasync fn delay() {\n    tokio::time::sleep(Duration::from_secs(2)).await;\n}\n"
  },
  {
    "path": "beacon/src/span.rs",
    "content": "use crate::core::window;\n\nuse serde::{Deserialize, Serialize};\n\n#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub enum Span {\n    Boot,\n    Update {\n        number: usize,\n        message: String,\n        tasks: usize,\n        subscriptions: usize,\n    },\n    View {\n        window: window::Id,\n    },\n    Layout {\n        window: window::Id,\n    },\n    Interact {\n        window: window::Id,\n    },\n    Draw {\n        window: window::Id,\n    },\n    Present {\n        window: window::Id,\n        prepare: present::Stage,\n        render: present::Stage,\n        layers: usize,\n    },\n    Custom {\n        name: String,\n    },\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]\npub enum Stage {\n    Boot,\n    Update,\n    View(window::Id),\n    Layout(window::Id),\n    Interact(window::Id),\n    Draw(window::Id),\n    Present(window::Id),\n    Prepare(present::Primitive),\n    Render(present::Primitive),\n    Custom(String),\n}\n\nimpl std::fmt::Display for Stage {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_str(match self {\n            Stage::Boot => \"Boot\",\n            Stage::Update => \"Update\",\n            Stage::View(_) => \"View\",\n            Stage::Layout(_) => \"Layout\",\n            Stage::Interact(_) => \"Interact\",\n            Stage::Draw(_) => \"Draw\",\n            Stage::Prepare(_) => \"Prepare\",\n            Stage::Render(_) => \"Render\",\n            Stage::Present(_) => \"Present\",\n            Stage::Custom(name) => name,\n        })\n    }\n}\n\npub mod present {\n    use crate::core::time::Duration;\n\n    use serde::{Deserialize, Serialize};\n\n    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]\n    pub struct Stage {\n        pub quads: Duration,\n        pub triangles: Duration,\n        pub shaders: Duration,\n        pub text: Duration,\n        pub images: Duration,\n    }\n\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]\n    pub enum Primitive {\n        Quad,\n        Triangle,\n        Shader,\n        Text,\n        Image,\n    }\n}\n"
  },
  {
    "path": "beacon/src/stream.rs",
    "content": "use futures::Future;\nuse futures::channel::mpsc;\nuse futures::stream::{self, Stream, StreamExt};\n\npub fn channel<T, F>(f: impl Fn(mpsc::Sender<T>) -> F) -> impl Stream<Item = T>\nwhere\n    F: Future<Output = ()>,\n{\n    let (sender, receiver) = mpsc::channel(1);\n\n    stream::select(\n        receiver,\n        stream::once(f(sender)).filter_map(|_| async { None }),\n    )\n}\n"
  },
  {
    "path": "benches/ipsum.txt",
    "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at elit mollis, dictum nunc non, tempus metus. Sed iaculis ac mauris eu lobortis. Integer elementum venenatis eros, id placerat odio feugiat vel. Maecenas consequat convallis tincidunt. Nunc eu lorem justo. Praesent quis ornare sapien. Aliquam interdum tortor ut rhoncus faucibus. Suspendisse molestie scelerisque nulla, eget sodales lacus sodales vel. Nunc placerat id arcu sodales venenatis. Praesent ullamcorper viverra nibh eget efficitur. Aliquam molestie felis vehicula, finibus sapien eget, accumsan purus. Praesent vestibulum eleifend consectetur. Sed tincidunt lectus a libero efficitur, non scelerisque lectus tincidunt.\n\nCras ullamcorper tincidunt tellus non tempor. Integer pulvinar turpis quam, nec pharetra purus egestas non. Vivamus sed ipsum consequat, dignissim ante et, suscipit nibh. Quisque et mauris eu erat rutrum cursus. Pellentesque ut neque eu neque eleifend auctor ac hendrerit dolor. Morbi eget egestas ex. Integer hendrerit ipsum in enim bibendum, at vehicula ipsum dapibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce tempus consectetur tortor, vel fermentum sem pulvinar eget. Maecenas rutrum fringilla eros a pellentesque. Cras quis magna consectetur, tristique massa vel, aliquet nunc. Aliquam erat volutpat. Suspendisse porttitor risus id auctor fermentum. Vivamus efficitur tellus sed tortor cursus tincidunt. Sed auctor varius arcu, non congue tellus vehicula finibus.\n\nFusce a tincidunt urna. Nunc at quam ac enim tempor vehicula imperdiet in sapien. Donec lobortis tristique felis vel semper. Quisque vulputate felis eu enim vestibulum malesuada. Fusce a lobortis mauris, iaculis eleifend ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus sodales vel elit dignissim mattis.\n\nAliquam placerat vulputate dignissim. Proin pellentesque vitae arcu ut feugiat. Nunc mi felis, ornare at gravida sed, vestibulum sed urna. Duis fermentum maximus viverra. Donec imperdiet pellentesque sollicitudin. Cras non sem quis metus bibendum molestie. Duis imperdiet nec lectus eu rutrum. Mauris congue enim purus, in iaculis arcu dapibus ut. Nullam id erat tincidunt, iaculis dolor non, lobortis magna. Proin convallis scelerisque maximus. Morbi at lorem fringilla libero blandit fringilla. Ut aliquet tellus non sem dictum viverra. Aenean venenatis purus eget lacus placerat, non mollis mauris pellentesque.\n\nEtiam elit diam, aliquet quis suscipit non, condimentum viverra odio. Praesent mi enim, suscipit id mi in, rhoncus ultricies lorem. Nulla facilisi. Integer convallis sagittis euismod. Vestibulum porttitor sodales turpis ac accumsan. Nullam molestie turpis vel lacus tincidunt, sed finibus erat pharetra. Nullam vestibulum turpis id sollicitudin accumsan. Praesent eget posuere lacus. Donec vehicula, nisl nec suscipit porta, felis lorem gravida orci, a hendrerit tellus nibh sit amet elit.\n"
  },
  {
    "path": "benches/wgpu.rs",
    "content": "#![allow(missing_docs)]\nuse criterion::{Bencher, Criterion, criterion_group, criterion_main};\n\nuse iced::alignment;\nuse iced::mouse;\nuse iced::widget::{canvas, scrollable, stack, text};\nuse iced::{Color, Element, Font, Length, Pixels, Point, Rectangle, Size, Theme};\nuse iced_wgpu::Renderer;\nuse iced_wgpu::wgpu;\n\ncriterion_main!(benches);\ncriterion_group!(benches, wgpu_benchmark);\n\n#[allow(unused_results)]\npub fn wgpu_benchmark(c: &mut Criterion) {\n    use iced_futures::futures::executor;\n    use iced_wgpu::wgpu;\n\n    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {\n        backends: wgpu::Backends::all(),\n        ..Default::default()\n    });\n\n    let adapter = executor::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {\n        power_preference: wgpu::PowerPreference::HighPerformance,\n        compatible_surface: None,\n        force_fallback_adapter: false,\n    }))\n    .expect(\"request adapter\");\n\n    let (device, queue) = executor::block_on(adapter.request_device(&wgpu::DeviceDescriptor {\n        label: None,\n        required_features: wgpu::Features::empty(),\n        required_limits: wgpu::Limits::default(),\n        memory_hints: wgpu::MemoryHints::MemoryUsage,\n        trace: wgpu::Trace::Off,\n        experimental_features: wgpu::ExperimentalFeatures::disabled(),\n    }))\n    .expect(\"request device\");\n\n    c.bench_function(\"wgpu — canvas (light)\", |b| {\n        benchmark(b, &adapter, &device, &queue, |_| scene(10));\n    });\n    c.bench_function(\"wgpu — canvas (heavy)\", |b| {\n        benchmark(b, &adapter, &device, &queue, |_| scene(1_000));\n    });\n\n    c.bench_function(\"wgpu - layered text (light)\", |b| {\n        benchmark(b, &adapter, &device, &queue, |_| layered_text(10));\n    });\n    c.bench_function(\"wgpu - layered text (heavy)\", |b| {\n        benchmark(b, &adapter, &device, &queue, |_| layered_text(1_000));\n    });\n\n    c.bench_function(\"wgpu - dynamic text (light)\", |b| {\n        benchmark(b, &adapter, &device, &queue, |i| dynamic_text(1_000, i));\n    });\n    c.bench_function(\"wgpu - dynamic text (heavy)\", |b| {\n        benchmark(b, &adapter, &device, &queue, |i| dynamic_text(100_000, i));\n    });\n\n    c.bench_function(\"wgpu - advanced shaping (light)\", |b| {\n        benchmark(b, &adapter, &device, &queue, |i| advanced_shaping(1_000, i));\n    });\n    c.bench_function(\"wgpu - advanced shaping (heavy)\", |b| {\n        benchmark(b, &adapter, &device, &queue, |i| {\n            advanced_shaping(100_000, i)\n        });\n    });\n}\n\nfn benchmark<'a>(\n    bencher: &mut Bencher<'_>,\n    adapter: &wgpu::Adapter,\n    device: &wgpu::Device,\n    queue: &wgpu::Queue,\n    view: impl Fn(usize) -> Element<'a, (), Theme, Renderer>,\n) {\n    use iced_wgpu::graphics;\n    use iced_wgpu::graphics::{Antialiasing, Shell};\n    use iced_wgpu::wgpu;\n    use iced_winit::core;\n    use iced_winit::core::renderer;\n    use iced_winit::runtime;\n\n    let format = wgpu::TextureFormat::Bgra8UnormSrgb;\n\n    let engine = iced_wgpu::Engine::new(\n        adapter,\n        device.clone(),\n        queue.clone(),\n        format,\n        Some(Antialiasing::MSAAx4),\n        Shell::headless(),\n    );\n\n    let mut renderer = Renderer::new(engine, renderer::Settings::default());\n\n    let viewport = graphics::Viewport::with_physical_size(Size::new(3840, 2160), 2.0);\n\n    let texture = device.create_texture(&wgpu::TextureDescriptor {\n        label: None,\n        size: wgpu::Extent3d {\n            width: 3840,\n            height: 2160,\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: wgpu::TextureUsages::RENDER_ATTACHMENT,\n        view_formats: &[],\n    });\n\n    let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());\n\n    let mut i = 0;\n    let mut cache = Some(runtime::user_interface::Cache::default());\n\n    bencher.iter(|| {\n        let mut user_interface = runtime::UserInterface::build(\n            view(i),\n            viewport.logical_size(),\n            cache.take().unwrap(),\n            &mut renderer,\n        );\n\n        user_interface.draw(\n            &mut renderer,\n            &Theme::Dark,\n            &core::renderer::Style {\n                text_color: Color::WHITE,\n            },\n            mouse::Cursor::Unavailable,\n        );\n\n        cache = Some(user_interface.into_cache());\n\n        let submission = renderer.present(Some(Color::BLACK), format, &texture_view, &viewport);\n\n        let _ = device.poll(wgpu::PollType::Wait {\n            submission_index: Some(submission),\n            timeout: None,\n        });\n\n        i += 1;\n    });\n}\n\nfn scene<'a, Message: 'a>(n: usize) -> Element<'a, Message, Theme, Renderer> {\n    struct Scene {\n        n: usize,\n    }\n\n    impl<Message, Theme> canvas::Program<Message, Theme, Renderer> for Scene {\n        type State = canvas::Cache<Renderer>;\n\n        fn draw(\n            &self,\n            cache: &Self::State,\n            renderer: &Renderer,\n            _theme: &Theme,\n            bounds: Rectangle,\n            _cursor: mouse::Cursor,\n        ) -> Vec<canvas::Geometry<Renderer>> {\n            vec![cache.draw(renderer, bounds.size(), |frame| {\n                for i in 0..self.n {\n                    frame.fill_rectangle(\n                        Point::new(0.0, i as f32),\n                        Size::new(10.0, 10.0),\n                        Color::WHITE,\n                    );\n                }\n\n                for i in 0..self.n {\n                    frame.fill_text(canvas::Text {\n                        content: i.to_string(),\n                        position: Point::new(0.0, i as f32),\n                        color: Color::BLACK,\n                        size: Pixels::from(16),\n                        line_height: text::LineHeight::default(),\n                        font: Font::DEFAULT,\n                        align_x: text::Alignment::Left,\n                        align_y: alignment::Vertical::Top,\n                        shaping: text::Shaping::Basic,\n                        wrapping: text::Wrapping::default(),\n                        ellipsis: text::Ellipsis::default(),\n                        max_width: f32::INFINITY,\n                    });\n                }\n            })]\n        }\n    }\n\n    canvas(Scene { n })\n        .width(Length::Fill)\n        .height(Length::Fill)\n        .into()\n}\n\nfn layered_text<'a, Message: 'a>(n: usize) -> Element<'a, Message, Theme, Renderer> {\n    stack((0..n).map(|i| text!(\"I am paragraph {i}!\").into()))\n        .width(Length::Fill)\n        .height(Length::Fill)\n        .into()\n}\n\nfn dynamic_text<'a, Message: 'a>(n: usize, i: usize) -> Element<'a, Message, Theme, Renderer> {\n    const LOREM_IPSUM: &str = include_str!(\"ipsum.txt\");\n\n    scrollable(\n        text!(\n            \"{}... Iteration {i}\",\n            std::iter::repeat(LOREM_IPSUM.chars())\n                .flatten()\n                .take(n)\n                .collect::<String>(),\n        )\n        .size(10),\n    )\n    .into()\n}\n\nfn advanced_shaping<'a, Message: 'a>(n: usize, i: usize) -> Element<'a, Message, Theme, Renderer> {\n    const LOREM_IPSUM: &str = include_str!(\"ipsum.txt\");\n\n    scrollable(\n        text!(\n            \"{}... Iteration {i} 😎\",\n            std::iter::repeat(LOREM_IPSUM.chars())\n                .flatten()\n                .take(n)\n                .collect::<String>(),\n        )\n        .shaping(text::Shaping::Advanced)\n        .size(10),\n    )\n    .into()\n}\n"
  },
  {
    "path": "clippy.toml",
    "content": "too-many-arguments-threshold = 20\nenum-variant-name-threshold = 10\n"
  },
  {
    "path": "core/Cargo.toml",
    "content": "[package]\nname = \"iced_core\"\ndescription = \"The essential ideas of iced\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[features]\nadvanced = []\ncrisp = []\nimage = []\nbasic-shaping = []\nadvanced-shaping = []\n\n[dependencies]\nbitflags.workspace = true\nbytes.workspace = true\nglam.workspace = true\nlilt.workspace = true\nlog.workspace = true\nnum-traits.workspace = true\nrustc-hash.workspace = true\nsmol_str.workspace = true\nthiserror.workspace = true\nweb-time.workspace = true\n\nserde.workspace = true\nserde.optional = true\nserde.features = [\"derive\"]\n"
  },
  {
    "path": "core/README.md",
    "content": "# `iced_core`\n[![Documentation](https://docs.rs/iced_core/badge.svg)][documentation]\n[![Crates.io](https://img.shields.io/crates/v/iced_core.svg)](https://crates.io/crates/iced_core)\n[![License](https://img.shields.io/crates/l/iced_core.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)\n[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)\n\n`iced_core` holds basic reusable types of the public API. For instance, basic data types like `Point`, `Rectangle`, `Length`, etc.\n\nThis crate is meant to be a starting point for an Iced runtime.\n\n<p align=\"center\">\n  <img alt=\"The foundations\" src=\"../docs/graphs/foundations.png\" width=\"50%\">\n</p>\n\n[documentation]: https://docs.rs/iced_core\n"
  },
  {
    "path": "core/src/alignment.rs",
    "content": "//! Align and position widgets.\n\n/// Alignment on the axis of a container.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum Alignment {\n    /// Align at the start of the axis.\n    Start,\n\n    /// Align at the center of the axis.\n    Center,\n\n    /// Align at the end of the axis.\n    End,\n}\n\nimpl From<Horizontal> for Alignment {\n    fn from(horizontal: Horizontal) -> Self {\n        match horizontal {\n            Horizontal::Left => Self::Start,\n            Horizontal::Center => Self::Center,\n            Horizontal::Right => Self::End,\n        }\n    }\n}\n\nimpl From<Vertical> for Alignment {\n    fn from(vertical: Vertical) -> Self {\n        match vertical {\n            Vertical::Top => Self::Start,\n            Vertical::Center => Self::Center,\n            Vertical::Bottom => Self::End,\n        }\n    }\n}\n\n/// The horizontal [`Alignment`] of some resource.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum Horizontal {\n    /// Align left\n    Left,\n\n    /// Horizontally centered\n    Center,\n\n    /// Align right\n    Right,\n}\n\nimpl From<Alignment> for Horizontal {\n    fn from(alignment: Alignment) -> Self {\n        match alignment {\n            Alignment::Start => Self::Left,\n            Alignment::Center => Self::Center,\n            Alignment::End => Self::Right,\n        }\n    }\n}\n\n/// The vertical [`Alignment`] of some resource.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum Vertical {\n    /// Align top\n    Top,\n\n    /// Vertically centered\n    Center,\n\n    /// Align bottom\n    Bottom,\n}\n\nimpl From<Alignment> for Vertical {\n    fn from(alignment: Alignment) -> Self {\n        match alignment {\n            Alignment::Start => Self::Top,\n            Alignment::Center => Self::Center,\n            Alignment::End => Self::Bottom,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/angle.rs",
    "content": "use crate::{Point, Rectangle, Vector};\n\nuse std::f32::consts::{FRAC_PI_2, PI};\nuse std::fmt::Display;\nuse std::ops::{Add, AddAssign, Div, Mul, RangeInclusive, Rem, Sub, SubAssign};\n\n/// Degrees\n#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]\npub struct Degrees(pub f32);\n\nimpl Degrees {\n    /// The range of degrees of a circle.\n    pub const RANGE: RangeInclusive<Self> = Self(0.0)..=Self(360.0);\n}\n\nimpl PartialEq<f32> for Degrees {\n    fn eq(&self, other: &f32) -> bool {\n        self.0.eq(other)\n    }\n}\n\nimpl PartialOrd<f32> for Degrees {\n    fn partial_cmp(&self, other: &f32) -> Option<std::cmp::Ordering> {\n        self.0.partial_cmp(other)\n    }\n}\n\nimpl From<f32> for Degrees {\n    fn from(degrees: f32) -> Self {\n        Self(degrees)\n    }\n}\n\nimpl From<u8> for Degrees {\n    fn from(degrees: u8) -> Self {\n        Self(f32::from(degrees))\n    }\n}\n\nimpl From<Degrees> for f32 {\n    fn from(degrees: Degrees) -> Self {\n        degrees.0\n    }\n}\n\nimpl From<Degrees> for f64 {\n    fn from(degrees: Degrees) -> Self {\n        Self::from(degrees.0)\n    }\n}\n\nimpl Mul<f32> for Degrees {\n    type Output = Degrees;\n\n    fn mul(self, rhs: f32) -> Self::Output {\n        Self(self.0 * rhs)\n    }\n}\n\nimpl num_traits::FromPrimitive for Degrees {\n    fn from_i64(n: i64) -> Option<Self> {\n        Some(Self(n as f32))\n    }\n\n    fn from_u64(n: u64) -> Option<Self> {\n        Some(Self(n as f32))\n    }\n\n    fn from_f64(n: f64) -> Option<Self> {\n        Some(Self(n as f32))\n    }\n}\n\n/// Radians\n#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]\npub struct Radians(pub f32);\n\nimpl Radians {\n    /// The range of radians of a circle.\n    pub const RANGE: RangeInclusive<Self> = Self(0.0)..=Self(2.0 * PI);\n\n    /// The amount of radians in half a circle.\n    pub const PI: Self = Self(PI);\n\n    /// Calculates the line in which the angle intercepts the `bounds`.\n    pub fn to_distance(&self, bounds: &Rectangle) -> (Point, Point) {\n        let angle = self.0 - FRAC_PI_2;\n        let r = Vector::new(f32::cos(angle), f32::sin(angle));\n\n        let distance_to_rect = f32::max(\n            f32::abs(r.x * bounds.width / 2.0),\n            f32::abs(r.y * bounds.height / 2.0),\n        );\n\n        let start = bounds.center() - r * distance_to_rect;\n        let end = bounds.center() + r * distance_to_rect;\n\n        (start, end)\n    }\n}\n\nimpl From<Degrees> for Radians {\n    fn from(degrees: Degrees) -> Self {\n        Self(degrees.0 * PI / 180.0)\n    }\n}\n\nimpl From<f32> for Radians {\n    fn from(radians: f32) -> Self {\n        Self(radians)\n    }\n}\n\nimpl From<u8> for Radians {\n    fn from(radians: u8) -> Self {\n        Self(f32::from(radians))\n    }\n}\n\nimpl From<Radians> for f32 {\n    fn from(radians: Radians) -> Self {\n        radians.0\n    }\n}\n\nimpl From<Radians> for f64 {\n    fn from(radians: Radians) -> Self {\n        Self::from(radians.0)\n    }\n}\n\nimpl num_traits::FromPrimitive for Radians {\n    fn from_i64(n: i64) -> Option<Self> {\n        Some(Self(n as f32))\n    }\n\n    fn from_u64(n: u64) -> Option<Self> {\n        Some(Self(n as f32))\n    }\n\n    fn from_f64(n: f64) -> Option<Self> {\n        Some(Self(n as f32))\n    }\n}\n\nimpl Sub for Radians {\n    type Output = Self;\n\n    fn sub(self, rhs: Self) -> Self::Output {\n        Self(self.0 - rhs.0)\n    }\n}\n\nimpl SubAssign for Radians {\n    fn sub_assign(&mut self, rhs: Self) {\n        self.0 = self.0 - rhs.0;\n    }\n}\n\nimpl Add for Radians {\n    type Output = Self;\n\n    fn add(self, rhs: Self) -> Self::Output {\n        Self(self.0 + rhs.0)\n    }\n}\n\nimpl Add<Degrees> for Radians {\n    type Output = Self;\n\n    fn add(self, rhs: Degrees) -> Self::Output {\n        Self(self.0 + rhs.0.to_radians())\n    }\n}\n\nimpl AddAssign for Radians {\n    fn add_assign(&mut self, rhs: Radians) {\n        self.0 = self.0 + rhs.0;\n    }\n}\n\nimpl Mul for Radians {\n    type Output = Self;\n\n    fn mul(self, rhs: Radians) -> Self::Output {\n        Radians(self.0 * rhs.0)\n    }\n}\n\nimpl Mul<f32> for Radians {\n    type Output = Self;\n\n    fn mul(self, rhs: f32) -> Self::Output {\n        Self(self.0 * rhs)\n    }\n}\n\nimpl Mul<Radians> for f32 {\n    type Output = Radians;\n\n    fn mul(self, rhs: Radians) -> Self::Output {\n        Radians(self * rhs.0)\n    }\n}\n\nimpl Div<f32> for Radians {\n    type Output = Self;\n\n    fn div(self, rhs: f32) -> Self::Output {\n        Radians(self.0 / rhs)\n    }\n}\n\nimpl Div for Radians {\n    type Output = Self;\n\n    fn div(self, rhs: Self) -> Self::Output {\n        Self(self.0 / rhs.0)\n    }\n}\n\nimpl Rem for Radians {\n    type Output = Self;\n\n    fn rem(self, rhs: Self) -> Self::Output {\n        Self(self.0 % rhs.0)\n    }\n}\n\nimpl PartialEq<f32> for Radians {\n    fn eq(&self, other: &f32) -> bool {\n        self.0.eq(other)\n    }\n}\n\nimpl PartialOrd<f32> for Radians {\n    fn partial_cmp(&self, other: &f32) -> Option<std::cmp::Ordering> {\n        self.0.partial_cmp(other)\n    }\n}\n\nimpl Display for Radians {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{} rad\", self.0)\n    }\n}\n"
  },
  {
    "path": "core/src/animation.rs",
    "content": "//! Animate your applications.\nuse crate::time::{Duration, Instant};\n\npub use lilt::{Easing, FloatRepresentable as Float, Interpolable};\n\n/// The animation of some particular state.\n///\n/// It tracks state changes and allows projecting interpolated values\n/// through time.\n#[derive(Debug, Clone)]\npub struct Animation<T>\nwhere\n    T: Clone + Copy + PartialEq + Float,\n{\n    raw: lilt::Animated<T, Instant>,\n    duration: Duration, // TODO: Expose duration getter in `lilt`\n}\n\nimpl<T> Animation<T>\nwhere\n    T: Clone + Copy + PartialEq + Float,\n{\n    /// Creates a new [`Animation`] with the given initial state.\n    pub fn new(state: T) -> Self {\n        Self {\n            raw: lilt::Animated::new(state),\n            duration: Duration::from_millis(100),\n        }\n    }\n\n    /// Sets the [`Easing`] function of the [`Animation`].\n    ///\n    /// See the [Easing Functions Cheat Sheet](https://easings.net) for\n    /// details!\n    pub fn easing(mut self, easing: Easing) -> Self {\n        self.raw = self.raw.easing(easing);\n        self\n    }\n\n    /// Sets the duration of the [`Animation`] to 100ms.\n    pub fn very_quick(self) -> Self {\n        self.duration(Duration::from_millis(100))\n    }\n\n    /// Sets the duration of the [`Animation`] to 200ms.\n    pub fn quick(self) -> Self {\n        self.duration(Duration::from_millis(200))\n    }\n\n    /// Sets the duration of the [`Animation`] to 400ms.\n    pub fn slow(self) -> Self {\n        self.duration(Duration::from_millis(400))\n    }\n\n    /// Sets the duration of the [`Animation`] to 500ms.\n    pub fn very_slow(self) -> Self {\n        self.duration(Duration::from_millis(500))\n    }\n\n    /// Sets the duration of the [`Animation`] to the given value.\n    pub fn duration(mut self, duration: Duration) -> Self {\n        self.raw = self.raw.duration(duration.as_secs_f32() * 1_000.0);\n        self.duration = duration;\n        self\n    }\n\n    /// Sets a delay for the [`Animation`].\n    pub fn delay(mut self, duration: Duration) -> Self {\n        self.raw = self.raw.delay(duration.as_secs_f64() as f32 * 1000.0);\n        self\n    }\n\n    /// Makes the [`Animation`] repeat a given amount of times.\n    ///\n    /// Providing 1 repetition plays the animation twice in total.\n    pub fn repeat(mut self, repetitions: u32) -> Self {\n        self.raw = self.raw.repeat(repetitions);\n        self\n    }\n\n    /// Makes the [`Animation`] repeat forever.\n    pub fn repeat_forever(mut self) -> Self {\n        self.raw = self.raw.repeat_forever();\n        self\n    }\n\n    /// Makes the [`Animation`] automatically reverse when repeating.\n    pub fn auto_reverse(mut self) -> Self {\n        self.raw = self.raw.auto_reverse();\n        self\n    }\n\n    /// Transitions the [`Animation`] from its current state to the given new state\n    /// at the given time.\n    pub fn go(mut self, new_state: T, at: Instant) -> Self {\n        self.go_mut(new_state, at);\n        self\n    }\n\n    /// Transitions the [`Animation`] from its current state to the given new state\n    /// at the given time, by reference.\n    pub fn go_mut(&mut self, new_state: T, at: Instant) {\n        self.raw.transition(new_state, at);\n    }\n\n    /// Returns true if the [`Animation`] is currently in progress.\n    ///\n    /// An [`Animation`] is in progress when it is transitioning to a different state.\n    pub fn is_animating(&self, at: Instant) -> bool {\n        self.raw.in_progress(at)\n    }\n\n    /// Projects the [`Animation`] into an interpolated value at the given [`Instant`]; using the\n    /// closure provided to calculate the different keyframes of interpolated values.\n    ///\n    /// If the [`Animation`] state is a `bool`, you can use the simpler [`interpolate`] method.\n    ///\n    /// [`interpolate`]: Animation::interpolate\n    pub fn interpolate_with<I>(&self, f: impl Fn(T) -> I, at: Instant) -> I\n    where\n        I: Interpolable,\n    {\n        self.raw.animate(f, at)\n    }\n\n    /// Retuns the current state of the [`Animation`].\n    pub fn value(&self) -> T {\n        self.raw.value\n    }\n}\n\nimpl Animation<bool> {\n    /// Projects the [`Animation`] into an interpolated value at the given [`Instant`]; using the\n    /// `start` and `end` values as the origin and destination keyframes.\n    pub fn interpolate<I>(&self, start: I, end: I, at: Instant) -> I\n    where\n        I: Interpolable + Clone,\n    {\n        self.raw.animate_bool(start, end, at)\n    }\n\n    /// Returns the remaining [`Duration`] of the [`Animation`].\n    pub fn remaining(&self, at: Instant) -> Duration {\n        Duration::from_secs_f32(self.interpolate(self.duration.as_secs_f32(), 0.0, at))\n    }\n}\n"
  },
  {
    "path": "core/src/background.rs",
    "content": "use crate::Color;\nuse crate::gradient::{self, Gradient};\n\n/// The background of some element.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Background {\n    /// A solid color.\n    Color(Color),\n    /// Linearly interpolate between several colors.\n    Gradient(Gradient),\n    // TODO: Add image variant\n}\n\nimpl Background {\n    /// Scales the alpha channel of the [`Background`] by the given\n    /// factor.\n    pub fn scale_alpha(self, factor: f32) -> Self {\n        match self {\n            Self::Color(color) => Self::Color(color.scale_alpha(factor)),\n            Self::Gradient(gradient) => Self::Gradient(gradient.scale_alpha(factor)),\n        }\n    }\n}\n\nimpl From<Color> for Background {\n    fn from(color: Color) -> Self {\n        Background::Color(color)\n    }\n}\n\nimpl From<Gradient> for Background {\n    fn from(gradient: Gradient) -> Self {\n        Background::Gradient(gradient)\n    }\n}\n\nimpl From<gradient::Linear> for Background {\n    fn from(gradient: gradient::Linear) -> Self {\n        Background::Gradient(Gradient::Linear(gradient))\n    }\n}\n"
  },
  {
    "path": "core/src/border.rs",
    "content": "//! Draw lines around containers.\nuse crate::{Color, Pixels};\n\n/// A border.\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub struct Border {\n    /// The color of the border.\n    pub color: Color,\n\n    /// The width of the border.\n    pub width: f32,\n\n    /// The [`Radius`] of the border.\n    pub radius: Radius,\n}\n\n/// Creates a new [`Border`] with the given [`Radius`].\n///\n/// ```\n/// # use iced_core::border::{self, Border};\n/// #\n/// assert_eq!(border::rounded(10), Border::default().rounded(10));\n/// ```\npub fn rounded(radius: impl Into<Radius>) -> Border {\n    Border::default().rounded(radius)\n}\n\n/// Creates a new [`Border`] with the given [`Color`].\n///\n/// ```\n/// # use iced_core::border::{self, Border};\n/// # use iced_core::Color;\n/// #\n/// assert_eq!(border::color(Color::BLACK), Border::default().color(Color::BLACK));\n/// ```\npub fn color(color: impl Into<Color>) -> Border {\n    Border::default().color(color)\n}\n\n/// Creates a new [`Border`] with the given `width`.\n///\n/// ```\n/// # use iced_core::border::{self, Border};\n/// # use iced_core::Color;\n/// #\n/// assert_eq!(border::width(10), Border::default().width(10));\n/// ```\npub fn width(width: impl Into<Pixels>) -> Border {\n    Border::default().width(width)\n}\n\nimpl Border {\n    /// Sets the [`Color`] of the [`Border`].\n    pub fn color(self, color: impl Into<Color>) -> Self {\n        Self {\n            color: color.into(),\n            ..self\n        }\n    }\n\n    /// Sets the [`Radius`] of the [`Border`].\n    pub fn rounded(self, radius: impl Into<Radius>) -> Self {\n        Self {\n            radius: radius.into(),\n            ..self\n        }\n    }\n\n    /// Sets the width of the [`Border`].\n    pub fn width(self, width: impl Into<Pixels>) -> Self {\n        Self {\n            width: width.into().0,\n            ..self\n        }\n    }\n}\n\n/// The border radii for the corners of a graphics primitive in the order:\n/// top-left, top-right, bottom-right, bottom-left.\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub struct Radius {\n    /// Top left radius\n    pub top_left: f32,\n    /// Top right radius\n    pub top_right: f32,\n    /// Bottom right radius\n    pub bottom_right: f32,\n    /// Bottom left radius\n    pub bottom_left: f32,\n}\n\n/// Creates a new [`Radius`] with the same value for each corner.\npub fn radius(value: impl Into<Pixels>) -> Radius {\n    Radius::new(value)\n}\n\n/// Creates a new [`Radius`] with the given top left value.\npub fn top_left(value: impl Into<Pixels>) -> Radius {\n    Radius::default().top_left(value)\n}\n\n/// Creates a new [`Radius`] with the given top right value.\npub fn top_right(value: impl Into<Pixels>) -> Radius {\n    Radius::default().top_right(value)\n}\n\n/// Creates a new [`Radius`] with the given bottom right value.\npub fn bottom_right(value: impl Into<Pixels>) -> Radius {\n    Radius::default().bottom_right(value)\n}\n\n/// Creates a new [`Radius`] with the given bottom left value.\npub fn bottom_left(value: impl Into<Pixels>) -> Radius {\n    Radius::default().bottom_left(value)\n}\n\n/// Creates a new [`Radius`] with the given value as top left and top right.\npub fn top(value: impl Into<Pixels>) -> Radius {\n    Radius::default().top(value)\n}\n\n/// Creates a new [`Radius`] with the given value as bottom left and bottom right.\npub fn bottom(value: impl Into<Pixels>) -> Radius {\n    Radius::default().bottom(value)\n}\n\n/// Creates a new [`Radius`] with the given value as top left and bottom left.\npub fn left(value: impl Into<Pixels>) -> Radius {\n    Radius::default().left(value)\n}\n\n/// Creates a new [`Radius`] with the given value as top right and bottom right.\npub fn right(value: impl Into<Pixels>) -> Radius {\n    Radius::default().right(value)\n}\n\nimpl Radius {\n    /// Creates a new [`Radius`] with the same value for each corner.\n    pub fn new(value: impl Into<Pixels>) -> Self {\n        let value = value.into().0;\n\n        Self {\n            top_left: value,\n            top_right: value,\n            bottom_right: value,\n            bottom_left: value,\n        }\n    }\n\n    /// Sets the top left value of the [`Radius`].\n    pub fn top_left(self, value: impl Into<Pixels>) -> Self {\n        Self {\n            top_left: value.into().0,\n            ..self\n        }\n    }\n\n    /// Sets the top right value of the [`Radius`].\n    pub fn top_right(self, value: impl Into<Pixels>) -> Self {\n        Self {\n            top_right: value.into().0,\n            ..self\n        }\n    }\n\n    /// Sets the bottom right value of the [`Radius`].\n    pub fn bottom_right(self, value: impl Into<Pixels>) -> Self {\n        Self {\n            bottom_right: value.into().0,\n            ..self\n        }\n    }\n\n    /// Sets the bottom left value of the [`Radius`].\n    pub fn bottom_left(self, value: impl Into<Pixels>) -> Self {\n        Self {\n            bottom_left: value.into().0,\n            ..self\n        }\n    }\n\n    /// Sets the top left and top right values of the [`Radius`].\n    pub fn top(self, value: impl Into<Pixels>) -> Self {\n        let value = value.into().0;\n\n        Self {\n            top_left: value,\n            top_right: value,\n            ..self\n        }\n    }\n\n    /// Sets the bottom left and bottom right values of the [`Radius`].\n    pub fn bottom(self, value: impl Into<Pixels>) -> Self {\n        let value = value.into().0;\n\n        Self {\n            bottom_left: value,\n            bottom_right: value,\n            ..self\n        }\n    }\n\n    /// Sets the top left and bottom left values of the [`Radius`].\n    pub fn left(self, value: impl Into<Pixels>) -> Self {\n        let value = value.into().0;\n\n        Self {\n            top_left: value,\n            bottom_left: value,\n            ..self\n        }\n    }\n\n    /// Sets the top right and bottom right values of the [`Radius`].\n    pub fn right(self, value: impl Into<Pixels>) -> Self {\n        let value = value.into().0;\n\n        Self {\n            top_right: value,\n            bottom_right: value,\n            ..self\n        }\n    }\n}\n\nimpl From<f32> for Radius {\n    fn from(radius: f32) -> Self {\n        Self {\n            top_left: radius,\n            top_right: radius,\n            bottom_right: radius,\n            bottom_left: radius,\n        }\n    }\n}\n\nimpl From<u8> for Radius {\n    fn from(w: u8) -> Self {\n        Self::from(f32::from(w))\n    }\n}\n\nimpl From<u32> for Radius {\n    fn from(w: u32) -> Self {\n        Self::from(w as f32)\n    }\n}\n\nimpl From<i32> for Radius {\n    fn from(w: i32) -> Self {\n        Self::from(w as f32)\n    }\n}\n\nimpl From<Radius> for [f32; 4] {\n    fn from(radi: Radius) -> Self {\n        [\n            radi.top_left,\n            radi.top_right,\n            radi.bottom_right,\n            radi.bottom_left,\n        ]\n    }\n}\n\nimpl std::ops::Mul<f32> for Radius {\n    type Output = Self;\n\n    fn mul(self, scale: f32) -> Self::Output {\n        Self {\n            top_left: self.top_left * scale,\n            top_right: self.top_right * scale,\n            bottom_right: self.bottom_right * scale,\n            bottom_left: self.bottom_left * scale,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/clipboard.rs",
    "content": "//! Access the clipboard.\nuse std::path::PathBuf;\nuse std::sync::Arc;\n\n/// A set of clipboard requests.\n#[derive(Debug, Clone)]\npub struct Clipboard {\n    /// The read requests the runtime must fulfill.\n    pub reads: Vec<Kind>,\n    /// The content that must be written to the clipboard by the runtime,\n    /// if any.\n    pub write: Option<Content>,\n}\n\nimpl Clipboard {\n    /// Creates a new empty set of [`Clipboard`] requests.\n    pub fn new() -> Self {\n        Self {\n            reads: Vec::new(),\n            write: None,\n        }\n    }\n\n    /// Merges the current [`Clipboard`] requests with others.\n    pub fn merge(&mut self, other: &mut Self) {\n        self.reads.append(&mut other.reads);\n        self.write = other.write.take().or(self.write.take());\n    }\n}\n\nimpl Default for Clipboard {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// A clipboard event.\n#[derive(Debug, Clone, PartialEq)]\npub enum Event {\n    /// The clipboard was read.\n    Read(Result<Arc<Content>, Error>),\n\n    /// The clipboard was written.\n    Written(Result<(), Error>),\n}\n\n/// Some clipboard content.\n#[derive(Debug, Clone, PartialEq)]\n#[allow(missing_docs)]\n#[non_exhaustive]\npub enum Content {\n    Text(String),\n    Html(String),\n    #[cfg(feature = \"image\")]\n    Image(Image),\n    Files(Vec<PathBuf>),\n}\n\nimpl From<String> for Content {\n    fn from(text: String) -> Self {\n        Self::Text(text)\n    }\n}\n\n#[cfg(feature = \"image\")]\nimpl From<Image> for Content {\n    fn from(image: Image) -> Self {\n        Self::Image(image)\n    }\n}\n\nimpl From<Vec<PathBuf>> for Content {\n    fn from(files: Vec<PathBuf>) -> Self {\n        Self::Files(files)\n    }\n}\n\n/// The kind of some clipboard [`Content`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[allow(missing_docs)]\n#[non_exhaustive]\npub enum Kind {\n    Text,\n    Html,\n    #[cfg(feature = \"image\")]\n    Image,\n    Files,\n}\n\n/// A clipboard image.\n#[cfg(feature = \"image\")]\n#[derive(Debug, Clone, PartialEq)]\npub struct Image {\n    /// The pixels of the image in RGBA format.\n    pub rgba: crate::Bytes,\n\n    /// The physical [`Size`](crate::Size) of the image.\n    pub size: crate::Size<u32>,\n}\n\n/// A clipboard error.\n#[derive(Debug, Clone, PartialEq)]\npub enum Error {\n    /// The clipboard in the current environment is either not present or could not be accessed.\n    ClipboardUnavailable,\n\n    /// The native clipboard is not accessible due to being held by another party.\n    ClipboardOccupied,\n\n    /// The clipboard contents were not available in the requested format.\n    /// This could either be due to the clipboard being empty or the clipboard contents having\n    /// an incompatible format to the requested one\n    ContentNotAvailable,\n\n    /// The image or the text that was about the be transferred to/from the clipboard could not be\n    /// converted to the appropriate format.\n    ConversionFailure,\n\n    /// Any error that doesn't fit the other error types.\n    Unknown {\n        /// A description only meant to help the developer that should not be relied on as a\n        /// means to identify an error case during runtime.\n        description: Arc<String>,\n    },\n}\n"
  },
  {
    "path": "core/src/color.rs",
    "content": "use crate::animation::Interpolable;\n\n/// A color in the `sRGB` color space.\n///\n/// # String Representation\n///\n/// A color can be represented in either of the following valid formats: `#rrggbb`, `#rrggbbaa`, `#rgb`, and `#rgba`.\n/// Where `rgba` represent hexadecimal digits. Both uppercase and lowercase letters are supported.\n///\n/// If `a` (transparency) is not specified, `1.0` (completely opaque) would be used by default.\n///\n/// If you have a static color string, using the [`color!`] macro should be preferred\n/// since it leverages hexadecimal literal notation and arithmetic directly.\n///\n/// [`color!`]: crate::color!\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\n#[must_use]\npub struct Color {\n    /// Red component, 0.0 - 1.0\n    pub r: f32,\n    /// Green component, 0.0 - 1.0\n    pub g: f32,\n    /// Blue component, 0.0 - 1.0\n    pub b: f32,\n    /// Transparency, 0.0 - 1.0\n    pub a: f32,\n}\n\nimpl Color {\n    /// The black color.\n    pub const BLACK: Color = Color {\n        r: 0.0,\n        g: 0.0,\n        b: 0.0,\n        a: 1.0,\n    };\n\n    /// The white color.\n    pub const WHITE: Color = Color {\n        r: 1.0,\n        g: 1.0,\n        b: 1.0,\n        a: 1.0,\n    };\n\n    /// A color with no opacity.\n    pub const TRANSPARENT: Color = Color {\n        r: 0.0,\n        g: 0.0,\n        b: 0.0,\n        a: 0.0,\n    };\n\n    /// Creates a new [`Color`].\n    ///\n    /// In debug mode, it will panic if the values are not in the correct\n    /// range: 0.0 - 1.0\n    const fn new(r: f32, g: f32, b: f32, a: f32) -> Color {\n        debug_assert!(\n            r >= 0.0 && r <= 1.0,\n            \"Red component must be in [0, 1] range.\"\n        );\n        debug_assert!(\n            g >= 0.0 && g <= 1.0,\n            \"Green component must be in [0, 1] range.\"\n        );\n        debug_assert!(\n            b >= 0.0 && b <= 1.0,\n            \"Blue component must be in [0, 1] range.\"\n        );\n\n        Self { r, g, b, a }\n    }\n\n    /// Creates a [`Color`] from its RGB components.\n    pub const fn from_rgb(r: f32, g: f32, b: f32) -> Self {\n        Self::from_rgba(r, g, b, 1.0f32)\n    }\n\n    /// Creates a [`Color`] from its RGBA components.\n    pub const fn from_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {\n        Self::new(r, g, b, a)\n    }\n\n    /// Creates a [`Color`] from its RGB8 components.\n    pub const fn from_rgb8(r: u8, g: u8, b: u8) -> Self {\n        Self::from_rgba8(r, g, b, 1.0)\n    }\n\n    /// Creates a [`Color`] from its RGB8 components and an alpha value.\n    pub const fn from_rgba8(r: u8, g: u8, b: u8, a: f32) -> Self {\n        Self::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, a)\n    }\n\n    /// Creates a [`Color`] from its RGB8 components packed in the lower bits of a `u32`.\n    pub const fn from_packed_rgb8(rgb: u32) -> Self {\n        Self::from_packed_rgba8(rgb, 1.0)\n    }\n\n    /// Creates a [`Color`] from its RGB8 components packed in the lower bits of a `u32`\n    /// and an alpha value.\n    pub const fn from_packed_rgba8(rgb: u32, a: f32) -> Self {\n        let r = (rgb & 0xff0000) >> 16;\n        let g = (rgb & 0xff00) >> 8;\n        let b = rgb & 0xff;\n\n        Self::from_rgba8(r as u8, g as u8, b as u8, a)\n    }\n\n    /// Creates a [`Color`] from its linear RGBA components.\n    pub fn from_linear_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {\n        // As described in:\n        // https://en.wikipedia.org/wiki/SRGB\n        fn gamma_component(u: f32) -> f32 {\n            if u < 0.0031308 {\n                12.92 * u\n            } else {\n                1.055 * u.powf(1.0 / 2.4) - 0.055\n            }\n        }\n\n        Self::new(\n            gamma_component(r),\n            gamma_component(g),\n            gamma_component(b),\n            a,\n        )\n    }\n\n    /// Inverts the [`Color`] in-place.\n    pub const fn invert(&mut self) {\n        self.r = 1.0f32 - self.r;\n        self.b = 1.0f32 - self.g;\n        self.g = 1.0f32 - self.b;\n    }\n\n    /// Returns the inverted [`Color`].\n    pub const fn inverse(self) -> Self {\n        Self::new(1.0f32 - self.r, 1.0f32 - self.g, 1.0f32 - self.b, self.a)\n    }\n\n    /// Scales the alpha channel of the [`Color`] by the given factor.\n    pub const fn scale_alpha(self, factor: f32) -> Self {\n        Self {\n            a: self.a * factor,\n            ..self\n        }\n    }\n\n    /// Mixes the current [`Color`] with another one by the given factor.\n    pub fn mix(self, b: Color, factor: f32) -> Color {\n        let b_amount = factor.clamp(0.0, 1.0);\n        let a_amount = 1.0 - b_amount;\n\n        let a_linear = self.into_linear().map(|c| c * a_amount);\n        let b_linear = b.into_linear().map(|c| c * b_amount);\n\n        Color::from_linear_rgba(\n            a_linear[0] + b_linear[0],\n            a_linear[1] + b_linear[1],\n            a_linear[2] + b_linear[2],\n            a_linear[3] + b_linear[3],\n        )\n    }\n\n    /// Returns the relative luminance of the [`Color`].\n    /// <https://www.w3.org/TR/WCAG21/#dfn-relative-luminance>\n    #[must_use]\n    pub fn relative_luminance(self) -> f32 {\n        let linear = self.into_linear();\n        0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2]\n    }\n\n    /// Returns the [relative contrast ratio] of the [`Color`] against another one.\n    ///\n    /// [relative contrast ratio]: https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio\n    #[must_use]\n    pub fn relative_contrast(self, b: Self) -> f32 {\n        let lum_a = self.relative_luminance();\n        let lum_b = b.relative_luminance();\n\n        (lum_a.max(lum_b) + 0.05) / (lum_a.min(lum_b) + 0.05)\n    }\n\n    /// Returns true if the current [`Color`] is readable on top\n    /// of the given background [`Color`].\n    #[must_use]\n    pub fn is_readable_on(self, background: Self) -> bool {\n        background.relative_contrast(self) >= 6.0\n    }\n\n    /// Converts the [`Color`] into its RGBA8 equivalent.\n    #[must_use]\n    pub const fn into_rgba8(self) -> [u8; 4] {\n        [\n            (self.r * 255.0).round() as u8,\n            (self.g * 255.0).round() as u8,\n            (self.b * 255.0).round() as u8,\n            (self.a * 255.0).round() as u8,\n        ]\n    }\n\n    /// Converts the [`Color`] into its linear values.\n    #[must_use]\n    pub fn into_linear(self) -> [f32; 4] {\n        // As described in:\n        // https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation\n        fn linear_component(u: f32) -> f32 {\n            if u < 0.04045 {\n                u / 12.92\n            } else {\n                ((u + 0.055) / 1.055).powf(2.4)\n            }\n        }\n\n        [\n            linear_component(self.r),\n            linear_component(self.g),\n            linear_component(self.b),\n            self.a,\n        ]\n    }\n}\n\nimpl From<[f32; 3]> for Color {\n    fn from([r, g, b]: [f32; 3]) -> Self {\n        Color::new(r, g, b, 1.0)\n    }\n}\n\nimpl From<[f32; 4]> for Color {\n    fn from([r, g, b, a]: [f32; 4]) -> Self {\n        Color::new(r, g, b, a)\n    }\n}\n\n/// An error which can be returned when parsing color from an RGB hexadecimal string.\n///\n/// See [`Color`] for specifications for the string.\n#[derive(Debug, thiserror::Error)]\npub enum ParseError {\n    /// The string could not be parsed to valid integers.\n    #[error(transparent)]\n    ParseIntError(#[from] std::num::ParseIntError),\n    /// The string is of invalid length.\n    #[error(\"expected hex string of length 3, 4, 6 or 8 excluding optional prefix '#', found {0}\")]\n    InvalidLength(usize),\n}\n\nimpl std::str::FromStr for Color {\n    type Err = ParseError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let hex = s.strip_prefix('#').unwrap_or(s);\n\n        let parse_channel = |from: usize, to: usize| -> Result<f32, std::num::ParseIntError> {\n            let num = usize::from_str_radix(&hex[from..=to], 16)? as f32 / 255.0;\n\n            // If we only got half a byte (one letter), expand it into a full byte (two letters)\n            Ok(if from == to { num + num * 16.0 } else { num })\n        };\n\n        let val = match hex.len() {\n            3 => Color::from_rgb(\n                parse_channel(0, 0)?,\n                parse_channel(1, 1)?,\n                parse_channel(2, 2)?,\n            ),\n            4 => Color::from_rgba(\n                parse_channel(0, 0)?,\n                parse_channel(1, 1)?,\n                parse_channel(2, 2)?,\n                parse_channel(3, 3)?,\n            ),\n            6 => Color::from_rgb(\n                parse_channel(0, 1)?,\n                parse_channel(2, 3)?,\n                parse_channel(4, 5)?,\n            ),\n            8 => Color::from_rgba(\n                parse_channel(0, 1)?,\n                parse_channel(2, 3)?,\n                parse_channel(4, 5)?,\n                parse_channel(6, 7)?,\n            ),\n            _ => return Err(ParseError::InvalidLength(hex.len())),\n        };\n\n        Ok(val)\n    }\n}\n\nimpl std::fmt::Display for Color {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let [r, g, b, a] = self.into_rgba8();\n\n        if self.a == 1.0 {\n            return write!(f, \"#{r:02x}{g:02x}{b:02x}\");\n        }\n\n        write!(f, \"#{r:02x}{g:02x}{b:02x}{a:02x}\")\n    }\n}\n\nimpl Interpolable for Color {\n    /// Interpolates the color. Equivalent to [`Color::mix`].\n    fn interpolated(&self, other: Self, ratio: f32) -> Self {\n        self.mix(other, ratio)\n    }\n}\n\n/// Creates a [`Color`] with shorter and cleaner syntax.\n///\n/// # Examples\n///\n/// ```\n/// # use iced_core::{Color, color};\n/// assert_eq!(color!(0, 0, 0), Color::BLACK);\n/// assert_eq!(color!(0, 0, 0, 0.0), Color::TRANSPARENT);\n/// assert_eq!(color!(0xffffff), Color::from_rgb(1.0, 1.0, 1.0));\n/// assert_eq!(color!(0xffffff, 0.), Color::from_rgba(1.0, 1.0, 1.0, 0.0));\n/// assert_eq!(color!(0x0000ff), Color::from_rgba(0.0, 0.0, 1.0, 1.0));\n/// ```\n#[macro_export]\nmacro_rules! color {\n    ($r:expr, $g:expr, $b:expr) => {\n        $crate::Color::from_rgb8($r, $g, $b)\n    };\n    ($r:expr, $g:expr, $b:expr, $a:expr) => {{ $crate::Color::from_rgba8($r, $g, $b, $a) }};\n    ($hex:literal) => {{ $crate::color!($hex, 1.0) }};\n    ($hex:literal, $a:expr) => {{\n        let mut hex = $hex as u32;\n\n        // Shorthand notation: 0x123\n        if stringify!($hex).len() == 5 {\n            let r = hex & 0xF00;\n            let g = hex & 0xF0;\n            let b = hex & 0xF;\n\n            hex = (r << 12) | (r << 8) | (g << 8) | (g << 4) | (b << 4) | b;\n        }\n\n        debug_assert!(hex <= 0xffffff, \"color! value must not exceed 0xffffff\");\n\n        $crate::Color::from_packed_rgba8(hex, $a)\n    }};\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse() {\n        let tests = [\n            (\"#ff0000\", [255, 0, 0, 255], \"#ff0000\"),\n            (\"00ff0080\", [0, 255, 0, 128], \"#00ff0080\"),\n            (\"#F80\", [255, 136, 0, 255], \"#ff8800\"),\n            (\"#00f1\", [0, 0, 255, 17], \"#0000ff11\"),\n            (\"#00ff\", [0, 0, 255, 255], \"#0000ff\"),\n        ];\n\n        for (arg, expected_rgba8, expected_str) in tests {\n            let color = arg.parse::<Color>().expect(\"color must parse\");\n\n            assert_eq!(color.into_rgba8(), expected_rgba8);\n            assert_eq!(color.to_string(), expected_str);\n        }\n\n        assert!(\"invalid\".parse::<Color>().is_err());\n    }\n\n    const SHORTHAND: Color = color!(0x123);\n\n    #[test]\n    fn shorthand_notation() {\n        assert_eq!(SHORTHAND, Color::from_rgb8(0x11, 0x22, 0x33));\n    }\n}\n"
  },
  {
    "path": "core/src/content_fit.rs",
    "content": "//! Control the fit of some content (like an image) within a space.\nuse crate::Size;\n\nuse std::fmt;\n\n/// The strategy used to fit the contents of a widget to its bounding box.\n///\n/// Each variant of this enum is a strategy that can be applied for resolving\n/// differences in aspect ratio and size between the image being displayed and\n/// the space its being displayed in.\n///\n/// For an interactive demonstration of these properties as they are implemented\n/// in CSS, see [Mozilla's docs][1], or run the `tour` example\n///\n/// [1]: https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit\n#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, Default)]\npub enum ContentFit {\n    /// Scale as big as it can be without needing to crop or hide parts.\n    ///\n    /// The image will be scaled (preserving aspect ratio) so that it just fits\n    /// within the window.  This won't distort the image or crop/hide any edges,\n    /// but if the image doesn't fit perfectly, there may be whitespace on the\n    /// top/bottom or left/right.\n    ///\n    /// This is a great fit for when you need to display an image without losing\n    /// any part of it, particularly when the image itself is the focus of the\n    /// screen.\n    #[default]\n    Contain,\n\n    /// Scale the image to cover all of the bounding box, cropping if needed.\n    ///\n    /// This doesn't distort the image, and it ensures that the widget's area is\n    /// completely covered, but it might crop off a bit of the edges of the\n    /// widget, particularly when there is a big difference between the aspect\n    /// ratio of the widget and the aspect ratio of the image.\n    ///\n    /// This is best for when you're using an image as a background, or to fill\n    /// space, and any details of the image around the edge aren't too\n    /// important.\n    Cover,\n\n    /// Distort the image so the widget is 100% covered without cropping.\n    ///\n    /// This stretches the image to fit the widget, without any whitespace or\n    /// cropping. However, because of the stretch, the image may look distorted\n    /// or elongated, particularly when there's a mismatch of aspect ratios.\n    Fill,\n\n    /// Don't resize or scale the image at all.\n    ///\n    /// This will not apply any transformations to the provided image, but also\n    /// means that unless you do the math yourself, the widget's area will not\n    /// be completely covered, or the image might be cropped.\n    ///\n    /// This is best for when you've sized the image yourself.\n    None,\n\n    /// Scale the image down if it's too big for the space, but never scale it\n    /// up.\n    ///\n    /// This works much like [`Contain`](Self::Contain), except that if the\n    /// image would have been scaled up, it keeps its original resolution to\n    /// avoid the bluring that accompanies upscaling images.\n    ScaleDown,\n}\n\nimpl ContentFit {\n    /// Attempt to apply the given fit for a content size within some bounds.\n    ///\n    /// The returned value is the recommended scaled size of the content.\n    pub fn fit(&self, content: Size, bounds: Size) -> Size {\n        let content_ar = content.width / content.height;\n        let bounds_ar = bounds.width / bounds.height;\n\n        match self {\n            Self::Contain => {\n                if bounds_ar > content_ar {\n                    Size {\n                        width: content.width * bounds.height / content.height,\n                        ..bounds\n                    }\n                } else {\n                    Size {\n                        height: content.height * bounds.width / content.width,\n                        ..bounds\n                    }\n                }\n            }\n            Self::Cover => {\n                if bounds_ar < content_ar {\n                    Size {\n                        width: content.width * bounds.height / content.height,\n                        ..bounds\n                    }\n                } else {\n                    Size {\n                        height: content.height * bounds.width / content.width,\n                        ..bounds\n                    }\n                }\n            }\n            Self::Fill => bounds,\n            Self::None => content,\n            Self::ScaleDown => {\n                if bounds_ar > content_ar && bounds.height < content.height {\n                    Size {\n                        width: content.width * bounds.height / content.height,\n                        ..bounds\n                    }\n                } else if bounds.width < content.width {\n                    Size {\n                        height: content.height * bounds.width / content.width,\n                        ..bounds\n                    }\n                } else {\n                    content\n                }\n            }\n        }\n    }\n}\n\nimpl fmt::Display for ContentFit {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(match self {\n            ContentFit::Contain => \"Contain\",\n            ContentFit::Cover => \"Cover\",\n            ContentFit::Fill => \"Fill\",\n            ContentFit::None => \"None\",\n            ContentFit::ScaleDown => \"Scale Down\",\n        })\n    }\n}\n"
  },
  {
    "path": "core/src/element.rs",
    "content": "use crate::layout;\nuse crate::mouse;\nuse crate::overlay;\nuse crate::renderer;\nuse crate::widget;\nuse crate::widget::tree::{self, Tree};\nuse crate::{Border, Color, Event, Layout, Length, Rectangle, Shell, Size, Vector, Widget};\n\nuse std::borrow::Borrow;\n\n/// A generic [`Widget`].\n///\n/// It is useful to build composable user interfaces that do not leak\n/// implementation details in their __view logic__.\n///\n/// If you have a [built-in widget], you should be able to use `Into<Element>`\n/// to turn it into an [`Element`].\n///\n/// [built-in widget]: crate::widget\npub struct Element<'a, Message, Theme, Renderer> {\n    widget: Box<dyn Widget<Message, Theme, Renderer> + 'a>,\n}\n\nimpl<'a, Message, Theme, Renderer> Element<'a, Message, Theme, Renderer> {\n    /// Creates a new [`Element`] containing the given [`Widget`].\n    pub fn new(widget: impl Widget<Message, Theme, Renderer> + 'a) -> Self\n    where\n        Renderer: crate::Renderer,\n    {\n        Self {\n            widget: Box::new(widget),\n        }\n    }\n\n    /// Returns a reference to the [`Widget`] of the [`Element`],\n    pub fn as_widget(&self) -> &dyn Widget<Message, Theme, Renderer> {\n        self.widget.as_ref()\n    }\n\n    /// Returns a mutable reference to the [`Widget`] of the [`Element`],\n    pub fn as_widget_mut(&mut self) -> &mut dyn Widget<Message, Theme, Renderer> {\n        self.widget.as_mut()\n    }\n\n    /// Applies a transformation to the produced message of the [`Element`].\n    ///\n    /// This method is useful when you want to decouple different parts of your\n    /// UI and make them __composable__.\n    ///\n    /// # Example\n    /// Imagine we want to use [our counter](index.html#usage). But instead of\n    /// showing a single counter, we want to display many of them. We can reuse\n    /// the `Counter` type as it is!\n    ///\n    /// We use composition to model the __state__ of our new application:\n    ///\n    /// ```\n    /// # mod counter {\n    /// #     pub struct Counter;\n    /// # }\n    /// use counter::Counter;\n    ///\n    /// struct ManyCounters {\n    ///     counters: Vec<Counter>,\n    /// }\n    /// ```\n    ///\n    /// We can store the state of multiple counters now. However, the\n    /// __messages__ we implemented before describe the user interactions\n    /// of a __single__ counter. Right now, we need to also identify which\n    /// counter is receiving user interactions. Can we use composition again?\n    /// Yes.\n    ///\n    /// ```\n    /// # mod counter {\n    /// #     #[derive(Debug, Clone, Copy)]\n    /// #     pub enum Message {}\n    /// # }\n    /// #[derive(Debug, Clone, Copy)]\n    /// pub enum Message {\n    ///     Counter(usize, counter::Message)\n    /// }\n    /// ```\n    ///\n    /// We compose the previous __messages__ with the index of the counter\n    /// producing them. Let's implement our __view logic__ now:\n    ///\n    /// ```no_run\n    /// # mod iced {\n    /// #     pub use iced_core::Function;\n    /// #     pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>;\n    /// #\n    /// #     pub mod widget {\n    /// #         pub fn row<'a, Message>(iter: impl IntoIterator<Item = super::Element<'a, Message>>) -> super::Element<'a, Message> {\n    /// #             unimplemented!()\n    /// #         }\n    /// #     }\n    /// # }\n    /// #\n    /// # mod counter {\n    /// #     #[derive(Debug, Clone, Copy)]\n    /// #     pub enum Message {}\n    /// #     pub struct Counter;\n    /// #\n    /// #     pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>;\n    /// #\n    /// #     impl Counter {\n    /// #         pub fn view(&self) -> Element<Message> {\n    /// #             unimplemented!()\n    /// #         }\n    /// #     }\n    /// # }\n    /// #\n    /// use counter::Counter;\n    ///\n    /// use iced::widget::row;\n    /// use iced::{Element, Function};\n    ///\n    /// struct ManyCounters {\n    ///     counters: Vec<Counter>,\n    /// }\n    ///\n    /// #[derive(Debug, Clone, Copy)]\n    /// pub enum Message {\n    ///     Counter(usize, counter::Message),\n    /// }\n    ///\n    /// impl ManyCounters {\n    ///     pub fn view(&self) -> Element<Message> {\n    ///         // We can quickly populate a `row` by mapping our counters\n    ///         row(\n    ///             self.counters\n    ///                 .iter()\n    ///                 .map(Counter::view)\n    ///                 .enumerate()\n    ///                 .map(|(index, counter)| {\n    ///                     // Here we turn our `Element<counter::Message>` into\n    ///                     // an `Element<Message>` by combining the `index` and the\n    ///                     // message of the `element`.\n    ///                     counter.map(Message::Counter.with(index))\n    ///                 }),\n    ///         )\n    ///         .into()\n    ///     }\n    /// }\n    /// ```\n    ///\n    /// Finally, our __update logic__ is pretty straightforward: simple\n    /// delegation.\n    ///\n    /// ```\n    /// # mod counter {\n    /// #     #[derive(Debug, Clone, Copy)]\n    /// #     pub enum Message {}\n    /// #     pub struct Counter;\n    /// #\n    /// #     impl Counter {\n    /// #         pub fn update(&mut self, _message: Message) {}\n    /// #     }\n    /// # }\n    /// #\n    /// # use counter::Counter;\n    /// #\n    /// # struct ManyCounters {\n    /// #     counters: Vec<Counter>,\n    /// # }\n    /// #\n    /// # #[derive(Debug, Clone, Copy)]\n    /// # pub enum Message {\n    /// #    Counter(usize, counter::Message)\n    /// # }\n    /// impl ManyCounters {\n    ///     pub fn update(&mut self, message: Message) {\n    ///         match message {\n    ///             Message::Counter(index, counter_msg) => {\n    ///                 if let Some(counter) = self.counters.get_mut(index) {\n    ///                     counter.update(counter_msg);\n    ///                 }\n    ///             }\n    ///         }\n    ///     }\n    /// }\n    /// ```\n    pub fn map<B>(self, f: impl Fn(Message) -> B + 'a) -> Element<'a, B, Theme, Renderer>\n    where\n        Message: 'a,\n        Theme: 'a,\n        Renderer: crate::Renderer + 'a,\n        B: 'a,\n    {\n        Element::new(Map::new(self.widget, f))\n    }\n\n    /// Marks the [`Element`] as _to-be-explained_.\n    ///\n    /// The [`Renderer`] will explain the layout of the [`Element`] graphically.\n    /// This can be very useful for debugging your layout!\n    ///\n    /// [`Renderer`]: crate::Renderer\n    pub fn explain<C: Into<Color>>(self, color: C) -> Element<'a, Message, Theme, Renderer>\n    where\n        Message: 'a,\n        Theme: 'a,\n        Renderer: crate::Renderer + 'a,\n    {\n        Element {\n            widget: Box::new(Explain::new(self, color.into())),\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> Borrow<dyn Widget<Message, Theme, Renderer> + 'a>\n    for Element<'a, Message, Theme, Renderer>\n{\n    fn borrow(&self) -> &(dyn Widget<Message, Theme, Renderer> + 'a) {\n        self.widget.borrow()\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> Borrow<dyn Widget<Message, Theme, Renderer> + 'a>\n    for &Element<'a, Message, Theme, Renderer>\n{\n    fn borrow(&self) -> &(dyn Widget<Message, Theme, Renderer> + 'a) {\n        self.widget.borrow()\n    }\n}\n\nstruct Map<'a, A, B, Theme, Renderer> {\n    widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,\n    mapper: Box<dyn Fn(A) -> B + 'a>,\n}\n\nimpl<'a, A, B, Theme, Renderer> Map<'a, A, B, Theme, Renderer> {\n    pub fn new<F>(\n        widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,\n        mapper: F,\n    ) -> Map<'a, A, B, Theme, Renderer>\n    where\n        F: 'a + Fn(A) -> B,\n    {\n        Map {\n            widget,\n            mapper: Box::new(mapper),\n        }\n    }\n}\n\nimpl<'a, A, B, Theme, Renderer> Widget<B, Theme, Renderer> for Map<'a, A, B, Theme, Renderer>\nwhere\n    Renderer: crate::Renderer + 'a,\n    A: 'a,\n    B: 'a,\n{\n    fn tag(&self) -> tree::Tag {\n        self.widget.tag()\n    }\n\n    fn state(&self) -> tree::State {\n        self.widget.state()\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        self.widget.children()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        self.widget.diff(tree);\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.widget.size()\n    }\n\n    fn size_hint(&self) -> Size<Length> {\n        self.widget.size_hint()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.widget.layout(tree, renderer, limits)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.widget.operate(tree, layout, renderer, operation);\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, B>,\n        viewport: &Rectangle,\n    ) {\n        let mut local_messages = Vec::new();\n        let mut local_shell = Shell::new(&mut local_messages);\n\n        self.widget.update(\n            tree,\n            event,\n            layout,\n            cursor,\n            renderer,\n            &mut local_shell,\n            viewport,\n        );\n\n        shell.merge(local_shell, &self.mapper);\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.widget\n            .draw(tree, renderer, theme, style, layout, cursor, viewport);\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.widget\n            .mouse_interaction(tree, layout, cursor, viewport, renderer)\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, B, Theme, Renderer>> {\n        let mapper = &self.mapper;\n\n        self.widget\n            .overlay(tree, layout, renderer, viewport, translation)\n            .map(move |overlay| overlay.map(mapper))\n    }\n}\n\nstruct Explain<'a, Message, Theme, Renderer: crate::Renderer> {\n    element: Element<'a, Message, Theme, Renderer>,\n    color: Color,\n}\n\nimpl<'a, Message, Theme, Renderer> Explain<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::Renderer,\n{\n    fn new(element: Element<'a, Message, Theme, Renderer>, color: Color) -> Self {\n        Explain { element, color }\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Explain<'_, Message, Theme, Renderer>\nwhere\n    Renderer: crate::Renderer,\n{\n    fn size(&self) -> Size<Length> {\n        self.element.widget.size()\n    }\n\n    fn size_hint(&self) -> Size<Length> {\n        self.element.widget.size_hint()\n    }\n\n    fn tag(&self) -> tree::Tag {\n        self.element.widget.tag()\n    }\n\n    fn state(&self) -> tree::State {\n        self.element.widget.state()\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        self.element.widget.children()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        self.element.widget.diff(tree);\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.element.widget.layout(tree, renderer, limits)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.element\n            .widget\n            .operate(tree, layout, renderer, operation);\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.element\n            .widget\n            .update(tree, event, layout, cursor, renderer, shell, viewport);\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        fn explain_layout<Renderer: crate::Renderer>(\n            renderer: &mut Renderer,\n            color: Color,\n            layout: Layout<'_>,\n        ) {\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds: layout.bounds(),\n                    border: Border {\n                        color,\n                        width: 1.0,\n                        ..Border::default()\n                    },\n                    ..renderer::Quad::default()\n                },\n                Color::TRANSPARENT,\n            );\n\n            for child in layout.children() {\n                explain_layout(renderer, color, child);\n            }\n        }\n\n        self.element\n            .widget\n            .draw(tree, renderer, theme, style, layout, cursor, viewport);\n\n        renderer.with_layer(Rectangle::INFINITE, |renderer| {\n            explain_layout(renderer, self.color, layout);\n        });\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.element\n            .widget\n            .mouse_interaction(tree, layout, cursor, viewport, renderer)\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.element\n            .widget\n            .overlay(tree, layout, renderer, viewport, translation)\n    }\n}\n\nimpl<'a, T, Message, Theme, Renderer> From<Option<T>> for Element<'a, Message, Theme, Renderer>\nwhere\n    T: Into<Self>,\n    Renderer: crate::Renderer,\n{\n    fn from(element: Option<T>) -> Self {\n        struct Void;\n\n        impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Void\n        where\n            Renderer: crate::Renderer,\n        {\n            fn size(&self) -> Size<Length> {\n                Size {\n                    width: Length::Fixed(0.0),\n                    height: Length::Fixed(0.0),\n                }\n            }\n\n            fn layout(\n                &mut self,\n                _tree: &mut Tree,\n                _renderer: &Renderer,\n                _limits: &layout::Limits,\n            ) -> layout::Node {\n                layout::Node::new(Size::ZERO)\n            }\n\n            fn draw(\n                &self,\n                _tree: &Tree,\n                _renderer: &mut Renderer,\n                _theme: &Theme,\n                _style: &renderer::Style,\n                _layout: Layout<'_>,\n                _cursor: mouse::Cursor,\n                _viewport: &Rectangle,\n            ) {\n            }\n        }\n\n        element.map(T::into).unwrap_or_else(|| Element::new(Void))\n    }\n}\n"
  },
  {
    "path": "core/src/event.rs",
    "content": "//! Handle events of a user interface.\nuse crate::clipboard;\nuse crate::input_method;\nuse crate::keyboard;\nuse crate::mouse;\nuse crate::touch;\nuse crate::window;\n\n/// A user interface event.\n///\n/// _**Note:** This type is largely incomplete! If you need to track\n/// additional events, feel free to [open an issue] and share your use case!_\n///\n/// [open an issue]: https://github.com/iced-rs/iced/issues\n#[derive(Debug, Clone, PartialEq)]\npub enum Event {\n    /// A keyboard event\n    Keyboard(keyboard::Event),\n\n    /// A mouse event\n    Mouse(mouse::Event),\n\n    /// A window event\n    Window(window::Event),\n\n    /// A touch event\n    Touch(touch::Event),\n\n    /// An input method event\n    InputMethod(input_method::Event),\n\n    /// A clipboard event\n    Clipboard(clipboard::Event),\n}\n\n/// The status of an [`Event`] after being processed.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`Event`] was **NOT** handled by any widget.\n    Ignored,\n\n    /// The [`Event`] was handled and processed by a widget.\n    Captured,\n}\n\nimpl Status {\n    /// Merges two [`Status`] into one.\n    ///\n    /// `Captured` takes precedence over `Ignored`:\n    ///\n    /// ```\n    /// use iced_core::event::Status;\n    ///\n    /// assert_eq!(Status::Ignored.merge(Status::Ignored), Status::Ignored);\n    /// assert_eq!(Status::Ignored.merge(Status::Captured), Status::Captured);\n    /// assert_eq!(Status::Captured.merge(Status::Ignored), Status::Captured);\n    /// assert_eq!(Status::Captured.merge(Status::Captured), Status::Captured);\n    /// ```\n    pub fn merge(self, b: Self) -> Self {\n        match self {\n            Status::Ignored => b,\n            Status::Captured => Status::Captured,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/font.rs",
    "content": "//! Load and use fonts.\nuse std::hash::Hash;\n\n/// A font.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub struct Font {\n    /// The [`Family`] of the [`Font`].\n    pub family: Family,\n    /// The [`Weight`] of the [`Font`].\n    pub weight: Weight,\n    /// The [`Stretch`] of the [`Font`].\n    pub stretch: Stretch,\n    /// The [`Style`] of the [`Font`].\n    pub style: Style,\n}\n\nimpl Font {\n    /// A non-monospaced sans-serif font with normal [`Weight`].\n    pub const DEFAULT: Font = Font {\n        family: Family::SansSerif,\n        weight: Weight::Normal,\n        stretch: Stretch::Normal,\n        style: Style::Normal,\n    };\n\n    /// A monospaced font with normal [`Weight`].\n    pub const MONOSPACE: Font = Font {\n        family: Family::Monospace,\n        ..Self::DEFAULT\n    };\n\n    /// Creates a [`Font`] with the given [`Family::Name`] and default attributes.\n    pub const fn new(name: &'static str) -> Self {\n        Self {\n            family: Family::Name(name),\n            ..Self::DEFAULT\n        }\n    }\n\n    /// Creates a [`Font`] with the given [`Family`] and default attributes.\n    pub fn with_family(family: impl Into<Family>) -> Self {\n        Font {\n            family: family.into(),\n            ..Self::DEFAULT\n        }\n    }\n\n    /// Sets the [`Weight`] of the [`Font`].\n    pub const fn weight(self, weight: Weight) -> Self {\n        Self { weight, ..self }\n    }\n\n    /// Sets the [`Stretch`] of the [`Font`].\n    pub const fn stretch(self, stretch: Stretch) -> Self {\n        Self { stretch, ..self }\n    }\n\n    /// Sets the [`Style`] of the [`Font`].\n    pub const fn style(self, style: Style) -> Self {\n        Self { style, ..self }\n    }\n}\n\nimpl From<&'static str> for Font {\n    fn from(name: &'static str) -> Self {\n        Font::new(name)\n    }\n}\n\nimpl From<Family> for Font {\n    fn from(family: Family) -> Self {\n        Font::with_family(family)\n    }\n}\n\n/// A font family.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub enum Family {\n    /// The name of a font family of choice.\n    Name(&'static str),\n\n    /// Serif fonts represent the formal text style for a script.\n    Serif,\n\n    /// Glyphs in sans-serif fonts, as the term is used in CSS, are generally low\n    /// contrast and have stroke endings that are plain — without any flaring,\n    /// cross stroke, or other ornamentation.\n    #[default]\n    SansSerif,\n\n    /// Glyphs in cursive fonts generally use a more informal script style, and\n    /// the result looks more like handwritten pen or brush writing than printed\n    /// letterwork.\n    Cursive,\n\n    /// Fantasy fonts are primarily decorative or expressive fonts that contain\n    /// decorative or expressive representations of characters.\n    Fantasy,\n\n    /// The sole criterion of a monospace font is that all glyphs have the same\n    /// fixed width.\n    Monospace,\n}\n\nimpl Family {\n    /// A list of all the different standalone family variants.\n    pub const VARIANTS: &[Self] = &[\n        Self::Serif,\n        Self::SansSerif,\n        Self::Cursive,\n        Self::Fantasy,\n        Self::Monospace,\n    ];\n\n    /// Creates a [`Family::Name`] from the given string.\n    ///\n    /// The name is interned in a global cache and never freed.\n    pub fn name(name: &str) -> Self {\n        use rustc_hash::FxHashSet;\n        use std::sync::{LazyLock, Mutex};\n\n        static NAMES: LazyLock<Mutex<FxHashSet<&'static str>>> = LazyLock::new(Mutex::default);\n\n        let mut names = NAMES.lock().expect(\"lock font name cache\");\n\n        let Some(name) = names.get(name) else {\n            let name: &'static str = name.to_owned().leak();\n            let _ = names.insert(name);\n\n            return Self::Name(name);\n        };\n\n        Self::Name(name)\n    }\n}\n\nimpl From<&str> for Family {\n    fn from(name: &str) -> Self {\n        Family::name(name)\n    }\n}\n\nimpl std::fmt::Display for Family {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_str(match self {\n            Family::Name(name) => name,\n            Family::Serif => \"Serif\",\n            Family::SansSerif => \"Sans-serif\",\n            Family::Cursive => \"Cursive\",\n            Family::Fantasy => \"Fantasy\",\n            Family::Monospace => \"Monospace\",\n        })\n    }\n}\n\n/// The weight of some text.\n#[allow(missing_docs)]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub enum Weight {\n    Thin,\n    ExtraLight,\n    Light,\n    #[default]\n    Normal,\n    Medium,\n    Semibold,\n    Bold,\n    ExtraBold,\n    Black,\n}\n\n/// The width of some text.\n#[allow(missing_docs)]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub enum Stretch {\n    UltraCondensed,\n    ExtraCondensed,\n    Condensed,\n    SemiCondensed,\n    #[default]\n    Normal,\n    SemiExpanded,\n    Expanded,\n    ExtraExpanded,\n    UltraExpanded,\n}\n\n/// The style of some text.\n#[allow(missing_docs)]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub enum Style {\n    #[default]\n    Normal,\n    Italic,\n    Oblique,\n}\n\n/// A font error.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Error {}\n"
  },
  {
    "path": "core/src/gradient.rs",
    "content": "//! Colors that transition progressively.\nuse crate::{Color, Radians};\n\nuse std::cmp::Ordering;\n\n#[derive(Debug, Clone, Copy, PartialEq)]\n/// A fill which transitions colors progressively along a direction, either linearly, radially (TBD),\n/// or conically (TBD).\npub enum Gradient {\n    /// A linear gradient interpolates colors along a direction at a specific angle.\n    Linear(Linear),\n}\n\nimpl Gradient {\n    /// Scales the alpha channel of the [`Gradient`] by the given factor.\n    pub fn scale_alpha(self, factor: f32) -> Self {\n        match self {\n            Gradient::Linear(linear) => Gradient::Linear(linear.scale_alpha(factor)),\n        }\n    }\n}\n\nimpl From<Linear> for Gradient {\n    fn from(gradient: Linear) -> Self {\n        Self::Linear(gradient)\n    }\n}\n\n#[derive(Debug, Default, Clone, Copy, PartialEq)]\n/// A point along the gradient vector where the specified [`color`] is unmixed.\n///\n/// [`color`]: Self::color\npub struct ColorStop {\n    /// Offset along the gradient vector.\n    pub offset: f32,\n\n    /// The color of the gradient at the specified [`offset`].\n    ///\n    /// [`offset`]: Self::offset\n    pub color: Color,\n}\n\n/// A linear gradient.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Linear {\n    /// How the [`Gradient`] is angled within its bounds.\n    pub angle: Radians,\n    /// [`ColorStop`]s along the linear gradient path.\n    pub stops: [Option<ColorStop>; 8],\n}\n\nimpl Linear {\n    /// Creates a new [`Linear`] gradient with the given angle in [`Radians`].\n    pub fn new(angle: impl Into<Radians>) -> Self {\n        Self {\n            angle: angle.into(),\n            stops: [None; 8],\n        }\n    }\n\n    /// Adds a new [`ColorStop`], defined by an offset and a color, to the gradient.\n    ///\n    /// Any `offset` that is not within `0.0..=1.0` will be silently ignored.\n    ///\n    /// Any stop added after the 8th will be silently ignored.\n    pub fn add_stop(mut self, offset: f32, color: Color) -> Self {\n        if offset.is_finite() && (0.0..=1.0).contains(&offset) {\n            let (Ok(index) | Err(index)) = self.stops.binary_search_by(|stop| match stop {\n                None => Ordering::Greater,\n                Some(stop) => stop.offset.partial_cmp(&offset).unwrap(),\n            });\n\n            if index < 8 {\n                self.stops[index] = Some(ColorStop { offset, color });\n            }\n        } else {\n            log::warn!(\"Gradient color stop must be within 0.0..=1.0 range.\");\n        };\n\n        self\n    }\n\n    /// Adds multiple [`ColorStop`]s to the gradient.\n    ///\n    /// Any stop added after the 8th will be silently ignored.\n    pub fn add_stops(mut self, stops: impl IntoIterator<Item = ColorStop>) -> Self {\n        for stop in stops {\n            self = self.add_stop(stop.offset, stop.color);\n        }\n\n        self\n    }\n\n    /// Scales the alpha channel of the [`Linear`] gradient by the given\n    /// factor.\n    pub fn scale_alpha(mut self, factor: f32) -> Self {\n        for stop in self.stops.iter_mut().flatten() {\n            stop.color.a *= factor;\n        }\n\n        self\n    }\n}\n"
  },
  {
    "path": "core/src/image.rs",
    "content": "//! Load and draw raster graphics.\nuse crate::border;\nuse crate::{Bytes, Radians, Rectangle, Size};\n\nuse rustc_hash::FxHasher;\n\nuse std::hash::{Hash, Hasher};\nuse std::io;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Arc, Weak};\n\n/// A raster image that can be drawn.\n#[derive(Debug, Clone, PartialEq)]\npub struct Image<H = Handle> {\n    /// The handle of the image.\n    pub handle: H,\n\n    /// The filter method of the image.\n    pub filter_method: FilterMethod,\n\n    /// The rotation to be applied to the image; on its center.\n    pub rotation: Radians,\n\n    /// The border radius of the [`Image`].\n    ///\n    /// Currently, this will only be applied to the `clip_bounds`.\n    pub border_radius: border::Radius,\n\n    /// The opacity of the image.\n    ///\n    /// 0 means transparent. 1 means opaque.\n    pub opacity: f32,\n}\n\nimpl Image<Handle> {\n    /// Creates a new [`Image`] with the given handle.\n    pub fn new(handle: impl Into<Handle>) -> Self {\n        Self {\n            handle: handle.into(),\n            filter_method: FilterMethod::default(),\n            rotation: Radians(0.0),\n            border_radius: border::Radius::default(),\n            opacity: 1.0,\n        }\n    }\n\n    /// Sets the filter method of the [`Image`].\n    pub fn filter_method(mut self, filter_method: FilterMethod) -> Self {\n        self.filter_method = filter_method;\n        self\n    }\n\n    /// Sets the rotation of the [`Image`].\n    pub fn rotation(mut self, rotation: impl Into<Radians>) -> Self {\n        self.rotation = rotation.into();\n        self\n    }\n\n    /// Sets the opacity of the [`Image`].\n    pub fn opacity(mut self, opacity: impl Into<f32>) -> Self {\n        self.opacity = opacity.into();\n        self\n    }\n}\n\nimpl From<&Handle> for Image {\n    fn from(handle: &Handle) -> Self {\n        Image::new(handle.clone())\n    }\n}\n\n/// A handle of some image data.\n#[derive(Clone, PartialEq, Eq)]\npub enum Handle {\n    /// A file handle. The image data will be read\n    /// from the file path.\n    ///\n    /// Use [`from_path`] to create this variant.\n    ///\n    /// [`from_path`]: Self::from_path\n    Path(Id, PathBuf),\n\n    /// A handle pointing to some encoded image bytes in-memory.\n    ///\n    /// Use [`from_bytes`] to create this variant.\n    ///\n    /// [`from_bytes`]: Self::from_bytes\n    Bytes(Id, Bytes),\n\n    /// A handle pointing to decoded image pixels in RGBA format.\n    ///\n    /// Use [`from_rgba`] to create this variant.\n    ///\n    /// [`from_rgba`]: Self::from_rgba\n    Rgba {\n        /// The id of this handle.\n        id: Id,\n        /// The width of the image.\n        width: u32,\n        /// The height of the image.\n        height: u32,\n        /// The pixels.\n        pixels: Bytes,\n    },\n}\n\nimpl Handle {\n    /// Creates an image [`Handle`] pointing to the image of the given path.\n    ///\n    /// Makes an educated guess about the image format by examining the data in the file.\n    pub fn from_path<T: Into<PathBuf>>(path: T) -> Handle {\n        let path = path.into();\n\n        Self::Path(Id::path(&path), path)\n    }\n\n    /// Creates an image [`Handle`] containing the encoded image data directly.\n    ///\n    /// Makes an educated guess about the image format by examining the given data.\n    ///\n    /// This is useful if you already have your image loaded in-memory, maybe\n    /// because you downloaded or generated it procedurally.\n    pub fn from_bytes(bytes: impl Into<Bytes>) -> Handle {\n        Self::Bytes(Id::unique(), bytes.into())\n    }\n\n    /// Creates an image [`Handle`] containing the decoded image pixels directly.\n    ///\n    /// This function expects the pixel data to be provided as a collection of [`Bytes`]\n    /// of RGBA pixels. Therefore, the length of the pixel data should always be\n    /// `width * height * 4`.\n    ///\n    /// This is useful if you have already decoded your image.\n    pub fn from_rgba(width: u32, height: u32, pixels: impl Into<Bytes>) -> Handle {\n        Self::Rgba {\n            id: Id::unique(),\n            width,\n            height,\n            pixels: pixels.into(),\n        }\n    }\n\n    /// Returns the unique identifier of the [`Handle`].\n    pub fn id(&self) -> Id {\n        match self {\n            Handle::Path(id, _) | Handle::Bytes(id, _) | Handle::Rgba { id, .. } => *id,\n        }\n    }\n}\n\nimpl<T> From<T> for Handle\nwhere\n    T: Into<PathBuf>,\n{\n    fn from(path: T) -> Handle {\n        Handle::from_path(path.into())\n    }\n}\n\nimpl From<&Handle> for Handle {\n    fn from(value: &Handle) -> Self {\n        value.clone()\n    }\n}\n\nimpl std::fmt::Debug for Handle {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Path(id, path) => write!(f, \"Path({id:?}, {path:?})\"),\n            Self::Bytes(id, _) => write!(f, \"Bytes({id:?}, ...)\"),\n            Self::Rgba {\n                id, width, height, ..\n            } => {\n                write!(f, \"Pixels({id:?}, {width} * {height})\")\n            }\n        }\n    }\n}\n\n/// The unique identifier of some [`Handle`] data.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct Id(_Id);\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\nenum _Id {\n    Unique(u64),\n    Hash(u64),\n}\n\nimpl Id {\n    fn unique() -> Self {\n        use std::sync::atomic::{self, AtomicU64};\n\n        static NEXT_ID: AtomicU64 = AtomicU64::new(0);\n\n        Self(_Id::Unique(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)))\n    }\n\n    fn path(path: impl AsRef<Path>) -> Self {\n        let hash = {\n            let mut hasher = FxHasher::default();\n            path.as_ref().hash(&mut hasher);\n\n            hasher.finish()\n        };\n\n        Self(_Id::Hash(hash))\n    }\n}\n\n/// Image filtering strategy.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub enum FilterMethod {\n    /// Bilinear interpolation.\n    #[default]\n    Linear,\n    /// Nearest neighbor.\n    Nearest,\n}\n\n/// A memory allocation of a [`Handle`], often in GPU memory.\n///\n/// Renderers tend to decode and upload image data concurrently to\n/// avoid blocking the user interface. This means that when you use a\n/// [`Handle`] in a widget, there may be a slight frame delay until it\n/// is finally visible. If you are animating images, this can cause\n/// undesirable flicker.\n///\n/// When you obtain an [`Allocation`] explicitly, you get the guarantee\n/// that using a [`Handle`] will draw the corresponding [`Image`]\n/// immediately in the next frame.\n///\n/// This guarantee is valid as long as you hold an [`Allocation`].\n/// Only when you drop all its clones, the renderer may choose to free\n/// the memory of the [`Handle`]. Be careful!\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Allocation(Arc<Memory>);\n\n/// Some memory taken by an [`Allocation`].\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Memory {\n    handle: Handle,\n    size: Size<u32>,\n}\n\nimpl Allocation {\n    /// Returns a weak reference to the [`Memory`] of the [`Allocation`].\n    pub fn downgrade(&self) -> Weak<Memory> {\n        Arc::downgrade(&self.0)\n    }\n\n    /// Upgrades a [`Weak`] memory reference to an [`Allocation`].\n    pub fn upgrade(weak: &Weak<Memory>) -> Option<Allocation> {\n        Weak::upgrade(weak).map(Allocation)\n    }\n\n    /// Returns the [`Handle`] of this [`Allocation`].\n    pub fn handle(&self) -> &Handle {\n        &self.0.handle\n    }\n\n    /// Returns the [`Size`] of the image of this [`Allocation`].\n    pub fn size(&self) -> Size<u32> {\n        self.0.size\n    }\n}\n\n/// Creates a new [`Allocation`] for the given handle.\n///\n/// This should only be used internally by renderer implementations.\n///\n/// # Safety\n/// Must only be created once the [`Handle`] is allocated in memory.\n#[allow(unsafe_code)]\npub unsafe fn allocate(handle: &Handle, size: Size<u32>) -> Allocation {\n    Allocation(Arc::new(Memory {\n        handle: handle.clone(),\n        size,\n    }))\n}\n\n/// A [`Renderer`] that can render raster graphics.\n///\n/// [renderer]: crate::renderer\npub trait Renderer: crate::Renderer {\n    /// The image Handle to be displayed. Iced exposes its own default implementation of a [`Handle`]\n    ///\n    /// [`Handle`]: Self::Handle\n    type Handle: Clone;\n\n    /// Loads an image and returns an explicit [`Allocation`] to it.\n    ///\n    /// If the image is not already loaded, this method will block! You should\n    /// generally not use it in drawing logic if you want to avoid frame drops.\n    fn load_image(&self, handle: &Self::Handle) -> Result<Allocation, Error>;\n\n    /// Returns the dimensions of an image for the given [`Handle`].\n    ///\n    /// If the image is not already loaded, the [`Renderer`] may choose to return\n    /// `None`, load the image in the background, and then trigger a relayout.\n    ///\n    /// If you need a measurement right away, consider using [`Renderer::load_image`].\n    fn measure_image(&self, handle: &Self::Handle) -> Option<Size<u32>>;\n\n    /// Draws an [`Image`] inside the provided `bounds`.\n    ///\n    /// If the image is not already loaded, the [`Renderer`] may choose to render\n    /// nothing, load the image in the background, and then trigger a redraw.\n    ///\n    /// If you need to draw an image right away, consider using [`Renderer::load_image`]\n    /// and hold on to an [`Allocation`] first.\n    fn draw_image(&mut self, image: Image<Self::Handle>, bounds: Rectangle, clip_bounds: Rectangle);\n}\n\n/// An image loading error.\n#[derive(Debug, Clone, thiserror::Error)]\npub enum Error {\n    /// The image data was invalid or could not be decoded.\n    #[error(\"the image data was invalid or could not be decoded: {0}\")]\n    Invalid(Arc<dyn std::error::Error + Send + Sync>),\n    /// The image file was not found.\n    #[error(\"the image file could not be opened: {0}\")]\n    Inaccessible(Arc<io::Error>),\n    /// Loading images is unsupported.\n    #[error(\"loading images is unsupported\")]\n    Unsupported,\n    /// The image is empty.\n    #[error(\"the image is empty\")]\n    Empty,\n    /// Not enough memory to allocate the image.\n    #[error(\"not enough memory to allocate the image\")]\n    OutOfMemory,\n}\n"
  },
  {
    "path": "core/src/input_method.rs",
    "content": "//! Listen to input method events.\nuse crate::{Pixels, Rectangle};\n\nuse std::ops::Range;\n\n/// The input method strategy of a widget.\n#[derive(Debug, Clone, PartialEq)]\npub enum InputMethod<T = String> {\n    /// Input method is disabled.\n    Disabled,\n    /// Input method is enabled.\n    Enabled {\n        /// The area of the cursor of the input method.\n        ///\n        /// This area should not be covered.\n        cursor: Rectangle,\n        /// The [`Purpose`] of the input method.\n        purpose: Purpose,\n        /// The preedit to overlay on top of the input method dialog, if needed.\n        ///\n        /// Ideally, your widget will show pre-edits on-the-spot; but, since that can\n        /// be tricky, you can instead provide the current pre-edit here and the\n        /// runtime will display it as an overlay (i.e. \"Over-the-spot IME\").\n        preedit: Option<Preedit<T>>,\n    },\n}\n\n/// The pre-edit of an [`InputMethod`].\n#[derive(Debug, Clone, PartialEq, Default)]\npub struct Preedit<T = String> {\n    /// The current content.\n    pub content: T,\n    /// The selected range of the content.\n    pub selection: Option<Range<usize>>,\n    /// The text size of the content.\n    pub text_size: Option<Pixels>,\n}\n\nimpl<T> Preedit<T> {\n    /// Creates a new empty [`Preedit`].\n    pub fn new() -> Self\n    where\n        T: Default,\n    {\n        Self::default()\n    }\n\n    /// Turns a [`Preedit`] into its owned version.\n    pub fn to_owned(&self) -> Preedit\n    where\n        T: AsRef<str>,\n    {\n        Preedit {\n            content: self.content.as_ref().to_owned(),\n            selection: self.selection.clone(),\n            text_size: self.text_size,\n        }\n    }\n}\n\nimpl Preedit {\n    /// Borrows the contents of a [`Preedit`].\n    pub fn as_ref(&self) -> Preedit<&str> {\n        Preedit {\n            content: &self.content,\n            selection: self.selection.clone(),\n            text_size: self.text_size,\n        }\n    }\n}\n\n/// The purpose of an [`InputMethod`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum Purpose {\n    /// No special hints for the IME (default).\n    #[default]\n    Normal,\n    /// The IME is used for secure input (e.g. passwords).\n    Secure,\n    /// The IME is used to input into a terminal.\n    ///\n    /// For example, that could alter OSK on Wayland to show extra buttons.\n    Terminal,\n}\n\nimpl InputMethod {\n    /// Merges two [`InputMethod`] strategies, prioritizing the first one when both open:\n    /// ```\n    /// # use iced_core::input_method::{InputMethod, Purpose, Preedit};\n    /// # use iced_core::{Point, Rectangle, Size};\n    ///\n    /// let open = InputMethod::Enabled {\n    ///     cursor: Rectangle::new(Point::ORIGIN, Size::UNIT),\n    ///     purpose: Purpose::Normal,\n    ///     preedit: Some(Preedit { content: \"1\".to_owned(), selection: None, text_size: None }),\n    /// };\n    ///\n    /// let open_2 = InputMethod::Enabled {\n    ///     cursor: Rectangle::new(Point::ORIGIN, Size::UNIT),\n    ///     purpose: Purpose::Secure,\n    ///     preedit: Some(Preedit { content: \"2\".to_owned(), selection: None, text_size: None }),\n    /// };\n    ///\n    /// let mut ime = InputMethod::Disabled;\n    ///\n    /// ime.merge(&open);\n    /// assert_eq!(ime, open);\n    ///\n    /// ime.merge(&open_2);\n    /// assert_eq!(ime, open);\n    /// ```\n    pub fn merge<T: AsRef<str>>(&mut self, other: &InputMethod<T>) {\n        if let InputMethod::Enabled { .. } = self {\n            return;\n        }\n\n        *self = other.to_owned();\n    }\n\n    /// Returns true if the [`InputMethod`] is open.\n    pub fn is_enabled(&self) -> bool {\n        matches!(self, Self::Enabled { .. })\n    }\n}\n\nimpl<T> InputMethod<T> {\n    /// Turns an [`InputMethod`] into its owned version.\n    pub fn to_owned(&self) -> InputMethod\n    where\n        T: AsRef<str>,\n    {\n        match self {\n            Self::Disabled => InputMethod::Disabled,\n            Self::Enabled {\n                cursor,\n                purpose,\n                preedit,\n            } => InputMethod::Enabled {\n                cursor: *cursor,\n                purpose: *purpose,\n                preedit: preedit.as_ref().map(Preedit::to_owned),\n            },\n        }\n    }\n}\n\n/// Describes [input method](https://en.wikipedia.org/wiki/Input_method) events.\n///\n/// This is also called a \"composition event\".\n///\n/// Most keypresses using a latin-like keyboard layout simply generate a\n/// [`keyboard::Event::KeyPressed`](crate::keyboard::Event::KeyPressed).\n/// However, one couldn't possibly have a key for every single\n/// unicode character that the user might want to type. The solution operating systems employ is\n/// to allow the user to type these using _a sequence of keypresses_ instead.\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub enum Event {\n    /// Notifies when the IME was opened.\n    ///\n    /// After getting this event you could receive [`Preedit`][Self::Preedit] and\n    /// [`Commit`][Self::Commit] events. You should also start performing IME related requests\n    /// like [`Shell::request_input_method`].\n    ///\n    /// [`Shell::request_input_method`]: crate::Shell::request_input_method\n    Opened,\n\n    /// Notifies when a new composing text should be set at the cursor position.\n    ///\n    /// The value represents a pair of the preedit string and the cursor begin position and end\n    /// position. When it's `None`, the cursor should be hidden. When `String` is an empty string\n    /// this indicates that preedit was cleared.\n    ///\n    /// The cursor range is byte-wise indexed.\n    Preedit(String, Option<Range<usize>>),\n\n    /// Notifies when text should be inserted into the editor widget.\n    ///\n    /// Right before this event, an empty [`Self::Preedit`] event will be issued.\n    Commit(String),\n\n    /// Notifies when the IME was disabled.\n    ///\n    /// After receiving this event you won't get any more [`Preedit`][Self::Preedit] or\n    /// [`Commit`][Self::Commit] events until the next [`Opened`][Self::Opened] event. You should\n    /// also stop issuing IME related requests like [`Shell::request_input_method`] and clear\n    /// pending preedit text.\n    ///\n    /// [`Shell::request_input_method`]: crate::Shell::request_input_method\n    Closed,\n}\n"
  },
  {
    "path": "core/src/keyboard/event.rs",
    "content": "use crate::SmolStr;\nuse crate::keyboard::key;\nuse crate::keyboard::{Key, Location, Modifiers};\n\n/// A keyboard event.\n///\n/// _**Note:** This type is largely incomplete! If you need to track\n/// additional events, feel free to [open an issue] and share your use case!_\n///\n/// [open an issue]: https://github.com/iced-rs/iced/issues\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum Event {\n    /// A keyboard key was pressed.\n    KeyPressed {\n        /// The key pressed.\n        key: Key,\n\n        /// The key pressed with all keyboard modifiers applied, except Ctrl.\n        modified_key: Key,\n\n        /// The physical key pressed.\n        physical_key: key::Physical,\n\n        /// The location of the key.\n        location: Location,\n\n        /// The state of the modifier keys.\n        modifiers: Modifiers,\n\n        /// The text produced by the key press, if any.\n        text: Option<SmolStr>,\n\n        /// Whether the event was the result of key repeat.\n        repeat: bool,\n    },\n\n    /// A keyboard key was released.\n    KeyReleased {\n        /// The key released.\n        key: Key,\n\n        /// The key released with all keyboard modifiers applied, except Ctrl.\n        modified_key: Key,\n\n        /// The physical key released.\n        physical_key: key::Physical,\n\n        /// The location of the key.\n        location: Location,\n\n        /// The state of the modifier keys.\n        modifiers: Modifiers,\n    },\n\n    /// The keyboard modifiers have changed.\n    ModifiersChanged(Modifiers),\n}\n"
  },
  {
    "path": "core/src/keyboard/key.rs",
    "content": "//! Identify keyboard keys.\nuse crate::SmolStr;\n\n/// A key on the keyboard.\n///\n/// This is mostly the `Key` type found in [`winit`].\n///\n/// [`winit`]: https://docs.rs/winit/0.30/winit/keyboard/enum.Key.html\n#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub enum Key<C = SmolStr> {\n    /// A key with an established name.\n    Named(Named),\n\n    /// A key string that corresponds to the character typed by the user, taking into account the\n    /// user’s current locale setting, and any system-level keyboard mapping overrides that are in\n    /// effect.\n    Character(C),\n\n    /// An unidentified key.\n    Unidentified,\n}\n\nimpl Key {\n    /// Convert `Key::Character(SmolStr)` to `Key::Character(&str)` so you can more easily match on\n    /// `Key`. All other variants remain unchanged.\n    pub fn as_ref(&self) -> Key<&str> {\n        match self {\n            Self::Named(named) => Key::Named(*named),\n            Self::Character(c) => Key::Character(c.as_ref()),\n            Self::Unidentified => Key::Unidentified,\n        }\n    }\n\n    /// Tries to convert this logical [`Key`] into its latin character, using the\n    /// [`Physical`] key provided for translation if it isn't already in latin.\n    ///\n    /// Returns `None` if no latin variant could be found.\n    ///\n    /// ```\n    /// use iced_core::keyboard::key::{Key, Named, Physical, Code};\n    ///\n    /// // Latin c\n    /// assert_eq!(\n    ///     Key::Character(\"c\".into()).to_latin(Physical::Code(Code::KeyC)),\n    ///     Some('c'),\n    /// );\n    ///\n    /// // Cyrillic с\n    /// assert_eq!(\n    ///     Key::Character(\"с\".into()).to_latin(Physical::Code(Code::KeyC)),\n    ///     Some('c'),\n    /// );\n    ///\n    /// // Arrow Left\n    /// assert_eq!(\n    ///     Key::Named(Named::ArrowLeft).to_latin(Physical::Code(Code::ArrowLeft)),\n    ///     None,\n    /// );\n    /// ```\n    pub fn to_latin(&self, physical_key: Physical) -> Option<char> {\n        let Self::Character(s) = self else {\n            return None;\n        };\n\n        let mut chars = s.chars();\n        let c = chars.next()?;\n\n        if chars.next().is_none() && c < '\\u{370}' {\n            return Some(c);\n        }\n\n        let Physical::Code(code) = physical_key else {\n            return None;\n        };\n\n        let latin = match code {\n            Code::KeyA => 'a',\n            Code::KeyB => 'b',\n            Code::KeyC => 'c',\n            Code::KeyD => 'd',\n            Code::KeyE => 'e',\n            Code::KeyF => 'f',\n            Code::KeyG => 'g',\n            Code::KeyH => 'h',\n            Code::KeyI => 'i',\n            Code::KeyJ => 'j',\n            Code::KeyK => 'k',\n            Code::KeyL => 'l',\n            Code::KeyM => 'm',\n            Code::KeyN => 'n',\n            Code::KeyO => 'o',\n            Code::KeyP => 'p',\n            Code::KeyQ => 'q',\n            Code::KeyR => 'r',\n            Code::KeyS => 's',\n            Code::KeyT => 't',\n            Code::KeyU => 'u',\n            Code::KeyV => 'v',\n            Code::KeyW => 'w',\n            Code::KeyX => 'x',\n            Code::KeyY => 'y',\n            Code::KeyZ => 'z',\n            Code::Digit0 => '0',\n            Code::Digit1 => '1',\n            Code::Digit2 => '2',\n            Code::Digit3 => '3',\n            Code::Digit4 => '4',\n            Code::Digit5 => '5',\n            Code::Digit6 => '6',\n            Code::Digit7 => '7',\n            Code::Digit8 => '8',\n            Code::Digit9 => '9',\n            _ => return None,\n        };\n\n        Some(latin)\n    }\n}\n\nimpl From<Named> for Key {\n    fn from(named: Named) -> Self {\n        Self::Named(named)\n    }\n}\n\n/// A named key.\n///\n/// This is mostly the `NamedKey` type found in [`winit`].\n///\n/// [`winit`]: https://docs.rs/winit/0.30/winit/keyboard/enum.Key.html\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\n#[allow(missing_docs)]\npub enum Named {\n    /// The `Alt` (Alternative) key.\n    ///\n    /// This key enables the alternate modifier function for interpreting concurrent or subsequent\n    /// keyboard input. This key value is also used for the Apple <kbd>Option</kbd> key.\n    Alt,\n    /// The Alternate Graphics (<kbd>AltGr</kbd> or <kbd>AltGraph</kbd>) key.\n    ///\n    /// This key is used enable the ISO Level 3 shift modifier (the standard `Shift` key is the\n    /// level 2 modifier).\n    AltGraph,\n    /// The `Caps Lock` (Capital) key.\n    ///\n    /// Toggle capital character lock function for interpreting subsequent keyboard input event.\n    CapsLock,\n    /// The `Control` or `Ctrl` key.\n    ///\n    /// Used to enable control modifier function for interpreting concurrent or subsequent keyboard\n    /// input.\n    Control,\n    /// The Function switch `Fn` key. Activating this key simultaneously with another key changes\n    /// that key’s value to an alternate character or function. This key is often handled directly\n    /// in the keyboard hardware and does not usually generate key events.\n    Fn,\n    /// The Function-Lock (`FnLock` or `F-Lock`) key. Activating this key switches the mode of the\n    /// keyboard to changes some keys' values to an alternate character or function. This key is\n    /// often handled directly in the keyboard hardware and does not usually generate key events.\n    FnLock,\n    /// The `NumLock` or Number Lock key. Used to toggle numpad mode function for interpreting\n    /// subsequent keyboard input.\n    NumLock,\n    /// Toggle between scrolling and cursor movement modes.\n    ScrollLock,\n    /// Used to enable shift modifier function for interpreting concurrent or subsequent keyboard\n    /// input.\n    Shift,\n    /// The Symbol modifier key (used on some virtual keyboards).\n    Symbol,\n    SymbolLock,\n    // Legacy modifier key. Also called \"Super\" in certain places.\n    Meta,\n    // Legacy modifier key.\n    Hyper,\n    /// Used to enable \"super\" modifier function for interpreting concurrent or subsequent keyboard\n    /// input. This key value is used for the \"Windows Logo\" key and the Apple `Command` or `⌘` key.\n    ///\n    /// Note: In some contexts (e.g. the Web) this is referred to as the \"Meta\" key.\n    Super,\n    /// The `Enter` or `↵` key. Used to activate current selection or accept current input. This key\n    /// value is also used for the `Return` (Macintosh numpad) key. This key value is also used for\n    /// the Android `KEYCODE_DPAD_CENTER`.\n    Enter,\n    /// The Horizontal Tabulation `Tab` key.\n    Tab,\n    /// Used in text to insert a space between words. Usually located below the character keys.\n    Space,\n    /// Navigate or traverse downward. (`KEYCODE_DPAD_DOWN`)\n    ArrowDown,\n    /// Navigate or traverse leftward. (`KEYCODE_DPAD_LEFT`)\n    ArrowLeft,\n    /// Navigate or traverse rightward. (`KEYCODE_DPAD_RIGHT`)\n    ArrowRight,\n    /// Navigate or traverse upward. (`KEYCODE_DPAD_UP`)\n    ArrowUp,\n    /// The End key, used with keyboard entry to go to the end of content (`KEYCODE_MOVE_END`).\n    End,\n    /// The Home key, used with keyboard entry, to go to start of content (`KEYCODE_MOVE_HOME`).\n    /// For the mobile phone `Home` key (which goes to the phone’s main screen), use [`GoHome`].\n    ///\n    /// [`GoHome`]: Self::GoHome\n    Home,\n    /// Scroll down or display next page of content.\n    PageDown,\n    /// Scroll up or display previous page of content.\n    PageUp,\n    /// Used to remove the character to the left of the cursor. This key value is also used for\n    /// the key labeled `Delete` on MacOS keyboards.\n    Backspace,\n    /// Remove the currently selected input.\n    Clear,\n    /// Copy the current selection. (`APPCOMMAND_COPY`)\n    Copy,\n    /// The Cursor Select key.\n    CrSel,\n    /// Cut the current selection. (`APPCOMMAND_CUT`)\n    Cut,\n    /// Used to delete the character to the right of the cursor. This key value is also used for the\n    /// key labeled `Delete` on MacOS keyboards when `Fn` is active.\n    Delete,\n    /// The Erase to End of Field key. This key deletes all characters from the current cursor\n    /// position to the end of the current field.\n    EraseEof,\n    /// The Extend Selection (Exsel) key.\n    ExSel,\n    /// Toggle between text modes for insertion or overtyping.\n    /// (`KEYCODE_INSERT`)\n    Insert,\n    /// The Paste key. (`APPCOMMAND_PASTE`)\n    Paste,\n    /// Redo the last action. (`APPCOMMAND_REDO`)\n    Redo,\n    /// Undo the last action. (`APPCOMMAND_UNDO`)\n    Undo,\n    /// The Accept (Commit, OK) key. Accept current option or input method sequence conversion.\n    Accept,\n    /// Redo or repeat an action.\n    Again,\n    /// The Attention (Attn) key.\n    Attn,\n    Cancel,\n    /// Show the application’s context menu.\n    /// This key is commonly found between the right `Super` key and the right `Control` key.\n    ContextMenu,\n    /// The `Esc` key. This key was originally used to initiate an escape sequence, but is\n    /// now more generally used to exit or \"escape\" the current context, such as closing a dialog\n    /// or exiting full screen mode.\n    Escape,\n    Execute,\n    /// Open the Find dialog. (`APPCOMMAND_FIND`)\n    Find,\n    /// Open a help dialog or toggle display of help information. (`APPCOMMAND_HELP`,\n    /// `KEYCODE_HELP`)\n    Help,\n    /// Pause the current state or application (as appropriate).\n    ///\n    /// Note: Do not use this value for the `Pause` button on media controllers. Use `\"MediaPause\"`\n    /// instead.\n    Pause,\n    /// Play or resume the current state or application (as appropriate).\n    ///\n    /// Note: Do not use this value for the `Play` button on media controllers. Use `\"MediaPlay\"`\n    /// instead.\n    Play,\n    /// The properties (Props) key.\n    Props,\n    Select,\n    /// The ZoomIn key. (`KEYCODE_ZOOM_IN`)\n    ZoomIn,\n    /// The ZoomOut key. (`KEYCODE_ZOOM_OUT`)\n    ZoomOut,\n    /// The Brightness Down key. Typically controls the display brightness.\n    /// (`KEYCODE_BRIGHTNESS_DOWN`)\n    BrightnessDown,\n    /// The Brightness Up key. Typically controls the display brightness. (`KEYCODE_BRIGHTNESS_UP`)\n    BrightnessUp,\n    /// Toggle removable media to eject (open) and insert (close) state. (`KEYCODE_MEDIA_EJECT`)\n    Eject,\n    LogOff,\n    /// Toggle power state. (`KEYCODE_POWER`)\n    /// Note: Note: Some devices might not expose this key to the operating environment.\n    Power,\n    /// The `PowerOff` key. Sometime called `PowerDown`.\n    PowerOff,\n    /// Initiate print-screen function.\n    PrintScreen,\n    /// The Hibernate key. This key saves the current state of the computer to disk so that it can\n    /// be restored. The computer will then shutdown.\n    Hibernate,\n    /// The Standby key. This key turns off the display and places the computer into a low-power\n    /// mode without completely shutting down. It is sometimes labelled `Suspend` or `Sleep` key.\n    /// (`KEYCODE_SLEEP`)\n    Standby,\n    /// The WakeUp key. (`KEYCODE_WAKEUP`)\n    WakeUp,\n    /// Initiate the multi-candidate mode.\n    AllCandidates,\n    Alphanumeric,\n    /// Initiate the Code Input mode to allow characters to be entered by\n    /// their code points.\n    CodeInput,\n    /// The Compose key, also known as \"Multi_key\" on the X Window System. This key acts in a\n    /// manner similar to a dead key, triggering a mode where subsequent key presses are combined to\n    /// produce a different character.\n    Compose,\n    /// Convert the current input method sequence.\n    Convert,\n    /// The Final Mode `Final` key used on some Asian keyboards, to enable the final mode for IMEs.\n    FinalMode,\n    /// Switch to the first character group. (ISO/IEC 9995)\n    GroupFirst,\n    /// Switch to the last character group. (ISO/IEC 9995)\n    GroupLast,\n    /// Switch to the next character group. (ISO/IEC 9995)\n    GroupNext,\n    /// Switch to the previous character group. (ISO/IEC 9995)\n    GroupPrevious,\n    /// Toggle between or cycle through input modes of IMEs.\n    ModeChange,\n    NextCandidate,\n    /// Accept current input method sequence without\n    /// conversion in IMEs.\n    NonConvert,\n    PreviousCandidate,\n    Process,\n    SingleCandidate,\n    /// Toggle between Hangul and English modes.\n    HangulMode,\n    HanjaMode,\n    JunjaMode,\n    /// The Eisu key. This key may close the IME, but its purpose is defined by the current IME.\n    /// (`KEYCODE_EISU`)\n    Eisu,\n    /// The (Half-Width) Characters key.\n    Hankaku,\n    /// The Hiragana (Japanese Kana characters) key.\n    Hiragana,\n    /// The Hiragana/Katakana toggle key. (`KEYCODE_KATAKANA_HIRAGANA`)\n    HiraganaKatakana,\n    /// The Kana Mode (Kana Lock) key. This key is used to enter hiragana mode (typically from\n    /// romaji mode).\n    KanaMode,\n    /// The Kanji (Japanese name for ideographic characters of Chinese origin) Mode key. This key is\n    /// typically used to switch to a hiragana keyboard for the purpose of converting input into\n    /// kanji. (`KEYCODE_KANA`)\n    KanjiMode,\n    /// The Katakana (Japanese Kana characters) key.\n    Katakana,\n    /// The Roman characters function key.\n    Romaji,\n    /// The Zenkaku (Full-Width) Characters key.\n    Zenkaku,\n    /// The Zenkaku/Hankaku (full-width/half-width) toggle key. (`KEYCODE_ZENKAKU_HANKAKU`)\n    ZenkakuHankaku,\n    /// General purpose virtual function key, as index 1.\n    Soft1,\n    /// General purpose virtual function key, as index 2.\n    Soft2,\n    /// General purpose virtual function key, as index 3.\n    Soft3,\n    /// General purpose virtual function key, as index 4.\n    Soft4,\n    /// Select next (numerically or logically) lower channel. (`APPCOMMAND_MEDIA_CHANNEL_DOWN`,\n    /// `KEYCODE_CHANNEL_DOWN`)\n    ChannelDown,\n    /// Select next (numerically or logically) higher channel. (`APPCOMMAND_MEDIA_CHANNEL_UP`,\n    /// `KEYCODE_CHANNEL_UP`)\n    ChannelUp,\n    /// Close the current document or message (Note: This doesn’t close the application).\n    /// (`APPCOMMAND_CLOSE`)\n    Close,\n    /// Open an editor to forward the current message. (`APPCOMMAND_FORWARD_MAIL`)\n    MailForward,\n    /// Open an editor to reply to the current message. (`APPCOMMAND_REPLY_TO_MAIL`)\n    MailReply,\n    /// Send the current message. (`APPCOMMAND_SEND_MAIL`)\n    MailSend,\n    /// Close the current media, for example to close a CD or DVD tray. (`KEYCODE_MEDIA_CLOSE`)\n    MediaClose,\n    /// Initiate or continue forward playback at faster than normal speed, or increase speed if\n    /// already fast forwarding. (`APPCOMMAND_MEDIA_FAST_FORWARD`, `KEYCODE_MEDIA_FAST_FORWARD`)\n    MediaFastForward,\n    /// Pause the currently playing media. (`APPCOMMAND_MEDIA_PAUSE`, `KEYCODE_MEDIA_PAUSE`)\n    ///\n    /// Note: Media controller devices should use this value rather than `\"Pause\"` for their pause\n    /// keys.\n    MediaPause,\n    /// Initiate or continue media playback at normal speed, if not currently playing at normal\n    /// speed. (`APPCOMMAND_MEDIA_PLAY`, `KEYCODE_MEDIA_PLAY`)\n    MediaPlay,\n    /// Toggle media between play and pause states. (`APPCOMMAND_MEDIA_PLAY_PAUSE`,\n    /// `KEYCODE_MEDIA_PLAY_PAUSE`)\n    MediaPlayPause,\n    /// Initiate or resume recording of currently selected media. (`APPCOMMAND_MEDIA_RECORD`,\n    /// `KEYCODE_MEDIA_RECORD`)\n    MediaRecord,\n    /// Initiate or continue reverse playback at faster than normal speed, or increase speed if\n    /// already rewinding. (`APPCOMMAND_MEDIA_REWIND`, `KEYCODE_MEDIA_REWIND`)\n    MediaRewind,\n    /// Stop media playing, pausing, forwarding, rewinding, or recording, if not already stopped.\n    /// (`APPCOMMAND_MEDIA_STOP`, `KEYCODE_MEDIA_STOP`)\n    MediaStop,\n    /// Seek to next media or program track. (`APPCOMMAND_MEDIA_NEXTTRACK`, `KEYCODE_MEDIA_NEXT`)\n    MediaTrackNext,\n    /// Seek to previous media or program track. (`APPCOMMAND_MEDIA_PREVIOUSTRACK`,\n    /// `KEYCODE_MEDIA_PREVIOUS`)\n    MediaTrackPrevious,\n    /// Open a new document or message. (`APPCOMMAND_NEW`)\n    New,\n    /// Open an existing document or message. (`APPCOMMAND_OPEN`)\n    Open,\n    /// Print the current document or message. (`APPCOMMAND_PRINT`)\n    Print,\n    /// Save the current document or message. (`APPCOMMAND_SAVE`)\n    Save,\n    /// Spellcheck the current document or selection. (`APPCOMMAND_SPELL_CHECK`)\n    SpellCheck,\n    /// The `11` key found on media numpads that\n    /// have buttons from `1` ... `12`.\n    Key11,\n    /// The `12` key found on media numpads that\n    /// have buttons from `1` ... `12`.\n    Key12,\n    /// Adjust audio balance leftward. (`VK_AUDIO_BALANCE_LEFT`)\n    AudioBalanceLeft,\n    /// Adjust audio balance rightward. (`VK_AUDIO_BALANCE_RIGHT`)\n    AudioBalanceRight,\n    /// Decrease audio bass boost or cycle down through bass boost states. (`APPCOMMAND_BASS_DOWN`,\n    /// `VK_BASS_BOOST_DOWN`)\n    AudioBassBoostDown,\n    /// Toggle bass boost on/off. (`APPCOMMAND_BASS_BOOST`)\n    AudioBassBoostToggle,\n    /// Increase audio bass boost or cycle up through bass boost states. (`APPCOMMAND_BASS_UP`,\n    /// `VK_BASS_BOOST_UP`)\n    AudioBassBoostUp,\n    /// Adjust audio fader towards front. (`VK_FADER_FRONT`)\n    AudioFaderFront,\n    /// Adjust audio fader towards rear. (`VK_FADER_REAR`)\n    AudioFaderRear,\n    /// Advance surround audio mode to next available mode. (`VK_SURROUND_MODE_NEXT`)\n    AudioSurroundModeNext,\n    /// Decrease treble. (`APPCOMMAND_TREBLE_DOWN`)\n    AudioTrebleDown,\n    /// Increase treble. (`APPCOMMAND_TREBLE_UP`)\n    AudioTrebleUp,\n    /// Decrease audio volume. (`APPCOMMAND_VOLUME_DOWN`, `KEYCODE_VOLUME_DOWN`)\n    AudioVolumeDown,\n    /// Increase audio volume. (`APPCOMMAND_VOLUME_UP`, `KEYCODE_VOLUME_UP`)\n    AudioVolumeUp,\n    /// Toggle between muted state and prior volume level. (`APPCOMMAND_VOLUME_MUTE`,\n    /// `KEYCODE_VOLUME_MUTE`)\n    AudioVolumeMute,\n    /// Toggle the microphone on/off. (`APPCOMMAND_MIC_ON_OFF_TOGGLE`)\n    MicrophoneToggle,\n    /// Decrease microphone volume. (`APPCOMMAND_MICROPHONE_VOLUME_DOWN`)\n    MicrophoneVolumeDown,\n    /// Increase microphone volume. (`APPCOMMAND_MICROPHONE_VOLUME_UP`)\n    MicrophoneVolumeUp,\n    /// Mute the microphone. (`APPCOMMAND_MICROPHONE_VOLUME_MUTE`, `KEYCODE_MUTE`)\n    MicrophoneVolumeMute,\n    /// Show correction list when a word is incorrectly identified. (`APPCOMMAND_CORRECTION_LIST`)\n    SpeechCorrectionList,\n    /// Toggle between dictation mode and command/control mode.\n    /// (`APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE`)\n    SpeechInputToggle,\n    /// The first generic \"LaunchApplication\" key. This is commonly associated with launching \"My\n    /// Computer\", and may have a computer symbol on the key. (`APPCOMMAND_LAUNCH_APP1`)\n    LaunchApplication1,\n    /// The second generic \"LaunchApplication\" key. This is commonly associated with launching\n    /// \"Calculator\", and may have a calculator symbol on the key. (`APPCOMMAND_LAUNCH_APP2`,\n    /// `KEYCODE_CALCULATOR`)\n    LaunchApplication2,\n    /// The \"Calendar\" key. (`KEYCODE_CALENDAR`)\n    LaunchCalendar,\n    /// The \"Contacts\" key. (`KEYCODE_CONTACTS`)\n    LaunchContacts,\n    /// The \"Mail\" key. (`APPCOMMAND_LAUNCH_MAIL`)\n    LaunchMail,\n    /// The \"Media Player\" key. (`APPCOMMAND_LAUNCH_MEDIA_SELECT`)\n    LaunchMediaPlayer,\n    LaunchMusicPlayer,\n    LaunchPhone,\n    LaunchScreenSaver,\n    LaunchSpreadsheet,\n    LaunchWebBrowser,\n    LaunchWebCam,\n    LaunchWordProcessor,\n    /// Navigate to previous content or page in current history. (`APPCOMMAND_BROWSER_BACKWARD`)\n    BrowserBack,\n    /// Open the list of browser favorites. (`APPCOMMAND_BROWSER_FAVORITES`)\n    BrowserFavorites,\n    /// Navigate to next content or page in current history. (`APPCOMMAND_BROWSER_FORWARD`)\n    BrowserForward,\n    /// Go to the user’s preferred home page. (`APPCOMMAND_BROWSER_HOME`)\n    BrowserHome,\n    /// Refresh the current page or content. (`APPCOMMAND_BROWSER_REFRESH`)\n    BrowserRefresh,\n    /// Call up the user’s preferred search page. (`APPCOMMAND_BROWSER_SEARCH`)\n    BrowserSearch,\n    /// Stop loading the current page or content. (`APPCOMMAND_BROWSER_STOP`)\n    BrowserStop,\n    /// The Application switch key, which provides a list of recent apps to switch between.\n    /// (`KEYCODE_APP_SWITCH`)\n    AppSwitch,\n    /// The Call key. (`KEYCODE_CALL`)\n    Call,\n    /// The Camera key. (`KEYCODE_CAMERA`)\n    Camera,\n    /// The Camera focus key. (`KEYCODE_FOCUS`)\n    CameraFocus,\n    /// The End Call key. (`KEYCODE_ENDCALL`)\n    EndCall,\n    /// The Back key. (`KEYCODE_BACK`)\n    GoBack,\n    /// The Home key, which goes to the phone’s main screen. (`KEYCODE_HOME`)\n    GoHome,\n    /// The Headset Hook key. (`KEYCODE_HEADSETHOOK`)\n    HeadsetHook,\n    LastNumberRedial,\n    /// The Notification key. (`KEYCODE_NOTIFICATION`)\n    Notification,\n    /// Toggle between manner mode state: silent, vibrate, ring, ... (`KEYCODE_MANNER_MODE`)\n    MannerMode,\n    VoiceDial,\n    /// Switch to viewing TV. (`KEYCODE_TV`)\n    TV,\n    /// TV 3D Mode. (`KEYCODE_3D_MODE`)\n    TV3DMode,\n    /// Toggle between antenna and cable input. (`KEYCODE_TV_ANTENNA_CABLE`)\n    TVAntennaCable,\n    /// Audio description. (`KEYCODE_TV_AUDIO_DESCRIPTION`)\n    TVAudioDescription,\n    /// Audio description mixing volume down. (`KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN`)\n    TVAudioDescriptionMixDown,\n    /// Audio description mixing volume up. (`KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP`)\n    TVAudioDescriptionMixUp,\n    /// Contents menu. (`KEYCODE_TV_CONTENTS_MENU`)\n    TVContentsMenu,\n    /// Contents menu. (`KEYCODE_TV_DATA_SERVICE`)\n    TVDataService,\n    /// Switch the input mode on an external TV. (`KEYCODE_TV_INPUT`)\n    TVInput,\n    /// Switch to component input #1. (`KEYCODE_TV_INPUT_COMPONENT_1`)\n    TVInputComponent1,\n    /// Switch to component input #2. (`KEYCODE_TV_INPUT_COMPONENT_2`)\n    TVInputComponent2,\n    /// Switch to composite input #1. (`KEYCODE_TV_INPUT_COMPOSITE_1`)\n    TVInputComposite1,\n    /// Switch to composite input #2. (`KEYCODE_TV_INPUT_COMPOSITE_2`)\n    TVInputComposite2,\n    /// Switch to HDMI input #1. (`KEYCODE_TV_INPUT_HDMI_1`)\n    TVInputHDMI1,\n    /// Switch to HDMI input #2. (`KEYCODE_TV_INPUT_HDMI_2`)\n    TVInputHDMI2,\n    /// Switch to HDMI input #3. (`KEYCODE_TV_INPUT_HDMI_3`)\n    TVInputHDMI3,\n    /// Switch to HDMI input #4. (`KEYCODE_TV_INPUT_HDMI_4`)\n    TVInputHDMI4,\n    /// Switch to VGA input #1. (`KEYCODE_TV_INPUT_VGA_1`)\n    TVInputVGA1,\n    /// Media context menu. (`KEYCODE_TV_MEDIA_CONTEXT_MENU`)\n    TVMediaContext,\n    /// Toggle network. (`KEYCODE_TV_NETWORK`)\n    TVNetwork,\n    /// Number entry. (`KEYCODE_TV_NUMBER_ENTRY`)\n    TVNumberEntry,\n    /// Toggle the power on an external TV. (`KEYCODE_TV_POWER`)\n    TVPower,\n    /// Radio. (`KEYCODE_TV_RADIO_SERVICE`)\n    TVRadioService,\n    /// Satellite. (`KEYCODE_TV_SATELLITE`)\n    TVSatellite,\n    /// Broadcast Satellite. (`KEYCODE_TV_SATELLITE_BS`)\n    TVSatelliteBS,\n    /// Communication Satellite. (`KEYCODE_TV_SATELLITE_CS`)\n    TVSatelliteCS,\n    /// Toggle between available satellites. (`KEYCODE_TV_SATELLITE_SERVICE`)\n    TVSatelliteToggle,\n    /// Analog Terrestrial. (`KEYCODE_TV_TERRESTRIAL_ANALOG`)\n    TVTerrestrialAnalog,\n    /// Digital Terrestrial. (`KEYCODE_TV_TERRESTRIAL_DIGITAL`)\n    TVTerrestrialDigital,\n    /// Timer programming. (`KEYCODE_TV_TIMER_PROGRAMMING`)\n    TVTimer,\n    /// Switch the input mode on an external AVR (audio/video receiver). (`KEYCODE_AVR_INPUT`)\n    AVRInput,\n    /// Toggle the power on an external AVR (audio/video receiver). (`KEYCODE_AVR_POWER`)\n    AVRPower,\n    /// General purpose color-coded media function key, as index 0 (red). (`VK_COLORED_KEY_0`,\n    /// `KEYCODE_PROG_RED`)\n    ColorF0Red,\n    /// General purpose color-coded media function key, as index 1 (green). (`VK_COLORED_KEY_1`,\n    /// `KEYCODE_PROG_GREEN`)\n    ColorF1Green,\n    /// General purpose color-coded media function key, as index 2 (yellow). (`VK_COLORED_KEY_2`,\n    /// `KEYCODE_PROG_YELLOW`)\n    ColorF2Yellow,\n    /// General purpose color-coded media function key, as index 3 (blue). (`VK_COLORED_KEY_3`,\n    /// `KEYCODE_PROG_BLUE`)\n    ColorF3Blue,\n    /// General purpose color-coded media function key, as index 4 (grey). (`VK_COLORED_KEY_4`)\n    ColorF4Grey,\n    /// General purpose color-coded media function key, as index 5 (brown). (`VK_COLORED_KEY_5`)\n    ColorF5Brown,\n    /// Toggle the display of Closed Captions. (`VK_CC`, `KEYCODE_CAPTIONS`)\n    ClosedCaptionToggle,\n    /// Adjust brightness of device, by toggling between or cycling through states. (`VK_DIMMER`)\n    Dimmer,\n    /// Swap video sources. (`VK_DISPLAY_SWAP`)\n    DisplaySwap,\n    /// Select Digital Video Rrecorder. (`KEYCODE_DVR`)\n    DVR,\n    /// Exit the current application. (`VK_EXIT`)\n    Exit,\n    /// Clear program or content stored as favorite 0. (`VK_CLEAR_FAVORITE_0`)\n    FavoriteClear0,\n    /// Clear program or content stored as favorite 1. (`VK_CLEAR_FAVORITE_1`)\n    FavoriteClear1,\n    /// Clear program or content stored as favorite 2. (`VK_CLEAR_FAVORITE_2`)\n    FavoriteClear2,\n    /// Clear program or content stored as favorite 3. (`VK_CLEAR_FAVORITE_3`)\n    FavoriteClear3,\n    /// Select (recall) program or content stored as favorite 0. (`VK_RECALL_FAVORITE_0`)\n    FavoriteRecall0,\n    /// Select (recall) program or content stored as favorite 1. (`VK_RECALL_FAVORITE_1`)\n    FavoriteRecall1,\n    /// Select (recall) program or content stored as favorite 2. (`VK_RECALL_FAVORITE_2`)\n    FavoriteRecall2,\n    /// Select (recall) program or content stored as favorite 3. (`VK_RECALL_FAVORITE_3`)\n    FavoriteRecall3,\n    /// Store current program or content as favorite 0. (`VK_STORE_FAVORITE_0`)\n    FavoriteStore0,\n    /// Store current program or content as favorite 1. (`VK_STORE_FAVORITE_1`)\n    FavoriteStore1,\n    /// Store current program or content as favorite 2. (`VK_STORE_FAVORITE_2`)\n    FavoriteStore2,\n    /// Store current program or content as favorite 3. (`VK_STORE_FAVORITE_3`)\n    FavoriteStore3,\n    /// Toggle display of program or content guide. (`VK_GUIDE`, `KEYCODE_GUIDE`)\n    Guide,\n    /// If guide is active and displayed, then display next day’s content. (`VK_NEXT_DAY`)\n    GuideNextDay,\n    /// If guide is active and displayed, then display previous day’s content. (`VK_PREV_DAY`)\n    GuidePreviousDay,\n    /// Toggle display of information about currently selected context or media. (`VK_INFO`,\n    /// `KEYCODE_INFO`)\n    Info,\n    /// Toggle instant replay. (`VK_INSTANT_REPLAY`)\n    InstantReplay,\n    /// Launch linked content, if available and appropriate. (`VK_LINK`)\n    Link,\n    /// List the current program. (`VK_LIST`)\n    ListProgram,\n    /// Toggle display listing of currently available live content or programs. (`VK_LIVE`)\n    LiveContent,\n    /// Lock or unlock current content or program. (`VK_LOCK`)\n    Lock,\n    /// Show a list of media applications: audio/video players and image viewers. (`VK_APPS`)\n    ///\n    /// Note: Do not confuse this key value with the Windows' `VK_APPS` / `VK_CONTEXT_MENU` key,\n    /// which is encoded as `\"ContextMenu\"`.\n    MediaApps,\n    /// Audio track key. (`KEYCODE_MEDIA_AUDIO_TRACK`)\n    MediaAudioTrack,\n    /// Select previously selected channel or media. (`VK_LAST`, `KEYCODE_LAST_CHANNEL`)\n    MediaLast,\n    /// Skip backward to next content or program. (`KEYCODE_MEDIA_SKIP_BACKWARD`)\n    MediaSkipBackward,\n    /// Skip forward to next content or program. (`VK_SKIP`, `KEYCODE_MEDIA_SKIP_FORWARD`)\n    MediaSkipForward,\n    /// Step backward to next content or program. (`KEYCODE_MEDIA_STEP_BACKWARD`)\n    MediaStepBackward,\n    /// Step forward to next content or program. (`KEYCODE_MEDIA_STEP_FORWARD`)\n    MediaStepForward,\n    /// Media top menu. (`KEYCODE_MEDIA_TOP_MENU`)\n    MediaTopMenu,\n    /// Navigate in. (`KEYCODE_NAVIGATE_IN`)\n    NavigateIn,\n    /// Navigate to next key. (`KEYCODE_NAVIGATE_NEXT`)\n    NavigateNext,\n    /// Navigate out. (`KEYCODE_NAVIGATE_OUT`)\n    NavigateOut,\n    /// Navigate to previous key. (`KEYCODE_NAVIGATE_PREVIOUS`)\n    NavigatePrevious,\n    /// Cycle to next favorite channel (in favorites list). (`VK_NEXT_FAVORITE_CHANNEL`)\n    NextFavoriteChannel,\n    /// Cycle to next user profile (if there are multiple user profiles). (`VK_USER`)\n    NextUserProfile,\n    /// Access on-demand content or programs. (`VK_ON_DEMAND`)\n    OnDemand,\n    /// Pairing key to pair devices. (`KEYCODE_PAIRING`)\n    Pairing,\n    /// Move picture-in-picture window down. (`VK_PINP_DOWN`)\n    PinPDown,\n    /// Move picture-in-picture window. (`VK_PINP_MOVE`)\n    PinPMove,\n    /// Toggle display of picture-in-picture window. (`VK_PINP_TOGGLE`)\n    PinPToggle,\n    /// Move picture-in-picture window up. (`VK_PINP_UP`)\n    PinPUp,\n    /// Decrease media playback speed. (`VK_PLAY_SPEED_DOWN`)\n    PlaySpeedDown,\n    /// Reset playback to normal speed. (`VK_PLAY_SPEED_RESET`)\n    PlaySpeedReset,\n    /// Increase media playback speed. (`VK_PLAY_SPEED_UP`)\n    PlaySpeedUp,\n    /// Toggle random media or content shuffle mode. (`VK_RANDOM_TOGGLE`)\n    RandomToggle,\n    /// Not a physical key, but this key code is sent when the remote control battery is low.\n    /// (`VK_RC_LOW_BATTERY`)\n    RcLowBattery,\n    /// Toggle or cycle between media recording speeds. (`VK_RECORD_SPEED_NEXT`)\n    RecordSpeedNext,\n    /// Toggle RF (radio frequency) input bypass mode (pass RF input directly to the RF output).\n    /// (`VK_RF_BYPASS`)\n    RfBypass,\n    /// Toggle scan channels mode. (`VK_SCAN_CHANNELS_TOGGLE`)\n    ScanChannelsToggle,\n    /// Advance display screen mode to next available mode. (`VK_SCREEN_MODE_NEXT`)\n    ScreenModeNext,\n    /// Toggle display of device settings screen. (`VK_SETTINGS`, `KEYCODE_SETTINGS`)\n    Settings,\n    /// Toggle split screen mode. (`VK_SPLIT_SCREEN_TOGGLE`)\n    SplitScreenToggle,\n    /// Switch the input mode on an external STB (set top box). (`KEYCODE_STB_INPUT`)\n    STBInput,\n    /// Toggle the power on an external STB (set top box). (`KEYCODE_STB_POWER`)\n    STBPower,\n    /// Toggle display of subtitles, if available. (`VK_SUBTITLE`)\n    Subtitle,\n    /// Toggle display of teletext, if available (`VK_TELETEXT`, `KEYCODE_TV_TELETEXT`).\n    Teletext,\n    /// Advance video mode to next available mode. (`VK_VIDEO_MODE_NEXT`)\n    VideoModeNext,\n    /// Cause device to identify itself in some manner, e.g., audibly or visibly. (`VK_WINK`)\n    Wink,\n    /// Toggle between full-screen and scaled content, or alter magnification level. (`VK_ZOOM`,\n    /// `KEYCODE_TV_ZOOM_MODE`)\n    ZoomToggle,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F1,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F2,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F3,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F4,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F5,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F6,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F7,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F8,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F9,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F10,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F11,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F12,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F13,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F14,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F15,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F16,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F17,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F18,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F19,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F20,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F21,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F22,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F23,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F24,\n    /// General-purpose function key.\n    F25,\n    /// General-purpose function key.\n    F26,\n    /// General-purpose function key.\n    F27,\n    /// General-purpose function key.\n    F28,\n    /// General-purpose function key.\n    F29,\n    /// General-purpose function key.\n    F30,\n    /// General-purpose function key.\n    F31,\n    /// General-purpose function key.\n    F32,\n    /// General-purpose function key.\n    F33,\n    /// General-purpose function key.\n    F34,\n    /// General-purpose function key.\n    F35,\n}\n\n/// Code representing the location of a physical key.\n///\n/// This mostly conforms to the UI Events Specification's [`KeyboardEvent.code`] with a few\n/// exceptions:\n/// - The keys that the specification calls \"MetaLeft\" and \"MetaRight\" are named \"SuperLeft\" and\n///   \"SuperRight\" here.\n/// - The key that the specification calls \"Super\" is reported as `Unidentified` here.\n///\n/// [`KeyboardEvent.code`]: https://w3c.github.io/uievents-code/#code-value-tables\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\n#[allow(missing_docs)]\n#[non_exhaustive]\npub enum Code {\n    /// <kbd>`</kbd> on a US keyboard. This is also called a backtick or grave.\n    /// This is the <kbd>半角</kbd>/<kbd>全角</kbd>/<kbd>漢字</kbd>\n    /// (hankaku/zenkaku/kanji) key on Japanese keyboards\n    Backquote,\n    /// Used for both the US <kbd>\\\\</kbd> (on the 101-key layout) and also for the key\n    /// located between the <kbd>\"</kbd> and <kbd>Enter</kbd> keys on row C of the 102-,\n    /// 104- and 106-key layouts.\n    /// Labeled <kbd>#</kbd> on a UK (102) keyboard.\n    Backslash,\n    /// <kbd>[</kbd> on a US keyboard.\n    BracketLeft,\n    /// <kbd>]</kbd> on a US keyboard.\n    BracketRight,\n    /// <kbd>,</kbd> on a US keyboard.\n    Comma,\n    /// <kbd>0</kbd> on a US keyboard.\n    Digit0,\n    /// <kbd>1</kbd> on a US keyboard.\n    Digit1,\n    /// <kbd>2</kbd> on a US keyboard.\n    Digit2,\n    /// <kbd>3</kbd> on a US keyboard.\n    Digit3,\n    /// <kbd>4</kbd> on a US keyboard.\n    Digit4,\n    /// <kbd>5</kbd> on a US keyboard.\n    Digit5,\n    /// <kbd>6</kbd> on a US keyboard.\n    Digit6,\n    /// <kbd>7</kbd> on a US keyboard.\n    Digit7,\n    /// <kbd>8</kbd> on a US keyboard.\n    Digit8,\n    /// <kbd>9</kbd> on a US keyboard.\n    Digit9,\n    /// <kbd>=</kbd> on a US keyboard.\n    Equal,\n    /// Located between the left <kbd>Shift</kbd> and <kbd>Z</kbd> keys.\n    /// Labeled <kbd>\\\\</kbd> on a UK keyboard.\n    IntlBackslash,\n    /// Located between the <kbd>/</kbd> and right <kbd>Shift</kbd> keys.\n    /// Labeled <kbd>\\\\</kbd> (ro) on a Japanese keyboard.\n    IntlRo,\n    /// Located between the <kbd>=</kbd> and <kbd>Backspace</kbd> keys.\n    /// Labeled <kbd>¥</kbd> (yen) on a Japanese keyboard. <kbd>\\\\</kbd> on a\n    /// Russian keyboard.\n    IntlYen,\n    /// <kbd>a</kbd> on a US keyboard.\n    /// Labeled <kbd>q</kbd> on an AZERTY (e.g., French) keyboard.\n    KeyA,\n    /// <kbd>b</kbd> on a US keyboard.\n    KeyB,\n    /// <kbd>c</kbd> on a US keyboard.\n    KeyC,\n    /// <kbd>d</kbd> on a US keyboard.\n    KeyD,\n    /// <kbd>e</kbd> on a US keyboard.\n    KeyE,\n    /// <kbd>f</kbd> on a US keyboard.\n    KeyF,\n    /// <kbd>g</kbd> on a US keyboard.\n    KeyG,\n    /// <kbd>h</kbd> on a US keyboard.\n    KeyH,\n    /// <kbd>i</kbd> on a US keyboard.\n    KeyI,\n    /// <kbd>j</kbd> on a US keyboard.\n    KeyJ,\n    /// <kbd>k</kbd> on a US keyboard.\n    KeyK,\n    /// <kbd>l</kbd> on a US keyboard.\n    KeyL,\n    /// <kbd>m</kbd> on a US keyboard.\n    KeyM,\n    /// <kbd>n</kbd> on a US keyboard.\n    KeyN,\n    /// <kbd>o</kbd> on a US keyboard.\n    KeyO,\n    /// <kbd>p</kbd> on a US keyboard.\n    KeyP,\n    /// <kbd>q</kbd> on a US keyboard.\n    /// Labeled <kbd>a</kbd> on an AZERTY (e.g., French) keyboard.\n    KeyQ,\n    /// <kbd>r</kbd> on a US keyboard.\n    KeyR,\n    /// <kbd>s</kbd> on a US keyboard.\n    KeyS,\n    /// <kbd>t</kbd> on a US keyboard.\n    KeyT,\n    /// <kbd>u</kbd> on a US keyboard.\n    KeyU,\n    /// <kbd>v</kbd> on a US keyboard.\n    KeyV,\n    /// <kbd>w</kbd> on a US keyboard.\n    /// Labeled <kbd>z</kbd> on an AZERTY (e.g., French) keyboard.\n    KeyW,\n    /// <kbd>x</kbd> on a US keyboard.\n    KeyX,\n    /// <kbd>y</kbd> on a US keyboard.\n    /// Labeled <kbd>z</kbd> on a QWERTZ (e.g., German) keyboard.\n    KeyY,\n    /// <kbd>z</kbd> on a US keyboard.\n    /// Labeled <kbd>w</kbd> on an AZERTY (e.g., French) keyboard, and <kbd>y</kbd> on a\n    /// QWERTZ (e.g., German) keyboard.\n    KeyZ,\n    /// <kbd>-</kbd> on a US keyboard.\n    Minus,\n    /// <kbd>.</kbd> on a US keyboard.\n    Period,\n    /// <kbd>'</kbd> on a US keyboard.\n    Quote,\n    /// <kbd>;</kbd> on a US keyboard.\n    Semicolon,\n    /// <kbd>/</kbd> on a US keyboard.\n    Slash,\n    /// <kbd>Alt</kbd>, <kbd>Option</kbd>, or <kbd>⌥</kbd>.\n    AltLeft,\n    /// <kbd>Alt</kbd>, <kbd>Option</kbd>, or <kbd>⌥</kbd>.\n    /// This is labeled <kbd>AltGr</kbd> on many keyboard layouts.\n    AltRight,\n    /// <kbd>Backspace</kbd> or <kbd>⌫</kbd>.\n    /// Labeled <kbd>Delete</kbd> on Apple keyboards.\n    Backspace,\n    /// <kbd>CapsLock</kbd> or <kbd>⇪</kbd>\n    CapsLock,\n    /// The application context menu key, which is typically found between the right\n    /// <kbd>Super</kbd> key and the right <kbd>Control</kbd> key.\n    ContextMenu,\n    /// <kbd>Control</kbd> or <kbd>⌃</kbd>\n    ControlLeft,\n    /// <kbd>Control</kbd> or <kbd>⌃</kbd>\n    ControlRight,\n    /// <kbd>Enter</kbd> or <kbd>↵</kbd>. Labeled <kbd>Return</kbd> on Apple keyboards.\n    Enter,\n    /// The Windows, <kbd>⌘</kbd>, <kbd>Command</kbd>, or other OS symbol key.\n    SuperLeft,\n    /// The Windows, <kbd>⌘</kbd>, <kbd>Command</kbd>, or other OS symbol key.\n    SuperRight,\n    /// <kbd>Shift</kbd> or <kbd>⇧</kbd>\n    ShiftLeft,\n    /// <kbd>Shift</kbd> or <kbd>⇧</kbd>\n    ShiftRight,\n    /// <kbd> </kbd> (space)\n    Space,\n    /// <kbd>Tab</kbd> or <kbd>⇥</kbd>\n    Tab,\n    /// Japanese: <kbd>変</kbd> (henkan)\n    Convert,\n    /// Japanese: <kbd>カタカナ</kbd>/<kbd>ひらがな</kbd>/<kbd>ローマ字</kbd>\n    /// (katakana/hiragana/romaji)\n    KanaMode,\n    /// Korean: HangulMode <kbd>한/영</kbd> (han/yeong)\n    ///\n    /// Japanese (Mac keyboard): <kbd>か</kbd> (kana)\n    Lang1,\n    /// Korean: Hanja <kbd>한</kbd> (hanja)\n    ///\n    /// Japanese (Mac keyboard): <kbd>英</kbd> (eisu)\n    Lang2,\n    /// Japanese (word-processing keyboard): Katakana\n    Lang3,\n    /// Japanese (word-processing keyboard): Hiragana\n    Lang4,\n    /// Japanese (word-processing keyboard): Zenkaku/Hankaku\n    Lang5,\n    /// Japanese: <kbd>無変換</kbd> (muhenkan)\n    NonConvert,\n    /// <kbd>⌦</kbd>. The forward delete key.\n    /// Note that on Apple keyboards, the key labelled <kbd>Delete</kbd> on the main part of\n    /// the keyboard is encoded as [`Backspace`].\n    ///\n    /// [`Backspace`]: Self::Backspace\n    Delete,\n    /// <kbd>Page Down</kbd>, <kbd>End</kbd>, or <kbd>↘</kbd>\n    End,\n    /// <kbd>Help</kbd>. Not present on standard PC keyboards.\n    Help,\n    /// <kbd>Home</kbd> or <kbd>↖</kbd>\n    Home,\n    /// <kbd>Insert</kbd> or <kbd>Ins</kbd>. Not present on Apple keyboards.\n    Insert,\n    /// <kbd>Page Down</kbd>, <kbd>PgDn</kbd>, or <kbd>⇟</kbd>\n    PageDown,\n    /// <kbd>Page Up</kbd>, <kbd>PgUp</kbd>, or <kbd>⇞</kbd>\n    PageUp,\n    /// <kbd>↓</kbd>\n    ArrowDown,\n    /// <kbd>←</kbd>\n    ArrowLeft,\n    /// <kbd>→</kbd>\n    ArrowRight,\n    /// <kbd>↑</kbd>\n    ArrowUp,\n    /// On the Mac, this is used for the numpad <kbd>Clear</kbd> key.\n    NumLock,\n    /// <kbd>0 Ins</kbd> on a keyboard. <kbd>0</kbd> on a phone or remote control\n    Numpad0,\n    /// <kbd>1 End</kbd> on a keyboard. <kbd>1</kbd> or <kbd>1 QZ</kbd> on a phone or remote\n    /// control\n    Numpad1,\n    /// <kbd>2 ↓</kbd> on a keyboard. <kbd>2 ABC</kbd> on a phone or remote control\n    Numpad2,\n    /// <kbd>3 PgDn</kbd> on a keyboard. <kbd>3 DEF</kbd> on a phone or remote control\n    Numpad3,\n    /// <kbd>4 ←</kbd> on a keyboard. <kbd>4 GHI</kbd> on a phone or remote control\n    Numpad4,\n    /// <kbd>5</kbd> on a keyboard. <kbd>5 JKL</kbd> on a phone or remote control\n    Numpad5,\n    /// <kbd>6 →</kbd> on a keyboard. <kbd>6 MNO</kbd> on a phone or remote control\n    Numpad6,\n    /// <kbd>7 Home</kbd> on a keyboard. <kbd>7 PQRS</kbd> or <kbd>7 PRS</kbd> on a phone\n    /// or remote control\n    Numpad7,\n    /// <kbd>8 ↑</kbd> on a keyboard. <kbd>8 TUV</kbd> on a phone or remote control\n    Numpad8,\n    /// <kbd>9 PgUp</kbd> on a keyboard. <kbd>9 WXYZ</kbd> or <kbd>9 WXY</kbd> on a phone\n    /// or remote control\n    Numpad9,\n    /// <kbd>+</kbd>\n    NumpadAdd,\n    /// Found on the Microsoft Natural Keyboard.\n    NumpadBackspace,\n    /// <kbd>C</kbd> or <kbd>A</kbd> (All Clear). Also for use with numpads that have a\n    /// <kbd>Clear</kbd> key that is separate from the <kbd>NumLock</kbd> key. On the Mac, the\n    /// numpad <kbd>Clear</kbd> key is encoded as [`NumLock`].\n    ///\n    /// [`NumLock`]: Self::NumLock\n    NumpadClear,\n    /// <kbd>C</kbd> (Clear Entry)\n    NumpadClearEntry,\n    /// <kbd>,</kbd> (thousands separator). For locales where the thousands separator\n    /// is a \".\" (e.g., Brazil), this key may generate a <kbd>.</kbd>.\n    NumpadComma,\n    /// <kbd>. Del</kbd>. For locales where the decimal separator is \",\" (e.g.,\n    /// Brazil), this key may generate a <kbd>,</kbd>.\n    NumpadDecimal,\n    /// <kbd>/</kbd>\n    NumpadDivide,\n    NumpadEnter,\n    /// <kbd>=</kbd>\n    NumpadEqual,\n    /// <kbd>#</kbd> on a phone or remote control device. This key is typically found\n    /// below the <kbd>9</kbd> key and to the right of the <kbd>0</kbd> key.\n    NumpadHash,\n    /// <kbd>M</kbd> Add current entry to the value stored in memory.\n    NumpadMemoryAdd,\n    /// <kbd>M</kbd> Clear the value stored in memory.\n    NumpadMemoryClear,\n    /// <kbd>M</kbd> Replace the current entry with the value stored in memory.\n    NumpadMemoryRecall,\n    /// <kbd>M</kbd> Replace the value stored in memory with the current entry.\n    NumpadMemoryStore,\n    /// <kbd>M</kbd> Subtract current entry from the value stored in memory.\n    NumpadMemorySubtract,\n    /// <kbd>*</kbd> on a keyboard. For use with numpads that provide mathematical\n    /// operations (<kbd>+</kbd>, <kbd>-</kbd> <kbd>*</kbd> and <kbd>/</kbd>).\n    ///\n    /// Use `NumpadStar` for the <kbd>*</kbd> key on phones and remote controls.\n    NumpadMultiply,\n    /// <kbd>(</kbd> Found on the Microsoft Natural Keyboard.\n    NumpadParenLeft,\n    /// <kbd>)</kbd> Found on the Microsoft Natural Keyboard.\n    NumpadParenRight,\n    /// <kbd>*</kbd> on a phone or remote control device.\n    ///\n    /// This key is typically found below the <kbd>7</kbd> key and to the left of\n    /// the <kbd>0</kbd> key.\n    ///\n    /// Use <kbd>\"NumpadMultiply\"</kbd> for the <kbd>*</kbd> key on\n    /// numeric keypads.\n    NumpadStar,\n    /// <kbd>-</kbd>\n    NumpadSubtract,\n    /// <kbd>Esc</kbd> or <kbd>⎋</kbd>\n    Escape,\n    /// <kbd>Fn</kbd> This is typically a hardware key that does not generate a separate code.\n    Fn,\n    /// <kbd>FLock</kbd> or <kbd>FnLock</kbd>. Function Lock key. Found on the Microsoft\n    /// Natural Keyboard.\n    FnLock,\n    /// <kbd>PrtScr SysRq</kbd> or <kbd>Print Screen</kbd>\n    PrintScreen,\n    /// <kbd>Scroll Lock</kbd>\n    ScrollLock,\n    /// <kbd>Pause Break</kbd>\n    Pause,\n    /// Some laptops place this key to the left of the <kbd>↑</kbd> key.\n    ///\n    /// This also the \"back\" button (triangle) on Android.\n    BrowserBack,\n    BrowserFavorites,\n    /// Some laptops place this key to the right of the <kbd>↑</kbd> key.\n    BrowserForward,\n    /// The \"home\" button on Android.\n    BrowserHome,\n    BrowserRefresh,\n    BrowserSearch,\n    BrowserStop,\n    /// <kbd>Eject</kbd> or <kbd>⏏</kbd>. This key is placed in the function section on some Apple\n    /// keyboards.\n    Eject,\n    /// Sometimes labelled <kbd>My Computer</kbd> on the keyboard\n    LaunchApp1,\n    /// Sometimes labelled <kbd>Calculator</kbd> on the keyboard\n    LaunchApp2,\n    LaunchMail,\n    MediaPlayPause,\n    MediaSelect,\n    MediaStop,\n    MediaTrackNext,\n    MediaTrackPrevious,\n    /// This key is placed in the function section on some Apple keyboards, replacing the\n    /// <kbd>Eject</kbd> key.\n    Power,\n    Sleep,\n    AudioVolumeDown,\n    AudioVolumeMute,\n    AudioVolumeUp,\n    WakeUp,\n    // Legacy modifier key. Also called \"Super\" in certain places.\n    Meta,\n    // Legacy modifier key.\n    Hyper,\n    Turbo,\n    Abort,\n    Resume,\n    Suspend,\n    /// Found on Sun’s USB keyboard.\n    Again,\n    /// Found on Sun’s USB keyboard.\n    Copy,\n    /// Found on Sun’s USB keyboard.\n    Cut,\n    /// Found on Sun’s USB keyboard.\n    Find,\n    /// Found on Sun’s USB keyboard.\n    Open,\n    /// Found on Sun’s USB keyboard.\n    Paste,\n    /// Found on Sun’s USB keyboard.\n    Props,\n    /// Found on Sun’s USB keyboard.\n    Select,\n    /// Found on Sun’s USB keyboard.\n    Undo,\n    /// Use for dedicated <kbd>ひらがな</kbd> key found on some Japanese word processing keyboards.\n    Hiragana,\n    /// Use for dedicated <kbd>カタカナ</kbd> key found on some Japanese word processing keyboards.\n    Katakana,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F1,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F2,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F3,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F4,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F5,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F6,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F7,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F8,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F9,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F10,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F11,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F12,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F13,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F14,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F15,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F16,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F17,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F18,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F19,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F20,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F21,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F22,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F23,\n    /// General-purpose function key.\n    /// Usually found at the top of the keyboard.\n    F24,\n    /// General-purpose function key.\n    F25,\n    /// General-purpose function key.\n    F26,\n    /// General-purpose function key.\n    F27,\n    /// General-purpose function key.\n    F28,\n    /// General-purpose function key.\n    F29,\n    /// General-purpose function key.\n    F30,\n    /// General-purpose function key.\n    F31,\n    /// General-purpose function key.\n    F32,\n    /// General-purpose function key.\n    F33,\n    /// General-purpose function key.\n    F34,\n    /// General-purpose function key.\n    F35,\n}\n\n/// Contains the platform-native physical key identifier.\n///\n/// The exact values vary from platform to platform (which is part of why this is a per-platform\n/// enum), but the values are primarily tied to the key's physical location on the keyboard.\n///\n/// This enum is primarily used to store raw keycodes when Winit doesn't map a given native\n/// physical key identifier to a meaningful [`Code`] variant. In the presence of identifiers we\n/// haven't mapped for you yet, this lets you use use [`Code`] to:\n///\n/// - Correctly match key press and release events.\n/// - On non-web platforms, support assigning keybinds to virtually any key through a UI.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub enum NativeCode {\n    /// An unidentified code.\n    Unidentified,\n    /// An Android \"scancode\".\n    Android(u32),\n    /// A macOS \"scancode\".\n    MacOS(u16),\n    /// A Windows \"scancode\".\n    Windows(u16),\n    /// An XKB \"keycode\".\n    Xkb(u32),\n}\n\n/// Represents the location of a physical key.\n///\n/// This type is a superset of [`Code`], including an [`Unidentified`][Self::Unidentified]\n/// variant.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub enum Physical {\n    /// A known key code\n    Code(Code),\n    /// This variant is used when the key cannot be translated to a [`Code`]\n    ///\n    /// The native keycode is provided (if available) so you're able to more reliably match\n    /// key-press and key-release events by hashing the [`Physical`] key. It is also possible to use\n    /// this for keybinds for non-standard keys, but such keybinds are tied to a given platform.\n    Unidentified(NativeCode),\n}\n\nimpl PartialEq<Code> for Physical {\n    #[inline]\n    fn eq(&self, rhs: &Code) -> bool {\n        match self {\n            Physical::Code(code) => code == rhs,\n            Physical::Unidentified(_) => false,\n        }\n    }\n}\n\nimpl PartialEq<Physical> for Code {\n    #[inline]\n    fn eq(&self, rhs: &Physical) -> bool {\n        rhs == self\n    }\n}\n\nimpl PartialEq<NativeCode> for Physical {\n    #[inline]\n    fn eq(&self, rhs: &NativeCode) -> bool {\n        match self {\n            Physical::Unidentified(code) => code == rhs,\n            Physical::Code(_) => false,\n        }\n    }\n}\n\nimpl PartialEq<Physical> for NativeCode {\n    #[inline]\n    fn eq(&self, rhs: &Physical) -> bool {\n        rhs == self\n    }\n}\n"
  },
  {
    "path": "core/src/keyboard/location.rs",
    "content": "/// The location of a key on the keyboard.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Location {\n    /// The standard group of keys on the keyboard.\n    Standard,\n    /// The left side of the keyboard.\n    Left,\n    /// The right side of the keyboard.\n    Right,\n    /// The numpad of the keyboard.\n    Numpad,\n}\n"
  },
  {
    "path": "core/src/keyboard/modifiers.rs",
    "content": "use bitflags::bitflags;\n\nbitflags! {\n    /// The current state of the keyboard modifiers.\n    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    pub struct Modifiers: u32{\n        /// The \"shift\" key.\n        const SHIFT = 0b100;\n        // const LSHIFT = 0b010 << 0;\n        // const RSHIFT = 0b001 << 0;\n        //\n        /// The \"control\" key.\n        const CTRL = 0b100 << 3;\n        // const LCTRL = 0b010 << 3;\n        // const RCTRL = 0b001 << 3;\n        //\n        /// The \"alt\" key.\n        const ALT = 0b100 << 6;\n        // const LALT = 0b010 << 6;\n        // const RALT = 0b001 << 6;\n        //\n        /// The \"windows\" key on Windows, \"command\" key on Mac, and\n        /// \"super\" key on Linux.\n        const LOGO = 0b100 << 9;\n        // const LLOGO = 0b010 << 9;\n        // const RLOGO = 0b001 << 9;\n        /// No modifiers\n        const NONE = 0;\n    }\n}\n\nimpl Modifiers {\n    /// The \"command\" key.\n    ///\n    /// This is normally the main modifier to be used for hotkeys.\n    ///\n    /// On macOS, this is equivalent to `Self::LOGO`.\n    /// Otherwise, this is equivalent to `Self::CTRL`.\n    pub const COMMAND: Self = if cfg!(target_os = \"macos\") {\n        Self::LOGO\n    } else {\n        Self::CTRL\n    };\n\n    /// Returns true if the [`SHIFT`] key is pressed in the [`Modifiers`].\n    ///\n    /// [`SHIFT`]: Self::SHIFT\n    pub fn shift(self) -> bool {\n        self.contains(Self::SHIFT)\n    }\n\n    /// Returns true if the [`CTRL`] key is pressed in the [`Modifiers`].\n    ///\n    /// [`CTRL`]: Self::CTRL\n    pub fn control(self) -> bool {\n        self.contains(Self::CTRL)\n    }\n\n    /// Returns true if the [`ALT`] key is pressed in the [`Modifiers`].\n    ///\n    /// [`ALT`]: Self::ALT\n    pub fn alt(self) -> bool {\n        self.contains(Self::ALT)\n    }\n\n    /// Returns true if the [`LOGO`] key is pressed in the [`Modifiers`].\n    ///\n    /// [`LOGO`]: Self::LOGO\n    pub fn logo(self) -> bool {\n        self.contains(Self::LOGO)\n    }\n\n    /// Returns true if a \"command key\" is pressed in the [`Modifiers`].\n    ///\n    /// The \"command key\" is the main modifier key used to issue commands in the\n    /// current platform. Specifically:\n    ///\n    /// - It is the `logo` or command key (⌘) on macOS\n    /// - It is the `control` key on other platforms\n    pub fn command(self) -> bool {\n        #[cfg(target_os = \"macos\")]\n        let is_pressed = self.logo();\n\n        #[cfg(not(target_os = \"macos\"))]\n        let is_pressed = self.control();\n\n        is_pressed\n    }\n\n    /// Returns true if the \"jump key\" is pressed in the [`Modifiers`].\n    ///\n    /// The \"jump key\" is the modifier key used to widen text motions. It is the `Alt`\n    /// key in macOS and the `Ctrl` key in other platforms.\n    pub fn jump(self) -> bool {\n        if cfg!(target_os = \"macos\") {\n            self.alt()\n        } else {\n            self.control()\n        }\n    }\n\n    /// Returns true if the \"command key\" is pressed on a macOS device.\n    ///\n    /// This is relevant for macOS-specific actions (e.g. `⌘ + ArrowLeft` moves the cursor\n    /// to the beginning of the line).\n    pub fn macos_command(self) -> bool {\n        if cfg!(target_os = \"macos\") {\n            self.logo()\n        } else {\n            false\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/keyboard.rs",
    "content": "//! Listen to keyboard events.\npub mod key;\n\nmod event;\nmod location;\nmod modifiers;\n\npub use event::Event;\npub use key::Key;\npub use location::Location;\npub use modifiers::Modifiers;\n"
  },
  {
    "path": "core/src/layout/DRUID_LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "core/src/layout/flex.rs",
    "content": "//! Distribute elements using a flex-based layout.\n// This code is heavily inspired by the [`druid`] codebase.\n//\n// [`druid`]: https://github.com/xi-editor/druid\n//\n// Copyright 2018 The xi-editor Authors, Héctor Ramón\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nuse crate::Element;\n\nuse crate::layout::{Limits, Node};\nuse crate::widget;\nuse crate::{Alignment, Length, Padding, Point, Size};\n\n/// The main axis of a flex layout.\n#[derive(Debug)]\npub enum Axis {\n    /// The horizontal axis\n    Horizontal,\n\n    /// The vertical axis\n    Vertical,\n}\n\nimpl Axis {\n    fn main(&self, size: Size) -> f32 {\n        match self {\n            Axis::Horizontal => size.width,\n            Axis::Vertical => size.height,\n        }\n    }\n\n    fn cross(&self, size: Size) -> f32 {\n        match self {\n            Axis::Horizontal => size.height,\n            Axis::Vertical => size.width,\n        }\n    }\n\n    fn pack<T>(&self, main: T, cross: T) -> (T, T) {\n        match self {\n            Axis::Horizontal => (main, cross),\n            Axis::Vertical => (cross, main),\n        }\n    }\n}\n\n/// Computes the flex layout with the given axis and limits, applying spacing,\n/// padding and alignment to the items as needed.\n///\n/// It returns a new layout [`Node`].\npub fn resolve<Message, Theme, Renderer>(\n    axis: Axis,\n    renderer: &Renderer,\n    limits: &Limits,\n    width: Length,\n    height: Length,\n    padding: Padding,\n    spacing: f32,\n    align_items: Alignment,\n    items: &mut [Element<'_, Message, Theme, Renderer>],\n    trees: &mut [widget::Tree],\n) -> Node\nwhere\n    Renderer: crate::Renderer,\n{\n    let limits = limits.width(width).height(height).shrink(padding);\n    let total_spacing = spacing * items.len().saturating_sub(1) as f32;\n    let max_cross = axis.cross(limits.max());\n\n    let (main_compress, cross_compress) = {\n        let compression = limits.compression();\n        axis.pack(compression.width, compression.height)\n    };\n\n    let compression = {\n        let (compress_x, compress_y) = axis.pack(main_compress, false);\n        Size::new(compress_x, compress_y)\n    };\n\n    let mut fill_main_sum = 0;\n    let mut some_fill_cross = false;\n    let mut cross = if cross_compress { 0.0 } else { max_cross };\n    let mut available = axis.main(limits.max()) - total_spacing;\n\n    let mut nodes: Vec<Node> = Vec::with_capacity(items.len());\n    nodes.resize(items.len(), Node::default());\n\n    // FIRST PASS\n    // We lay out non-fluid elements in the main axis.\n    // If we need to compress the cross axis, then we skip any of these elements\n    // that are also fluid in the cross axis.\n    for (i, (child, tree)) in items.iter_mut().zip(trees.iter_mut()).enumerate() {\n        let (fill_main_factor, fill_cross_factor) = {\n            let size = child.as_widget().size();\n\n            axis.pack(size.width.fill_factor(), size.height.fill_factor())\n        };\n\n        if (main_compress || fill_main_factor == 0) && (!cross_compress || fill_cross_factor == 0) {\n            let (max_width, max_height) = axis.pack(\n                available,\n                if fill_cross_factor == 0 {\n                    max_cross\n                } else {\n                    cross\n                },\n            );\n\n            let child_limits =\n                Limits::with_compression(Size::ZERO, Size::new(max_width, max_height), compression);\n\n            let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);\n            let size = layout.size();\n\n            available -= axis.main(size);\n            cross = cross.max(axis.cross(size));\n\n            nodes[i] = layout;\n        } else {\n            fill_main_sum += fill_main_factor;\n            some_fill_cross = some_fill_cross || fill_cross_factor != 0;\n        }\n    }\n\n    // SECOND PASS (conditional)\n    // If we must compress the cross axis and there are fluid elements in the\n    // cross axis, we lay out any of these elements that are also non-fluid in\n    // the main axis (i.e. the ones we deliberately skipped in the first pass).\n    //\n    // We use the maximum cross length obtained in the first pass as the maximum\n    // cross limit.\n    //\n    // We can defer the layout of any elements that have a fixed size in the main axis,\n    // allowing them to use the cross calculations of the next pass.\n    if cross_compress && some_fill_cross {\n        for (i, (child, tree)) in items.iter_mut().zip(trees.iter_mut()).enumerate() {\n            let (main_size, cross_size) = {\n                let size = child.as_widget().size();\n\n                axis.pack(size.width, size.height)\n            };\n\n            if (main_compress || main_size.fill_factor() == 0) && cross_size.fill_factor() != 0 {\n                if let Length::Fixed(main) = main_size {\n                    available -= main;\n                    continue;\n                }\n\n                let (max_width, max_height) = axis.pack(available, cross);\n\n                let child_limits = Limits::with_compression(\n                    Size::ZERO,\n                    Size::new(max_width, max_height),\n                    compression,\n                );\n\n                let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);\n                let size = layout.size();\n\n                available -= axis.main(size);\n                cross = cross.max(axis.cross(size));\n\n                nodes[i] = layout;\n            }\n        }\n    }\n\n    let remaining = available.max(0.0);\n\n    // THIRD PASS (conditional)\n    // We lay out the elements that are fluid in the main axis.\n    // We use the remaining space to evenly allocate space based on fill factors.\n    if !main_compress {\n        for (i, (child, tree)) in items.iter_mut().zip(trees.iter_mut()).enumerate() {\n            let (fill_main_factor, fill_cross_factor) = {\n                let size = child.as_widget().size();\n\n                axis.pack(size.width.fill_factor(), size.height.fill_factor())\n            };\n\n            if fill_main_factor != 0 {\n                let max_main = remaining * fill_main_factor as f32 / fill_main_sum as f32;\n\n                let max_main = if max_main.is_nan() {\n                    f32::INFINITY\n                } else {\n                    max_main\n                };\n\n                let min_main = if max_main.is_infinite() {\n                    0.0\n                } else {\n                    max_main\n                };\n\n                let (min_width, min_height) = axis.pack(min_main, 0.0);\n                let (max_width, max_height) = axis.pack(\n                    max_main,\n                    if fill_cross_factor == 0 {\n                        max_cross\n                    } else {\n                        cross\n                    },\n                );\n\n                let child_limits = Limits::with_compression(\n                    Size::new(min_width, min_height),\n                    Size::new(max_width, max_height),\n                    compression,\n                );\n\n                let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);\n                cross = cross.max(axis.cross(layout.size()));\n\n                nodes[i] = layout;\n            }\n        }\n    }\n\n    // FOURTH PASS (conditional)\n    // We lay out any elements that were deferred in the second pass.\n    // These are elements that must be compressed in their cross axis and have\n    // a fixed length in the main axis.\n    if cross_compress && some_fill_cross {\n        for (i, (child, tree)) in items.iter_mut().zip(trees).enumerate() {\n            let (main_size, cross_size) = {\n                let size = child.as_widget().size();\n\n                axis.pack(size.width, size.height)\n            };\n\n            if cross_size.fill_factor() != 0 {\n                let Length::Fixed(main) = main_size else {\n                    continue;\n                };\n\n                let (max_width, max_height) = axis.pack(main, cross);\n\n                let child_limits = Limits::new(Size::ZERO, Size::new(max_width, max_height));\n\n                let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);\n                let size = layout.size();\n\n                cross = cross.max(axis.cross(size));\n\n                nodes[i] = layout;\n            }\n        }\n    }\n\n    let pad = axis.pack(padding.left, padding.top);\n    let mut main = pad.0;\n\n    // FIFTH PASS\n    // We align all the laid out nodes in the cross axis, if needed.\n    for (i, node) in nodes.iter_mut().enumerate() {\n        if i > 0 {\n            main += spacing;\n        }\n\n        let (x, y) = axis.pack(main, pad.1);\n\n        node.move_to_mut(Point::new(x, y));\n\n        match axis {\n            Axis::Horizontal => {\n                node.align_mut(Alignment::Start, align_items, Size::new(0.0, cross));\n            }\n            Axis::Vertical => {\n                node.align_mut(align_items, Alignment::Start, Size::new(cross, 0.0));\n            }\n        }\n\n        let size = node.size();\n\n        main += axis.main(size);\n    }\n\n    let (intrinsic_width, intrinsic_height) = axis.pack(main - pad.0, cross);\n    let size = limits.resolve(width, height, Size::new(intrinsic_width, intrinsic_height));\n\n    Node::with_children(size.expand(padding), nodes)\n}\n"
  },
  {
    "path": "core/src/layout/limits.rs",
    "content": "#![allow(clippy::manual_clamp)]\nuse crate::{Length, Size};\n\n/// A set of size constraints for layouting.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Limits {\n    min: Size,\n    max: Size,\n    compression: Size<bool>,\n}\n\nimpl Limits {\n    /// No limits\n    pub const NONE: Limits = Limits {\n        min: Size::ZERO,\n        max: Size::INFINITE,\n        compression: Size::new(false, false),\n    };\n\n    /// Creates new [`Limits`] with the given minimum and maximum [`Size`].\n    pub const fn new(min: Size, max: Size) -> Limits {\n        Limits::with_compression(min, max, Size::new(false, false))\n    }\n\n    /// Creates new [`Limits`] with the given minimun and maximum [`Size`], and\n    /// whether fluid lengths should be compressed to intrinsic dimensions.\n    pub const fn with_compression(min: Size, max: Size, compress: Size<bool>) -> Self {\n        Limits {\n            min,\n            max,\n            compression: compress,\n        }\n    }\n\n    /// Returns the minimum [`Size`] of the [`Limits`].\n    pub fn min(&self) -> Size {\n        self.min\n    }\n\n    /// Returns the maximum [`Size`] of the [`Limits`].\n    pub fn max(&self) -> Size {\n        self.max\n    }\n\n    /// Returns the compression of the [`Limits`].\n    pub fn compression(&self) -> Size<bool> {\n        self.compression\n    }\n\n    /// Applies a width constraint to the current [`Limits`].\n    pub fn width(mut self, width: impl Into<Length>) -> Limits {\n        match width.into() {\n            Length::Shrink => {\n                self.compression.width = true;\n            }\n            Length::Fixed(amount) => {\n                let new_width = amount.min(self.max.width).max(self.min.width);\n\n                self.min.width = new_width;\n                self.max.width = new_width;\n                self.compression.width = false;\n            }\n            Length::Fill | Length::FillPortion(_) => {}\n        }\n\n        self\n    }\n\n    /// Applies a height constraint to the current [`Limits`].\n    pub fn height(mut self, height: impl Into<Length>) -> Limits {\n        match height.into() {\n            Length::Shrink => {\n                self.compression.height = true;\n            }\n            Length::Fixed(amount) => {\n                let new_height = amount.min(self.max.height).max(self.min.height);\n\n                self.min.height = new_height;\n                self.max.height = new_height;\n                self.compression.height = false;\n            }\n            Length::Fill | Length::FillPortion(_) => {}\n        }\n\n        self\n    }\n\n    /// Applies a minimum width constraint to the current [`Limits`].\n    pub fn min_width(mut self, min_width: f32) -> Limits {\n        self.min.width = self.min.width.max(min_width).min(self.max.width);\n\n        self\n    }\n\n    /// Applies a maximum width constraint to the current [`Limits`].\n    pub fn max_width(mut self, max_width: f32) -> Limits {\n        self.max.width = self.max.width.min(max_width).max(self.min.width);\n\n        self\n    }\n\n    /// Applies a minimum height constraint to the current [`Limits`].\n    pub fn min_height(mut self, min_height: f32) -> Limits {\n        self.min.height = self.min.height.max(min_height).min(self.max.height);\n\n        self\n    }\n\n    /// Applies a maximum height constraint to the current [`Limits`].\n    pub fn max_height(mut self, max_height: f32) -> Limits {\n        self.max.height = self.max.height.min(max_height).max(self.min.height);\n\n        self\n    }\n\n    /// Shrinks the current [`Limits`] by the given [`Size`].\n    pub fn shrink(&self, size: impl Into<Size>) -> Limits {\n        let size = size.into();\n\n        let min = Size::new(\n            (self.min().width - size.width).max(0.0),\n            (self.min().height - size.height).max(0.0),\n        );\n\n        let max = Size::new(\n            (self.max().width - size.width).max(0.0),\n            (self.max().height - size.height).max(0.0),\n        );\n\n        Limits {\n            min,\n            max,\n            compression: self.compression,\n        }\n    }\n\n    /// Removes the minimum [`Size`] constraint for the current [`Limits`].\n    pub fn loose(&self) -> Limits {\n        Limits {\n            min: Size::ZERO,\n            max: self.max,\n            compression: self.compression,\n        }\n    }\n\n    /// Computes the resulting [`Size`] that fits the [`Limits`] given\n    /// some width and height requirements and the intrinsic size of\n    /// some content.\n    pub fn resolve(\n        &self,\n        width: impl Into<Length>,\n        height: impl Into<Length>,\n        intrinsic_size: Size,\n    ) -> Size {\n        let width = match width.into() {\n            Length::Fill | Length::FillPortion(_) if !self.compression.width => self.max.width,\n            Length::Fixed(amount) => amount.min(self.max.width).max(self.min.width),\n            _ => intrinsic_size.width.min(self.max.width).max(self.min.width),\n        };\n\n        let height = match height.into() {\n            Length::Fill | Length::FillPortion(_) if !self.compression.height => self.max.height,\n            Length::Fixed(amount) => amount.min(self.max.height).max(self.min.height),\n            _ => intrinsic_size\n                .height\n                .min(self.max.height)\n                .max(self.min.height),\n        };\n\n        Size::new(width, height)\n    }\n}\n"
  },
  {
    "path": "core/src/layout/node.rs",
    "content": "use crate::{Alignment, Padding, Point, Rectangle, Size, Vector};\n\n/// The bounds of an element and its children.\n#[derive(Debug, Clone, Default)]\npub struct Node {\n    bounds: Rectangle,\n    children: Vec<Node>,\n}\n\nimpl Node {\n    /// Creates a new [`Node`] with the given [`Size`].\n    pub const fn new(size: Size) -> Self {\n        Self::with_children(size, Vec::new())\n    }\n\n    /// Creates a new [`Node`] with the given [`Size`] and children.\n    pub const fn with_children(size: Size, children: Vec<Node>) -> Self {\n        Node {\n            bounds: Rectangle {\n                x: 0.0,\n                y: 0.0,\n                width: size.width,\n                height: size.height,\n            },\n            children,\n        }\n    }\n\n    /// Creates a new [`Node`] that wraps a single child with some [`Padding`].\n    pub fn container(child: Self, padding: Padding) -> Self {\n        Self::with_children(\n            child.bounds.size().expand(padding),\n            vec![child.move_to(Point::new(padding.left, padding.top))],\n        )\n    }\n\n    /// Returns the [`Size`] of the [`Node`].\n    pub fn size(&self) -> Size {\n        Size::new(self.bounds.width, self.bounds.height)\n    }\n\n    /// Returns the bounds of the [`Node`].\n    pub fn bounds(&self) -> Rectangle {\n        self.bounds\n    }\n\n    /// Returns the children of the [`Node`].\n    pub fn children(&self) -> &[Node] {\n        &self.children\n    }\n\n    /// Aligns the [`Node`] in the given space.\n    pub fn align(mut self, align_x: Alignment, align_y: Alignment, space: Size) -> Self {\n        self.align_mut(align_x, align_y, space);\n        self\n    }\n\n    /// Mutable reference version of [`Self::align`].\n    pub fn align_mut(&mut self, align_x: Alignment, align_y: Alignment, space: Size) {\n        match align_x {\n            Alignment::Start => {}\n            Alignment::Center => {\n                self.bounds.x += (space.width - self.bounds.width) / 2.0;\n            }\n            Alignment::End => {\n                self.bounds.x += space.width - self.bounds.width;\n            }\n        }\n\n        match align_y {\n            Alignment::Start => {}\n            Alignment::Center => {\n                self.bounds.y += (space.height - self.bounds.height) / 2.0;\n            }\n            Alignment::End => {\n                self.bounds.y += space.height - self.bounds.height;\n            }\n        }\n    }\n\n    /// Moves the [`Node`] to the given position.\n    pub fn move_to(mut self, position: impl Into<Point>) -> Self {\n        self.move_to_mut(position);\n        self\n    }\n\n    /// Mutable reference version of [`Self::move_to`].\n    pub fn move_to_mut(&mut self, position: impl Into<Point>) {\n        let position = position.into();\n\n        self.bounds.x = position.x;\n        self.bounds.y = position.y;\n    }\n\n    /// Translates the [`Node`] by the given translation.\n    pub fn translate(mut self, translation: impl Into<Vector>) -> Self {\n        self.translate_mut(translation);\n        self\n    }\n\n    /// Translates the [`Node`] by the given translation.\n    pub fn translate_mut(&mut self, translation: impl Into<Vector>) {\n        self.bounds = self.bounds + translation.into();\n    }\n}\n"
  },
  {
    "path": "core/src/layout.rs",
    "content": "//! Position your widgets properly.\nmod limits;\nmod node;\n\npub mod flex;\n\npub use limits::Limits;\npub use node::Node;\n\nuse crate::{Length, Padding, Point, Rectangle, Size, Vector};\n\n/// The bounds of a [`Node`] and its children, using absolute coordinates.\n#[derive(Debug, Clone, Copy)]\npub struct Layout<'a> {\n    position: Point,\n    node: &'a Node,\n}\n\nimpl<'a> Layout<'a> {\n    /// Creates a new [`Layout`] for the given [`Node`] at the origin.\n    pub fn new(node: &'a Node) -> Self {\n        Self::with_offset(Vector::new(0.0, 0.0), node)\n    }\n\n    /// Creates a new [`Layout`] for the given [`Node`] with the provided offset\n    /// from the origin.\n    pub fn with_offset(offset: Vector, node: &'a Node) -> Self {\n        let bounds = node.bounds();\n\n        Self {\n            position: Point::new(bounds.x, bounds.y) + offset,\n            node,\n        }\n    }\n\n    /// Returns the position of the [`Layout`].\n    pub fn position(&self) -> Point {\n        self.position\n    }\n\n    /// Returns the bounds of the [`Layout`].\n    ///\n    /// The returned [`Rectangle`] describes the position and size of a\n    /// [`Node`].\n    pub fn bounds(&self) -> Rectangle {\n        let bounds = self.node.bounds();\n\n        Rectangle {\n            x: self.position.x,\n            y: self.position.y,\n            width: bounds.width,\n            height: bounds.height,\n        }\n    }\n\n    /// Returns an iterator over the children of this [`Layout`].\n    pub fn children(self) -> impl DoubleEndedIterator<Item = Layout<'a>> + ExactSizeIterator {\n        self.node.children().iter().map(move |node| {\n            Layout::with_offset(Vector::new(self.position.x, self.position.y), node)\n        })\n    }\n\n    /// Returns the [`Layout`] of the child at the given index.\n    ///\n    /// This can be useful if you ever need to access children out of order\n    /// for layering purposes.\n    ///\n    /// # Panics\n    /// Panics if index is out of bounds.\n    pub fn child(self, index: usize) -> Layout<'a> {\n        let node = &self.node.children()[index];\n\n        Layout::with_offset(Vector::new(self.position.x, self.position.y), node)\n    }\n}\n\n/// Produces a [`Node`] with two children nodes one right next to each other.\npub fn next_to_each_other(\n    limits: &Limits,\n    spacing: f32,\n    left: impl FnOnce(&Limits) -> Node,\n    right: impl FnOnce(&Limits) -> Node,\n) -> Node {\n    let left_node = left(limits);\n    let left_size = left_node.size();\n\n    let right_limits = limits.shrink(Size::new(left_size.width + spacing, 0.0));\n\n    let right_node = right(&right_limits);\n    let right_size = right_node.size();\n\n    let (left_y, right_y) = if left_size.height > right_size.height {\n        (0.0, (left_size.height - right_size.height) / 2.0)\n    } else {\n        ((right_size.height - left_size.height) / 2.0, 0.0)\n    };\n\n    Node::with_children(\n        Size::new(\n            left_size.width + spacing + right_size.width,\n            left_size.height.max(right_size.height),\n        ),\n        vec![\n            left_node.move_to(Point::new(0.0, left_y)),\n            right_node.move_to(Point::new(left_size.width + spacing, right_y)),\n        ],\n    )\n}\n\n/// Computes the resulting [`Node`] that fits the [`Limits`] given\n/// some width and height requirements and no intrinsic size.\npub fn atomic(limits: &Limits, width: impl Into<Length>, height: impl Into<Length>) -> Node {\n    let width = width.into();\n    let height = height.into();\n\n    Node::new(limits.resolve(width, height, Size::ZERO))\n}\n\n/// Computes the resulting [`Node`] that fits the [`Limits`] given\n/// some width and height requirements and a closure that produces\n/// the intrinsic [`Size`] inside the given [`Limits`].\npub fn sized(\n    limits: &Limits,\n    width: impl Into<Length>,\n    height: impl Into<Length>,\n    f: impl FnOnce(&Limits) -> Size,\n) -> Node {\n    let width = width.into();\n    let height = height.into();\n\n    let limits = limits.width(width).height(height);\n    let intrinsic_size = f(&limits);\n\n    Node::new(limits.resolve(width, height, intrinsic_size))\n}\n\n/// Computes the resulting [`Node`] that fits the [`Limits`] given\n/// some width and height requirements and a closure that produces\n/// the content [`Node`] inside the given [`Limits`].\npub fn contained(\n    limits: &Limits,\n    width: impl Into<Length>,\n    height: impl Into<Length>,\n    f: impl FnOnce(&Limits) -> Node,\n) -> Node {\n    let width = width.into();\n    let height = height.into();\n\n    let limits = limits.width(width).height(height);\n    let content = f(&limits);\n\n    Node::with_children(limits.resolve(width, height, content.size()), vec![content])\n}\n\n/// Computes the [`Node`] that fits the [`Limits`] given some width, height, and\n/// [`Padding`] requirements and a closure that produces the content [`Node`]\n/// inside the given [`Limits`].\npub fn padded(\n    limits: &Limits,\n    width: impl Into<Length>,\n    height: impl Into<Length>,\n    padding: impl Into<Padding>,\n    layout: impl FnOnce(&Limits) -> Node,\n) -> Node {\n    positioned(limits, width, height, padding, layout, |content, _| content)\n}\n\n/// Computes a [`padded`] [`Node`] with a positioning step.\npub fn positioned(\n    limits: &Limits,\n    width: impl Into<Length>,\n    height: impl Into<Length>,\n    padding: impl Into<Padding>,\n    layout: impl FnOnce(&Limits) -> Node,\n    position: impl FnOnce(Node, Size) -> Node,\n) -> Node {\n    let width = width.into();\n    let height = height.into();\n    let padding = padding.into();\n\n    let limits = limits.width(width).height(height);\n    let content = layout(&limits.shrink(padding));\n    let padding = padding.fit(content.size(), limits.max());\n\n    let size = limits\n        .shrink(padding)\n        .resolve(width, height, content.size());\n\n    Node::with_children(\n        size.expand(padding),\n        vec![position(content.move_to((padding.left, padding.top)), size)],\n    )\n}\n"
  },
  {
    "path": "core/src/length.rs",
    "content": "use crate::Pixels;\n\n/// The strategy used to fill space in a specific dimension.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Length {\n    /// Fill all the remaining space\n    Fill,\n\n    /// Fill a portion of the remaining space relative to other elements.\n    ///\n    /// Let's say we have two elements: one with `FillPortion(2)` and one with\n    /// `FillPortion(3)`. The first will get 2 portions of the available space,\n    /// while the second one would get 3.\n    ///\n    /// `Length::Fill` is equivalent to `Length::FillPortion(1)`.\n    FillPortion(u16),\n\n    /// Fill the least amount of space\n    Shrink,\n\n    /// Fill a fixed amount of space\n    Fixed(f32),\n}\n\nimpl Length {\n    /// Returns the _fill factor_ of the [`Length`].\n    ///\n    /// The _fill factor_ is a relative unit describing how much of the\n    /// remaining space should be filled when compared to other elements. It\n    /// is only meant to be used by layout engines.\n    pub fn fill_factor(&self) -> u16 {\n        match self {\n            Length::Fill => 1,\n            Length::FillPortion(factor) => *factor,\n            Length::Shrink => 0,\n            Length::Fixed(_) => 0,\n        }\n    }\n\n    /// Returns `true` if the [`Length`] is either [`Length::Fill`] or\n    /// [`Length::FillPortion`].\n    pub fn is_fill(&self) -> bool {\n        self.fill_factor() != 0\n    }\n\n    /// Returns the \"fluid\" variant of the [`Length`].\n    ///\n    /// Specifically:\n    /// - [`Length::Shrink`] if [`Length::Shrink`] or [`Length::Fixed`].\n    /// - [`Length::Fill`] otherwise.\n    pub fn fluid(&self) -> Self {\n        match self {\n            Length::Fill | Length::FillPortion(_) => Length::Fill,\n            Length::Shrink | Length::Fixed(_) => Length::Shrink,\n        }\n    }\n\n    /// Adapts the [`Length`] so it can contain the other [`Length`] and\n    /// match its fluidity.\n    #[inline]\n    pub fn enclose(self, other: Length) -> Self {\n        match (self, other) {\n            (Length::Shrink, Length::Fill | Length::FillPortion(_)) => other,\n            _ => self,\n        }\n    }\n}\n\nimpl From<Pixels> for Length {\n    fn from(amount: Pixels) -> Self {\n        Length::Fixed(f32::from(amount))\n    }\n}\n\nimpl From<f32> for Length {\n    fn from(amount: f32) -> Self {\n        Length::Fixed(amount)\n    }\n}\n\nimpl From<u32> for Length {\n    fn from(units: u32) -> Self {\n        Length::Fixed(units as f32)\n    }\n}\n"
  },
  {
    "path": "core/src/lib.rs",
    "content": "//! The core library of [Iced].\n//!\n//! This library holds basic types that can be reused and re-exported in\n//! different runtime implementations.\n//!\n//! ![The foundations of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/foundations.png?raw=true)\n//!\n//! [Iced]: https://github.com/iced-rs/iced\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg\"\n)]\npub mod alignment;\npub mod animation;\npub mod border;\npub mod clipboard;\npub mod event;\npub mod font;\npub mod gradient;\npub mod image;\npub mod input_method;\npub mod keyboard;\npub mod layout;\npub mod mouse;\npub mod overlay;\npub mod padding;\npub mod renderer;\npub mod svg;\npub mod text;\npub mod theme;\npub mod time;\npub mod touch;\npub mod widget;\npub mod window;\n\nmod angle;\nmod background;\nmod color;\nmod content_fit;\nmod element;\nmod length;\nmod pixels;\nmod point;\nmod rectangle;\nmod rotation;\nmod settings;\nmod shadow;\nmod shell;\nmod size;\nmod transformation;\nmod vector;\n\npub use alignment::Alignment;\npub use angle::{Degrees, Radians};\npub use animation::Animation;\npub use background::Background;\npub use border::Border;\npub use clipboard::Clipboard;\npub use color::Color;\npub use content_fit::ContentFit;\npub use element::Element;\npub use event::Event;\npub use font::Font;\npub use gradient::Gradient;\npub use image::Image;\npub use input_method::InputMethod;\npub use layout::Layout;\npub use length::Length;\npub use overlay::Overlay;\npub use padding::Padding;\npub use pixels::Pixels;\npub use point::Point;\npub use rectangle::Rectangle;\npub use renderer::Renderer;\npub use rotation::Rotation;\npub use settings::Settings;\npub use shadow::Shadow;\npub use shell::Shell;\npub use size::Size;\npub use svg::Svg;\npub use text::Text;\npub use theme::Theme;\npub use transformation::Transformation;\npub use vector::Vector;\npub use widget::Widget;\n\npub use bytes::Bytes;\npub use smol_str::SmolStr;\npub use std::convert::Infallible as Never;\n\n/// A function that can _never_ be called.\n///\n/// This is useful to turn generic types into anything\n/// you want by coercing them into a type with no possible\n/// values.\npub fn never<T>(never: Never) -> T {\n    match never {}\n}\n\n/// A trait extension for binary functions (`Fn(A, B) -> O`).\n///\n/// It enables you to use a bunch of nifty functional programming paradigms\n/// that work well with iced.\npub trait Function<A, B, O> {\n    /// Applies the given first argument to a binary function and returns\n    /// a new function that takes the other argument.\n    ///\n    /// This lets you partially \"apply\" a function—equivalent to currying,\n    /// but it only works with binary functions. If you want to apply an\n    /// arbitrary number of arguments, create a little struct for them.\n    ///\n    /// # When is this useful?\n    /// Sometimes you will want to identify the source or target\n    /// of some message in your user interface. This can be achieved through\n    /// normal means by defining a closure and moving the identifier\n    /// inside:\n    ///\n    /// ```rust\n    /// # let element: Option<()> = Some(());\n    /// # enum Message { ButtonPressed(u32, ()) }\n    /// let id = 123;\n    ///\n    /// # let _ = {\n    /// element.map(move |result| Message::ButtonPressed(id, result))\n    /// # };\n    /// ```\n    ///\n    /// That's quite a mouthful. [`with`](Self::with) lets you write:\n    ///\n    /// ```rust\n    /// # use iced_core::Function;\n    /// # let element: Option<()> = Some(());\n    /// # enum Message { ButtonPressed(u32, ()) }\n    /// let id = 123;\n    ///\n    /// # let _ = {\n    /// element.map(Message::ButtonPressed.with(id))\n    /// # };\n    /// ```\n    ///\n    /// Effectively creating the same closure that partially applies\n    /// the `id` to the message—but much more concise!\n    fn with(self, prefix: A) -> impl Fn(B) -> O;\n}\n\nimpl<F, A, B, O> Function<A, B, O> for F\nwhere\n    F: Fn(A, B) -> O,\n    Self: Sized,\n    A: Clone,\n{\n    fn with(self, prefix: A) -> impl Fn(B) -> O {\n        move |result| self(prefix.clone(), result)\n    }\n}\n"
  },
  {
    "path": "core/src/mouse/button.rs",
    "content": "/// The button of a mouse.\n#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]\npub enum Button {\n    /// The left mouse button.\n    Left,\n\n    /// The right mouse button.\n    Right,\n\n    /// The middle (wheel) button.\n    Middle,\n\n    /// The back mouse button.\n    Back,\n\n    /// The forward mouse button.\n    Forward,\n\n    /// Some other button.\n    Other(u16),\n}\n"
  },
  {
    "path": "core/src/mouse/click.rs",
    "content": "//! Track mouse clicks.\nuse crate::mouse::Button;\nuse crate::time::Instant;\nuse crate::{Point, Transformation};\n\nuse std::ops::Mul;\n\n/// A mouse click.\n#[derive(Debug, Clone, Copy)]\npub struct Click {\n    kind: Kind,\n    button: Button,\n    position: Point,\n    time: Instant,\n}\n\n/// The kind of mouse click.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Kind {\n    /// A single click\n    Single,\n\n    /// A double click\n    Double,\n\n    /// A triple click\n    Triple,\n}\n\nimpl Kind {\n    fn next(self) -> Kind {\n        match self {\n            Kind::Single => Kind::Double,\n            Kind::Double => Kind::Triple,\n            Kind::Triple => Kind::Double,\n        }\n    }\n}\n\nimpl Click {\n    /// Creates a new [`Click`] with the given position and previous last\n    /// [`Click`].\n    pub fn new(position: Point, button: Button, previous: Option<Click>) -> Click {\n        let time = Instant::now();\n\n        let kind = if let Some(previous) = previous {\n            if previous.is_consecutive(position, time) && button == previous.button {\n                previous.kind.next()\n            } else {\n                Kind::Single\n            }\n        } else {\n            Kind::Single\n        };\n\n        Click {\n            kind,\n            button,\n            position,\n            time,\n        }\n    }\n\n    /// Returns the [`Kind`] of [`Click`].\n    pub fn kind(&self) -> Kind {\n        self.kind\n    }\n\n    /// Returns the position of the [`Click`].\n    pub fn position(&self) -> Point {\n        self.position\n    }\n\n    fn is_consecutive(&self, new_position: Point, time: Instant) -> bool {\n        let duration = if time > self.time {\n            Some(time - self.time)\n        } else {\n            None\n        };\n\n        self.position.distance(new_position) < 6.0\n            && duration\n                .map(|duration| duration.as_millis() <= 300)\n                .unwrap_or(false)\n    }\n}\n\nimpl Mul<Transformation> for Click {\n    type Output = Click;\n\n    fn mul(self, transformation: Transformation) -> Click {\n        Click {\n            kind: self.kind,\n            button: self.button,\n            position: self.position * transformation,\n            time: self.time,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/mouse/cursor.rs",
    "content": "use crate::{Point, Rectangle, Transformation, Vector};\n\n/// The mouse cursor state.\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub enum Cursor {\n    /// The cursor has a defined position.\n    Available(Point),\n\n    /// The cursor has a defined position, but it's levitating over a layer above.\n    Levitating(Point),\n\n    /// The cursor is currently unavailable (i.e. out of bounds or busy).\n    #[default]\n    Unavailable,\n}\n\nimpl Cursor {\n    /// Returns the absolute position of the [`Cursor`], if available.\n    pub fn position(self) -> Option<Point> {\n        match self {\n            Cursor::Available(position) => Some(position),\n            Cursor::Levitating(_) | Cursor::Unavailable => None,\n        }\n    }\n\n    /// Returns the absolute position of the [`Cursor`], if available and inside\n    /// the given bounds.\n    ///\n    /// If the [`Cursor`] is not over the provided bounds, this method will\n    /// return `None`.\n    pub fn position_over(self, bounds: Rectangle) -> Option<Point> {\n        self.position().filter(|p| bounds.contains(*p))\n    }\n\n    /// Returns the relative position of the [`Cursor`] inside the given bounds,\n    /// if available.\n    ///\n    /// If the [`Cursor`] is not over the provided bounds, this method will\n    /// return `None`.\n    pub fn position_in(self, bounds: Rectangle) -> Option<Point> {\n        self.position_over(bounds)\n            .map(|p| p - Vector::new(bounds.x, bounds.y))\n    }\n\n    /// Returns the relative position of the [`Cursor`] from the given origin,\n    /// if available.\n    pub fn position_from(self, origin: Point) -> Option<Point> {\n        self.position().map(|p| p - Vector::new(origin.x, origin.y))\n    }\n\n    /// Returns true if the [`Cursor`] is over the given `bounds`.\n    pub fn is_over(self, bounds: Rectangle) -> bool {\n        self.position_over(bounds).is_some()\n    }\n\n    /// Returns true if the [`Cursor`] is levitating over a layer above.\n    pub fn is_levitating(self) -> bool {\n        matches!(self, Self::Levitating(_))\n    }\n\n    /// Makes the [`Cursor`] levitate over a layer above.\n    pub fn levitate(self) -> Self {\n        match self {\n            Self::Available(position) => Self::Levitating(position),\n            _ => self,\n        }\n    }\n\n    /// Brings the [`Cursor`] back to the current layer.\n    pub fn land(self) -> Self {\n        match self {\n            Cursor::Levitating(position) => Cursor::Available(position),\n            _ => self,\n        }\n    }\n}\n\nimpl std::ops::Add<Vector> for Cursor {\n    type Output = Self;\n\n    fn add(self, translation: Vector) -> Self::Output {\n        match self {\n            Cursor::Available(point) => Cursor::Available(point + translation),\n            Cursor::Levitating(point) => Cursor::Levitating(point + translation),\n            Cursor::Unavailable => Cursor::Unavailable,\n        }\n    }\n}\n\nimpl std::ops::Sub<Vector> for Cursor {\n    type Output = Self;\n\n    fn sub(self, translation: Vector) -> Self::Output {\n        match self {\n            Cursor::Available(point) => Cursor::Available(point - translation),\n            Cursor::Levitating(point) => Cursor::Levitating(point - translation),\n            Cursor::Unavailable => Cursor::Unavailable,\n        }\n    }\n}\n\nimpl std::ops::Mul<Transformation> for Cursor {\n    type Output = Self;\n\n    fn mul(self, transformation: Transformation) -> Self {\n        match self {\n            Self::Available(position) => Self::Available(position * transformation),\n            Self::Levitating(position) => Self::Levitating(position * transformation),\n            Self::Unavailable => Self::Unavailable,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/mouse/event.rs",
    "content": "use crate::Point;\n\nuse super::Button;\n\n/// A mouse event.\n///\n/// _**Note:** This type is largely incomplete! If you need to track\n/// additional events, feel free to [open an issue] and share your use case!_\n///\n/// [open an issue]: https://github.com/iced-rs/iced/issues\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Event {\n    /// The mouse cursor entered the window.\n    CursorEntered,\n\n    /// The mouse cursor left the window.\n    CursorLeft,\n\n    /// The mouse cursor was moved\n    CursorMoved {\n        /// The new position of the mouse cursor\n        position: Point,\n    },\n\n    /// A mouse button was pressed.\n    ButtonPressed(Button),\n\n    /// A mouse button was released.\n    ButtonReleased(Button),\n\n    /// The mouse wheel was scrolled.\n    WheelScrolled {\n        /// The scroll movement.\n        delta: ScrollDelta,\n    },\n}\n\n/// A scroll movement.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum ScrollDelta {\n    /// A line-based scroll movement\n    Lines {\n        /// The number of horizontal lines scrolled\n        x: f32,\n\n        /// The number of vertical lines scrolled\n        y: f32,\n    },\n    /// A pixel-based scroll movement\n    Pixels {\n        /// The number of horizontal pixels scrolled\n        x: f32,\n        /// The number of vertical pixels scrolled\n        y: f32,\n    },\n}\n"
  },
  {
    "path": "core/src/mouse/interaction.rs",
    "content": "/// The interaction of a mouse cursor.\n#[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Default)]\n#[allow(missing_docs)]\npub enum Interaction {\n    #[default]\n    None,\n    Hidden,\n    Idle,\n    ContextMenu,\n    Help,\n    Pointer,\n    Progress,\n    Wait,\n    Cell,\n    Crosshair,\n    Text,\n    Alias,\n    Copy,\n    Move,\n    NoDrop,\n    NotAllowed,\n    Grab,\n    Grabbing,\n    ResizingHorizontally,\n    ResizingVertically,\n    ResizingDiagonallyUp,\n    ResizingDiagonallyDown,\n    ResizingColumn,\n    ResizingRow,\n    AllScroll,\n    ZoomIn,\n    ZoomOut,\n}\n"
  },
  {
    "path": "core/src/mouse.rs",
    "content": "//! Handle mouse events.\npub mod click;\n\nmod button;\nmod cursor;\nmod event;\nmod interaction;\n\npub use button::Button;\npub use click::Click;\npub use cursor::Cursor;\npub use event::{Event, ScrollDelta};\npub use interaction::Interaction;\n"
  },
  {
    "path": "core/src/overlay/element.rs",
    "content": "pub use crate::Overlay;\n\nuse crate::layout;\nuse crate::mouse;\nuse crate::renderer;\nuse crate::widget;\nuse crate::{Event, Layout, Shell, Size};\n\n/// A generic [`Overlay`].\npub struct Element<'a, Message, Theme, Renderer> {\n    overlay: Box<dyn Overlay<Message, Theme, Renderer> + 'a>,\n}\n\nimpl<'a, Message, Theme, Renderer> Element<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::Renderer,\n{\n    /// Creates a new [`Element`] containing the given [`Overlay`].\n    pub fn new(overlay: Box<dyn Overlay<Message, Theme, Renderer> + 'a>) -> Self {\n        Self { overlay }\n    }\n\n    /// Returns a reference to the [`Overlay`] of the [`Element`],\n    pub fn as_overlay(&self) -> &dyn Overlay<Message, Theme, Renderer> {\n        self.overlay.as_ref()\n    }\n\n    /// Returns a mutable reference to the [`Overlay`] of the [`Element`],\n    pub fn as_overlay_mut(&mut self) -> &mut dyn Overlay<Message, Theme, Renderer> {\n        self.overlay.as_mut()\n    }\n\n    /// Applies a transformation to the produced message of the [`Element`].\n    pub fn map<B>(self, f: &'a dyn Fn(Message) -> B) -> Element<'a, B, Theme, Renderer>\n    where\n        Message: 'a,\n        Theme: 'a,\n        Renderer: 'a,\n        B: 'a,\n    {\n        Element {\n            overlay: Box::new(Map::new(self.overlay, f)),\n        }\n    }\n}\n\nstruct Map<'a, A, B, Theme, Renderer> {\n    content: Box<dyn Overlay<A, Theme, Renderer> + 'a>,\n    mapper: &'a dyn Fn(A) -> B,\n}\n\nimpl<'a, A, B, Theme, Renderer> Map<'a, A, B, Theme, Renderer> {\n    pub fn new(\n        content: Box<dyn Overlay<A, Theme, Renderer> + 'a>,\n        mapper: &'a dyn Fn(A) -> B,\n    ) -> Map<'a, A, B, Theme, Renderer> {\n        Map { content, mapper }\n    }\n}\n\nimpl<A, B, Theme, Renderer> Overlay<B, Theme, Renderer> for Map<'_, A, B, Theme, Renderer>\nwhere\n    Renderer: crate::Renderer,\n{\n    fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n        self.content.layout(renderer, bounds)\n    }\n\n    fn operate(\n        &mut self,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.content.operate(layout, renderer, operation);\n    }\n\n    fn update(\n        &mut self,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, B>,\n    ) {\n        let mut local_messages = Vec::new();\n        let mut local_shell = Shell::new(&mut local_messages);\n\n        self.content\n            .update(event, layout, cursor, renderer, &mut local_shell);\n\n        shell.merge(local_shell, self.mapper);\n    }\n\n    fn mouse_interaction(\n        &self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.content.mouse_interaction(layout, cursor, renderer)\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) {\n        self.content.draw(renderer, theme, style, layout, cursor);\n    }\n\n    fn overlay<'a>(\n        &'a mut self,\n        layout: Layout<'a>,\n        renderer: &Renderer,\n    ) -> Option<Element<'a, B, Theme, Renderer>> {\n        self.content\n            .overlay(layout, renderer)\n            .map(|overlay| overlay.map(self.mapper))\n    }\n}\n"
  },
  {
    "path": "core/src/overlay/group.rs",
    "content": "use crate::layout;\nuse crate::mouse;\nuse crate::overlay;\nuse crate::renderer;\nuse crate::widget;\nuse crate::{Event, Layout, Overlay, Shell, Size};\n\n/// An [`Overlay`] container that displays multiple overlay [`overlay::Element`]\n/// children.\npub struct Group<'a, Message, Theme, Renderer> {\n    children: Vec<overlay::Element<'a, Message, Theme, Renderer>>,\n}\n\nimpl<'a, Message, Theme, Renderer> Group<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: 'a + crate::Renderer,\n{\n    /// Creates an empty [`Group`].\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Creates a [`Group`] with the given elements.\n    pub fn with_children(\n        mut children: Vec<overlay::Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        use std::cmp;\n\n        children.sort_unstable_by(|a, b| {\n            a.as_overlay()\n                .index()\n                .partial_cmp(&b.as_overlay().index())\n                .unwrap_or(cmp::Ordering::Equal)\n        });\n\n        Group { children }\n    }\n\n    /// Turns the [`Group`] into an overlay [`overlay::Element`].\n    pub fn overlay(self) -> overlay::Element<'a, Message, Theme, Renderer> {\n        overlay::Element::new(Box::new(self))\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> Default for Group<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: 'a + crate::Renderer,\n{\n    fn default() -> Self {\n        Self::with_children(Vec::new())\n    }\n}\n\nimpl<Message, Theme, Renderer> Overlay<Message, Theme, Renderer>\n    for Group<'_, Message, Theme, Renderer>\nwhere\n    Renderer: crate::Renderer,\n{\n    fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n        layout::Node::with_children(\n            bounds,\n            self.children\n                .iter_mut()\n                .map(|child| child.as_overlay_mut().layout(renderer, bounds))\n                .collect(),\n        )\n    }\n\n    fn update(\n        &mut self,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n    ) {\n        for (child, layout) in self.children.iter_mut().zip(layout.children()) {\n            child\n                .as_overlay_mut()\n                .update(event, layout, cursor, renderer, shell);\n        }\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) {\n        for (child, layout) in self.children.iter().zip(layout.children()) {\n            child\n                .as_overlay()\n                .draw(renderer, theme, style, layout, cursor);\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.children\n            .iter()\n            .zip(layout.children())\n            .map(|(child, layout)| {\n                child\n                    .as_overlay()\n                    .mouse_interaction(layout, cursor, renderer)\n            })\n            .max()\n            .unwrap_or_default()\n    }\n\n    fn operate(\n        &mut self,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        operation.traverse(&mut |operation| {\n            self.children\n                .iter_mut()\n                .zip(layout.children())\n                .for_each(|(child, layout)| {\n                    child.as_overlay_mut().operate(layout, renderer, operation);\n                });\n        });\n    }\n\n    fn overlay<'a>(\n        &'a mut self,\n        layout: Layout<'a>,\n        renderer: &Renderer,\n    ) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {\n        let children = self\n            .children\n            .iter_mut()\n            .zip(layout.children())\n            .filter_map(|(child, layout)| child.as_overlay_mut().overlay(layout, renderer))\n            .collect::<Vec<_>>();\n\n        (!children.is_empty()).then(|| Group::with_children(children).overlay())\n    }\n\n    fn index(&self) -> f32 {\n        self.children\n            .first()\n            .map(|child| child.as_overlay().index())\n            .unwrap_or(1.0)\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Group<'a, Message, Theme, Renderer>>\n    for overlay::Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: 'a + crate::Renderer,\n{\n    fn from(group: Group<'a, Message, Theme, Renderer>) -> Self {\n        group.overlay()\n    }\n}\n"
  },
  {
    "path": "core/src/overlay/nested.rs",
    "content": "use crate::event;\nuse crate::layout;\nuse crate::mouse;\nuse crate::overlay;\nuse crate::renderer;\nuse crate::widget;\nuse crate::{Event, Layout, Shell, Size};\n\n/// An overlay container that displays nested overlays\npub struct Nested<'a, Message, Theme, Renderer> {\n    overlay: overlay::Element<'a, Message, Theme, Renderer>,\n}\n\nimpl<'a, Message, Theme, Renderer> Nested<'a, Message, Theme, Renderer>\nwhere\n    Renderer: renderer::Renderer,\n{\n    /// Creates a nested overlay from the provided [`overlay::Element`]\n    pub fn new(element: overlay::Element<'a, Message, Theme, Renderer>) -> Self {\n        Self { overlay: element }\n    }\n\n    /// Returns the layout [`Node`] of the [`Nested`] overlay.\n    ///\n    /// [`Node`]: layout::Node\n    pub fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n        fn recurse<Message, Theme, Renderer>(\n            element: &mut overlay::Element<'_, Message, Theme, Renderer>,\n            renderer: &Renderer,\n            bounds: Size,\n        ) -> layout::Node\n        where\n            Renderer: renderer::Renderer,\n        {\n            let overlay = element.as_overlay_mut();\n            let node = overlay.layout(renderer, bounds);\n\n            let nested_node = overlay\n                .overlay(Layout::new(&node), renderer)\n                .as_mut()\n                .map(|nested| recurse(nested, renderer, bounds));\n\n            if let Some(nested_node) = nested_node {\n                layout::Node::with_children(node.size(), vec![node, nested_node])\n            } else {\n                layout::Node::with_children(node.size(), vec![node])\n            }\n        }\n\n        recurse(&mut self.overlay, renderer, bounds)\n    }\n\n    /// Draws the [`Nested`] overlay using the associated `Renderer`.\n    pub fn draw(\n        &mut self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) {\n        fn recurse<Message, Theme, Renderer>(\n            element: &mut overlay::Element<'_, Message, Theme, Renderer>,\n            layout: Layout<'_>,\n            renderer: &mut Renderer,\n            theme: &Theme,\n            style: &renderer::Style,\n            cursor: mouse::Cursor,\n        ) where\n            Renderer: renderer::Renderer,\n        {\n            let mut layouts = layout.children();\n\n            if let Some(layout) = layouts.next() {\n                let nested_layout = layouts.next();\n                let overlay = element.as_overlay_mut();\n\n                let is_over = cursor\n                    .position()\n                    .zip(nested_layout)\n                    .and_then(|(cursor_position, nested_layout)| {\n                        overlay.overlay(layout, renderer).map(|nested| {\n                            nested.as_overlay().mouse_interaction(\n                                nested_layout.children().next().unwrap(),\n                                mouse::Cursor::Available(cursor_position),\n                                renderer,\n                            ) != mouse::Interaction::None\n                        })\n                    })\n                    .unwrap_or_default();\n\n                renderer.with_layer(layout.bounds(), |renderer| {\n                    overlay.draw(\n                        renderer,\n                        theme,\n                        style,\n                        layout,\n                        if is_over {\n                            mouse::Cursor::Unavailable\n                        } else {\n                            cursor\n                        },\n                    );\n                });\n\n                if let Some((mut nested, nested_layout)) =\n                    overlay.overlay(layout, renderer).zip(nested_layout)\n                {\n                    recurse(&mut nested, nested_layout, renderer, theme, style, cursor);\n                }\n            }\n        }\n\n        recurse(&mut self.overlay, layout, renderer, theme, style, cursor);\n    }\n\n    /// Applies a [`widget::Operation`] to the [`Nested`] overlay.\n    pub fn operate(\n        &mut self,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        fn recurse<Message, Theme, Renderer>(\n            element: &mut overlay::Element<'_, Message, Theme, Renderer>,\n            layout: Layout<'_>,\n            renderer: &Renderer,\n            operation: &mut dyn widget::Operation,\n        ) where\n            Renderer: renderer::Renderer,\n        {\n            let mut layouts = layout.children();\n\n            if let Some(layout) = layouts.next() {\n                let overlay = element.as_overlay_mut();\n\n                overlay.operate(layout, renderer, operation);\n\n                if let Some((mut nested, nested_layout)) =\n                    overlay.overlay(layout, renderer).zip(layouts.next())\n                {\n                    recurse(&mut nested, nested_layout, renderer, operation);\n                }\n            }\n        }\n\n        recurse(&mut self.overlay, layout, renderer, operation);\n    }\n\n    /// Processes a runtime [`Event`].\n    pub fn update(\n        &mut self,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n    ) {\n        fn recurse<Message, Theme, Renderer>(\n            element: &mut overlay::Element<'_, Message, Theme, Renderer>,\n            layout: Layout<'_>,\n            event: &Event,\n            cursor: mouse::Cursor,\n            renderer: &Renderer,\n            shell: &mut Shell<'_, Message>,\n        ) -> bool\n        where\n            Renderer: renderer::Renderer,\n        {\n            let mut layouts = layout.children();\n\n            if let Some(layout) = layouts.next() {\n                let overlay = element.as_overlay_mut();\n\n                let nested_is_over = if let Some((mut nested, nested_layout)) =\n                    overlay.overlay(layout, renderer).zip(layouts.next())\n                {\n                    recurse(&mut nested, nested_layout, event, cursor, renderer, shell)\n                } else {\n                    false\n                };\n\n                if shell.event_status() == event::Status::Ignored {\n                    let is_over = nested_is_over\n                        || cursor\n                            .position()\n                            .map(|cursor_position| {\n                                overlay.mouse_interaction(\n                                    layout,\n                                    mouse::Cursor::Available(cursor_position),\n                                    renderer,\n                                ) != mouse::Interaction::None\n                            })\n                            .unwrap_or_default();\n\n                    overlay.update(\n                        event,\n                        layout,\n                        if nested_is_over {\n                            mouse::Cursor::Unavailable\n                        } else {\n                            cursor\n                        },\n                        renderer,\n                        shell,\n                    );\n\n                    is_over\n                } else {\n                    nested_is_over\n                }\n            } else {\n                false\n            }\n        }\n\n        let _ = recurse(&mut self.overlay, layout, event, cursor, renderer, shell);\n    }\n\n    /// Returns the current [`mouse::Interaction`] of the [`Nested`] overlay.\n    pub fn mouse_interaction(\n        &mut self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        fn recurse<Message, Theme, Renderer>(\n            element: &mut overlay::Element<'_, Message, Theme, Renderer>,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            renderer: &Renderer,\n        ) -> Option<mouse::Interaction>\n        where\n            Renderer: renderer::Renderer,\n        {\n            let mut layouts = layout.children();\n\n            let layout = layouts.next()?;\n            let overlay = element.as_overlay_mut();\n\n            Some(\n                overlay\n                    .overlay(layout, renderer)\n                    .zip(layouts.next())\n                    .and_then(|(mut overlay, layout)| {\n                        recurse(&mut overlay, layout, cursor, renderer)\n                    })\n                    .unwrap_or_else(|| overlay.mouse_interaction(layout, cursor, renderer)),\n            )\n        }\n\n        recurse(&mut self.overlay, layout, cursor, renderer).unwrap_or_default()\n    }\n}\n"
  },
  {
    "path": "core/src/overlay.rs",
    "content": "//! Display interactive elements on top of other widgets.\nmod element;\nmod group;\nmod nested;\n\npub use element::Element;\npub use group::Group;\npub use nested::Nested;\n\nuse crate::layout;\nuse crate::mouse;\nuse crate::renderer;\nuse crate::widget;\nuse crate::widget::Tree;\nuse crate::{Event, Layout, Rectangle, Shell, Size, Vector};\n\n/// An interactive component that can be displayed on top of other widgets.\npub trait Overlay<Message, Theme, Renderer>\nwhere\n    Renderer: crate::Renderer,\n{\n    /// Returns the layout [`Node`] of the [`Overlay`].\n    ///\n    /// This [`Node`] is used by the runtime to compute the [`Layout`] of the\n    /// user interface.\n    ///\n    /// [`Node`]: layout::Node\n    fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node;\n\n    /// Draws the [`Overlay`] using the associated `Renderer`.\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    );\n\n    /// Applies a [`widget::Operation`] to the [`Overlay`].\n    fn operate(\n        &mut self,\n        _layout: Layout<'_>,\n        _renderer: &Renderer,\n        _operation: &mut dyn widget::Operation,\n    ) {\n    }\n\n    /// Processes a runtime [`Event`].\n    ///\n    /// By default, it does nothing.\n    fn update(\n        &mut self,\n        _event: &Event,\n        _layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        _shell: &mut Shell<'_, Message>,\n    ) {\n    }\n\n    /// Returns the current [`mouse::Interaction`] of the [`Overlay`].\n    ///\n    /// By default, it returns [`mouse::Interaction::None`].\n    fn mouse_interaction(\n        &self,\n        _layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        mouse::Interaction::None\n    }\n\n    /// Returns the nested overlay of the [`Overlay`], if there is any.\n    fn overlay<'a>(\n        &'a mut self,\n        _layout: Layout<'a>,\n        _renderer: &Renderer,\n    ) -> Option<Element<'a, Message, Theme, Renderer>> {\n        None\n    }\n\n    /// The index of the overlay.\n    ///\n    /// Overlays with a higher index will be rendered on top of overlays with\n    /// a lower index.\n    ///\n    /// By default, it returns `1.0`.\n    fn index(&self) -> f32 {\n        1.0\n    }\n}\n\n/// Returns a [`Group`] of overlay [`Element`] children.\n///\n/// This method will generally only be used by advanced users that are\n/// implementing the [`Widget`](crate::Widget) trait.\npub fn from_children<'a, Message, Theme, Renderer>(\n    children: &'a mut [crate::Element<'_, Message, Theme, Renderer>],\n    tree: &'a mut Tree,\n    layout: Layout<'a>,\n    renderer: &Renderer,\n    viewport: &Rectangle,\n    translation: Vector,\n) -> Option<Element<'a, Message, Theme, Renderer>>\nwhere\n    Renderer: crate::Renderer,\n{\n    let children = children\n        .iter_mut()\n        .zip(&mut tree.children)\n        .zip(layout.children())\n        .filter_map(|((child, state), layout)| {\n            child\n                .as_widget_mut()\n                .overlay(state, layout, renderer, viewport, translation)\n        })\n        .collect::<Vec<_>>();\n\n    (!children.is_empty()).then(|| Group::with_children(children).overlay())\n}\n"
  },
  {
    "path": "core/src/padding.rs",
    "content": "//! Space stuff around the perimeter.\nuse crate::{Pixels, Size};\n\n/// An amount of space to pad for each side of a box\n///\n/// You can leverage the `From` trait to build [`Padding`] conveniently:\n///\n/// ```\n/// # use iced_core::Padding;\n/// #\n/// let padding = Padding::from(20);              // 20px on all sides\n/// let padding = Padding::from([10, 20]);        // top/bottom, left/right\n/// ```\n///\n/// Normally, the `padding` method of a widget will ask for an `Into<Padding>`,\n/// so you can easily write:\n///\n/// ```\n/// # use iced_core::Padding;\n/// #\n/// # struct Widget;\n/// #\n/// impl Widget {\n///     # pub fn new() -> Self { Self }\n///     #\n///     pub fn padding(mut self, padding: impl Into<Padding>) -> Self {\n///         // ...\n///         self\n///     }\n/// }\n///\n/// let widget = Widget::new().padding(20);              // 20px on all sides\n/// let widget = Widget::new().padding([10, 20]);        // top/bottom, left/right\n/// ```\n#[derive(Debug, Copy, Clone, PartialEq, Default)]\npub struct Padding {\n    /// Top padding\n    pub top: f32,\n    /// Right padding\n    pub right: f32,\n    /// Bottom padding\n    pub bottom: f32,\n    /// Left padding\n    pub left: f32,\n}\n\n/// Create a [`Padding`] that is equal on all sides.\npub fn all(padding: impl Into<Pixels>) -> Padding {\n    Padding::new(padding.into().0)\n}\n\n/// Create some top [`Padding`].\npub fn top(padding: impl Into<Pixels>) -> Padding {\n    Padding::default().top(padding)\n}\n\n/// Create some bottom [`Padding`].\npub fn bottom(padding: impl Into<Pixels>) -> Padding {\n    Padding::default().bottom(padding)\n}\n\n/// Create some left [`Padding`].\npub fn left(padding: impl Into<Pixels>) -> Padding {\n    Padding::default().left(padding)\n}\n\n/// Create some right [`Padding`].\npub fn right(padding: impl Into<Pixels>) -> Padding {\n    Padding::default().right(padding)\n}\n\n/// Create some [`Padding`] with equal left and right sides.\npub fn horizontal(padding: impl Into<Pixels>) -> Padding {\n    Padding::default().horizontal(padding)\n}\n\n/// Create some [`Padding`] with equal top and bottom sides.\npub fn vertical(padding: impl Into<Pixels>) -> Padding {\n    Padding::default().vertical(padding)\n}\n\nimpl Padding {\n    /// Padding of zero\n    pub const ZERO: Padding = Padding {\n        top: 0.0,\n        right: 0.0,\n        bottom: 0.0,\n        left: 0.0,\n    };\n\n    /// Create a [`Padding`] that is equal on all sides.\n    pub const fn new(padding: f32) -> Padding {\n        Padding {\n            top: padding,\n            right: padding,\n            bottom: padding,\n            left: padding,\n        }\n    }\n\n    /// Sets the [`top`] of the [`Padding`].\n    ///\n    /// [`top`]: Self::top\n    pub fn top(self, top: impl Into<Pixels>) -> Self {\n        Self {\n            top: top.into().0,\n            ..self\n        }\n    }\n\n    /// Sets the [`bottom`] of the [`Padding`].\n    ///\n    /// [`bottom`]: Self::bottom\n    pub fn bottom(self, bottom: impl Into<Pixels>) -> Self {\n        Self {\n            bottom: bottom.into().0,\n            ..self\n        }\n    }\n\n    /// Sets the [`left`] of the [`Padding`].\n    ///\n    /// [`left`]: Self::left\n    pub fn left(self, left: impl Into<Pixels>) -> Self {\n        Self {\n            left: left.into().0,\n            ..self\n        }\n    }\n\n    /// Sets the [`right`] of the [`Padding`].\n    ///\n    /// [`right`]: Self::right\n    pub fn right(self, right: impl Into<Pixels>) -> Self {\n        Self {\n            right: right.into().0,\n            ..self\n        }\n    }\n\n    /// Sets the [`left`] and [`right`] of the [`Padding`].\n    ///\n    /// [`left`]: Self::left\n    /// [`right`]: Self::right\n    pub fn horizontal(self, horizontal: impl Into<Pixels>) -> Self {\n        let horizontal = horizontal.into();\n\n        Self {\n            left: horizontal.0,\n            right: horizontal.0,\n            ..self\n        }\n    }\n\n    /// Sets the [`top`] and [`bottom`] of the [`Padding`].\n    ///\n    /// [`top`]: Self::top\n    /// [`bottom`]: Self::bottom\n    pub fn vertical(self, vertical: impl Into<Pixels>) -> Self {\n        let vertical = vertical.into();\n\n        Self {\n            top: vertical.0,\n            bottom: vertical.0,\n            ..self\n        }\n    }\n\n    /// Returns the total amount of horizontal [`Padding`].\n    pub fn x(self) -> f32 {\n        self.left + self.right\n    }\n\n    /// Returns the total amount of vertical [`Padding`].\n    pub fn y(self) -> f32 {\n        self.top + self.bottom\n    }\n\n    /// Fits the [`Padding`] between the provided `inner` and `outer` [`Size`].\n    pub fn fit(self, inner: Size, outer: Size) -> Self {\n        let available = (outer - inner).max(Size::ZERO);\n        let new_top = self.top.min(available.height);\n        let new_left = self.left.min(available.width);\n\n        Padding {\n            top: new_top,\n            bottom: self.bottom.min(available.height - new_top),\n            left: new_left,\n            right: self.right.min(available.width - new_left),\n        }\n    }\n}\n\nimpl From<u16> for Padding {\n    fn from(p: u16) -> Self {\n        Padding {\n            top: f32::from(p),\n            right: f32::from(p),\n            bottom: f32::from(p),\n            left: f32::from(p),\n        }\n    }\n}\n\nimpl From<[u16; 2]> for Padding {\n    fn from(p: [u16; 2]) -> Self {\n        Padding {\n            top: f32::from(p[0]),\n            right: f32::from(p[1]),\n            bottom: f32::from(p[0]),\n            left: f32::from(p[1]),\n        }\n    }\n}\n\nimpl From<f32> for Padding {\n    fn from(p: f32) -> Self {\n        Padding {\n            top: p,\n            right: p,\n            bottom: p,\n            left: p,\n        }\n    }\n}\n\nimpl From<[f32; 2]> for Padding {\n    fn from(p: [f32; 2]) -> Self {\n        Padding {\n            top: p[0],\n            right: p[1],\n            bottom: p[0],\n            left: p[1],\n        }\n    }\n}\n\nimpl From<Padding> for Size {\n    fn from(padding: Padding) -> Self {\n        Self::new(padding.x(), padding.y())\n    }\n}\n\nimpl From<Pixels> for Padding {\n    fn from(pixels: Pixels) -> Self {\n        Self::from(pixels.0)\n    }\n}\n"
  },
  {
    "path": "core/src/pixels.rs",
    "content": "/// An amount of logical pixels.\n///\n/// Normally used to represent an amount of space, or the size of something.\n///\n/// This type is normally asked as an argument in a generic way\n/// (e.g. `impl Into<Pixels>`) and, since `Pixels` implements `From` both for\n/// `f32` and `u16`, you should be able to provide both integers and float\n/// literals as needed.\n#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]\npub struct Pixels(pub f32);\n\nimpl Pixels {\n    /// Zero pixels.\n    pub const ZERO: Self = Self(0.0);\n}\n\nimpl From<f32> for Pixels {\n    fn from(amount: f32) -> Self {\n        Self(amount)\n    }\n}\n\nimpl From<u32> for Pixels {\n    fn from(amount: u32) -> Self {\n        Self(amount as f32)\n    }\n}\n\nimpl From<Pixels> for f32 {\n    fn from(pixels: Pixels) -> Self {\n        pixels.0\n    }\n}\n\nimpl std::ops::Add for Pixels {\n    type Output = Pixels;\n\n    fn add(self, rhs: Self) -> Self {\n        Pixels(self.0 + rhs.0)\n    }\n}\n\nimpl std::ops::Add<f32> for Pixels {\n    type Output = Pixels;\n\n    fn add(self, rhs: f32) -> Self {\n        Pixels(self.0 + rhs)\n    }\n}\n\nimpl std::ops::Mul for Pixels {\n    type Output = Pixels;\n\n    fn mul(self, rhs: Self) -> Self {\n        Pixels(self.0 * rhs.0)\n    }\n}\n\nimpl std::ops::Mul<f32> for Pixels {\n    type Output = Pixels;\n\n    fn mul(self, rhs: f32) -> Self {\n        Pixels(self.0 * rhs)\n    }\n}\n\nimpl std::ops::Div for Pixels {\n    type Output = Pixels;\n\n    fn div(self, rhs: Self) -> Self {\n        Pixels(self.0 / rhs.0)\n    }\n}\n\nimpl std::ops::Div<f32> for Pixels {\n    type Output = Pixels;\n\n    fn div(self, rhs: f32) -> Self {\n        Pixels(self.0 / rhs)\n    }\n}\n\nimpl std::ops::Div<u32> for Pixels {\n    type Output = Pixels;\n\n    fn div(self, rhs: u32) -> Self {\n        Pixels(self.0 / rhs as f32)\n    }\n}\n"
  },
  {
    "path": "core/src/point.rs",
    "content": "use crate::Vector;\n\nuse num_traits::{Float, Num};\nuse std::fmt;\n\n/// A 2D point.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub struct Point<T = f32> {\n    /// The X coordinate.\n    pub x: T,\n\n    /// The Y coordinate.\n    pub y: T,\n}\n\nimpl Point {\n    /// The origin (i.e. a [`Point`] at (0, 0)).\n    pub const ORIGIN: Self = Self::new(0.0, 0.0);\n}\n\nimpl<T: Num> Point<T> {\n    /// Creates a new [`Point`] with the given coordinates.\n    pub const fn new(x: T, y: T) -> Self {\n        Self { x, y }\n    }\n\n    /// Computes the distance to another [`Point`].\n    pub fn distance(&self, to: Self) -> T\n    where\n        T: Float,\n    {\n        let a = self.x - to.x;\n        let b = self.y - to.y;\n\n        a.hypot(b)\n    }\n}\n\nimpl<T> From<[T; 2]> for Point<T>\nwhere\n    T: Num,\n{\n    fn from([x, y]: [T; 2]) -> Self {\n        Point { x, y }\n    }\n}\n\nimpl<T> From<(T, T)> for Point<T>\nwhere\n    T: Num,\n{\n    fn from((x, y): (T, T)) -> Self {\n        Self { x, y }\n    }\n}\n\nimpl<T> From<Point<T>> for [T; 2] {\n    fn from(point: Point<T>) -> [T; 2] {\n        [point.x, point.y]\n    }\n}\n\nimpl<T> std::ops::Add<Vector<T>> for Point<T>\nwhere\n    T: std::ops::Add<Output = T>,\n{\n    type Output = Self;\n\n    fn add(self, vector: Vector<T>) -> Self {\n        Self {\n            x: self.x + vector.x,\n            y: self.y + vector.y,\n        }\n    }\n}\n\nimpl<T> std::ops::AddAssign<Vector<T>> for Point<T>\nwhere\n    T: std::ops::AddAssign,\n{\n    fn add_assign(&mut self, vector: Vector<T>) {\n        self.x += vector.x;\n        self.y += vector.y;\n    }\n}\n\nimpl<T> std::ops::Sub<Vector<T>> for Point<T>\nwhere\n    T: std::ops::Sub<Output = T>,\n{\n    type Output = Self;\n\n    fn sub(self, vector: Vector<T>) -> Self {\n        Self {\n            x: self.x - vector.x,\n            y: self.y - vector.y,\n        }\n    }\n}\n\nimpl<T> std::ops::SubAssign<Vector<T>> for Point<T>\nwhere\n    T: std::ops::SubAssign,\n{\n    fn sub_assign(&mut self, vector: Vector<T>) {\n        self.x -= vector.x;\n        self.y -= vector.y;\n    }\n}\n\nimpl<T> std::ops::Sub<Point<T>> for Point<T>\nwhere\n    T: std::ops::Sub<Output = T>,\n{\n    type Output = Vector<T>;\n\n    fn sub(self, point: Self) -> Vector<T> {\n        Vector::new(self.x - point.x, self.y - point.y)\n    }\n}\n\nimpl<T> fmt::Display for Point<T>\nwhere\n    T: fmt::Display,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Point {{ x: {}, y: {} }}\", self.x, self.y)\n    }\n}\n\nimpl Point<f32> {\n    /// Rounds the [`Point`] coordinates.\n    pub fn round(self) -> Self {\n        Point {\n            x: self.x.round(),\n            y: self.y.round(),\n        }\n    }\n\n    /// Snaps the [`Point`] to __unsigned__ integer coordinates.\n    pub fn snap(self) -> Point<u32> {\n        Point {\n            x: self.x.round() as u32,\n            y: self.y.round() as u32,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/rectangle.rs",
    "content": "use crate::alignment;\nuse crate::{Padding, Point, Radians, Size, Vector};\n\n/// An axis-aligned rectangle.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub struct Rectangle<T = f32> {\n    /// X coordinate of the top-left corner.\n    pub x: T,\n\n    /// Y coordinate of the top-left corner.\n    pub y: T,\n\n    /// Width of the rectangle.\n    pub width: T,\n\n    /// Height of the rectangle.\n    pub height: T,\n}\n\nimpl<T> Rectangle<T>\nwhere\n    T: Default,\n{\n    /// Creates a new [`Rectangle`] with its top-left corner at the origin\n    /// and with the provided [`Size`].\n    pub fn with_size(size: Size<T>) -> Self {\n        Self {\n            x: T::default(),\n            y: T::default(),\n            width: size.width,\n            height: size.height,\n        }\n    }\n}\n\nimpl Rectangle<f32> {\n    /// A rectangle starting at negative infinity and with infinite width and height.\n    pub const INFINITE: Self = Self::new(\n        Point::new(f32::NEG_INFINITY, f32::NEG_INFINITY),\n        Size::INFINITE,\n    );\n\n    /// Creates a new [`Rectangle`] with its top-left corner in the given\n    /// [`Point`] and with the provided [`Size`].\n    pub const fn new(top_left: Point, size: Size) -> Self {\n        Self {\n            x: top_left.x,\n            y: top_left.y,\n            width: size.width,\n            height: size.height,\n        }\n    }\n\n    /// Creates a new square [`Rectangle`] with the center at the origin and\n    /// with the given radius.\n    pub fn with_radius(radius: f32) -> Self {\n        Self {\n            x: -radius,\n            y: -radius,\n            width: radius * 2.0,\n            height: radius * 2.0,\n        }\n    }\n\n    /// Creates a new axis-aligned [`Rectangle`] from the given vertices; returning the\n    /// rotation in [`Radians`] that must be applied to the axis-aligned [`Rectangle`]\n    /// to obtain the desired result.\n    pub fn with_vertices(\n        top_left: Point,\n        top_right: Point,\n        bottom_left: Point,\n    ) -> (Rectangle, Radians) {\n        let width = (top_right.x - top_left.x).hypot(top_right.y - top_left.y);\n\n        let height = (bottom_left.x - top_left.x).hypot(bottom_left.y - top_left.y);\n\n        let rotation = (top_right.y - top_left.y).atan2(top_right.x - top_left.x);\n\n        let rotation = if rotation < 0.0 {\n            2.0 * std::f32::consts::PI + rotation\n        } else {\n            rotation\n        };\n\n        let position = {\n            let center = Point::new(\n                (top_right.x + bottom_left.x) / 2.0,\n                (top_right.y + bottom_left.y) / 2.0,\n            );\n\n            let rotation = -rotation - std::f32::consts::PI * 2.0;\n\n            Point::new(\n                center.x + (top_left.x - center.x) * rotation.cos()\n                    - (top_left.y - center.y) * rotation.sin(),\n                center.y\n                    + (top_left.x - center.x) * rotation.sin()\n                    + (top_left.y - center.y) * rotation.cos(),\n            )\n        };\n\n        (\n            Rectangle::new(position, Size::new(width, height)),\n            Radians(rotation),\n        )\n    }\n\n    /// Returns the [`Point`] at the center of the [`Rectangle`].\n    pub fn center(&self) -> Point {\n        Point::new(self.center_x(), self.center_y())\n    }\n\n    /// Returns the X coordinate of the [`Point`] at the center of the\n    /// [`Rectangle`].\n    pub fn center_x(&self) -> f32 {\n        self.x + self.width / 2.0\n    }\n\n    /// Returns the Y coordinate of the [`Point`] at the center of the\n    /// [`Rectangle`].\n    pub fn center_y(&self) -> f32 {\n        self.y + self.height / 2.0\n    }\n\n    /// Returns the position of the top left corner of the [`Rectangle`].\n    pub fn position(&self) -> Point {\n        Point::new(self.x, self.y)\n    }\n\n    /// Returns the [`Size`] of the [`Rectangle`].\n    pub fn size(&self) -> Size {\n        Size::new(self.width, self.height)\n    }\n\n    /// Returns the area of the [`Rectangle`].\n    pub fn area(&self) -> f32 {\n        self.width * self.height\n    }\n\n    /// Returns true if the given [`Point`] is contained in the [`Rectangle`].\n    /// Excludes the right and bottom edges.\n    pub fn contains(&self, point: Point) -> bool {\n        self.x <= point.x\n            && point.x < self.x + self.width\n            && self.y <= point.y\n            && point.y < self.y + self.height\n    }\n\n    /// Returns the minimum distance from the given [`Point`] to any of the edges\n    /// of the [`Rectangle`].\n    pub fn distance(&self, point: Point) -> f32 {\n        let center = self.center();\n\n        let distance_x = ((point.x - center.x).abs() - self.width / 2.0).max(0.0);\n\n        let distance_y = ((point.y - center.y).abs() - self.height / 2.0).max(0.0);\n\n        distance_x.hypot(distance_y)\n    }\n\n    /// Computes the offset that must be applied to the [`Rectangle`] to be placed\n    /// inside the given `container`.\n    pub fn offset(&self, container: &Rectangle) -> Vector {\n        let Some(intersection) = self.intersection(container) else {\n            return Vector::ZERO;\n        };\n\n        let left = intersection.x - self.x;\n        let top = intersection.y - self.y;\n\n        Vector::new(\n            if left > 0.0 {\n                left\n            } else {\n                intersection.x + intersection.width - self.x - self.width\n            },\n            if top > 0.0 {\n                top\n            } else {\n                intersection.y + intersection.height - self.y - self.height\n            },\n        )\n    }\n\n    /// Returns true if the current [`Rectangle`] is within the given\n    /// `container`. Includes the right and bottom edges.\n    pub fn is_within(&self, container: &Rectangle) -> bool {\n        self.x >= container.x\n            && self.y >= container.y\n            && self.x + self.width <= container.x + container.width\n            && self.y + self.height <= container.y + container.height\n    }\n\n    /// Computes the intersection with the given [`Rectangle`].\n    pub fn intersection(&self, other: &Rectangle<f32>) -> Option<Rectangle<f32>> {\n        let x = self.x.max(other.x);\n        let y = self.y.max(other.y);\n\n        let lower_right_x = (self.x + self.width).min(other.x + other.width);\n        let lower_right_y = (self.y + self.height).min(other.y + other.height);\n\n        let width = lower_right_x - x;\n        let height = lower_right_y - y;\n\n        if width > 0.0 && height > 0.0 {\n            Some(Rectangle {\n                x,\n                y,\n                width,\n                height,\n            })\n        } else {\n            None\n        }\n    }\n\n    /// Returns whether the [`Rectangle`] intersects with the given one.\n    pub fn intersects(&self, other: &Self) -> bool {\n        self.intersection(other).is_some()\n    }\n\n    /// Computes the union with the given [`Rectangle`].\n    pub fn union(&self, other: &Self) -> Self {\n        let x = self.x.min(other.x);\n        let y = self.y.min(other.y);\n\n        let lower_right_x = (self.x + self.width).max(other.x + other.width);\n        let lower_right_y = (self.y + self.height).max(other.y + other.height);\n\n        let width = lower_right_x - x;\n        let height = lower_right_y - y;\n\n        Rectangle {\n            x,\n            y,\n            width,\n            height,\n        }\n    }\n\n    /// Rounds the [`Rectangle`] coordinates.\n    pub fn round(self) -> Self {\n        let top_left = self.position().round();\n        let bottom_right = (self.position() + Vector::from(self.size())).round();\n\n        Self {\n            x: top_left.x,\n            y: top_left.y,\n            width: bottom_right.x - top_left.x,\n            height: bottom_right.y - top_left.y,\n        }\n    }\n\n    /// Snaps the [`Rectangle`] to __unsigned__ integer coordinates.\n    pub fn snap(self) -> Option<Rectangle<u32>> {\n        let rounded = self.round();\n\n        if rounded.width < 1.0 || rounded.height < 1.0 {\n            return None;\n        }\n\n        Some(Rectangle {\n            x: rounded.x as u32,\n            y: rounded.y as u32,\n            width: rounded.width as u32,\n            height: rounded.height as u32,\n        })\n    }\n\n    /// Expands the [`Rectangle`] a given amount.\n    pub fn expand(self, padding: impl Into<Padding>) -> Self {\n        let padding = padding.into();\n\n        Self {\n            x: self.x - padding.left,\n            y: self.y - padding.top,\n            width: self.width + padding.x(),\n            height: self.height + padding.y(),\n        }\n    }\n\n    /// Shrinks the [`Rectangle`] a given amount.\n    pub fn shrink(self, padding: impl Into<Padding>) -> Self {\n        let padding = padding.into();\n\n        Self {\n            x: self.x + padding.left,\n            y: self.y + padding.top,\n            width: self.width - padding.x(),\n            height: self.height - padding.y(),\n        }\n    }\n\n    /// Rotates the [`Rectangle`] and returns the smallest [`Rectangle`]\n    /// containing it.\n    pub fn rotate(self, rotation: Radians) -> Self {\n        let size = self.size().rotate(rotation);\n        let position = Point::new(\n            self.center_x() - size.width / 2.0,\n            self.center_y() - size.height / 2.0,\n        );\n\n        Self::new(position, size)\n    }\n\n    /// Scales the [`Rectangle`] without changing its position, effectively\n    /// \"zooming\" it.\n    pub fn zoom(self, zoom: f32) -> Self {\n        Self {\n            x: self.x - (self.width * (zoom - 1.0)) / 2.0,\n            y: self.y - (self.height * (zoom - 1.0)) / 2.0,\n            width: self.width * zoom,\n            height: self.height * zoom,\n        }\n    }\n\n    /// Returns the top-left position to render an object of the given [`Size`].\n    /// inside the [`Rectangle`] that is anchored to the edge or corner\n    /// defined by the alignment arguments.\n    pub fn anchor(\n        &self,\n        size: Size,\n        align_x: impl Into<alignment::Horizontal>,\n        align_y: impl Into<alignment::Vertical>,\n    ) -> Point {\n        let x = match align_x.into() {\n            alignment::Horizontal::Left => self.x,\n            alignment::Horizontal::Center => self.x + (self.width - size.width) / 2.0,\n            alignment::Horizontal::Right => self.x + self.width - size.width,\n        };\n\n        let y = match align_y.into() {\n            alignment::Vertical::Top => self.y,\n            alignment::Vertical::Center => self.y + (self.height - size.height) / 2.0,\n            alignment::Vertical::Bottom => self.y + self.height - size.height,\n        };\n\n        Point::new(x, y)\n    }\n}\n\nimpl std::ops::Mul<f32> for Rectangle<f32> {\n    type Output = Self;\n\n    fn mul(self, scale: f32) -> Self {\n        Self {\n            x: self.x * scale,\n            y: self.y * scale,\n            width: self.width * scale,\n            height: self.height * scale,\n        }\n    }\n}\n\nimpl From<Rectangle<u32>> for Rectangle<f32> {\n    fn from(rectangle: Rectangle<u32>) -> Rectangle<f32> {\n        Rectangle {\n            x: rectangle.x as f32,\n            y: rectangle.y as f32,\n            width: rectangle.width as f32,\n            height: rectangle.height as f32,\n        }\n    }\n}\n\nimpl<T> std::ops::Add<Vector<T>> for Rectangle<T>\nwhere\n    T: std::ops::Add<Output = T>,\n{\n    type Output = Rectangle<T>;\n\n    fn add(self, translation: Vector<T>) -> Self {\n        Rectangle {\n            x: self.x + translation.x,\n            y: self.y + translation.y,\n            ..self\n        }\n    }\n}\n\nimpl<T> std::ops::Sub<Vector<T>> for Rectangle<T>\nwhere\n    T: std::ops::Sub<Output = T>,\n{\n    type Output = Rectangle<T>;\n\n    fn sub(self, translation: Vector<T>) -> Self {\n        Rectangle {\n            x: self.x - translation.x,\n            y: self.y - translation.y,\n            ..self\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/renderer/null.rs",
    "content": "use crate::alignment;\nuse crate::image::{self, Image};\nuse crate::renderer::{self, Renderer};\nuse crate::svg;\nuse crate::text::{self, Text};\nuse crate::{Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation};\n\nimpl Renderer for () {\n    fn start_layer(&mut self, _bounds: Rectangle) {}\n\n    fn end_layer(&mut self) {}\n\n    fn start_transformation(&mut self, _transformation: Transformation) {}\n\n    fn end_transformation(&mut self) {}\n\n    fn fill_quad(&mut self, _quad: renderer::Quad, _background: impl Into<Background>) {}\n\n    fn allocate_image(\n        &mut self,\n        handle: &image::Handle,\n        callback: impl FnOnce(Result<image::Allocation, image::Error>) + Send + 'static,\n    ) {\n        #[allow(unsafe_code)]\n        callback(Ok(unsafe { image::allocate(handle, Size::new(100, 100)) }));\n    }\n\n    fn hint(&mut self, _scale_factor: f32) {}\n\n    fn scale_factor(&self) -> Option<f32> {\n        None\n    }\n\n    fn reset(&mut self, _new_bounds: Rectangle) {}\n}\n\nimpl text::Renderer for () {\n    type Font = Font;\n    type Paragraph = ();\n    type Editor = ();\n\n    const ICON_FONT: Font = Font::DEFAULT;\n    const CHECKMARK_ICON: char = '0';\n    const ARROW_DOWN_ICON: char = '0';\n    const SCROLL_UP_ICON: char = '0';\n    const SCROLL_DOWN_ICON: char = '0';\n    const SCROLL_LEFT_ICON: char = '0';\n    const SCROLL_RIGHT_ICON: char = '0';\n    const ICED_LOGO: char = '0';\n\n    fn default_font(&self) -> Self::Font {\n        Font::default()\n    }\n\n    fn default_size(&self) -> Pixels {\n        Pixels(16.0)\n    }\n\n    fn fill_paragraph(\n        &mut self,\n        _paragraph: &Self::Paragraph,\n        _position: Point,\n        _color: Color,\n        _clip_bounds: Rectangle,\n    ) {\n    }\n\n    fn fill_editor(\n        &mut self,\n        _editor: &Self::Editor,\n        _position: Point,\n        _color: Color,\n        _clip_bounds: Rectangle,\n    ) {\n    }\n\n    fn fill_text(\n        &mut self,\n        _paragraph: Text,\n        _position: Point,\n        _color: Color,\n        _clip_bounds: Rectangle,\n    ) {\n    }\n}\n\nimpl text::Paragraph for () {\n    type Font = Font;\n\n    fn with_text(_text: Text<&str>) -> Self {}\n\n    fn with_spans<Link>(_text: Text<&[text::Span<'_, Link, Self::Font>], Self::Font>) -> Self {}\n\n    fn resize(&mut self, _new_bounds: Size) {}\n\n    fn compare(&self, _text: Text<()>) -> text::Difference {\n        text::Difference::None\n    }\n\n    fn hint_factor(&self) -> Option<f32> {\n        None\n    }\n\n    fn size(&self) -> Pixels {\n        Pixels(16.0)\n    }\n\n    fn font(&self) -> Font {\n        Font::DEFAULT\n    }\n\n    fn line_height(&self) -> text::LineHeight {\n        text::LineHeight::default()\n    }\n\n    fn align_x(&self) -> text::Alignment {\n        text::Alignment::Default\n    }\n\n    fn align_y(&self) -> alignment::Vertical {\n        alignment::Vertical::Top\n    }\n\n    fn wrapping(&self) -> text::Wrapping {\n        text::Wrapping::default()\n    }\n\n    fn ellipsis(&self) -> text::Ellipsis {\n        text::Ellipsis::default()\n    }\n\n    fn shaping(&self) -> text::Shaping {\n        text::Shaping::default()\n    }\n\n    fn grapheme_position(&self, _line: usize, _index: usize) -> Option<Point> {\n        None\n    }\n\n    fn bounds(&self) -> Size {\n        Size::ZERO\n    }\n\n    fn min_bounds(&self) -> Size {\n        Size::ZERO\n    }\n\n    fn hit_test(&self, _point: Point) -> Option<text::Hit> {\n        None\n    }\n\n    fn hit_span(&self, _point: Point) -> Option<usize> {\n        None\n    }\n\n    fn span_bounds(&self, _index: usize) -> Vec<Rectangle> {\n        vec![]\n    }\n}\n\nimpl text::Editor for () {\n    type Font = Font;\n\n    fn with_text(_text: &str) -> Self {}\n\n    fn is_empty(&self) -> bool {\n        true\n    }\n\n    fn cursor(&self) -> text::editor::Cursor {\n        text::editor::Cursor {\n            position: text::editor::Position { line: 0, column: 0 },\n            selection: None,\n        }\n    }\n\n    fn selection(&self) -> text::editor::Selection {\n        text::editor::Selection::Caret(Point::ORIGIN)\n    }\n\n    fn copy(&self) -> Option<String> {\n        None\n    }\n\n    fn line(&self, _index: usize) -> Option<text::editor::Line<'_>> {\n        None\n    }\n\n    fn line_count(&self) -> usize {\n        0\n    }\n\n    fn perform(&mut self, _action: text::editor::Action) {}\n\n    fn move_to(&mut self, _cursor: text::editor::Cursor) {}\n\n    fn bounds(&self) -> Size {\n        Size::ZERO\n    }\n\n    fn hint_factor(&self) -> Option<f32> {\n        None\n    }\n\n    fn min_bounds(&self) -> Size {\n        Size::ZERO\n    }\n\n    fn update(\n        &mut self,\n        _new_bounds: Size,\n        _new_font: Self::Font,\n        _new_size: Pixels,\n        _new_line_height: text::LineHeight,\n        _new_wrapping: text::Wrapping,\n        _new_hint_factor: Option<f32>,\n        _new_highlighter: &mut impl text::Highlighter,\n    ) {\n    }\n\n    fn highlight<H: text::Highlighter>(\n        &mut self,\n        _font: Self::Font,\n        _highlighter: &mut H,\n        _format_highlight: impl Fn(&H::Highlight) -> text::highlighter::Format<Self::Font>,\n    ) {\n    }\n}\n\nimpl image::Renderer for () {\n    type Handle = image::Handle;\n\n    fn load_image(&self, handle: &Self::Handle) -> Result<image::Allocation, image::Error> {\n        #[allow(unsafe_code)]\n        Ok(unsafe { image::allocate(handle, Size::new(100, 100)) })\n    }\n\n    fn measure_image(&self, _handle: &Self::Handle) -> Option<Size<u32>> {\n        Some(Size::new(100, 100))\n    }\n\n    fn draw_image(&mut self, _image: Image, _bounds: Rectangle, _clip_bounds: Rectangle) {}\n}\n\nimpl svg::Renderer for () {\n    fn measure_svg(&self, _handle: &svg::Handle) -> Size<u32> {\n        Size::default()\n    }\n\n    fn draw_svg(&mut self, _svg: svg::Svg, _bounds: Rectangle, _clip_bounds: Rectangle) {}\n}\n\nimpl renderer::Headless for () {\n    async fn new(_settings: renderer::Settings, _backend: Option<&str>) -> Option<Self>\n    where\n        Self: Sized,\n    {\n        Some(())\n    }\n\n    fn name(&self) -> String {\n        \"null renderer\".to_owned()\n    }\n\n    fn screenshot(\n        &mut self,\n        _size: Size<u32>,\n        _scale_factor: f32,\n        _background_color: Color,\n    ) -> Vec<u8> {\n        Vec::new()\n    }\n}\n"
  },
  {
    "path": "core/src/renderer.rs",
    "content": "//! Write your own renderer.\n#[cfg(debug_assertions)]\nmod null;\n\nuse crate::image;\nuse crate::{\n    Background, Border, Color, Font, Pixels, Rectangle, Shadow, Size, Transformation, Vector,\n};\n\n/// Whether anti-aliasing should be avoided by snapping primitive coordinates to the\n/// pixel grid.\npub const CRISP: bool = cfg!(feature = \"crisp\");\n\n/// A component that can be used by widgets to draw themselves on a screen.\npub trait Renderer {\n    /// Starts recording a new layer.\n    fn start_layer(&mut self, bounds: Rectangle);\n\n    /// Ends recording a new layer.\n    ///\n    /// The new layer will clip its contents to the provided `bounds`.\n    fn end_layer(&mut self);\n\n    /// Draws the primitives recorded in the given closure in a new layer.\n    ///\n    /// The layer will clip its contents to the provided `bounds`.\n    fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) {\n        self.start_layer(bounds);\n        f(self);\n        self.end_layer();\n    }\n\n    /// Starts recording with a new [`Transformation`].\n    fn start_transformation(&mut self, transformation: Transformation);\n\n    /// Ends recording a new layer.\n    ///\n    /// The new layer will clip its contents to the provided `bounds`.\n    fn end_transformation(&mut self);\n\n    /// Applies a [`Transformation`] to the primitives recorded in the given closure.\n    fn with_transformation(&mut self, transformation: Transformation, f: impl FnOnce(&mut Self)) {\n        self.start_transformation(transformation);\n        f(self);\n        self.end_transformation();\n    }\n\n    /// Applies a translation to the primitives recorded in the given closure.\n    fn with_translation(&mut self, translation: Vector, f: impl FnOnce(&mut Self)) {\n        self.with_transformation(Transformation::translate(translation.x, translation.y), f);\n    }\n\n    /// Fills a [`Quad`] with the provided [`Background`].\n    fn fill_quad(&mut self, quad: Quad, background: impl Into<Background>);\n\n    /// Creates an [`image::Allocation`] for the given [`image::Handle`] and calls the given callback with it.\n    fn allocate_image(\n        &mut self,\n        handle: &image::Handle,\n        callback: impl FnOnce(Result<image::Allocation, image::Error>) + Send + 'static,\n    );\n\n    /// Provides hints to the [`Renderer`] about the rendering target.\n    ///\n    /// This may be used internally by the [`Renderer`] to perform optimizations\n    /// and/or improve rendering quality.\n    ///\n    /// For instance, providing a `scale_factor` may be used by some renderers to\n    /// perform metrics hinting internally in physical coordinates while keeping\n    /// layout coordinates logical and, therefore, maintain linearity.\n    fn hint(&mut self, scale_factor: f32);\n\n    /// Returns the last scale factor provided as a [`hint`](Self::hint).\n    fn scale_factor(&self) -> Option<f32>;\n\n    /// Resets the [`Renderer`] to start drawing in the `new_bounds` from scratch.\n    fn reset(&mut self, new_bounds: Rectangle);\n\n    /// Polls any concurrent computations that may be pending in the [`Renderer`].\n    ///\n    /// By default, it does nothing.\n    fn tick(&mut self) {}\n}\n\n/// A polygon with four sides.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Quad {\n    /// The bounds of the [`Quad`].\n    pub bounds: Rectangle,\n\n    /// The [`Border`] of the [`Quad`]. The border is drawn on the inside of the [`Quad`].\n    pub border: Border,\n\n    /// The [`Shadow`] of the [`Quad`].\n    pub shadow: Shadow,\n\n    /// Whether the [`Quad`] should be snapped to the pixel grid.\n    pub snap: bool,\n}\n\nimpl Default for Quad {\n    fn default() -> Self {\n        Self {\n            bounds: Rectangle::with_size(Size::ZERO),\n            border: Border::default(),\n            shadow: Shadow::default(),\n            snap: CRISP,\n        }\n    }\n}\n\n/// The styling attributes of a [`Renderer`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The text color\n    pub text_color: Color,\n}\n\nimpl Default for Style {\n    fn default() -> Self {\n        Style {\n            text_color: Color::BLACK,\n        }\n    }\n}\n\n/// A headless renderer is a renderer that can render offscreen without\n/// a window nor a compositor.\npub trait Headless {\n    /// Creates a new [`Headless`] renderer;\n    fn new(settings: Settings, backend: Option<&str>) -> impl Future<Output = Option<Self>>\n    where\n        Self: Sized;\n\n    /// Returns the unique name of the renderer.\n    ///\n    /// This name may be used by testing libraries to uniquely identify\n    /// snapshots.\n    fn name(&self) -> String;\n\n    /// Draws offscreen into a screenshot, returning a collection of\n    /// bytes representing the rendered pixels in RGBA order.\n    fn screenshot(\n        &mut self,\n        size: Size<u32>,\n        scale_factor: f32,\n        background_color: Color,\n    ) -> Vec<u8>;\n}\n\n/// The settings of a [`Renderer`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Settings {\n    /// The default [`Font`] to use.\n    pub default_font: Font,\n\n    /// The default size of text.\n    ///\n    /// By default, it will be set to `16.0`.\n    pub default_text_size: Pixels,\n}\n\nimpl Default for Settings {\n    fn default() -> Self {\n        Self {\n            default_font: Font::DEFAULT,\n            default_text_size: Pixels(16.0),\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/rotation.rs",
    "content": "//! Control the rotation of some content (like an image) within a space.\nuse crate::{Degrees, Radians, Size};\n\n/// The strategy used to rotate the content.\n///\n/// This is used to control the behavior of the layout when the content is rotated\n/// by a certain angle.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Rotation {\n    /// The element will float while rotating. The layout will be kept exactly as it was\n    /// before the rotation.\n    ///\n    /// This is especially useful when used for animations, as it will avoid the\n    /// layout being shifted or resized when smoothly i.e. an icon.\n    ///\n    /// This is the default.\n    Floating(Radians),\n    /// The element will be solid while rotating. The layout will be adjusted to fit\n    /// the rotated content.\n    ///\n    /// This allows you to rotate an image and have the layout adjust to fit the new\n    /// size of the image.\n    Solid(Radians),\n}\n\nimpl Rotation {\n    /// Returns the angle of the [`Rotation`] in [`Radians`].\n    pub fn radians(self) -> Radians {\n        match self {\n            Rotation::Floating(radians) | Rotation::Solid(radians) => radians,\n        }\n    }\n\n    /// Returns a mutable reference to the angle of the [`Rotation`] in [`Radians`].\n    pub fn radians_mut(&mut self) -> &mut Radians {\n        match self {\n            Rotation::Floating(radians) | Rotation::Solid(radians) => radians,\n        }\n    }\n\n    /// Returns the angle of the [`Rotation`] in [`Degrees`].\n    pub fn degrees(self) -> Degrees {\n        Degrees(self.radians().0.to_degrees())\n    }\n\n    /// Applies the [`Rotation`] to the given [`Size`], returning\n    /// the minimum [`Size`] containing the rotated one.\n    pub fn apply(self, size: Size) -> Size {\n        match self {\n            Self::Floating(_) => size,\n            Self::Solid(rotation) => size.rotate(rotation),\n        }\n    }\n}\n\nimpl Default for Rotation {\n    fn default() -> Self {\n        Self::Floating(Radians(0.0))\n    }\n}\n\nimpl From<Radians> for Rotation {\n    fn from(radians: Radians) -> Self {\n        Self::Floating(radians)\n    }\n}\n\nimpl From<f32> for Rotation {\n    fn from(radians: f32) -> Self {\n        Self::Floating(Radians(radians))\n    }\n}\n"
  },
  {
    "path": "core/src/settings.rs",
    "content": "//! Configure your application.\nuse crate::renderer;\nuse crate::{Font, Pixels};\n\nuse std::borrow::Cow;\n\n/// The settings of an iced program.\n#[derive(Debug, Clone)]\npub struct Settings {\n    /// The identifier of the application.\n    ///\n    /// If provided, this identifier may be used to identify the application or\n    /// communicate with it through the windowing system.\n    pub id: Option<String>,\n\n    /// The fonts to load on boot.\n    pub fonts: Vec<Cow<'static, [u8]>>,\n\n    /// The default [`Font`] to be used.\n    ///\n    /// By default, it uses [`Family::SansSerif`](crate::font::Family::SansSerif).\n    pub default_font: Font,\n\n    /// The text size that will be used by default.\n    ///\n    /// The default value is `16.0`.\n    pub default_text_size: Pixels,\n\n    /// If set to true, the renderer will try to perform antialiasing for some\n    /// primitives.\n    ///\n    /// Enabling it can produce a smoother result in some widgets, like the\n    /// `canvas` widget, at a performance cost.\n    ///\n    /// By default, it is enabled.\n    pub antialiasing: bool,\n\n    /// Whether or not to attempt to synchronize rendering when possible.\n    ///\n    /// Disabling it can improve rendering performance on some platforms.\n    ///\n    /// By default, it is enabled.\n    pub vsync: bool,\n}\n\nimpl Default for Settings {\n    fn default() -> Self {\n        let renderer = renderer::Settings::default();\n\n        Self {\n            id: None,\n            fonts: Vec::new(),\n            default_font: renderer.default_font,\n            default_text_size: renderer.default_text_size,\n            antialiasing: true,\n            vsync: true,\n        }\n    }\n}\n\nimpl From<&Settings> for renderer::Settings {\n    fn from(settings: &Settings) -> Self {\n        Self {\n            default_font: settings.default_font,\n            default_text_size: settings.default_text_size,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/shadow.rs",
    "content": "use crate::{Color, Vector};\n\n/// A shadow.\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub struct Shadow {\n    /// The color of the shadow.\n    pub color: Color,\n\n    /// The offset of the shadow.\n    pub offset: Vector,\n\n    /// The blur radius of the shadow.\n    pub blur_radius: f32,\n}\n"
  },
  {
    "path": "core/src/shell.rs",
    "content": "use crate::clipboard;\nuse crate::event;\nuse crate::window;\nuse crate::{Clipboard, InputMethod};\n\n/// A connection to the state of a shell.\n///\n/// A [`Widget`] can leverage a [`Shell`] to trigger changes in an application,\n/// like publishing messages or invalidating the current layout.\n///\n/// [`Widget`]: crate::Widget\n#[derive(Debug)]\npub struct Shell<'a, Message> {\n    messages: &'a mut Vec<Message>,\n    event_status: event::Status,\n    redraw_request: window::RedrawRequest,\n    input_method: InputMethod,\n    is_layout_invalid: bool,\n    are_widgets_invalid: bool,\n    clipboard: Clipboard,\n}\n\nimpl<'a, Message> Shell<'a, Message> {\n    /// Creates a new [`Shell`] with the provided buffer of messages.\n    pub fn new(messages: &'a mut Vec<Message>) -> Self {\n        Self {\n            messages,\n            event_status: event::Status::Ignored,\n            redraw_request: window::RedrawRequest::Wait,\n            is_layout_invalid: false,\n            are_widgets_invalid: false,\n            input_method: InputMethod::Disabled,\n            clipboard: Clipboard {\n                reads: Vec::new(),\n                write: None,\n            },\n        }\n    }\n\n    /// Returns true if the [`Shell`] contains no published messages\n    #[must_use]\n    pub fn is_empty(&self) -> bool {\n        self.messages.is_empty()\n    }\n\n    /// Publish the given `Message` for an application to process it.\n    pub fn publish(&mut self, message: Message) {\n        self.messages.push(message);\n    }\n\n    /// Marks the current event as captured. Prevents \"event bubbling\".\n    ///\n    /// A widget should capture an event when no ancestor should\n    /// handle it.\n    pub fn capture_event(&mut self) {\n        self.event_status = event::Status::Captured;\n    }\n\n    /// Returns the current [`event::Status`] of the [`Shell`].\n    #[must_use]\n    pub fn event_status(&self) -> event::Status {\n        self.event_status\n    }\n\n    /// Returns whether the current event has been captured.\n    #[must_use]\n    pub fn is_event_captured(&self) -> bool {\n        self.event_status == event::Status::Captured\n    }\n\n    /// Requests a new frame to be drawn as soon as possible.\n    pub fn request_redraw(&mut self) {\n        self.redraw_request = window::RedrawRequest::NextFrame;\n    }\n\n    /// Requests a new frame to be drawn at the given [`window::RedrawRequest`].\n    pub fn request_redraw_at(&mut self, redraw_request: impl Into<window::RedrawRequest>) {\n        self.redraw_request = self.redraw_request.min(redraw_request.into());\n    }\n\n    /// Returns the request a redraw should happen, if any.\n    #[must_use]\n    pub fn redraw_request(&self) -> window::RedrawRequest {\n        self.redraw_request\n    }\n\n    /// Replaces the redraw request of the [`Shell`]; without conflict resolution.\n    ///\n    /// This is useful if you want to overwrite the redraw request to a previous value.\n    /// Since it's a fairly advanced use case and should rarely be used, it is a static\n    /// method.\n    pub fn replace_redraw_request(shell: &mut Self, redraw_request: window::RedrawRequest) {\n        shell.redraw_request = redraw_request;\n    }\n\n    /// Requests the runtime to read the clipboard contents expecting the given [`clipboard::Kind`].\n    ///\n    /// The runtime will produce a [`clipboard::Event::Read`] when the contents have been read.\n    pub fn read_clipboard(&mut self, kind: clipboard::Kind) {\n        self.clipboard.reads.push(kind);\n    }\n\n    /// Requests the runtime to write the given [`clipboard::Content`] to the clipboard.\n    ///\n    /// The runtime will produce a [`clipboard::Event::Written`] when the contents have been written.\n    pub fn write_clipboard(&mut self, content: clipboard::Content) {\n        self.clipboard.write = Some(content);\n    }\n\n    /// Returns the [`Clipboard`] requests of the [`Shell`], mutably.\n    pub fn clipboard_mut(&mut self) -> &mut Clipboard {\n        &mut self.clipboard\n    }\n\n    /// Requests the current [`InputMethod`] strategy.\n    ///\n    /// __Important__: This request will only be honored by the\n    /// [`Shell`] only during a [`window::Event::RedrawRequested`].\n    pub fn request_input_method<T: AsRef<str>>(&mut self, ime: &InputMethod<T>) {\n        self.input_method.merge(ime);\n    }\n\n    /// Returns the current [`InputMethod`] strategy.\n    #[must_use]\n    pub fn input_method(&self) -> &InputMethod {\n        &self.input_method\n    }\n\n    /// Returns the current [`InputMethod`] strategy.\n    #[must_use]\n    pub fn input_method_mut(&mut self) -> &mut InputMethod {\n        &mut self.input_method\n    }\n\n    /// Returns whether the current layout is invalid or not.\n    #[must_use]\n    pub fn is_layout_invalid(&self) -> bool {\n        self.is_layout_invalid\n    }\n\n    /// Invalidates the current application layout.\n    ///\n    /// The shell will relayout the application widgets.\n    pub fn invalidate_layout(&mut self) {\n        self.is_layout_invalid = true;\n    }\n\n    /// Triggers the given function if the layout is invalid, cleaning it in the\n    /// process.\n    pub fn revalidate_layout(&mut self, f: impl FnOnce()) {\n        if self.is_layout_invalid {\n            self.is_layout_invalid = false;\n\n            f();\n        }\n    }\n\n    /// Returns whether the widgets of the current application have been\n    /// invalidated.\n    #[must_use]\n    pub fn are_widgets_invalid(&self) -> bool {\n        self.are_widgets_invalid\n    }\n\n    /// Invalidates the current application widgets.\n    ///\n    /// The shell will rebuild and relayout the widget tree.\n    pub fn invalidate_widgets(&mut self) {\n        self.are_widgets_invalid = true;\n    }\n\n    /// Merges the current [`Shell`] with another one by applying the given\n    /// function to the messages of the latter.\n    ///\n    /// This method is useful for composition.\n    pub fn merge<B>(&mut self, mut other: Shell<'_, B>, f: impl Fn(B) -> Message) {\n        self.messages.extend(other.messages.drain(..).map(f));\n\n        self.is_layout_invalid = self.is_layout_invalid || other.is_layout_invalid;\n        self.are_widgets_invalid = self.are_widgets_invalid || other.are_widgets_invalid;\n        self.redraw_request = self.redraw_request.min(other.redraw_request);\n        self.event_status = self.event_status.merge(other.event_status);\n\n        self.input_method.merge(&other.input_method);\n        self.clipboard.merge(&mut other.clipboard);\n    }\n}\n"
  },
  {
    "path": "core/src/size.rs",
    "content": "use crate::{Length, Radians, Vector};\n\n/// An amount of space in 2 dimensions.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub struct Size<T = f32> {\n    /// The width.\n    pub width: T,\n    /// The height.\n    pub height: T,\n}\n\nimpl<T> Size<T> {\n    /// Creates a new  [`Size`] with the given width and height.\n    pub const fn new(width: T, height: T) -> Self {\n        Size { width, height }\n    }\n}\n\nimpl Size {\n    /// A [`Size`] with zero width and height.\n    pub const ZERO: Size = Size::new(0., 0.);\n\n    /// A [`Size`] with a width and height of 1 unit.\n    pub const UNIT: Size = Size::new(1., 1.);\n\n    /// A [`Size`] with infinite width and height.\n    pub const INFINITE: Size = Size::new(f32::INFINITY, f32::INFINITY);\n\n    /// Returns the minimum of each component of this size and another.\n    pub fn min(self, other: Self) -> Self {\n        Size {\n            width: self.width.min(other.width),\n            height: self.height.min(other.height),\n        }\n    }\n\n    /// Returns the maximum of each component of this size and another.\n    pub fn max(self, other: Self) -> Self {\n        Size {\n            width: self.width.max(other.width),\n            height: self.height.max(other.height),\n        }\n    }\n\n    /// Expands this [`Size`] by the given amount.\n    pub fn expand(self, other: impl Into<Size>) -> Self {\n        let other = other.into();\n\n        Size {\n            width: self.width + other.width,\n            height: self.height + other.height,\n        }\n    }\n\n    /// Rotates this [`Size`] and returns the minimum [`Size`]\n    /// containing it.\n    pub fn rotate(self, rotation: Radians) -> Size {\n        let radians = f32::from(rotation);\n\n        Size {\n            width: (self.width * radians.cos()).abs() + (self.height * radians.sin()).abs(),\n            height: (self.width * radians.sin()).abs() + (self.height * radians.cos()).abs(),\n        }\n    }\n\n    /// Applies an aspect ratio to this [`Size`] without\n    /// exceeding its bounds.\n    pub const fn ratio(self, aspect_ratio: f32) -> Size {\n        Size {\n            width: (self.height * aspect_ratio).min(self.width),\n            height: (self.width / aspect_ratio).min(self.height),\n        }\n    }\n}\n\nimpl Size<Length> {\n    /// Returns true if either `width` or `height` are 0-sized.\n    #[inline]\n    pub fn is_void(&self) -> bool {\n        matches!(self.width, Length::Fixed(0.0)) || matches!(self.height, Length::Fixed(0.0))\n    }\n}\n\nimpl<T> From<[T; 2]> for Size<T> {\n    fn from([width, height]: [T; 2]) -> Self {\n        Size { width, height }\n    }\n}\n\nimpl<T> From<(T, T)> for Size<T> {\n    fn from((width, height): (T, T)) -> Self {\n        Self { width, height }\n    }\n}\n\nimpl From<(u32, u32)> for Size {\n    fn from((width, height): (u32, u32)) -> Self {\n        Size::new(width as f32, height as f32)\n    }\n}\n\nimpl<T> From<Vector<T>> for Size<T> {\n    fn from(vector: Vector<T>) -> Self {\n        Size {\n            width: vector.x,\n            height: vector.y,\n        }\n    }\n}\n\nimpl<T> From<Size<T>> for [T; 2] {\n    fn from(size: Size<T>) -> Self {\n        [size.width, size.height]\n    }\n}\n\nimpl<T> From<Size<T>> for Vector<T> {\n    fn from(size: Size<T>) -> Self {\n        Vector::new(size.width, size.height)\n    }\n}\n\nimpl<T> std::ops::Add for Size<T>\nwhere\n    T: std::ops::Add<Output = T>,\n{\n    type Output = Size<T>;\n\n    fn add(self, rhs: Self) -> Self::Output {\n        Size {\n            width: self.width + rhs.width,\n            height: self.height + rhs.height,\n        }\n    }\n}\n\nimpl<T> std::ops::Sub for Size<T>\nwhere\n    T: std::ops::Sub<Output = T>,\n{\n    type Output = Size<T>;\n\n    fn sub(self, rhs: Self) -> Self::Output {\n        Size {\n            width: self.width - rhs.width,\n            height: self.height - rhs.height,\n        }\n    }\n}\n\nimpl<T> std::ops::Mul<T> for Size<T>\nwhere\n    T: std::ops::Mul<Output = T> + Copy,\n{\n    type Output = Size<T>;\n\n    fn mul(self, rhs: T) -> Self::Output {\n        Size {\n            width: self.width * rhs,\n            height: self.height * rhs,\n        }\n    }\n}\n\nimpl<T> std::ops::Div<T> for Size<T>\nwhere\n    T: std::ops::Div<Output = T> + Copy,\n{\n    type Output = Size<T>;\n\n    fn div(self, rhs: T) -> Self::Output {\n        Size {\n            width: self.width / rhs,\n            height: self.height / rhs,\n        }\n    }\n}\n\nimpl<T> std::ops::Mul<Vector<T>> for Size<T>\nwhere\n    T: std::ops::Mul<Output = T> + Copy,\n{\n    type Output = Size<T>;\n\n    fn mul(self, scale: Vector<T>) -> Self::Output {\n        Size {\n            width: self.width * scale.x,\n            height: self.height * scale.y,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/svg.rs",
    "content": "//! Load and draw vector graphics.\nuse crate::{Color, Radians, Rectangle, Size};\n\nuse rustc_hash::FxHasher;\nuse std::borrow::Cow;\nuse std::hash::{Hash, Hasher as _};\nuse std::path::PathBuf;\nuse std::sync::Arc;\n\n/// A raster image that can be drawn.\n#[derive(Debug, Clone, PartialEq)]\npub struct Svg<H = Handle> {\n    /// The handle of the [`Svg`].\n    pub handle: H,\n\n    /// The [`Color`] filter to be applied to the [`Svg`].\n    ///\n    /// If some [`Color`] is set, the whole [`Svg`] will be\n    /// painted with it—ignoring any intrinsic colors.\n    ///\n    /// This can be useful for coloring icons programmatically\n    /// (e.g. with a theme).\n    pub color: Option<Color>,\n\n    /// The rotation to be applied to the image; on its center.\n    pub rotation: Radians,\n\n    /// The opacity of the [`Svg`].\n    ///\n    /// 0 means transparent. 1 means opaque.\n    pub opacity: f32,\n}\n\nimpl Svg<Handle> {\n    /// Creates a new [`Svg`] with the given handle.\n    pub fn new(handle: impl Into<Handle>) -> Self {\n        Self {\n            handle: handle.into(),\n            color: None,\n            rotation: Radians(0.0),\n            opacity: 1.0,\n        }\n    }\n\n    /// Sets the [`Color`] filter of the [`Svg`].\n    pub fn color(mut self, color: impl Into<Color>) -> Self {\n        self.color = Some(color.into());\n        self\n    }\n\n    /// Sets the rotation of the [`Svg`].\n    pub fn rotation(mut self, rotation: impl Into<Radians>) -> Self {\n        self.rotation = rotation.into();\n        self\n    }\n\n    /// Sets the opacity of the [`Svg`].\n    pub fn opacity(mut self, opacity: impl Into<f32>) -> Self {\n        self.opacity = opacity.into();\n        self\n    }\n}\n\nimpl From<&Handle> for Svg {\n    fn from(handle: &Handle) -> Self {\n        Svg::new(handle.clone())\n    }\n}\n\n/// A handle of Svg data.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Handle {\n    id: u64,\n    data: Arc<Data>,\n}\n\nimpl Handle {\n    /// Creates an SVG [`Handle`] pointing to the vector image of the given\n    /// path.\n    pub fn from_path(path: impl Into<PathBuf>) -> Handle {\n        Self::from_data(Data::Path(path.into()))\n    }\n\n    /// Creates an SVG [`Handle`] from raw bytes containing either an SVG string\n    /// or gzip compressed data.\n    ///\n    /// This is useful if you already have your SVG data in-memory, maybe\n    /// because you downloaded or generated it procedurally.\n    pub fn from_memory(bytes: impl Into<Cow<'static, [u8]>>) -> Handle {\n        Self::from_data(Data::Bytes(bytes.into()))\n    }\n\n    fn from_data(data: Data) -> Handle {\n        let mut hasher = FxHasher::default();\n        data.hash(&mut hasher);\n\n        Handle {\n            id: hasher.finish(),\n            data: Arc::new(data),\n        }\n    }\n\n    /// Returns the unique identifier of the [`Handle`].\n    pub fn id(&self) -> u64 {\n        self.id\n    }\n\n    /// Returns a reference to the SVG [`Data`].\n    pub fn data(&self) -> &Data {\n        &self.data\n    }\n}\n\nimpl<T> From<T> for Handle\nwhere\n    T: Into<PathBuf>,\n{\n    fn from(path: T) -> Handle {\n        Handle::from_path(path.into())\n    }\n}\n\nimpl Hash for Handle {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.id.hash(state);\n    }\n}\n\n/// The data of a vectorial image.\n#[derive(Clone, Hash, PartialEq, Eq)]\npub enum Data {\n    /// File data\n    Path(PathBuf),\n\n    /// In-memory data\n    ///\n    /// Can contain an SVG string or a gzip compressed data.\n    Bytes(Cow<'static, [u8]>),\n}\n\nimpl std::fmt::Debug for Data {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Data::Path(path) => write!(f, \"Path({path:?})\"),\n            Data::Bytes(_) => write!(f, \"Bytes(...)\"),\n        }\n    }\n}\n\n/// A [`Renderer`] that can render vector graphics.\n///\n/// [renderer]: crate::renderer\npub trait Renderer: crate::Renderer {\n    /// Returns the default dimensions of an SVG for the given [`Handle`].\n    fn measure_svg(&self, handle: &Handle) -> Size<u32>;\n\n    /// Draws an SVG with the given [`Handle`], an optional [`Color`] filter, and inside the provided `bounds`.\n    fn draw_svg(&mut self, svg: Svg, bounds: Rectangle, clip_bounds: Rectangle);\n}\n"
  },
  {
    "path": "core/src/text/editor.rs",
    "content": "//! Edit text.\nuse crate::text::highlighter::{self, Highlighter};\nuse crate::text::{LineHeight, Wrapping};\nuse crate::{Pixels, Point, Rectangle, Size};\n\nuse std::borrow::Cow;\nuse std::sync::Arc;\n\n/// A component that can be used by widgets to edit multi-line text.\npub trait Editor: Sized + Default {\n    /// The font of the [`Editor`].\n    type Font: Copy + PartialEq + Default;\n\n    /// Creates a new [`Editor`] laid out with the given text.\n    fn with_text(text: &str) -> Self;\n\n    /// Returns true if the [`Editor`] has no contents.\n    fn is_empty(&self) -> bool;\n\n    /// Returns the current [`Cursor`] of the [`Editor`].\n    fn cursor(&self) -> Cursor;\n\n    /// Returns the current [`Selection`] of the [`Editor`].\n    fn selection(&self) -> Selection;\n\n    /// Returns the current selected text of the [`Editor`].\n    fn copy(&self) -> Option<String>;\n\n    /// Returns the text of the given line in the [`Editor`], if it exists.\n    fn line(&self, index: usize) -> Option<Line<'_>>;\n\n    /// Returns the amount of lines in the [`Editor`].\n    fn line_count(&self) -> usize;\n\n    /// Performs an [`Action`] on the [`Editor`].\n    fn perform(&mut self, action: Action);\n\n    /// Moves the cursor to the given position.\n    fn move_to(&mut self, cursor: Cursor);\n\n    /// Returns the current boundaries of the [`Editor`].\n    fn bounds(&self) -> Size;\n\n    /// Returns the minimum boundaries to fit the current contents of\n    /// the [`Editor`].\n    fn min_bounds(&self) -> Size;\n\n    /// Returns the hint factor of the [`Editor`].\n    fn hint_factor(&self) -> Option<f32>;\n\n    /// Updates the [`Editor`] with some new attributes.\n    fn update(\n        &mut self,\n        new_bounds: Size,\n        new_font: Self::Font,\n        new_size: Pixels,\n        new_line_height: LineHeight,\n        new_wrapping: Wrapping,\n        new_hint_factor: Option<f32>,\n        new_highlighter: &mut impl Highlighter,\n    );\n\n    /// Runs a text [`Highlighter`] in the [`Editor`].\n    fn highlight<H: Highlighter>(\n        &mut self,\n        font: Self::Font,\n        highlighter: &mut H,\n        format_highlight: impl Fn(&H::Highlight) -> highlighter::Format<Self::Font>,\n    );\n}\n\n/// An interaction with an [`Editor`].\n#[derive(Debug, Clone, PartialEq)]\npub enum Action {\n    /// Apply a [`Motion`].\n    Move(Motion),\n    /// Select text with a given [`Motion`].\n    Select(Motion),\n    /// Select the word at the current cursor.\n    SelectWord,\n    /// Select the line at the current cursor.\n    SelectLine,\n    /// Select the entire buffer.\n    SelectAll,\n    /// Perform an [`Edit`].\n    Edit(Edit),\n    /// Click the [`Editor`] at the given [`Point`].\n    Click(Point),\n    /// Drag the mouse on the [`Editor`] to the given [`Point`].\n    Drag(Point),\n    /// Scroll the [`Editor`] a certain amount of lines.\n    Scroll {\n        /// The amount of lines to scroll.\n        lines: i32,\n    },\n}\n\nimpl Action {\n    /// Returns whether the [`Action`] is an editing action.\n    pub fn is_edit(&self) -> bool {\n        matches!(self, Self::Edit(_))\n    }\n}\n\n/// An action that edits text.\n#[derive(Debug, Clone, PartialEq)]\npub enum Edit {\n    /// Insert the given character.\n    Insert(char),\n    /// Paste the given text.\n    Paste(Arc<String>),\n    /// Break the current line.\n    Enter,\n    /// Indent the current line.\n    Indent,\n    /// Unindent the current line.\n    Unindent,\n    /// Delete the previous character.\n    Backspace,\n    /// Delete the next character.\n    Delete,\n}\n\n/// A cursor movement.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Motion {\n    /// Move left.\n    Left,\n    /// Move right.\n    Right,\n    /// Move up.\n    Up,\n    /// Move down.\n    Down,\n    /// Move to the left boundary of a word.\n    WordLeft,\n    /// Move to the right boundary of a word.\n    WordRight,\n    /// Move to the start of the line.\n    Home,\n    /// Move to the end of the line.\n    End,\n    /// Move to the start of the previous window.\n    PageUp,\n    /// Move to the start of the next window.\n    PageDown,\n    /// Move to the start of the text.\n    DocumentStart,\n    /// Move to the end of the text.\n    DocumentEnd,\n}\n\nimpl Motion {\n    /// Widens the [`Motion`], if possible.\n    pub fn widen(self) -> Self {\n        match self {\n            Self::Left => Self::WordLeft,\n            Self::Right => Self::WordRight,\n            Self::Home => Self::DocumentStart,\n            Self::End => Self::DocumentEnd,\n            _ => self,\n        }\n    }\n\n    /// Returns the [`Direction`] of the [`Motion`].\n    pub fn direction(&self) -> Direction {\n        match self {\n            Self::Left\n            | Self::Up\n            | Self::WordLeft\n            | Self::Home\n            | Self::PageUp\n            | Self::DocumentStart => Direction::Left,\n            Self::Right\n            | Self::Down\n            | Self::WordRight\n            | Self::End\n            | Self::PageDown\n            | Self::DocumentEnd => Direction::Right,\n        }\n    }\n}\n\n/// A direction in some text.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Direction {\n    /// <-\n    Left,\n    /// ->\n    Right,\n}\n\n/// The cursor of an [`Editor`].\n#[derive(Debug, Clone)]\npub enum Selection {\n    /// Cursor without a selection\n    Caret(Point),\n\n    /// Cursor selecting a range of text\n    Range(Vec<Rectangle>),\n}\n\n/// The range of an [`Editor`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Cursor {\n    /// The cursor position.\n    pub position: Position,\n\n    /// The selection position, if any.\n    pub selection: Option<Position>,\n}\n\n/// A cursor position in an [`Editor`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Position {\n    /// The line of text.\n    pub line: usize,\n    /// The column in the line.\n    pub column: usize,\n}\n\n/// A line of an [`Editor`].\n#[derive(Clone, Debug, Default, Eq, PartialEq)]\npub struct Line<'a> {\n    /// The raw text of the [`Line`].\n    pub text: Cow<'a, str>,\n    /// The line ending of the [`Line`].\n    pub ending: LineEnding,\n}\n\n/// The line ending of a [`Line`].\n#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]\npub enum LineEnding {\n    /// Use `\\n` for line ending (POSIX-style)\n    #[default]\n    Lf,\n    /// Use `\\r\\n` for line ending (Windows-style)\n    CrLf,\n    /// Use `\\r` for line ending (many legacy systems)\n    Cr,\n    /// Use `\\n\\r` for line ending (some legacy systems)\n    LfCr,\n    /// No line ending\n    None,\n}\n\nimpl LineEnding {\n    /// Gets the string representation of the [`LineEnding`].\n    pub fn as_str(self) -> &'static str {\n        match self {\n            Self::Lf => \"\\n\",\n            Self::CrLf => \"\\r\\n\",\n            Self::Cr => \"\\r\",\n            Self::LfCr => \"\\n\\r\",\n            Self::None => \"\",\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/text/highlighter.rs",
    "content": "//! Highlight text.\nuse crate::Color;\n\nuse std::ops::Range;\n\n/// A type capable of highlighting text.\n///\n/// A [`Highlighter`] highlights lines in sequence. When a line changes,\n/// it must be notified and the lines after the changed one must be fed\n/// again to the [`Highlighter`].\npub trait Highlighter: 'static {\n    /// The settings to configure the [`Highlighter`].\n    type Settings: PartialEq + Clone;\n\n    /// The output of the [`Highlighter`].\n    type Highlight;\n\n    /// The highlight iterator type.\n    type Iterator<'a>: Iterator<Item = (Range<usize>, Self::Highlight)>\n    where\n        Self: 'a;\n\n    /// Creates a new [`Highlighter`] from its [`Self::Settings`].\n    fn new(settings: &Self::Settings) -> Self;\n\n    /// Updates the [`Highlighter`] with some new [`Self::Settings`].\n    fn update(&mut self, new_settings: &Self::Settings);\n\n    /// Notifies the [`Highlighter`] that the line at the given index has changed.\n    fn change_line(&mut self, line: usize);\n\n    /// Highlights the given line.\n    ///\n    /// If a line changed prior to this, the first line provided here will be the\n    /// line that changed.\n    fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_>;\n\n    /// Returns the current line of the [`Highlighter`].\n    ///\n    /// If `change_line` has been called, this will normally be the least index\n    /// that changed.\n    fn current_line(&self) -> usize;\n}\n\n/// A highlighter that highlights nothing.\n#[derive(Debug, Clone, Copy)]\npub struct PlainText;\n\nimpl Highlighter for PlainText {\n    type Settings = ();\n    type Highlight = ();\n\n    type Iterator<'a> = std::iter::Empty<(Range<usize>, Self::Highlight)>;\n\n    fn new(_settings: &Self::Settings) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _new_settings: &Self::Settings) {}\n\n    fn change_line(&mut self, _line: usize) {}\n\n    fn highlight_line(&mut self, _line: &str) -> Self::Iterator<'_> {\n        std::iter::empty()\n    }\n\n    fn current_line(&self) -> usize {\n        usize::MAX\n    }\n}\n\n/// The format of some text.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Format<Font> {\n    /// The [`Color`] of the text.\n    pub color: Option<Color>,\n    /// The `Font` of the text.\n    pub font: Option<Font>,\n}\n\nimpl<Font> Default for Format<Font> {\n    fn default() -> Self {\n        Self {\n            color: None,\n            font: None,\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/text/paragraph.rs",
    "content": "//! Draw paragraphs.\nuse crate::alignment;\nuse crate::text::{\n    Alignment, Difference, Ellipsis, Hit, LineHeight, Shaping, Span, Text, Wrapping,\n};\nuse crate::{Pixels, Point, Rectangle, Size};\n\n/// A text paragraph.\npub trait Paragraph: Sized + Default {\n    /// The font of this [`Paragraph`].\n    type Font: Copy + PartialEq;\n\n    /// Creates a new [`Paragraph`] laid out with the given [`Text`].\n    fn with_text(text: Text<&str, Self::Font>) -> Self;\n\n    /// Creates a new [`Paragraph`] laid out with the given [`Text`].\n    fn with_spans<Link>(text: Text<&[Span<'_, Link, Self::Font>], Self::Font>) -> Self;\n\n    /// Lays out the [`Paragraph`] with some new boundaries.\n    fn resize(&mut self, new_bounds: Size);\n\n    /// Compares the [`Paragraph`] with some desired [`Text`] and returns the\n    /// [`Difference`].\n    fn compare(&self, text: Text<(), Self::Font>) -> Difference;\n\n    /// Returns the text size of the [`Paragraph`] in [`Pixels`].\n    fn size(&self) -> Pixels;\n\n    /// Returns the hint factor of the [`Paragraph`].\n    fn hint_factor(&self) -> Option<f32>;\n\n    /// Returns the font of the [`Paragraph`].\n    fn font(&self) -> Self::Font;\n\n    /// Returns the [`LineHeight`] of the [`Paragraph`].\n    fn line_height(&self) -> LineHeight;\n\n    /// Returns the horizontal alignment of the [`Paragraph`].\n    fn align_x(&self) -> Alignment;\n\n    /// Returns the vertical alignment of the [`Paragraph`].\n    fn align_y(&self) -> alignment::Vertical;\n\n    /// Returns the [`Wrapping`] strategy of the [`Paragraph`]>\n    fn wrapping(&self) -> Wrapping;\n\n    /// Returns the [`Ellipsis`] strategy of the [`Paragraph`]>\n    fn ellipsis(&self) -> Ellipsis;\n\n    /// Returns the [`Shaping`] strategy of the [`Paragraph`]>\n    fn shaping(&self) -> Shaping;\n\n    /// Returns the available bounds used to layout the [`Paragraph`].\n    fn bounds(&self) -> Size;\n\n    /// Returns the minimum boundaries that can fit the contents of the\n    /// [`Paragraph`].\n    fn min_bounds(&self) -> Size;\n\n    /// Tests whether the provided point is within the boundaries of the\n    /// [`Paragraph`], returning information about the nearest character.\n    fn hit_test(&self, point: Point) -> Option<Hit>;\n\n    /// Tests whether the provided point is within the boundaries of a\n    /// [`Span`] in the [`Paragraph`], returning the index of the [`Span`]\n    /// that was hit.\n    fn hit_span(&self, point: Point) -> Option<usize>;\n\n    /// Returns all bounds for the provided [`Span`] index of the [`Paragraph`].\n    /// A [`Span`] can have multiple bounds for each line it's on.\n    fn span_bounds(&self, index: usize) -> Vec<Rectangle>;\n\n    /// Returns the distance to the given grapheme index in the [`Paragraph`].\n    fn grapheme_position(&self, line: usize, index: usize) -> Option<Point>;\n\n    /// Returns the minimum width that can fit the contents of the [`Paragraph`].\n    fn min_width(&self) -> f32 {\n        self.min_bounds().width\n    }\n\n    /// Returns the minimum height that can fit the contents of the [`Paragraph`].\n    fn min_height(&self) -> f32 {\n        self.min_bounds().height\n    }\n}\n\n/// A [`Paragraph`] of plain text.\n#[derive(Debug, Clone, Default)]\npub struct Plain<P: Paragraph> {\n    raw: P,\n    content: String,\n}\n\nimpl<P: Paragraph> Plain<P> {\n    /// Creates a new [`Plain`] paragraph.\n    pub fn new(text: Text<String, P::Font>) -> Self {\n        Self {\n            raw: P::with_text(text.as_ref()),\n            content: text.content,\n        }\n    }\n\n    /// Updates the plain [`Paragraph`] to match the given [`Text`], if needed.\n    ///\n    /// Returns true if the [`Paragraph`] changed.\n    pub fn update(&mut self, text: Text<&str, P::Font>) -> bool {\n        if self.content != text.content {\n            text.content.clone_into(&mut self.content);\n            self.raw = P::with_text(text);\n            return true;\n        }\n\n        match self.raw.compare(text.with_content(())) {\n            Difference::None => false,\n            Difference::Bounds => {\n                self.raw.resize(text.bounds);\n                true\n            }\n            Difference::Shape => {\n                self.raw = P::with_text(text);\n                true\n            }\n        }\n    }\n\n    /// Returns the horizontal alignment of the [`Paragraph`].\n    pub fn align_x(&self) -> Alignment {\n        self.raw.align_x()\n    }\n\n    /// Returns the vertical alignment of the [`Paragraph`].\n    pub fn align_y(&self) -> alignment::Vertical {\n        self.raw.align_y()\n    }\n\n    /// Returns the minimum boundaries that can fit the contents of the\n    /// [`Paragraph`].\n    pub fn min_bounds(&self) -> Size {\n        self.raw.min_bounds()\n    }\n\n    /// Returns the minimum width that can fit the contents of the\n    /// [`Paragraph`].\n    pub fn min_width(&self) -> f32 {\n        self.raw.min_width()\n    }\n\n    /// Returns the minimum height that can fit the contents of the\n    /// [`Paragraph`].\n    pub fn min_height(&self) -> f32 {\n        self.raw.min_height()\n    }\n\n    /// Returns the cached [`Paragraph`].\n    pub fn raw(&self) -> &P {\n        &self.raw\n    }\n\n    /// Returns the current content of the plain [`Paragraph`].\n    pub fn content(&self) -> &str {\n        &self.content\n    }\n\n    /// Returns the [`Paragraph`] as a [`Text`] definition.\n    pub fn as_text(&self) -> Text<&str, P::Font> {\n        Text {\n            content: &self.content,\n            bounds: self.raw.bounds(),\n            size: self.raw.size(),\n            line_height: self.raw.line_height(),\n            font: self.raw.font(),\n            align_x: self.raw.align_x(),\n            align_y: self.raw.align_y(),\n            shaping: self.raw.shaping(),\n            wrapping: self.raw.wrapping(),\n            ellipsis: self.raw.ellipsis(),\n            hint_factor: self.raw.hint_factor(),\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/text.rs",
    "content": "//! Draw and interact with text.\npub mod editor;\npub mod highlighter;\npub mod paragraph;\n\npub use editor::Editor;\npub use highlighter::Highlighter;\npub use paragraph::Paragraph;\n\nuse crate::alignment;\nuse crate::{Background, Border, Color, Padding, Pixels, Point, Rectangle, Size};\n\nuse std::borrow::Cow;\nuse std::hash::{Hash, Hasher};\n\n/// A paragraph.\n#[derive(Debug, Clone, Copy)]\npub struct Text<Content = String, Font = crate::Font> {\n    /// The content of the paragraph.\n    pub content: Content,\n\n    /// The bounds of the paragraph.\n    pub bounds: Size,\n\n    /// The size of the [`Text`] in logical pixels.\n    pub size: Pixels,\n\n    /// The line height of the [`Text`].\n    pub line_height: LineHeight,\n\n    /// The font of the [`Text`].\n    pub font: Font,\n\n    /// The horizontal alignment of the [`Text`].\n    pub align_x: Alignment,\n\n    /// The vertical alignment of the [`Text`].\n    pub align_y: alignment::Vertical,\n\n    /// The [`Shaping`] strategy of the [`Text`].\n    pub shaping: Shaping,\n\n    /// The [`Wrapping`] strategy of the [`Text`].\n    pub wrapping: Wrapping,\n\n    /// The [`Ellipsis`] strategy of the [`Text`].\n    pub ellipsis: Ellipsis,\n\n    /// The scale factor that may be used to internally scale the layout\n    /// calculation of the [`Paragraph`] and leverage metrics hinting.\n    ///\n    /// Effectively, this defines the \"base\" layout that will be used for\n    /// linear scaling.\n    ///\n    /// If `None`, hinting will be disabled and subpixel positioning will be\n    /// performed.\n    pub hint_factor: Option<f32>,\n}\n\nimpl<Content, Font> Text<Content, Font>\nwhere\n    Font: Copy,\n{\n    /// Returns a new [`Text`] replacing only the content with the\n    /// given value.\n    pub fn with_content<T>(&self, content: T) -> Text<T, Font> {\n        Text {\n            content,\n            bounds: self.bounds,\n            size: self.size,\n            line_height: self.line_height,\n            font: self.font,\n            align_x: self.align_x,\n            align_y: self.align_y,\n            shaping: self.shaping,\n            wrapping: self.wrapping,\n            ellipsis: self.ellipsis,\n            hint_factor: self.hint_factor,\n        }\n    }\n}\n\nimpl<Content, Font> Text<Content, Font>\nwhere\n    Content: AsRef<str>,\n    Font: Copy,\n{\n    /// Returns a borrowed version of [`Text`].\n    pub fn as_ref(&self) -> Text<&str, Font> {\n        self.with_content(self.content.as_ref())\n    }\n}\n\n/// The alignment of some text.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub enum Alignment {\n    /// No specific alignment.\n    ///\n    /// Left-to-right text will be aligned to the left, while\n    /// right-to-left text will be aligned to the right.\n    #[default]\n    Default,\n    /// Align text to the left.\n    Left,\n    /// Center text.\n    Center,\n    /// Align text to the right.\n    Right,\n    /// Justify text.\n    Justified,\n}\n\nimpl From<alignment::Horizontal> for Alignment {\n    fn from(alignment: alignment::Horizontal) -> Self {\n        match alignment {\n            alignment::Horizontal::Left => Self::Left,\n            alignment::Horizontal::Center => Self::Center,\n            alignment::Horizontal::Right => Self::Right,\n        }\n    }\n}\n\nimpl From<crate::Alignment> for Alignment {\n    fn from(alignment: crate::Alignment) -> Self {\n        match alignment {\n            crate::Alignment::Start => Self::Left,\n            crate::Alignment::Center => Self::Center,\n            crate::Alignment::End => Self::Right,\n        }\n    }\n}\n\nimpl From<Alignment> for alignment::Horizontal {\n    fn from(alignment: Alignment) -> Self {\n        match alignment {\n            Alignment::Default | Alignment::Left | Alignment::Justified => {\n                alignment::Horizontal::Left\n            }\n            Alignment::Center => alignment::Horizontal::Center,\n            Alignment::Right => alignment::Horizontal::Right,\n        }\n    }\n}\n\n/// The shaping strategy of some text.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum Shaping {\n    /// Auto-detect the best shaping strategy from the text.\n    ///\n    /// This strategy will use [`Basic`](Self::Basic) shaping if the\n    /// text consists of only ASCII characters; otherwise, it will\n    /// use [`Advanced`](Self::Advanced) shaping.\n    ///\n    /// This is the default, if neither the `basic-shaping` nor `advanced-shaping`\n    /// features are enabled.\n    Auto,\n    /// No shaping and no font fallback.\n    ///\n    /// This shaping strategy is very cheap, but it will not display complex\n    /// scripts properly nor try to find missing glyphs in your system fonts.\n    ///\n    /// You should use this strategy when you have complete control of the text\n    /// and the font you are displaying in your application.\n    ///\n    /// This will be the default if the `basic-shaping` feature is enabled and\n    /// the `advanced-shaping` feature is disabled.\n    Basic,\n    /// Advanced text shaping and font fallback.\n    ///\n    /// You will need to enable this flag if the text contains a complex\n    /// script, the font used needs it, and/or multiple fonts in your system\n    /// may be needed to display all of the glyphs.\n    ///\n    /// Advanced shaping is expensive! You should only enable it when necessary.\n    ///\n    /// This will be the default if the `advanced-shaping` feature is enabled.\n    Advanced,\n}\n\nimpl Default for Shaping {\n    fn default() -> Self {\n        if cfg!(feature = \"advanced-shaping\") {\n            Self::Advanced\n        } else if cfg!(feature = \"basic-shaping\") {\n            Self::Basic\n        } else {\n            Self::Auto\n        }\n    }\n}\n\n/// The wrapping strategy of some text.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\npub enum Wrapping {\n    /// No wrapping.\n    None,\n    /// Wraps at the word level.\n    ///\n    /// This is the default.\n    #[default]\n    Word,\n    /// Wraps at the glyph level.\n    Glyph,\n    /// Wraps at the word level, or fallback to glyph level if a word can't fit on a line by itself.\n    WordOrGlyph,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\n/// The ellipsis strategy of some text.\npub enum Ellipsis {\n    /// No ellipsis.\n    ///\n    /// This is the default.\n    #[default]\n    None,\n    /// Ellipsize the start of the last visual line in the text.\n    Start,\n    /// Ellipsize the middle of the last visual line in the text.\n    Middle,\n    /// Ellipsize the end of the last visual line in the text.\n    End,\n}\n\n/// The height of a line of text in a paragraph.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum LineHeight {\n    /// A factor of the size of the text.\n    Relative(f32),\n\n    /// An absolute height in logical pixels.\n    Absolute(Pixels),\n}\n\nimpl LineHeight {\n    /// Returns the [`LineHeight`] in absolute logical pixels.\n    pub fn to_absolute(self, text_size: Pixels) -> Pixels {\n        match self {\n            Self::Relative(factor) => Pixels(factor * text_size.0),\n            Self::Absolute(pixels) => pixels,\n        }\n    }\n}\n\nimpl Default for LineHeight {\n    fn default() -> Self {\n        Self::Relative(1.3)\n    }\n}\n\nimpl From<f32> for LineHeight {\n    fn from(factor: f32) -> Self {\n        Self::Relative(factor)\n    }\n}\n\nimpl From<Pixels> for LineHeight {\n    fn from(pixels: Pixels) -> Self {\n        Self::Absolute(pixels)\n    }\n}\n\nimpl Hash for LineHeight {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        match self {\n            Self::Relative(factor) => {\n                state.write_u8(0);\n                factor.to_bits().hash(state);\n            }\n            Self::Absolute(pixels) => {\n                state.write_u8(1);\n                f32::from(*pixels).to_bits().hash(state);\n            }\n        }\n    }\n}\n\n/// The result of hit testing on text.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Hit {\n    /// The point was within the bounds of the returned character index.\n    CharOffset(usize),\n}\n\nimpl Hit {\n    /// Computes the cursor position of the [`Hit`] .\n    pub fn cursor(self) -> usize {\n        match self {\n            Self::CharOffset(i) => i,\n        }\n    }\n}\n\n/// The difference detected in some text.\n///\n/// You will obtain a [`Difference`] when you [`compare`] a [`Paragraph`] with some\n/// [`Text`].\n///\n/// [`compare`]: Paragraph::compare\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Difference {\n    /// No difference.\n    ///\n    /// The text can be reused as it is!\n    None,\n\n    /// A bounds difference.\n    ///\n    /// This normally means a relayout is necessary, but the shape of the text can\n    /// be reused.\n    Bounds,\n\n    /// A shape difference.\n    ///\n    /// The contents, alignment, sizes, fonts, or any other essential attributes\n    /// of the shape of the text have changed. A complete reshape and relayout of\n    /// the text is necessary.\n    Shape,\n}\n\n/// A renderer capable of measuring and drawing [`Text`].\npub trait Renderer: crate::Renderer {\n    /// The font type used.\n    type Font: Copy + PartialEq;\n\n    /// The [`Paragraph`] of this [`Renderer`].\n    type Paragraph: Paragraph<Font = Self::Font> + 'static;\n\n    /// The [`Editor`] of this [`Renderer`].\n    type Editor: Editor<Font = Self::Font> + 'static;\n\n    /// The icon font of the backend.\n    const ICON_FONT: Self::Font;\n\n    /// The `char` representing a ✔ icon in the [`ICON_FONT`].\n    ///\n    /// [`ICON_FONT`]: Self::ICON_FONT\n    const CHECKMARK_ICON: char;\n\n    /// The `char` representing a ▼ icon in the built-in [`ICON_FONT`].\n    ///\n    /// [`ICON_FONT`]: Self::ICON_FONT\n    const ARROW_DOWN_ICON: char;\n\n    /// The `char` representing a ^ icon in the built-in [`ICON_FONT`].\n    ///\n    /// [`ICON_FONT`]: Self::ICON_FONT\n    const SCROLL_UP_ICON: char;\n\n    /// The `char` representing a v icon in the built-in [`ICON_FONT`].\n    ///\n    /// [`ICON_FONT`]: Self::ICON_FONT\n    const SCROLL_DOWN_ICON: char;\n\n    /// The `char` representing a < icon in the built-in [`ICON_FONT`].\n    ///\n    /// [`ICON_FONT`]: Self::ICON_FONT\n    const SCROLL_LEFT_ICON: char;\n\n    /// The `char` representing a > icon in the built-in [`ICON_FONT`].\n    ///\n    /// [`ICON_FONT`]: Self::ICON_FONT\n    const SCROLL_RIGHT_ICON: char;\n\n    /// The 'char' representing the iced logo in the built-in ['ICON_FONT'].\n    ///\n    /// ['ICON_FONT']: Self::ICON_FONT\n    const ICED_LOGO: char;\n\n    /// Returns the default [`Self::Font`].\n    fn default_font(&self) -> Self::Font;\n\n    /// Returns the default size of [`Text`].\n    fn default_size(&self) -> Pixels;\n\n    /// Draws the given [`Paragraph`] at the given position and with the given\n    /// [`Color`].\n    fn fill_paragraph(\n        &mut self,\n        text: &Self::Paragraph,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    );\n\n    /// Draws the given [`Editor`] at the given position and with the given\n    /// [`Color`].\n    fn fill_editor(\n        &mut self,\n        editor: &Self::Editor,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    );\n\n    /// Draws the given [`Text`] at the given position and with the given\n    /// [`Color`].\n    fn fill_text(\n        &mut self,\n        text: Text<String, Self::Font>,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    );\n}\n\n/// A span of text.\n#[derive(Debug, Clone)]\npub struct Span<'a, Link = (), Font = crate::Font> {\n    /// The [`Fragment`] of text.\n    pub text: Fragment<'a>,\n    /// The size of the [`Span`] in [`Pixels`].\n    pub size: Option<Pixels>,\n    /// The [`LineHeight`] of the [`Span`].\n    pub line_height: Option<LineHeight>,\n    /// The font of the [`Span`].\n    pub font: Option<Font>,\n    /// The [`Color`] of the [`Span`].\n    pub color: Option<Color>,\n    /// The link of the [`Span`].\n    pub link: Option<Link>,\n    /// The [`Highlight`] of the [`Span`].\n    pub highlight: Option<Highlight>,\n    /// The [`Padding`] of the [`Span`].\n    ///\n    /// Currently, it only affects the bounds of the [`Highlight`].\n    pub padding: Padding,\n    /// Whether the [`Span`] should be underlined or not.\n    pub underline: bool,\n    /// Whether the [`Span`] should be struck through or not.\n    pub strikethrough: bool,\n}\n\n/// A text highlight.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Highlight {\n    /// The [`Background`] of the highlight.\n    pub background: Background,\n    /// The [`Border`] of the highlight.\n    pub border: Border,\n}\n\nimpl<'a, Link, Font> Span<'a, Link, Font> {\n    /// Creates a new [`Span`] of text with the given text fragment.\n    pub fn new(fragment: impl IntoFragment<'a>) -> Self {\n        Self {\n            text: fragment.into_fragment(),\n            ..Self::default()\n        }\n    }\n\n    /// Sets the size of the [`Span`].\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        self.size = Some(size.into());\n        self\n    }\n\n    /// Sets the [`LineHeight`] of the [`Span`].\n    pub fn line_height(mut self, line_height: impl Into<LineHeight>) -> Self {\n        self.line_height = Some(line_height.into());\n        self\n    }\n\n    /// Sets the font of the [`Span`].\n    pub fn font(mut self, font: impl Into<Font>) -> Self {\n        self.font = Some(font.into());\n        self\n    }\n\n    /// Sets the font of the [`Span`], if any.\n    pub fn font_maybe(mut self, font: Option<impl Into<Font>>) -> Self {\n        self.font = font.map(Into::into);\n        self\n    }\n\n    /// Sets the [`Color`] of the [`Span`].\n    pub fn color(mut self, color: impl Into<Color>) -> Self {\n        self.color = Some(color.into());\n        self\n    }\n\n    /// Sets the [`Color`] of the [`Span`], if any.\n    pub fn color_maybe(mut self, color: Option<impl Into<Color>>) -> Self {\n        self.color = color.map(Into::into);\n        self\n    }\n\n    /// Sets the link of the [`Span`].\n    pub fn link(mut self, link: impl Into<Link>) -> Self {\n        self.link = Some(link.into());\n        self\n    }\n\n    /// Sets the link of the [`Span`], if any.\n    pub fn link_maybe(mut self, link: Option<impl Into<Link>>) -> Self {\n        self.link = link.map(Into::into);\n        self\n    }\n\n    /// Sets the [`Background`] of the [`Span`].\n    pub fn background(self, background: impl Into<Background>) -> Self {\n        self.background_maybe(Some(background))\n    }\n\n    /// Sets the [`Background`] of the [`Span`], if any.\n    pub fn background_maybe(mut self, background: Option<impl Into<Background>>) -> Self {\n        let Some(background) = background else {\n            return self;\n        };\n\n        match &mut self.highlight {\n            Some(highlight) => {\n                highlight.background = background.into();\n            }\n            None => {\n                self.highlight = Some(Highlight {\n                    background: background.into(),\n                    border: Border::default(),\n                });\n            }\n        }\n\n        self\n    }\n\n    /// Sets the [`Border`] of the [`Span`].\n    pub fn border(self, border: impl Into<Border>) -> Self {\n        self.border_maybe(Some(border))\n    }\n\n    /// Sets the [`Border`] of the [`Span`], if any.\n    pub fn border_maybe(mut self, border: Option<impl Into<Border>>) -> Self {\n        let Some(border) = border else {\n            return self;\n        };\n\n        match &mut self.highlight {\n            Some(highlight) => {\n                highlight.border = border.into();\n            }\n            None => {\n                self.highlight = Some(Highlight {\n                    border: border.into(),\n                    background: Background::Color(Color::TRANSPARENT),\n                });\n            }\n        }\n\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`Span`].\n    ///\n    /// It only affects the [`background`] and [`border`] of the\n    /// [`Span`], currently.\n    ///\n    /// [`background`]: Self::background\n    /// [`border`]: Self::border\n    pub fn padding(mut self, padding: impl Into<Padding>) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets whether the [`Span`] should be underlined or not.\n    pub fn underline(mut self, underline: bool) -> Self {\n        self.underline = underline;\n        self\n    }\n\n    /// Sets whether the [`Span`] should be struck through or not.\n    pub fn strikethrough(mut self, strikethrough: bool) -> Self {\n        self.strikethrough = strikethrough;\n        self\n    }\n\n    /// Turns the [`Span`] into a static one.\n    pub fn to_static(self) -> Span<'static, Link, Font> {\n        Span {\n            text: Cow::Owned(self.text.into_owned()),\n            size: self.size,\n            line_height: self.line_height,\n            font: self.font,\n            color: self.color,\n            link: self.link,\n            highlight: self.highlight,\n            padding: self.padding,\n            underline: self.underline,\n            strikethrough: self.strikethrough,\n        }\n    }\n}\n\nimpl<Link, Font> Default for Span<'_, Link, Font> {\n    fn default() -> Self {\n        Self {\n            text: Cow::default(),\n            size: None,\n            line_height: None,\n            font: None,\n            color: None,\n            link: None,\n            highlight: None,\n            padding: Padding::default(),\n            underline: false,\n            strikethrough: false,\n        }\n    }\n}\n\nimpl<'a, Link, Font> From<&'a str> for Span<'a, Link, Font> {\n    fn from(value: &'a str) -> Self {\n        Span::new(value)\n    }\n}\n\nimpl<Link, Font: PartialEq> PartialEq for Span<'_, Link, Font> {\n    fn eq(&self, other: &Self) -> bool {\n        self.text == other.text\n            && self.size == other.size\n            && self.line_height == other.line_height\n            && self.font == other.font\n            && self.color == other.color\n    }\n}\n\n/// A fragment of [`Text`].\n///\n/// This is just an alias to a string that may be either\n/// borrowed or owned.\npub type Fragment<'a> = Cow<'a, str>;\n\n/// A trait for converting a value to some text [`Fragment`].\npub trait IntoFragment<'a> {\n    /// Converts the value to some text [`Fragment`].\n    fn into_fragment(self) -> Fragment<'a>;\n}\n\nimpl<'a> IntoFragment<'a> for Fragment<'a> {\n    fn into_fragment(self) -> Fragment<'a> {\n        self\n    }\n}\n\nimpl<'a> IntoFragment<'a> for &'a Fragment<'_> {\n    fn into_fragment(self) -> Fragment<'a> {\n        Fragment::Borrowed(self)\n    }\n}\n\nimpl<'a> IntoFragment<'a> for &'a str {\n    fn into_fragment(self) -> Fragment<'a> {\n        Fragment::Borrowed(self)\n    }\n}\n\nimpl<'a> IntoFragment<'a> for &'a String {\n    fn into_fragment(self) -> Fragment<'a> {\n        Fragment::Borrowed(self.as_str())\n    }\n}\n\nimpl<'a> IntoFragment<'a> for String {\n    fn into_fragment(self) -> Fragment<'a> {\n        Fragment::Owned(self)\n    }\n}\n\nmacro_rules! into_fragment {\n    ($type:ty) => {\n        impl<'a> IntoFragment<'a> for $type {\n            fn into_fragment(self) -> Fragment<'a> {\n                Fragment::Owned(self.to_string())\n            }\n        }\n\n        impl<'a> IntoFragment<'a> for &$type {\n            fn into_fragment(self) -> Fragment<'a> {\n                Fragment::Owned(self.to_string())\n            }\n        }\n    };\n}\n\ninto_fragment!(char);\ninto_fragment!(bool);\n\ninto_fragment!(u8);\ninto_fragment!(u16);\ninto_fragment!(u32);\ninto_fragment!(u64);\ninto_fragment!(u128);\ninto_fragment!(usize);\n\ninto_fragment!(i8);\ninto_fragment!(i16);\ninto_fragment!(i32);\ninto_fragment!(i64);\ninto_fragment!(i128);\ninto_fragment!(isize);\n\ninto_fragment!(f32);\ninto_fragment!(f64);\n"
  },
  {
    "path": "core/src/theme/palette.rs",
    "content": "//! Define the colors of a theme.\nuse crate::{Color, color};\n\nuse std::sync::LazyLock;\n\n/// An extended set of colors generated from a [`Seed`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Palette {\n    /// The set of background colors.\n    pub background: Background,\n    /// The set of primary colors.\n    pub primary: Swatch,\n    /// The set of secondary colors.\n    pub secondary: Swatch,\n    /// The set of success colors.\n    pub success: Swatch,\n    /// The set of warning colors.\n    pub warning: Swatch,\n    /// The set of danger colors.\n    pub danger: Swatch,\n    /// Whether the palette is dark or not.\n    pub is_dark: bool,\n}\n\nimpl Palette {\n    /// Generates a [`Palette`] from the given [`Seed`].\n    pub fn generate(palette: Seed) -> Self {\n        Self {\n            background: Background::new(palette.background, palette.text),\n            primary: Swatch::generate(palette.primary, palette.background, palette.text),\n            secondary: Swatch::derive(palette.background, palette.text),\n            success: Swatch::generate(palette.success, palette.background, palette.text),\n            warning: Swatch::generate(palette.warning, palette.background, palette.text),\n            danger: Swatch::generate(palette.danger, palette.background, palette.text),\n            is_dark: is_dark(palette.background),\n        }\n    }\n}\n\n/// A pair of background and text colors.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Pair {\n    /// The background color.\n    pub color: Color,\n\n    /// The text color.\n    ///\n    /// It's guaranteed to be readable on top of the background [`color`].\n    ///\n    /// [`color`]: Self::color\n    pub text: Color,\n}\n\nimpl Pair {\n    /// Creates a new [`Pair`] from a background [`Color`] and some text [`Color`].\n    pub fn new(color: Color, text: Color) -> Self {\n        Self {\n            color,\n            text: readable(color, text),\n        }\n    }\n}\n\n/// A set of background colors.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Background {\n    /// The base background color.\n    pub base: Pair,\n    /// The weakest version of the base background color.\n    pub weakest: Pair,\n    /// A weaker version of the base background color.\n    pub weaker: Pair,\n    /// A weak version of the base background color.\n    pub weak: Pair,\n    /// A neutral version of the base background color, between weak and strong.\n    pub neutral: Pair,\n    /// A strong version of the base background color.\n    pub strong: Pair,\n    /// A stronger version of the base background color.\n    pub stronger: Pair,\n    /// The strongest version of the base background color.\n    pub strongest: Pair,\n}\n\nimpl Background {\n    /// Generates a set of [`Background`] colors from the base and text colors.\n    pub fn new(base: Color, text: Color) -> Self {\n        let weakest = deviate(base, 0.03);\n        let weaker = deviate(base, 0.07);\n        let weak = deviate(base, 0.1);\n        let neutral = deviate(base, 0.125);\n        let strong = deviate(base, 0.15);\n        let stronger = deviate(base, 0.175);\n        let strongest = deviate(base, 0.20);\n\n        Self {\n            base: Pair::new(base, text),\n            weakest: Pair::new(weakest, text),\n            weaker: Pair::new(weaker, text),\n            weak: Pair::new(weak, text),\n            neutral: Pair::new(neutral, text),\n            strong: Pair::new(strong, text),\n            stronger: Pair::new(stronger, text),\n            strongest: Pair::new(strongest, text),\n        }\n    }\n}\n\n/// A color sample in a palette of colors.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Swatch {\n    /// The base color.\n    pub base: Pair,\n    /// A weaker version of the base color.\n    pub weak: Pair,\n    /// A stronger version of the base color.\n    pub strong: Pair,\n}\n\nimpl Swatch {\n    /// Generates a [`Swatch`] from a base, background and text color.\n    pub fn generate(base: Color, background: Color, text: Color) -> Self {\n        let weak = base.mix(background, 0.4);\n        let strong = deviate(base, 0.1);\n\n        Self {\n            base: Pair::new(base, text),\n            weak: Pair::new(weak, text),\n            strong: Pair::new(strong, text),\n        }\n    }\n\n    /// Derives a [`Swatch`] from a base color and text color.\n    pub fn derive(base: Color, text: Color) -> Self {\n        let factor = if is_dark(base) { 0.2 } else { 0.4 };\n\n        let weak = deviate(base, 0.1).mix(text, factor);\n        let strong = deviate(base, 0.3).mix(text, factor);\n        let base = deviate(base, 0.2).mix(text, factor);\n\n        Self {\n            base: Pair::new(base, text),\n            weak: Pair::new(weak, text),\n            strong: Pair::new(strong, text),\n        }\n    }\n}\n\n/// The base set of colors of a [`Palette`].\n#[derive(Debug, Clone, Copy, PartialEq)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct Seed {\n    /// The background [`Color`] of the [`Palette`].\n    pub background: Color,\n    /// The text [`Color`] of the [`Palette`].\n    pub text: Color,\n    /// The primary [`Color`] of the [`Palette`].\n    pub primary: Color,\n    /// The success [`Color`] of the [`Palette`].\n    pub success: Color,\n    /// The warning [`Color`] of the [`Palette`].\n    pub warning: Color,\n    /// The danger [`Color`] of the [`Palette`].\n    pub danger: Color,\n}\n\nimpl Seed {\n    /// The built-in light variant of a [`Palette`].\n    pub const LIGHT: Self = Self {\n        background: Color::WHITE,\n        text: Color::BLACK,\n        primary: color!(0x5865F2),\n        success: color!(0x12664f),\n        warning: color!(0xb77e33),\n        danger: color!(0xc3423f),\n    };\n\n    /// The built-in dark variant of a [`Palette`].\n    pub const DARK: Self = Self {\n        background: color!(0x2B2D31),\n        text: Color::from_rgb(0.90, 0.90, 0.90),\n        primary: color!(0x5865F2),\n        success: color!(0x12664f),\n        warning: color!(0xffc14e),\n        danger: color!(0xc3423f),\n    };\n\n    /// The built-in [Dracula] variant of a [`Palette`].\n    ///\n    /// [Dracula]: https://draculatheme.com\n    pub const DRACULA: Self = Self {\n        background: color!(0x282A36), // BACKGROUND\n        text: color!(0xf8f8f2),       // FOREGROUND\n        primary: color!(0xbd93f9),    // PURPLE\n        success: color!(0x50fa7b),    // GREEN\n        warning: color!(0xf1fa8c),    // YELLOW\n        danger: color!(0xff5555),     // RED\n    };\n\n    /// The built-in [Nord] variant of a [`Palette`].\n    ///\n    /// [Nord]: https://www.nordtheme.com/docs/colors-and-palettes\n    pub const NORD: Self = Self {\n        background: color!(0x2e3440), // nord0\n        text: color!(0xeceff4),       // nord6\n        primary: color!(0x8fbcbb),    // nord7\n        success: color!(0xa3be8c),    // nord14\n        warning: color!(0xebcb8b),    // nord13\n        danger: color!(0xbf616a),     // nord11\n    };\n\n    /// The built-in [Solarized] Light variant of a [`Palette`].\n    ///\n    /// [Solarized]: https://ethanschoonover.com/solarized\n    pub const SOLARIZED_LIGHT: Self = Self {\n        background: color!(0xfdf6e3), // base3\n        text: color!(0x657b83),       // base00\n        primary: color!(0x2aa198),    // cyan\n        success: color!(0x859900),    // green\n        warning: color!(0xb58900),    // yellow\n        danger: color!(0xdc322f),     // red\n    };\n\n    /// The built-in [Solarized] Dark variant of a [`Palette`].\n    ///\n    /// [Solarized]: https://ethanschoonover.com/solarized\n    pub const SOLARIZED_DARK: Self = Self {\n        background: color!(0x002b36), // base03\n        text: color!(0x839496),       // base0\n        primary: color!(0x2aa198),    // cyan\n        success: color!(0x859900),    // green\n        warning: color!(0xb58900),    // yellow\n        danger: color!(0xdc322f),     // red\n    };\n\n    /// The built-in [Gruvbox] Light variant of a [`Palette`].\n    ///\n    /// [Gruvbox]: https://github.com/morhetz/gruvbox\n    pub const GRUVBOX_LIGHT: Self = Self {\n        background: color!(0xfbf1c7), // light BG_0\n        text: color!(0x282828),       // light FG0_29\n        primary: color!(0x458588),    // light BLUE_4\n        success: color!(0x98971a),    // light GREEN_2\n        warning: color!(0xd79921),    // light YELLOW_3\n        danger: color!(0xcc241d),     // light RED_1\n    };\n\n    /// The built-in [Gruvbox] Dark variant of a [`Palette`].\n    ///\n    /// [Gruvbox]: https://github.com/morhetz/gruvbox\n    pub const GRUVBOX_DARK: Self = Self {\n        background: color!(0x282828), // dark BG_0\n        text: color!(0xfbf1c7),       // dark FG0_29\n        primary: color!(0x458588),    // dark BLUE_4\n        success: color!(0x98971a),    // dark GREEN_2\n        warning: color!(0xd79921),    // dark YELLOW_3\n        danger: color!(0xcc241d),     // dark RED_1\n    };\n\n    /// The built-in [Catppuccin] Latte variant of a [`Palette`].\n    ///\n    /// [Catppuccin]: https://github.com/catppuccin/catppuccin\n    pub const CATPPUCCIN_LATTE: Self = Self {\n        background: color!(0xeff1f5), // Base\n        text: color!(0x4c4f69),       // Text\n        primary: color!(0x1e66f5),    // Blue\n        success: color!(0x40a02b),    // Green\n        warning: color!(0xdf8e1d),    // Yellow\n        danger: color!(0xd20f39),     // Red\n    };\n\n    /// The built-in [Catppuccin] Frappé variant of a [`Palette`].\n    ///\n    /// [Catppuccin]: https://github.com/catppuccin/catppuccin\n    pub const CATPPUCCIN_FRAPPE: Self = Self {\n        background: color!(0x303446), // Base\n        text: color!(0xc6d0f5),       // Text\n        primary: color!(0x8caaee),    // Blue\n        success: color!(0xa6d189),    // Green\n        warning: color!(0xe5c890),    // Yellow\n        danger: color!(0xe78284),     // Red\n    };\n\n    /// The built-in [Catppuccin] Macchiato variant of a [`Palette`].\n    ///\n    /// [Catppuccin]: https://github.com/catppuccin/catppuccin\n    pub const CATPPUCCIN_MACCHIATO: Self = Self {\n        background: color!(0x24273a), // Base\n        text: color!(0xcad3f5),       // Text\n        primary: color!(0x8aadf4),    // Blue\n        success: color!(0xa6da95),    // Green\n        warning: color!(0xeed49f),    // Yellow\n        danger: color!(0xed8796),     // Red\n    };\n\n    /// The built-in [Catppuccin] Mocha variant of a [`Palette`].\n    ///\n    /// [Catppuccin]: https://github.com/catppuccin/catppuccin\n    pub const CATPPUCCIN_MOCHA: Self = Self {\n        background: color!(0x1e1e2e), // Base\n        text: color!(0xcdd6f4),       // Text\n        primary: color!(0x89b4fa),    // Blue\n        success: color!(0xa6e3a1),    // Green\n        warning: color!(0xf9e2af),    // Yellow\n        danger: color!(0xf38ba8),     // Red\n    };\n\n    /// The built-in [Tokyo Night] variant of a [`Palette`].\n    ///\n    /// [Tokyo Night]: https://github.com/enkia/tokyo-night-vscode-theme\n    pub const TOKYO_NIGHT: Self = Self {\n        background: color!(0x1a1b26), // Background (Night)\n        text: color!(0x9aa5ce),       // Text\n        primary: color!(0x2ac3de),    // Blue\n        success: color!(0x9ece6a),    // Green\n        warning: color!(0xe0af68),    // Yellow\n        danger: color!(0xf7768e),     // Red\n    };\n\n    /// The built-in [Tokyo Night] Storm variant of a [`Palette`].\n    ///\n    /// [Tokyo Night]: https://github.com/enkia/tokyo-night-vscode-theme\n    pub const TOKYO_NIGHT_STORM: Self = Self {\n        background: color!(0x24283b), // Background (Storm)\n        text: color!(0x9aa5ce),       // Text\n        primary: color!(0x2ac3de),    // Blue\n        success: color!(0x9ece6a),    // Green\n        warning: color!(0xe0af68),    // Yellow\n        danger: color!(0xf7768e),     // Red\n    };\n\n    /// The built-in [Tokyo Night] Light variant of a [`Palette`].\n    ///\n    /// [Tokyo Night]: https://github.com/enkia/tokyo-night-vscode-theme\n    pub const TOKYO_NIGHT_LIGHT: Self = Self {\n        background: color!(0xd5d6db), // Background\n        text: color!(0x565a6e),       // Text\n        primary: color!(0x166775),    // Blue\n        success: color!(0x485e30),    // Green\n        warning: color!(0x8f5e15),    // Yellow\n        danger: color!(0x8c4351),     // Red\n    };\n\n    /// The built-in [Kanagawa] Wave variant of a [`Palette`].\n    ///\n    /// [Kanagawa]: https://github.com/rebelot/kanagawa.nvim\n    pub const KANAGAWA_WAVE: Self = Self {\n        background: color!(0x1f1f28), // Sumi Ink 3\n        text: color!(0xDCD7BA),       // Fuji White\n        primary: color!(0x7FB4CA),    // Wave Blue\n        success: color!(0x76946A),    // Autumn Green\n        warning: color!(0xff9e3b),    // Ronin Yellow\n        danger: color!(0xC34043),     // Autumn Red\n    };\n\n    /// The built-in [Kanagawa] Dragon variant of a [`Palette`].\n    ///\n    /// [Kanagawa]: https://github.com/rebelot/kanagawa.nvim\n    pub const KANAGAWA_DRAGON: Self = Self {\n        background: color!(0x181616), // Dragon Black 3\n        text: color!(0xc5c9c5),       // Dragon White\n        primary: color!(0x223249),    // Wave Blue 1\n        success: color!(0x8a9a7b),    // Dragon Green 2\n        warning: color!(0xff9e3b),    // Ronin Yellow\n        danger: color!(0xc4746e),     // Dragon Red\n    };\n\n    /// The built-in [Kanagawa] Lotus variant of a [`Palette`].\n    ///\n    /// [Kanagawa]: https://github.com/rebelot/kanagawa.nvim\n    pub const KANAGAWA_LOTUS: Self = Self {\n        background: color!(0xf2ecbc), // Lotus White 3\n        text: color!(0x545464),       // Lotus Ink 1\n        primary: color!(0x4d699b),    // Lotus Blue\n        success: color!(0x6f894e),    // Lotus Green\n        warning: color!(0xe98a00),    // Lotus Orange 2\n        danger: color!(0xc84053),     // Lotus Red\n    };\n\n    /// The built-in [Moonfly] variant of a [`Palette`].\n    ///\n    /// [Moonfly]: https://github.com/bluz71/vim-moonfly-colors\n    pub const MOONFLY: Self = Self {\n        background: color!(0x080808), // Background\n        text: color!(0xbdbdbd),       // Foreground\n        primary: color!(0x80a0ff),    // Blue (normal)\n        success: color!(0x8cc85f),    // Green (normal)\n        warning: color!(0xe3c78a),    // Yellow (normal)\n        danger: color!(0xff5454),     // Red (normal)\n    };\n\n    /// The built-in [Nightfly] variant of a [`Palette`].\n    ///\n    /// [Nightfly]: https://github.com/bluz71/vim-nightfly-colors\n    pub const NIGHTFLY: Self = Self {\n        background: color!(0x011627), // Background\n        text: color!(0xbdc1c6),       // Foreground\n        primary: color!(0x82aaff),    // Blue (normal)\n        success: color!(0xa1cd5e),    // Green (normal)\n        warning: color!(0xe3d18a),    // Yellow (normal)\n        danger: color!(0xfc514e),     // Red (normal)\n    };\n\n    /// The built-in [Oxocarbon] variant of a [`Palette`].\n    ///\n    /// [Oxocarbon]: https://github.com/nyoom-engineering/oxocarbon.nvim\n    pub const OXOCARBON: Self = Self {\n        background: color!(0x232323),\n        text: color!(0xd0d0d0),\n        primary: color!(0x00b4ff),\n        success: color!(0x00c15a),\n        warning: color!(0xbe95ff), // Base 14\n        danger: color!(0xf62d0f),\n    };\n\n    /// The built-in [Ferra] variant of a [`Palette`].\n    ///\n    /// [Ferra]: https://github.com/casperstorm/ferra\n    pub const FERRA: Self = Self {\n        background: color!(0x2b292d),\n        text: color!(0xfecdb2),\n        primary: color!(0xd1d1e0),\n        success: color!(0xb1b695),\n        warning: color!(0xf5d76e), // Honey\n        danger: color!(0xe06b75),\n    };\n}\n\n/// The built-in light variant of a [`Palette`].\npub static LIGHT: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::LIGHT));\n\n/// The built-in dark variant of a [`Palette`].\npub static DARK: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::DARK));\n\n/// The built-in Dracula variant of a [`Palette`].\npub static DRACULA: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::DRACULA));\n\n/// The built-in Nord variant of a [`Palette`].\npub static NORD: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::NORD));\n\n/// The built-in Solarized Light variant of a [`Palette`].\npub static SOLARIZED_LIGHT: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::SOLARIZED_LIGHT));\n\n/// The built-in Solarized Dark variant of a [`Palette`].\npub static SOLARIZED_DARK: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::SOLARIZED_DARK));\n\n/// The built-in Gruvbox Light variant of a [`Palette`].\npub static GRUVBOX_LIGHT: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::GRUVBOX_LIGHT));\n\n/// The built-in Gruvbox Dark variant of a [`Palette`].\npub static GRUVBOX_DARK: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::GRUVBOX_DARK));\n\n/// The built-in Catppuccin Latte variant of a [`Palette`].\npub static CATPPUCCIN_LATTE: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::CATPPUCCIN_LATTE));\n\n/// The built-in Catppuccin Frappé variant of a [`Palette`].\npub static CATPPUCCIN_FRAPPE: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::CATPPUCCIN_FRAPPE));\n\n/// The built-in Catppuccin Macchiato variant of a [`Palette`].\npub static CATPPUCCIN_MACCHIATO: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::CATPPUCCIN_MACCHIATO));\n\n/// The built-in Catppuccin Mocha variant of a [`Palette`].\npub static CATPPUCCIN_MOCHA: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::CATPPUCCIN_MOCHA));\n\n/// The built-in Tokyo Night variant of a [`Palette`].\npub static TOKYO_NIGHT: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::TOKYO_NIGHT));\n\n/// The built-in Tokyo Night Storm variant of a [`Palette`].\npub static TOKYO_NIGHT_STORM: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::TOKYO_NIGHT_STORM));\n\n/// The built-in Tokyo Night variant of a [`Palette`].\npub static TOKYO_NIGHT_LIGHT: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::TOKYO_NIGHT_LIGHT));\n\n/// The built-in Kanagawa Wave variant of a [`Palette`].\npub static KANAGAWA_WAVE: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::KANAGAWA_WAVE));\n\n/// The built-in Kanagawa Dragon variant of a [`Palette`].\npub static KANAGAWA_DRAGON: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::KANAGAWA_DRAGON));\n\n/// The built-in Kanagawa Lotus variant of a [`Palette`].\npub static KANAGAWA_LOTUS: LazyLock<Palette> =\n    LazyLock::new(|| Palette::generate(Seed::KANAGAWA_LOTUS));\n\n/// The built-in Moonfly variant of a [`Palette`].\npub static MOONFLY: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::MOONFLY));\n\n/// The built-in Nightfly variant of a [`Palette`].\npub static NIGHTFLY: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::NIGHTFLY));\n\n/// The built-in Oxocarbon variant of a [`Palette`].\npub static OXOCARBON: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::OXOCARBON));\n\n/// The built-in Ferra variant of a [`Palette`].\npub static FERRA: LazyLock<Palette> = LazyLock::new(|| Palette::generate(Seed::FERRA));\n\nstruct Oklch {\n    l: f32,\n    c: f32,\n    h: f32,\n    a: f32,\n}\n\n/// Darkens a [`Color`] by the given factor.\npub fn darken(color: Color, amount: f32) -> Color {\n    let mut oklch = to_oklch(color);\n\n    // We try to bump the chroma a bit for more colorful palettes\n    if oklch.c > 0.0 && oklch.c < (1.0 - oklch.l) / 2.0 {\n        // Formula empirically and cluelessly derived\n        oklch.c *= 1.0 + (0.2 / oklch.c).min(100.0) * amount;\n    }\n\n    oklch.l = if oklch.l - amount < 0.0 {\n        0.0\n    } else {\n        oklch.l - amount\n    };\n\n    from_oklch(oklch)\n}\n\n/// Lightens a [`Color`] by the given factor.\npub fn lighten(color: Color, amount: f32) -> Color {\n    let mut oklch = to_oklch(color);\n\n    // We try to bump the chroma a bit for more colorful palettes\n    // Formula empirically and cluelessly derived\n    oklch.c *= 1.0 + 2.0 * amount / oklch.l.max(0.05);\n\n    oklch.l = if oklch.l + amount > 1.0 {\n        1.0\n    } else {\n        oklch.l + amount\n    };\n\n    from_oklch(oklch)\n}\n\n/// Deviates a [`Color`] by the given factor. Lightens if the [`Color`] is\n/// dark, darkens otherwise.\npub fn deviate(color: Color, amount: f32) -> Color {\n    if is_dark(color) {\n        lighten(color, amount)\n    } else {\n        darken(color, amount)\n    }\n}\n\n/// Computes a [`Color`] from the given text color that is\n/// readable on top of the given background color.\npub fn readable(background: Color, text: Color) -> Color {\n    if text.is_readable_on(background) {\n        return text;\n    }\n\n    let improve = if is_dark(background) { lighten } else { darken };\n\n    // TODO: Compute factor from relative contrast value\n    let candidate = improve(text, 0.1);\n\n    if candidate.is_readable_on(background) {\n        return candidate;\n    }\n\n    let candidate = improve(text, 0.2);\n\n    if candidate.is_readable_on(background) {\n        return candidate;\n    }\n\n    let white_contrast = background.relative_contrast(Color::WHITE);\n    let black_contrast = background.relative_contrast(Color::BLACK);\n\n    if white_contrast >= black_contrast {\n        Color::WHITE.mix(background, 0.05)\n    } else {\n        Color::BLACK.mix(background, 0.05)\n    }\n}\n\n/// Returns true if the [`Color`] is dark.\npub fn is_dark(color: Color) -> bool {\n    to_oklch(color).l < 0.6\n}\n\n// https://en.wikipedia.org/wiki/Oklab_color_space#Conversions_between_color_spaces\nfn to_oklch(color: Color) -> Oklch {\n    let [r, g, b, alpha] = color.into_linear();\n\n    // linear RGB → LMS\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    // Nonlinear transform (cube root)\n    let l_ = l.cbrt();\n    let m_ = m.cbrt();\n    let s_ = s.cbrt();\n\n    // LMS → Oklab\n    let l = 0.21045426 * l_ + 0.7936178 * m_ - 0.004072047 * s_;\n    let a = 1.9779985 * l_ - 2.4285922 * m_ + 0.4505937 * s_;\n    let b = 0.025904037 * l_ + 0.78277177 * m_ - 0.80867577 * s_;\n\n    // Oklab → Oklch\n    let c = (a * a + b * b).sqrt();\n    let h = b.atan2(a); // radians\n\n    Oklch { l, c, h, a: alpha }\n}\n\n// https://en.wikipedia.org/wiki/Oklab_color_space#Conversions_between_color_spaces\nfn from_oklch(oklch: Oklch) -> Color {\n    let Oklch { l, c, h, a: alpha } = oklch;\n\n    let a = c * h.cos();\n    let b = c * h.sin();\n\n    // Oklab → LMS (nonlinear)\n    let l_ = l + 0.39633778 * a + 0.21580376 * b;\n    let m_ = l - 0.105561346 * a - 0.06385417 * b;\n    let s_ = l - 0.08948418 * a - 1.2914855 * b;\n\n    // Cubing back\n    let l = l_ * l_ * l_;\n    let m = m_ * m_ * m_;\n    let s = s_ * s_ * s_;\n\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    Color::from_linear_rgba(\n        r.clamp(0.0, 1.0),\n        g.clamp(0.0, 1.0),\n        b.clamp(0.0, 1.0),\n        alpha,\n    )\n}\n"
  },
  {
    "path": "core/src/theme.rs",
    "content": "//! Use the built-in theme and styles.\npub mod palette;\n\npub use palette::Palette;\n\nuse crate::Color;\n\nuse std::borrow::Cow;\nuse std::fmt;\nuse std::sync::Arc;\n\n/// A built-in theme.\n#[derive(Debug, Clone, PartialEq)]\npub enum Theme {\n    /// The built-in light variant.\n    Light,\n    /// The built-in dark variant.\n    Dark,\n    /// The built-in Dracula variant.\n    Dracula,\n    /// The built-in Nord variant.\n    Nord,\n    /// The built-in Solarized Light variant.\n    SolarizedLight,\n    /// The built-in Solarized Dark variant.\n    SolarizedDark,\n    /// The built-in Gruvbox Light variant.\n    GruvboxLight,\n    /// The built-in Gruvbox Dark variant.\n    GruvboxDark,\n    /// The built-in Catppuccin Latte variant.\n    CatppuccinLatte,\n    /// The built-in Catppuccin Frappé variant.\n    CatppuccinFrappe,\n    /// The built-in Catppuccin Macchiato variant.\n    CatppuccinMacchiato,\n    /// The built-in Catppuccin Mocha variant.\n    CatppuccinMocha,\n    /// The built-in Tokyo Night variant.\n    TokyoNight,\n    /// The built-in Tokyo Night Storm variant.\n    TokyoNightStorm,\n    /// The built-in Tokyo Night Light variant.\n    TokyoNightLight,\n    /// The built-in Kanagawa Wave variant.\n    KanagawaWave,\n    /// The built-in Kanagawa Dragon variant.\n    KanagawaDragon,\n    /// The built-in Kanagawa Lotus variant.\n    KanagawaLotus,\n    /// The built-in Moonfly variant.\n    Moonfly,\n    /// The built-in Nightfly variant.\n    Nightfly,\n    /// The built-in Oxocarbon variant.\n    Oxocarbon,\n    /// The built-in Ferra variant:\n    Ferra,\n    /// A [`Theme`] that uses a [`Custom`] palette.\n    Custom(Arc<Custom>),\n}\n\nimpl Theme {\n    /// A list with all the defined themes.\n    pub const ALL: &'static [Self] = &[\n        Self::Light,\n        Self::Dark,\n        Self::Dracula,\n        Self::Nord,\n        Self::SolarizedLight,\n        Self::SolarizedDark,\n        Self::GruvboxLight,\n        Self::GruvboxDark,\n        Self::CatppuccinLatte,\n        Self::CatppuccinFrappe,\n        Self::CatppuccinMacchiato,\n        Self::CatppuccinMocha,\n        Self::TokyoNight,\n        Self::TokyoNightStorm,\n        Self::TokyoNightLight,\n        Self::KanagawaWave,\n        Self::KanagawaDragon,\n        Self::KanagawaLotus,\n        Self::Moonfly,\n        Self::Nightfly,\n        Self::Oxocarbon,\n        Self::Ferra,\n    ];\n\n    /// Creates a new custom [`Theme`] from the given [`Seed`](palette::Seed).\n    pub fn custom(name: impl Into<Cow<'static, str>>, seed: palette::Seed) -> Self {\n        Self::custom_with_fn(name, seed, Palette::generate)\n    }\n\n    /// Creates a new custom [`Theme`] from the given [`Seed`](palette::Seed), with\n    /// a custom generator of a [`Palette`].\n    pub fn custom_with_fn(\n        name: impl Into<Cow<'static, str>>,\n        palette: palette::Seed,\n        generate: impl FnOnce(palette::Seed) -> Palette,\n    ) -> Self {\n        Self::Custom(Arc::new(Custom::with_fn(name, palette, generate)))\n    }\n\n    /// Returns the [`Palette`] of the [`Theme`].\n    pub fn palette(&self) -> &palette::Palette {\n        match self {\n            Self::Light => &palette::LIGHT,\n            Self::Dark => &palette::DARK,\n            Self::Dracula => &palette::DRACULA,\n            Self::Nord => &palette::NORD,\n            Self::SolarizedLight => &palette::SOLARIZED_LIGHT,\n            Self::SolarizedDark => &palette::SOLARIZED_DARK,\n            Self::GruvboxLight => &palette::GRUVBOX_LIGHT,\n            Self::GruvboxDark => &palette::GRUVBOX_DARK,\n            Self::CatppuccinLatte => &palette::CATPPUCCIN_LATTE,\n            Self::CatppuccinFrappe => &palette::CATPPUCCIN_FRAPPE,\n            Self::CatppuccinMacchiato => &palette::CATPPUCCIN_MACCHIATO,\n            Self::CatppuccinMocha => &palette::CATPPUCCIN_MOCHA,\n            Self::TokyoNight => &palette::TOKYO_NIGHT,\n            Self::TokyoNightStorm => &palette::TOKYO_NIGHT_STORM,\n            Self::TokyoNightLight => &palette::TOKYO_NIGHT_LIGHT,\n            Self::KanagawaWave => &palette::KANAGAWA_WAVE,\n            Self::KanagawaDragon => &palette::KANAGAWA_DRAGON,\n            Self::KanagawaLotus => &palette::KANAGAWA_LOTUS,\n            Self::Moonfly => &palette::MOONFLY,\n            Self::Nightfly => &palette::NIGHTFLY,\n            Self::Oxocarbon => &palette::OXOCARBON,\n            Self::Ferra => &palette::FERRA,\n            Self::Custom(custom) => &custom.palette,\n        }\n    }\n\n    /// Returns the [`Seed`](palette::Seed) of the [`Theme`].\n    pub fn seed(&self) -> palette::Seed {\n        match self {\n            Self::Light => palette::Seed::LIGHT,\n            Self::Dark => palette::Seed::DARK,\n            Self::Dracula => palette::Seed::DRACULA,\n            Self::Nord => palette::Seed::NORD,\n            Self::SolarizedLight => palette::Seed::SOLARIZED_LIGHT,\n            Self::SolarizedDark => palette::Seed::SOLARIZED_DARK,\n            Self::GruvboxLight => palette::Seed::GRUVBOX_LIGHT,\n            Self::GruvboxDark => palette::Seed::GRUVBOX_DARK,\n            Self::CatppuccinLatte => palette::Seed::CATPPUCCIN_LATTE,\n            Self::CatppuccinFrappe => palette::Seed::CATPPUCCIN_FRAPPE,\n            Self::CatppuccinMacchiato => palette::Seed::CATPPUCCIN_MACCHIATO,\n            Self::CatppuccinMocha => palette::Seed::CATPPUCCIN_MOCHA,\n            Self::TokyoNight => palette::Seed::TOKYO_NIGHT,\n            Self::TokyoNightStorm => palette::Seed::TOKYO_NIGHT_STORM,\n            Self::TokyoNightLight => palette::Seed::TOKYO_NIGHT_LIGHT,\n            Self::KanagawaWave => palette::Seed::KANAGAWA_WAVE,\n            Self::KanagawaDragon => palette::Seed::KANAGAWA_DRAGON,\n            Self::KanagawaLotus => palette::Seed::KANAGAWA_LOTUS,\n            Self::Moonfly => palette::Seed::MOONFLY,\n            Self::Nightfly => palette::Seed::NIGHTFLY,\n            Self::Oxocarbon => palette::Seed::OXOCARBON,\n            Self::Ferra => palette::Seed::FERRA,\n            Self::Custom(custom) => custom.seed,\n        }\n    }\n}\n\nimpl fmt::Display for Theme {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.name())\n    }\n}\n\n/// A [`Theme`] with a customized [`Palette`].\n#[derive(Debug, Clone, PartialEq)]\npub struct Custom {\n    name: Cow<'static, str>,\n    seed: palette::Seed,\n    palette: Palette,\n}\n\nimpl Custom {\n    /// Creates a [`Custom`] theme from the given [`Seed`](palette::Seed).\n    pub fn new(name: String, seed: palette::Seed) -> Self {\n        Self::with_fn(name, seed, Palette::generate)\n    }\n\n    /// Creates a [`Custom`] theme from the given [`Seed`](palette::Seed) with\n    /// a custom generator of a [`Palette`].\n    pub fn with_fn(\n        name: impl Into<Cow<'static, str>>,\n        seed: palette::Seed,\n        generate: impl FnOnce(palette::Seed) -> Palette,\n    ) -> Self {\n        Self {\n            name: name.into(),\n            seed,\n            palette: generate(seed),\n        }\n    }\n}\n\nimpl fmt::Display for Custom {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.name)\n    }\n}\n\n/// A theme mode, denoting the tone or brightness of a theme.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum Mode {\n    /// No specific tone.\n    #[default]\n    None,\n    /// A mode referring to themes with light tones.\n    Light,\n    /// A mode referring to themes with dark tones.\n    Dark,\n}\n\n/// The base style of a theme.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The background [`Color`] of the application.\n    pub background_color: Color,\n\n    /// The default text [`Color`] of the application.\n    pub text_color: Color,\n}\n\n/// The default blank style of a theme.\npub trait Base {\n    /// Returns the default theme for the preferred [`Mode`].\n    fn default(preference: Mode) -> Self;\n\n    /// Returns the [`Mode`] of the theme.\n    fn mode(&self) -> Mode;\n\n    /// Returns the default base [`Style`] of the theme.\n    fn base(&self) -> Style;\n\n    /// Returns the [`Seed`](palette::Seed) of the theme.\n    ///\n    /// This may be used by the runtime to recreate a [`Theme`] for\n    /// debugging purposes; like displaying performance metrics or devtools.\n    fn seed(&self) -> Option<palette::Seed>;\n\n    /// Returns the unique name of the theme.\n    ///\n    /// This name may be used to efficiently detect theme\n    /// changes in some widgets.\n    fn name(&self) -> &str;\n}\n\nimpl Base for Theme {\n    fn default(preference: Mode) -> Self {\n        use std::env;\n        use std::sync::OnceLock;\n\n        static SYSTEM: OnceLock<Option<Theme>> = OnceLock::new();\n\n        let system = SYSTEM.get_or_init(|| {\n            let name = env::var(\"ICED_THEME\").ok()?;\n\n            Theme::ALL\n                .iter()\n                .find(|theme| theme.to_string() == name)\n                .cloned()\n        });\n\n        if let Some(system) = system {\n            return system.clone();\n        }\n\n        match preference {\n            Mode::None | Mode::Light => Self::Light,\n            Mode::Dark => Self::Dark,\n        }\n    }\n\n    fn mode(&self) -> Mode {\n        if self.palette().is_dark {\n            Mode::Dark\n        } else {\n            Mode::Light\n        }\n    }\n\n    fn base(&self) -> Style {\n        default(self)\n    }\n\n    fn seed(&self) -> Option<palette::Seed> {\n        Some(self.seed())\n    }\n\n    fn name(&self) -> &str {\n        match self {\n            Self::Light => \"Light\",\n            Self::Dark => \"Dark\",\n            Self::Dracula => \"Dracula\",\n            Self::Nord => \"Nord\",\n            Self::SolarizedLight => \"Solarized Light\",\n            Self::SolarizedDark => \"Solarized Dark\",\n            Self::GruvboxLight => \"Gruvbox Light\",\n            Self::GruvboxDark => \"Gruvbox Dark\",\n            Self::CatppuccinLatte => \"Catppuccin Latte\",\n            Self::CatppuccinFrappe => \"Catppuccin Frappé\",\n            Self::CatppuccinMacchiato => \"Catppuccin Macchiato\",\n            Self::CatppuccinMocha => \"Catppuccin Mocha\",\n            Self::TokyoNight => \"Tokyo Night\",\n            Self::TokyoNightStorm => \"Tokyo Night Storm\",\n            Self::TokyoNightLight => \"Tokyo Night Light\",\n            Self::KanagawaWave => \"Kanagawa Wave\",\n            Self::KanagawaDragon => \"Kanagawa Dragon\",\n            Self::KanagawaLotus => \"Kanagawa Lotus\",\n            Self::Moonfly => \"Moonfly\",\n            Self::Nightfly => \"Nightfly\",\n            Self::Oxocarbon => \"Oxocarbon\",\n            Self::Ferra => \"Ferra\",\n            Self::Custom(custom) => &custom.name,\n        }\n    }\n}\n\n/// The default [`Style`] of a built-in [`Theme`].\npub fn default(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    Style {\n        background_color: palette.background.base.color,\n        text_color: palette.background.base.text,\n    }\n}\n"
  },
  {
    "path": "core/src/time.rs",
    "content": "//! Keep track of time, both in native and web platforms!\n\npub use web_time::Duration;\npub use web_time::Instant;\npub use web_time::SystemTime;\n\n/// Creates a [`Duration`] representing the given amount of milliseconds.\npub fn milliseconds(milliseconds: u64) -> Duration {\n    Duration::from_millis(milliseconds)\n}\n\n/// Creates a [`Duration`] representing the given amount of seconds.\npub fn seconds(seconds: u64) -> Duration {\n    Duration::from_secs(seconds)\n}\n\n/// Creates a [`Duration`] representing the given amount of minutes.\npub fn minutes(minutes: u64) -> Duration {\n    seconds(minutes * 60)\n}\n\n/// Creates a [`Duration`] representing the given amount of hours.\npub fn hours(hours: u64) -> Duration {\n    minutes(hours * 60)\n}\n\n/// Creates a [`Duration`] representing the given amount of days.\npub fn days(days: u64) -> Duration {\n    hours(days * 24)\n}\n"
  },
  {
    "path": "core/src/touch.rs",
    "content": "//! Build touch events.\nuse crate::Point;\n\n/// A touch interaction.\n#[derive(Debug, Clone, Copy, PartialEq)]\n#[allow(missing_docs)]\npub enum Event {\n    /// A touch interaction was started.\n    FingerPressed { id: Finger, position: Point },\n\n    /// An on-going touch interaction was moved.\n    FingerMoved { id: Finger, position: Point },\n\n    /// A touch interaction was ended.\n    FingerLifted { id: Finger, position: Point },\n\n    /// A touch interaction was canceled.\n    FingerLost { id: Finger, position: Point },\n}\n\n/// A unique identifier representing a finger on a touch interaction.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub struct Finger(pub u64);\n"
  },
  {
    "path": "core/src/transformation.rs",
    "content": "use crate::{Point, Rectangle, Size, Vector};\n\nuse glam::{Mat4, Vec3, Vec4};\nuse std::ops::Mul;\n\n/// A 2D transformation matrix.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Transformation(Mat4);\n\nimpl Transformation {\n    /// A [`Transformation`] that preserves whatever is transformed.\n    pub const IDENTITY: Self = Self(Mat4::IDENTITY);\n\n    /// Creates an orthographic projection.\n    #[rustfmt::skip]\n    pub fn orthographic(width: u32, height: u32) -> Self{\n        Self(Mat4::orthographic_rh_gl(\n            0.0, width as f32,\n            height as f32, 0.0,\n            -1.0, 1.0\n        ))\n    }\n\n    /// Creates a translate transformation.\n    pub fn translate(x: f32, y: f32) -> Self {\n        Self(Mat4::from_translation(Vec3::new(x, y, 0.0)))\n    }\n\n    /// Creates a uniform scaling transformation.\n    pub fn scale(scaling: f32) -> Self {\n        Self(Mat4::from_scale(Vec3::new(scaling, scaling, 1.0)))\n    }\n\n    /// Returns the inverse of the [`Transformation`].\n    pub fn inverse(self) -> Self {\n        Self(self.0.inverse())\n    }\n\n    /// Returns the scale factor of the [`Transformation`].\n    pub fn scale_factor(&self) -> f32 {\n        self.0.x_axis.x\n    }\n\n    /// Returns the translation of the [`Transformation`].\n    pub fn translation(&self) -> Vector {\n        Vector::new(self.0.w_axis.x, self.0.w_axis.y)\n    }\n}\n\nimpl Default for Transformation {\n    fn default() -> Self {\n        Transformation::IDENTITY\n    }\n}\n\nimpl Mul for Transformation {\n    type Output = Self;\n\n    fn mul(self, rhs: Self) -> Self {\n        Self(self.0 * rhs.0)\n    }\n}\n\nimpl Mul<Transformation> for Point {\n    type Output = Self;\n\n    fn mul(self, transformation: Transformation) -> Self {\n        let point = transformation\n            .0\n            .mul_vec4(Vec4::new(self.x, self.y, 1.0, 1.0));\n\n        Point::new(point.x, point.y)\n    }\n}\n\nimpl Mul<Transformation> for Vector {\n    type Output = Self;\n\n    fn mul(self, transformation: Transformation) -> Self {\n        let new_vector = transformation\n            .0\n            .mul_vec4(Vec4::new(self.x, self.y, 1.0, 0.0));\n\n        Vector::new(new_vector.x, new_vector.y)\n    }\n}\n\nimpl Mul<Transformation> for Size {\n    type Output = Self;\n\n    fn mul(self, transformation: Transformation) -> Self {\n        let new_size = transformation\n            .0\n            .mul_vec4(Vec4::new(self.width, self.height, 1.0, 0.0));\n\n        Size::new(new_size.x, new_size.y)\n    }\n}\n\nimpl Mul<Transformation> for Rectangle {\n    type Output = Self;\n\n    fn mul(self, transformation: Transformation) -> Self {\n        let position = self.position();\n        let size = self.size();\n\n        Self::new(position * transformation, size * transformation)\n    }\n}\n\nimpl AsRef<[f32; 16]> for Transformation {\n    fn as_ref(&self) -> &[f32; 16] {\n        self.0.as_ref()\n    }\n}\n\nimpl From<Transformation> for [f32; 16] {\n    fn from(t: Transformation) -> [f32; 16] {\n        *t.as_ref()\n    }\n}\n\nimpl From<Transformation> for Mat4 {\n    fn from(transformation: Transformation) -> Self {\n        transformation.0\n    }\n}\n"
  },
  {
    "path": "core/src/vector.rs",
    "content": "/// A 2D vector.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub struct Vector<T = f32> {\n    /// The X component of the [`Vector`]\n    pub x: T,\n\n    /// The Y component of the [`Vector`]\n    pub y: T,\n}\n\nimpl<T> Vector<T> {\n    /// Creates a new [`Vector`] with the given components.\n    pub const fn new(x: T, y: T) -> Self {\n        Self { x, y }\n    }\n}\n\nimpl Vector {\n    /// The zero [`Vector`].\n    pub const ZERO: Self = Self::new(0.0, 0.0);\n\n    /// Rounds the [`Vector`].\n    pub fn round(self) -> Self {\n        Self {\n            x: self.x.round(),\n            y: self.y.round(),\n        }\n    }\n}\n\nimpl<T> std::ops::Neg for Vector<T>\nwhere\n    T: std::ops::Neg<Output = T>,\n{\n    type Output = Self;\n\n    fn neg(self) -> Self::Output {\n        Self::new(-self.x, -self.y)\n    }\n}\n\nimpl<T> std::ops::Add for Vector<T>\nwhere\n    T: std::ops::Add<Output = T>,\n{\n    type Output = Self;\n\n    fn add(self, b: Self) -> Self {\n        Self::new(self.x + b.x, self.y + b.y)\n    }\n}\n\nimpl<T> std::ops::AddAssign for Vector<T>\nwhere\n    T: std::ops::AddAssign,\n{\n    fn add_assign(&mut self, b: Self) {\n        self.x += b.x;\n        self.y += b.y;\n    }\n}\n\nimpl<T> std::ops::Sub for Vector<T>\nwhere\n    T: std::ops::Sub<Output = T>,\n{\n    type Output = Self;\n\n    fn sub(self, b: Self) -> Self {\n        Self::new(self.x - b.x, self.y - b.y)\n    }\n}\n\nimpl<T> std::ops::SubAssign for Vector<T>\nwhere\n    T: std::ops::SubAssign,\n{\n    fn sub_assign(&mut self, b: Self) {\n        self.x -= b.x;\n        self.y -= b.y;\n    }\n}\n\nimpl<T> std::ops::Mul<T> for Vector<T>\nwhere\n    T: std::ops::Mul<Output = T> + Copy,\n{\n    type Output = Self;\n\n    fn mul(self, scale: T) -> Self {\n        Self::new(self.x * scale, self.y * scale)\n    }\n}\n\nimpl<T> std::ops::MulAssign<T> for Vector<T>\nwhere\n    T: std::ops::MulAssign + Copy,\n{\n    fn mul_assign(&mut self, scale: T) {\n        self.x *= scale;\n        self.y *= scale;\n    }\n}\n\nimpl<T> std::ops::Div<T> for Vector<T>\nwhere\n    T: std::ops::Div<Output = T> + Copy,\n{\n    type Output = Self;\n\n    fn div(self, scale: T) -> Self {\n        Self::new(self.x / scale, self.y / scale)\n    }\n}\n\nimpl<T> std::ops::DivAssign<T> for Vector<T>\nwhere\n    T: std::ops::DivAssign + Copy,\n{\n    fn div_assign(&mut self, scale: T) {\n        self.x /= scale;\n        self.y /= scale;\n    }\n}\n\nimpl<T> From<[T; 2]> for Vector<T> {\n    fn from([x, y]: [T; 2]) -> Self {\n        Self::new(x, y)\n    }\n}\n\nimpl<T> From<Vector<T>> for [T; 2]\nwhere\n    T: Copy,\n{\n    fn from(other: Vector<T>) -> Self {\n        [other.x, other.y]\n    }\n}\n"
  },
  {
    "path": "core/src/widget/id.rs",
    "content": "use std::borrow;\nuse std::sync::atomic::{self, AtomicUsize};\n\nstatic NEXT_ID: AtomicUsize = AtomicUsize::new(0);\n\n/// The identifier of a generic widget.\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct Id(Internal);\n\nimpl Id {\n    /// Creates a new [`Id`] from a static `str`.\n    pub const fn new(id: &'static str) -> Self {\n        Self(Internal::Custom(borrow::Cow::Borrowed(id)))\n    }\n\n    /// Creates a unique [`Id`].\n    ///\n    /// This function produces a different [`Id`] every time it is called.\n    pub fn unique() -> Self {\n        let id = NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed);\n\n        Self(Internal::Unique(id))\n    }\n}\n\nimpl From<&'static str> for Id {\n    fn from(value: &'static str) -> Self {\n        Self::new(value)\n    }\n}\n\nimpl From<String> for Id {\n    fn from(value: String) -> Self {\n        Self(Internal::Custom(borrow::Cow::Owned(value)))\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\nenum Internal {\n    Unique(usize),\n    Custom(borrow::Cow<'static, str>),\n}\n\n#[cfg(test)]\nmod tests {\n    use super::Id;\n\n    #[test]\n    fn unique_generates_different_ids() {\n        let a = Id::unique();\n        let b = Id::unique();\n\n        assert_ne!(a, b);\n    }\n}\n"
  },
  {
    "path": "core/src/widget/operation/focusable.rs",
    "content": "//! Operate on widgets that can be focused.\nuse crate::Rectangle;\nuse crate::widget::Id;\nuse crate::widget::operation::{self, Operation, Outcome};\n\n/// The internal state of a widget that can be focused.\npub trait Focusable {\n    /// Returns whether the widget is focused or not.\n    fn is_focused(&self) -> bool;\n\n    /// Focuses the widget.\n    fn focus(&mut self);\n\n    /// Unfocuses the widget.\n    fn unfocus(&mut self);\n}\n\n/// A summary of the focusable widgets present on a widget tree.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub struct Count {\n    /// The index of the current focused widget, if any.\n    pub focused: Option<usize>,\n\n    /// The total amount of focusable widgets.\n    pub total: usize,\n}\n\n/// Produces an [`Operation`] that focuses the widget with the given [`Id`].\npub fn focus<T>(target: Id) -> impl Operation<T> {\n    struct Focus {\n        target: Id,\n    }\n\n    impl<T> Operation<T> for Focus {\n        fn focusable(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {\n            match id {\n                Some(id) if id == &self.target => {\n                    state.focus();\n                }\n                _ => {\n                    state.unfocus();\n                }\n            }\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    Focus { target }\n}\n\n/// Produces an [`Operation`] that unfocuses the focused widget.\npub fn unfocus<T>() -> impl Operation<T> {\n    struct Unfocus;\n\n    impl<T> Operation<T> for Unfocus {\n        fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {\n            state.unfocus();\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    Unfocus\n}\n\n/// Produces an [`Operation`] that generates a [`Count`] and chains it with the\n/// provided function to build a new [`Operation`].\npub fn count() -> impl Operation<Count> {\n    struct CountFocusable {\n        count: Count,\n    }\n\n    impl Operation<Count> for CountFocusable {\n        fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {\n            if state.is_focused() {\n                self.count.focused = Some(self.count.total);\n            }\n\n            self.count.total += 1;\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<Count>)) {\n            operate(self);\n        }\n\n        fn finish(&self) -> Outcome<Count> {\n            Outcome::Some(self.count)\n        }\n    }\n\n    CountFocusable {\n        count: Count::default(),\n    }\n}\n\n/// Produces an [`Operation`] that searches for the current focused widget, and\n/// - if found, focuses the previous focusable widget.\n/// - if not found, focuses the last focusable widget.\npub fn focus_previous<T>() -> impl Operation<T>\nwhere\n    T: Send + 'static,\n{\n    struct FocusPrevious {\n        count: Count,\n        current: usize,\n    }\n\n    impl<T> Operation<T> for FocusPrevious {\n        fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {\n            if self.count.total == 0 {\n                return;\n            }\n\n            match self.count.focused {\n                None if self.current == self.count.total - 1 => state.focus(),\n                Some(0) if self.current == 0 => state.unfocus(),\n                Some(0) => {}\n                Some(focused) if focused == self.current => state.unfocus(),\n                Some(focused) if focused - 1 == self.current => state.focus(),\n                _ => {}\n            }\n\n            self.current += 1;\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    operation::then(count(), |count| FocusPrevious { count, current: 0 })\n}\n\n/// Produces an [`Operation`] that searches for the current focused widget, and\n/// - if found, focuses the next focusable widget.\n/// - if not found, focuses the first focusable widget.\npub fn focus_next<T>() -> impl Operation<T>\nwhere\n    T: Send + 'static,\n{\n    struct FocusNext {\n        count: Count,\n        current: usize,\n    }\n\n    impl<T> Operation<T> for FocusNext {\n        fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {\n            match self.count.focused {\n                None if self.current == 0 => state.focus(),\n                Some(focused) if focused == self.current => state.unfocus(),\n                Some(focused) if focused + 1 == self.current => state.focus(),\n                _ => {}\n            }\n\n            self.current += 1;\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    operation::then(count(), |count| FocusNext { count, current: 0 })\n}\n\n/// Produces an [`Operation`] that searches for the current focused widget\n/// and stores its ID. This ignores widgets that do not have an ID.\npub fn find_focused() -> impl Operation<Id> {\n    struct FindFocused {\n        focused: Option<Id>,\n    }\n\n    impl Operation<Id> for FindFocused {\n        fn focusable(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {\n            if state.is_focused() && id.is_some() {\n                self.focused = id.cloned();\n            }\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<Id>)) {\n            operate(self);\n        }\n\n        fn finish(&self) -> Outcome<Id> {\n            if let Some(id) = &self.focused {\n                Outcome::Some(id.clone())\n            } else {\n                Outcome::None\n            }\n        }\n    }\n\n    FindFocused { focused: None }\n}\n\n/// Produces an [`Operation`] that searches for the focusable widget\n/// and stores whether it is focused or not. This ignores widgets that\n/// do not have an ID.\npub fn is_focused(target: Id) -> impl Operation<bool> {\n    struct IsFocused {\n        target: Id,\n        is_focused: Option<bool>,\n    }\n\n    impl Operation<bool> for IsFocused {\n        fn focusable(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {\n            if id.is_some_and(|id| *id == self.target) {\n                self.is_focused = Some(state.is_focused());\n            }\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<bool>)) {\n            if self.is_focused.is_some() {\n                return;\n            }\n\n            operate(self);\n        }\n\n        fn finish(&self) -> Outcome<bool> {\n            self.is_focused.map_or(Outcome::None, Outcome::Some)\n        }\n    }\n\n    IsFocused {\n        target,\n        is_focused: None,\n    }\n}\n"
  },
  {
    "path": "core/src/widget/operation/scrollable.rs",
    "content": "//! Operate on widgets that can be scrolled.\nuse crate::widget::{Id, Operation};\nuse crate::{Rectangle, Vector};\n\n/// The internal state of a widget that can be scrolled.\npub trait Scrollable {\n    /// Snaps the scroll of the widget to the given `percentage` along the horizontal & vertical axis.\n    fn snap_to(&mut self, offset: RelativeOffset<Option<f32>>);\n\n    /// Scroll the widget to the given [`AbsoluteOffset`] along the horizontal & vertical axis.\n    fn scroll_to(&mut self, offset: AbsoluteOffset<Option<f32>>);\n\n    /// Scroll the widget by the given [`AbsoluteOffset`] along the horizontal & vertical axis.\n    fn scroll_by(&mut self, offset: AbsoluteOffset, bounds: Rectangle, content_bounds: Rectangle);\n}\n\n/// Produces an [`Operation`] that snaps the widget with the given [`Id`] to\n/// the provided `percentage`.\npub fn snap_to<T>(target: Id, offset: RelativeOffset<Option<f32>>) -> impl Operation<T> {\n    struct SnapTo {\n        target: Id,\n        offset: RelativeOffset<Option<f32>>,\n    }\n\n    impl<T> Operation<T> for SnapTo {\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n\n        fn scrollable(\n            &mut self,\n            id: Option<&Id>,\n            _bounds: Rectangle,\n            _content_bounds: Rectangle,\n            _translation: Vector,\n            state: &mut dyn Scrollable,\n        ) {\n            if Some(&self.target) == id {\n                state.snap_to(self.offset);\n            }\n        }\n    }\n\n    SnapTo { target, offset }\n}\n\n/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] to\n/// the provided [`AbsoluteOffset`].\npub fn scroll_to<T>(target: Id, offset: AbsoluteOffset<Option<f32>>) -> impl Operation<T> {\n    struct ScrollTo {\n        target: Id,\n        offset: AbsoluteOffset<Option<f32>>,\n    }\n\n    impl<T> Operation<T> for ScrollTo {\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n\n        fn scrollable(\n            &mut self,\n            id: Option<&Id>,\n            _bounds: Rectangle,\n            _content_bounds: Rectangle,\n            _translation: Vector,\n            state: &mut dyn Scrollable,\n        ) {\n            if Some(&self.target) == id {\n                state.scroll_to(self.offset);\n            }\n        }\n    }\n\n    ScrollTo { target, offset }\n}\n\n/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] by\n/// the provided [`AbsoluteOffset`].\npub fn scroll_by<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {\n    struct ScrollBy {\n        target: Id,\n        offset: AbsoluteOffset,\n    }\n\n    impl<T> Operation<T> for ScrollBy {\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n\n        fn scrollable(\n            &mut self,\n            id: Option<&Id>,\n            bounds: Rectangle,\n            content_bounds: Rectangle,\n            _translation: Vector,\n            state: &mut dyn Scrollable,\n        ) {\n            if Some(&self.target) == id {\n                state.scroll_by(self.offset, bounds, content_bounds);\n            }\n        }\n    }\n\n    ScrollBy { target, offset }\n}\n\n/// The amount of absolute offset in each direction of a [`Scrollable`].\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub struct AbsoluteOffset<T = f32> {\n    /// The amount of horizontal offset\n    pub x: T,\n    /// The amount of vertical offset\n    pub y: T,\n}\n\nimpl From<AbsoluteOffset> for AbsoluteOffset<Option<f32>> {\n    fn from(offset: AbsoluteOffset) -> Self {\n        Self {\n            x: Some(offset.x),\n            y: Some(offset.y),\n        }\n    }\n}\n\n/// The amount of relative offset in each direction of a [`Scrollable`].\n///\n/// A value of `0.0` means start, while `1.0` means end.\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub struct RelativeOffset<T = f32> {\n    /// The amount of horizontal offset\n    pub x: T,\n    /// The amount of vertical offset\n    pub y: T,\n}\n\nimpl RelativeOffset {\n    /// A relative offset that points to the top-left of a [`Scrollable`].\n    pub const START: Self = Self { x: 0.0, y: 0.0 };\n\n    /// A relative offset that points to the bottom-right of a [`Scrollable`].\n    pub const END: Self = Self { x: 1.0, y: 1.0 };\n}\n\nimpl From<RelativeOffset> for RelativeOffset<Option<f32>> {\n    fn from(offset: RelativeOffset) -> Self {\n        Self {\n            x: Some(offset.x),\n            y: Some(offset.y),\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/widget/operation/text_input.rs",
    "content": "//! Operate on widgets that have text input.\nuse crate::Rectangle;\nuse crate::widget::Id;\nuse crate::widget::operation::Operation;\n\n/// The internal state of a widget that has text input.\npub trait TextInput {\n    /// Returns the current _visible_ text of the text input\n    ///\n    /// Normally, this is either its value or its placeholder.\n    fn text(&self) -> &str;\n\n    /// Moves the cursor of the text input to the front of the input text.\n    fn move_cursor_to_front(&mut self);\n\n    /// Moves the cursor of the text input to the end of the input text.\n    fn move_cursor_to_end(&mut self);\n\n    /// Moves the cursor of the text input to an arbitrary location.\n    fn move_cursor_to(&mut self, position: usize);\n\n    /// Selects all the content of the text input.\n    fn select_all(&mut self);\n    /// Selects the given content range of the text input.\n    fn select_range(&mut self, start: usize, end: usize);\n}\n\n/// Produces an [`Operation`] that moves the cursor of the widget with the given [`Id`] to the\n/// front.\npub fn move_cursor_to_front<T>(target: Id) -> impl Operation<T> {\n    struct MoveCursor {\n        target: Id,\n    }\n\n    impl<T> Operation<T> for MoveCursor {\n        fn text_input(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn TextInput) {\n            match id {\n                Some(id) if id == &self.target => {\n                    state.move_cursor_to_front();\n                }\n                _ => {}\n            }\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    MoveCursor { target }\n}\n\n/// Produces an [`Operation`] that moves the cursor of the widget with the given [`Id`] to the\n/// end.\npub fn move_cursor_to_end<T>(target: Id) -> impl Operation<T> {\n    struct MoveCursor {\n        target: Id,\n    }\n\n    impl<T> Operation<T> for MoveCursor {\n        fn text_input(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn TextInput) {\n            match id {\n                Some(id) if id == &self.target => {\n                    state.move_cursor_to_end();\n                }\n                _ => {}\n            }\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    MoveCursor { target }\n}\n\n/// Produces an [`Operation`] that moves the cursor of the widget with the given [`Id`] to the\n/// provided position.\npub fn move_cursor_to<T>(target: Id, position: usize) -> impl Operation<T> {\n    struct MoveCursor {\n        target: Id,\n        position: usize,\n    }\n\n    impl<T> Operation<T> for MoveCursor {\n        fn text_input(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn TextInput) {\n            match id {\n                Some(id) if id == &self.target => {\n                    state.move_cursor_to(self.position);\n                }\n                _ => {}\n            }\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    MoveCursor { target, position }\n}\n\n/// Produces an [`Operation`] that selects all the content of the widget with the given [`Id`].\npub fn select_all<T>(target: Id) -> impl Operation<T> {\n    struct MoveCursor {\n        target: Id,\n    }\n\n    impl<T> Operation<T> for MoveCursor {\n        fn text_input(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn TextInput) {\n            match id {\n                Some(id) if id == &self.target => {\n                    state.select_all();\n                }\n                _ => {}\n            }\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    MoveCursor { target }\n}\n\n/// Produces an [`Operation`] that selects the given content range of the widget with the given [`Id`].\npub fn select_range<T>(target: Id, start: usize, end: usize) -> impl Operation<T> {\n    struct SelectRange {\n        target: Id,\n        start: usize,\n        end: usize,\n    }\n\n    impl<T> Operation<T> for SelectRange {\n        fn text_input(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn TextInput) {\n            match id {\n                Some(id) if id == &self.target => {\n                    state.select_range(self.start, self.end);\n                }\n                _ => {}\n            }\n        }\n\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {\n            operate(self);\n        }\n    }\n\n    SelectRange { target, start, end }\n}\n"
  },
  {
    "path": "core/src/widget/operation.rs",
    "content": "//! Query or update internal widget state.\npub mod focusable;\npub mod scrollable;\npub mod text_input;\n\npub use focusable::Focusable;\npub use scrollable::Scrollable;\npub use text_input::TextInput;\n\nuse crate::widget::Id;\nuse crate::{Rectangle, Vector};\n\nuse std::any::Any;\nuse std::fmt;\nuse std::marker::PhantomData;\nuse std::sync::Arc;\n\n/// A piece of logic that can traverse the widget tree of an application in\n/// order to query or update some widget state.\npub trait Operation<T = ()>: Send {\n    /// Requests further traversal of the widget tree to keep operating.\n    ///\n    /// The provided `operate` closure may be called by an [`Operation`]\n    /// to return control to the widget tree and keep traversing it. If\n    /// the closure is not called, the children of the widget asking for\n    /// traversal will be skipped.\n    fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>));\n\n    /// Operates on a widget that contains other widgets.\n    fn container(&mut self, _id: Option<&Id>, _bounds: Rectangle) {}\n\n    /// Operates on a widget that can be scrolled.\n    fn scrollable(\n        &mut self,\n        _id: Option<&Id>,\n        _bounds: Rectangle,\n        _content_bounds: Rectangle,\n        _translation: Vector,\n        _state: &mut dyn Scrollable,\n    ) {\n    }\n\n    /// Operates on a widget that can be focused.\n    fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Focusable) {}\n\n    /// Operates on a widget that has text input.\n    fn text_input(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn TextInput) {}\n\n    /// Operates on a widget that contains some text.\n    fn text(&mut self, _id: Option<&Id>, _bounds: Rectangle, _text: &str) {}\n\n    /// Operates on a custom widget with some state.\n    fn custom(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Any) {}\n\n    /// Finishes the [`Operation`] and returns its [`Outcome`].\n    fn finish(&self) -> Outcome<T> {\n        Outcome::None\n    }\n}\n\nimpl<T, O> Operation<O> for Box<T>\nwhere\n    T: Operation<O> + ?Sized,\n{\n    fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>)) {\n        self.as_mut().traverse(operate);\n    }\n\n    fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {\n        self.as_mut().container(id, bounds);\n    }\n\n    fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {\n        self.as_mut().focusable(id, bounds, state);\n    }\n\n    fn scrollable(\n        &mut self,\n        id: Option<&Id>,\n        bounds: Rectangle,\n        content_bounds: Rectangle,\n        translation: Vector,\n        state: &mut dyn Scrollable,\n    ) {\n        self.as_mut()\n            .scrollable(id, bounds, content_bounds, translation, state);\n    }\n\n    fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {\n        self.as_mut().text_input(id, bounds, state);\n    }\n\n    fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {\n        self.as_mut().text(id, bounds, text);\n    }\n\n    fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {\n        self.as_mut().custom(id, bounds, state);\n    }\n\n    fn finish(&self) -> Outcome<O> {\n        self.as_ref().finish()\n    }\n}\n\n/// The result of an [`Operation`].\npub enum Outcome<T> {\n    /// The [`Operation`] produced no result.\n    None,\n\n    /// The [`Operation`] produced some result.\n    Some(T),\n\n    /// The [`Operation`] needs to be followed by another [`Operation`].\n    Chain(Box<dyn Operation<T>>),\n}\n\nimpl<T> fmt::Debug for Outcome<T>\nwhere\n    T: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::None => write!(f, \"Outcome::None\"),\n            Self::Some(output) => write!(f, \"Outcome::Some({output:?})\"),\n            Self::Chain(_) => write!(f, \"Outcome::Chain(...)\"),\n        }\n    }\n}\n\n/// Wraps the [`Operation`] in a black box, erasing its returning type.\npub fn black_box<'a, T, O>(operation: &'a mut dyn Operation<T>) -> impl Operation<O> + 'a\nwhere\n    T: 'a,\n{\n    struct BlackBox<'a, T> {\n        operation: &'a mut dyn Operation<T>,\n    }\n\n    impl<T, O> Operation<O> for BlackBox<'_, T> {\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>))\n        where\n            Self: Sized,\n        {\n            self.operation.traverse(&mut |operation| {\n                operate(&mut BlackBox { operation });\n            });\n        }\n\n        fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {\n            self.operation.container(id, bounds);\n        }\n\n        fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {\n            self.operation.focusable(id, bounds, state);\n        }\n\n        fn scrollable(\n            &mut self,\n            id: Option<&Id>,\n            bounds: Rectangle,\n            content_bounds: Rectangle,\n            translation: Vector,\n            state: &mut dyn Scrollable,\n        ) {\n            self.operation\n                .scrollable(id, bounds, content_bounds, translation, state);\n        }\n\n        fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {\n            self.operation.text_input(id, bounds, state);\n        }\n\n        fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {\n            self.operation.text(id, bounds, text);\n        }\n\n        fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {\n            self.operation.custom(id, bounds, state);\n        }\n\n        fn finish(&self) -> Outcome<O> {\n            Outcome::None\n        }\n    }\n\n    BlackBox { operation }\n}\n\n/// Maps the output of an [`Operation`] using the given function.\npub fn map<A, B>(\n    operation: impl Operation<A>,\n    f: impl Fn(A) -> B + Send + Sync + 'static,\n) -> impl Operation<B>\nwhere\n    A: 'static,\n    B: 'static,\n{\n    struct Map<O, A, B> {\n        operation: O,\n        f: Arc<dyn Fn(A) -> B + Send + Sync>,\n    }\n\n    impl<O, A, B> Operation<B> for Map<O, A, B>\n    where\n        O: Operation<A>,\n        A: 'static,\n        B: 'static,\n    {\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {\n            struct MapRef<'a, A> {\n                operation: &'a mut dyn Operation<A>,\n            }\n\n            impl<A, B> Operation<B> for MapRef<'_, A> {\n                fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {\n                    self.operation.traverse(&mut |operation| {\n                        operate(&mut MapRef { operation });\n                    });\n                }\n\n                fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {\n                    let Self { operation, .. } = self;\n\n                    operation.container(id, bounds);\n                }\n\n                fn scrollable(\n                    &mut self,\n                    id: Option<&Id>,\n                    bounds: Rectangle,\n                    content_bounds: Rectangle,\n                    translation: Vector,\n                    state: &mut dyn Scrollable,\n                ) {\n                    self.operation\n                        .scrollable(id, bounds, content_bounds, translation, state);\n                }\n\n                fn focusable(\n                    &mut self,\n                    id: Option<&Id>,\n                    bounds: Rectangle,\n                    state: &mut dyn Focusable,\n                ) {\n                    self.operation.focusable(id, bounds, state);\n                }\n\n                fn text_input(\n                    &mut self,\n                    id: Option<&Id>,\n                    bounds: Rectangle,\n                    state: &mut dyn TextInput,\n                ) {\n                    self.operation.text_input(id, bounds, state);\n                }\n\n                fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {\n                    self.operation.text(id, bounds, text);\n                }\n\n                fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {\n                    self.operation.custom(id, bounds, state);\n                }\n            }\n\n            self.operation.traverse(&mut |operation| {\n                operate(&mut MapRef { operation });\n            });\n        }\n\n        fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {\n            self.operation.container(id, bounds);\n        }\n\n        fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {\n            self.operation.focusable(id, bounds, state);\n        }\n\n        fn scrollable(\n            &mut self,\n            id: Option<&Id>,\n            bounds: Rectangle,\n            content_bounds: Rectangle,\n            translation: Vector,\n            state: &mut dyn Scrollable,\n        ) {\n            self.operation\n                .scrollable(id, bounds, content_bounds, translation, state);\n        }\n\n        fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {\n            self.operation.text_input(id, bounds, state);\n        }\n\n        fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {\n            self.operation.text(id, bounds, text);\n        }\n\n        fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {\n            self.operation.custom(id, bounds, state);\n        }\n\n        fn finish(&self) -> Outcome<B> {\n            match self.operation.finish() {\n                Outcome::None => Outcome::None,\n                Outcome::Some(output) => Outcome::Some((self.f)(output)),\n                Outcome::Chain(next) => Outcome::Chain(Box::new(Map {\n                    operation: next,\n                    f: self.f.clone(),\n                })),\n            }\n        }\n    }\n\n    Map {\n        operation,\n        f: Arc::new(f),\n    }\n}\n\n/// Chains the output of an [`Operation`] with the provided function to\n/// build a new [`Operation`].\npub fn then<A, B, O>(operation: impl Operation<A> + 'static, f: fn(A) -> O) -> impl Operation<B>\nwhere\n    A: 'static,\n    B: Send + 'static,\n    O: Operation<B> + 'static,\n{\n    struct Chain<T, O, A, B>\n    where\n        T: Operation<A>,\n        O: Operation<B>,\n    {\n        operation: T,\n        next: fn(A) -> O,\n        _result: PhantomData<B>,\n    }\n\n    impl<T, O, A, B> Operation<B> for Chain<T, O, A, B>\n    where\n        T: Operation<A> + 'static,\n        O: Operation<B> + 'static,\n        A: 'static,\n        B: Send + 'static,\n    {\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {\n            self.operation.traverse(&mut |operation| {\n                operate(&mut black_box(operation));\n            });\n        }\n\n        fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {\n            self.operation.container(id, bounds);\n        }\n\n        fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {\n            self.operation.focusable(id, bounds, state);\n        }\n\n        fn scrollable(\n            &mut self,\n            id: Option<&Id>,\n            bounds: Rectangle,\n            content_bounds: Rectangle,\n            translation: crate::Vector,\n            state: &mut dyn Scrollable,\n        ) {\n            self.operation\n                .scrollable(id, bounds, content_bounds, translation, state);\n        }\n\n        fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {\n            self.operation.text_input(id, bounds, state);\n        }\n\n        fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {\n            self.operation.text(id, bounds, text);\n        }\n\n        fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {\n            self.operation.custom(id, bounds, state);\n        }\n\n        fn finish(&self) -> Outcome<B> {\n            match self.operation.finish() {\n                Outcome::None => Outcome::None,\n                Outcome::Some(value) => Outcome::Chain(Box::new((self.next)(value))),\n                Outcome::Chain(operation) => Outcome::Chain(Box::new(then(operation, self.next))),\n            }\n        }\n    }\n\n    Chain {\n        operation,\n        next: f,\n        _result: PhantomData,\n    }\n}\n\n/// Produces an [`Operation`] that applies the given [`Operation`] to the\n/// children of a container with the given [`Id`].\npub fn scope<T: 'static>(target: Id, operation: impl Operation<T> + 'static) -> impl Operation<T> {\n    struct ScopedOperation<Message> {\n        target: Id,\n        current: Option<Id>,\n        operation: Box<dyn Operation<Message>>,\n    }\n\n    impl<Message: 'static> Operation<Message> for ScopedOperation<Message> {\n        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<Message>)) {\n            if self.current.as_ref() == Some(&self.target) {\n                self.operation.as_mut().traverse(operate);\n            } else {\n                operate(self);\n            }\n\n            self.current = None;\n        }\n\n        fn container(&mut self, id: Option<&Id>, _bounds: Rectangle) {\n            self.current = id.cloned();\n        }\n\n        fn finish(&self) -> Outcome<Message> {\n            match self.operation.finish() {\n                Outcome::Chain(next) => Outcome::Chain(Box::new(ScopedOperation {\n                    target: self.target.clone(),\n                    current: None,\n                    operation: next,\n                })),\n                outcome => outcome,\n            }\n        }\n    }\n\n    ScopedOperation {\n        target,\n        current: None,\n        operation: Box::new(operation),\n    }\n}\n"
  },
  {
    "path": "core/src/widget/text.rs",
    "content": "//! Text widgets display information through writing.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub fn text<T>(t: T) -> iced_core::widget::Text<'static, iced_core::Theme, ()> { unimplemented!() } }\n//! #            pub use iced_core::color; }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>;\n//! use iced::widget::text;\n//! use iced::color;\n//!\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     text(\"Hello, this is iced!\")\n//!         .size(20)\n//!         .color(color!(0x0000ff))\n//!         .into()\n//! }\n//! ```\nuse crate::alignment;\nuse crate::layout;\nuse crate::mouse;\nuse crate::renderer;\nuse crate::text;\nuse crate::text::paragraph::{self, Paragraph};\nuse crate::widget::tree::{self, Tree};\nuse crate::{Color, Element, Layout, Length, Pixels, Rectangle, Size, Theme, Widget};\n\npub use text::{Alignment, Ellipsis, LineHeight, Shaping, Wrapping};\n\n/// A bunch of text.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub fn text<T>(t: T) -> iced_core::widget::Text<'static, iced_core::Theme, ()> { unimplemented!() } }\n/// #            pub use iced_core::color; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>;\n/// use iced::widget::text;\n/// use iced::color;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     text(\"Hello, this is iced!\")\n///         .size(20)\n///         .color(color!(0x0000ff))\n///         .into()\n/// }\n/// ```\n#[must_use]\npub struct Text<'a, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fragment: text::Fragment<'a>,\n    format: Format<Renderer::Font>,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Theme, Renderer> Text<'a, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// Create a new fragment of [`Text`] with the given contents.\n    pub fn new(fragment: impl text::IntoFragment<'a>) -> Self {\n        Text {\n            fragment: fragment.into_fragment(),\n            format: Format::default(),\n            class: Theme::default(),\n        }\n    }\n\n    /// Sets the size of the [`Text`].\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        self.format.size = Some(size.into());\n        self\n    }\n\n    /// Sets the [`LineHeight`] of the [`Text`].\n    pub fn line_height(mut self, line_height: impl Into<LineHeight>) -> Self {\n        self.format.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the [`Font`] of the [`Text`].\n    ///\n    /// [`Font`]: crate::text::Renderer::Font\n    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {\n        self.format.font = Some(font.into());\n        self\n    }\n\n    /// Sets the [`Font`] of the [`Text`], if `Some`.\n    ///\n    /// [`Font`]: crate::text::Renderer::Font\n    pub fn font_maybe(mut self, font: Option<impl Into<Renderer::Font>>) -> Self {\n        self.format.font = font.map(Into::into);\n        self\n    }\n\n    /// Sets the width of the [`Text`] boundaries.\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.format.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Text`] boundaries.\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.format.height = height.into();\n        self\n    }\n\n    /// Centers the [`Text`], both horizontally and vertically.\n    pub fn center(self) -> Self {\n        self.align_x(alignment::Horizontal::Center)\n            .align_y(alignment::Vertical::Center)\n    }\n\n    /// Sets the [`alignment::Horizontal`] of the [`Text`].\n    pub fn align_x(mut self, alignment: impl Into<text::Alignment>) -> Self {\n        self.format.align_x = alignment.into();\n        self\n    }\n\n    /// Sets the [`alignment::Vertical`] of the [`Text`].\n    pub fn align_y(mut self, alignment: impl Into<alignment::Vertical>) -> Self {\n        self.format.align_y = alignment.into();\n        self\n    }\n\n    /// Sets the [`Shaping`] strategy of the [`Text`].\n    pub fn shaping(mut self, shaping: Shaping) -> Self {\n        self.format.shaping = shaping;\n        self\n    }\n\n    /// Sets the [`Wrapping`] strategy of the [`Text`].\n    pub fn wrapping(mut self, wrapping: Wrapping) -> Self {\n        self.format.wrapping = wrapping;\n        self\n    }\n\n    /// Sets the [`Ellipsis`] strategy of the [`Text`].\n    pub fn ellipsis(mut self, ellipsis: Ellipsis) -> Self {\n        self.format.ellipsis = ellipsis;\n        self\n    }\n\n    /// Sets the style of the [`Text`].\n    pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the [`Color`] of the [`Text`].\n    pub fn color(self, color: impl Into<Color>) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.color_maybe(Some(color))\n    }\n\n    /// Sets the [`Color`] of the [`Text`], if `Some`.\n    pub fn color_maybe(self, color: Option<impl Into<Color>>) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        let color = color.map(Into::into);\n\n        self.style(move |_theme| Style { color })\n    }\n\n    /// Sets the style class of the [`Text`].\n    #[cfg(feature = \"advanced\")]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\n/// The internal state of a [`Text`] widget.\npub type State<P> = paragraph::Plain<P>;\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Text<'_, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State<Renderer::Paragraph>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(paragraph::Plain::<Renderer::Paragraph>::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.format.width,\n            height: self.format.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout(\n            tree.state.downcast_mut::<State<Renderer::Paragraph>>(),\n            renderer,\n            limits,\n            &self.fragment,\n            self.format,\n        )\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        defaults: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor_position: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_ref::<State<Renderer::Paragraph>>();\n        let style = theme.style(&self.class);\n\n        draw(\n            renderer,\n            defaults,\n            layout.bounds(),\n            state.raw(),\n            style,\n            viewport,\n        );\n    }\n\n    fn operate(\n        &mut self,\n        _tree: &mut Tree,\n        layout: Layout<'_>,\n        _renderer: &Renderer,\n        operation: &mut dyn super::Operation,\n    ) {\n        operation.text(None, layout.bounds(), &self.fragment);\n    }\n}\n\n/// The format of some [`Text`].\n///\n/// Check out the methods of the [`Text`] widget\n/// to learn more about each field.\n#[derive(Debug, Clone, Copy)]\n#[allow(missing_docs)]\npub struct Format<Font> {\n    pub width: Length,\n    pub height: Length,\n    pub size: Option<Pixels>,\n    pub font: Option<Font>,\n    pub line_height: LineHeight,\n    pub align_x: text::Alignment,\n    pub align_y: alignment::Vertical,\n    pub shaping: Shaping,\n    pub wrapping: Wrapping,\n    pub ellipsis: Ellipsis,\n}\n\nimpl<Font> Default for Format<Font> {\n    fn default() -> Self {\n        Self {\n            size: None,\n            line_height: LineHeight::default(),\n            font: None,\n            width: Length::Shrink,\n            height: Length::Shrink,\n            align_x: text::Alignment::Default,\n            align_y: alignment::Vertical::Top,\n            shaping: Shaping::default(),\n            wrapping: Wrapping::default(),\n            ellipsis: Ellipsis::default(),\n        }\n    }\n}\n\n/// Produces the [`layout::Node`] of a [`Text`] widget.\npub fn layout<Renderer>(\n    paragraph: &mut paragraph::Plain<Renderer::Paragraph>,\n    renderer: &Renderer,\n    limits: &layout::Limits,\n    content: &str,\n    format: Format<Renderer::Font>,\n) -> layout::Node\nwhere\n    Renderer: text::Renderer,\n{\n    layout::sized(limits, format.width, format.height, |limits| {\n        let bounds = limits.max();\n\n        let size = format.size.unwrap_or_else(|| renderer.default_size());\n        let font = format.font.unwrap_or_else(|| renderer.default_font());\n\n        let _ = paragraph.update(text::Text {\n            content,\n            bounds,\n            size,\n            line_height: format.line_height,\n            font,\n            align_x: format.align_x,\n            align_y: format.align_y,\n            shaping: format.shaping,\n            wrapping: format.wrapping,\n            ellipsis: format.ellipsis,\n            hint_factor: renderer.scale_factor(),\n        });\n\n        paragraph.min_bounds()\n    })\n}\n\n/// Draws text using the same logic as the [`Text`] widget.\npub fn draw<Renderer>(\n    renderer: &mut Renderer,\n    style: &renderer::Style,\n    bounds: Rectangle,\n    paragraph: &Renderer::Paragraph,\n    appearance: Style,\n    viewport: &Rectangle,\n) where\n    Renderer: text::Renderer,\n{\n    let anchor = bounds.anchor(\n        paragraph.min_bounds(),\n        paragraph.align_x(),\n        paragraph.align_y(),\n    );\n\n    renderer.fill_paragraph(\n        paragraph,\n        anchor,\n        appearance.color.unwrap_or(style.text_color),\n        *viewport,\n    );\n}\n\nimpl<'a, Message, Theme, Renderer> From<Text<'a, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n{\n    fn from(text: Text<'a, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(text)\n    }\n}\n\nimpl<'a, Theme, Renderer> From<&'a str> for Text<'a, Theme, Renderer>\nwhere\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer,\n{\n    fn from(content: &'a str) -> Self {\n        Self::new(content)\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<&'a str> for Element<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n{\n    fn from(content: &'a str) -> Self {\n        Text::from(content).into()\n    }\n}\n\n/// The appearance of some text.\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub struct Style {\n    /// The [`Color`] of the text.\n    ///\n    /// The default, `None`, means using the inherited color.\n    pub color: Option<Color>,\n}\n\n/// The theme catalog of a [`Text`].\npub trait Catalog: Sized {\n    /// The item class of this [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by this [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, item: &Self::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`Text`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(|_theme| Style::default())\n    }\n\n    fn style(&self, class: &Self::Class<'_>) -> Style {\n        class(self)\n    }\n}\n\n/// The default text styling; color is inherited.\npub fn default(_theme: &Theme) -> Style {\n    Style { color: None }\n}\n\n/// Text with the default base color.\npub fn base(theme: &Theme) -> Style {\n    Style {\n        color: Some(theme.seed().text),\n    }\n}\n\n/// Text conveying some important information, like an action.\npub fn primary(theme: &Theme) -> Style {\n    Style {\n        color: Some(theme.seed().primary),\n    }\n}\n\n/// Text conveying some secondary information, like a footnote.\npub fn secondary(theme: &Theme) -> Style {\n    Style {\n        color: Some(theme.palette().secondary.base.color),\n    }\n}\n\n/// Text conveying some positive information, like a successful event.\npub fn success(theme: &Theme) -> Style {\n    Style {\n        color: Some(theme.seed().success),\n    }\n}\n\n/// Text conveying some mildly negative information, like a warning.\npub fn warning(theme: &Theme) -> Style {\n    Style {\n        color: Some(theme.seed().warning),\n    }\n}\n\n/// Text conveying some negative information, like an error.\npub fn danger(theme: &Theme) -> Style {\n    Style {\n        color: Some(theme.seed().danger),\n    }\n}\n"
  },
  {
    "path": "core/src/widget/tree.rs",
    "content": "//! Store internal widget state in a state tree to ensure continuity.\nuse crate::Widget;\n\nuse std::any::{self, Any};\nuse std::borrow::Borrow;\nuse std::fmt;\n\n/// A persistent state widget tree.\n///\n/// A [`Tree`] is normally associated with a specific widget in the widget tree.\n#[derive(Debug)]\npub struct Tree {\n    /// The tag of the [`Tree`].\n    pub tag: Tag,\n\n    /// The [`State`] of the [`Tree`].\n    pub state: State,\n\n    /// The children of the root widget of the [`Tree`].\n    pub children: Vec<Tree>,\n}\n\nimpl Tree {\n    /// Creates an empty, stateless [`Tree`] with no children.\n    pub fn empty() -> Self {\n        Self {\n            tag: Tag::stateless(),\n            state: State::None,\n            children: Vec::new(),\n        }\n    }\n\n    /// Creates a new [`Tree`] for the provided [`Widget`].\n    pub fn new<'a, Message, Theme, Renderer>(\n        widget: impl Borrow<dyn Widget<Message, Theme, Renderer> + 'a>,\n    ) -> Self\n    where\n        Renderer: crate::Renderer,\n    {\n        let widget = widget.borrow();\n\n        Self {\n            tag: widget.tag(),\n            state: widget.state(),\n            children: widget.children(),\n        }\n    }\n\n    /// Reconciles the current tree with the provided [`Widget`].\n    ///\n    /// If the tag of the [`Widget`] matches the tag of the [`Tree`], then the\n    /// [`Widget`] proceeds with the reconciliation (i.e. [`Widget::diff`] is called).\n    ///\n    /// Otherwise, the whole [`Tree`] is recreated.\n    ///\n    /// [`Widget::diff`]: crate::Widget::diff\n    pub fn diff<'a, Message, Theme, Renderer>(\n        &mut self,\n        new: impl Borrow<dyn Widget<Message, Theme, Renderer> + 'a>,\n    ) where\n        Renderer: crate::Renderer,\n    {\n        if self.tag == new.borrow().tag() {\n            new.borrow().diff(self);\n        } else {\n            *self = Self::new(new);\n        }\n    }\n\n    /// Reconciles the children of the tree with the provided list of widgets.\n    pub fn diff_children<'a, Message, Theme, Renderer>(\n        &mut self,\n        new_children: &[impl Borrow<dyn Widget<Message, Theme, Renderer> + 'a>],\n    ) where\n        Renderer: crate::Renderer,\n    {\n        self.diff_children_custom(\n            new_children,\n            |tree, widget| tree.diff(widget.borrow()),\n            |widget| Self::new(widget.borrow()),\n        );\n    }\n\n    /// Reconciles the children of the tree with the provided list of widgets using custom\n    /// logic both for diffing and creating new widget state.\n    pub fn diff_children_custom<T>(\n        &mut self,\n        new_children: &[T],\n        diff: impl Fn(&mut Tree, &T),\n        new_state: impl Fn(&T) -> Self,\n    ) {\n        if self.children.len() > new_children.len() {\n            self.children.truncate(new_children.len());\n        }\n\n        for (child_state, new) in self.children.iter_mut().zip(new_children.iter()) {\n            diff(child_state, new);\n        }\n\n        if self.children.len() < new_children.len() {\n            self.children\n                .extend(new_children[self.children.len()..].iter().map(new_state));\n        }\n    }\n}\n\n/// Reconciles the `current_children` with the provided list of widgets using\n/// custom logic both for diffing and creating new widget state.\n///\n/// The algorithm will try to minimize the impact of diffing by querying the\n/// `maybe_changed` closure.\npub fn diff_children_custom_with_search<T>(\n    current_children: &mut Vec<Tree>,\n    new_children: &[T],\n    diff: impl Fn(&mut Tree, &T),\n    maybe_changed: impl Fn(usize) -> bool,\n    new_state: impl Fn(&T) -> Tree,\n) {\n    if new_children.is_empty() {\n        current_children.clear();\n        return;\n    }\n\n    if current_children.is_empty() {\n        current_children.extend(new_children.iter().map(new_state));\n        return;\n    }\n\n    let first_maybe_changed = maybe_changed(0);\n    let last_maybe_changed = maybe_changed(current_children.len() - 1);\n\n    if current_children.len() > new_children.len() {\n        if !first_maybe_changed && last_maybe_changed {\n            current_children.truncate(new_children.len());\n        } else {\n            let difference_index = if first_maybe_changed {\n                0\n            } else {\n                (1..current_children.len())\n                    .find(|&i| maybe_changed(i))\n                    .unwrap_or(0)\n            };\n\n            let _ = current_children.splice(\n                difference_index..difference_index + (current_children.len() - new_children.len()),\n                std::iter::empty(),\n            );\n        }\n    }\n\n    if current_children.len() < new_children.len() {\n        let first_maybe_changed = maybe_changed(0);\n        let last_maybe_changed = maybe_changed(current_children.len() - 1);\n\n        if !first_maybe_changed && last_maybe_changed {\n            current_children.extend(new_children[current_children.len()..].iter().map(new_state));\n        } else {\n            let difference_index = if first_maybe_changed {\n                0\n            } else {\n                (1..current_children.len())\n                    .find(|&i| maybe_changed(i))\n                    .unwrap_or(0)\n            };\n\n            let _ = current_children.splice(\n                difference_index..difference_index,\n                new_children[difference_index\n                    ..difference_index + (new_children.len() - current_children.len())]\n                    .iter()\n                    .map(new_state),\n            );\n        }\n    }\n\n    // TODO: Merge loop with extend logic (?)\n    for (child_state, new) in current_children.iter_mut().zip(new_children.iter()) {\n        diff(child_state, new);\n    }\n}\n\n/// The identifier of some widget state.\n#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]\npub struct Tag(any::TypeId);\n\nimpl Tag {\n    /// Creates a [`Tag`] for a state of type `T`.\n    pub fn of<T>() -> Self\n    where\n        T: 'static,\n    {\n        Self(any::TypeId::of::<T>())\n    }\n\n    /// Creates a [`Tag`] for a stateless widget.\n    pub fn stateless() -> Self {\n        Self::of::<()>()\n    }\n}\n\n/// The internal [`State`] of a widget.\npub enum State {\n    /// No meaningful internal state.\n    None,\n\n    /// Some meaningful internal state.\n    Some(Box<dyn Any>),\n}\n\nimpl State {\n    /// Creates a new [`State`].\n    pub fn new<T>(state: T) -> Self\n    where\n        T: 'static,\n    {\n        State::Some(Box::new(state))\n    }\n\n    /// Downcasts the [`State`] to `T` and returns a reference to it.\n    ///\n    /// # Panics\n    /// This method will panic if the downcast fails or the [`State`] is [`State::None`].\n    pub fn downcast_ref<T>(&self) -> &T\n    where\n        T: 'static,\n    {\n        match self {\n            State::None => panic!(\"Downcast on stateless state\"),\n            State::Some(state) => state.downcast_ref().expect(\"Downcast widget state\"),\n        }\n    }\n\n    /// Downcasts the [`State`] to `T` and returns a mutable reference to it.\n    ///\n    /// # Panics\n    /// This method will panic if the downcast fails or the [`State`] is [`State::None`].\n    pub fn downcast_mut<T>(&mut self) -> &mut T\n    where\n        T: 'static,\n    {\n        match self {\n            State::None => panic!(\"Downcast on stateless state\"),\n            State::Some(state) => state.downcast_mut().expect(\"Downcast widget state\"),\n        }\n    }\n}\n\nimpl fmt::Debug for State {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::None => write!(f, \"State::None\"),\n            Self::Some(_) => write!(f, \"State::Some\"),\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/widget.rs",
    "content": "//! Create custom widgets and operate on them.\npub mod operation;\npub mod text;\npub mod tree;\n\nmod id;\n\npub use id::Id;\npub use operation::Operation;\npub use text::Text;\npub use tree::Tree;\n\nuse crate::layout::{self, Layout};\nuse crate::mouse;\nuse crate::overlay;\nuse crate::renderer;\nuse crate::{Event, Length, Rectangle, Shell, Size, Vector};\n\n/// A component that displays information and allows interaction.\n///\n/// If you want to build your own widgets, you will need to implement this\n/// trait.\n///\n/// # Examples\n/// The repository has some [examples] showcasing how to implement a custom\n/// widget:\n///\n/// - [`custom_widget`], a demonstration of how to build a custom widget that\n///   draws a circle.\n/// - [`geometry`], a custom widget showcasing how to draw geometry with the\n///   `Mesh2D` primitive in [`iced_wgpu`].\n///\n/// [examples]: https://github.com/iced-rs/iced/tree/master/examples\n/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/master/examples/custom_widget\n/// [`geometry`]: https://github.com/iced-rs/iced/tree/master/examples/geometry\n/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/master/wgpu\npub trait Widget<Message, Theme, Renderer>\nwhere\n    Renderer: crate::Renderer,\n{\n    /// Returns the [`Size`] of the [`Widget`] in lengths.\n    fn size(&self) -> Size<Length>;\n\n    /// Returns a [`Size`] hint for laying out the [`Widget`].\n    ///\n    /// This hint may be used by some widget containers to adjust their sizing strategy\n    /// during construction.\n    fn size_hint(&self) -> Size<Length> {\n        self.size()\n    }\n\n    /// Returns the [`layout::Node`] of the [`Widget`].\n    ///\n    /// This [`layout::Node`] is used by the runtime to compute the [`Layout`] of the\n    /// user interface.\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node;\n\n    /// Draws the [`Widget`] using the associated `Renderer`.\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    );\n\n    /// Returns the [`Tag`] of the [`Widget`].\n    ///\n    /// [`Tag`]: tree::Tag\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::stateless()\n    }\n\n    /// Returns the [`State`] of the [`Widget`].\n    ///\n    /// [`State`]: tree::State\n    fn state(&self) -> tree::State {\n        tree::State::None\n    }\n\n    /// Returns the state [`Tree`] of the children of the [`Widget`].\n    fn children(&self) -> Vec<Tree> {\n        Vec::new()\n    }\n\n    /// Reconciles the [`Widget`] with the provided [`Tree`].\n    fn diff(&self, tree: &mut Tree) {\n        tree.children.clear();\n    }\n\n    /// Applies an [`Operation`] to the [`Widget`].\n    fn operate(\n        &mut self,\n        _tree: &mut Tree,\n        _layout: Layout<'_>,\n        _renderer: &Renderer,\n        _operation: &mut dyn Operation,\n    ) {\n    }\n\n    /// Processes a runtime [`Event`].\n    ///\n    /// By default, it does nothing.\n    fn update(\n        &mut self,\n        _tree: &mut Tree,\n        _event: &Event,\n        _layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        _shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n    }\n\n    /// Returns the current [`mouse::Interaction`] of the [`Widget`].\n    ///\n    /// By default, it returns [`mouse::Interaction::None`].\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        _layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        mouse::Interaction::None\n    }\n\n    /// Returns the overlay of the [`Widget`], if there is any.\n    fn overlay<'a>(\n        &'a mut self,\n        _tree: &'a mut Tree,\n        _layout: Layout<'a>,\n        _renderer: &Renderer,\n        _viewport: &Rectangle,\n        _translation: Vector,\n    ) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {\n        None\n    }\n}\n"
  },
  {
    "path": "core/src/window/direction.rs",
    "content": "/// The cardinal directions relative to the center of a window.\n#[derive(Debug, Clone, Copy)]\npub enum Direction {\n    /// Points to the top edge of a window.\n    North,\n\n    /// Points to the bottom edge of a window.\n    South,\n\n    /// Points to the right edge of a window.\n    East,\n\n    /// Points to the left edge of a window.\n    West,\n\n    /// Points to the top-right corner of a window.\n    NorthEast,\n\n    /// Points to the top-left corner of a window.\n    NorthWest,\n\n    /// Points to the bottom-right corner of a window.\n    SouthEast,\n\n    /// Points to the bottom-left corner of a window.\n    SouthWest,\n}\n"
  },
  {
    "path": "core/src/window/event.rs",
    "content": "use crate::time::Instant;\nuse crate::{Point, Size};\n\nuse std::path::PathBuf;\n\n/// A window-related event.\n#[derive(PartialEq, Clone, Debug)]\npub enum Event {\n    /// A window was opened.\n    Opened {\n        /// The position of the opened window. This is relative to the top-left corner of the desktop\n        /// the window is on, including virtual desktops. Refers to window's \"outer\" position,\n        /// or the window area, in logical pixels.\n        ///\n        /// **Note**: Not available in Wayland.\n        position: Option<Point>,\n        /// The size of the created window. This is its \"inner\" size, or the size of the\n        /// client area, in logical pixels.\n        size: Size,\n        /// The scale factor of the created window.\n        scale_factor: f32,\n    },\n\n    /// A window was closed.\n    Closed,\n\n    /// A window was moved.\n    Moved(Point),\n\n    /// A window was resized.\n    Resized(Size),\n\n    /// A window changed its scale factor.\n    Rescaled(f32),\n\n    /// A window redraw was requested.\n    ///\n    /// The [`Instant`] contains the current time.\n    RedrawRequested(Instant),\n\n    /// The user has requested for the window to close.\n    CloseRequested,\n\n    /// A window was focused.\n    Focused,\n\n    /// A window was unfocused.\n    Unfocused,\n\n    /// A file is being hovered over the window.\n    ///\n    /// When the user hovers multiple files at once, this event will be emitted\n    /// for each file separately.\n    ///\n    /// ## Platform-specific\n    ///\n    /// - **Wayland:** Not implemented.\n    FileHovered(PathBuf),\n\n    /// A file has been dropped into the window.\n    ///\n    /// When the user drops multiple files at once, this event will be emitted\n    /// for each file separately.\n    ///\n    /// ## Platform-specific\n    ///\n    /// - **Wayland:** Not implemented.\n    FileDropped(PathBuf),\n\n    /// A file was hovered, but has exited the window.\n    ///\n    /// There will be a single `FilesHoveredLeft` event triggered even if\n    /// multiple files were hovered.\n    ///\n    /// ## Platform-specific\n    ///\n    /// - **Wayland:** Not implemented.\n    FilesHoveredLeft,\n}\n"
  },
  {
    "path": "core/src/window/icon.rs",
    "content": "//! Change the icon of a window.\nuse crate::Size;\n\nuse std::mem;\n\n/// Builds an  [`Icon`] from its RGBA pixels in the `sRGB` color space.\npub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Icon, Error> {\n    const PIXEL_SIZE: usize = mem::size_of::<u8>() * 4;\n\n    if !rgba.len().is_multiple_of(PIXEL_SIZE) {\n        return Err(Error::ByteCountNotDivisibleBy4 {\n            byte_count: rgba.len(),\n        });\n    }\n\n    let pixel_count = rgba.len() / PIXEL_SIZE;\n\n    if pixel_count != (width * height) as usize {\n        return Err(Error::DimensionsVsPixelCount {\n            width,\n            height,\n            width_x_height: (width * height) as usize,\n            pixel_count,\n        });\n    }\n\n    Ok(Icon {\n        rgba,\n        size: Size::new(width, height),\n    })\n}\n\n/// An window icon normally used for the titlebar or taskbar.\n#[derive(Clone)]\npub struct Icon {\n    rgba: Vec<u8>,\n    size: Size<u32>,\n}\n\nimpl Icon {\n    /// Returns the raw data of the [`Icon`].\n    pub fn into_raw(self) -> (Vec<u8>, Size<u32>) {\n        (self.rgba, self.size)\n    }\n}\n\nimpl std::fmt::Debug for Icon {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Icon\")\n            .field(\"rgba\", &format!(\"{} pixels\", self.rgba.len() / 4))\n            .field(\"size\", &self.size)\n            .finish()\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\n/// An error produced when using [`from_rgba`] with invalid arguments.\npub enum Error {\n    /// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be\n    /// safely interpreted as 32bpp RGBA pixels.\n    #[error(\n        \"The provided RGBA data (with length {byte_count}) isn't divisible \\\n        by 4. Therefore, it cannot be safely interpreted as 32bpp RGBA pixels\"\n    )]\n    ByteCountNotDivisibleBy4 {\n        /// The length of the provided RGBA data.\n        byte_count: usize,\n    },\n    /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.\n    /// At least one of your arguments is incorrect.\n    #[error(\n        \"The number of RGBA pixels ({pixel_count}) does not match the \\\n        provided dimensions ({width}x{height}).\"\n    )]\n    DimensionsVsPixelCount {\n        /// The provided width.\n        width: u32,\n        /// The provided height.\n        height: u32,\n        /// The product of `width` and `height`.\n        width_x_height: usize,\n        /// The amount of pixels of the provided RGBA data.\n        pixel_count: usize,\n    },\n}\n"
  },
  {
    "path": "core/src/window/id.rs",
    "content": "use std::fmt;\nuse std::hash::Hash;\nuse std::sync::atomic::{self, AtomicU64};\n\n/// The id of the window.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct Id(u64);\n\nstatic COUNT: AtomicU64 = AtomicU64::new(1);\n\nimpl Id {\n    /// Creates a new unique window [`Id`].\n    pub fn unique() -> Id {\n        Id(COUNT.fetch_add(1, atomic::Ordering::Relaxed))\n    }\n}\n\nimpl fmt::Display for Id {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.0.fmt(f)\n    }\n}\n"
  },
  {
    "path": "core/src/window/level.rs",
    "content": "/// A window level groups windows with respect to their z-position.\n///\n/// The relative ordering between windows in different window levels is fixed.\n/// The z-order of a window within the same window level may change dynamically\n/// on user interaction.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum Level {\n    /// The default behavior.\n    #[default]\n    Normal,\n\n    /// The window will always be below normal windows.\n    ///\n    /// This is useful for a widget-based app.\n    AlwaysOnBottom,\n\n    /// The window will always be on top of normal windows.\n    AlwaysOnTop,\n}\n"
  },
  {
    "path": "core/src/window/mode.rs",
    "content": "/// The mode of a window-based application.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Mode {\n    /// The application appears in its own window.\n    Windowed,\n\n    /// The application takes the whole screen of its current monitor.\n    Fullscreen,\n\n    /// The application is hidden\n    Hidden,\n}\n"
  },
  {
    "path": "core/src/window/position.rs",
    "content": "use crate::{Point, Size};\n\n/// The position of a window in a given screen.\n#[derive(Debug, Clone, Copy, Default)]\npub enum Position {\n    /// The platform-specific default position for a new window.\n    #[default]\n    Default,\n    /// The window is completely centered on the screen.\n    Centered,\n    /// The window is positioned with specific coordinates: `(X, Y)`.\n    ///\n    /// When the decorations of the window are enabled, Windows 10 will add some\n    /// invisible padding to the window. This padding gets included in the\n    /// position. So if you have decorations enabled and want the window to be\n    /// at (0, 0) you would have to set the position to\n    /// `(PADDING_X, PADDING_Y)`.\n    Specific(Point),\n    /// Like [`Specific`], but the window is positioned with the specific coordinates returned by the function.\n    ///\n    /// The function receives the window size and the monitor's resolution as input.\n    ///\n    /// [`Specific`]: Self::Specific\n    SpecificWith(fn(Size, Size) -> Point),\n}\n"
  },
  {
    "path": "core/src/window/redraw_request.rs",
    "content": "use crate::time::Instant;\n\n/// A request to redraw a window.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]\npub enum RedrawRequest {\n    /// Redraw the next frame.\n    NextFrame,\n\n    /// Redraw at the given time.\n    At(Instant),\n\n    /// No redraw is needed.\n    Wait,\n}\n\nimpl From<Instant> for RedrawRequest {\n    fn from(time: Instant) -> Self {\n        Self::At(time)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::time::Duration;\n\n    #[test]\n    fn ordering() {\n        let now = Instant::now();\n        let later = now + Duration::from_millis(10);\n\n        assert_eq!(RedrawRequest::NextFrame, RedrawRequest::NextFrame);\n        assert_eq!(RedrawRequest::At(now), RedrawRequest::At(now));\n\n        assert!(RedrawRequest::NextFrame < RedrawRequest::At(now));\n        assert!(RedrawRequest::At(now) > RedrawRequest::NextFrame);\n        assert!(RedrawRequest::At(now) < RedrawRequest::At(later));\n        assert!(RedrawRequest::At(later) > RedrawRequest::At(now));\n\n        assert!(RedrawRequest::NextFrame <= RedrawRequest::NextFrame);\n        assert!(RedrawRequest::NextFrame <= RedrawRequest::At(now));\n        assert!(RedrawRequest::At(now) >= RedrawRequest::NextFrame);\n        assert!(RedrawRequest::At(now) <= RedrawRequest::At(now));\n        assert!(RedrawRequest::At(now) <= RedrawRequest::At(later));\n        assert!(RedrawRequest::At(later) >= RedrawRequest::At(now));\n\n        assert!(RedrawRequest::Wait > RedrawRequest::NextFrame);\n        assert!(RedrawRequest::Wait > RedrawRequest::At(later));\n    }\n}\n"
  },
  {
    "path": "core/src/window/screenshot.rs",
    "content": "//! Take screenshots of a window.\nuse crate::{Bytes, Rectangle, Size};\n\nuse std::fmt::{Debug, Formatter};\n\n/// Data of a screenshot, captured with `window::screenshot()`.\n///\n/// The `bytes` of this screenshot will always be ordered as `RGBA` in the `sRGB` color space.\n#[derive(Clone)]\npub struct Screenshot {\n    /// The RGBA bytes of the [`Screenshot`].\n    pub rgba: Bytes,\n    /// The size of the [`Screenshot`] in physical pixels.\n    pub size: Size<u32>,\n    /// The scale factor of the [`Screenshot`]. This can be useful when converting between widget\n    /// bounds (which are in logical pixels) to crop screenshots.\n    pub scale_factor: f32,\n}\n\nimpl Debug for Screenshot {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"Screenshot: {{ \\n bytes: {}\\n scale: {}\\n size: {:?} }}\",\n            self.rgba.len(),\n            self.scale_factor,\n            self.size\n        )\n    }\n}\n\nimpl Screenshot {\n    /// Creates a new [`Screenshot`].\n    pub fn new(rgba: impl Into<Bytes>, size: Size<u32>, scale_factor: f32) -> Self {\n        Self {\n            rgba: rgba.into(),\n            size,\n            scale_factor,\n        }\n    }\n\n    /// Crops a [`Screenshot`] to the provided `region`. This will always be relative to the\n    /// top-left corner of the [`Screenshot`].\n    pub fn crop(&self, region: Rectangle<u32>) -> Result<Self, CropError> {\n        if region.width == 0 || region.height == 0 {\n            return Err(CropError::Zero);\n        }\n\n        if region.x + region.width > self.size.width || region.y + region.height > self.size.height\n        {\n            return Err(CropError::OutOfBounds);\n        }\n\n        // Image is always RGBA8 = 4 bytes per pixel\n        const PIXEL_SIZE: usize = 4;\n\n        let bytes_per_row = self.size.width as usize * PIXEL_SIZE;\n        let row_range = region.y as usize..(region.y + region.height) as usize;\n        let column_range =\n            region.x as usize * PIXEL_SIZE..(region.x + region.width) as usize * PIXEL_SIZE;\n\n        let chopped =\n            self.rgba\n                .chunks(bytes_per_row)\n                .enumerate()\n                .fold(vec![], |mut acc, (row, bytes)| {\n                    if row_range.contains(&row) {\n                        acc.extend(&bytes[column_range.clone()]);\n                    }\n\n                    acc\n                });\n\n        Ok(Self {\n            rgba: Bytes::from(chopped),\n            size: Size::new(region.width, region.height),\n            scale_factor: self.scale_factor,\n        })\n    }\n}\n\nimpl AsRef<[u8]> for Screenshot {\n    fn as_ref(&self) -> &[u8] {\n        &self.rgba\n    }\n}\n\nimpl From<Screenshot> for Bytes {\n    fn from(screenshot: Screenshot) -> Self {\n        screenshot.rgba\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\n/// Errors that can occur when cropping a [`Screenshot`].\npub enum CropError {\n    #[error(\"The cropped region is out of bounds.\")]\n    /// The cropped region's size is out of bounds.\n    OutOfBounds,\n    #[error(\"The cropped region is not visible.\")]\n    /// The cropped region's size is zero.\n    Zero,\n}\n"
  },
  {
    "path": "core/src/window/settings/linux.rs",
    "content": "//! Platform specific settings for Linux.\n\n/// The platform specific window settings of an application.\n#[derive(Debug, Clone, PartialEq, Eq, Default)]\npub struct PlatformSpecific {\n    /// Sets the application id of the window.\n    ///\n    /// As a best practice, it is suggested to select an application id that match\n    /// the basename of the application’s .desktop file.\n    pub application_id: String,\n\n    /// Whether bypass the window manager mapping for x11 windows\n    ///\n    /// This flag is particularly useful for creating UI elements that need precise\n    /// positioning and immediate display without window manager interference.\n    pub override_redirect: bool,\n}\n"
  },
  {
    "path": "core/src/window/settings/macos.rs",
    "content": "//! Platform specific settings for macOS.\n\n/// The platform specific window settings of an application.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub struct PlatformSpecific {\n    /// Hides the window title.\n    pub title_hidden: bool,\n    /// Makes the titlebar transparent and allows the content to appear behind it.\n    pub titlebar_transparent: bool,\n    /// Makes the window content appear behind the titlebar.\n    pub fullsize_content_view: bool,\n}\n"
  },
  {
    "path": "core/src/window/settings/other.rs",
    "content": "/// The platform specific window settings of an application.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub struct PlatformSpecific;\n"
  },
  {
    "path": "core/src/window/settings/wasm.rs",
    "content": "//! Platform specific settings for WebAssembly.\n\n/// The platform specific window settings of an application.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct PlatformSpecific {\n    /// The identifier of a DOM element that will be replaced with the\n    /// application.\n    ///\n    /// If set to `None`, the application will be appended to the HTML body.\n    ///\n    /// By default, it is set to `\"iced\"`.\n    pub target: Option<String>,\n}\n\nimpl Default for PlatformSpecific {\n    fn default() -> Self {\n        Self {\n            target: Some(String::from(\"iced\")),\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/window/settings/windows.rs",
    "content": "//! Platform specific settings for Windows.\n\n/// The platform specific window settings of an application.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub struct PlatformSpecific {\n    /// Drag and drop support\n    pub drag_and_drop: bool,\n\n    /// Whether show or hide the window icon in the taskbar.\n    pub skip_taskbar: bool,\n\n    /// Shows or hides the background drop shadow for undecorated windows.\n    ///\n    /// The shadow is hidden by default.\n    /// Enabling the shadow causes a thin 1px line to appear on the top of the window.\n    pub undecorated_shadow: bool,\n\n    /// Sets the preferred style of the window corners.\n    ///\n    /// Supported starting with Windows 11 Build 22000.\n    pub corner_preference: CornerPreference,\n}\n\nimpl Default for PlatformSpecific {\n    fn default() -> Self {\n        Self {\n            drag_and_drop: true,\n            skip_taskbar: false,\n            undecorated_shadow: false,\n            corner_preference: Default::default(),\n        }\n    }\n}\n\n/// Describes how the corners of a window should look like.\n#[repr(i32)]\n#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]\npub enum CornerPreference {\n    /// Corresponds to `DWMWCP_DEFAULT`.\n    ///\n    /// Let the system decide when to round window corners.\n    #[default]\n    Default = 0,\n\n    /// Corresponds to `DWMWCP_DONOTROUND`.\n    ///\n    /// Never round window corners.\n    DoNotRound = 1,\n\n    /// Corresponds to `DWMWCP_ROUND`.\n    ///\n    /// Round the corners, if appropriate.\n    Round = 2,\n\n    /// Corresponds to `DWMWCP_ROUNDSMALL`.\n    ///\n    /// Round the corners if appropriate, with a small radius.\n    RoundSmall = 3,\n}\n"
  },
  {
    "path": "core/src/window/settings.rs",
    "content": "//! Configure your windows.\n#[cfg(target_os = \"windows\")]\n#[path = \"settings/windows.rs\"]\npub mod platform;\n\n#[cfg(target_os = \"macos\")]\n#[path = \"settings/macos.rs\"]\nmod platform;\n\n#[cfg(target_os = \"linux\")]\n#[path = \"settings/linux.rs\"]\nmod platform;\n\n#[cfg(target_arch = \"wasm32\")]\n#[path = \"settings/wasm.rs\"]\nmod platform;\n\n#[cfg(not(any(\n    target_os = \"windows\",\n    target_os = \"macos\",\n    target_os = \"linux\",\n    target_arch = \"wasm32\"\n)))]\n#[path = \"settings/other.rs\"]\nmod platform;\n\nuse crate::Size;\nuse crate::window::{Icon, Level, Position};\n\npub use platform::PlatformSpecific;\n\n/// The window settings of an application.\n#[derive(Debug, Clone)]\npub struct Settings {\n    /// The initial logical dimensions of the window.\n    pub size: Size,\n\n    /// Whether the window should start maximized.\n    pub maximized: bool,\n\n    /// Whether the window should start fullscreen.\n    pub fullscreen: bool,\n\n    /// The initial position of the window.\n    pub position: Position,\n\n    /// The minimum size of the window.\n    pub min_size: Option<Size>,\n\n    /// The maximum size of the window.\n    pub max_size: Option<Size>,\n\n    /// Whether the window should be visible or not.\n    pub visible: bool,\n\n    /// Whether the window should be resizable or not.\n    pub resizable: bool,\n\n    /// Whether the title bar has Close button or not\n    pub closeable: bool,\n\n    /// Whether the title bar has Minimize button or not\n    pub minimizable: bool,\n\n    /// Whether the window should have a border, a title bar, etc. or not.\n    pub decorations: bool,\n\n    /// Whether the window should be transparent.\n    pub transparent: bool,\n\n    /// Whether the window should have blurry background.\n    ///\n    /// Note that the blurry effect is applied to the transparent window. You need to enable\n    /// [`Settings::transparent`] and set a proper opacity value to the background color with\n    /// `Application::style`.\n    ///\n    /// This option is only supported on macOS and Linux. Please read the [winit document][winit]\n    /// for more details.\n    ///\n    /// [winit]: https://docs.rs/winit/0.30/winit/window/struct.Window.html#method.set_blur\n    pub blur: bool,\n\n    /// The window [`Level`].\n    pub level: Level,\n\n    /// The icon of the window.\n    pub icon: Option<Icon>,\n\n    /// Platform specific settings.\n    pub platform_specific: PlatformSpecific,\n\n    /// Whether the window will close when the user requests it, e.g. when a user presses the\n    /// close button.\n    ///\n    /// This can be useful if you want to have some behavior that executes before the window is\n    /// actually destroyed. If you disable this, you must manually close the window with the\n    /// `window::close` command.\n    ///\n    /// By default this is enabled.\n    pub exit_on_close_request: bool,\n}\n\nimpl Default for Settings {\n    fn default() -> Self {\n        Self {\n            size: Size::new(1024.0, 768.0),\n            maximized: false,\n            fullscreen: false,\n            position: Position::default(),\n            min_size: None,\n            max_size: None,\n            visible: true,\n            resizable: true,\n            minimizable: true,\n            closeable: true,\n            decorations: true,\n            transparent: false,\n            blur: false,\n            level: Level::default(),\n            icon: None,\n            exit_on_close_request: true,\n            platform_specific: PlatformSpecific::default(),\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/window/user_attention.rs",
    "content": "/// The type of user attention to request.\n///\n/// ## Platform-specific\n///\n/// - **X11:** Sets the WM's `XUrgencyHint`. No distinction between [`Critical`] and [`Informational`].\n///\n/// [`Critical`]: Self::Critical\n/// [`Informational`]: Self::Informational\n#[derive(Debug, Clone, Copy)]\npub enum UserAttention {\n    /// ## Platform-specific\n    ///\n    /// - **macOS:** Bounces the dock icon until the application is in focus.\n    /// - **Windows:** Flashes both the window and the taskbar button until the application is in focus.\n    Critical,\n    /// ## Platform-specific\n    ///\n    /// - **macOS:** Bounces the dock icon once.\n    /// - **Windows:** Flashes the taskbar button until the application is in focus.\n    Informational,\n}\n"
  },
  {
    "path": "core/src/window.rs",
    "content": "//! Build window-based GUI applications.\npub mod icon;\npub mod screenshot;\npub mod settings;\n\nmod direction;\nmod event;\nmod id;\nmod level;\nmod mode;\nmod position;\nmod redraw_request;\nmod user_attention;\n\npub use direction::Direction;\npub use event::Event;\npub use icon::Icon;\npub use id::Id;\npub use level::Level;\npub use mode::Mode;\npub use position::Position;\npub use redraw_request::RedrawRequest;\npub use screenshot::Screenshot;\npub use settings::Settings;\npub use user_attention::UserAttention;\n"
  },
  {
    "path": "debug/Cargo.toml",
    "content": "[package]\nname = \"iced_debug\"\ndescription = \"A pluggable API for debugging iced applications\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[features]\nenable = [\"dep:iced_beacon\"]\nhot = [\"enable\", \"dep:cargo-hot\"]\n\n[dependencies]\niced_core.workspace = true\niced_futures.workspace = true\nlog.workspace = true\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\niced_beacon.workspace = true\niced_beacon.optional = true\n\ncargo-hot.workspace = true\ncargo-hot.optional = true\n"
  },
  {
    "path": "debug/src/lib.rs",
    "content": "pub use iced_core as core;\npub use iced_futures as futures;\n\nuse crate::core::theme::palette;\nuse crate::core::window;\nuse crate::futures::Subscription;\n\npub use internal::Span;\n\n#[derive(Debug, Clone, Copy)]\npub struct Metadata {\n    pub name: &'static str,\n    pub theme: Option<palette::Seed>,\n    pub can_time_travel: bool,\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum Primitive {\n    Quad,\n    Triangle,\n    Shader,\n    Image,\n    Text,\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum Command {\n    RewindTo { message: usize },\n    GoLive,\n}\n\npub fn enable() {\n    internal::enable();\n}\n\npub fn disable() {\n    internal::disable();\n}\n\npub fn init(metadata: Metadata) {\n    internal::init(metadata);\n    hot::init();\n}\n\npub fn quit() -> bool {\n    internal::quit()\n}\n\npub fn theme_changed(f: impl FnOnce() -> Option<palette::Seed>) {\n    internal::theme_changed(f);\n}\n\npub fn tasks_spawned(amount: usize) {\n    internal::tasks_spawned(amount);\n}\n\npub fn subscriptions_tracked(amount: usize) {\n    internal::subscriptions_tracked(amount);\n}\n\npub fn layers_rendered(amount: impl FnOnce() -> usize) {\n    internal::layers_rendered(amount);\n}\n\npub fn boot() -> Span {\n    internal::boot()\n}\n\npub fn update(message: &impl std::fmt::Debug) -> Span {\n    internal::update(message)\n}\n\npub fn view(window: window::Id) -> Span {\n    internal::view(window)\n}\n\npub fn layout(window: window::Id) -> Span {\n    internal::layout(window)\n}\n\npub fn interact(window: window::Id) -> Span {\n    internal::interact(window)\n}\n\npub fn draw(window: window::Id) -> Span {\n    internal::draw(window)\n}\n\npub fn prepare(primitive: Primitive) -> Span {\n    internal::prepare(primitive)\n}\n\npub fn render(primitive: Primitive) -> Span {\n    internal::render(primitive)\n}\n\npub fn present(window: window::Id) -> Span {\n    internal::present(window)\n}\n\npub fn time(name: impl Into<String>) -> Span {\n    internal::time(name)\n}\n\npub fn time_with<T>(name: impl Into<String>, f: impl FnOnce() -> T) -> T {\n    let span = time(name);\n    let result = f();\n    span.finish();\n\n    result\n}\n\npub fn commands() -> Subscription<Command> {\n    internal::commands()\n}\n\npub fn hot<O>(f: impl FnOnce() -> O) -> O {\n    hot::call(f)\n}\n\npub fn on_hotpatch(f: impl Fn() + Send + Sync + 'static) {\n    hot::on_hotpatch(f)\n}\n\npub fn is_stale() -> bool {\n    hot::is_stale()\n}\n\n#[cfg(all(feature = \"enable\", not(target_arch = \"wasm32\")))]\nmod internal {\n    use crate::core::theme::palette;\n    use crate::core::time::Instant;\n    use crate::core::window;\n    use crate::futures::Subscription;\n    use crate::futures::futures::Stream;\n    use crate::{Command, Metadata, Primitive};\n\n    use iced_beacon as beacon;\n\n    use beacon::client::{self, Client};\n    use beacon::span;\n    use beacon::span::present;\n\n    use std::sync::atomic::{self, AtomicBool, AtomicUsize};\n    use std::sync::{LazyLock, RwLock};\n\n    pub fn init(metadata: Metadata) {\n        let name = metadata.name.split(\"::\").next().unwrap_or(metadata.name);\n\n        *METADATA.write().expect(\"Write application metadata\") = client::Metadata {\n            name,\n            theme: metadata.theme,\n            can_time_travel: metadata.can_time_travel,\n        };\n    }\n\n    pub fn quit() -> bool {\n        if BEACON.is_connected() {\n            BEACON.quit();\n\n            true\n        } else {\n            false\n        }\n    }\n\n    pub fn theme_changed(f: impl FnOnce() -> Option<palette::Seed>) {\n        let Some(palette) = f() else {\n            return;\n        };\n\n        if METADATA.read().expect(\"Read last palette\").theme.as_ref() != Some(&palette) {\n            log(client::Event::ThemeChanged(palette));\n\n            METADATA.write().expect(\"Write last palette\").theme = Some(palette);\n        }\n    }\n\n    pub fn tasks_spawned(amount: usize) {\n        log(client::Event::CommandsSpawned(amount));\n    }\n\n    pub fn subscriptions_tracked(amount: usize) {\n        log(client::Event::SubscriptionsTracked(amount));\n    }\n\n    pub fn layers_rendered(amount: impl FnOnce() -> usize) {\n        log(client::Event::LayersRendered(amount()));\n    }\n\n    pub fn boot() -> Span {\n        span(span::Stage::Boot)\n    }\n\n    pub fn update(message: &impl std::fmt::Debug) -> Span {\n        let span = span(span::Stage::Update);\n\n        let number = LAST_UPDATE.fetch_add(1, atomic::Ordering::Relaxed);\n\n        let start = Instant::now();\n        let message = format!(\"{message:?}\");\n        let elapsed = start.elapsed();\n\n        if elapsed.as_millis() >= 1 {\n            log::warn!(\"Slow `Debug` implementation of `Message` (took {elapsed:?})!\");\n        }\n\n        let message = if message.len() > 49 {\n            message\n                .chars()\n                .take(49)\n                .chain(\"...\".chars())\n                .collect::<String>()\n        } else {\n            message\n        };\n\n        log(client::Event::MessageLogged { number, message });\n\n        span\n    }\n\n    pub fn view(window: window::Id) -> Span {\n        span(span::Stage::View(window))\n    }\n\n    pub fn layout(window: window::Id) -> Span {\n        span(span::Stage::Layout(window))\n    }\n\n    pub fn interact(window: window::Id) -> Span {\n        span(span::Stage::Interact(window))\n    }\n\n    pub fn draw(window: window::Id) -> Span {\n        span(span::Stage::Draw(window))\n    }\n\n    pub fn prepare(primitive: Primitive) -> Span {\n        span(span::Stage::Prepare(to_primitive(primitive)))\n    }\n\n    pub fn render(primitive: Primitive) -> Span {\n        span(span::Stage::Render(to_primitive(primitive)))\n    }\n\n    pub fn present(window: window::Id) -> Span {\n        span(span::Stage::Present(window))\n    }\n\n    pub fn time(name: impl Into<String>) -> Span {\n        span(span::Stage::Custom(name.into()))\n    }\n\n    pub fn enable() {\n        ENABLED.store(true, atomic::Ordering::Relaxed);\n    }\n\n    pub fn disable() {\n        ENABLED.store(false, atomic::Ordering::Relaxed);\n    }\n\n    pub fn commands() -> Subscription<Command> {\n        fn listen_for_commands() -> impl Stream<Item = Command> {\n            use crate::futures::futures::stream;\n\n            stream::unfold(BEACON.subscribe(), async move |mut receiver| {\n                let command = match receiver.recv().await? {\n                    client::Command::RewindTo { message } => Command::RewindTo { message },\n                    client::Command::GoLive => Command::GoLive,\n                };\n\n                Some((command, receiver))\n            })\n        }\n\n        Subscription::run(listen_for_commands)\n    }\n\n    fn span(span: span::Stage) -> Span {\n        log(client::Event::SpanStarted(span.clone()));\n\n        Span {\n            span,\n            start: Instant::now(),\n        }\n    }\n\n    fn to_primitive(primitive: Primitive) -> present::Primitive {\n        match primitive {\n            Primitive::Quad => present::Primitive::Quad,\n            Primitive::Triangle => present::Primitive::Triangle,\n            Primitive::Shader => present::Primitive::Shader,\n            Primitive::Text => present::Primitive::Text,\n            Primitive::Image => present::Primitive::Image,\n        }\n    }\n\n    fn log(event: client::Event) {\n        if ENABLED.load(atomic::Ordering::Relaxed) {\n            BEACON.log(event);\n        }\n    }\n\n    #[derive(Debug)]\n    pub struct Span {\n        span: span::Stage,\n        start: Instant,\n    }\n\n    impl Span {\n        pub fn finish(self) {\n            log(client::Event::SpanFinished(self.span, self.start.elapsed()));\n        }\n    }\n\n    static BEACON: LazyLock<Client> = LazyLock::new(|| {\n        let metadata = METADATA.read().expect(\"Read application metadata\");\n\n        client::connect(metadata.clone())\n    });\n\n    static METADATA: RwLock<client::Metadata> = RwLock::new(client::Metadata {\n        name: \"\",\n        theme: None,\n        can_time_travel: false,\n    });\n\n    static LAST_UPDATE: AtomicUsize = AtomicUsize::new(0);\n    static ENABLED: AtomicBool = AtomicBool::new(true);\n}\n\n#[cfg(any(not(feature = \"enable\"), target_arch = \"wasm32\"))]\nmod internal {\n    use crate::core::theme::palette;\n    use crate::core::window;\n    use crate::futures::Subscription;\n    use crate::{Command, Metadata, Primitive};\n\n    pub fn enable() {}\n    pub fn disable() {}\n\n    pub fn init(_metadata: Metadata) {}\n\n    pub fn quit() -> bool {\n        false\n    }\n\n    pub fn theme_changed(_f: impl FnOnce() -> Option<palette::Seed>) {}\n\n    pub fn tasks_spawned(_amount: usize) {}\n\n    pub fn subscriptions_tracked(_amount: usize) {}\n\n    pub fn layers_rendered(_amount: impl FnOnce() -> usize) {}\n\n    pub fn boot() -> Span {\n        Span\n    }\n\n    pub fn update(_message: &impl std::fmt::Debug) -> Span {\n        Span\n    }\n\n    pub fn view(_window: window::Id) -> Span {\n        Span\n    }\n\n    pub fn layout(_window: window::Id) -> Span {\n        Span\n    }\n\n    pub fn interact(_window: window::Id) -> Span {\n        Span\n    }\n\n    pub fn draw(_window: window::Id) -> Span {\n        Span\n    }\n\n    pub fn prepare(_primitive: Primitive) -> Span {\n        Span\n    }\n\n    pub fn render(_primitive: Primitive) -> Span {\n        Span\n    }\n\n    pub fn present(_window: window::Id) -> Span {\n        Span\n    }\n\n    pub fn time(_name: impl Into<String>) -> Span {\n        Span\n    }\n\n    pub fn commands() -> Subscription<Command> {\n        Subscription::none()\n    }\n\n    #[derive(Debug)]\n    pub struct Span;\n\n    impl Span {\n        pub fn finish(self) {}\n    }\n}\n\n#[cfg(all(feature = \"hot\", not(target_arch = \"wasm32\")))]\nmod hot {\n    use std::collections::BTreeSet;\n    use std::sync::atomic::{self, AtomicBool};\n    use std::sync::{Arc, Mutex, OnceLock};\n\n    static IS_STALE: AtomicBool = AtomicBool::new(false);\n\n    static HOT_FUNCTIONS_PENDING: Mutex<BTreeSet<u64>> = Mutex::new(BTreeSet::new());\n\n    static HOT_FUNCTIONS: OnceLock<BTreeSet<u64>> = OnceLock::new();\n\n    pub fn init() {\n        cargo_hot::connect();\n\n        cargo_hot::subsecond::register_handler(Arc::new(|| {\n            if HOT_FUNCTIONS.get().is_none() {\n                HOT_FUNCTIONS\n                    .set(std::mem::take(\n                        &mut HOT_FUNCTIONS_PENDING.lock().expect(\"Lock hot functions\"),\n                    ))\n                    .expect(\"Set hot functions\");\n            }\n\n            IS_STALE.store(false, atomic::Ordering::Relaxed);\n        }));\n    }\n\n    pub fn call<O>(f: impl FnOnce() -> O) -> O {\n        let mut f = Some(f);\n\n        // The `move` here is important. Hotpatching will not work\n        // otherwise.\n        let mut f = cargo_hot::subsecond::HotFn::current(move || {\n            f.take().expect(\"Hot function is stale\")()\n        });\n\n        let address = f.ptr_address().0;\n\n        if let Some(hot_functions) = HOT_FUNCTIONS.get() {\n            if hot_functions.contains(&address) {\n                IS_STALE.store(true, atomic::Ordering::Relaxed);\n            }\n        } else {\n            let _ = HOT_FUNCTIONS_PENDING\n                .lock()\n                .expect(\"Lock hot functions\")\n                .insert(address);\n        }\n\n        f.call(())\n    }\n\n    pub fn on_hotpatch(f: impl Fn() + Send + Sync + 'static) {\n        cargo_hot::subsecond::register_handler(Arc::new(f));\n    }\n\n    pub fn is_stale() -> bool {\n        IS_STALE.load(atomic::Ordering::Relaxed)\n    }\n}\n\n#[cfg(any(not(feature = \"hot\"), target_arch = \"wasm32\"))]\nmod hot {\n    pub fn init() {}\n\n    pub fn call<O>(f: impl FnOnce() -> O) -> O {\n        f()\n    }\n\n    pub fn on_hotpatch(_f: impl Fn()) {}\n\n    pub fn is_stale() -> bool {\n        false\n    }\n}\n"
  },
  {
    "path": "devtools/Cargo.toml",
    "content": "[package]\nname = \"iced_devtools\"\ndescription = \"Attachable developer tools for any iced program\"\nversion.workspace = true\nauthors.workspace = true\nedition.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\nrust-version.workspace = true\n\n[lints]\nworkspace = true\n\n[features]\ntime-travel = [\"iced_program/time-travel\"]\n\n[dependencies]\niced_debug.workspace = true\niced_widget.workspace = true\nlog.workspace = true\n\niced_program.workspace = true\niced_program.features = [\"debug\"]\n"
  },
  {
    "path": "devtools/src/comet.rs",
    "content": "use crate::runtime::task::{self, Task};\n\nuse std::process;\n\npub const COMPATIBLE_REVISION: &str = \"fbef808eed51562f0ea601d8fc7c715bea9cfd0b\";\n\npub fn launch() -> Task<launch::Result> {\n    task::try_blocking(|mut sender| {\n        let cargo_install = process::Command::new(\"cargo\")\n            .args([\"install\", \"--list\"])\n            .output()?;\n\n        let installed_packages = String::from_utf8_lossy(&cargo_install.stdout);\n\n        for line in installed_packages.lines() {\n            if !line.starts_with(\"iced_comet \") {\n                continue;\n            }\n\n            let Some((_, revision)) = line.rsplit_once(\"?rev=\") else {\n                return Err(launch::Error::Outdated { revision: None });\n            };\n\n            let Some((revision, _)) = revision.rsplit_once(\"#\") else {\n                return Err(launch::Error::Outdated { revision: None });\n            };\n\n            if revision != COMPATIBLE_REVISION {\n                return Err(launch::Error::Outdated {\n                    revision: Some(revision.to_owned()),\n                });\n            }\n\n            let _ = process::Command::new(\"iced_comet\")\n                .stdin(process::Stdio::null())\n                .stdout(process::Stdio::null())\n                .stderr(process::Stdio::null())\n                .spawn()?;\n\n            let _ = sender.try_send(());\n            return Ok(());\n        }\n\n        Err(launch::Error::NotFound)\n    })\n}\n\npub fn install() -> Task<install::Result> {\n    task::try_blocking(|mut sender| {\n        use std::io::{BufRead, BufReader};\n        use std::process::{Command, Stdio};\n\n        let mut install = Command::new(\"cargo\")\n            .args([\n                \"install\",\n                \"--locked\",\n                \"--git\",\n                \"https://github.com/iced-rs/comet.git\",\n                \"--rev\",\n                COMPATIBLE_REVISION,\n            ])\n            .stdin(Stdio::null())\n            .stdout(Stdio::null())\n            .stderr(Stdio::piped())\n            .spawn()?;\n\n        let mut stderr = BufReader::new(install.stderr.take().expect(\"stderr must be piped\"));\n\n        let mut log = String::new();\n\n        while let Ok(n) = stderr.read_line(&mut log) {\n            if n == 0 {\n                let status = install.wait()?;\n\n                if status.success() {\n                    break;\n                } else {\n                    return Err(install::Error::ProcessFailed(status));\n                }\n            }\n\n            let _ = sender.try_send(install::Event::Logged(log.trim_end().to_owned()));\n\n            log.clear();\n        }\n\n        let _ = sender.try_send(install::Event::Finished);\n\n        Ok(())\n    })\n}\n\npub mod launch {\n    use std::io;\n    use std::sync::Arc;\n\n    pub type Result = std::result::Result<(), Error>;\n\n    #[derive(Debug, Clone)]\n    pub enum Error {\n        NotFound,\n        Outdated { revision: Option<String> },\n        IoFailed(Arc<io::Error>),\n    }\n\n    impl From<io::Error> for Error {\n        fn from(error: io::Error) -> Self {\n            Self::IoFailed(Arc::new(error))\n        }\n    }\n}\n\npub mod install {\n    use std::io;\n    use std::process;\n    use std::sync::Arc;\n\n    pub type Result = std::result::Result<Event, Error>;\n\n    #[derive(Debug, Clone)]\n    pub enum Event {\n        Logged(String),\n        Finished,\n    }\n\n    #[derive(Debug, Clone)]\n    pub enum Error {\n        ProcessFailed(process::ExitStatus),\n        IoFailed(Arc<io::Error>),\n    }\n\n    impl From<io::Error> for Error {\n        fn from(error: io::Error) -> Self {\n            Self::IoFailed(Arc::new(error))\n        }\n    }\n}\n"
  },
  {
    "path": "devtools/src/lib.rs",
    "content": "#![allow(missing_docs)]\nuse iced_debug as debug;\nuse iced_program as program;\nuse iced_program::runtime;\nuse iced_program::runtime::futures;\nuse iced_widget as widget;\nuse iced_widget::core;\n\nmod comet;\nmod time_machine;\n\nuse crate::core::border;\nuse crate::core::keyboard;\nuse crate::core::theme::{self, Theme};\nuse crate::core::time::seconds;\nuse crate::core::window;\nuse crate::core::{Alignment::Center, Color, Element, Font, Length::Fill, Settings};\nuse crate::futures::Subscription;\nuse crate::program::Program;\nuse crate::program::message;\nuse crate::runtime::task::{self, Task};\nuse crate::time_machine::TimeMachine;\nuse crate::widget::{\n    bottom_right, button, center, column, container, opaque, row, scrollable, space, stack, text,\n    themer,\n};\n\nuse std::fmt;\nuse std::thread;\n\npub fn attach<P: Program + 'static>(program: P) -> Attach<P> {\n    Attach { program }\n}\n\n/// A [`Program`] with some devtools attached to it.\n#[derive(Debug)]\npub struct Attach<P> {\n    /// The original [`Program`] managed by these devtools.\n    pub program: P,\n}\n\nimpl<P> Program for Attach<P>\nwhere\n    P: Program + 'static,\n    P::Message: std::fmt::Debug + message::MaybeClone,\n{\n    type State = DevTools<P>;\n    type Message = Event<P>;\n    type Theme = P::Theme;\n    type Renderer = P::Renderer;\n    type Executor = P::Executor;\n\n    fn name() -> &'static str {\n        P::name()\n    }\n\n    fn settings(&self) -> Settings {\n        self.program.settings()\n    }\n\n    fn window(&self) -> Option<window::Settings> {\n        self.program.window()\n    }\n\n    fn boot(&self) -> (Self::State, Task<Self::Message>) {\n        let (state, boot) = self.program.boot();\n        let (devtools, task) = DevTools::new(state);\n\n        (\n            devtools,\n            Task::batch([boot.map(Event::Program), task.map(Event::Message)]),\n        )\n    }\n\n    fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n        state.update(&self.program, message)\n    }\n\n    fn view<'a>(\n        &self,\n        state: &'a Self::State,\n        window: window::Id,\n    ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n        state.view(&self.program, window)\n    }\n\n    fn title(&self, state: &Self::State, window: window::Id) -> String {\n        state.title(&self.program, window)\n    }\n\n    fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n        state.subscription(&self.program)\n    }\n\n    fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {\n        state.theme(&self.program, window)\n    }\n\n    fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n        state.style(&self.program, theme)\n    }\n\n    fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n        state.scale_factor(&self.program, window)\n    }\n}\n\n/// The state of the devtools.\npub struct DevTools<P>\nwhere\n    P: Program,\n{\n    state: P::State,\n    show_notification: bool,\n    time_machine: TimeMachine<P>,\n    mode: Mode,\n}\n\n#[derive(Debug, Clone)]\npub enum Message {\n    HideNotification,\n    ToggleComet,\n    CometLaunched(comet::launch::Result),\n    InstallComet,\n    Installing(comet::install::Result),\n    CancelSetup,\n}\n\nenum Mode {\n    Hidden,\n    Setup(Setup),\n}\n\nenum Setup {\n    Idle { goal: Goal },\n    Running { logs: Vec<String> },\n}\n\nenum Goal {\n    Installation,\n    Update { revision: Option<String> },\n}\n\nimpl<P> DevTools<P>\nwhere\n    P: Program + 'static,\n    P::Message: std::fmt::Debug + message::MaybeClone,\n{\n    pub fn new(state: P::State) -> (Self, Task<Message>) {\n        (\n            Self {\n                state,\n                mode: Mode::Hidden,\n                show_notification: true,\n                time_machine: TimeMachine::new(),\n            },\n            Task::batch([task::blocking(|mut sender| {\n                thread::sleep(seconds(2));\n                let _ = sender.try_send(());\n            })\n            .map(|_| Message::HideNotification)]),\n        )\n    }\n\n    pub fn title(&self, program: &P, window: window::Id) -> String {\n        program.title(&self.state, window)\n    }\n\n    pub fn update(&mut self, program: &P, event: Event<P>) -> Task<Event<P>> {\n        match event {\n            Event::Message(message) => match message {\n                Message::HideNotification => {\n                    self.show_notification = false;\n\n                    Task::none()\n                }\n                Message::ToggleComet => {\n                    if let Mode::Setup(setup) = &self.mode {\n                        if matches!(setup, Setup::Idle { .. }) {\n                            self.mode = Mode::Hidden;\n                        }\n\n                        Task::none()\n                    } else if debug::quit() {\n                        Task::none()\n                    } else {\n                        comet::launch()\n                            .map(Message::CometLaunched)\n                            .map(Event::Message)\n                    }\n                }\n                Message::CometLaunched(Ok(())) => Task::none(),\n                Message::CometLaunched(Err(error)) => {\n                    match error {\n                        comet::launch::Error::NotFound => {\n                            self.mode = Mode::Setup(Setup::Idle {\n                                goal: Goal::Installation,\n                            });\n                        }\n                        comet::launch::Error::Outdated { revision } => {\n                            self.mode = Mode::Setup(Setup::Idle {\n                                goal: Goal::Update { revision },\n                            });\n                        }\n                        comet::launch::Error::IoFailed(error) => {\n                            log::error!(\"comet failed to run: {error}\");\n                        }\n                    }\n\n                    Task::none()\n                }\n                Message::InstallComet => {\n                    self.mode = Mode::Setup(Setup::Running { logs: Vec::new() });\n\n                    comet::install()\n                        .map(Message::Installing)\n                        .map(Event::Message)\n                }\n                Message::Installing(Ok(installation)) => {\n                    let Mode::Setup(Setup::Running { logs }) = &mut self.mode else {\n                        return Task::none();\n                    };\n\n                    match installation {\n                        comet::install::Event::Logged(log) => {\n                            logs.push(log);\n                            Task::none()\n                        }\n                        comet::install::Event::Finished => {\n                            self.mode = Mode::Hidden;\n                            comet::launch().discard()\n                        }\n                    }\n                }\n                Message::Installing(Err(error)) => {\n                    let Mode::Setup(Setup::Running { logs }) = &mut self.mode else {\n                        return Task::none();\n                    };\n\n                    match error {\n                        comet::install::Error::ProcessFailed(status) => {\n                            logs.push(format!(\"process failed with {status}\"));\n                        }\n                        comet::install::Error::IoFailed(error) => {\n                            logs.push(error.to_string());\n                        }\n                    }\n\n                    Task::none()\n                }\n                Message::CancelSetup => {\n                    self.mode = Mode::Hidden;\n\n                    Task::none()\n                }\n            },\n            Event::Program(message) => {\n                self.time_machine.push(&message);\n\n                if self.time_machine.is_rewinding() {\n                    debug::enable();\n                }\n\n                let span = debug::update(&message);\n                let task = program.update(&mut self.state, message);\n                debug::tasks_spawned(task.units());\n                span.finish();\n\n                if self.time_machine.is_rewinding() {\n                    debug::disable();\n                }\n\n                task.map(Event::Program)\n            }\n            Event::Command(command) => {\n                match command {\n                    debug::Command::RewindTo { message } => {\n                        self.time_machine.rewind(program, message);\n                    }\n                    debug::Command::GoLive => {\n                        self.time_machine.go_to_present();\n                    }\n                }\n\n                Task::none()\n            }\n            Event::Discard => Task::none(),\n        }\n    }\n\n    pub fn view(\n        &self,\n        program: &P,\n        window: window::Id,\n    ) -> Element<'_, Event<P>, P::Theme, P::Renderer> {\n        let state = self.state();\n\n        let view = {\n            let view = program.view(state, window);\n\n            if self.time_machine.is_rewinding() {\n                view.map(|_| Event::Discard)\n            } else {\n                view.map(Event::Program)\n            }\n        };\n\n        let theme = || {\n            program\n                .theme(state, window)\n                .as_ref()\n                .and_then(theme::Base::seed)\n                .map(|seed| Theme::custom(\"iced devtools\", seed))\n        };\n\n        let setup = if let Mode::Setup(setup) = &self.mode {\n            let stage: Element<'_, _, Theme, P::Renderer> = match setup {\n                Setup::Idle { goal } => self::setup(goal),\n                Setup::Running { logs } => installation(logs),\n            };\n\n            let setup = center(\n                container(stage)\n                    .padding(20)\n                    .max_width(500)\n                    .style(container::bordered_box),\n            )\n            .padding(10)\n            .style(|_theme| container::Style::default().background(Color::BLACK.scale_alpha(0.8)));\n\n            Some(themer(theme(), opaque(setup).map(Event::Message)))\n        } else {\n            None\n        };\n\n        let notification = self\n            .show_notification\n            .then(|| text(\"Press F12 to open debug metrics\"))\n            .or_else(|| {\n                debug::is_stale()\n                    .then(|| text(\"Types have changed. Restart to re-enable hotpatching.\"))\n            })\n            .map(|notification| {\n                themer(\n                    theme(),\n                    bottom_right(opaque(\n                        container(notification).padding(10).style(container::dark),\n                    )),\n                )\n            });\n\n        stack![view, setup, notification]\n            .width(Fill)\n            .height(Fill)\n            .into()\n    }\n\n    pub fn subscription(&self, program: &P) -> Subscription<Event<P>> {\n        let subscription = program.subscription(&self.state).map(Event::Program);\n        debug::subscriptions_tracked(subscription.units());\n\n        let hotkeys = futures::keyboard::listen()\n            .filter_map(|event| match event {\n                keyboard::Event::KeyPressed {\n                    modified_key: keyboard::Key::Named(keyboard::key::Named::F12),\n                    ..\n                } => Some(Message::ToggleComet),\n                _ => None,\n            })\n            .map(Event::Message);\n\n        let commands = debug::commands().map(Event::Command);\n\n        Subscription::batch([subscription, hotkeys, commands])\n    }\n\n    pub fn theme(&self, program: &P, window: window::Id) -> Option<P::Theme> {\n        program.theme(self.state(), window)\n    }\n\n    pub fn style(&self, program: &P, theme: &P::Theme) -> theme::Style {\n        program.style(self.state(), theme)\n    }\n\n    pub fn scale_factor(&self, program: &P, window: window::Id) -> f32 {\n        program.scale_factor(self.state(), window)\n    }\n\n    pub fn state(&self) -> &P::State {\n        self.time_machine.state().unwrap_or(&self.state)\n    }\n}\n\npub enum Event<P>\nwhere\n    P: Program,\n{\n    Message(Message),\n    Program(P::Message),\n    Command(debug::Command),\n    Discard,\n}\n\nimpl<P> fmt::Debug for Event<P>\nwhere\n    P: Program,\n    P::Message: std::fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Message(message) => message.fmt(f),\n            Self::Program(message) => message.fmt(f),\n            Self::Command(command) => command.fmt(f),\n            Self::Discard => f.write_str(\"Discard\"),\n        }\n    }\n}\n\nfn setup<Renderer>(goal: &Goal) -> Element<'_, Message, Theme, Renderer>\nwhere\n    Renderer: program::Renderer + 'static,\n{\n    let controls = row![\n        button(text(\"Cancel\").center().width(Fill))\n            .width(100)\n            .on_press(Message::CancelSetup)\n            .style(button::danger),\n        space::horizontal(),\n        button(\n            text(match goal {\n                Goal::Installation => \"Install\",\n                Goal::Update { .. } => \"Update\",\n            })\n            .center()\n            .width(Fill)\n        )\n        .width(100)\n        .on_press(Message::InstallComet)\n        .style(button::success),\n    ];\n\n    let command = container(\n        text!(\n            \"cargo install --locked \\\\\n    --git https://github.com/iced-rs/comet.git \\\\\n    --rev {}\",\n            comet::COMPATIBLE_REVISION\n        )\n        .size(14)\n        .font(Font::MONOSPACE),\n    )\n    .width(Fill)\n    .padding(5)\n    .style(container::dark);\n\n    Element::from(match goal {\n        Goal::Installation => column![\n            text(\"comet is not installed!\").size(20),\n            \"In order to display performance \\\n                metrics, the  comet debugger must \\\n                be installed in your system.\",\n            \"The comet debugger is an official \\\n                companion tool that helps you debug \\\n                your iced applications.\",\n            column![\n                \"Do you wish to install it with the \\\n                    following command?\",\n                command\n            ]\n            .spacing(10),\n            controls,\n        ]\n        .spacing(20),\n        Goal::Update { revision } => {\n            let comparison = column![\n                row![\n                    \"Installed revision:\",\n                    space::horizontal(),\n                    inline_code(revision.as_deref().unwrap_or(\"Unknown\"))\n                ]\n                .align_y(Center),\n                row![\n                    \"Compatible revision:\",\n                    space::horizontal(),\n                    inline_code(comet::COMPATIBLE_REVISION),\n                ]\n                .align_y(Center)\n            ]\n            .spacing(5);\n\n            column![\n                text(\"comet is out of date!\").size(20),\n                comparison,\n                column![\n                    \"Do you wish to update it with the following \\\n                        command?\",\n                    command\n                ]\n                .spacing(10),\n                controls,\n            ]\n            .spacing(20)\n        }\n    })\n}\n\nfn installation<'a, Renderer>(logs: &'a [String]) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Renderer: program::Renderer + 'a,\n{\n    column![\n        text(\"Installing comet...\").size(20),\n        container(\n            scrollable(\n                column(\n                    logs.iter()\n                        .map(|log| { text(log).size(12).font(Font::MONOSPACE).into() })\n                )\n                .spacing(3),\n            )\n            .spacing(10)\n            .width(Fill)\n            .height(300)\n            .anchor_bottom(),\n        )\n        .padding(10)\n        .style(container::dark)\n    ]\n    .spacing(20)\n    .into()\n}\n\nfn inline_code<'a, Renderer>(\n    code: impl text::IntoFragment<'a>,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Renderer: program::Renderer + 'a,\n{\n    container(text(code).size(12).font(Font::MONOSPACE))\n        .style(|_theme| {\n            container::Style::default()\n                .background(Color::BLACK)\n                .border(border::rounded(2))\n        })\n        .padding([2, 4])\n        .into()\n}\n"
  },
  {
    "path": "devtools/src/time_machine.rs",
    "content": "use crate::Program;\n\n#[cfg(feature = \"time-travel\")]\npub struct TimeMachine<P>\nwhere\n    P: Program,\n{\n    state: Option<P::State>,\n    messages: Vec<P::Message>,\n}\n\n#[cfg(feature = \"time-travel\")]\nimpl<P> TimeMachine<P>\nwhere\n    P: Program,\n    P::Message: Clone,\n{\n    pub fn new() -> Self {\n        Self {\n            state: None,\n            messages: Vec::new(),\n        }\n    }\n\n    pub fn is_rewinding(&self) -> bool {\n        self.state.is_some()\n    }\n\n    pub fn push(&mut self, message: &P::Message) {\n        self.messages.push(message.clone());\n    }\n\n    pub fn rewind(&mut self, program: &P, message: usize) {\n        crate::debug::disable();\n        let (mut state, _) = program.boot();\n\n        if message < self.messages.len() {\n            // TODO: Run concurrently (?)\n            for message in &self.messages[0..message] {\n                let _ = program.update(&mut state, message.clone());\n            }\n        }\n\n        self.state = Some(state);\n    }\n\n    pub fn go_to_present(&mut self) {\n        self.state = None;\n        crate::debug::enable();\n    }\n\n    pub fn state(&self) -> Option<&P::State> {\n        self.state.as_ref()\n    }\n}\n\n#[cfg(not(feature = \"time-travel\"))]\npub struct TimeMachine<P>\nwhere\n    P: Program,\n{\n    _program: std::marker::PhantomData<P>,\n}\n\n#[cfg(not(feature = \"time-travel\"))]\nimpl<P> TimeMachine<P>\nwhere\n    P: Program,\n{\n    pub fn new() -> Self {\n        Self {\n            _program: std::marker::PhantomData,\n        }\n    }\n\n    pub fn is_rewinding(&self) -> bool {\n        false\n    }\n\n    pub fn push(&mut self, _message: &P::Message) {}\n\n    pub fn rewind(&mut self, _program: &P, _message: usize) {}\n\n    pub fn go_to_present(&mut self) {}\n\n    pub fn state(&self) -> Option<&P::State> {\n        None\n    }\n}\n"
  },
  {
    "path": "docs/redirect.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Redirecting...</title>\n    <meta http-equiv=\"refresh\" content=\"0; URL='/iced/'\" />\n</head>\n<body>\n    <p>If you are not redirected automatically, follow this <a href=\"/iced/\">link</a>.</p>\n</body>\n</html>\n"
  },
  {
    "path": "docs/release_summary.py",
    "content": "import requests\nimport os\n\ndef get_merged_prs(repo, milestone, token):\n    url = f'https://api.github.com/repos/{repo}/pulls'\n    params = {\n        'state': 'closed',\n        'per_page': 100,  # Number of items per page, adjust as needed\n    }\n    headers = {'Authorization': f'token {token}'}\n\n    all_prs = []\n    page = 1\n\n    while True:\n        params['page'] = page\n        response = requests.get(url, params=params, headers=headers)\n        response.raise_for_status()\n\n        prs = response.json()\n\n        if not prs:\n            break  # No more pages\n\n        all_prs.extend([pr for pr in prs if pr['merged_at'] and (pr['milestone'] or {}).get('title', '') == milestone])\n        page += 1\n\n    return all_prs\n\ndef categorize_prs(prs):\n    categorized_prs = {'addition': [], 'change': [], 'fix': []}\n\n    for pr in prs:\n        labels = [label['name'] for label in pr['labels']]\n        if 'addition' in labels or 'feature' in labels:\n            categorized_prs['addition'].append(pr)\n        elif 'fix' in labels or 'bug' in labels:\n            categorized_prs['fix'].append(pr)\n        elif 'change' in labels or 'improvement' in labels:\n            categorized_prs['change'].append(pr)\n\n    return categorized_prs\n\ndef get_authors(prs):\n    authors = set()\n    for pr in prs:\n        authors.add(pr['user']['login'])\n    return sorted(authors, key=str.casefold)\n\ndef main():\n    repo = 'iced-rs/iced'\n    milestone = '0.12'\n    token = os.environ['GITHUB_TOKEN']\n\n    prs = get_merged_prs(repo, milestone, token)\n    categorized_prs = categorize_prs(prs)\n\n    for category, items in categorized_prs.items():\n        print(f\"### {category.capitalize()}\")\n\n        for pr in items:\n            print(f\"- {pr['title']}. [#{pr['number']}](https://github.com/{repo}/pull/{pr['number']})\")\n\n        print(\"\")\n\n    print(\"\")\n\n    authors = get_authors(prs)\n\n    print(\"Many thanks to...\")\n    for author in authors:\n        print(f\"- @{author}\")\n\nif __name__ == \"__main__\":\n    main()"
  },
  {
    "path": "examples/README.md",
    "content": "# Examples\n__Iced moves fast and the `master` branch can contain breaking changes!__ If you want to browse examples that are compatible with the latest release,\nthen [switch to the `latest` branch](https://github.com/iced-rs/iced/tree/latest/examples#examples).\n\n## [Tour](tour)\nA simple UI tour that can run both on native platforms and the web! It showcases different widgets that can be built using Iced.\n\nThe __[`main`](tour/src/main.rs)__ file contains all the code of the example! All the cross-platform GUI is defined in terms of __state__, __messages__, __update logic__ and __view logic__.\n\n<div align=\"center\">\n  <a href=\"https://iced.rs/examples/tour.mp4\">\n    <img src=\"https://iced.rs/examples/tour.gif\">\n  </a>\n</div>\n\n[`iced_winit`]: ../winit\n[`iced_native`]: ../native\n[`iced_wgpu`]: ../wgpu\n[`iced_web`]: https://github.com/iced-rs/iced_web\n[`winit`]: https://github.com/rust-windowing/winit\n[`wgpu`]: https://github.com/gfx-rs/wgpu\n\nYou can run the native version with `cargo run`:\n```\ncargo run --package tour\n```\n\n## [Todos](todos)\nA todos tracker inspired by [TodoMVC]. It showcases dynamic layout, text input, checkboxes, scrollables, icons, and async actions! It automatically saves your tasks in the background, even if you did not finish typing them.\n\nThe example code is located in the __[`main`](todos/src/main.rs)__ file.\n\n<div align=\"center\">\n  <a href=\"https://iced.rs/examples/todos.mp4\">\n    <img src=\"https://iced.rs/examples/todos.gif\" height=\"400px\">\n  </a>\n</div>\n\nYou can run the native version with `cargo run`:\n```\ncargo run --package todos\n```\n\n[TodoMVC]: http://todomvc.com/\n\n## [Game of Life](game_of_life)\nAn interactive version of the [Game of Life], invented by [John Horton Conway].\n\nIt runs a simulation in a background thread while allowing interaction with a `Canvas` that displays an infinite grid with zooming, panning, and drawing support.\n\nThe relevant code is located in the __[`main`](game_of_life/src/main.rs)__ file.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/game_of_life.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package game_of_life\n```\n\n[Game of Life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life\n[John Horton Conway]: https://en.wikipedia.org/wiki/John_Horton_Conway\n\n## [Styling](styling)\nAn example showcasing custom styling with a light and dark theme.\n\nThe example code is located in the __[`main`](styling/src/main.rs)__ file.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/styling.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package styling\n```\n\n## Extras\nA bunch of simpler examples exist:\n\n- [`bezier_tool`](bezier_tool), a Paint-like tool for drawing Bézier curves using the `Canvas` widget.\n- [`clock`](clock), an application that uses the `Canvas` widget to draw a clock and its hands to display the current time.\n- [`color_palette`](color_palette), a color palette generator based on a user-defined root color.\n- [`counter`](counter), the classic counter example explained in the [`README`](../README.md).\n- [`custom_widget`](custom_widget), a demonstration of how to build a custom widget that draws a circle.\n- [`download_progress`](download_progress), a basic application that asynchronously downloads a dummy file of 100 MB and tracks the download progress.\n- [`events`](events), a log of native events displayed using a conditional `Subscription`.\n- [`geometry`](geometry), a custom widget showcasing how to draw geometry with the `Mesh2D` primitive in [`iced_wgpu`](../wgpu).\n- [`integration`](integration), a demonstration of how to integrate Iced in an existing [`wgpu`] application.\n- [`pane_grid`](pane_grid), a grid of panes that can be split, resized, and reorganized.\n- [`pick_list`](pick_list), a dropdown list of selectable options.\n- [`pokedex`](pokedex), an application that displays a random Pokédex entry (sprite included!) by using the [PokéAPI].\n- [`progress_bar`](progress_bar), a simple progress bar that can be filled by using a slider.\n- [`scrollable`](scrollable), a showcase of various scrollable content configurations.\n- [`sierpinski_triangle`](sierpinski_triangle), a [sierpiński triangle](https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle) Emulator, use `Canvas` and `Slider`.\n- [`solar_system`](solar_system), an animated solar system drawn using the `Canvas` widget and showcasing how to compose different transforms.\n- [`stopwatch`](stopwatch), a watch with start/stop and reset buttons showcasing how to listen to time.\n- [`svg`](svg), an application that renders the [Ghostscript Tiger] by leveraging the `Svg` widget.\n\nAll of them are packaged in their own crate and, therefore, can be run using `cargo`:\n```\ncargo run --package <example>\n```\n\n[`lyon`]: https://github.com/nical/lyon\n[PokéAPI]: https://pokeapi.co/\n[Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg\n[`wgpu`]: https://github.com/gfx-rs/wgpu\n\n## [Coffee]\nSince [Iced was born in May 2019], it has been powering the user interfaces in\n[Coffee], an experimental 2D game engine.\n\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/coffee.gif\">\n</div>\n\n[Iced was born in May 2019]: https://github.com/hecrj/coffee/pull/35\n[`ui` module]: https://docs.rs/coffee/0.3.2/coffee/ui/index.html\n[Coffee]: https://github.com/hecrj/coffee\n"
  },
  {
    "path": "examples/arc/Cargo.toml",
    "content": "[package]\nname = \"arc\"\nversion = \"0.1.0\"\nauthors = [\"ThatsNoMoon <git@thatsnomoon.dev>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"canvas\", \"tokio\", \"debug\"]\n"
  },
  {
    "path": "examples/arc/README.md",
    "content": "## Arc\n\nAn application that uses the `Canvas` widget to draw a rotating arc.\n\nThis is a simple demo for https://github.com/iced-rs/iced/pull/1358.\n\nThe __[`main`]__ file contains all the code of the example.\n\nYou can run it with `cargo run`:\n```\ncargo run --package arc\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/arc/src/main.rs",
    "content": "use std::{f32::consts::PI, time::Instant};\n\nuse iced::mouse;\nuse iced::widget::canvas::{self, Cache, Canvas, Geometry, Path, Stroke, stroke};\nuse iced::window;\nuse iced::{Element, Fill, Point, Rectangle, Renderer, Subscription, Theme};\n\npub fn main() -> iced::Result {\n    iced::application(Arc::new, Arc::update, Arc::view)\n        .subscription(Arc::subscription)\n        .theme(Theme::Dark)\n        .run()\n}\n\nstruct Arc {\n    start: Instant,\n    cache: Cache,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Tick,\n}\n\nimpl Arc {\n    fn new() -> Self {\n        Arc {\n            start: Instant::now(),\n            cache: Cache::default(),\n        }\n    }\n\n    fn update(&mut self, _: Message) {\n        self.cache.clear();\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        Canvas::new(self).width(Fill).height(Fill).into()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        window::frames().map(|_| Message::Tick)\n    }\n}\n\nimpl<Message> canvas::Program<Message> for Arc {\n    type State = ();\n\n    fn draw(\n        &self,\n        _state: &Self::State,\n        renderer: &Renderer,\n        theme: &Theme,\n        bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Vec<Geometry> {\n        let geometry = self.cache.draw(renderer, bounds.size(), |frame| {\n            let palette = theme.seed();\n            let center = frame.center();\n            let radius = frame.width().min(frame.height()) / 5.0;\n\n            let start = Point::new(center.x, center.y - radius);\n\n            let angle = (self.start.elapsed().as_millis() % 10_000) as f32 / 10_000.0 * 2.0 * PI;\n\n            let end = Point::new(\n                center.x + radius * angle.cos(),\n                center.y + radius * angle.sin(),\n            );\n\n            let circles = Path::new(|b| {\n                b.circle(start, 10.0);\n                b.move_to(end);\n                b.circle(end, 10.0);\n            });\n\n            frame.fill(&circles, palette.text);\n\n            let path = Path::new(|b| {\n                b.move_to(start);\n                b.arc_to(center, end, 50.0);\n                b.line_to(end);\n            });\n\n            frame.stroke(\n                &path,\n                Stroke {\n                    style: stroke::Style::Solid(palette.text),\n                    width: 10.0,\n                    ..Stroke::default()\n                },\n            );\n        });\n\n        vec![geometry]\n    }\n}\n"
  },
  {
    "path": "examples/bezier_tool/Cargo.toml",
    "content": "[package]\nname = \"bezier_tool\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"canvas\", \"debug\"]\n"
  },
  {
    "path": "examples/bezier_tool/README.md",
    "content": "## Bézier tool\n\nA Paint-like tool for drawing Bézier curves using the `Canvas` widget.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/bezier_tool.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package bezier_tool\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/bezier_tool/src/main.rs",
    "content": "//! This example showcases an interactive `Canvas` for drawing Bézier curves.\nuse iced::widget::{button, container, hover, right, space};\nuse iced::{Element, Theme};\n\npub fn main() -> iced::Result {\n    iced::application(Example::default, Example::update, Example::view)\n        .theme(Theme::CatppuccinMocha)\n        .run()\n}\n\n#[derive(Default)]\nstruct Example {\n    bezier: bezier::State,\n    curves: Vec<bezier::Curve>,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    AddCurve(bezier::Curve),\n    Clear,\n}\n\nimpl Example {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::AddCurve(curve) => {\n                self.curves.push(curve);\n                self.bezier.request_redraw();\n            }\n            Message::Clear => {\n                self.bezier = bezier::State::default();\n                self.curves.clear();\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        container(hover(\n            self.bezier.view(&self.curves).map(Message::AddCurve),\n            if self.curves.is_empty() {\n                container(space::horizontal())\n            } else {\n                right(\n                    button(\"Clear\")\n                        .style(button::danger)\n                        .on_press(Message::Clear),\n                )\n                .padding(10)\n            },\n        ))\n        .padding(20)\n        .into()\n    }\n}\n\nmod bezier {\n    use iced::mouse;\n    use iced::widget::canvas::{self, Canvas, Event, Frame, Geometry, Path, Stroke};\n    use iced::{Element, Fill, Point, Rectangle, Renderer, Theme};\n\n    #[derive(Default)]\n    pub struct State {\n        cache: canvas::Cache,\n    }\n\n    impl State {\n        pub fn view<'a>(&'a self, curves: &'a [Curve]) -> Element<'a, Curve> {\n            Canvas::new(Bezier {\n                state: self,\n                curves,\n            })\n            .width(Fill)\n            .height(Fill)\n            .into()\n        }\n\n        pub fn request_redraw(&mut self) {\n            self.cache.clear();\n        }\n    }\n\n    struct Bezier<'a> {\n        state: &'a State,\n        curves: &'a [Curve],\n    }\n\n    impl canvas::Program<Curve> for Bezier<'_> {\n        type State = Option<Pending>;\n\n        fn update(\n            &self,\n            state: &mut Self::State,\n            event: &Event,\n            bounds: Rectangle,\n            cursor: mouse::Cursor,\n        ) -> Option<canvas::Action<Curve>> {\n            let cursor_position = cursor.position_in(bounds)?;\n\n            match event {\n                Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => Some(\n                    match *state {\n                        None => {\n                            *state = Some(Pending::One {\n                                from: cursor_position,\n                            });\n\n                            canvas::Action::request_redraw()\n                        }\n                        Some(Pending::One { from }) => {\n                            *state = Some(Pending::Two {\n                                from,\n                                to: cursor_position,\n                            });\n\n                            canvas::Action::request_redraw()\n                        }\n                        Some(Pending::Two { from, to }) => {\n                            *state = None;\n\n                            canvas::Action::publish(Curve {\n                                from,\n                                to,\n                                control: cursor_position,\n                            })\n                        }\n                    }\n                    .and_capture(),\n                ),\n                Event::Mouse(mouse::Event::CursorMoved { .. }) if state.is_some() => {\n                    Some(canvas::Action::request_redraw())\n                }\n                _ => None,\n            }\n        }\n\n        fn draw(\n            &self,\n            state: &Self::State,\n            renderer: &Renderer,\n            theme: &Theme,\n            bounds: Rectangle,\n            cursor: mouse::Cursor,\n        ) -> Vec<Geometry> {\n            let content = self.state.cache.draw(renderer, bounds.size(), |frame| {\n                Curve::draw_all(self.curves, frame, theme);\n\n                frame.stroke(\n                    &Path::rectangle(Point::ORIGIN, frame.size()),\n                    Stroke::default()\n                        .with_width(2.0)\n                        .with_color(theme.seed().text),\n                );\n            });\n\n            if let Some(pending) = state {\n                vec![content, pending.draw(renderer, theme, bounds, cursor)]\n            } else {\n                vec![content]\n            }\n        }\n\n        fn mouse_interaction(\n            &self,\n            _state: &Self::State,\n            bounds: Rectangle,\n            cursor: mouse::Cursor,\n        ) -> mouse::Interaction {\n            if cursor.is_over(bounds) {\n                mouse::Interaction::Crosshair\n            } else {\n                mouse::Interaction::default()\n            }\n        }\n    }\n\n    #[derive(Debug, Clone, Copy)]\n    pub struct Curve {\n        from: Point,\n        to: Point,\n        control: Point,\n    }\n\n    impl Curve {\n        fn draw_all(curves: &[Curve], frame: &mut Frame, theme: &Theme) {\n            let curves = Path::new(|p| {\n                for curve in curves {\n                    p.move_to(curve.from);\n                    p.quadratic_curve_to(curve.control, curve.to);\n                }\n            });\n\n            frame.stroke(\n                &curves,\n                Stroke::default()\n                    .with_width(2.0)\n                    .with_color(theme.seed().text),\n            );\n        }\n    }\n\n    #[derive(Debug, Clone, Copy)]\n    enum Pending {\n        One { from: Point },\n        Two { from: Point, to: Point },\n    }\n\n    impl Pending {\n        fn draw(\n            &self,\n            renderer: &Renderer,\n            theme: &Theme,\n            bounds: Rectangle,\n            cursor: mouse::Cursor,\n        ) -> Geometry {\n            let mut frame = Frame::new(renderer, bounds.size());\n\n            if let Some(cursor_position) = cursor.position_in(bounds) {\n                match *self {\n                    Pending::One { from } => {\n                        let line = Path::line(from, cursor_position);\n                        frame.stroke(\n                            &line,\n                            Stroke::default()\n                                .with_width(2.0)\n                                .with_color(theme.seed().text),\n                        );\n                    }\n                    Pending::Two { from, to } => {\n                        let curve = Curve {\n                            from,\n                            to,\n                            control: cursor_position,\n                        };\n\n                        Curve::draw_all(&[curve], &mut frame, theme);\n                    }\n                };\n            }\n\n            frame.into_geometry()\n        }\n    }\n}\n"
  },
  {
    "path": "examples/changelog/Cargo.toml",
    "content": "[package]\nname = \"changelog\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[lints.clippy]\nlarge_enum_variant = \"allow\"\n\n[dependencies]\niced.workspace = true\niced.features = [\"tokio\", \"markdown\", \"highlighter\", \"debug\"]\n\nlog.workspace = true\nthiserror.workspace = true\n\ntokio.features = [\"fs\", \"process\"]\ntokio.workspace = true\n\nserde.workspace = true\nserde.features = [\"derive\"]\n\njiff = \"0.2\"\nwebbrowser = \"1\"\ntracing-subscriber = \"0.3\"\n\n[dependencies.reqwest]\nversion = \"0.12\"\nfeatures = [\"json\"]\n"
  },
  {
    "path": "examples/changelog/src/changelog.rs",
    "content": "use jiff::Timestamp;\nuse serde::Deserialize;\nuse tokio::fs;\nuse tokio::process;\n\nuse std::collections::{BTreeMap, BTreeSet};\nuse std::env;\nuse std::fmt;\nuse std::io;\nuse std::sync::Arc;\n\n#[derive(Debug, Clone)]\npub struct Changelog {\n    ids: Vec<u64>,\n    added: Vec<String>,\n    changed: Vec<String>,\n    fixed: Vec<String>,\n    removed: Vec<String>,\n    authors: Vec<String>,\n    contributions: BTreeMap<String, usize>,\n}\n\nimpl Changelog {\n    pub fn new() -> Self {\n        Self {\n            ids: Vec::new(),\n            added: Vec::new(),\n            changed: Vec::new(),\n            fixed: Vec::new(),\n            removed: Vec::new(),\n            authors: Vec::new(),\n            contributions: BTreeMap::new(),\n        }\n    }\n\n    pub async fn list() -> Result<(Self, Vec<Contribution>), Error> {\n        let mut changelog = Self::new();\n\n        {\n            let markdown = fs::read_to_string(\"CHANGELOG.md\").await?;\n\n            if let Some(unreleased) = markdown.split(\"\\n## \").nth(1) {\n                let sections = unreleased.split(\"\\n\\n\");\n\n                for section in sections {\n                    if section.starts_with(\"Many thanks to...\") {\n                        for author in section.lines().skip(1) {\n                            let author = author.trim_start_matches(\"- @\");\n\n                            if author.is_empty() {\n                                continue;\n                            }\n\n                            changelog.authors.push(author.to_owned());\n                        }\n\n                        continue;\n                    }\n\n                    let Some((_, rest)) = section.split_once(\"### \") else {\n                        continue;\n                    };\n\n                    let Some((name, rest)) = rest.split_once(\"\\n\") else {\n                        continue;\n                    };\n\n                    let category = match name {\n                        \"Added\" => Category::Added,\n                        \"Fixed\" => Category::Fixed,\n                        \"Changed\" => Category::Changed,\n                        \"Removed\" => Category::Removed,\n                        _ => continue,\n                    };\n\n                    for entry in rest.lines() {\n                        let Some((_, id)) = entry.split_once(\"[#\") else {\n                            continue;\n                        };\n\n                        let Some((id, _)) = id.split_once(']') else {\n                            continue;\n                        };\n\n                        let Ok(id): Result<u64, _> = id.parse() else {\n                            continue;\n                        };\n\n                        changelog.ids.push(id);\n\n                        let target = match category {\n                            Category::Added => &mut changelog.added,\n                            Category::Changed => &mut changelog.changed,\n                            Category::Fixed => &mut changelog.fixed,\n                            Category::Removed => &mut changelog.removed,\n                        };\n\n                        target.push(entry.to_owned());\n                    }\n                }\n            }\n        }\n\n        let mut candidates = Contribution::list().await?;\n\n        for candidate in &candidates {\n            *changelog\n                .contributions\n                .entry(candidate.author.clone())\n                .or_default() += 1;\n        }\n\n        for author in &changelog.authors {\n            if !changelog.contributions.contains_key(author) {\n                changelog.contributions.insert(author.clone(), 1);\n            }\n        }\n\n        for reviewed_entry in changelog.entries() {\n            candidates.retain(|candidate| candidate.id != reviewed_entry);\n        }\n\n        Ok((changelog, candidates))\n    }\n\n    pub async fn save(self) -> Result<(), Error> {\n        let markdown = fs::read_to_string(\"CHANGELOG.md\").await?;\n\n        let Some((header, rest)) = markdown.split_once(\"\\n## \") else {\n            return Err(Error::InvalidFormat);\n        };\n\n        let Some((_unreleased, rest)) = rest.split_once(\"\\n## \") else {\n            return Err(Error::InvalidFormat);\n        };\n\n        let unreleased = format!(\"\\n## [Unreleased]\\n{self}\");\n\n        let rest = format!(\"\\n## {rest}\");\n\n        let changelog = [header, &unreleased, &rest].concat();\n        fs::write(\"CHANGELOG.md\", changelog).await?;\n\n        Ok(())\n    }\n\n    pub fn len(&self) -> usize {\n        self.ids.len()\n    }\n\n    pub fn entries(&self) -> impl Iterator<Item = u64> + '_ {\n        self.ids.iter().copied()\n    }\n\n    pub fn push(&mut self, entry: Entry) {\n        self.ids.push(entry.id);\n\n        let item = format!(\n            \"- {title}. [#{id}](https://github.com/iced-rs/iced/pull/{id})\",\n            title = entry.title,\n            id = entry.id\n        );\n\n        let target = match entry.category {\n            Category::Added => &mut self.added,\n            Category::Changed => &mut self.changed,\n            Category::Fixed => &mut self.fixed,\n            Category::Removed => &mut self.removed,\n        };\n\n        target.push(item);\n\n        let _ = self.contributions.entry(entry.author.clone()).or_default();\n\n        if entry.author != \"hecrj\" && !self.authors.contains(&entry.author) {\n            self.authors.push(entry.author);\n        }\n\n        self.authors.sort_by(|a, b| {\n            self.contributions\n                .get(a)\n                .copied()\n                .unwrap_or_default()\n                .cmp(&self.contributions.get(b).copied().unwrap_or_default())\n                .reverse()\n                .then(a.to_lowercase().cmp(&b.to_lowercase()))\n        });\n    }\n}\n\nimpl fmt::Display for Changelog {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fn section(category: Category, entries: &[String]) -> String {\n            if entries.is_empty() {\n                return String::new();\n            }\n\n            format!(\"### {category}\\n{list}\\n\", list = entries.join(\"\\n\"))\n        }\n\n        fn thank_you<'a>(authors: impl IntoIterator<Item = &'a str>) -> String {\n            let mut list = String::new();\n\n            for author in authors {\n                list.push_str(&format!(\"- @{author}\\n\"));\n            }\n\n            format!(\"Many thanks to...\\n{list}\")\n        }\n\n        let changelog = [\n            section(Category::Added, &self.added),\n            section(Category::Changed, &self.changed),\n            section(Category::Fixed, &self.fixed),\n            section(Category::Removed, &self.removed),\n            thank_you(self.authors.iter().map(String::as_str)),\n        ]\n        .into_iter()\n        .filter(|section| !section.is_empty())\n        .collect::<Vec<String>>()\n        .join(\"\\n\");\n\n        f.write_str(&changelog)\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct Entry {\n    pub id: u64,\n    pub title: String,\n    pub category: Category,\n    pub author: String,\n}\n\nimpl Entry {\n    pub fn new(title: &str, category: Category, pull_request: &PullRequest) -> Option<Self> {\n        let title = title.strip_suffix(\".\").unwrap_or(title);\n\n        if title.is_empty() {\n            return None;\n        };\n\n        Some(Self {\n            id: pull_request.id,\n            title: title.to_owned(),\n            category,\n            author: pull_request.author.clone(),\n        })\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Category {\n    Added,\n    Changed,\n    Fixed,\n    Removed,\n}\n\nimpl Category {\n    pub const ALL: &'static [Self] = &[Self::Added, Self::Changed, Self::Fixed, Self::Removed];\n\n    pub fn guess(label: &str) -> Option<Self> {\n        Some(match label {\n            \"feature\" | \"addition\" => Self::Added,\n            \"change\" => Self::Changed,\n            \"bug\" | \"fix\" => Self::Fixed,\n            _ => None?,\n        })\n    }\n}\n\nimpl fmt::Display for Category {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(match self {\n            Category::Added => \"Added\",\n            Category::Changed => \"Changed\",\n            Category::Fixed => \"Fixed\",\n            Category::Removed => \"Removed\",\n        })\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]\npub struct Contribution {\n    pub id: u64,\n    pub author: String,\n}\n\nimpl Contribution {\n    pub async fn list() -> Result<Vec<Contribution>, Error> {\n        let output = process::Command::new(\"git\")\n            .args([\n                \"log\",\n                \"--oneline\",\n                \"--grep\",\n                \"#[0-9]*\",\n                \"origin/latest..HEAD\",\n            ])\n            .output()\n            .await?;\n\n        let log = String::from_utf8_lossy(&output.stdout);\n\n        let mut contributions: Vec<_> = log\n            .lines()\n            .filter(|title| !title.is_empty())\n            .filter_map(|title| {\n                let (_, pull_request) = title.split_once('#')?;\n                let (pull_request, _) = pull_request.split_once([')', ' '])?;\n\n                let (author, _) = title.split_once('/').unwrap_or_default();\n                let (_, author) = author.rsplit_once(' ').unwrap_or_default();\n\n                Some(Contribution {\n                    id: pull_request.parse().ok()?,\n                    author: author.to_owned(),\n                })\n            })\n            .collect();\n\n        let mut unique = BTreeSet::from_iter(contributions.clone());\n        contributions.retain_mut(|contribution| unique.remove(contribution));\n\n        Ok(contributions)\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct PullRequest {\n    pub id: u64,\n    pub title: String,\n    pub description: Option<String>,\n    pub labels: Vec<String>,\n    pub author: String,\n    pub created_at: Timestamp,\n}\n\nimpl PullRequest {\n    pub async fn fetch(contribution: Contribution) -> Result<Self, Error> {\n        let request = reqwest::Client::new()\n            .request(\n                reqwest::Method::GET,\n                format!(\n                    \"https://api.github.com/repos/iced-rs/iced/pulls/{}\",\n                    contribution.id\n                ),\n            )\n            .header(\"User-Agent\", \"iced changelog generator\")\n            .header(\n                \"Authorization\",\n                format!(\n                    \"Bearer {}\",\n                    env::var(\"GITHUB_TOKEN\").map_err(|_| Error::GitHubTokenNotFound)?\n                ),\n            );\n\n        #[derive(Deserialize)]\n        struct Schema {\n            title: String,\n            body: Option<String>,\n            user: User,\n            labels: Vec<Label>,\n            created_at: String,\n        }\n\n        #[derive(Deserialize)]\n        struct User {\n            login: String,\n        }\n\n        #[derive(Deserialize)]\n        struct Label {\n            name: String,\n        }\n\n        let schema: Schema = request.send().await?.json().await?;\n\n        Ok(Self {\n            id: contribution.id,\n            title: schema.title,\n            description: schema.body.map(|body| body.replace(\"\\r\", \"\")),\n            labels: schema.labels.into_iter().map(|label| label.name).collect(),\n            author: schema.user.login,\n            created_at: schema.created_at.parse()?,\n        })\n    }\n}\n\n#[derive(Debug, Clone, thiserror::Error)]\npub enum Error {\n    #[error(\"io operation failed: {0}\")]\n    IOFailed(Arc<io::Error>),\n\n    #[error(\"http request failed: {0}\")]\n    RequestFailed(Arc<reqwest::Error>),\n\n    #[error(\"no GITHUB_TOKEN variable was set\")]\n    GitHubTokenNotFound,\n\n    #[error(\"the changelog format is not valid\")]\n    InvalidFormat,\n\n    #[error(\"date could not be parsed: {0}\")]\n    InvalidDate(#[from] jiff::Error),\n}\n\nimpl From<io::Error> for Error {\n    fn from(error: io::Error) -> Self {\n        Error::IOFailed(Arc::new(error))\n    }\n}\n\nimpl From<reqwest::Error> for Error {\n    fn from(error: reqwest::Error) -> Self {\n        Error::RequestFailed(Arc::new(error))\n    }\n}\n"
  },
  {
    "path": "examples/changelog/src/icon.rs",
    "content": "use iced::widget::{text, Text};\nuse iced::Font;\n\npub const FONT_BYTES: &[u8] = include_bytes!(\"../fonts/changelog-icons.ttf\");\n\nconst FONT: Font = Font::with_name(\"changelog-icons\");\n\npub fn copy() -> Text<'static> {\n    text('\\u{e800}').font(FONT)\n}\n"
  },
  {
    "path": "examples/changelog/src/main.rs",
    "content": "mod changelog;\n\nuse crate::changelog::Changelog;\n\nuse iced::font;\nuse iced::widget::{\n    button, center, column, container, markdown, pick_list, progress_bar, rich_text, row,\n    scrollable, span, stack, text, text_input,\n};\nuse iced::{Center, Element, Fill, FillPortion, Font, Task, Theme};\n\npub fn main() -> iced::Result {\n    tracing_subscriber::fmt::init();\n\n    iced::application(Generator::new, Generator::update, Generator::view)\n        .theme(Generator::theme)\n        .run()\n}\n\nenum Generator {\n    Loading,\n    Reviewing {\n        changelog: Changelog,\n        pending: Vec<changelog::Contribution>,\n        state: State,\n        preview: Vec<markdown::Item>,\n        timezone: jiff::tz::TimeZone,\n    },\n    Done,\n}\n\nenum State {\n    Loading(changelog::Contribution),\n    Loaded {\n        pull_request: changelog::PullRequest,\n        description: Vec<markdown::Item>,\n        title: String,\n        category: changelog::Category,\n    },\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    ChangelogListed(Result<(Changelog, Vec<changelog::Contribution>), changelog::Error>),\n    PullRequestFetched(Result<changelog::PullRequest, changelog::Error>),\n    LinkClicked(markdown::Uri),\n    TitleChanged(String),\n    CategorySelected(changelog::Category),\n    Next,\n    OpenPullRequest(u64),\n    ChangelogSaved(Result<(), changelog::Error>),\n    Quit,\n}\n\nimpl Generator {\n    fn new() -> (Self, Task<Message>) {\n        (\n            Self::Loading,\n            Task::perform(Changelog::list(), Message::ChangelogListed),\n        )\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::ChangelogListed(Ok((changelog, mut pending))) => {\n                if let Some(contribution) = pending.pop() {\n                    let preview = markdown::parse(&changelog.to_string()).collect();\n\n                    *self = Self::Reviewing {\n                        changelog,\n                        pending,\n                        state: State::Loading(contribution.clone()),\n                        preview,\n                        timezone: jiff::tz::TimeZone::system(),\n                    };\n\n                    Task::perform(\n                        changelog::PullRequest::fetch(contribution),\n                        Message::PullRequestFetched,\n                    )\n                } else {\n                    *self = Self::Done;\n\n                    Task::none()\n                }\n            }\n            Message::PullRequestFetched(Ok(pull_request)) => {\n                let Self::Reviewing { state, .. } = self else {\n                    return Task::none();\n                };\n\n                let description = markdown::parse(\n                    pull_request\n                        .description\n                        .as_deref()\n                        .unwrap_or(\"*No description provided*\"),\n                )\n                .collect();\n\n                *state = State::Loaded {\n                    title: pull_request.title.clone(),\n                    category: pull_request\n                        .labels\n                        .iter()\n                        .map(String::as_str)\n                        .filter_map(changelog::Category::guess)\n                        .next()\n                        .unwrap_or(changelog::Category::Added),\n                    pull_request,\n                    description,\n                };\n\n                Task::none()\n            }\n            Message::LinkClicked(url) => {\n                let _ = webbrowser::open(url.as_str());\n\n                Task::none()\n            }\n            Message::TitleChanged(new_title) => {\n                let Self::Reviewing { state, .. } = self else {\n                    return Task::none();\n                };\n\n                let State::Loaded { title, .. } = state else {\n                    return Task::none();\n                };\n\n                *title = new_title;\n\n                Task::none()\n            }\n            Message::CategorySelected(new_category) => {\n                let Self::Reviewing { state, .. } = self else {\n                    return Task::none();\n                };\n\n                let State::Loaded { category, .. } = state else {\n                    return Task::none();\n                };\n\n                *category = new_category;\n\n                Task::none()\n            }\n            Message::Next => {\n                let Self::Reviewing {\n                    changelog,\n                    pending,\n                    state,\n                    preview,\n                    ..\n                } = self\n                else {\n                    return Task::none();\n                };\n\n                let State::Loaded {\n                    title,\n                    category,\n                    pull_request,\n                    ..\n                } = state\n                else {\n                    return Task::none();\n                };\n\n                if let Some(entry) = changelog::Entry::new(title, *category, pull_request) {\n                    changelog.push(entry);\n\n                    let save = Task::perform(changelog.clone().save(), Message::ChangelogSaved);\n\n                    *preview = markdown::parse(&changelog.to_string()).collect();\n\n                    if let Some(contribution) = pending.pop() {\n                        *state = State::Loading(contribution.clone());\n\n                        Task::batch([\n                            save,\n                            Task::perform(\n                                changelog::PullRequest::fetch(contribution),\n                                Message::PullRequestFetched,\n                            ),\n                        ])\n                    } else {\n                        *self = Self::Done;\n                        save\n                    }\n                } else {\n                    Task::none()\n                }\n            }\n            Message::OpenPullRequest(id) => {\n                let _ = webbrowser::open(&format!(\"https://github.com/iced-rs/iced/pull/{id}\"));\n\n                Task::none()\n            }\n            Message::ChangelogSaved(Ok(())) => Task::none(),\n\n            Message::ChangelogListed(Err(error))\n            | Message::PullRequestFetched(Err(error))\n            | Message::ChangelogSaved(Err(error)) => {\n                log::error!(\"{error}\");\n\n                Task::none()\n            }\n            Message::Quit => iced::exit(),\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        match self {\n            Self::Loading => center(\"Loading...\").into(),\n            Self::Done => center(\n                column![\n                    text(\"Changelog is up-to-date! 🎉\").shaping(text::Shaping::Advanced),\n                    button(\"Quit\").on_press(Message::Quit),\n                ]\n                .spacing(10)\n                .align_x(Center),\n            )\n            .into(),\n            Self::Reviewing {\n                changelog,\n                pending,\n                state,\n                preview,\n                timezone,\n            } => {\n                let progress = {\n                    let total = pending.len() + changelog.len();\n                    let percent = 100.0 * changelog.len() as f32 / total as f32;\n\n                    let bar = progress_bar(0.0..=100.0, percent).style(progress_bar::secondary);\n\n                    let label = text!(\n                        \"{amount_reviewed} / {total} ({percent:.0}%)\",\n                        amount_reviewed = changelog.len()\n                    )\n                    .font(Font::MONOSPACE)\n                    .size(12);\n\n                    stack![bar, center(label)]\n                };\n\n                let form: Element<_> = match state {\n                    State::Loading(contribution) => text!(\"Loading #{}...\", contribution.id).into(),\n                    State::Loaded {\n                        pull_request,\n                        description,\n                        title,\n                        category,\n                    } => {\n                        let details = {\n                            let title = rich_text![\n                                span(&pull_request.title).size(24).link(pull_request.id),\n                                \"\\n\",\n                                span(format!(\" by {}\", pull_request.author)).font(Font {\n                                    style: font::Style::Italic,\n                                    ..Font::default()\n                                }),\n                            ]\n                            .on_link_click(Message::OpenPullRequest)\n                            .font(Font::MONOSPACE);\n\n                            let description =\n                                markdown(description, self.theme()).map(Message::LinkClicked);\n\n                            let labels = row(pull_request.labels.iter().map(|label| {\n                                container(text(label).size(10).font(Font::MONOSPACE))\n                                    .padding(5)\n                                    .style(container::rounded_box)\n                                    .into()\n                            }))\n                            .spacing(10)\n                            .wrap();\n\n                            let created_at = text(\n                                timezone\n                                    .to_datetime(pull_request.created_at)\n                                    .strftime(\"%B %d, %Y at %I:%M%p\")\n                                    .to_string(),\n                            )\n                            .size(12);\n\n                            column![\n                                title,\n                                row![labels, created_at].align_y(Center).spacing(10),\n                                scrollable(description).spacing(10).width(Fill).height(Fill)\n                            ]\n                            .spacing(10)\n                        };\n\n                        let title = text_input(\"Type a changelog entry title...\", title)\n                            .on_input(Message::TitleChanged)\n                            .on_submit(Message::Next);\n\n                        let category = pick_list(\n                            Some(category),\n                            changelog::Category::ALL,\n                            changelog::Category::to_string,\n                        )\n                        .on_select(Message::CategorySelected);\n\n                        let next = button(\"Next →\")\n                            .on_press(Message::Next)\n                            .style(button::success);\n\n                        column![details, row![title, category, next].spacing(10)]\n                            .spacing(10)\n                            .into()\n                    }\n                };\n\n                let preview = if preview.is_empty() {\n                    center(\n                        container(text(\"The changelog is empty... so far!\").size(12))\n                            .padding(10)\n                            .style(container::rounded_box),\n                    )\n                } else {\n                    container(\n                        scrollable(\n                            markdown(\n                                preview,\n                                markdown::Settings::with_text_size(12, self.theme()),\n                            )\n                            .map(Message::LinkClicked),\n                        )\n                        .width(Fill)\n                        .spacing(10),\n                    )\n                    .width(Fill)\n                    .padding(10)\n                    .style(container::rounded_box)\n                };\n\n                let review = column![container(form).height(Fill), progress]\n                    .spacing(10)\n                    .width(FillPortion(2));\n\n                row![review, preview].spacing(10).padding(10).into()\n            }\n        }\n    }\n\n    fn theme(&self) -> Theme {\n        Theme::CatppuccinMocha\n    }\n}\n"
  },
  {
    "path": "examples/checkbox/Cargo.toml",
    "content": "[package]\nname = \"checkbox\"\nversion = \"0.1.0\"\nauthors = [\"Casper Rogild Storm<casper@rogildstorm.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\n"
  },
  {
    "path": "examples/checkbox/README.md",
    "content": "## Checkbox\n\nA box that can be checked.\n\nThe __[`main`]__ file contains all the code of the example.\n\nYou can run it with `cargo run`:\n```\ncargo run --package checkbox\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/checkbox/src/main.rs",
    "content": "use iced::widget::{center, checkbox, column, row, text};\nuse iced::{Element, Font};\n\nconst ICON_FONT: Font = Font::new(\"icons\");\n\npub fn main() -> iced::Result {\n    iced::application(Example::default, Example::update, Example::view)\n        .font(include_bytes!(\"../fonts/icons.ttf\").as_slice())\n        .run()\n}\n\n#[derive(Default)]\nstruct Example {\n    default: bool,\n    styled: bool,\n    custom: bool,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    DefaultToggled(bool),\n    CustomToggled(bool),\n    StyledToggled(bool),\n}\n\nimpl Example {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::DefaultToggled(default) => {\n                self.default = default;\n            }\n            Message::StyledToggled(styled) => {\n                self.styled = styled;\n            }\n            Message::CustomToggled(custom) => {\n                self.custom = custom;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let default_checkbox = checkbox(self.default)\n            .label(\"Default\")\n            .on_toggle(Message::DefaultToggled);\n\n        let styled_checkbox = |label| {\n            checkbox(self.styled)\n                .label(label)\n                .on_toggle_maybe(self.default.then_some(Message::StyledToggled))\n        };\n\n        let checkboxes = row![\n            styled_checkbox(\"Primary\").style(checkbox::primary),\n            styled_checkbox(\"Secondary\").style(checkbox::secondary),\n            styled_checkbox(\"Success\").style(checkbox::success),\n            styled_checkbox(\"Danger\").style(checkbox::danger),\n        ]\n        .spacing(20);\n\n        let custom_checkbox = checkbox(self.custom)\n            .label(\"Custom\")\n            .on_toggle(Message::CustomToggled)\n            .icon(checkbox::Icon {\n                font: ICON_FONT,\n                code_point: '\\u{e901}',\n                size: None,\n                line_height: text::LineHeight::Relative(1.0),\n                shaping: text::Shaping::Basic,\n            });\n\n        let content = column![default_checkbox, checkboxes, custom_checkbox].spacing(20);\n\n        center(content).into()\n    }\n}\n"
  },
  {
    "path": "examples/clock/Cargo.toml",
    "content": "[package]\nname = \"clock\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"canvas\", \"tokio\", \"debug\"]\nchrono = \"0.4\"\ntracing-subscriber = \"0.3\"\n"
  },
  {
    "path": "examples/clock/README.md",
    "content": "## Clock\n\nAn application that uses the `Canvas` widget to draw a clock and its hands to display the current time.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://user-images.githubusercontent.com/518289/74716344-a3e6b300-522e-11ea-8aea-3cc0a5100a2e.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package clock\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/clock/src/main.rs",
    "content": "use iced::alignment;\nuse iced::mouse;\nuse iced::time::{self, milliseconds};\nuse iced::widget::canvas::{Cache, Geometry, LineCap, Path, Stroke, stroke};\nuse iced::widget::{canvas, container, text};\nuse iced::{\n    Degrees, Element, Fill, Font, Point, Radians, Rectangle, Renderer, Size, Subscription, Theme,\n    Vector,\n};\n\npub fn main() -> iced::Result {\n    tracing_subscriber::fmt::init();\n\n    iced::application(Clock::new, Clock::update, Clock::view)\n        .subscription(Clock::subscription)\n        .theme(Clock::theme)\n        .run()\n}\n\nstruct Clock {\n    now: chrono::DateTime<chrono::Local>,\n    clock: Cache,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Tick(chrono::DateTime<chrono::Local>),\n}\n\nimpl Clock {\n    fn new() -> Self {\n        Self {\n            now: chrono::offset::Local::now(),\n            clock: Cache::default(),\n        }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Tick(local_time) => {\n                let now = local_time;\n\n                if now != self.now {\n                    self.now = now;\n                    self.clock.clear();\n                }\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let canvas = canvas(self as &Self).width(Fill).height(Fill);\n\n        container(canvas).padding(20).into()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        time::every(milliseconds(500)).map(|_| Message::Tick(chrono::offset::Local::now()))\n    }\n\n    fn theme(&self) -> Theme {\n        Theme::ALL[(self.now.timestamp() as usize / 10) % Theme::ALL.len()].clone()\n    }\n}\n\nimpl<Message> canvas::Program<Message> for Clock {\n    type State = ();\n\n    fn draw(\n        &self,\n        _state: &Self::State,\n        renderer: &Renderer,\n        theme: &Theme,\n        bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Vec<Geometry> {\n        use chrono::Timelike;\n\n        let clock = self.clock.draw(renderer, bounds.size(), |frame| {\n            let palette = theme.palette();\n            let center = frame.center();\n            let radius = frame.width().min(frame.height()) / 2.0;\n\n            let background = Path::circle(center, radius);\n            frame.fill(&background, palette.secondary.strong.color);\n\n            let short_hand = Path::line(Point::ORIGIN, Point::new(0.0, -0.5 * radius));\n\n            let long_hand = Path::line(Point::ORIGIN, Point::new(0.0, -0.8 * radius));\n\n            let width = radius / 100.0;\n\n            let thin_stroke = || -> Stroke {\n                Stroke {\n                    width,\n                    style: stroke::Style::Solid(palette.secondary.strong.text),\n                    line_cap: LineCap::Round,\n                    ..Stroke::default()\n                }\n            };\n\n            let wide_stroke = || -> Stroke {\n                Stroke {\n                    width: width * 3.0,\n                    style: stroke::Style::Solid(palette.secondary.strong.text),\n                    line_cap: LineCap::Round,\n                    ..Stroke::default()\n                }\n            };\n\n            frame.translate(Vector::new(center.x, center.y));\n            let minutes_portion = Radians::from(hand_rotation(self.now.minute(), 60)) / 12.0;\n            let hour_hand_angle =\n                Radians::from(hand_rotation(self.now.hour(), 12)) + minutes_portion;\n\n            frame.with_save(|frame| {\n                frame.rotate(hour_hand_angle);\n                frame.stroke(&short_hand, wide_stroke());\n            });\n\n            frame.with_save(|frame| {\n                frame.rotate(hand_rotation(self.now.minute(), 60));\n                frame.stroke(&long_hand, wide_stroke());\n            });\n\n            frame.with_save(|frame| {\n                let rotation = hand_rotation(self.now.second(), 60);\n\n                frame.rotate(rotation);\n                frame.stroke(&long_hand, thin_stroke());\n\n                let rotate_factor = if rotation < 180.0 { 1.0 } else { -1.0 };\n\n                frame.rotate(Degrees(-90.0 * rotate_factor));\n                frame.fill_text(canvas::Text {\n                    content: theme.to_string(),\n                    size: (radius / 15.0).into(),\n                    position: Point::new((0.78 * radius) * rotate_factor, -width * 2.0),\n                    color: palette.secondary.strong.text,\n                    align_x: if rotate_factor > 0.0 {\n                        text::Alignment::Right\n                    } else {\n                        text::Alignment::Left\n                    },\n                    align_y: alignment::Vertical::Bottom,\n                    font: Font::MONOSPACE,\n                    ..canvas::Text::default()\n                });\n            });\n\n            // Draw clock numbers\n            for hour in 1..=12 {\n                let angle = Radians::from(hand_rotation(hour, 12)) - Radians::from(Degrees(90.0));\n                let x = radius * angle.0.cos();\n                let y = radius * angle.0.sin();\n\n                frame.fill_text(canvas::Text {\n                    content: format!(\"{hour}\"),\n                    size: (radius / 5.0).into(),\n                    position: Point::new(x * 0.82, y * 0.82),\n                    color: palette.secondary.strong.text,\n                    align_x: text::Alignment::Center,\n                    align_y: alignment::Vertical::Center,\n                    font: Font::MONOSPACE,\n                    ..canvas::Text::default()\n                });\n            }\n\n            // Draw ticks\n            for tick in 0..60 {\n                let angle = hand_rotation(tick, 60);\n                let width = if tick % 5 == 0 { 3.0 } else { 1.0 };\n\n                frame.with_save(|frame| {\n                    frame.rotate(angle);\n                    frame.fill(\n                        &Path::rectangle(Point::new(0.0, radius - 15.0), Size::new(width, 7.0)),\n                        palette.secondary.strong.text,\n                    );\n                });\n            }\n        });\n\n        vec![clock]\n    }\n}\n\nfn hand_rotation(n: u32, total: u32) -> Degrees {\n    let turns = n as f32 / total as f32;\n\n    Degrees(360.0 * turns)\n}\n"
  },
  {
    "path": "examples/color_palette/Cargo.toml",
    "content": "[package]\nname = \"color_palette\"\nversion = \"0.1.0\"\nauthors = [\"Clark Moody <clark@clarkmoody.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"canvas\"]\n\npalette = \"0.7\"\n"
  },
  {
    "path": "examples/color_palette/README.md",
    "content": "## Color palette\n\nA color palette generator, based on a user-defined root color.\n\n<div align=\"center\">\n  <img src=\"screenshot.png\">\n</div>\n\nYou can run it with `cargo run`:\n\n```\ncargo run --package color_palette\n```\n"
  },
  {
    "path": "examples/color_palette/src/main.rs",
    "content": "use iced::alignment;\nuse iced::mouse;\nuse iced::theme;\nuse iced::widget::canvas::{self, Canvas, Frame, Geometry, Path};\nuse iced::widget::{Slider, column, row, text};\nuse iced::{Center, Color, Element, Fill, Font, Pixels, Point, Rectangle, Renderer, Size, Vector};\n\nuse palette::{Darken, Hsl, Lighten, ShiftHue, convert::FromColor, rgb::Rgb};\nuse std::marker::PhantomData;\nuse std::ops::RangeInclusive;\n\npub fn main() -> iced::Result {\n    iced::application(\n        ColorPalette::default,\n        ColorPalette::update,\n        ColorPalette::view,\n    )\n    .theme(ColorPalette::theme)\n    .default_font(Font::MONOSPACE)\n    .run()\n}\n\n#[derive(Default)]\npub struct ColorPalette {\n    theme: Theme,\n    rgb: ColorPicker<Color>,\n    hsl: ColorPicker<palette::Hsl>,\n    hsv: ColorPicker<palette::Hsv>,\n    hwb: ColorPicker<palette::Hwb>,\n    lab: ColorPicker<palette::Lab>,\n    lch: ColorPicker<palette::Lch>,\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum Message {\n    RgbColorChanged(Color),\n    HslColorChanged(palette::Hsl),\n    HsvColorChanged(palette::Hsv),\n    HwbColorChanged(palette::Hwb),\n    LabColorChanged(palette::Lab),\n    LchColorChanged(palette::Lch),\n}\n\nimpl ColorPalette {\n    fn update(&mut self, message: Message) {\n        let srgb = match message {\n            Message::RgbColorChanged(rgb) => to_rgb(rgb),\n            Message::HslColorChanged(hsl) => Rgb::from_color(hsl),\n            Message::HsvColorChanged(hsv) => Rgb::from_color(hsv),\n            Message::HwbColorChanged(hwb) => Rgb::from_color(hwb),\n            Message::LabColorChanged(lab) => Rgb::from_color(lab),\n            Message::LchColorChanged(lch) => Rgb::from_color(lch),\n        };\n\n        self.theme = Theme::new(to_color(srgb));\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let base = self.theme.base;\n\n        let srgb = to_rgb(base);\n        let hsl = palette::Hsl::from_color(srgb);\n        let hsv = palette::Hsv::from_color(srgb);\n        let hwb = palette::Hwb::from_color(srgb);\n        let lab = palette::Lab::from_color(srgb);\n        let lch = palette::Lch::from_color(srgb);\n\n        column![\n            self.rgb.view(base).map(Message::RgbColorChanged),\n            self.hsl.view(hsl).map(Message::HslColorChanged),\n            self.hsv.view(hsv).map(Message::HsvColorChanged),\n            self.hwb.view(hwb).map(Message::HwbColorChanged),\n            self.lab.view(lab).map(Message::LabColorChanged),\n            self.lch.view(lch).map(Message::LchColorChanged),\n            self.theme.view(),\n        ]\n        .padding(10)\n        .spacing(10)\n        .into()\n    }\n\n    fn theme(&self) -> iced::Theme {\n        iced::Theme::custom(\n            String::from(\"Custom\"),\n            theme::palette::Seed {\n                background: self.theme.base,\n                primary: *self.theme.lower.first().unwrap(),\n                text: *self.theme.higher.last().unwrap(),\n                success: *self.theme.lower.last().unwrap(),\n                warning: *self.theme.higher.last().unwrap(),\n                danger: *self.theme.higher.last().unwrap(),\n            },\n        )\n    }\n}\n\n#[derive(Debug)]\nstruct Theme {\n    lower: Vec<Color>,\n    base: Color,\n    higher: Vec<Color>,\n    canvas_cache: canvas::Cache,\n}\n\nimpl Theme {\n    pub fn new(base: impl Into<Color>) -> Theme {\n        let base = base.into();\n\n        // Convert to HSL color for manipulation\n        let hsl = Hsl::from_color(to_rgb(base));\n\n        let lower = [\n            hsl.shift_hue(-135.0).lighten(0.075),\n            hsl.shift_hue(-120.0),\n            hsl.shift_hue(-105.0).darken(0.075),\n            hsl.darken(0.075),\n        ];\n\n        let higher = [\n            hsl.lighten(0.075),\n            hsl.shift_hue(105.0).darken(0.075),\n            hsl.shift_hue(120.0),\n            hsl.shift_hue(135.0).lighten(0.075),\n        ];\n\n        Theme {\n            lower: lower\n                .iter()\n                .map(|&color| to_color(Rgb::from_color(color)))\n                .collect(),\n            base,\n            higher: higher\n                .iter()\n                .map(|&color| to_color(Rgb::from_color(color)))\n                .collect(),\n            canvas_cache: canvas::Cache::default(),\n        }\n    }\n\n    pub fn len(&self) -> usize {\n        self.lower.len() + self.higher.len() + 1\n    }\n\n    pub fn colors(&self) -> impl Iterator<Item = &Color> {\n        self.lower\n            .iter()\n            .chain(std::iter::once(&self.base))\n            .chain(self.higher.iter())\n    }\n\n    pub fn view(&self) -> Element<'_, Message> {\n        Canvas::new(self).width(Fill).height(Fill).into()\n    }\n\n    fn draw(&self, frame: &mut Frame, text_color: Color) {\n        let pad = 20.0;\n\n        let box_size = Size {\n            width: frame.width() / self.len() as f32,\n            height: frame.height() / 2.0 - pad,\n        };\n\n        let triangle = Path::new(|path| {\n            path.move_to(Point { x: 0.0, y: -0.5 });\n            path.line_to(Point { x: -0.5, y: 0.0 });\n            path.line_to(Point { x: 0.5, y: 0.0 });\n            path.close();\n        });\n\n        let mut text = canvas::Text {\n            align_x: text::Alignment::Center,\n            align_y: alignment::Vertical::Top,\n            size: Pixels(15.0),\n            color: text_color,\n            ..canvas::Text::default()\n        };\n\n        for (i, &color) in self.colors().enumerate() {\n            let anchor = Point {\n                x: (i as f32) * box_size.width,\n                y: 0.0,\n            };\n            frame.fill_rectangle(anchor, box_size, color);\n\n            // We show a little indicator for the base color\n            if color == self.base {\n                let triangle_x = anchor.x + box_size.width / 2.0;\n\n                frame.with_save(|frame| {\n                    frame.translate(Vector::new(triangle_x, 0.0));\n                    frame.scale(10.0);\n                    frame.rotate(std::f32::consts::PI);\n\n                    frame.fill(&triangle, Color::WHITE);\n                });\n\n                frame.with_save(|frame| {\n                    frame.translate(Vector::new(triangle_x, box_size.height));\n                    frame.scale(10.0);\n\n                    frame.fill(&triangle, Color::WHITE);\n                });\n            }\n\n            frame.fill_text(canvas::Text {\n                content: color_hex_string(&color),\n                position: Point {\n                    x: anchor.x + box_size.width / 2.0,\n                    y: box_size.height,\n                },\n                ..text\n            });\n        }\n\n        text.align_y = alignment::Vertical::Bottom;\n\n        let hsl = Hsl::from_color(to_rgb(self.base));\n        for i in 0..self.len() {\n            let pct = (i as f32 + 1.0) / (self.len() as f32 + 1.0);\n            let graded = Hsl {\n                lightness: 1.0 - pct,\n                ..hsl\n            };\n            let color: Color = to_color(Rgb::from_color(graded));\n\n            let anchor = Point {\n                x: (i as f32) * box_size.width,\n                y: box_size.height + 2.0 * pad,\n            };\n\n            frame.fill_rectangle(anchor, box_size, color);\n\n            frame.fill_text(canvas::Text {\n                content: color_hex_string(&color),\n                position: Point {\n                    x: anchor.x + box_size.width / 2.0,\n                    y: box_size.height + 2.0 * pad,\n                },\n                ..text\n            });\n        }\n    }\n}\n\nimpl<Message> canvas::Program<Message> for Theme {\n    type State = ();\n\n    fn draw(\n        &self,\n        _state: &Self::State,\n        renderer: &Renderer,\n        theme: &iced::Theme,\n        bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Vec<Geometry> {\n        let theme = self.canvas_cache.draw(renderer, bounds.size(), |frame| {\n            let palette = theme.palette();\n\n            self.draw(frame, palette.background.base.text);\n        });\n\n        vec![theme]\n    }\n}\n\nimpl Default for Theme {\n    fn default() -> Self {\n        Theme::new(Color::from_rgb8(75, 128, 190))\n    }\n}\n\nfn color_hex_string(color: &Color) -> String {\n    format!(\n        \"#{:x}{:x}{:x}\",\n        (255.0 * color.r).round() as u8,\n        (255.0 * color.g).round() as u8,\n        (255.0 * color.b).round() as u8\n    )\n}\n\n#[derive(Default)]\nstruct ColorPicker<C: ColorSpace> {\n    color_space: PhantomData<C>,\n}\n\ntrait ColorSpace: Sized {\n    const LABEL: &'static str;\n    const COMPONENT_RANGES: [RangeInclusive<f64>; 3];\n\n    fn new(a: f32, b: f32, c: f32) -> Self;\n\n    fn components(&self) -> [f32; 3];\n\n    fn to_string(&self) -> String;\n}\n\nimpl<C: ColorSpace + Copy> ColorPicker<C> {\n    fn view(&self, color: C) -> Element<'_, C> {\n        let [c1, c2, c3] = color.components();\n        let [cr1, cr2, cr3] = C::COMPONENT_RANGES;\n\n        fn slider<'a, C: Clone>(\n            range: RangeInclusive<f64>,\n            component: f32,\n            update: impl Fn(f32) -> C + 'a,\n        ) -> Slider<'a, f64, C> {\n            Slider::new(range, f64::from(component), move |v| update(v as f32)).step(0.01)\n        }\n\n        row![\n            text(C::LABEL).width(50),\n            slider(cr1, c1, move |v| C::new(v, c2, c3)),\n            slider(cr2, c2, move |v| C::new(c1, v, c3)),\n            slider(cr3, c3, move |v| C::new(c1, c2, v)),\n            text(color.to_string()).width(185).size(12),\n        ]\n        .spacing(10)\n        .align_y(Center)\n        .into()\n    }\n}\n\nimpl ColorSpace for Color {\n    const LABEL: &'static str = \"RGB\";\n    const COMPONENT_RANGES: [RangeInclusive<f64>; 3] = [0.0..=1.0, 0.0..=1.0, 0.0..=1.0];\n\n    fn new(r: f32, g: f32, b: f32) -> Self {\n        Color::from_rgb(r, g, b)\n    }\n\n    fn components(&self) -> [f32; 3] {\n        [self.r, self.g, self.b]\n    }\n\n    fn to_string(&self) -> String {\n        format!(\n            \"rgb({:.0}, {:.0}, {:.0})\",\n            255.0 * self.r,\n            255.0 * self.g,\n            255.0 * self.b\n        )\n    }\n}\n\nimpl ColorSpace for palette::Hsl {\n    const LABEL: &'static str = \"HSL\";\n    const COMPONENT_RANGES: [RangeInclusive<f64>; 3] = [0.0..=360.0, 0.0..=1.0, 0.0..=1.0];\n\n    fn new(hue: f32, saturation: f32, lightness: f32) -> Self {\n        palette::Hsl::new(palette::RgbHue::from_degrees(hue), saturation, lightness)\n    }\n\n    fn components(&self) -> [f32; 3] {\n        [\n            self.hue.into_positive_degrees(),\n            self.saturation,\n            self.lightness,\n        ]\n    }\n\n    fn to_string(&self) -> String {\n        format!(\n            \"hsl({:.1}, {:.1}%, {:.1}%)\",\n            self.hue.into_positive_degrees(),\n            100.0 * self.saturation,\n            100.0 * self.lightness\n        )\n    }\n}\n\nimpl ColorSpace for palette::Hsv {\n    const LABEL: &'static str = \"HSV\";\n    const COMPONENT_RANGES: [RangeInclusive<f64>; 3] = [0.0..=360.0, 0.0..=1.0, 0.0..=1.0];\n\n    fn new(hue: f32, saturation: f32, value: f32) -> Self {\n        palette::Hsv::new(palette::RgbHue::from_degrees(hue), saturation, value)\n    }\n\n    fn components(&self) -> [f32; 3] {\n        [\n            self.hue.into_positive_degrees(),\n            self.saturation,\n            self.value,\n        ]\n    }\n\n    fn to_string(&self) -> String {\n        format!(\n            \"hsv({:.1}, {:.1}%, {:.1}%)\",\n            self.hue.into_positive_degrees(),\n            100.0 * self.saturation,\n            100.0 * self.value\n        )\n    }\n}\n\nimpl ColorSpace for palette::Hwb {\n    const LABEL: &'static str = \"HWB\";\n    const COMPONENT_RANGES: [RangeInclusive<f64>; 3] = [0.0..=360.0, 0.0..=1.0, 0.0..=1.0];\n\n    fn new(hue: f32, whiteness: f32, blackness: f32) -> Self {\n        palette::Hwb::new(palette::RgbHue::from_degrees(hue), whiteness, blackness)\n    }\n\n    fn components(&self) -> [f32; 3] {\n        [\n            self.hue.into_positive_degrees(),\n            self.whiteness,\n            self.blackness,\n        ]\n    }\n\n    fn to_string(&self) -> String {\n        format!(\n            \"hwb({:.1}, {:.1}%, {:.1}%)\",\n            self.hue.into_positive_degrees(),\n            100.0 * self.whiteness,\n            100.0 * self.blackness\n        )\n    }\n}\n\nimpl ColorSpace for palette::Lab {\n    const LABEL: &'static str = \"Lab\";\n    const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =\n        [0.0..=100.0, -128.0..=127.0, -128.0..=127.0];\n\n    fn new(l: f32, a: f32, b: f32) -> Self {\n        palette::Lab::new(l, a, b)\n    }\n\n    fn components(&self) -> [f32; 3] {\n        [self.l, self.a, self.b]\n    }\n\n    fn to_string(&self) -> String {\n        format!(\"Lab({:.1}, {:.1}, {:.1})\", self.l, self.a, self.b)\n    }\n}\n\nimpl ColorSpace for palette::Lch {\n    const LABEL: &'static str = \"Lch\";\n    const COMPONENT_RANGES: [RangeInclusive<f64>; 3] = [0.0..=100.0, 0.0..=128.0, 0.0..=360.0];\n\n    fn new(l: f32, chroma: f32, hue: f32) -> Self {\n        palette::Lch::new(l, chroma, palette::LabHue::from_degrees(hue))\n    }\n\n    fn components(&self) -> [f32; 3] {\n        [self.l, self.chroma, self.hue.into_positive_degrees()]\n    }\n\n    fn to_string(&self) -> String {\n        format!(\n            \"Lch({:.1}, {:.1}, {:.1})\",\n            self.l,\n            self.chroma,\n            self.hue.into_positive_degrees()\n        )\n    }\n}\n\nfn to_rgb(color: Color) -> Rgb {\n    Rgb {\n        red: color.r,\n        green: color.g,\n        blue: color.b,\n        ..Rgb::default()\n    }\n}\n\nfn to_color(rgb: Rgb) -> Color {\n    Color {\n        r: rgb.red,\n        g: rgb.green,\n        b: rgb.blue,\n        a: 1.0,\n    }\n}\n"
  },
  {
    "path": "examples/combo_box/Cargo.toml",
    "content": "[package]\nname = \"combo_box\"\nversion = \"0.1.0\"\nauthors = [\"Joao Freitas <jhff.15@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\"]\n"
  },
  {
    "path": "examples/combo_box/README.md",
    "content": "## Combo-Box\n\nA dropdown list of searchable and selectable options.\n\nIt displays and positions an overlay based on the window position of the widget.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n    <img src=\"combobox.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package combo_box\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/combo_box/src/main.rs",
    "content": "use iced::widget::{center, column, combo_box, scrollable, space, text};\nuse iced::{Center, Element, Fill};\n\npub fn main() -> iced::Result {\n    iced::run(Example::update, Example::view)\n}\n\nstruct Example {\n    languages: combo_box::State<Language>,\n    selected_language: Option<Language>,\n    text: String,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Selected(Language),\n    OptionHovered(Language),\n    Closed,\n}\n\nimpl Example {\n    fn new() -> Self {\n        Self {\n            languages: combo_box::State::new(Language::ALL.to_vec()),\n            selected_language: None,\n            text: String::new(),\n        }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Selected(language) => {\n                self.selected_language = Some(language);\n                self.text = language.hello().to_string();\n            }\n            Message::OptionHovered(language) => {\n                self.text = language.hello().to_string();\n            }\n            Message::Closed => {\n                self.text = self\n                    .selected_language\n                    .map(|language| language.hello().to_string())\n                    .unwrap_or_default();\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let combo_box = combo_box(\n            &self.languages,\n            \"Type a language...\",\n            self.selected_language.as_ref(),\n            Message::Selected,\n        )\n        .on_option_hovered(Message::OptionHovered)\n        .on_close(Message::Closed)\n        .width(250);\n\n        let content = column![\n            text(&self.text),\n            \"What is your language?\",\n            combo_box,\n            space().height(150),\n        ]\n        .width(Fill)\n        .align_x(Center)\n        .spacing(10);\n\n        center(scrollable(content)).into()\n    }\n}\n\nimpl Default for Example {\n    fn default() -> Self {\n        Example::new()\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum Language {\n    Danish,\n    #[default]\n    English,\n    French,\n    German,\n    Italian,\n    Japanese,\n    Portuguese,\n    Spanish,\n    Other,\n}\n\nimpl Language {\n    const ALL: [Language; 9] = [\n        Language::Danish,\n        Language::English,\n        Language::French,\n        Language::German,\n        Language::Italian,\n        Language::Japanese,\n        Language::Portuguese,\n        Language::Spanish,\n        Language::Other,\n    ];\n\n    fn hello(&self) -> &str {\n        match self {\n            Language::Danish => \"Halloy!\",\n            Language::English => \"Hello!\",\n            Language::French => \"Salut!\",\n            Language::German => \"Hallo!\",\n            Language::Italian => \"Ciao!\",\n            Language::Japanese => \"こんにちは!\",\n            Language::Portuguese => \"Olá!\",\n            Language::Spanish => \"¡Hola!\",\n            Language::Other => \"... hello?\",\n        }\n    }\n}\n\nimpl std::fmt::Display for Language {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"{}\",\n            match self {\n                Language::Danish => \"Danish\",\n                Language::English => \"English\",\n                Language::French => \"French\",\n                Language::German => \"German\",\n                Language::Italian => \"Italian\",\n                Language::Japanese => \"日本語\",\n                Language::Portuguese => \"Portuguese\",\n                Language::Spanish => \"Spanish\",\n                Language::Other => \"Some other language\",\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "examples/counter/Cargo.toml",
    "content": "[package]\nname = \"counter\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\niced.workspace = true\niced.features = [\"webgl\", \"fira-sans\"]\n\n[dev-dependencies]\niced_test.workspace = true\n"
  },
  {
    "path": "examples/counter/README.md",
    "content": "## Counter\n\nThe classic counter example explained in the [`README`](../../README.md).\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/counter.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package counter\n```\n\nThe web version can be run with [`trunk`]:\n\n```\ncd examples/counter\ntrunk serve\n```\n\n[`main`]: src/main.rs\n[`trunk`]: https://trunkrs.dev/\n"
  },
  {
    "path": "examples/counter/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>Counter - Iced</title>\n    <base data-trunk-public-url />\n</head>\n<body>\n<link data-trunk rel=\"rust\" href=\"Cargo.toml\" data-wasm-opt=\"z\" data-bin=\"counter\" />\n</body>\n</html>\n"
  },
  {
    "path": "examples/counter/src/main.rs",
    "content": "use iced::Center;\nuse iced::widget::{Column, button, column, text};\n\npub fn main() -> iced::Result {\n    iced::run(Counter::update, Counter::view)\n}\n\n#[derive(Default)]\nstruct Counter {\n    value: i64,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Increment,\n    Decrement,\n}\n\nimpl Counter {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Increment => {\n                self.value += 1;\n            }\n            Message::Decrement => {\n                self.value -= 1;\n            }\n        }\n    }\n\n    fn view(&self) -> Column<'_, Message> {\n        column![\n            button(\"Increment\").on_press(Message::Increment),\n            text(self.value).size(50),\n            button(\"Decrement\").on_press(Message::Decrement)\n        ]\n        .padding(20)\n        .align_x(Center)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use iced_test::{Error, simulator};\n\n    #[test]\n    fn it_counts() -> Result<(), Error> {\n        let mut counter = Counter { value: 0 };\n        let mut ui = simulator(counter.view());\n\n        let _ = ui.click(\"Increment\")?;\n        let _ = ui.click(\"Increment\")?;\n        let _ = ui.click(\"Decrement\")?;\n\n        for message in ui.into_messages() {\n            counter.update(message);\n        }\n\n        assert_eq!(counter.value, 1);\n\n        let mut ui = simulator(counter.view());\n        assert!(ui.find(\"1\").is_ok(), \"Counter should display 1!\");\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "examples/custom_quad/Cargo.toml",
    "content": "[package]\nname = \"custom_quad\"\nversion = \"0.1.0\"\nauthors = [\"Robert Krahn\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"advanced\"]\n"
  },
  {
    "path": "examples/custom_quad/src/main.rs",
    "content": "//! This example showcases a drawing a quad.\nuse iced::border;\nuse iced::widget::{center, column, slider, text, toggler};\nuse iced::{Center, Color, Element, Shadow, Vector};\n\npub fn main() -> iced::Result {\n    iced::run(Example::update, Example::view)\n}\n\nstruct Example {\n    radius: border::Radius,\n    border_width: f32,\n    shadow: Shadow,\n    snap: bool,\n}\n\n#[derive(Debug, Clone, Copy)]\n#[allow(clippy::enum_variant_names)]\nenum Message {\n    RadiusTopLeftChanged(f32),\n    RadiusTopRightChanged(f32),\n    RadiusBottomRightChanged(f32),\n    RadiusBottomLeftChanged(f32),\n    BorderWidthChanged(f32),\n    ShadowXOffsetChanged(f32),\n    ShadowYOffsetChanged(f32),\n    ShadowBlurRadiusChanged(f32),\n    SnapToggled(bool),\n}\n\nimpl Example {\n    fn new() -> Self {\n        Self {\n            radius: border::radius(50),\n            border_width: 0.0,\n            shadow: Shadow {\n                color: Color::from_rgba(0.0, 0.0, 0.0, 0.8),\n                offset: Vector::new(0.0, 8.0),\n                blur_radius: 16.0,\n            },\n            snap: false,\n        }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::RadiusTopLeftChanged(radius) => {\n                self.radius = self.radius.top_left(radius);\n            }\n            Message::RadiusTopRightChanged(radius) => {\n                self.radius = self.radius.top_right(radius);\n            }\n            Message::RadiusBottomRightChanged(radius) => {\n                self.radius = self.radius.bottom_right(radius);\n            }\n            Message::RadiusBottomLeftChanged(radius) => {\n                self.radius = self.radius.bottom_left(radius);\n            }\n            Message::BorderWidthChanged(width) => {\n                self.border_width = width;\n            }\n            Message::ShadowXOffsetChanged(x) => {\n                self.shadow.offset.x = x;\n            }\n            Message::ShadowYOffsetChanged(y) => {\n                self.shadow.offset.y = y;\n            }\n            Message::ShadowBlurRadiusChanged(s) => {\n                self.shadow.blur_radius = s;\n            }\n            Message::SnapToggled(snap) => {\n                self.snap = snap;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let border::Radius {\n            top_left,\n            top_right,\n            bottom_right,\n            bottom_left,\n        } = self.radius;\n\n        let Shadow {\n            offset: Vector { x: sx, y: sy },\n            blur_radius: sr,\n            ..\n        } = self.shadow;\n\n        let content = column![\n            quad::CustomQuad::new(\n                200.0,\n                self.radius,\n                self.border_width,\n                self.shadow,\n                self.snap,\n            ),\n            text!(\"Radius: {top_left:.2}/{top_right:.2}/{bottom_right:.2}/{bottom_left:.2}\"),\n            slider(1.0..=200.0, top_left, Message::RadiusTopLeftChanged).step(0.01),\n            slider(1.0..=200.0, top_right, Message::RadiusTopRightChanged).step(0.01),\n            slider(1.0..=200.0, bottom_right, Message::RadiusBottomRightChanged).step(0.01),\n            slider(1.0..=200.0, bottom_left, Message::RadiusBottomLeftChanged).step(0.01),\n            slider(0.0..=10.0, self.border_width, Message::BorderWidthChanged).step(0.01),\n            text!(\"Shadow: {sx:.2}x{sy:.2}, {sr:.2}\"),\n            slider(-100.0..=100.0, sx, Message::ShadowXOffsetChanged).step(0.01),\n            slider(-100.0..=100.0, sy, Message::ShadowYOffsetChanged).step(0.01),\n            slider(0.0..=100.0, sr, Message::ShadowBlurRadiusChanged).step(0.01),\n            toggler(self.snap)\n                .label(\"Snap to pixel grid\")\n                .on_toggle(Message::SnapToggled),\n        ]\n        .padding(20)\n        .spacing(20)\n        .max_width(500)\n        .align_x(Center);\n\n        center(content).into()\n    }\n}\n\nimpl Default for Example {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nmod quad {\n    use iced::advanced::layout::{self, Layout};\n    use iced::advanced::renderer;\n    use iced::advanced::widget::{self, Widget};\n    use iced::border;\n    use iced::mouse;\n    use iced::{Border, Color, Element, Length, Rectangle, Shadow, Size};\n\n    pub struct CustomQuad {\n        size: f32,\n        radius: border::Radius,\n        border_width: f32,\n        shadow: Shadow,\n        snap: bool,\n    }\n\n    impl CustomQuad {\n        pub fn new(\n            size: f32,\n            radius: border::Radius,\n            border_width: f32,\n            shadow: Shadow,\n            snap: bool,\n        ) -> Self {\n            Self {\n                size,\n                radius,\n                border_width,\n                shadow,\n                snap,\n            }\n        }\n    }\n\n    impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for CustomQuad\n    where\n        Renderer: renderer::Renderer,\n    {\n        fn size(&self) -> Size<Length> {\n            Size {\n                width: Length::Shrink,\n                height: Length::Shrink,\n            }\n        }\n\n        fn layout(\n            &mut self,\n            _tree: &mut widget::Tree,\n            _renderer: &Renderer,\n            _limits: &layout::Limits,\n        ) -> layout::Node {\n            layout::Node::new(Size::new(self.size, self.size))\n        }\n\n        fn draw(\n            &self,\n            _tree: &widget::Tree,\n            renderer: &mut Renderer,\n            _theme: &Theme,\n            _style: &renderer::Style,\n            layout: Layout<'_>,\n            _cursor: mouse::Cursor,\n            _viewport: &Rectangle,\n        ) {\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds: layout.bounds(),\n                    border: Border {\n                        radius: self.radius,\n                        width: self.border_width,\n                        color: Color::from_rgb(1.0, 0.0, 0.0),\n                    },\n                    shadow: self.shadow,\n                    snap: self.snap,\n                },\n                Color::BLACK,\n            );\n        }\n    }\n\n    impl<Message> From<CustomQuad> for Element<'_, Message> {\n        fn from(circle: CustomQuad) -> Self {\n            Self::new(circle)\n        }\n    }\n}\n"
  },
  {
    "path": "examples/custom_shader/Cargo.toml",
    "content": "[package]\nname = \"custom_shader\"\nversion = \"0.1.0\"\nauthors = [\"Bingus <shankern@protonmail.com>\"]\nedition = \"2024\"\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"image\", \"advanced\"]\n\nimage.workspace = true\nbytemuck.workspace = true\n\nglam.workspace = true\nglam.features = [\"bytemuck\"]\n\nrand = \"0.8.5\"\n"
  },
  {
    "path": "examples/custom_shader/src/main.rs",
    "content": "mod scene;\n\nuse scene::Scene;\n\nuse iced::time::Instant;\nuse iced::wgpu;\nuse iced::widget::{center, checkbox, column, row, shader, slider, text};\nuse iced::window;\nuse iced::{Center, Color, Element, Fill, Subscription};\n\nfn main() -> iced::Result {\n    iced::application(IcedCubes::default, IcedCubes::update, IcedCubes::view)\n        .subscription(IcedCubes::subscription)\n        .run()\n}\n\nstruct IcedCubes {\n    start: Instant,\n    scene: Scene,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    CubeAmountChanged(u32),\n    CubeSizeChanged(f32),\n    Tick(Instant),\n    ShowDepthBuffer(bool),\n    LightColorChanged(Color),\n}\n\nimpl IcedCubes {\n    fn new() -> Self {\n        Self {\n            start: Instant::now(),\n            scene: Scene::new(),\n        }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::CubeAmountChanged(amount) => {\n                self.scene.change_amount(amount);\n            }\n            Message::CubeSizeChanged(size) => {\n                self.scene.size = size;\n            }\n            Message::Tick(time) => {\n                self.scene.update(time - self.start);\n            }\n            Message::ShowDepthBuffer(show) => {\n                self.scene.show_depth_buffer = show;\n            }\n            Message::LightColorChanged(color) => {\n                self.scene.light_color = color;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let top_controls = row![\n            control(\n                \"Amount\",\n                slider(\n                    1..=scene::MAX,\n                    self.scene.cubes.len() as u32,\n                    Message::CubeAmountChanged\n                )\n                .width(100)\n            ),\n            control(\n                \"Size\",\n                slider(0.1..=0.25, self.scene.size, Message::CubeSizeChanged)\n                    .step(0.01)\n                    .width(100),\n            ),\n            checkbox(self.scene.show_depth_buffer)\n                .label(\"Show Depth Buffer\")\n                .on_toggle(Message::ShowDepthBuffer),\n        ]\n        .spacing(40);\n\n        let bottom_controls = row![\n            control(\n                \"R\",\n                slider(0.0..=1.0, self.scene.light_color.r, move |r| {\n                    Message::LightColorChanged(Color {\n                        r,\n                        ..self.scene.light_color\n                    })\n                })\n                .step(0.01)\n                .width(100)\n            ),\n            control(\n                \"G\",\n                slider(0.0..=1.0, self.scene.light_color.g, move |g| {\n                    Message::LightColorChanged(Color {\n                        g,\n                        ..self.scene.light_color\n                    })\n                })\n                .step(0.01)\n                .width(100)\n            ),\n            control(\n                \"B\",\n                slider(0.0..=1.0, self.scene.light_color.b, move |b| {\n                    Message::LightColorChanged(Color {\n                        b,\n                        ..self.scene.light_color\n                    })\n                })\n                .step(0.01)\n                .width(100)\n            )\n        ]\n        .spacing(40);\n\n        let controls = column![top_controls, bottom_controls,]\n            .spacing(10)\n            .padding(20)\n            .align_x(Center);\n\n        let shader = shader(&self.scene).width(Fill).height(Fill);\n\n        center(column![shader, controls].align_x(Center)).into()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        window::frames().map(Message::Tick)\n    }\n}\n\nimpl Default for IcedCubes {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nfn control<'a>(\n    label: &'static str,\n    control: impl Into<Element<'a, Message>>,\n) -> Element<'a, Message> {\n    row![text(label), control.into()].spacing(10).into()\n}\n"
  },
  {
    "path": "examples/custom_shader/src/scene/camera.rs",
    "content": "use glam::{mat4, vec3, vec4};\nuse iced::Rectangle;\n\n#[derive(Copy, Clone)]\npub struct Camera {\n    eye: glam::Vec3,\n    target: glam::Vec3,\n    up: glam::Vec3,\n    fov_y: f32,\n    near: f32,\n    far: f32,\n}\n\nimpl Default for Camera {\n    fn default() -> Self {\n        Self {\n            eye: vec3(0.0, 2.0, 3.0),\n            target: glam::Vec3::ZERO,\n            up: glam::Vec3::Y,\n            fov_y: 45.0,\n            near: 0.1,\n            far: 100.0,\n        }\n    }\n}\n\npub const OPENGL_TO_WGPU_MATRIX: glam::Mat4 = mat4(\n    vec4(1.0, 0.0, 0.0, 0.0),\n    vec4(0.0, 1.0, 0.0, 0.0),\n    vec4(0.0, 0.0, 0.5, 0.0),\n    vec4(0.0, 0.0, 0.5, 1.0),\n);\n\nimpl Camera {\n    pub fn build_view_proj_matrix(&self, bounds: Rectangle) -> glam::Mat4 {\n        let aspect_ratio = bounds.width / bounds.height;\n        let view = glam::Mat4::look_at_rh(self.eye, self.target, self.up);\n        let proj = glam::Mat4::perspective_rh(self.fov_y, aspect_ratio, self.near, self.far);\n\n        OPENGL_TO_WGPU_MATRIX * proj * view\n    }\n\n    pub fn position(&self) -> glam::Vec4 {\n        glam::Vec4::from((self.eye, 0.0))\n    }\n}\n"
  },
  {
    "path": "examples/custom_shader/src/scene/pipeline/buffer.rs",
    "content": "use crate::wgpu;\n\n// A custom buffer container for dynamic resizing.\npub struct Buffer {\n    pub raw: wgpu::Buffer,\n    label: &'static str,\n    size: u64,\n    usage: wgpu::BufferUsages,\n}\n\nimpl Buffer {\n    pub fn new(\n        device: &wgpu::Device,\n        label: &'static str,\n        size: u64,\n        usage: wgpu::BufferUsages,\n    ) -> Self {\n        Self {\n            raw: device.create_buffer(&wgpu::BufferDescriptor {\n                label: Some(label),\n                size,\n                usage,\n                mapped_at_creation: false,\n            }),\n            label,\n            size,\n            usage,\n        }\n    }\n\n    pub fn resize(&mut self, device: &wgpu::Device, new_size: u64) {\n        if new_size > self.size {\n            self.raw = device.create_buffer(&wgpu::BufferDescriptor {\n                label: Some(self.label),\n                size: new_size,\n                usage: self.usage,\n                mapped_at_creation: false,\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "examples/custom_shader/src/scene/pipeline/cube.rs",
    "content": "use crate::scene::pipeline::Vertex;\nuse crate::wgpu;\n\nuse glam::{Vec3, vec2, vec3};\nuse rand::{Rng, thread_rng};\n\n/// A single instance of a cube.\n#[derive(Debug, Clone)]\npub struct Cube {\n    pub rotation: glam::Quat,\n    pub position: Vec3,\n    pub size: f32,\n    rotation_dir: f32,\n    rotation_axis: glam::Vec3,\n}\n\nimpl Default for Cube {\n    fn default() -> Self {\n        Self {\n            rotation: glam::Quat::IDENTITY,\n            position: glam::Vec3::ZERO,\n            size: 0.1,\n            rotation_dir: 1.0,\n            rotation_axis: glam::Vec3::Y,\n        }\n    }\n}\n\nimpl Cube {\n    pub fn new(size: f32, origin: Vec3) -> Self {\n        let rnd = thread_rng().gen_range(0.0..=1.0f32);\n\n        Self {\n            rotation: glam::Quat::IDENTITY,\n            position: origin + Vec3::new(0.1, 0.1, 0.1),\n            size,\n            rotation_dir: if rnd <= 0.5 { -1.0 } else { 1.0 },\n            rotation_axis: if rnd <= 0.33 {\n                glam::Vec3::Y\n            } else if rnd <= 0.66 {\n                glam::Vec3::X\n            } else {\n                glam::Vec3::Z\n            },\n        }\n    }\n\n    pub fn update(&mut self, size: f32, time: f32) {\n        self.rotation =\n            glam::Quat::from_axis_angle(self.rotation_axis, time / 2.0 * self.rotation_dir);\n        self.size = size;\n    }\n}\n\n#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable, Debug)]\n#[repr(C)]\npub struct Raw {\n    transformation: glam::Mat4,\n    normal: glam::Mat3,\n    _padding: [f32; 3],\n}\n\nimpl Raw {\n    const ATTRIBS: [wgpu::VertexAttribute; 7] = wgpu::vertex_attr_array![\n        //cube transformation matrix\n        4 => Float32x4,\n        5 => Float32x4,\n        6 => Float32x4,\n        7 => Float32x4,\n        //normal rotation matrix\n        8 => Float32x3,\n        9 => Float32x3,\n        10 => Float32x3,\n    ];\n\n    pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {\n        wgpu::VertexBufferLayout {\n            array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,\n            step_mode: wgpu::VertexStepMode::Instance,\n            attributes: &Self::ATTRIBS,\n        }\n    }\n}\n\nimpl Raw {\n    pub fn from_cube(cube: &Cube) -> Raw {\n        Raw {\n            transformation: glam::Mat4::from_scale_rotation_translation(\n                glam::vec3(cube.size, cube.size, cube.size),\n                cube.rotation,\n                cube.position,\n            ),\n            normal: glam::Mat3::from_quat(cube.rotation),\n            _padding: [0.0; 3],\n        }\n    }\n\n    pub fn vertices() -> [Vertex; 36] {\n        [\n            //face 1\n            Vertex {\n                pos: vec3(-0.5, -0.5, -0.5),\n                normal: vec3(0.0, 0.0, -1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, -0.5, -0.5),\n                normal: vec3(0.0, 0.0, -1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, -0.5),\n                normal: vec3(0.0, 0.0, -1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, -0.5),\n                normal: vec3(0.0, 0.0, -1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, 0.5, -0.5),\n                normal: vec3(0.0, 0.0, -1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, -0.5, -0.5),\n                normal: vec3(0.0, 0.0, -1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 1.0),\n            },\n            //face 2\n            Vertex {\n                pos: vec3(-0.5, -0.5, 0.5),\n                normal: vec3(0.0, 0.0, 1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, -0.5, 0.5),\n                normal: vec3(0.0, 0.0, 1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, 0.5),\n                normal: vec3(0.0, 0.0, 1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, 0.5),\n                normal: vec3(0.0, 0.0, 1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, 0.5, 0.5),\n                normal: vec3(0.0, 0.0, 1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, -0.5, 0.5),\n                normal: vec3(0.0, 0.0, 1.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 1.0),\n            },\n            //face 3\n            Vertex {\n                pos: vec3(-0.5, 0.5, 0.5),\n                normal: vec3(-1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(0.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, 0.5, -0.5),\n                normal: vec3(-1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(1.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, -0.5, -0.5),\n                normal: vec3(-1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, -0.5, -0.5),\n                normal: vec3(-1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, -0.5, 0.5),\n                normal: vec3(-1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(0.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, 0.5, 0.5),\n                normal: vec3(-1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(0.0, 1.0),\n            },\n            //face 4\n            Vertex {\n                pos: vec3(0.5, 0.5, 0.5),\n                normal: vec3(1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(0.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, -0.5),\n                normal: vec3(1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(1.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, -0.5, -0.5),\n                normal: vec3(1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(0.5, -0.5, -0.5),\n                normal: vec3(1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(0.5, -0.5, 0.5),\n                normal: vec3(1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(0.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, 0.5),\n                normal: vec3(1.0, 0.0, 0.0),\n                tangent: vec3(0.0, 0.0, -1.0),\n                uv: vec2(0.0, 1.0),\n            },\n            //face 5\n            Vertex {\n                pos: vec3(-0.5, -0.5, -0.5),\n                normal: vec3(0.0, -1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, -0.5, -0.5),\n                normal: vec3(0.0, -1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, -0.5, 0.5),\n                normal: vec3(0.0, -1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(0.5, -0.5, 0.5),\n                normal: vec3(0.0, -1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, -0.5, 0.5),\n                normal: vec3(0.0, -1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, -0.5, -0.5),\n                normal: vec3(0.0, -1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 1.0),\n            },\n            //face 6\n            Vertex {\n                pos: vec3(-0.5, 0.5, -0.5),\n                normal: vec3(0.0, 1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, -0.5),\n                normal: vec3(0.0, 1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 1.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, 0.5),\n                normal: vec3(0.0, 1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(0.5, 0.5, 0.5),\n                normal: vec3(0.0, 1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(1.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, 0.5, 0.5),\n                normal: vec3(0.0, 1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 0.0),\n            },\n            Vertex {\n                pos: vec3(-0.5, 0.5, -0.5),\n                normal: vec3(0.0, 1.0, 0.0),\n                tangent: vec3(1.0, 0.0, 0.0),\n                uv: vec2(0.0, 1.0),\n            },\n        ]\n    }\n}\n"
  },
  {
    "path": "examples/custom_shader/src/scene/pipeline/uniforms.rs",
    "content": "use crate::scene::Camera;\n\nuse iced::{Color, Rectangle};\n\n#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]\n#[repr(C)]\npub struct Uniforms {\n    camera_proj: glam::Mat4,\n    camera_pos: glam::Vec4,\n    light_color: glam::Vec4,\n}\n\nimpl Uniforms {\n    pub fn new(camera: &Camera, bounds: Rectangle, light_color: Color) -> Self {\n        let camera_proj = camera.build_view_proj_matrix(bounds);\n\n        Self {\n            camera_proj,\n            camera_pos: camera.position(),\n            light_color: glam::Vec4::from(light_color.into_linear()),\n        }\n    }\n}\n"
  },
  {
    "path": "examples/custom_shader/src/scene/pipeline/vertex.rs",
    "content": "use crate::wgpu;\n\n#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]\n#[repr(C)]\npub struct Vertex {\n    pub pos: glam::Vec3,\n    pub normal: glam::Vec3,\n    pub tangent: glam::Vec3,\n    pub uv: glam::Vec2,\n}\n\nimpl Vertex {\n    const ATTRIBS: [wgpu::VertexAttribute; 4] = wgpu::vertex_attr_array![\n        //position\n        0 => Float32x3,\n        //normal\n        1 => Float32x3,\n        //tangent\n        2 => Float32x3,\n        //uv\n        3 => Float32x2,\n    ];\n\n    pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {\n        wgpu::VertexBufferLayout {\n            array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,\n            step_mode: wgpu::VertexStepMode::Vertex,\n            attributes: &Self::ATTRIBS,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/custom_shader/src/scene/pipeline.rs",
    "content": "pub mod cube;\n\nmod buffer;\nmod uniforms;\nmod vertex;\n\npub use uniforms::Uniforms;\n\nuse buffer::Buffer;\nuse vertex::Vertex;\n\nuse crate::wgpu;\nuse crate::wgpu::util::DeviceExt;\n\nuse iced::{Rectangle, Size};\n\nconst SKY_TEXTURE_SIZE: u32 = 128;\n\npub struct Pipeline {\n    pipeline: wgpu::RenderPipeline,\n    vertices: wgpu::Buffer,\n    cubes: Buffer,\n    uniforms: wgpu::Buffer,\n    uniform_bind_group: wgpu::BindGroup,\n    depth_texture_size: Size<u32>,\n    depth_view: wgpu::TextureView,\n    depth_pipeline: DepthPipeline,\n}\n\nimpl Pipeline {\n    pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat) -> Self {\n        //vertices of one cube\n        let vertices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {\n            label: Some(\"cubes vertex buffer\"),\n            contents: bytemuck::cast_slice(&cube::Raw::vertices()),\n            usage: wgpu::BufferUsages::VERTEX,\n        });\n\n        //cube instance data\n        let cubes_buffer = Buffer::new(\n            device,\n            \"cubes instance buffer\",\n            std::mem::size_of::<cube::Raw>() as u64,\n            wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,\n        );\n\n        //uniforms for all cubes\n        let uniforms = device.create_buffer(&wgpu::BufferDescriptor {\n            label: Some(\"cubes uniform buffer\"),\n            size: std::mem::size_of::<Uniforms>() as u64,\n            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,\n            mapped_at_creation: false,\n        });\n\n        //depth buffer\n        let depth_texture = device.create_texture(&wgpu::TextureDescriptor {\n            label: Some(\"cubes depth texture\"),\n            size: wgpu::Extent3d {\n                width: 1,\n                height: 1,\n                depth_or_array_layers: 1,\n            },\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format: wgpu::TextureFormat::Depth32Float,\n            usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,\n            view_formats: &[],\n        });\n\n        let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());\n\n        let normal_map_data = load_normal_map_data();\n\n        //normal map\n        let normal_texture = device.create_texture_with_data(\n            queue,\n            &wgpu::TextureDescriptor {\n                label: Some(\"cubes normal map texture\"),\n                size: wgpu::Extent3d {\n                    width: 1024,\n                    height: 1024,\n                    depth_or_array_layers: 1,\n                },\n                mip_level_count: 1,\n                sample_count: 1,\n                dimension: wgpu::TextureDimension::D2,\n                format: wgpu::TextureFormat::Rgba8Unorm,\n                usage: wgpu::TextureUsages::TEXTURE_BINDING,\n                view_formats: &[],\n            },\n            wgpu::util::TextureDataOrder::LayerMajor,\n            &normal_map_data,\n        );\n\n        let normal_view = normal_texture.create_view(&wgpu::TextureViewDescriptor::default());\n\n        //skybox texture for reflection/refraction\n        let skybox_data = load_skybox_data();\n\n        let skybox_texture = device.create_texture_with_data(\n            queue,\n            &wgpu::TextureDescriptor {\n                label: Some(\"cubes skybox texture\"),\n                size: wgpu::Extent3d {\n                    width: SKY_TEXTURE_SIZE,\n                    height: SKY_TEXTURE_SIZE,\n                    depth_or_array_layers: 6, //one for each face of the cube\n                },\n                mip_level_count: 1,\n                sample_count: 1,\n                dimension: wgpu::TextureDimension::D2,\n                format: wgpu::TextureFormat::Rgba8Unorm,\n                usage: wgpu::TextureUsages::TEXTURE_BINDING,\n                view_formats: &[],\n            },\n            wgpu::util::TextureDataOrder::LayerMajor,\n            &skybox_data,\n        );\n\n        let sky_view = skybox_texture.create_view(&wgpu::TextureViewDescriptor {\n            label: Some(\"cubes skybox texture view\"),\n            dimension: Some(wgpu::TextureViewDimension::Cube),\n            ..Default::default()\n        });\n\n        let sky_sampler = device.create_sampler(&wgpu::SamplerDescriptor {\n            label: Some(\"cubes skybox sampler\"),\n            address_mode_u: wgpu::AddressMode::ClampToEdge,\n            address_mode_v: wgpu::AddressMode::ClampToEdge,\n            address_mode_w: wgpu::AddressMode::ClampToEdge,\n            mag_filter: wgpu::FilterMode::Linear,\n            min_filter: wgpu::FilterMode::Linear,\n            mipmap_filter: wgpu::MipmapFilterMode::Linear,\n            ..Default::default()\n        });\n\n        let uniform_bind_group_layout =\n            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n                label: Some(\"cubes uniform bind group layout\"),\n                entries: &[\n                    wgpu::BindGroupLayoutEntry {\n                        binding: 0,\n                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,\n                        ty: wgpu::BindingType::Buffer {\n                            ty: wgpu::BufferBindingType::Uniform,\n                            has_dynamic_offset: false,\n                            min_binding_size: None,\n                        },\n                        count: None,\n                    },\n                    wgpu::BindGroupLayoutEntry {\n                        binding: 1,\n                        visibility: wgpu::ShaderStages::FRAGMENT,\n                        ty: wgpu::BindingType::Texture {\n                            sample_type: wgpu::TextureSampleType::Float { filterable: true },\n                            view_dimension: wgpu::TextureViewDimension::Cube,\n                            multisampled: false,\n                        },\n                        count: None,\n                    },\n                    wgpu::BindGroupLayoutEntry {\n                        binding: 2,\n                        visibility: wgpu::ShaderStages::FRAGMENT,\n                        ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),\n                        count: None,\n                    },\n                    wgpu::BindGroupLayoutEntry {\n                        binding: 3,\n                        visibility: wgpu::ShaderStages::FRAGMENT,\n                        ty: wgpu::BindingType::Texture {\n                            sample_type: wgpu::TextureSampleType::Float { filterable: true },\n                            view_dimension: wgpu::TextureViewDimension::D2,\n                            multisampled: false,\n                        },\n                        count: None,\n                    },\n                ],\n            });\n\n        let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"cubes uniform bind group\"),\n            layout: &uniform_bind_group_layout,\n            entries: &[\n                wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: uniforms.as_entire_binding(),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 1,\n                    resource: wgpu::BindingResource::TextureView(&sky_view),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 2,\n                    resource: wgpu::BindingResource::Sampler(&sky_sampler),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 3,\n                    resource: wgpu::BindingResource::TextureView(&normal_view),\n                },\n            ],\n        });\n\n        let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: Some(\"cubes pipeline layout\"),\n            bind_group_layouts: &[&uniform_bind_group_layout],\n            immediate_size: 0,\n        });\n\n        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: Some(\"cubes shader\"),\n            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!(\n                \"../shaders/cubes.wgsl\"\n            ))),\n        });\n\n        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: Some(\"cubes pipeline\"),\n            layout: Some(&layout),\n            vertex: wgpu::VertexState {\n                module: &shader,\n                entry_point: Some(\"vs_main\"),\n                buffers: &[Vertex::desc(), cube::Raw::desc()],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            },\n            primitive: wgpu::PrimitiveState::default(),\n            depth_stencil: Some(wgpu::DepthStencilState {\n                format: wgpu::TextureFormat::Depth32Float,\n                depth_write_enabled: true,\n                depth_compare: wgpu::CompareFunction::Less,\n                stencil: wgpu::StencilState::default(),\n                bias: wgpu::DepthBiasState::default(),\n            }),\n            multisample: wgpu::MultisampleState {\n                count: 1,\n                mask: !0,\n                alpha_to_coverage_enabled: false,\n            },\n            fragment: Some(wgpu::FragmentState {\n                module: &shader,\n                entry_point: Some(\"fs_main\"),\n                targets: &[Some(wgpu::ColorTargetState {\n                    format,\n                    blend: Some(wgpu::BlendState {\n                        color: wgpu::BlendComponent {\n                            src_factor: wgpu::BlendFactor::SrcAlpha,\n                            dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,\n                            operation: wgpu::BlendOperation::Add,\n                        },\n                        alpha: wgpu::BlendComponent {\n                            src_factor: wgpu::BlendFactor::One,\n                            dst_factor: wgpu::BlendFactor::One,\n                            operation: wgpu::BlendOperation::Max,\n                        },\n                    }),\n                    write_mask: wgpu::ColorWrites::ALL,\n                })],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            }),\n            multiview_mask: None,\n            cache: None,\n        });\n\n        let depth_pipeline = DepthPipeline::new(\n            device,\n            format,\n            depth_texture.create_view(&wgpu::TextureViewDescriptor::default()),\n        );\n\n        Self {\n            pipeline,\n            cubes: cubes_buffer,\n            uniforms,\n            uniform_bind_group,\n            vertices,\n            depth_texture_size: Size::new(1, 1),\n            depth_view,\n            depth_pipeline,\n        }\n    }\n\n    fn update_depth_texture(&mut self, device: &wgpu::Device, size: Size<u32>) {\n        if self.depth_texture_size.height != size.height\n            || self.depth_texture_size.width != size.width\n        {\n            let text = device.create_texture(&wgpu::TextureDescriptor {\n                label: Some(\"cubes depth texture\"),\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: wgpu::TextureFormat::Depth32Float,\n                usage: wgpu::TextureUsages::RENDER_ATTACHMENT\n                    | wgpu::TextureUsages::TEXTURE_BINDING,\n                view_formats: &[],\n            });\n\n            self.depth_view = text.create_view(&wgpu::TextureViewDescriptor::default());\n            self.depth_texture_size = size;\n\n            self.depth_pipeline.update(device, &text);\n        }\n    }\n\n    pub fn update(\n        &mut self,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n        target_size: Size<u32>,\n        uniforms: &Uniforms,\n        num_cubes: usize,\n        cubes: &[cube::Raw],\n    ) {\n        //recreate depth texture if surface texture size has changed\n        self.update_depth_texture(device, target_size);\n\n        // update uniforms\n        queue.write_buffer(&self.uniforms, 0, bytemuck::bytes_of(uniforms));\n\n        //resize cubes vertex buffer if cubes amount changed\n        let new_size = num_cubes * std::mem::size_of::<cube::Raw>();\n        self.cubes.resize(device, new_size as u64);\n\n        //always write new cube data since they are constantly rotating\n        queue.write_buffer(&self.cubes.raw, 0, bytemuck::cast_slice(cubes));\n    }\n\n    pub fn render(\n        &self,\n        target: &wgpu::TextureView,\n        encoder: &mut wgpu::CommandEncoder,\n        clip_bounds: Rectangle<u32>,\n        num_cubes: u32,\n        show_depth: bool,\n    ) {\n        {\n            let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n                label: Some(\"cubes.pipeline.pass\"),\n                color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                    view: target,\n                    depth_slice: None,\n                    resolve_target: None,\n                    ops: wgpu::Operations {\n                        load: wgpu::LoadOp::Load,\n                        store: wgpu::StoreOp::Store,\n                    },\n                })],\n                depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {\n                    view: &self.depth_view,\n                    depth_ops: Some(wgpu::Operations {\n                        load: wgpu::LoadOp::Clear(1.0),\n                        store: wgpu::StoreOp::Store,\n                    }),\n                    stencil_ops: None,\n                }),\n                timestamp_writes: None,\n                occlusion_query_set: None,\n                multiview_mask: None,\n            });\n\n            pass.set_viewport(\n                clip_bounds.x as f32,\n                clip_bounds.y as f32,\n                clip_bounds.width as f32,\n                clip_bounds.height as f32,\n                0.0,\n                1.0,\n            );\n            pass.set_pipeline(&self.pipeline);\n            pass.set_bind_group(0, &self.uniform_bind_group, &[]);\n            pass.set_vertex_buffer(0, self.vertices.slice(..));\n            pass.set_vertex_buffer(1, self.cubes.raw.slice(..));\n            pass.draw(0..36, 0..num_cubes);\n        }\n\n        if show_depth {\n            self.depth_pipeline.render(encoder, target, clip_bounds);\n        }\n    }\n}\n\nstruct DepthPipeline {\n    pipeline: wgpu::RenderPipeline,\n    bind_group_layout: wgpu::BindGroupLayout,\n    bind_group: wgpu::BindGroup,\n    sampler: wgpu::Sampler,\n    depth_view: wgpu::TextureView,\n}\n\nimpl DepthPipeline {\n    pub fn new(\n        device: &wgpu::Device,\n        format: wgpu::TextureFormat,\n        depth_texture: wgpu::TextureView,\n    ) -> Self {\n        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {\n            label: Some(\"cubes.depth_pipeline.sampler\"),\n            ..Default::default()\n        });\n\n        let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n            label: Some(\"cubes.depth_pipeline.bind_group_layout\"),\n            entries: &[\n                wgpu::BindGroupLayoutEntry {\n                    binding: 0,\n                    visibility: wgpu::ShaderStages::FRAGMENT,\n                    ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),\n                    count: None,\n                },\n                wgpu::BindGroupLayoutEntry {\n                    binding: 1,\n                    visibility: wgpu::ShaderStages::FRAGMENT,\n                    ty: wgpu::BindingType::Texture {\n                        sample_type: wgpu::TextureSampleType::Float { filterable: false },\n                        view_dimension: wgpu::TextureViewDimension::D2,\n                        multisampled: false,\n                    },\n                    count: None,\n                },\n            ],\n        });\n\n        let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"cubes.depth_pipeline.bind_group\"),\n            layout: &bind_group_layout,\n            entries: &[\n                wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::Sampler(&sampler),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 1,\n                    resource: wgpu::BindingResource::TextureView(&depth_texture),\n                },\n            ],\n        });\n\n        let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: Some(\"cubes.depth_pipeline.layout\"),\n            bind_group_layouts: &[&bind_group_layout],\n            immediate_size: 0,\n        });\n\n        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: Some(\"cubes.depth_pipeline.shader\"),\n            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!(\n                \"../shaders/depth.wgsl\"\n            ))),\n        });\n\n        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: Some(\"cubes.depth_pipeline.pipeline\"),\n            layout: Some(&layout),\n            vertex: wgpu::VertexState {\n                module: &shader,\n                entry_point: Some(\"vs_main\"),\n                buffers: &[],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            },\n            primitive: wgpu::PrimitiveState::default(),\n            depth_stencil: Some(wgpu::DepthStencilState {\n                format: wgpu::TextureFormat::Depth32Float,\n                depth_write_enabled: false,\n                depth_compare: wgpu::CompareFunction::Less,\n                stencil: wgpu::StencilState::default(),\n                bias: wgpu::DepthBiasState::default(),\n            }),\n            multisample: wgpu::MultisampleState::default(),\n            fragment: Some(wgpu::FragmentState {\n                module: &shader,\n                entry_point: Some(\"fs_main\"),\n                targets: &[Some(wgpu::ColorTargetState {\n                    format,\n                    blend: Some(wgpu::BlendState::REPLACE),\n                    write_mask: wgpu::ColorWrites::ALL,\n                })],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            }),\n            multiview_mask: None,\n            cache: None,\n        });\n\n        Self {\n            pipeline,\n            bind_group_layout,\n            bind_group,\n            sampler,\n            depth_view: depth_texture,\n        }\n    }\n\n    pub fn update(&mut self, device: &wgpu::Device, depth_texture: &wgpu::Texture) {\n        self.depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());\n\n        self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"cubes.depth_pipeline.bind_group\"),\n            layout: &self.bind_group_layout,\n            entries: &[\n                wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::Sampler(&self.sampler),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 1,\n                    resource: wgpu::BindingResource::TextureView(&self.depth_view),\n                },\n            ],\n        });\n    }\n\n    pub fn render(\n        &self,\n        encoder: &mut wgpu::CommandEncoder,\n        target: &wgpu::TextureView,\n        clip_bounds: Rectangle<u32>,\n    ) {\n        let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n            label: Some(\"cubes.pipeline.depth_pass\"),\n            color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                view: target,\n                depth_slice: None,\n                resolve_target: None,\n                ops: wgpu::Operations {\n                    load: wgpu::LoadOp::Load,\n                    store: wgpu::StoreOp::Store,\n                },\n            })],\n            depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {\n                view: &self.depth_view,\n                depth_ops: None,\n                stencil_ops: None,\n            }),\n            timestamp_writes: None,\n            occlusion_query_set: None,\n            multiview_mask: None,\n        });\n\n        pass.set_viewport(\n            clip_bounds.x as f32,\n            clip_bounds.y as f32,\n            clip_bounds.width as f32,\n            clip_bounds.height as f32,\n            0.0,\n            1.0,\n        );\n        pass.set_pipeline(&self.pipeline);\n        pass.set_bind_group(0, &self.bind_group, &[]);\n        pass.draw(0..6, 0..1);\n    }\n}\n\nfn load_skybox_data() -> Vec<u8> {\n    let pos_x: &[u8] = include_bytes!(\"../../textures/skybox/pos_x.jpg\");\n    let neg_x: &[u8] = include_bytes!(\"../../textures/skybox/neg_x.jpg\");\n    let pos_y: &[u8] = include_bytes!(\"../../textures/skybox/pos_y.jpg\");\n    let neg_y: &[u8] = include_bytes!(\"../../textures/skybox/neg_y.jpg\");\n    let pos_z: &[u8] = include_bytes!(\"../../textures/skybox/pos_z.jpg\");\n    let neg_z: &[u8] = include_bytes!(\"../../textures/skybox/neg_z.jpg\");\n\n    let data: [&[u8]; 6] = [pos_x, neg_x, pos_y, neg_y, pos_z, neg_z];\n\n    data.iter().fold(vec![], |mut acc, bytes| {\n        let i = image::load_from_memory_with_format(bytes, image::ImageFormat::Jpeg)\n            .unwrap()\n            .to_rgba8()\n            .into_raw();\n\n        acc.extend(i);\n        acc\n    })\n}\n\nfn load_normal_map_data() -> Vec<u8> {\n    let bytes: &[u8] = include_bytes!(\"../../textures/ice_cube_normal_map.png\");\n\n    image::load_from_memory_with_format(bytes, image::ImageFormat::Png)\n        .unwrap()\n        .to_rgba8()\n        .into_raw()\n}\n"
  },
  {
    "path": "examples/custom_shader/src/scene.rs",
    "content": "mod camera;\nmod pipeline;\n\nuse camera::Camera;\nuse pipeline::Pipeline;\n\nuse crate::wgpu;\nuse pipeline::cube::{self, Cube};\n\nuse iced::mouse;\nuse iced::time::Duration;\nuse iced::widget::shader::{self, Viewport};\nuse iced::{Color, Rectangle};\n\nuse glam::Vec3;\nuse rand::Rng;\nuse std::cmp::Ordering;\nuse std::iter;\n\npub const MAX: u32 = 500;\n\n#[derive(Clone)]\npub struct Scene {\n    pub size: f32,\n    pub cubes: Vec<Cube>,\n    pub camera: Camera,\n    pub show_depth_buffer: bool,\n    pub light_color: Color,\n}\n\nimpl Scene {\n    pub fn new() -> Self {\n        let mut scene = Self {\n            size: 0.2,\n            cubes: vec![],\n            camera: Camera::default(),\n            show_depth_buffer: false,\n            light_color: Color::WHITE,\n        };\n\n        scene.change_amount(MAX);\n\n        scene\n    }\n\n    pub fn update(&mut self, time: Duration) {\n        for cube in self.cubes.iter_mut() {\n            cube.update(self.size, time.as_secs_f32());\n        }\n    }\n\n    pub fn change_amount(&mut self, amount: u32) {\n        let curr_cubes = self.cubes.len() as u32;\n\n        match amount.cmp(&curr_cubes) {\n            Ordering::Greater => {\n                // spawn\n                let cubes_2_spawn = (amount - curr_cubes) as usize;\n\n                let mut cubes = 0;\n                self.cubes.extend(iter::from_fn(|| {\n                    if cubes < cubes_2_spawn {\n                        cubes += 1;\n                        Some(Cube::new(self.size, rnd_origin()))\n                    } else {\n                        None\n                    }\n                }));\n            }\n            Ordering::Less => {\n                // chop\n                let cubes_2_cut = curr_cubes - amount;\n                let new_len = self.cubes.len() - cubes_2_cut as usize;\n                self.cubes.truncate(new_len);\n            }\n            Ordering::Equal => {}\n        }\n    }\n}\n\nimpl<Message> shader::Program<Message> for Scene {\n    type State = ();\n    type Primitive = Primitive;\n\n    fn draw(\n        &self,\n        _state: &Self::State,\n        _cursor: mouse::Cursor,\n        bounds: Rectangle,\n    ) -> Self::Primitive {\n        Primitive::new(\n            &self.cubes,\n            &self.camera,\n            bounds,\n            self.show_depth_buffer,\n            self.light_color,\n        )\n    }\n}\n\n/// A collection of `Cube`s that can be rendered.\n#[derive(Debug)]\npub struct Primitive {\n    cubes: Vec<cube::Raw>,\n    uniforms: pipeline::Uniforms,\n    show_depth_buffer: bool,\n}\n\nimpl Primitive {\n    pub fn new(\n        cubes: &[Cube],\n        camera: &Camera,\n        bounds: Rectangle,\n        show_depth_buffer: bool,\n        light_color: Color,\n    ) -> Self {\n        let uniforms = pipeline::Uniforms::new(camera, bounds, light_color);\n\n        Self {\n            cubes: cubes\n                .iter()\n                .map(cube::Raw::from_cube)\n                .collect::<Vec<cube::Raw>>(),\n            uniforms,\n            show_depth_buffer,\n        }\n    }\n}\n\nimpl shader::Primitive for Primitive {\n    type Pipeline = Pipeline;\n\n    fn prepare(\n        &self,\n        pipeline: &mut Pipeline,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n        _bounds: &Rectangle,\n        viewport: &Viewport,\n    ) {\n        // Upload data to GPU\n        pipeline.update(\n            device,\n            queue,\n            viewport.physical_size(),\n            &self.uniforms,\n            self.cubes.len(),\n            &self.cubes,\n        );\n    }\n\n    fn render(\n        &self,\n        pipeline: &Pipeline,\n        encoder: &mut wgpu::CommandEncoder,\n        target: &wgpu::TextureView,\n        clip_bounds: &Rectangle<u32>,\n    ) {\n        // Render primitive\n        pipeline.render(\n            target,\n            encoder,\n            *clip_bounds,\n            self.cubes.len() as u32,\n            self.show_depth_buffer,\n        );\n    }\n}\n\nfn rnd_origin() -> Vec3 {\n    Vec3::new(\n        rand::thread_rng().gen_range(-4.0..4.0),\n        rand::thread_rng().gen_range(-4.0..4.0),\n        rand::thread_rng().gen_range(-4.0..2.0),\n    )\n}\n\nimpl shader::Pipeline for Pipeline {\n    fn new(device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat) -> Pipeline {\n        Self::new(device, queue, format)\n    }\n}\n"
  },
  {
    "path": "examples/custom_shader/src/shaders/cubes.wgsl",
    "content": "struct Uniforms {\n    projection: mat4x4<f32>,\n    camera_pos: vec4<f32>,\n    light_color: vec4<f32>,\n}\n\nconst LIGHT_POS: vec3<f32> = vec3<f32>(0.0, 3.0, 3.0);\n\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\n@group(0) @binding(1) var sky_texture: texture_cube<f32>;\n@group(0) @binding(2) var tex_sampler: sampler;\n@group(0) @binding(3) var normal_texture: texture_2d<f32>;\n\nstruct Vertex {\n    @location(0) position: vec3<f32>,\n    @location(1) normal: vec3<f32>,\n    @location(2) tangent: vec3<f32>,\n    @location(3) uv: vec2<f32>,\n}\n\nstruct Cube {\n    @location(4) matrix_0: vec4<f32>,\n    @location(5) matrix_1: vec4<f32>,\n    @location(6) matrix_2: vec4<f32>,\n    @location(7) matrix_3: vec4<f32>,\n    @location(8) normal_matrix_0: vec3<f32>,\n    @location(9) normal_matrix_1: vec3<f32>,\n    @location(10) normal_matrix_2: vec3<f32>,\n}\n\nstruct Output {\n    @builtin(position) clip_pos: vec4<f32>,\n    @location(0) uv: vec2<f32>,\n    @location(1) tangent_pos: vec3<f32>,\n    @location(2) tangent_camera_pos: vec3<f32>,\n    @location(3) tangent_light_pos: vec3<f32>,\n}\n\n@vertex\nfn vs_main(vertex: Vertex, cube: Cube) -> Output {\n     let cube_matrix = mat4x4<f32>(\n         cube.matrix_0,\n         cube.matrix_1,\n         cube.matrix_2,\n         cube.matrix_3,\n     );\n\n    let normal_matrix = mat3x3<f32>(\n        cube.normal_matrix_0,\n        cube.normal_matrix_1,\n        cube.normal_matrix_2,\n    );\n\n    //convert to tangent space to calculate lighting in same coordinate space as normal map sample\n    let tangent = normalize(normal_matrix * vertex.tangent);\n    let normal = normalize(normal_matrix * vertex.normal);\n    let bitangent = cross(tangent, normal);\n\n    //shift everything into tangent space\n    let tbn = transpose(mat3x3<f32>(tangent, bitangent, normal));\n\n    let world_pos = cube_matrix * vec4<f32>(vertex.position, 1.0);\n\n    var out: Output;\n    out.clip_pos = uniforms.projection * world_pos;\n    out.uv = vertex.uv;\n    out.tangent_pos = tbn * world_pos.xyz;\n    out.tangent_camera_pos = tbn * uniforms.camera_pos.xyz;\n    out.tangent_light_pos = tbn * LIGHT_POS;\n\n    return out;\n}\n\n//cube properties\nconst CUBE_BASE_COLOR: vec4<f32> = vec4<f32>(0.294118, 0.462745, 0.611765, 0.6);\nconst SHINE_DAMPER: f32 = 1.0;\nconst REFLECTIVITY: f32 = 0.8;\nconst REFRACTION_INDEX: f32 = 1.31;\n\n//fog, for the ~* cinematic effect *~\nconst FOG_DENSITY: f32 = 0.15;\nconst FOG_GRADIENT: f32 = 8.0;\nconst FOG_COLOR: vec4<f32> = vec4<f32>(1.0, 1.0, 1.0, 1.0);\n\n@fragment\nfn fs_main(in: Output) -> @location(0) vec4<f32> {\n    let to_camera = in.tangent_camera_pos - in.tangent_pos;\n\n    //normal sample from texture\n    var normal = textureSample(normal_texture, tex_sampler, in.uv).xyz;\n    normal = normal * 2.0 - 1.0;\n\n    //diffuse\n    let dir_to_light: vec3<f32> = normalize(in.tangent_light_pos - in.tangent_pos);\n    let brightness = max(dot(normal, dir_to_light), 0.0);\n    let diffuse: vec3<f32> = brightness * uniforms.light_color.xyz;\n\n    //specular\n    let dir_to_camera = normalize(to_camera);\n    let light_dir = -dir_to_light;\n    let reflected_light_dir = reflect(light_dir, normal);\n    let specular_factor = max(dot(reflected_light_dir, dir_to_camera), 0.0);\n    let damped_factor = pow(specular_factor, SHINE_DAMPER);\n    let specular: vec3<f32> = damped_factor * uniforms.light_color.xyz * REFLECTIVITY;\n\n    //fog\n    let distance = length(to_camera);\n    let visibility = clamp(exp(-pow((distance * FOG_DENSITY), FOG_GRADIENT)), 0.0, 1.0);\n\n    //reflection\n    let reflection_dir = reflect(dir_to_camera, normal);\n    let reflection_color = textureSample(sky_texture, tex_sampler, reflection_dir);\n    let refraction_dir = refract(dir_to_camera, normal, REFRACTION_INDEX);\n    let refraction_color = textureSample(sky_texture, tex_sampler, refraction_dir);\n    let final_reflect_color = mix(reflection_color, refraction_color, 0.5);\n\n    //mix it all together!\n    var color = vec4<f32>(CUBE_BASE_COLOR.xyz * diffuse + specular, CUBE_BASE_COLOR.w);\n    color = mix(color, final_reflect_color, 0.8);\n    color = mix(FOG_COLOR, color, visibility);\n\n    return color;\n}\n"
  },
  {
    "path": "examples/custom_shader/src/shaders/depth.wgsl",
    "content": "var<private> positions: array<vec2<f32>, 6> = array<vec2<f32>, 6>(\n    vec2<f32>(-1.0, 1.0),\n    vec2<f32>(-1.0, -1.0),\n    vec2<f32>(1.0, -1.0),\n    vec2<f32>(-1.0, 1.0),\n    vec2<f32>(1.0, 1.0),\n    vec2<f32>(1.0, -1.0)\n);\n\nvar<private> uvs: array<vec2<f32>, 6> = array<vec2<f32>, 6>(\n    vec2<f32>(0.0, 0.0),\n    vec2<f32>(0.0, 1.0),\n    vec2<f32>(1.0, 1.0),\n    vec2<f32>(0.0, 0.0),\n    vec2<f32>(1.0, 0.0),\n    vec2<f32>(1.0, 1.0)\n);\n\n@group(0) @binding(0) var depth_sampler: sampler;\n@group(0) @binding(1) var depth_texture: texture_2d<f32>;\n\nstruct Output {\n    @builtin(position) position: vec4<f32>,\n    @location(0) uv: vec2<f32>,\n}\n\n@vertex\nfn vs_main(@builtin(vertex_index) v_index: u32) -> Output {\n    var out: Output;\n\n    out.position = vec4<f32>(positions[v_index], 0.0, 1.0);\n    out.uv = uvs[v_index];\n\n    return out;\n}\n\n@fragment\nfn fs_main(input: Output) -> @location(0) vec4<f32> {\n    let depth = textureSample(depth_texture, depth_sampler, input.uv).r;\n\n    if (depth > .9999) {\n        discard;\n    }\n\n    let c = 1.0 - depth;\n\n    return vec4<f32>(c, c, c, 1.0);\n}\n"
  },
  {
    "path": "examples/custom_widget/Cargo.toml",
    "content": "[package]\nname = \"custom_widget\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"advanced\"]\n"
  },
  {
    "path": "examples/custom_widget/README.md",
    "content": "## Custom widget\n\nA demonstration of how to build a custom widget that draws a circle.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/custom_widget.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package custom_widget\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/custom_widget/src/main.rs",
    "content": "//! This example showcases a simple native custom widget that draws a circle.\nmod circle {\n    use iced::advanced::layout::{self, Layout};\n    use iced::advanced::renderer;\n    use iced::advanced::widget::{self, Widget};\n    use iced::border;\n    use iced::mouse;\n    use iced::{Color, Element, Length, Rectangle, Size};\n\n    pub struct Circle {\n        radius: f32,\n    }\n\n    impl Circle {\n        pub fn new(radius: f32) -> Self {\n            Self { radius }\n        }\n    }\n\n    pub fn circle(radius: f32) -> Circle {\n        Circle::new(radius)\n    }\n\n    impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Circle\n    where\n        Renderer: renderer::Renderer,\n    {\n        fn size(&self) -> Size<Length> {\n            Size {\n                width: Length::Shrink,\n                height: Length::Shrink,\n            }\n        }\n\n        fn layout(\n            &mut self,\n            _tree: &mut widget::Tree,\n            _renderer: &Renderer,\n            _limits: &layout::Limits,\n        ) -> layout::Node {\n            layout::Node::new(Size::new(self.radius * 2.0, self.radius * 2.0))\n        }\n\n        fn draw(\n            &self,\n            _tree: &widget::Tree,\n            renderer: &mut Renderer,\n            _theme: &Theme,\n            _style: &renderer::Style,\n            layout: Layout<'_>,\n            _cursor: mouse::Cursor,\n            _viewport: &Rectangle,\n        ) {\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds: layout.bounds(),\n                    border: border::rounded(self.radius),\n                    ..renderer::Quad::default()\n                },\n                Color::BLACK,\n            );\n        }\n    }\n\n    impl<Message, Theme, Renderer> From<Circle> for Element<'_, Message, Theme, Renderer>\n    where\n        Renderer: renderer::Renderer,\n    {\n        fn from(circle: Circle) -> Self {\n            Self::new(circle)\n        }\n    }\n}\n\nuse circle::circle;\nuse iced::widget::{center, column, slider, text};\nuse iced::{Center, Element};\n\npub fn main() -> iced::Result {\n    iced::run(Example::update, Example::view)\n}\n\nstruct Example {\n    radius: f32,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    RadiusChanged(f32),\n}\n\nimpl Example {\n    fn new() -> Self {\n        Example { radius: 50.0 }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::RadiusChanged(radius) => {\n                self.radius = radius;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let content = column![\n            circle(self.radius),\n            text!(\"Radius: {:.2}\", self.radius),\n            slider(1.0..=100.0, self.radius, Message::RadiusChanged).step(0.01),\n        ]\n        .padding(20)\n        .spacing(20)\n        .max_width(500)\n        .align_x(Center);\n\n        center(content).into()\n    }\n}\n\nimpl Default for Example {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n"
  },
  {
    "path": "examples/delineate/Cargo.toml",
    "content": "[package]\nname = \"delineate\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"selector\"]\n"
  },
  {
    "path": "examples/delineate/src/main.rs",
    "content": "use iced::event::{self, Event};\nuse iced::mouse;\nuse iced::widget::{self, column, container, row, scrollable, selector, space, text};\nuse iced::window;\nuse iced::{Center, Color, Element, Fill, Font, Point, Rectangle, Subscription, Task, Theme};\n\npub fn main() -> iced::Result {\n    iced::application(Example::default, Example::update, Example::view)\n        .subscription(Example::subscription)\n        .theme(Theme::Dark)\n        .run()\n}\n\n#[derive(Default)]\nstruct Example {\n    mouse_position: Option<Point>,\n    outer_bounds: Option<Rectangle>,\n    inner_bounds: Option<Rectangle>,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    MouseMoved(Point),\n    WindowResized,\n    Scrolled,\n    OuterFound(Option<selector::Target>),\n    InnerFound(Option<selector::Target>),\n}\n\nimpl Example {\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::MouseMoved(position) => {\n                self.mouse_position = Some(position);\n\n                Task::none()\n            }\n            Message::Scrolled | Message::WindowResized => Task::batch(vec![\n                selector::find(OUTER_CONTAINER).map(Message::OuterFound),\n                selector::find(INNER_CONTAINER).map(Message::InnerFound),\n            ]),\n            Message::OuterFound(outer) => {\n                self.outer_bounds = outer.as_ref().and_then(selector::Target::visible_bounds);\n\n                Task::none()\n            }\n            Message::InnerFound(inner) => {\n                self.inner_bounds = inner.as_ref().and_then(selector::Target::visible_bounds);\n\n                Task::none()\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let data_row = |label, value, color| {\n            row![\n                text(label),\n                space::horizontal(),\n                text(value)\n                    .font(Font::MONOSPACE)\n                    .size(14)\n                    .color_maybe(color),\n            ]\n            .height(40)\n            .align_y(Center)\n        };\n\n        let view_bounds = |label, bounds: Option<Rectangle>| {\n            data_row(\n                label,\n                match bounds {\n                    Some(bounds) => format!(\"{bounds:?}\"),\n                    None => \"not visible\".to_string(),\n                },\n                if bounds\n                    .zip(self.mouse_position)\n                    .map(|(bounds, mouse_position)| bounds.contains(mouse_position))\n                    .unwrap_or_default()\n                {\n                    Some(Color {\n                        g: 1.0,\n                        ..Color::BLACK\n                    })\n                } else {\n                    None\n                },\n            )\n        };\n\n        column![\n            data_row(\n                \"Mouse position\",\n                match self.mouse_position {\n                    Some(Point { x, y }) => format!(\"({x}, {y})\"),\n                    None => \"unknown\".to_string(),\n                },\n                None,\n            ),\n            view_bounds(\"Outer container\", self.outer_bounds),\n            view_bounds(\"Inner container\", self.inner_bounds),\n            scrollable(\n                column![\n                    text(\"Scroll me!\"),\n                    space().height(400),\n                    container(text(\"I am the outer container!\"))\n                        .id(OUTER_CONTAINER)\n                        .padding(40)\n                        .style(container::rounded_box),\n                    space().height(400),\n                    scrollable(\n                        column![\n                            text(\"Scroll me!\"),\n                            space().height(400),\n                            container(text(\"I am the inner container!\"))\n                                .id(INNER_CONTAINER)\n                                .padding(40)\n                                .style(container::rounded_box),\n                            space().height(400),\n                        ]\n                        .padding(20)\n                    )\n                    .on_scroll(|_| Message::Scrolled)\n                    .width(Fill)\n                    .height(300),\n                ]\n                .padding(20)\n            )\n            .on_scroll(|_| Message::Scrolled)\n            .width(Fill)\n            .height(300),\n        ]\n        .spacing(10)\n        .padding(20)\n        .into()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        event::listen_with(|event, _status, _window| match event {\n            Event::Mouse(mouse::Event::CursorMoved { position }) => {\n                Some(Message::MouseMoved(position))\n            }\n            Event::Window(window::Event::Resized { .. }) => Some(Message::WindowResized),\n            _ => None,\n        })\n    }\n}\n\nconst OUTER_CONTAINER: widget::Id = widget::Id::new(\"outer\");\nconst INNER_CONTAINER: widget::Id = widget::Id::new(\"inner\");\n"
  },
  {
    "path": "examples/download_progress/Cargo.toml",
    "content": "[package]\nname = \"download_progress\"\nversion = \"0.1.0\"\nauthors = [\"Songtronix <contact@songtronix.com>\", \"Folyd <lyshuhow@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"tokio\", \"sipper\"]\n\n[dependencies.reqwest]\nversion = \"0.12\"\nfeatures = [\"stream\"]\n"
  },
  {
    "path": "examples/download_progress/README.md",
    "content": "## Download progress\n\nA basic application that asynchronously downloads multiple dummy files of 100 MB and tracks the download progress.\n\nThe example implements a custom `Subscription` in the __[`download`](src/download.rs)__ module. This subscription downloads and produces messages that can be used to keep track of its progress.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/download_progress.gif\">\n</div>\n\nYou can run it with `cargo run`:\n\n```\ncargo run --package download_progress\n```\n"
  },
  {
    "path": "examples/download_progress/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" style=\"height: 100%\">\n<head>\n    <meta charset=\"utf-8\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>Download_Progress - Iced</title>\n    <base data-trunk-public-url />\n</head>\n<body style=\"height: 100%; margin: 0\">\n<link data-trunk rel=\"rust\" href=\"Cargo.toml\" data-wasm-opt=\"z\" data-bin=\"download_progress\" />\n</body>\n</html>\n"
  },
  {
    "path": "examples/download_progress/src/download.rs",
    "content": "use iced::futures::StreamExt;\nuse iced::task::{Straw, sipper};\n\nuse std::sync::Arc;\n\npub fn download(url: impl AsRef<str>) -> impl Straw<(), Progress, Error> {\n    sipper(async move |mut progress| {\n        let response = reqwest::get(url.as_ref()).await?;\n        let total = response.content_length().ok_or(Error::NoContentLength)?;\n\n        let _ = progress.send(Progress { percent: 0.0 }).await;\n\n        let mut byte_stream = response.bytes_stream();\n        let mut downloaded = 0;\n\n        while let Some(next_bytes) = byte_stream.next().await {\n            let bytes = next_bytes?;\n            downloaded += bytes.len();\n\n            let _ = progress\n                .send(Progress {\n                    percent: 100.0 * downloaded as f32 / total as f32,\n                })\n                .await;\n        }\n\n        Ok(())\n    })\n}\n\n#[derive(Debug, Clone)]\npub struct Progress {\n    pub percent: f32,\n}\n\n#[derive(Debug, Clone)]\npub enum Error {\n    RequestFailed(Arc<reqwest::Error>),\n    NoContentLength,\n}\n\nimpl From<reqwest::Error> for Error {\n    fn from(error: reqwest::Error) -> Self {\n        Error::RequestFailed(Arc::new(error))\n    }\n}\n"
  },
  {
    "path": "examples/download_progress/src/main.rs",
    "content": "mod download;\n\nuse download::download;\n\nuse iced::task;\nuse iced::widget::{Column, button, center, column, progress_bar, text};\nuse iced::{Center, Element, Function, Right, Task};\n\npub fn main() -> iced::Result {\n    iced::application(Example::default, Example::update, Example::view).run()\n}\n\n#[derive(Debug)]\nstruct Example {\n    downloads: Vec<Download>,\n    last_id: usize,\n}\n\n#[derive(Debug, Clone)]\npub enum Message {\n    Add,\n    Download(usize),\n    DownloadUpdated(usize, Update),\n}\n\nimpl Example {\n    fn new() -> Self {\n        Self {\n            downloads: vec![Download::new(0)],\n            last_id: 0,\n        }\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::Add => {\n                self.last_id += 1;\n\n                self.downloads.push(Download::new(self.last_id));\n\n                Task::none()\n            }\n            Message::Download(index) => {\n                let Some(download) = self.downloads.get_mut(index) else {\n                    return Task::none();\n                };\n\n                let task = download.start();\n\n                task.map(Message::DownloadUpdated.with(index))\n            }\n            Message::DownloadUpdated(id, update) => {\n                if let Some(download) = self.downloads.iter_mut().find(|download| download.id == id)\n                {\n                    download.update(update);\n                }\n\n                Task::none()\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let downloads = Column::with_children(self.downloads.iter().map(Download::view))\n            .push(\n                button(\"Add another download\")\n                    .on_press(Message::Add)\n                    .padding(10),\n            )\n            .spacing(20)\n            .align_x(Right);\n\n        center(downloads).padding(20).into()\n    }\n}\n\nimpl Default for Example {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[derive(Debug)]\nstruct Download {\n    id: usize,\n    state: State,\n}\n\n#[derive(Debug, Clone)]\npub enum Update {\n    Downloading(download::Progress),\n    Finished(Result<(), download::Error>),\n}\n\n#[derive(Debug)]\nenum State {\n    Idle,\n    Downloading { progress: f32, _task: task::Handle },\n    Finished,\n    Errored,\n}\n\nimpl Download {\n    pub fn new(id: usize) -> Self {\n        Download {\n            id,\n            state: State::Idle,\n        }\n    }\n\n    pub fn start(&mut self) -> Task<Update> {\n        match self.state {\n            State::Idle | State::Finished | State::Errored => {\n                let (task, handle) = Task::sip(\n                    download(\n                        \"https://huggingface.co/\\\n                        mattshumer/Reflection-Llama-3.1-70B/\\\n                        resolve/main/model-00001-of-00162.safetensors\",\n                    ),\n                    Update::Downloading,\n                    Update::Finished,\n                )\n                .abortable();\n\n                self.state = State::Downloading {\n                    progress: 0.0,\n                    _task: handle.abort_on_drop(),\n                };\n\n                task\n            }\n            State::Downloading { .. } => Task::none(),\n        }\n    }\n\n    pub fn update(&mut self, update: Update) {\n        if let State::Downloading { progress, .. } = &mut self.state {\n            match update {\n                Update::Downloading(new_progress) => {\n                    *progress = new_progress.percent;\n                }\n                Update::Finished(result) => {\n                    self.state = if result.is_ok() {\n                        State::Finished\n                    } else {\n                        State::Errored\n                    };\n                }\n            }\n        }\n    }\n\n    pub fn view(&self) -> Element<'_, Message> {\n        let current_progress = match &self.state {\n            State::Idle => 0.0,\n            State::Downloading { progress, .. } => *progress,\n            State::Finished => 100.0,\n            State::Errored => 0.0,\n        };\n\n        let progress_bar = progress_bar(0.0..=100.0, current_progress);\n\n        let control: Element<_> = match &self.state {\n            State::Idle => button(\"Start the download!\")\n                .on_press(Message::Download(self.id))\n                .into(),\n            State::Finished => column![\"Download finished!\", button(\"Start again\")]\n                .spacing(10)\n                .align_x(Center)\n                .into(),\n            State::Downloading { .. } => text!(\"Downloading... {current_progress:.2}%\").into(),\n            State::Errored => column![\n                \"Something went wrong :(\",\n                button(\"Try again\").on_press(Message::Download(self.id)),\n            ]\n            .spacing(10)\n            .align_x(Center)\n            .into(),\n        };\n\n        Column::new()\n            .spacing(10)\n            .padding(10)\n            .align_x(Center)\n            .push(progress_bar)\n            .push(control)\n            .into()\n    }\n}\n"
  },
  {
    "path": "examples/editor/Cargo.toml",
    "content": "[package]\nname = \"editor\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector@hecrj.dev>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"highlighter\", \"tokio\", \"debug\"]\n\ntokio.workspace = true\ntokio.features = [\"fs\"]\n\nrfd.workspace = true\n"
  },
  {
    "path": "examples/editor/src/main.rs",
    "content": "use iced::highlighter;\nuse iced::keyboard;\nuse iced::widget::{\n    button, center_x, column, container, operation, pick_list, row, space, text, text_editor,\n    toggler, tooltip,\n};\nuse iced::window;\nuse iced::{Center, Element, Fill, Font, Task, Theme, Window};\n\nuse std::ffi;\nuse std::io;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\npub fn main() -> iced::Result {\n    iced::application(Editor::new, Editor::update, Editor::view)\n        .theme(Editor::theme)\n        .font(include_bytes!(\"../fonts/icons.ttf\").as_slice())\n        .default_font(Font::MONOSPACE)\n        .run()\n}\n\nstruct Editor {\n    file: Option<PathBuf>,\n    content: text_editor::Content,\n    theme: highlighter::Theme,\n    word_wrap: bool,\n    is_loading: bool,\n    is_dirty: bool,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    ActionPerformed(text_editor::Action),\n    ThemeSelected(highlighter::Theme),\n    WordWrapToggled(bool),\n    NewFile,\n    OpenFile,\n    FileOpened(Result<(PathBuf, Arc<String>), Error>),\n    SaveFile,\n    FileSaved(Result<PathBuf, Error>),\n}\n\nimpl Editor {\n    fn new() -> (Self, Task<Message>) {\n        (\n            Self {\n                file: None,\n                content: text_editor::Content::new(),\n                theme: highlighter::Theme::SolarizedDark,\n                word_wrap: true,\n                is_loading: true,\n                is_dirty: false,\n            },\n            Task::batch([\n                Task::perform(\n                    load_file(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/src/main.rs\",)),\n                    Message::FileOpened,\n                ),\n                operation::focus(EDITOR),\n            ]),\n        )\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::ActionPerformed(action) => {\n                self.is_dirty = self.is_dirty || action.is_edit();\n\n                self.content.perform(action);\n\n                Task::none()\n            }\n            Message::ThemeSelected(theme) => {\n                self.theme = theme;\n\n                Task::none()\n            }\n            Message::WordWrapToggled(word_wrap) => {\n                self.word_wrap = word_wrap;\n\n                Task::none()\n            }\n            Message::NewFile => {\n                if !self.is_loading {\n                    self.file = None;\n                    self.content = text_editor::Content::new();\n                }\n\n                Task::none()\n            }\n            Message::OpenFile => {\n                if self.is_loading {\n                    Task::none()\n                } else {\n                    self.is_loading = true;\n\n                    window::oldest()\n                        .and_then(|id| window::run(id, open_file))\n                        .then(Task::future)\n                        .map(Message::FileOpened)\n                }\n            }\n            Message::FileOpened(result) => {\n                self.is_loading = false;\n                self.is_dirty = false;\n\n                if let Ok((path, contents)) = result {\n                    self.file = Some(path);\n                    self.content = text_editor::Content::with_text(&contents);\n                }\n\n                Task::none()\n            }\n            Message::SaveFile => {\n                if self.is_loading {\n                    Task::none()\n                } else {\n                    self.is_loading = true;\n\n                    let mut text = self.content.text();\n\n                    if let Some(ending) = self.content.line_ending()\n                        && !text.ends_with(ending.as_str())\n                    {\n                        text.push_str(ending.as_str());\n                    }\n\n                    Task::perform(save_file(self.file.clone(), text), Message::FileSaved)\n                }\n            }\n            Message::FileSaved(result) => {\n                self.is_loading = false;\n\n                if let Ok(path) = result {\n                    self.file = Some(path);\n                    self.is_dirty = false;\n                }\n\n                Task::none()\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let controls = row![\n            action(new_icon(), \"New file\", Some(Message::NewFile)),\n            action(\n                open_icon(),\n                \"Open file\",\n                (!self.is_loading).then_some(Message::OpenFile)\n            ),\n            action(\n                save_icon(),\n                \"Save file\",\n                self.is_dirty.then_some(Message::SaveFile)\n            ),\n            space::horizontal(),\n            toggler(self.word_wrap)\n                .label(\"Word Wrap\")\n                .on_toggle(Message::WordWrapToggled),\n            pick_list(\n                Some(self.theme),\n                highlighter::Theme::ALL,\n                highlighter::Theme::to_string,\n            )\n            .on_select(Message::ThemeSelected)\n            .text_size(14)\n            .padding([5, 10])\n        ]\n        .spacing(10)\n        .align_y(Center);\n\n        let status = row![\n            text(if let Some(path) = &self.file {\n                let path = path.display().to_string();\n\n                if path.len() > 60 {\n                    format!(\"...{}\", &path[path.len() - 40..])\n                } else {\n                    path\n                }\n            } else {\n                String::from(\"New file\")\n            }),\n            space::horizontal(),\n            text({\n                let cursor = self.content.cursor();\n\n                format!(\n                    \"{}:{}\",\n                    cursor.position.line + 1,\n                    cursor.position.column + 1\n                )\n            })\n        ]\n        .spacing(10);\n\n        column![\n            controls,\n            text_editor(&self.content)\n                .id(EDITOR)\n                .height(Fill)\n                .on_action(Message::ActionPerformed)\n                .wrapping(if self.word_wrap {\n                    text::Wrapping::Word\n                } else {\n                    text::Wrapping::None\n                })\n                .highlight(\n                    self.file\n                        .as_deref()\n                        .and_then(Path::extension)\n                        .and_then(ffi::OsStr::to_str)\n                        .unwrap_or(\"rs\"),\n                    self.theme,\n                )\n                .key_binding(|key_press| {\n                    match key_press.key.as_ref() {\n                        keyboard::Key::Character(\"s\") if key_press.modifiers.command() => {\n                            Some(text_editor::Binding::Custom(Message::SaveFile))\n                        }\n                        _ => text_editor::Binding::from_key_press(key_press),\n                    }\n                }),\n            status,\n        ]\n        .spacing(10)\n        .padding(10)\n        .into()\n    }\n\n    fn theme(&self) -> Theme {\n        if self.theme.is_dark() {\n            Theme::Dark\n        } else {\n            Theme::Light\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum Error {\n    DialogClosed,\n    IoError(io::ErrorKind),\n}\n\nfn open_file(\n    window: &dyn Window,\n) -> impl Future<Output = Result<(PathBuf, Arc<String>), Error>> + use<> {\n    let dialog = rfd::AsyncFileDialog::new()\n        .set_title(\"Open a text file...\")\n        .set_parent(&window);\n\n    async move {\n        let picked_file = dialog.pick_file().await.ok_or(Error::DialogClosed)?;\n\n        load_file(picked_file).await\n    }\n}\n\nasync fn load_file(path: impl Into<PathBuf>) -> Result<(PathBuf, Arc<String>), Error> {\n    let path = path.into();\n\n    let contents = tokio::fs::read_to_string(&path)\n        .await\n        .map(Arc::new)\n        .map_err(|error| Error::IoError(error.kind()))?;\n\n    Ok((path, contents))\n}\n\nasync fn save_file(path: Option<PathBuf>, contents: String) -> Result<PathBuf, Error> {\n    let path = if let Some(path) = path {\n        path\n    } else {\n        rfd::AsyncFileDialog::new()\n            .save_file()\n            .await\n            .as_ref()\n            .map(rfd::FileHandle::path)\n            .map(Path::to_owned)\n            .ok_or(Error::DialogClosed)?\n    };\n\n    tokio::fs::write(&path, contents)\n        .await\n        .map_err(|error| Error::IoError(error.kind()))?;\n\n    Ok(path)\n}\n\nfn action<'a, Message: Clone + 'a>(\n    content: impl Into<Element<'a, Message>>,\n    label: &'a str,\n    on_press: Option<Message>,\n) -> Element<'a, Message> {\n    let action = button(center_x(content).width(30));\n\n    if let Some(on_press) = on_press {\n        tooltip(\n            action.on_press(on_press),\n            label,\n            tooltip::Position::FollowCursor,\n        )\n        .style(container::rounded_box)\n        .into()\n    } else {\n        action.style(button::secondary).into()\n    }\n}\n\nfn new_icon<'a, Message>() -> Element<'a, Message> {\n    icon('\\u{0e800}')\n}\n\nfn save_icon<'a, Message>() -> Element<'a, Message> {\n    icon('\\u{0e801}')\n}\n\nfn open_icon<'a, Message>() -> Element<'a, Message> {\n    icon('\\u{0f115}')\n}\n\nfn icon<'a, Message>(codepoint: char) -> Element<'a, Message> {\n    const ICON_FONT: Font = Font::new(\"editor-icons\");\n\n    text(codepoint)\n        .font(ICON_FONT)\n        .shaping(text::Shaping::Basic)\n        .into()\n}\n\nconst EDITOR: &str = \"editor\";\n"
  },
  {
    "path": "examples/events/Cargo.toml",
    "content": "[package]\nname = \"events\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\"]\n"
  },
  {
    "path": "examples/events/README.md",
    "content": "## Events\n\nA log of native events displayed using a conditional `Subscription`.\n\nThe __[`main`]__ file contains all the code of the example.\n\nYou can run it with `cargo run`:\n```\ncargo run --package events\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/events/src/main.rs",
    "content": "use iced::event::{self, Event};\nuse iced::widget::{Column, button, center, checkbox, text};\nuse iced::window;\nuse iced::{Center, Element, Fill, Subscription, Task};\n\npub fn main() -> iced::Result {\n    iced::application(Events::default, Events::update, Events::view)\n        .subscription(Events::subscription)\n        .exit_on_close_request(false)\n        .run()\n}\n\n#[derive(Debug, Default)]\nstruct Events {\n    last: Vec<Event>,\n    enabled: bool,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    EventOccurred(Event),\n    Toggled(bool),\n    Exit,\n}\n\nimpl Events {\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::EventOccurred(event) if self.enabled => {\n                self.last.push(event);\n\n                if self.last.len() > 5 {\n                    let _ = self.last.remove(0);\n                }\n\n                Task::none()\n            }\n            Message::EventOccurred(event) => {\n                if let Event::Window(window::Event::CloseRequested) = event {\n                    window::latest().and_then(window::close)\n                } else {\n                    Task::none()\n                }\n            }\n            Message::Toggled(enabled) => {\n                self.enabled = enabled;\n\n                Task::none()\n            }\n            Message::Exit => window::latest().and_then(window::close),\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        event::listen().map(Message::EventOccurred)\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let events = Column::with_children(\n            self.last\n                .iter()\n                .map(|event| text!(\"{event:?}\").size(40))\n                .map(Element::from),\n        );\n\n        let toggle = checkbox(self.enabled)\n            .label(\"Listen to runtime events\")\n            .on_toggle(Message::Toggled);\n\n        let exit = button(text(\"Exit\").width(Fill).align_x(Center))\n            .width(100)\n            .padding(10)\n            .on_press(Message::Exit);\n\n        let content = Column::new()\n            .align_x(Center)\n            .spacing(20)\n            .push(events)\n            .push(toggle)\n            .push(exit);\n\n        center(content).into()\n    }\n}\n"
  },
  {
    "path": "examples/exit/Cargo.toml",
    "content": "[package]\nname = \"exit\"\nversion = \"0.1.0\"\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\n"
  },
  {
    "path": "examples/exit/README.md",
    "content": "## Exit\n\nHow to exit an application based on user input.\n\nThe __[`main`]__ file contains all the code of the example.\n\nYou can run it with `cargo run`:\n```\ncargo run --package exit\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/exit/src/main.rs",
    "content": "use iced::widget::{button, center, column};\nuse iced::window;\nuse iced::{Center, Element, Task};\n\npub fn main() -> iced::Result {\n    iced::run(Exit::update, Exit::view)\n}\n\n#[derive(Default)]\nstruct Exit {\n    show_confirm: bool,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Confirm,\n    Exit,\n}\n\nimpl Exit {\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::Confirm => window::latest().and_then(window::close),\n            Message::Exit => {\n                self.show_confirm = true;\n\n                Task::none()\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let content = if self.show_confirm {\n            column![\n                \"Are you sure you want to exit?\",\n                button(\"Yes, exit now\")\n                    .padding([10, 20])\n                    .on_press(Message::Confirm),\n            ]\n        } else {\n            column![\n                \"Click the button to exit\",\n                button(\"Exit\").padding([10, 20]).on_press(Message::Exit),\n            ]\n        }\n        .spacing(10)\n        .align_x(Center);\n\n        center(content).padding(20).into()\n    }\n}\n"
  },
  {
    "path": "examples/ferris/Cargo.toml",
    "content": "[package]\nname = \"ferris\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"image\", \"tokio\", \"debug\"]\n"
  },
  {
    "path": "examples/ferris/src/main.rs",
    "content": "use iced::time::Instant;\nuse iced::widget::{center, checkbox, column, container, image, pick_list, row, slider, text};\nuse iced::window;\nuse iced::{\n    Bottom, Center, Color, ContentFit, Degrees, Element, Fill, Radians, Rotation, Subscription,\n    Theme,\n};\n\npub fn main() -> iced::Result {\n    iced::application(Image::default, Image::update, Image::view)\n        .subscription(Image::subscription)\n        .theme(Theme::TokyoNight)\n        .run()\n}\n\nstruct Image {\n    width: f32,\n    opacity: f32,\n    rotation: Rotation,\n    content_fit: ContentFit,\n    spin: bool,\n    last_tick: Instant,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    WidthChanged(f32),\n    OpacityChanged(f32),\n    RotationStrategyChanged(RotationStrategy),\n    RotationChanged(Degrees),\n    ContentFitChanged(ContentFit),\n    SpinToggled(bool),\n    RedrawRequested(Instant),\n}\n\nimpl Image {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::WidthChanged(width) => {\n                self.width = width;\n            }\n            Message::OpacityChanged(opacity) => {\n                self.opacity = opacity;\n            }\n            Message::RotationStrategyChanged(strategy) => {\n                self.rotation = match strategy {\n                    RotationStrategy::Floating => Rotation::Floating(self.rotation.radians()),\n                    RotationStrategy::Solid => Rotation::Solid(self.rotation.radians()),\n                };\n            }\n            Message::RotationChanged(rotation) => {\n                self.rotation = match self.rotation {\n                    Rotation::Floating(_) => Rotation::Floating(rotation.into()),\n                    Rotation::Solid(_) => Rotation::Solid(rotation.into()),\n                };\n            }\n            Message::ContentFitChanged(content_fit) => {\n                self.content_fit = content_fit;\n            }\n            Message::SpinToggled(spin) => {\n                self.spin = spin;\n                self.last_tick = Instant::now();\n            }\n            Message::RedrawRequested(now) => {\n                const ROTATION_SPEED: Degrees = Degrees(360.0);\n\n                let delta = (now - self.last_tick).as_millis() as f32 / 1_000.0;\n\n                *self.rotation.radians_mut() =\n                    (self.rotation.radians() + ROTATION_SPEED * delta) % (2.0 * Radians::PI);\n\n                self.last_tick = now;\n            }\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        if self.spin {\n            window::frames().map(Message::RedrawRequested)\n        } else {\n            Subscription::none()\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let i_am_ferris = column![\n            \"Hello!\",\n            Element::from(\n                image(concat!(\n                    env!(\"CARGO_MANIFEST_DIR\"),\n                    \"/../tour/images/ferris.png\",\n                ))\n                .width(self.width)\n                .content_fit(self.content_fit)\n                .rotation(self.rotation)\n                .opacity(self.opacity)\n            )\n            .explain(Color::WHITE),\n            \"I am Ferris!\"\n        ]\n        .spacing(20)\n        .align_x(Center);\n\n        let fit = row![\n            pick_list(\n                Some(self.content_fit),\n                [\n                    ContentFit::Contain,\n                    ContentFit::Cover,\n                    ContentFit::Fill,\n                    ContentFit::None,\n                    ContentFit::ScaleDown\n                ],\n                ContentFit::to_string,\n            )\n            .on_select(Message::ContentFitChanged)\n            .width(Fill),\n            pick_list(\n                Some(match self.rotation {\n                    Rotation::Floating(_) => RotationStrategy::Floating,\n                    Rotation::Solid(_) => RotationStrategy::Solid,\n                }),\n                [RotationStrategy::Floating, RotationStrategy::Solid],\n                RotationStrategy::to_string,\n            )\n            .on_select(Message::RotationStrategyChanged,)\n            .width(Fill),\n        ]\n        .spacing(10)\n        .align_y(Bottom);\n\n        let properties = row![\n            with_value(\n                slider(100.0..=500.0, self.width, Message::WidthChanged),\n                format!(\"Width: {}px\", self.width)\n            ),\n            with_value(\n                slider(0.0..=1.0, self.opacity, Message::OpacityChanged).step(0.01),\n                format!(\"Opacity: {:.2}\", self.opacity)\n            ),\n            with_value(\n                row![\n                    slider(\n                        Degrees::RANGE,\n                        self.rotation.degrees(),\n                        Message::RotationChanged\n                    ),\n                    checkbox(self.spin)\n                        .label(\"Spin!\")\n                        .text_size(12)\n                        .on_toggle(Message::SpinToggled)\n                        .size(12)\n                ]\n                .spacing(10)\n                .align_y(Center),\n                format!(\"Rotation: {:.0}°\", f32::from(self.rotation.degrees()))\n            )\n        ]\n        .spacing(10)\n        .align_y(Bottom);\n\n        container(column![fit, center(i_am_ferris), properties].spacing(10))\n            .padding(10)\n            .into()\n    }\n}\n\nimpl Default for Image {\n    fn default() -> Self {\n        Self {\n            width: 300.0,\n            opacity: 1.0,\n            rotation: Rotation::default(),\n            content_fit: ContentFit::default(),\n            spin: false,\n            last_tick: Instant::now(),\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\nenum RotationStrategy {\n    Floating,\n    Solid,\n}\n\nimpl std::fmt::Display for RotationStrategy {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_str(match self {\n            Self::Floating => \"Floating\",\n            Self::Solid => \"Solid\",\n        })\n    }\n}\n\nfn with_value<'a>(control: impl Into<Element<'a, Message>>, value: String) -> Element<'a, Message> {\n    column![control.into(), text(value).size(12).line_height(1.0)]\n        .spacing(2)\n        .align_x(Center)\n        .into()\n}\n"
  },
  {
    "path": "examples/gallery/Cargo.toml",
    "content": "[package]\nname = \"gallery\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"tokio\", \"sipper\", \"image\", \"debug\"]\n\nreqwest.version = \"0.12\"\nreqwest.features = [\"json\"]\n\nserde.version = \"1.0\"\nserde.features = [\"derive\"]\n\nbytes.workspace = true\nimage.workspace = true\nsipper.workspace = true\ntokio.workspace = true\n\nblurhash = \"0.2.3\"\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "examples/gallery/src/civitai.rs",
    "content": "use serde::Deserialize;\nuse sipper::{Straw, sipper};\nuse tokio::task;\n\nuse std::fmt;\nuse std::io;\nuse std::sync::{Arc, LazyLock};\n\nstatic CLIENT: LazyLock<reqwest::Client> = LazyLock::new(reqwest::Client::new);\n\n#[derive(Debug, Clone, Deserialize)]\npub struct Image {\n    pub id: Id,\n    url: String,\n    hash: String,\n}\n\nimpl Image {\n    pub const LIMIT: usize = 200;\n\n    pub async fn list() -> Result<Vec<Self>, Error> {\n        #[derive(Deserialize)]\n        struct Response {\n            items: Vec<Image>,\n        }\n\n        let response: Response = CLIENT\n            .get(\"https://civitai.com/api/v1/images\")\n            .query(&[\n                (\"sort\", \"Most Reactions\"),\n                (\"period\", \"Month\"),\n                (\"nsfw\", \"None\"),\n                (\"limit\", &Image::LIMIT.to_string()),\n            ])\n            .send()\n            .await?\n            .error_for_status()?\n            .json()\n            .await?;\n\n        Ok(response\n            .items\n            .into_iter()\n            .filter(|image| !image.url.ends_with(\".mp4\"))\n            .collect())\n    }\n\n    pub async fn blurhash(self, width: u32, height: u32) -> Result<Blurhash, Error> {\n        task::spawn_blocking(move || {\n            let pixels = blurhash::decode(&self.hash, width, height, 1.0)?;\n\n            Ok::<_, Error>(Blurhash {\n                rgba: Rgba {\n                    width,\n                    height,\n                    pixels: Bytes(pixels.into()),\n                },\n            })\n        })\n        .await?\n    }\n\n    pub fn download(self, size: Size) -> impl Straw<Bytes, Blurhash, Error> {\n        sipper(async move |mut sender| {\n            if let Size::Thumbnail { width, height } = size {\n                let image = self.clone();\n\n                drop(task::spawn(async move {\n                    if let Ok(blurhash) = image.blurhash(width, height).await {\n                        sender.send(blurhash).await;\n                    }\n                }));\n            }\n\n            let bytes = CLIENT\n                .get(match size {\n                    Size::Original => self.url,\n                    Size::Thumbnail { width, .. } => self\n                        .url\n                        .split(\"/\")\n                        .map(|part| {\n                            if part.starts_with(\"width=\") || part.starts_with(\"original=\") {\n                                format!(\"width={}\", width * 2) // High DPI\n                            } else {\n                                part.to_owned()\n                            }\n                        })\n                        .collect::<Vec<_>>()\n                        .join(\"/\"),\n                })\n                .send()\n                .await?\n                .error_for_status()?\n                .bytes()\n                .await?;\n\n            Ok(Bytes(bytes))\n        })\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize)]\npub struct Id(u32);\n\n#[derive(Debug, Clone)]\npub struct Blurhash {\n    pub rgba: Rgba,\n}\n\n#[derive(Clone)]\npub struct Rgba {\n    pub width: u32,\n    pub height: u32,\n    pub pixels: Bytes,\n}\n\nimpl fmt::Debug for Rgba {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Rgba\")\n            .field(\"width\", &self.width)\n            .field(\"height\", &self.height)\n            .finish()\n    }\n}\n\n#[derive(Clone)]\npub struct Bytes(bytes::Bytes);\n\nimpl Bytes {\n    pub fn as_slice(&self) -> &[u8] {\n        &self.0\n    }\n}\n\nimpl From<Bytes> for bytes::Bytes {\n    fn from(value: Bytes) -> Self {\n        value.0\n    }\n}\n\nimpl fmt::Debug for Bytes {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Compressed\")\n            .field(\"bytes\", &self.0.len())\n            .finish()\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum Size {\n    Original,\n    Thumbnail { width: u32, height: u32 },\n}\n\n#[derive(Debug, Clone)]\n#[allow(dead_code)]\npub enum Error {\n    RequestFailed(Arc<reqwest::Error>),\n    IOFailed(Arc<io::Error>),\n    JoinFailed(Arc<task::JoinError>),\n    ImageDecodingFailed,\n    BlurhashDecodingFailed(Arc<blurhash::Error>),\n}\n\nimpl From<reqwest::Error> for Error {\n    fn from(error: reqwest::Error) -> Self {\n        Self::RequestFailed(Arc::new(error))\n    }\n}\n\nimpl From<io::Error> for Error {\n    fn from(error: io::Error) -> Self {\n        Self::IOFailed(Arc::new(error))\n    }\n}\n\nimpl From<task::JoinError> for Error {\n    fn from(error: task::JoinError) -> Self {\n        Self::JoinFailed(Arc::new(error))\n    }\n}\n\nimpl From<blurhash::Error> for Error {\n    fn from(error: blurhash::Error) -> Self {\n        Self::BlurhashDecodingFailed(Arc::new(error))\n    }\n}\n"
  },
  {
    "path": "examples/gallery/src/main.rs",
    "content": "//! A simple gallery that displays the daily featured images of Civitai.\n//!\n//! Showcases lazy loading of images in the background, as well as\n//! some smooth animations.\nmod civitai;\n\nuse crate::civitai::{Bytes, Error, Id, Image, Rgba, Size};\n\nuse iced::animation;\nuse iced::border;\nuse iced::time::{Instant, milliseconds};\nuse iced::widget::{\n    button, container, float, grid, image, mouse_area, opaque, scrollable, sensor, space, stack,\n};\nuse iced::window;\nuse iced::{\n    Animation, Color, ContentFit, Element, Fill, Function, Shadow, Subscription, Task, Theme, color,\n};\n\nuse std::collections::{HashMap, HashSet};\n\nfn main() -> iced::Result {\n    iced::application::timed(\n        Gallery::new,\n        Gallery::update,\n        Gallery::subscription,\n        Gallery::view,\n    )\n    .window_size((Preview::WIDTH as f32 * 4.0, Preview::HEIGHT as f32 * 2.5))\n    .theme(Gallery::theme)\n    .run()\n}\n\nstruct Gallery {\n    images: Vec<Image>,\n    previews: HashMap<Id, Preview>,\n    visible: HashSet<Id>,\n    downloaded: HashSet<Id>,\n    viewer: Viewer,\n    now: Instant,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    ImagesListed(Result<Vec<Image>, Error>),\n    ImagePoppedIn(Id),\n    ImagePoppedOut(Id),\n    ImageDownloaded(Result<image::Allocation, Error>),\n    ThumbnailDownloaded(Id, Result<Bytes, Error>),\n    ThumbnailAllocated(Id, Result<image::Allocation, image::Error>),\n    ThumbnailHovered(Id, bool),\n    BlurhashDecoded(Id, civitai::Blurhash),\n    Open(Id),\n    Close,\n    Animate,\n}\n\nimpl Gallery {\n    pub fn new() -> (Self, Task<Message>) {\n        (\n            Self {\n                images: Vec::new(),\n                previews: HashMap::new(),\n                visible: HashSet::new(),\n                downloaded: HashSet::new(),\n                viewer: Viewer::new(),\n                now: Instant::now(),\n            },\n            Task::perform(Image::list(), Message::ImagesListed),\n        )\n    }\n\n    pub fn theme(&self) -> Theme {\n        Theme::TokyoNight\n    }\n\n    pub fn subscription(&self) -> Subscription<Message> {\n        let is_animating = self\n            .previews\n            .values()\n            .any(|preview| preview.is_animating(self.now))\n            || self.viewer.is_animating(self.now);\n\n        if is_animating {\n            window::frames().map(|_| Message::Animate)\n        } else {\n            Subscription::none()\n        }\n    }\n\n    pub fn update(&mut self, message: Message, now: Instant) -> Task<Message> {\n        self.now = now;\n\n        match message {\n            Message::ImagesListed(Ok(images)) => {\n                self.images = images;\n\n                Task::none()\n            }\n            Message::ImagePoppedIn(id) => {\n                let Some(image) = self\n                    .images\n                    .iter()\n                    .find(|candidate| candidate.id == id)\n                    .cloned()\n                else {\n                    return Task::none();\n                };\n\n                let _ = self.visible.insert(id);\n\n                if self.downloaded.contains(&id) {\n                    let Some(Preview::Ready {\n                        thumbnail,\n                        blurhash,\n                    }) = self.previews.get_mut(&id)\n                    else {\n                        return Task::none();\n                    };\n\n                    if let Some(blurhash) = blurhash {\n                        blurhash.show(now);\n                    }\n\n                    return to_rgba(thumbnail.bytes.clone())\n                        .then(image::allocate)\n                        .map(Message::ThumbnailAllocated.with(id));\n                }\n\n                let _ = self.downloaded.insert(id);\n\n                Task::sip(\n                    image.download(Size::Thumbnail {\n                        width: Preview::WIDTH,\n                        height: Preview::HEIGHT,\n                    }),\n                    Message::BlurhashDecoded.with(id),\n                    Message::ThumbnailDownloaded.with(id),\n                )\n            }\n            Message::ImagePoppedOut(id) => {\n                let _ = self.visible.remove(&id);\n\n                if let Some(Preview::Ready {\n                    thumbnail,\n                    blurhash,\n                }) = self.previews.get_mut(&id)\n                {\n                    thumbnail.reset();\n\n                    if let Some(blurhash) = blurhash {\n                        blurhash.reset();\n                    }\n                }\n\n                Task::none()\n            }\n            Message::ImageDownloaded(Ok(allocation)) => {\n                self.viewer.show(allocation, self.now);\n\n                Task::none()\n            }\n            Message::ThumbnailDownloaded(id, Ok(bytes)) => {\n                let preview = if let Some(preview) = self.previews.remove(&id) {\n                    preview.load(bytes.clone())\n                } else {\n                    Preview::ready(bytes.clone())\n                };\n\n                let _ = self.previews.insert(id, preview);\n\n                to_rgba(bytes)\n                    .then(image::allocate)\n                    .map(Message::ThumbnailAllocated.with(id))\n            }\n            Message::ThumbnailAllocated(id, Ok(allocation)) => {\n                if !self.visible.contains(&id) {\n                    return Task::none();\n                }\n\n                let Some(Preview::Ready { thumbnail, .. }) = self.previews.get_mut(&id) else {\n                    return Task::none();\n                };\n\n                thumbnail.show(allocation, now);\n\n                Task::none()\n            }\n            Message::ThumbnailHovered(id, is_hovered) => {\n                if let Some(preview) = self.previews.get_mut(&id) {\n                    preview.toggle_zoom(is_hovered, self.now);\n                }\n\n                Task::none()\n            }\n            Message::BlurhashDecoded(id, blurhash) => {\n                if !self.previews.contains_key(&id) {\n                    let _ = self\n                        .previews\n                        .insert(id, Preview::loading(blurhash.rgba, self.now));\n                }\n\n                Task::none()\n            }\n            Message::Open(id) => {\n                let Some(image) = self\n                    .images\n                    .iter()\n                    .find(|candidate| candidate.id == id)\n                    .cloned()\n                else {\n                    return Task::none();\n                };\n\n                self.viewer.open(self.now);\n\n                Task::future(image.download(Size::Original))\n                    .and_then(|bytes| {\n                        image::allocate(image::Handle::from_bytes(bytes))\n                            .map_err(|_| Error::ImageDecodingFailed)\n                    })\n                    .map(Message::ImageDownloaded)\n            }\n            Message::Close => {\n                self.viewer.close(self.now);\n\n                Task::none()\n            }\n            Message::Animate => Task::none(),\n            Message::ImagesListed(Err(error))\n            | Message::ImageDownloaded(Err(error))\n            | Message::ThumbnailDownloaded(_, Err(error)) => {\n                dbg!(error);\n\n                Task::none()\n            }\n            Message::ThumbnailAllocated(_, Err(error)) => {\n                dbg!(error);\n\n                Task::none()\n            }\n        }\n    }\n\n    pub fn view(&self) -> Element<'_, Message> {\n        let images = self\n            .images\n            .iter()\n            .map(|image| {\n                card(\n                    image,\n                    if self.visible.contains(&image.id) {\n                        self.previews.get(&image.id)\n                    } else {\n                        None\n                    },\n                    self.now,\n                )\n            })\n            .chain(\n                if self.images.is_empty() {\n                    0..Image::LIMIT\n                } else {\n                    0..0\n                }\n                .map(|_| placeholder()),\n            );\n\n        let gallery = grid(images)\n            .fluid(Preview::WIDTH)\n            .height(grid::aspect_ratio(Preview::WIDTH, Preview::HEIGHT))\n            .spacing(10);\n\n        let content = container(scrollable(gallery).spacing(10).auto_scroll(true)).padding(10);\n        let viewer = self.viewer.view(self.now);\n\n        stack![content, viewer].into()\n    }\n}\n\nfn card<'a>(\n    metadata: &'a Image,\n    preview: Option<&'a Preview>,\n    now: Instant,\n) -> Element<'a, Message> {\n    let image = if let Some(preview) = preview {\n        let thumbnail: Element<'_, _> = if let Preview::Ready { thumbnail, .. } = &preview\n            && let Some(allocation) = &thumbnail.allocation\n        {\n            float(\n                image(allocation.handle())\n                    .width(Fill)\n                    .content_fit(ContentFit::Cover)\n                    .opacity(thumbnail.fade_in.interpolate(0.0, 1.0, now))\n                    .border_radius(BORDER_RADIUS),\n            )\n            .scale(thumbnail.zoom.interpolate(1.0, 1.1, now))\n            .translate(move |bounds, viewport| {\n                bounds.zoom(1.1).offset(&viewport.shrink(10))\n                    * thumbnail.zoom.interpolate(0.0, 1.0, now)\n            })\n            .style(move |_theme| float::Style {\n                shadow: Shadow {\n                    color: Color::BLACK.scale_alpha(thumbnail.zoom.interpolate(0.0, 1.0, now)),\n                    blur_radius: thumbnail.zoom.interpolate(0.0, 20.0, now),\n                    ..Shadow::default()\n                },\n                shadow_border_radius: border::radius(BORDER_RADIUS),\n            })\n            .into()\n        } else {\n            space::horizontal().into()\n        };\n\n        if let Some(blurhash) = preview.blurhash(now) {\n            let blurhash = image(&blurhash.handle)\n                .width(Fill)\n                .content_fit(ContentFit::Cover)\n                .opacity(blurhash.fade_in.interpolate(0.0, 1.0, now))\n                .border_radius(BORDER_RADIUS);\n\n            stack![blurhash, thumbnail].into()\n        } else {\n            thumbnail\n        }\n    } else {\n        space::horizontal().into()\n    };\n\n    let card = mouse_area(container(image).style(rounded))\n        .on_enter(Message::ThumbnailHovered(metadata.id, true))\n        .on_exit(Message::ThumbnailHovered(metadata.id, false));\n\n    let card: Element<'_, _> = if let Some(preview) = preview {\n        let is_thumbnail = matches!(preview, Preview::Ready { .. });\n\n        button(card)\n            .on_press_maybe(is_thumbnail.then_some(Message::Open(metadata.id)))\n            .padding(0)\n            .style(button::text)\n            .into()\n    } else {\n        card.into()\n    };\n\n    sensor(card)\n        .on_show(|_| Message::ImagePoppedIn(metadata.id))\n        .on_hide(Message::ImagePoppedOut(metadata.id))\n        .into()\n}\n\nfn placeholder<'a>() -> Element<'a, Message> {\n    container(space()).style(rounded).into()\n}\n\nenum Preview {\n    Loading {\n        blurhash: Blurhash,\n    },\n    Ready {\n        blurhash: Option<Blurhash>,\n        thumbnail: Thumbnail,\n    },\n}\n\nstruct Blurhash {\n    handle: image::Handle,\n    fade_in: Animation<bool>,\n}\n\nimpl Blurhash {\n    pub fn show(&mut self, now: Instant) {\n        self.fade_in.go_mut(true, now);\n    }\n\n    pub fn reset(&mut self) {\n        self.fade_in = Animation::new(false)\n            .easing(animation::Easing::EaseIn)\n            .very_quick();\n    }\n}\n\nstruct Thumbnail {\n    bytes: Bytes,\n    allocation: Option<image::Allocation>,\n    fade_in: Animation<bool>,\n    zoom: Animation<bool>,\n}\n\nimpl Preview {\n    const WIDTH: u32 = 320;\n    const HEIGHT: u32 = 410;\n\n    fn loading(rgba: Rgba, now: Instant) -> Self {\n        Self::Loading {\n            blurhash: Blurhash {\n                fade_in: Animation::new(false)\n                    .duration(milliseconds(700))\n                    .easing(animation::Easing::EaseIn)\n                    .go(true, now),\n                handle: image::Handle::from_rgba(rgba.width, rgba.height, rgba.pixels),\n            },\n        }\n    }\n\n    fn ready(bytes: Bytes) -> Self {\n        Self::Ready {\n            blurhash: None,\n            thumbnail: Thumbnail::new(bytes),\n        }\n    }\n\n    fn load(self, bytes: Bytes) -> Self {\n        let Self::Loading { blurhash } = self else {\n            return self;\n        };\n\n        Self::Ready {\n            blurhash: Some(blurhash),\n            thumbnail: Thumbnail::new(bytes),\n        }\n    }\n\n    fn toggle_zoom(&mut self, enabled: bool, now: Instant) {\n        if let Self::Ready { thumbnail, .. } = self {\n            thumbnail.zoom.go_mut(enabled, now);\n        }\n    }\n\n    fn is_animating(&self, now: Instant) -> bool {\n        match &self {\n            Self::Loading { blurhash } => blurhash.fade_in.is_animating(now),\n            Self::Ready {\n                thumbnail,\n                blurhash,\n            } => {\n                thumbnail.fade_in.is_animating(now)\n                    || thumbnail.zoom.is_animating(now)\n                    || blurhash\n                        .as_ref()\n                        .is_some_and(|blurhash| blurhash.fade_in.is_animating(now))\n            }\n        }\n    }\n\n    fn blurhash(&self, now: Instant) -> Option<&Blurhash> {\n        match self {\n            Self::Loading { blurhash, .. } => Some(blurhash),\n            Self::Ready {\n                blurhash: Some(blurhash),\n                thumbnail,\n                ..\n            } if !thumbnail.fade_in.value() || thumbnail.fade_in.is_animating(now) => {\n                Some(blurhash)\n            }\n            Self::Ready { .. } => None,\n        }\n    }\n}\n\nimpl Thumbnail {\n    pub fn new(bytes: Bytes) -> Self {\n        Self {\n            bytes,\n            allocation: None,\n            fade_in: Animation::new(false)\n                .easing(animation::Easing::EaseIn)\n                .slow(),\n            zoom: Animation::new(false)\n                .quick()\n                .easing(animation::Easing::EaseInOut),\n        }\n    }\n\n    pub fn reset(&mut self) {\n        self.allocation = None;\n        self.fade_in = Animation::new(false)\n            .easing(animation::Easing::EaseIn)\n            .quick();\n    }\n\n    pub fn show(&mut self, allocation: image::Allocation, now: Instant) {\n        self.allocation = Some(allocation);\n        self.fade_in.go_mut(true, now);\n    }\n}\n\nstruct Viewer {\n    image: Option<image::Allocation>,\n    background_fade_in: Animation<bool>,\n    image_fade_in: Animation<bool>,\n}\n\nimpl Viewer {\n    fn new() -> Self {\n        Self {\n            image: None,\n            background_fade_in: Animation::new(false)\n                .very_slow()\n                .easing(animation::Easing::EaseInOut),\n            image_fade_in: Animation::new(false)\n                .very_slow()\n                .easing(animation::Easing::EaseInOut),\n        }\n    }\n\n    fn open(&mut self, now: Instant) {\n        self.image = None;\n        self.background_fade_in.go_mut(true, now);\n    }\n\n    fn show(&mut self, allocation: image::Allocation, now: Instant) {\n        self.image = Some(allocation);\n        self.background_fade_in.go_mut(true, now);\n        self.image_fade_in.go_mut(true, now);\n    }\n\n    fn close(&mut self, now: Instant) {\n        self.background_fade_in.go_mut(false, now);\n        self.image_fade_in.go_mut(false, now);\n    }\n\n    fn is_animating(&self, now: Instant) -> bool {\n        self.background_fade_in.is_animating(now) || self.image_fade_in.is_animating(now)\n    }\n\n    fn view(&self, now: Instant) -> Option<Element<'_, Message>> {\n        let opacity = self.background_fade_in.interpolate(0.0, 0.8, now);\n\n        if opacity <= 0.0 {\n            return None;\n        }\n\n        let image = self.image.as_ref().map(|allocation| {\n            image(allocation.handle())\n                .width(Fill)\n                .height(Fill)\n                .opacity(self.image_fade_in.interpolate(0.0, 1.0, now))\n                .scale(self.image_fade_in.interpolate(1.5, 1.0, now))\n        });\n\n        Some(opaque(\n            mouse_area(\n                container(image)\n                    .center(Fill)\n                    .style(move |_theme| {\n                        container::Style::default().background(color!(0x000000, opacity))\n                    })\n                    .padding(20),\n            )\n            .on_press(Message::Close),\n        ))\n    }\n}\n\nfn to_rgba(bytes: Bytes) -> Task<image::Handle> {\n    Task::future(async move {\n        tokio::task::spawn_blocking(move || match ::image::load_from_memory(bytes.as_slice()) {\n            Ok(image) => {\n                let rgba = image.to_rgba8();\n\n                image::Handle::from_rgba(rgba.width(), rgba.height(), rgba.into_raw())\n            }\n            _ => image::Handle::from_bytes(bytes),\n        })\n        .await\n        .unwrap()\n    })\n}\n\nfn rounded(theme: &Theme) -> container::Style {\n    container::dark(theme).border(border::rounded(BORDER_RADIUS))\n}\n\nconst BORDER_RADIUS: u32 = 10;\n"
  },
  {
    "path": "examples/game_of_life/Cargo.toml",
    "content": "[package]\nname = \"game_of_life\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"canvas\", \"tokio\"]\n\nitertools = \"0.12\"\nrustc-hash.workspace = true\ntokio = { workspace = true, features = [\"sync\"] }\ntracing-subscriber = \"0.3\"\n"
  },
  {
    "path": "examples/game_of_life/README.md",
    "content": "## Game of Life\n\nAn interactive version of the [Game of Life], invented by [John Horton Conway].\n\nIt runs a simulation in a background thread while allowing interaction with a `Canvas` that displays an infinite grid with zooming, panning, and drawing support.\n\nThe __[`main`]__ file contains the relevant code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/game_of_life.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package game_of_life\n```\n\n[`main`]: src/main.rs\n[Game of Life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life\n[John Horton Conway]: https://en.wikipedia.org/wiki/John_Horton_Conway\n"
  },
  {
    "path": "examples/game_of_life/src/main.rs",
    "content": "//! This example showcases an interactive version of the Game of Life, invented\n//! by John Conway. It leverages a `Canvas` together with other widgets.\nmod preset;\n\nuse grid::Grid;\nuse preset::Preset;\n\nuse iced::time::{self, milliseconds};\nuse iced::widget::{button, checkbox, column, container, pick_list, row, slider, text};\nuse iced::{Center, Element, Fill, Function, Subscription, Task, Theme};\n\npub fn main() -> iced::Result {\n    tracing_subscriber::fmt::init();\n\n    iced::application(GameOfLife::default, GameOfLife::update, GameOfLife::view)\n        .subscription(GameOfLife::subscription)\n        .theme(Theme::Dark)\n        .centered()\n        .run()\n}\n\nstruct GameOfLife {\n    grid: Grid,\n    is_playing: bool,\n    queued_ticks: usize,\n    speed: usize,\n    next_speed: Option<usize>,\n    version: usize,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    Grid(usize, grid::Message),\n    Tick,\n    TogglePlayback,\n    ToggleGrid(bool),\n    Next,\n    Clear,\n    SpeedChanged(f32),\n    PresetPicked(Preset),\n}\n\nimpl GameOfLife {\n    fn new() -> Self {\n        Self {\n            grid: Grid::default(),\n            is_playing: false,\n            queued_ticks: 0,\n            speed: 5,\n            next_speed: None,\n            version: 0,\n        }\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::Grid(version, message) => {\n                if version == self.version {\n                    self.grid.update(message);\n                }\n            }\n            Message::Tick | Message::Next => {\n                self.queued_ticks = (self.queued_ticks + 1).min(self.speed);\n\n                if let Some(task) = self.grid.tick(self.queued_ticks) {\n                    if let Some(speed) = self.next_speed.take() {\n                        self.speed = speed;\n                    }\n\n                    self.queued_ticks = 0;\n\n                    let version = self.version;\n\n                    return Task::perform(task, Message::Grid.with(version));\n                }\n            }\n            Message::TogglePlayback => {\n                self.is_playing = !self.is_playing;\n            }\n            Message::ToggleGrid(show_grid_lines) => {\n                self.grid.toggle_lines(show_grid_lines);\n            }\n            Message::Clear => {\n                self.grid.clear();\n                self.version += 1;\n            }\n            Message::SpeedChanged(speed) => {\n                if self.is_playing {\n                    self.next_speed = Some(speed.round() as usize);\n                } else {\n                    self.speed = speed.round() as usize;\n                }\n            }\n            Message::PresetPicked(new_preset) => {\n                self.grid = Grid::from_preset(new_preset);\n                self.version += 1;\n            }\n        }\n\n        Task::none()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        if self.is_playing {\n            time::every(milliseconds(1000 / self.speed as u64)).map(|_| Message::Tick)\n        } else {\n            Subscription::none()\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let version = self.version;\n        let selected_speed = self.next_speed.unwrap_or(self.speed);\n        let controls = view_controls(\n            self.is_playing,\n            self.grid.are_lines_visible(),\n            selected_speed,\n            self.grid.preset(),\n        );\n\n        let content =\n            column![self.grid.view().map(Message::Grid.with(version)), controls,].height(Fill);\n\n        container(content).width(Fill).height(Fill).into()\n    }\n}\n\nimpl Default for GameOfLife {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nfn view_controls<'a>(\n    is_playing: bool,\n    is_grid_enabled: bool,\n    speed: usize,\n    preset: Preset,\n) -> Element<'a, Message> {\n    let playback_controls = row![\n        button(if is_playing { \"Pause\" } else { \"Play\" }).on_press(Message::TogglePlayback),\n        button(\"Next\")\n            .on_press(Message::Next)\n            .style(button::secondary),\n    ]\n    .spacing(10);\n\n    let speed_controls = row![\n        slider(1.0..=1000.0, speed as f32, Message::SpeedChanged),\n        text!(\"x{speed}\").size(16),\n    ]\n    .align_y(Center)\n    .spacing(10);\n\n    row![\n        playback_controls,\n        speed_controls,\n        checkbox(is_grid_enabled)\n            .label(\"Grid\")\n            .on_toggle(Message::ToggleGrid),\n        row![\n            pick_list(Some(preset), preset::ALL, Preset::to_string)\n                .on_select(Message::PresetPicked)\n                .ellipsis(text::Ellipsis::Middle),\n            button(\"Clear\")\n                .on_press(Message::Clear)\n                .style(button::danger)\n        ]\n        .spacing(10)\n    ]\n    .padding(10)\n    .spacing(20)\n    .align_y(Center)\n    .into()\n}\n\nmod grid {\n    use crate::Preset;\n    use iced::alignment;\n    use iced::mouse;\n    use iced::time::{Duration, Instant};\n    use iced::touch;\n    use iced::widget::canvas;\n    use iced::widget::canvas::{Cache, Canvas, Event, Frame, Geometry, Path, Text};\n    use iced::widget::text;\n    use iced::{Color, Element, Fill, Point, Rectangle, Renderer, Size, Theme, Vector};\n    use rustc_hash::{FxHashMap, FxHashSet};\n    use std::ops::RangeInclusive;\n\n    pub struct Grid {\n        state: State,\n        preset: Preset,\n        life_cache: Cache,\n        grid_cache: Cache,\n        translation: Vector,\n        scaling: f32,\n        show_lines: bool,\n        last_tick_duration: Duration,\n        last_queued_ticks: usize,\n    }\n\n    #[derive(Debug, Clone)]\n    pub enum Message {\n        Populate(Cell),\n        Unpopulate(Cell),\n        Translated(Vector),\n        Scaled(f32, Option<Vector>),\n        Ticked {\n            result: Result<Life, TickError>,\n            tick_duration: Duration,\n        },\n    }\n\n    #[derive(Debug, Clone)]\n    pub enum TickError {\n        JoinFailed,\n    }\n\n    impl Default for Grid {\n        fn default() -> Self {\n            Self::from_preset(Preset::default())\n        }\n    }\n\n    impl Grid {\n        const MIN_SCALING: f32 = 0.1;\n        const MAX_SCALING: f32 = 2.0;\n\n        pub fn from_preset(preset: Preset) -> Self {\n            Self {\n                state: State::with_life(\n                    preset\n                        .life()\n                        .into_iter()\n                        .map(|(i, j)| Cell { i, j })\n                        .collect(),\n                ),\n                preset,\n                life_cache: Cache::default(),\n                grid_cache: Cache::default(),\n                translation: Vector::default(),\n                scaling: 1.0,\n                show_lines: true,\n                last_tick_duration: Duration::default(),\n                last_queued_ticks: 0,\n            }\n        }\n\n        pub fn tick(&mut self, amount: usize) -> Option<impl Future<Output = Message> + use<>> {\n            let tick = self.state.tick(amount)?;\n\n            self.last_queued_ticks = amount;\n\n            Some(async move {\n                let start = Instant::now();\n                let result = tick.await;\n                let tick_duration = start.elapsed() / amount as u32;\n\n                Message::Ticked {\n                    result,\n                    tick_duration,\n                }\n            })\n        }\n\n        pub fn update(&mut self, message: Message) {\n            match message {\n                Message::Populate(cell) => {\n                    self.state.populate(cell);\n                    self.life_cache.clear();\n\n                    self.preset = Preset::Custom;\n                }\n                Message::Unpopulate(cell) => {\n                    self.state.unpopulate(&cell);\n                    self.life_cache.clear();\n\n                    self.preset = Preset::Custom;\n                }\n                Message::Translated(translation) => {\n                    self.translation = translation;\n\n                    self.life_cache.clear();\n                    self.grid_cache.clear();\n                }\n                Message::Scaled(scaling, translation) => {\n                    self.scaling = scaling;\n\n                    if let Some(translation) = translation {\n                        self.translation = translation;\n                    }\n\n                    self.life_cache.clear();\n                    self.grid_cache.clear();\n                }\n                Message::Ticked {\n                    result: Ok(life),\n                    tick_duration,\n                } => {\n                    self.state.update(life);\n                    self.life_cache.clear();\n\n                    self.last_tick_duration = tick_duration;\n                }\n                Message::Ticked {\n                    result: Err(error), ..\n                } => {\n                    dbg!(error);\n                }\n            }\n        }\n\n        pub fn view(&self) -> Element<'_, Message> {\n            Canvas::new(self).width(Fill).height(Fill).into()\n        }\n\n        pub fn clear(&mut self) {\n            self.state = State::default();\n            self.preset = Preset::Custom;\n\n            self.life_cache.clear();\n        }\n\n        pub fn preset(&self) -> Preset {\n            self.preset\n        }\n\n        pub fn toggle_lines(&mut self, enabled: bool) {\n            self.show_lines = enabled;\n        }\n\n        pub fn are_lines_visible(&self) -> bool {\n            self.show_lines\n        }\n\n        fn visible_region(&self, size: Size) -> Region {\n            let width = size.width / self.scaling;\n            let height = size.height / self.scaling;\n\n            Region {\n                x: -self.translation.x - width / 2.0,\n                y: -self.translation.y - height / 2.0,\n                width,\n                height,\n            }\n        }\n\n        fn project(&self, position: Point, size: Size) -> Point {\n            let region = self.visible_region(size);\n\n            Point::new(\n                position.x / self.scaling + region.x,\n                position.y / self.scaling + region.y,\n            )\n        }\n    }\n\n    impl canvas::Program<Message> for Grid {\n        type State = Interaction;\n\n        fn update(\n            &self,\n            interaction: &mut Interaction,\n            event: &Event,\n            bounds: Rectangle,\n            cursor: mouse::Cursor,\n        ) -> Option<canvas::Action<Message>> {\n            if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event {\n                *interaction = Interaction::None;\n            }\n\n            let cursor_position = cursor.position_in(bounds)?;\n\n            let cell = Cell::at(self.project(cursor_position, bounds.size()));\n            let is_populated = self.state.contains(&cell);\n\n            let (populate, unpopulate) = if is_populated {\n                (None, Some(Message::Unpopulate(cell)))\n            } else {\n                (Some(Message::Populate(cell)), None)\n            };\n\n            match event {\n                Event::Touch(touch::Event::FingerMoved { .. }) => {\n                    let message = {\n                        *interaction = if is_populated {\n                            Interaction::Erasing\n                        } else {\n                            Interaction::Drawing\n                        };\n\n                        populate.or(unpopulate)\n                    };\n\n                    Some(\n                        message\n                            .map(canvas::Action::publish)\n                            .unwrap_or(canvas::Action::request_redraw())\n                            .and_capture(),\n                    )\n                }\n                Event::Mouse(mouse_event) => match mouse_event {\n                    mouse::Event::ButtonPressed(button) => {\n                        let message = match button {\n                            mouse::Button::Left => {\n                                *interaction = if is_populated {\n                                    Interaction::Erasing\n                                } else {\n                                    Interaction::Drawing\n                                };\n\n                                populate.or(unpopulate)\n                            }\n                            mouse::Button::Right => {\n                                *interaction = Interaction::Panning {\n                                    translation: self.translation,\n                                    start: cursor_position,\n                                };\n\n                                None\n                            }\n                            _ => None,\n                        };\n\n                        Some(\n                            message\n                                .map(canvas::Action::publish)\n                                .unwrap_or(canvas::Action::request_redraw())\n                                .and_capture(),\n                        )\n                    }\n                    mouse::Event::CursorMoved { .. } => {\n                        let message = match *interaction {\n                            Interaction::Drawing => populate,\n                            Interaction::Erasing => unpopulate,\n                            Interaction::Panning { translation, start } => {\n                                Some(Message::Translated(\n                                    translation + (cursor_position - start) * (1.0 / self.scaling),\n                                ))\n                            }\n                            Interaction::None => None,\n                        };\n\n                        let action = message\n                            .map(canvas::Action::publish)\n                            .unwrap_or(canvas::Action::request_redraw());\n\n                        Some(match interaction {\n                            Interaction::None => action,\n                            _ => action.and_capture(),\n                        })\n                    }\n                    mouse::Event::WheelScrolled { delta } => match *delta {\n                        mouse::ScrollDelta::Lines { y, .. }\n                        | mouse::ScrollDelta::Pixels { y, .. } => {\n                            if y < 0.0 && self.scaling > Self::MIN_SCALING\n                                || y > 0.0 && self.scaling < Self::MAX_SCALING\n                            {\n                                let old_scaling = self.scaling;\n\n                                let scaling = (self.scaling * (1.0 + y / 30.0))\n                                    .clamp(Self::MIN_SCALING, Self::MAX_SCALING);\n\n                                let translation = if let Some(cursor_to_center) =\n                                    cursor.position_from(bounds.center())\n                                {\n                                    let factor = scaling - old_scaling;\n\n                                    Some(\n                                        self.translation\n                                            - Vector::new(\n                                                cursor_to_center.x * factor\n                                                    / (old_scaling * old_scaling),\n                                                cursor_to_center.y * factor\n                                                    / (old_scaling * old_scaling),\n                                            ),\n                                    )\n                                } else {\n                                    None\n                                };\n\n                                Some(\n                                    canvas::Action::publish(Message::Scaled(scaling, translation))\n                                        .and_capture(),\n                                )\n                            } else {\n                                Some(canvas::Action::capture())\n                            }\n                        }\n                    },\n                    _ => None,\n                },\n                _ => None,\n            }\n        }\n\n        fn draw(\n            &self,\n            _interaction: &Interaction,\n            renderer: &Renderer,\n            _theme: &Theme,\n            bounds: Rectangle,\n            cursor: mouse::Cursor,\n        ) -> Vec<Geometry> {\n            let center = Vector::new(bounds.width / 2.0, bounds.height / 2.0);\n\n            let life = self.life_cache.draw(renderer, bounds.size(), |frame| {\n                let background = Path::rectangle(Point::ORIGIN, frame.size());\n                frame.fill(&background, Color::from_rgb8(0x40, 0x44, 0x4B));\n\n                frame.with_save(|frame| {\n                    frame.translate(center);\n                    frame.scale(self.scaling);\n                    frame.translate(self.translation);\n                    frame.scale(Cell::SIZE);\n\n                    let region = self.visible_region(frame.size());\n\n                    for cell in region.cull(self.state.cells()) {\n                        frame.fill_rectangle(\n                            Point::new(cell.j as f32, cell.i as f32),\n                            Size::UNIT,\n                            Color::WHITE,\n                        );\n                    }\n                });\n            });\n\n            let overlay = {\n                let mut frame = Frame::new(renderer, bounds.size());\n\n                let hovered_cell = cursor\n                    .position_in(bounds)\n                    .map(|position| Cell::at(self.project(position, frame.size())));\n\n                if let Some(cell) = hovered_cell {\n                    frame.with_save(|frame| {\n                        frame.translate(center);\n                        frame.scale(self.scaling);\n                        frame.translate(self.translation);\n                        frame.scale(Cell::SIZE);\n\n                        frame.fill_rectangle(\n                            Point::new(cell.j as f32, cell.i as f32),\n                            Size::UNIT,\n                            Color {\n                                a: 0.5,\n                                ..Color::BLACK\n                            },\n                        );\n                    });\n                }\n\n                let text = Text {\n                    color: Color::WHITE,\n                    size: 14.0.into(),\n                    position: Point::new(frame.width(), frame.height()),\n                    align_x: text::Alignment::Right,\n                    align_y: alignment::Vertical::Bottom,\n                    ..Text::default()\n                };\n\n                if let Some(cell) = hovered_cell {\n                    frame.fill_text(Text {\n                        content: format!(\"({}, {})\", cell.j, cell.i),\n                        position: text.position - Vector::new(0.0, 16.0),\n                        ..text\n                    });\n                }\n\n                let cell_count = self.state.cell_count();\n\n                frame.fill_text(Text {\n                    content: format!(\n                        \"{cell_count} cell{} @ {:?} ({})\",\n                        if cell_count == 1 { \"\" } else { \"s\" },\n                        self.last_tick_duration,\n                        self.last_queued_ticks\n                    ),\n                    ..text\n                });\n\n                frame.into_geometry()\n            };\n\n            if self.scaling >= 0.2 && self.show_lines {\n                let grid = self.grid_cache.draw(renderer, bounds.size(), |frame| {\n                    frame.translate(center);\n                    frame.scale(self.scaling);\n                    frame.translate(self.translation);\n                    frame.scale(Cell::SIZE);\n\n                    let region = self.visible_region(frame.size());\n                    let rows = region.rows();\n                    let columns = region.columns();\n                    let (total_rows, total_columns) =\n                        (rows.clone().count(), columns.clone().count());\n                    let width = 2.0 / Cell::SIZE as f32;\n                    let color = Color::from_rgb8(70, 74, 83);\n\n                    frame.translate(Vector::new(-width / 2.0, -width / 2.0));\n\n                    for row in region.rows() {\n                        frame.fill_rectangle(\n                            Point::new(*columns.start() as f32, row as f32),\n                            Size::new(total_columns as f32, width),\n                            color,\n                        );\n                    }\n\n                    for column in region.columns() {\n                        frame.fill_rectangle(\n                            Point::new(column as f32, *rows.start() as f32),\n                            Size::new(width, total_rows as f32),\n                            color,\n                        );\n                    }\n                });\n\n                vec![life, grid, overlay]\n            } else {\n                vec![life, overlay]\n            }\n        }\n\n        fn mouse_interaction(\n            &self,\n            interaction: &Interaction,\n            bounds: Rectangle,\n            cursor: mouse::Cursor,\n        ) -> mouse::Interaction {\n            match interaction {\n                Interaction::Drawing => mouse::Interaction::Crosshair,\n                Interaction::Erasing => mouse::Interaction::Crosshair,\n                Interaction::Panning { .. } => mouse::Interaction::Grabbing,\n                Interaction::None if cursor.is_over(bounds) => mouse::Interaction::Crosshair,\n                Interaction::None => mouse::Interaction::default(),\n            }\n        }\n    }\n\n    #[derive(Default)]\n    struct State {\n        life: Life,\n        births: FxHashSet<Cell>,\n        is_ticking: bool,\n    }\n\n    impl State {\n        pub fn with_life(life: Life) -> Self {\n            Self {\n                life,\n                ..Self::default()\n            }\n        }\n\n        fn cell_count(&self) -> usize {\n            self.life.len() + self.births.len()\n        }\n\n        fn contains(&self, cell: &Cell) -> bool {\n            self.life.contains(cell) || self.births.contains(cell)\n        }\n\n        fn cells(&self) -> impl Iterator<Item = &Cell> {\n            self.life.iter().chain(self.births.iter())\n        }\n\n        fn populate(&mut self, cell: Cell) {\n            if self.is_ticking {\n                self.births.insert(cell);\n            } else {\n                self.life.populate(cell);\n            }\n        }\n\n        fn unpopulate(&mut self, cell: &Cell) {\n            if self.is_ticking {\n                let _ = self.births.remove(cell);\n            } else {\n                self.life.unpopulate(cell);\n            }\n        }\n\n        fn update(&mut self, mut life: Life) {\n            self.births.drain().for_each(|cell| life.populate(cell));\n\n            self.life = life;\n            self.is_ticking = false;\n        }\n\n        fn tick(\n            &mut self,\n            amount: usize,\n        ) -> Option<impl Future<Output = Result<Life, TickError>> + use<>> {\n            if self.is_ticking {\n                return None;\n            }\n\n            self.is_ticking = true;\n\n            let mut life = self.life.clone();\n\n            Some(async move {\n                tokio::task::spawn_blocking(move || {\n                    for _ in 0..amount {\n                        life.tick();\n                    }\n\n                    life\n                })\n                .await\n                .map_err(|_| TickError::JoinFailed)\n            })\n        }\n    }\n\n    #[derive(Clone, Default)]\n    pub struct Life {\n        cells: FxHashSet<Cell>,\n    }\n\n    impl Life {\n        fn len(&self) -> usize {\n            self.cells.len()\n        }\n\n        fn contains(&self, cell: &Cell) -> bool {\n            self.cells.contains(cell)\n        }\n\n        fn populate(&mut self, cell: Cell) {\n            self.cells.insert(cell);\n        }\n\n        fn unpopulate(&mut self, cell: &Cell) {\n            let _ = self.cells.remove(cell);\n        }\n\n        fn tick(&mut self) {\n            let mut adjacent_life = FxHashMap::default();\n\n            for cell in &self.cells {\n                let _ = adjacent_life.entry(*cell).or_insert(0);\n\n                for neighbor in Cell::neighbors(*cell) {\n                    let amount = adjacent_life.entry(neighbor).or_insert(0);\n\n                    *amount += 1;\n                }\n            }\n\n            for (cell, amount) in &adjacent_life {\n                match amount {\n                    2 => {}\n                    3 => {\n                        let _ = self.cells.insert(*cell);\n                    }\n                    _ => {\n                        let _ = self.cells.remove(cell);\n                    }\n                }\n            }\n        }\n\n        pub fn iter(&self) -> impl Iterator<Item = &Cell> {\n            self.cells.iter()\n        }\n    }\n\n    impl std::iter::FromIterator<Cell> for Life {\n        fn from_iter<I: IntoIterator<Item = Cell>>(iter: I) -> Self {\n            Life {\n                cells: iter.into_iter().collect(),\n            }\n        }\n    }\n\n    impl std::fmt::Debug for Life {\n        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n            f.debug_struct(\"Life\")\n                .field(\"cells\", &self.cells.len())\n                .finish()\n        }\n    }\n\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\n    pub struct Cell {\n        i: isize,\n        j: isize,\n    }\n\n    impl Cell {\n        const SIZE: u16 = 20;\n\n        fn at(position: Point) -> Cell {\n            let i = (position.y / Cell::SIZE as f32).ceil() as isize;\n            let j = (position.x / Cell::SIZE as f32).ceil() as isize;\n\n            Cell {\n                i: i.saturating_sub(1),\n                j: j.saturating_sub(1),\n            }\n        }\n\n        fn cluster(cell: Cell) -> impl Iterator<Item = Cell> {\n            use itertools::Itertools;\n\n            let rows = cell.i.saturating_sub(1)..=cell.i.saturating_add(1);\n            let columns = cell.j.saturating_sub(1)..=cell.j.saturating_add(1);\n\n            rows.cartesian_product(columns).map(|(i, j)| Cell { i, j })\n        }\n\n        fn neighbors(cell: Cell) -> impl Iterator<Item = Cell> {\n            Cell::cluster(cell).filter(move |candidate| *candidate != cell)\n        }\n    }\n\n    pub struct Region {\n        x: f32,\n        y: f32,\n        width: f32,\n        height: f32,\n    }\n\n    impl Region {\n        fn rows(&self) -> RangeInclusive<isize> {\n            let first_row = (self.y / Cell::SIZE as f32).floor() as isize;\n\n            let visible_rows = (self.height / Cell::SIZE as f32).ceil() as isize;\n\n            first_row..=first_row + visible_rows\n        }\n\n        fn columns(&self) -> RangeInclusive<isize> {\n            let first_column = (self.x / Cell::SIZE as f32).floor() as isize;\n\n            let visible_columns = (self.width / Cell::SIZE as f32).ceil() as isize;\n\n            first_column..=first_column + visible_columns\n        }\n\n        fn cull<'a>(\n            &self,\n            cells: impl Iterator<Item = &'a Cell>,\n        ) -> impl Iterator<Item = &'a Cell> {\n            let rows = self.rows();\n            let columns = self.columns();\n\n            cells.filter(move |cell| rows.contains(&cell.i) && columns.contains(&cell.j))\n        }\n    }\n\n    #[derive(Default)]\n    pub enum Interaction {\n        #[default]\n        None,\n        Drawing,\n        Erasing,\n        Panning {\n            translation: Vector,\n            start: Point,\n        },\n    }\n}\n"
  },
  {
    "path": "examples/game_of_life/src/preset.rs",
    "content": "#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]\npub enum Preset {\n    Custom,\n    #[default]\n    Xkcd,\n    Glider,\n    SmallExploder,\n    Exploder,\n    TenCellRow,\n    LightweightSpaceship,\n    Tumbler,\n    GliderGun,\n    Acorn,\n}\n\npub static ALL: &[Preset] = &[\n    Preset::Custom,\n    Preset::Xkcd,\n    Preset::Glider,\n    Preset::SmallExploder,\n    Preset::Exploder,\n    Preset::TenCellRow,\n    Preset::LightweightSpaceship,\n    Preset::Tumbler,\n    Preset::GliderGun,\n    Preset::Acorn,\n];\n\nimpl Preset {\n    pub fn life(self) -> Vec<(isize, isize)> {\n        #[rustfmt::skip]\n        let cells = match self {\n            Preset::Custom => vec![],\n            Preset::Xkcd => vec![\n                \"  xxx  \",\n                \"  x x  \",\n                \"  x x  \",\n                \"   x   \",\n                \"x xxx  \",\n                \" x x x \",\n                \"   x  x\",\n                \"  x x  \",\n                \"  x x  \",\n            ],\n            Preset::Glider => vec![\n                \" x \",\n                \"  x\",\n                \"xxx\"\n            ],\n            Preset::SmallExploder => vec![\n                \" x \",\n                \"xxx\",\n                \"x x\",\n                \" x \",\n            ],\n            Preset::Exploder => vec![\n                \"x x x\",\n                \"x   x\",\n                \"x   x\",\n                \"x   x\",\n                \"x x x\",\n            ],\n            Preset::TenCellRow => vec![\n                \"xxxxxxxxxx\",\n            ],\n            Preset::LightweightSpaceship => vec![\n                \" xxxxx\",\n                \"x    x\",\n                \"     x\",\n                \"x   x \",\n            ],\n            Preset::Tumbler => vec![\n                \" xx xx \",\n                \" xx xx \",\n                \"  x x  \",\n                \"x x x x\",\n                \"x x x x\",\n                \"xx   xx\",\n            ],\n            Preset::GliderGun => vec![\n                \"                        x           \",\n                \"                      x x           \",\n                \"            xx      xx            xx\",\n                \"           x   x    xx            xx\",\n                \"xx        x     x   xx              \",\n                \"xx        x   x xx    x x           \",\n                \"          x     x       x           \",\n                \"           x   x                    \",\n                \"            xx                      \",\n            ],\n            Preset::Acorn => vec![\n                \" x     \",\n                \"   x   \",\n                \"xx  xxx\",\n            ],\n        };\n\n        let start_row = -(cells.len() as isize / 2);\n\n        cells\n            .into_iter()\n            .enumerate()\n            .flat_map(|(i, cells)| {\n                let start_column = -(cells.len() as isize / 2);\n\n                cells\n                    .chars()\n                    .enumerate()\n                    .filter(|(_, c)| !c.is_whitespace())\n                    .map(move |(j, _)| (start_row + i as isize, start_column + j as isize))\n            })\n            .collect()\n    }\n}\n\nimpl std::fmt::Display for Preset {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"{}\",\n            match self {\n                Preset::Custom => \"Custom\",\n                Preset::Xkcd => \"xkcd #2293\",\n                Preset::Glider => \"Glider\",\n                Preset::SmallExploder => \"Small Exploder\",\n                Preset::Exploder => \"Exploder\",\n                Preset::TenCellRow => \"10 Cell Row\",\n                Preset::LightweightSpaceship => \"Lightweight spaceship\",\n                Preset::Tumbler => \"Tumbler\",\n                Preset::GliderGun => \"Gosper Glider Gun\",\n                Preset::Acorn => \"Acorn\",\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "examples/geometry/Cargo.toml",
    "content": "[package]\nname = \"geometry\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"advanced\"]\n"
  },
  {
    "path": "examples/geometry/README.md",
    "content": "## Geometry\n\nA custom widget showcasing how to draw geometry with the `Mesh2D` primitive in [`iced_wgpu`](../../wgpu).\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/geometry.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package geometry\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/geometry/src/main.rs",
    "content": "//! This example showcases a simple native custom widget that renders using\n//! arbitrary low-level geometry.\nmod rainbow {\n    use iced::advanced::Shell;\n    use iced::advanced::graphics::color;\n    use iced::advanced::layout::{self, Layout};\n    use iced::advanced::renderer;\n    use iced::advanced::widget::{self, Widget};\n    use iced::mouse;\n    use iced::{Element, Event, Length, Rectangle, Renderer, Size, Theme, Transformation, Vector};\n\n    #[derive(Debug, Clone, Copy, Default)]\n    pub struct Rainbow;\n\n    pub fn rainbow() -> Rainbow {\n        Rainbow\n    }\n\n    impl<Message> Widget<Message, Theme, Renderer> for Rainbow {\n        fn size(&self) -> Size<Length> {\n            Size {\n                width: Length::Fill,\n                height: Length::Shrink,\n            }\n        }\n\n        fn layout(\n            &mut self,\n            _tree: &mut widget::Tree,\n            _renderer: &Renderer,\n            limits: &layout::Limits,\n        ) -> layout::Node {\n            let width = limits.max().width;\n\n            layout::Node::new(Size::new(width, width))\n        }\n\n        fn update(\n            &mut self,\n            _state: &mut widget::Tree,\n            _event: &Event,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            _renderer: &Renderer,\n            shell: &mut Shell<'_, Message>,\n            _viewport: &Rectangle,\n        ) {\n            if cursor.is_over(layout.bounds()) {\n                shell.request_redraw();\n            }\n        }\n\n        fn draw(\n            &self,\n            _tree: &widget::Tree,\n            renderer: &mut Renderer,\n            _theme: &Theme,\n            _style: &renderer::Style,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            _viewport: &Rectangle,\n        ) {\n            use iced::advanced::Renderer as _;\n            use iced::advanced::graphics::mesh::{self, Mesh, Renderer as _, SolidVertex2D};\n\n            let bounds = layout.bounds();\n\n            // R O Y G B I V\n            let color_r = [1.0, 0.0, 0.0, 1.0];\n            let color_o = [1.0, 0.5, 0.0, 1.0];\n            let color_y = [1.0, 1.0, 0.0, 1.0];\n            let color_g = [0.0, 1.0, 0.0, 1.0];\n            let color_gb = [0.0, 1.0, 0.5, 1.0];\n            let color_b = [0.0, 0.2, 1.0, 1.0];\n            let color_i = [0.5, 0.0, 1.0, 1.0];\n            let color_v = [0.75, 0.0, 0.5, 1.0];\n\n            let posn_center = {\n                if let Some(cursor_position) = cursor.position_in(bounds) {\n                    [cursor_position.x, cursor_position.y]\n                } else {\n                    [bounds.width / 2.0, bounds.height / 2.0]\n                }\n            };\n\n            let posn_tl = [0.0, 0.0];\n            let posn_t = [bounds.width / 2.0, 0.0];\n            let posn_tr = [bounds.width, 0.0];\n            let posn_r = [bounds.width, bounds.height / 2.0];\n            let posn_br = [bounds.width, bounds.height];\n            let posn_b = [(bounds.width / 2.0), bounds.height];\n            let posn_bl = [0.0, bounds.height];\n            let posn_l = [0.0, bounds.height / 2.0];\n\n            let mesh = Mesh::Solid {\n                buffers: mesh::Indexed {\n                    vertices: vec![\n                        SolidVertex2D {\n                            position: posn_center,\n                            color: color::pack([1.0, 1.0, 1.0, 1.0]),\n                        },\n                        SolidVertex2D {\n                            position: posn_tl,\n                            color: color::pack(color_r),\n                        },\n                        SolidVertex2D {\n                            position: posn_t,\n                            color: color::pack(color_o),\n                        },\n                        SolidVertex2D {\n                            position: posn_tr,\n                            color: color::pack(color_y),\n                        },\n                        SolidVertex2D {\n                            position: posn_r,\n                            color: color::pack(color_g),\n                        },\n                        SolidVertex2D {\n                            position: posn_br,\n                            color: color::pack(color_gb),\n                        },\n                        SolidVertex2D {\n                            position: posn_b,\n                            color: color::pack(color_b),\n                        },\n                        SolidVertex2D {\n                            position: posn_bl,\n                            color: color::pack(color_i),\n                        },\n                        SolidVertex2D {\n                            position: posn_l,\n                            color: color::pack(color_v),\n                        },\n                    ],\n                    indices: vec![\n                        0, 1, 2, // TL\n                        0, 2, 3, // T\n                        0, 3, 4, // TR\n                        0, 4, 5, // R\n                        0, 5, 6, // BR\n                        0, 6, 7, // B\n                        0, 7, 8, // BL\n                        0, 8, 1, // L\n                    ],\n                },\n                transformation: Transformation::IDENTITY,\n                clip_bounds: Rectangle::INFINITE,\n            };\n\n            renderer.with_translation(Vector::new(bounds.x, bounds.y), |renderer| {\n                renderer.draw_mesh(mesh);\n            });\n        }\n    }\n\n    impl<Message> From<Rainbow> for Element<'_, Message> {\n        fn from(rainbow: Rainbow) -> Self {\n            Self::new(rainbow)\n        }\n    }\n}\n\nuse iced::widget::{center_x, center_y, column, scrollable};\nuse iced::{Element, Never};\nuse rainbow::rainbow;\n\npub fn main() -> iced::Result {\n    iced::run((), view)\n}\n\nfn view(_state: &()) -> Element<'_, Never> {\n    let content = column![\n        rainbow(),\n        \"In this example we draw a custom widget Rainbow, using \\\n                 the Mesh2D primitive. This primitive supplies a list of \\\n                 triangles, expressed as vertices and indices.\",\n        \"Move your cursor over it, and see the center vertex \\\n                 follow you!\",\n        \"Every Vertex2D defines its own color. You could use the \\\n                 Mesh2D primitive to render virtually any two-dimensional \\\n                 geometry for your widget.\",\n    ]\n    .padding(20)\n    .spacing(20)\n    .max_width(500);\n\n    let scrollable = scrollable(center_x(content));\n\n    center_y(scrollable).into()\n}\n"
  },
  {
    "path": "examples/gradient/Cargo.toml",
    "content": "[package]\nname = \"gradient\"\nversion = \"0.1.0\"\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\"]\n\ntracing-subscriber = \"0.3\"\n"
  },
  {
    "path": "examples/gradient/src/main.rs",
    "content": "use iced::gradient;\nuse iced::theme;\nuse iced::widget::{checkbox, column, container, row, slider, space, text};\nuse iced::{Center, Color, Element, Fill, Radians, Theme, color};\n\npub fn main() -> iced::Result {\n    tracing_subscriber::fmt::init();\n\n    iced::application(Gradient::default, Gradient::update, Gradient::view)\n        .style(Gradient::style)\n        .transparent(true)\n        .run()\n}\n\n#[derive(Debug, Clone, Copy)]\nstruct Gradient {\n    start: Color,\n    end: Color,\n    angle: Radians,\n    transparent: bool,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    StartChanged(Color),\n    EndChanged(Color),\n    AngleChanged(Radians),\n    TransparentToggled(bool),\n}\n\nimpl Gradient {\n    fn new() -> Self {\n        Self {\n            start: Color::WHITE,\n            end: color!(0x0000ff),\n            angle: Radians(0.0),\n            transparent: false,\n        }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::StartChanged(color) => self.start = color,\n            Message::EndChanged(color) => self.end = color,\n            Message::AngleChanged(angle) => self.angle = angle,\n            Message::TransparentToggled(transparent) => {\n                self.transparent = transparent;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let Self {\n            start,\n            end,\n            angle,\n            transparent,\n        } = *self;\n\n        let gradient_box = container(space())\n            .style(move |_theme| {\n                let gradient = gradient::Linear::new(angle)\n                    .add_stop(0.0, start)\n                    .add_stop(1.0, end);\n\n                gradient.into()\n            })\n            .width(Fill)\n            .height(Fill);\n\n        let angle_picker = row![\n            text(\"Angle\").width(64),\n            slider(Radians::RANGE, self.angle, Message::AngleChanged).step(0.01)\n        ]\n        .spacing(8)\n        .padding(8)\n        .align_y(Center);\n\n        let transparency_toggle = iced::widget::Container::new(\n            checkbox(transparent)\n                .label(\"Transparent window\")\n                .on_toggle(Message::TransparentToggled),\n        )\n        .padding(8);\n\n        column![\n            color_picker(\"Start\", self.start).map(Message::StartChanged),\n            color_picker(\"End\", self.end).map(Message::EndChanged),\n            angle_picker,\n            transparency_toggle,\n            gradient_box,\n        ]\n        .into()\n    }\n\n    fn style(&self, theme: &Theme) -> theme::Style {\n        if self.transparent {\n            theme::Style {\n                background_color: Color::TRANSPARENT,\n                text_color: theme.seed().text,\n            }\n        } else {\n            theme::default(theme)\n        }\n    }\n}\n\nimpl Default for Gradient {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nfn color_picker(label: &str, color: Color) -> Element<'_, Color> {\n    row![\n        text(label).width(64),\n        slider(0.0..=1.0, color.r, move |r| { Color { r, ..color } }).step(0.01),\n        slider(0.0..=1.0, color.g, move |g| { Color { g, ..color } }).step(0.01),\n        slider(0.0..=1.0, color.b, move |b| { Color { b, ..color } }).step(0.01),\n        slider(0.0..=1.0, color.a, move |a| { Color { a, ..color } }).step(0.01),\n    ]\n    .spacing(8)\n    .padding(8)\n    .align_y(Center)\n    .into()\n}\n"
  },
  {
    "path": "examples/integration/.gitignore",
    "content": "*.wasm\n*.js\n"
  },
  {
    "path": "examples/integration/Cargo.toml",
    "content": "[package]\nname = \"integration\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced_winit.workspace = true\n\niced_wgpu.workspace = true\niced_wgpu.default-features = true\n\niced_widget.workspace = true\niced_widget.features = [\"wgpu\"]\n\nfutures.workspace = true\nfutures.features = [\"thread-pool\"]\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\ntracing-subscriber = \"0.3\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\niced_wgpu.workspace = true\niced_wgpu.features = [\"webgl\"]\n\nconsole_error_panic_hook = \"0.1\"\nconsole_log = \"1.0\"\nwasm-bindgen = \"0.2\"\nweb-sys = { version = \"0.3\", features = [\"Element\", \"HtmlCanvasElement\", \"Window\", \"Document\"] }\n"
  },
  {
    "path": "examples/integration/README.md",
    "content": "## `wgpu` integration\n\nA demonstration of how to integrate Iced in an existing [`wgpu`] application.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/integration.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package integration\n```\n\n[`main`]: src/main.rs\n[`wgpu`]: https://github.com/gfx-rs/wgpu\n"
  },
  {
    "path": "examples/integration/src/controls.rs",
    "content": "use iced_wgpu::Renderer;\nuse iced_widget::{bottom, column, row, slider, text, text_input};\nuse iced_winit::core::{Color, Element, Theme};\n\npub struct Controls {\n    background_color: Color,\n    input: String,\n}\n\n#[derive(Debug, Clone)]\npub enum Message {\n    BackgroundColorChanged(Color),\n    InputChanged(String),\n}\n\nimpl Controls {\n    pub fn new() -> Controls {\n        Controls {\n            background_color: Color::BLACK,\n            input: String::default(),\n        }\n    }\n\n    pub fn background_color(&self) -> Color {\n        self.background_color\n    }\n}\n\nimpl Controls {\n    pub fn update(&mut self, message: Message) {\n        match message {\n            Message::BackgroundColorChanged(color) => {\n                self.background_color = color;\n            }\n            Message::InputChanged(input) => {\n                self.input = input;\n            }\n        }\n    }\n\n    pub fn view(&self) -> Element<'_, Message, Theme, Renderer> {\n        let background_color = self.background_color;\n\n        let sliders = row![\n            slider(0.0..=1.0, background_color.r, move |r| {\n                Message::BackgroundColorChanged(Color {\n                    r,\n                    ..background_color\n                })\n            })\n            .step(0.01),\n            slider(0.0..=1.0, background_color.g, move |g| {\n                Message::BackgroundColorChanged(Color {\n                    g,\n                    ..background_color\n                })\n            })\n            .step(0.01),\n            slider(0.0..=1.0, background_color.b, move |b| {\n                Message::BackgroundColorChanged(Color {\n                    b,\n                    ..background_color\n                })\n            })\n            .step(0.01),\n        ]\n        .width(500)\n        .spacing(20);\n\n        bottom(\n            column![\n                text(\"Background color\").color(Color::WHITE),\n                text!(\"{background_color:?}\").size(14).color(Color::WHITE),\n                sliders,\n                text_input(\"Type something...\", &self.input).on_input(Message::InputChanged),\n            ]\n            .spacing(10),\n        )\n        .padding(10)\n        .into()\n    }\n}\n"
  },
  {
    "path": "examples/integration/src/main.rs",
    "content": "mod controls;\nmod scene;\n\nuse controls::Controls;\nuse scene::Scene;\n\nuse iced_wgpu::graphics::{Shell, Viewport};\nuse iced_wgpu::{Engine, Renderer, wgpu};\nuse iced_winit::conversion;\nuse iced_winit::core::mouse;\nuse iced_winit::core::renderer;\nuse iced_winit::core::time::Instant;\nuse iced_winit::core::window;\nuse iced_winit::core::{Event, Size, Theme};\nuse iced_winit::futures;\nuse iced_winit::runtime::user_interface::{self, UserInterface};\nuse iced_winit::winit;\n\nuse winit::{\n    event::WindowEvent,\n    event_loop::{ControlFlow, EventLoop},\n    keyboard::ModifiersState,\n};\n\nuse std::sync::Arc;\n\npub fn main() -> Result<(), winit::error::EventLoopError> {\n    tracing_subscriber::fmt::init();\n\n    // Initialize winit\n    let event_loop = EventLoop::new()?;\n\n    #[allow(clippy::large_enum_variant)]\n    enum Runner {\n        Loading,\n        Ready {\n            window: Arc<winit::window::Window>,\n            queue: wgpu::Queue,\n            device: wgpu::Device,\n            surface: wgpu::Surface<'static>,\n            format: wgpu::TextureFormat,\n            renderer: Renderer,\n            scene: Scene,\n            controls: Controls,\n            events: Vec<Event>,\n            cursor: mouse::Cursor,\n            cache: user_interface::Cache,\n            viewport: Viewport,\n            modifiers: ModifiersState,\n            resized: bool,\n        },\n    }\n\n    impl winit::application::ApplicationHandler for Runner {\n        fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {\n            if let Self::Loading = self {\n                let window = Arc::new(\n                    event_loop\n                        .create_window(winit::window::WindowAttributes::default())\n                        .expect(\"Create window\"),\n                );\n\n                let physical_size = window.inner_size();\n                let viewport = Viewport::with_physical_size(\n                    Size::new(physical_size.width, physical_size.height),\n                    window.scale_factor() as f32,\n                );\n\n                let backend = wgpu::Backends::from_env().unwrap_or_default();\n\n                let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {\n                    backends: backend,\n                    ..Default::default()\n                });\n                let surface = instance\n                    .create_surface(window.clone())\n                    .expect(\"Create window surface\");\n\n                let (format, adapter, device, queue) =\n                    futures::futures::executor::block_on(async {\n                        let adapter = wgpu::util::initialize_adapter_from_env_or_default(\n                            &instance,\n                            Some(&surface),\n                        )\n                        .await\n                        .expect(\"Create adapter\");\n\n                        let adapter_features = adapter.features();\n\n                        let capabilities = surface.get_capabilities(&adapter);\n\n                        let (device, queue) = adapter\n                            .request_device(&wgpu::DeviceDescriptor {\n                                label: None,\n                                required_features: adapter_features & wgpu::Features::default(),\n                                required_limits: wgpu::Limits::default(),\n                                memory_hints: wgpu::MemoryHints::MemoryUsage,\n                                trace: wgpu::Trace::Off,\n                                experimental_features: wgpu::ExperimentalFeatures::disabled(),\n                            })\n                            .await\n                            .expect(\"Request device\");\n\n                        (\n                            capabilities\n                                .formats\n                                .iter()\n                                .copied()\n                                .find(wgpu::TextureFormat::is_srgb)\n                                .or_else(|| capabilities.formats.first().copied())\n                                .expect(\"Get preferred format\"),\n                            adapter,\n                            device,\n                            queue,\n                        )\n                    });\n\n                surface.configure(\n                    &device,\n                    &wgpu::SurfaceConfiguration {\n                        usage: wgpu::TextureUsages::RENDER_ATTACHMENT,\n                        format,\n                        width: physical_size.width,\n                        height: physical_size.height,\n                        present_mode: wgpu::PresentMode::AutoVsync,\n                        alpha_mode: wgpu::CompositeAlphaMode::Auto,\n                        view_formats: vec![],\n                        desired_maximum_frame_latency: 2,\n                    },\n                );\n\n                // Initialize scene and GUI controls\n                let scene = Scene::new(&device, format);\n                let controls = Controls::new();\n\n                // Initialize iced\n\n                let renderer = {\n                    let engine = Engine::new(\n                        &adapter,\n                        device.clone(),\n                        queue.clone(),\n                        format,\n                        None,\n                        Shell::headless(),\n                    );\n\n                    Renderer::new(engine, renderer::Settings::default())\n                };\n\n                // You should change this if you want to render continuously\n                event_loop.set_control_flow(ControlFlow::Wait);\n\n                *self = Self::Ready {\n                    window,\n                    device,\n                    queue,\n                    renderer,\n                    surface,\n                    format,\n                    scene,\n                    controls,\n                    events: Vec::new(),\n                    cursor: mouse::Cursor::Unavailable,\n                    modifiers: ModifiersState::default(),\n                    cache: user_interface::Cache::new(),\n                    viewport,\n                    resized: false,\n                };\n            }\n        }\n\n        fn window_event(\n            &mut self,\n            event_loop: &winit::event_loop::ActiveEventLoop,\n            _window_id: winit::window::WindowId,\n            event: WindowEvent,\n        ) {\n            let Self::Ready {\n                window,\n                device,\n                queue,\n                surface,\n                format,\n                renderer,\n                scene,\n                controls,\n                events,\n                viewport,\n                cursor,\n                modifiers,\n                cache,\n                resized,\n            } = self\n            else {\n                return;\n            };\n\n            match event {\n                WindowEvent::RedrawRequested => {\n                    if *resized {\n                        let size = window.inner_size();\n\n                        *viewport = Viewport::with_physical_size(\n                            Size::new(size.width, size.height),\n                            window.scale_factor() as f32,\n                        );\n\n                        surface.configure(\n                            device,\n                            &wgpu::SurfaceConfiguration {\n                                format: *format,\n                                usage: wgpu::TextureUsages::RENDER_ATTACHMENT,\n                                width: size.width,\n                                height: size.height,\n                                present_mode: wgpu::PresentMode::AutoVsync,\n                                alpha_mode: wgpu::CompositeAlphaMode::Auto,\n                                view_formats: vec![],\n                                desired_maximum_frame_latency: 2,\n                            },\n                        );\n\n                        *resized = false;\n                    }\n\n                    match surface.get_current_texture() {\n                        Ok(frame) => {\n                            let view = frame\n                                .texture\n                                .create_view(&wgpu::TextureViewDescriptor::default());\n\n                            let mut encoder =\n                                device.create_command_encoder(&wgpu::CommandEncoderDescriptor {\n                                    label: None,\n                                });\n\n                            {\n                                // Clear the frame\n                                let mut render_pass =\n                                    Scene::clear(&view, &mut encoder, controls.background_color());\n\n                                // Draw the scene\n                                scene.draw(&mut render_pass);\n                            }\n\n                            // Submit the scene\n                            queue.submit([encoder.finish()]);\n\n                            // Draw iced on top\n                            let mut interface = UserInterface::build(\n                                controls.view(),\n                                viewport.logical_size(),\n                                std::mem::take(cache),\n                                renderer,\n                            );\n\n                            let (state, _) = interface.update(\n                                &[Event::Window(\n                                    window::Event::RedrawRequested(Instant::now()),\n                                )],\n                                *cursor,\n                                renderer,\n                                &mut Vec::new(),\n                            );\n\n                            // Update the mouse cursor\n                            if let user_interface::State::Updated {\n                                mouse_interaction, ..\n                            } = state\n                            {\n                                // Update the mouse cursor\n                                if let Some(icon) =\n                                    iced_winit::conversion::mouse_interaction(mouse_interaction)\n                                {\n                                    window.set_cursor(icon);\n                                    window.set_cursor_visible(true);\n                                } else {\n                                    window.set_cursor_visible(false);\n                                }\n                            }\n\n                            // Draw the interface\n                            interface.draw(\n                                renderer,\n                                &Theme::Dark,\n                                &renderer::Style::default(),\n                                *cursor,\n                            );\n                            *cache = interface.into_cache();\n\n                            renderer.present(None, frame.texture.format(), &view, viewport);\n\n                            // Present the frame\n                            frame.present();\n                        }\n                        Err(error) => match error {\n                            wgpu::SurfaceError::OutOfMemory => {\n                                panic!(\n                                    \"Swapchain error: {error}. \\\n                                        Rendering cannot continue.\"\n                                )\n                            }\n                            _ => {\n                                // Try rendering again next frame.\n                                window.request_redraw();\n                            }\n                        },\n                    }\n                }\n                WindowEvent::CursorMoved { position, .. } => {\n                    *cursor = mouse::Cursor::Available(conversion::cursor_position(\n                        position,\n                        viewport.scale_factor(),\n                    ));\n                }\n                WindowEvent::ModifiersChanged(new_modifiers) => {\n                    *modifiers = new_modifiers.state();\n                }\n                WindowEvent::Resized(_) => {\n                    *resized = true;\n                }\n                WindowEvent::CloseRequested => {\n                    event_loop.exit();\n                }\n                _ => {}\n            }\n\n            // Map window event to iced event\n            if let Some(event) =\n                conversion::window_event(event, window.scale_factor() as f32, *modifiers)\n            {\n                events.push(event);\n            }\n\n            // If there are events pending\n            if !events.is_empty() {\n                // We process them\n                let mut interface = UserInterface::build(\n                    controls.view(),\n                    viewport.logical_size(),\n                    std::mem::take(cache),\n                    renderer,\n                );\n\n                let mut messages = Vec::new();\n\n                let _ = interface.update(events, *cursor, renderer, &mut messages);\n\n                events.clear();\n                *cache = interface.into_cache();\n\n                // update our UI with any messages\n                for message in messages {\n                    controls.update(message);\n                }\n\n                // and request a redraw\n                window.request_redraw();\n            }\n        }\n    }\n\n    let mut runner = Runner::Loading;\n    event_loop.run_app(&mut runner)\n}\n"
  },
  {
    "path": "examples/integration/src/scene.rs",
    "content": "use iced_wgpu::wgpu;\nuse iced_winit::core::Color;\n\npub struct Scene {\n    pipeline: wgpu::RenderPipeline,\n}\n\nimpl Scene {\n    pub fn new(device: &wgpu::Device, texture_format: wgpu::TextureFormat) -> Scene {\n        let pipeline = build_pipeline(device, texture_format);\n\n        Scene { pipeline }\n    }\n\n    pub fn clear<'a>(\n        target: &'a wgpu::TextureView,\n        encoder: &'a mut wgpu::CommandEncoder,\n        background_color: Color,\n    ) -> wgpu::RenderPass<'a> {\n        encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n            label: None,\n            color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                view: target,\n                depth_slice: None,\n                resolve_target: None,\n                ops: wgpu::Operations {\n                    load: wgpu::LoadOp::Clear({\n                        let [r, g, b, a] = background_color.into_linear();\n\n                        wgpu::Color {\n                            r: r as f64,\n                            g: g as f64,\n                            b: b as f64,\n                            a: a as f64,\n                        }\n                    }),\n                    store: wgpu::StoreOp::Store,\n                },\n            })],\n            depth_stencil_attachment: None,\n            timestamp_writes: None,\n            occlusion_query_set: None,\n            multiview_mask: None,\n        })\n    }\n\n    pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {\n        render_pass.set_pipeline(&self.pipeline);\n        render_pass.draw(0..3, 0..1);\n    }\n}\n\nfn build_pipeline(\n    device: &wgpu::Device,\n    texture_format: wgpu::TextureFormat,\n) -> wgpu::RenderPipeline {\n    let (vs_module, fs_module) = (\n        device.create_shader_module(wgpu::include_wgsl!(\"shader/vert.wgsl\")),\n        device.create_shader_module(wgpu::include_wgsl!(\"shader/frag.wgsl\")),\n    );\n\n    let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n        label: None,\n        bind_group_layouts: &[],\n        immediate_size: 0,\n    });\n\n    device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n        label: None,\n        layout: Some(&pipeline_layout),\n        vertex: wgpu::VertexState {\n            module: &vs_module,\n            entry_point: Some(\"main\"),\n            buffers: &[],\n            compilation_options: wgpu::PipelineCompilationOptions::default(),\n        },\n        fragment: Some(wgpu::FragmentState {\n            module: &fs_module,\n            entry_point: Some(\"main\"),\n            targets: &[Some(wgpu::ColorTargetState {\n                format: texture_format,\n                blend: Some(wgpu::BlendState {\n                    color: wgpu::BlendComponent::REPLACE,\n                    alpha: wgpu::BlendComponent::REPLACE,\n                }),\n                write_mask: wgpu::ColorWrites::ALL,\n            })],\n            compilation_options: wgpu::PipelineCompilationOptions::default(),\n        }),\n        primitive: wgpu::PrimitiveState {\n            topology: wgpu::PrimitiveTopology::TriangleList,\n            front_face: wgpu::FrontFace::Ccw,\n            ..Default::default()\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"
  },
  {
    "path": "examples/integration/src/shader/frag.wgsl",
    "content": "@fragment\nfn main() -> @location(0) vec4<f32> {\n    return vec4<f32>(1.0, 0.0, 0.0, 1.0);\n}\n"
  },
  {
    "path": "examples/integration/src/shader/vert.wgsl",
    "content": "@vertex\nfn main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {\n    let x = f32(1 - i32(in_vertex_index)) * 0.5;\n    let y = f32(1 - i32(in_vertex_index & 1u) * 2) * 0.5;\n    return vec4<f32>(x, y, 0.0, 1.0);\n}\n"
  },
  {
    "path": "examples/layout/Cargo.toml",
    "content": "[package]\nname = \"layout\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced = { path = \"../..\", features = [\"canvas\", \"debug\"] }\n"
  },
  {
    "path": "examples/layout/src/main.rs",
    "content": "use iced::border;\nuse iced::keyboard;\nuse iced::mouse;\nuse iced::widget::{\n    button, canvas, center, center_y, checkbox, column, container, pick_list, pin, responsive, row,\n    rule, scrollable, space, stack, text,\n};\nuse iced::{\n    Center, Element, Fill, Font, Length, Point, Rectangle, Renderer, Shrink, Subscription, Theme,\n    color,\n};\n\npub fn main() -> iced::Result {\n    iced::application(Layout::default, Layout::update, Layout::view)\n        .subscription(Layout::subscription)\n        .theme(Layout::theme)\n        .title(Layout::title)\n        .run()\n}\n\n#[derive(Debug, Default)]\nstruct Layout {\n    example: Example,\n    explain: bool,\n    theme: Option<Theme>,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    Next,\n    Previous,\n    ExplainToggled(bool),\n    ThemeSelected(Theme),\n}\n\nimpl Layout {\n    fn title(&self) -> String {\n        format!(\"{} - Layout - Iced\", self.example.title)\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Next => {\n                self.example = self.example.next();\n            }\n            Message::Previous => {\n                self.example = self.example.previous();\n            }\n            Message::ExplainToggled(explain) => {\n                self.explain = explain;\n            }\n            Message::ThemeSelected(theme) => {\n                self.theme = Some(theme);\n            }\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        use keyboard::key;\n\n        keyboard::listen().filter_map(|event| {\n            let keyboard::Event::KeyPressed {\n                modified_key,\n                repeat: false,\n                ..\n            } = event\n            else {\n                return None;\n            };\n\n            match modified_key {\n                keyboard::Key::Named(key::Named::ArrowLeft) => Some(Message::Previous),\n                keyboard::Key::Named(key::Named::ArrowRight) => Some(Message::Next),\n                _ => None,\n            }\n        })\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let header = row![\n            text(self.example.title).size(20).font(Font::MONOSPACE),\n            space::horizontal(),\n            checkbox(self.explain)\n                .label(\"Explain\")\n                .on_toggle(Message::ExplainToggled),\n            pick_list(self.theme.as_ref(), Theme::ALL, Theme::to_string)\n                .on_select(Message::ThemeSelected)\n                .placeholder(\"Theme\"),\n        ]\n        .spacing(20)\n        .align_y(Center);\n\n        let example = center(if self.explain {\n            self.example.view().explain(color!(0x0000ff))\n        } else {\n            self.example.view()\n        })\n        .style(|theme| {\n            let palette = theme.palette();\n\n            container::Style::default()\n                .border(border::color(palette.background.strong.color).width(4))\n        })\n        .padding(4);\n\n        let controls = row![\n            (!self.example.is_first()).then_some(\n                button(text(\"← Previous\"))\n                    .padding([5, 10])\n                    .on_press(Message::Previous)\n            ),\n            space::horizontal(),\n            (!self.example.is_last()).then_some(\n                button(text(\"Next →\"))\n                    .padding([5, 10])\n                    .on_press(Message::Next)\n            ),\n        ];\n\n        column![header, example, controls]\n            .spacing(10)\n            .padding(20)\n            .into()\n    }\n\n    fn theme(&self) -> Option<Theme> {\n        self.theme.clone()\n    }\n}\n\n#[derive(Debug, Clone, Copy, Eq)]\nstruct Example {\n    title: &'static str,\n    view: fn() -> Element<'static, Message>,\n}\n\nimpl Example {\n    const LIST: &'static [Self] = &[\n        Self {\n            title: \"Centered\",\n            view: centered,\n        },\n        Self {\n            title: \"Column\",\n            view: column_,\n        },\n        Self {\n            title: \"Row\",\n            view: row_,\n        },\n        Self {\n            title: \"Space\",\n            view: space_,\n        },\n        Self {\n            title: \"Application\",\n            view: application,\n        },\n        Self {\n            title: \"Quotes\",\n            view: quotes,\n        },\n        Self {\n            title: \"Pinning\",\n            view: pinning,\n        },\n        Self {\n            title: \"Responsive\",\n            view: responsive_,\n        },\n    ];\n\n    fn is_first(self) -> bool {\n        Self::LIST.first() == Some(&self)\n    }\n\n    fn is_last(self) -> bool {\n        Self::LIST.last() == Some(&self)\n    }\n\n    fn previous(self) -> Self {\n        let Some(index) = Self::LIST.iter().position(|&example| example == self) else {\n            return self;\n        };\n\n        Self::LIST\n            .get(index.saturating_sub(1))\n            .copied()\n            .unwrap_or(self)\n    }\n\n    fn next(self) -> Self {\n        let Some(index) = Self::LIST.iter().position(|&example| example == self) else {\n            return self;\n        };\n\n        Self::LIST.get(index + 1).copied().unwrap_or(self)\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        (self.view)()\n    }\n}\n\nimpl Default for Example {\n    fn default() -> Self {\n        Self::LIST[0]\n    }\n}\n\nimpl PartialEq for Example {\n    fn eq(&self, other: &Self) -> bool {\n        self.title == other.title\n    }\n}\n\nfn centered<'a>() -> Element<'a, Message> {\n    center(text(\"I am centered!\").size(50)).into()\n}\n\nfn column_<'a>() -> Element<'a, Message> {\n    column![\n        \"A column can be used to\",\n        \"lay out widgets vertically.\",\n        square(50),\n        square(50),\n        square(50),\n        \"The amount of space between\",\n        \"elements can be configured!\",\n    ]\n    .spacing(40)\n    .into()\n}\n\nfn row_<'a>() -> Element<'a, Message> {\n    row![\n        \"A row works like a column...\",\n        square(50),\n        square(50),\n        square(50),\n        \"but lays out widgets horizontally!\",\n    ]\n    .spacing(40)\n    .into()\n}\n\nfn space_<'a>() -> Element<'a, Message> {\n    row![\"Left!\", space::horizontal(), \"Right!\"].into()\n}\n\nfn application<'a>() -> Element<'a, Message> {\n    let header = container(\n        row![\n            square(40),\n            space::horizontal(),\n            \"Header!\",\n            space::horizontal(),\n            square(40),\n        ]\n        .padding(10)\n        .align_y(Center),\n    )\n    .style(|theme| {\n        let palette = theme.palette();\n\n        container::Style::default().border(border::color(palette.background.strong.color).width(1))\n    });\n\n    let sidebar = center_y(\n        column![\"Sidebar!\", square(50), square(50)]\n            .spacing(40)\n            .padding(10)\n            .width(200)\n            .align_x(Center),\n    )\n    .style(container::rounded_box);\n\n    let content = container(\n        scrollable(\n            column![\n                \"Content!\",\n                row((1..10).map(|i| square(if i % 2 == 0 { 80 } else { 160 })))\n                    .spacing(20)\n                    .align_y(Center)\n                    .wrap(),\n                \"The end\"\n            ]\n            .spacing(40)\n            .align_x(Center)\n            .width(Fill),\n        )\n        .height(Fill),\n    )\n    .padding(10);\n\n    column![header, row![sidebar, content]].into()\n}\n\nfn quotes<'a>() -> Element<'a, Message> {\n    fn quote<'a>(content: impl Into<Element<'a, Message>>) -> Element<'a, Message> {\n        row![rule::vertical(1), content.into()]\n            .spacing(10)\n            .height(Shrink)\n            .into()\n    }\n\n    fn reply<'a>(\n        original: impl Into<Element<'a, Message>>,\n        reply: impl Into<Element<'a, Message>>,\n    ) -> Element<'a, Message> {\n        column![quote(original), reply.into()].spacing(10).into()\n    }\n\n    column![\n        reply(\n            reply(\"This is the original message\", \"This is a reply\"),\n            \"This is another reply\",\n        ),\n        rule::horizontal(1),\n        text(\"A separator ↑\"),\n    ]\n    .width(Shrink)\n    .spacing(10)\n    .into()\n}\n\nfn pinning<'a>() -> Element<'a, Message> {\n    column![\n        \"The pin widget can be used to position a widget \\\n        at some fixed coordinates inside some other widget.\",\n        stack![\n            container(pin(\"• (50, 50)\").x(50).y(50))\n                .width(500)\n                .height(500)\n                .style(container::bordered_box),\n            pin(\"• (300, 300)\").x(300).y(300),\n        ]\n    ]\n    .align_x(Center)\n    .spacing(10)\n    .into()\n}\n\nfn responsive_<'a>() -> Element<'a, Message> {\n    column![\n        responsive(|size| {\n            container(center(\n                text!(\"{}x{}px\", size.width, size.width).font(Font::MONOSPACE),\n            ))\n            .clip(true)\n            .width(size.width / 4.0)\n            .height(size.width / 4.0)\n            .style(container::bordered_box)\n            .into()\n        })\n        .width(Shrink)\n        .height(Shrink),\n        responsive(|size| {\n            let size = size.ratio(16.0 / 9.0);\n\n            container(center(\n                text!(\"{:.0}x{:.0}px (16:9)\", size.width, size.height).font(Font::MONOSPACE),\n            ))\n            .clip(true)\n            .width(size.width)\n            .height(size.height)\n            .style(container::bordered_box)\n            .into()\n        })\n        .width(Shrink)\n        .height(Shrink)\n    ]\n    .align_x(Center)\n    .spacing(10)\n    .padding(10)\n    .into()\n}\n\nfn square<'a>(size: impl Into<Length> + Copy) -> Element<'a, Message> {\n    struct Square;\n\n    impl canvas::Program<Message> for Square {\n        type State = ();\n\n        fn draw(\n            &self,\n            _state: &Self::State,\n            renderer: &Renderer,\n            theme: &Theme,\n            bounds: Rectangle,\n            _cursor: mouse::Cursor,\n        ) -> Vec<canvas::Geometry> {\n            let mut frame = canvas::Frame::new(renderer, bounds.size());\n\n            let palette = theme.palette();\n\n            frame.fill_rectangle(\n                Point::ORIGIN,\n                bounds.size(),\n                palette.background.strong.color,\n            );\n\n            vec![frame.into_geometry()]\n        }\n    }\n\n    canvas(Square).width(size).height(size).into()\n}\n"
  },
  {
    "path": "examples/lazy/Cargo.toml",
    "content": "[package]\nname = \"lazy\"\nversion = \"0.1.0\"\nauthors = [\"Nick Senger <dev@nsenger.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"lazy\"]\n"
  },
  {
    "path": "examples/lazy/src/main.rs",
    "content": "use iced::widget::{button, column, lazy, pick_list, row, scrollable, space, text, text_input};\nuse iced::{Element, Fill};\n\nuse std::collections::HashSet;\nuse std::hash::Hash;\n\npub fn main() -> iced::Result {\n    iced::run(App::update, App::view)\n}\n\nstruct App {\n    version: u8,\n    items: HashSet<Item>,\n    input: String,\n    order: Order,\n}\n\nimpl Default for App {\n    fn default() -> Self {\n        Self {\n            version: 0,\n            items: [\"Foo\", \"Bar\", \"Baz\", \"Qux\", \"Corge\", \"Waldo\", \"Fred\"]\n                .into_iter()\n                .map(From::from)\n                .collect(),\n            input: String::default(),\n            order: Order::Ascending,\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]\nenum Color {\n    #[default]\n    Black,\n    Red,\n    Orange,\n    Yellow,\n    Green,\n    Blue,\n    Purple,\n}\n\nimpl Color {\n    const ALL: &'static [Color] = &[\n        Color::Black,\n        Color::Red,\n        Color::Orange,\n        Color::Yellow,\n        Color::Green,\n        Color::Blue,\n        Color::Purple,\n    ];\n}\n\nimpl std::fmt::Display for Color {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_str(match self {\n            Self::Black => \"Black\",\n            Self::Red => \"Red\",\n            Self::Orange => \"Orange\",\n            Self::Yellow => \"Yellow\",\n            Self::Green => \"Green\",\n            Self::Blue => \"Blue\",\n            Self::Purple => \"Purple\",\n        })\n    }\n}\n\nimpl From<Color> for iced::Color {\n    fn from(value: Color) -> Self {\n        match value {\n            Color::Black => iced::Color::from_rgb8(0, 0, 0),\n            Color::Red => iced::Color::from_rgb8(220, 50, 47),\n            Color::Orange => iced::Color::from_rgb8(203, 75, 22),\n            Color::Yellow => iced::Color::from_rgb8(181, 137, 0),\n            Color::Green => iced::Color::from_rgb8(133, 153, 0),\n            Color::Blue => iced::Color::from_rgb8(38, 139, 210),\n            Color::Purple => iced::Color::from_rgb8(108, 113, 196),\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq)]\nstruct Item {\n    name: String,\n    color: Color,\n}\n\nimpl Hash for Item {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.name.hash(state);\n    }\n}\n\nimpl PartialEq for Item {\n    fn eq(&self, other: &Self) -> bool {\n        self.name.eq(&other.name)\n    }\n}\n\nimpl From<&str> for Item {\n    fn from(s: &str) -> Self {\n        Self {\n            name: s.to_owned(),\n            color: Color::default(),\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    InputChanged(String),\n    ToggleOrder,\n    DeleteItem(Item),\n    AddItem(String),\n    ItemColorChanged(Item, Color),\n}\n\nimpl App {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::InputChanged(input) => {\n                self.input = input;\n            }\n            Message::ToggleOrder => {\n                self.version = self.version.wrapping_add(1);\n                self.order = match self.order {\n                    Order::Ascending => Order::Descending,\n                    Order::Descending => Order::Ascending,\n                }\n            }\n            Message::AddItem(name) => {\n                self.version = self.version.wrapping_add(1);\n                self.items.insert(name.as_str().into());\n                self.input.clear();\n            }\n            Message::DeleteItem(item) => {\n                self.version = self.version.wrapping_add(1);\n                self.items.remove(&item);\n            }\n            Message::ItemColorChanged(item, color) => {\n                self.version = self.version.wrapping_add(1);\n                if self.items.remove(&item) {\n                    self.items.insert(Item {\n                        name: item.name,\n                        color,\n                    });\n                }\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let options = lazy(self.version, |_| {\n            let mut items: Vec<_> = self.items.iter().cloned().collect();\n\n            items.sort_by(|a, b| match self.order {\n                Order::Ascending => a.name.to_lowercase().cmp(&b.name.to_lowercase()),\n                Order::Descending => b.name.to_lowercase().cmp(&a.name.to_lowercase()),\n            });\n\n            column(items.into_iter().map(|item| {\n                let button = button(\"Delete\")\n                    .on_press(Message::DeleteItem(item.clone()))\n                    .style(button::danger);\n\n                row![\n                    text(item.name.clone()).color(item.color),\n                    space::horizontal(),\n                    pick_list(Some(item.color), Color::ALL, Color::to_string)\n                        .on_select(move |color| { Message::ItemColorChanged(item.clone(), color) }),\n                    button\n                ]\n                .spacing(20)\n                .into()\n            }))\n            .spacing(10)\n        });\n\n        column![\n            scrollable(options).height(Fill),\n            row![\n                text_input(\"Add a new option\", &self.input)\n                    .on_input(Message::InputChanged)\n                    .on_submit(Message::AddItem(self.input.clone())),\n                button(text!(\"Toggle Order ({})\", self.order)).on_press(Message::ToggleOrder)\n            ]\n            .spacing(10)\n        ]\n        .spacing(20)\n        .padding(20)\n        .into()\n    }\n}\n\n#[derive(Debug, Hash)]\nenum Order {\n    Ascending,\n    Descending,\n}\n\nimpl std::fmt::Display for Order {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"{}\",\n            match self {\n                Self::Ascending => \"Ascending\",\n                Self::Descending => \"Descending\",\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "examples/loading_spinners/Cargo.toml",
    "content": "[package]\nname = \"loading_spinners\"\nversion = \"0.1.0\"\nauthors = [\"Nick Senger <dev@nsenger.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"advanced\", \"canvas\"]\n\nlyon_algorithms = \"1.0\"\n"
  },
  {
    "path": "examples/loading_spinners/README.md",
    "content": "## Loading Spinners\n\nExample implementation of animated indeterminate loading spinners.\n\nYou can run it with `cargo run`:\n```\ncargo run --package loading_spinners\n```\n"
  },
  {
    "path": "examples/loading_spinners/src/circular.rs",
    "content": "//! Show a circular progress indicator.\nuse iced::advanced::layout;\nuse iced::advanced::renderer;\nuse iced::advanced::widget::tree::{self, Tree};\nuse iced::advanced::{self, Layout, Shell, Widget};\nuse iced::mouse;\nuse iced::time::Instant;\nuse iced::widget::canvas;\nuse iced::window;\nuse iced::{Background, Color, Element, Event, Length, Radians, Rectangle, Renderer, Size, Vector};\n\nuse super::easing::{self, Easing};\n\nuse std::f32::consts::PI;\nuse std::time::Duration;\n\nconst MIN_ANGLE: Radians = Radians(PI / 8.0);\nconst WRAP_ANGLE: Radians = Radians(2.0 * PI - PI / 4.0);\nconst BASE_ROTATION_SPEED: u32 = u32::MAX / 80;\n\npub struct Circular<'a, Theme>\nwhere\n    Theme: StyleSheet,\n{\n    size: f32,\n    bar_height: f32,\n    style: <Theme as StyleSheet>::Style,\n    easing: &'a Easing,\n    cycle_duration: Duration,\n    rotation_duration: Duration,\n}\n\nimpl<'a, Theme> Circular<'a, Theme>\nwhere\n    Theme: StyleSheet,\n{\n    /// Creates a new [`Circular`] with the given content.\n    pub fn new() -> Self {\n        Circular {\n            size: 40.0,\n            bar_height: 4.0,\n            style: <Theme as StyleSheet>::Style::default(),\n            easing: &easing::STANDARD,\n            cycle_duration: Duration::from_millis(600),\n            rotation_duration: Duration::from_secs(2),\n        }\n    }\n\n    /// Sets the size of the [`Circular`].\n    pub fn size(mut self, size: f32) -> Self {\n        self.size = size;\n        self\n    }\n\n    /// Sets the bar height of the [`Circular`].\n    pub fn bar_height(mut self, bar_height: f32) -> Self {\n        self.bar_height = bar_height;\n        self\n    }\n\n    /// Sets the style variant of this [`Circular`].\n    pub fn style(mut self, style: <Theme as StyleSheet>::Style) -> Self {\n        self.style = style;\n        self\n    }\n\n    /// Sets the easing of this [`Circular`].\n    pub fn easing(mut self, easing: &'a Easing) -> Self {\n        self.easing = easing;\n        self\n    }\n\n    /// Sets the cycle duration of this [`Circular`].\n    pub fn cycle_duration(mut self, duration: Duration) -> Self {\n        self.cycle_duration = duration / 2;\n        self\n    }\n\n    /// Sets the base rotation duration of this [`Circular`]. This is the duration that a full\n    /// rotation would take if the cycle rotation were set to 0.0 (no expanding or contracting)\n    pub fn rotation_duration(mut self, duration: Duration) -> Self {\n        self.rotation_duration = duration;\n        self\n    }\n}\n\nimpl<Theme> Default for Circular<'_, Theme>\nwhere\n    Theme: StyleSheet,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[derive(Clone, Copy)]\nenum Animation {\n    Expanding {\n        start: Instant,\n        progress: f32,\n        rotation: u32,\n        last: Instant,\n    },\n    Contracting {\n        start: Instant,\n        progress: f32,\n        rotation: u32,\n        last: Instant,\n    },\n}\n\nimpl Default for Animation {\n    fn default() -> Self {\n        Self::Expanding {\n            start: Instant::now(),\n            progress: 0.0,\n            rotation: 0,\n            last: Instant::now(),\n        }\n    }\n}\n\nimpl Animation {\n    fn next(&self, additional_rotation: u32, now: Instant) -> Self {\n        match self {\n            Self::Expanding { rotation, .. } => Self::Contracting {\n                start: now,\n                progress: 0.0,\n                rotation: rotation.wrapping_add(additional_rotation),\n                last: now,\n            },\n            Self::Contracting { rotation, .. } => Self::Expanding {\n                start: now,\n                progress: 0.0,\n                rotation: rotation.wrapping_add(BASE_ROTATION_SPEED.wrapping_add(\n                    (f64::from(WRAP_ANGLE / (2.0 * Radians::PI)) * u32::MAX as f64) as u32,\n                )),\n                last: now,\n            },\n        }\n    }\n\n    fn start(&self) -> Instant {\n        match self {\n            Self::Expanding { start, .. } | Self::Contracting { start, .. } => *start,\n        }\n    }\n\n    fn last(&self) -> Instant {\n        match self {\n            Self::Expanding { last, .. } | Self::Contracting { last, .. } => *last,\n        }\n    }\n\n    fn timed_transition(\n        &self,\n        cycle_duration: Duration,\n        rotation_duration: Duration,\n        now: Instant,\n    ) -> Self {\n        let elapsed = now.duration_since(self.start());\n        let additional_rotation = ((now - self.last()).as_secs_f32()\n            / rotation_duration.as_secs_f32()\n            * (u32::MAX) as f32) as u32;\n\n        match elapsed {\n            elapsed if elapsed > cycle_duration => self.next(additional_rotation, now),\n            _ => self.with_elapsed(cycle_duration, additional_rotation, elapsed, now),\n        }\n    }\n\n    fn with_elapsed(\n        &self,\n        cycle_duration: Duration,\n        additional_rotation: u32,\n        elapsed: Duration,\n        now: Instant,\n    ) -> Self {\n        let progress = elapsed.as_secs_f32() / cycle_duration.as_secs_f32();\n        match self {\n            Self::Expanding {\n                start, rotation, ..\n            } => Self::Expanding {\n                start: *start,\n                progress,\n                rotation: rotation.wrapping_add(additional_rotation),\n                last: now,\n            },\n            Self::Contracting {\n                start, rotation, ..\n            } => Self::Contracting {\n                start: *start,\n                progress,\n                rotation: rotation.wrapping_add(additional_rotation),\n                last: now,\n            },\n        }\n    }\n\n    fn rotation(&self) -> f32 {\n        match self {\n            Self::Expanding { rotation, .. } | Self::Contracting { rotation, .. } => {\n                *rotation as f32 / u32::MAX as f32\n            }\n        }\n    }\n}\n\n#[derive(Default)]\nstruct State {\n    animation: Animation,\n    cache: canvas::Cache,\n}\n\nimpl<'a, Message, Theme> Widget<Message, Theme, Renderer> for Circular<'a, Theme>\nwhere\n    Message: 'a + Clone,\n    Theme: StyleSheet,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: Length::Fixed(self.size),\n            height: Length::Fixed(self.size),\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::atomic(limits, self.size, self.size)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        _layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_mut::<State>();\n\n        if let Event::Window(window::Event::RedrawRequested(now)) = event {\n            state.animation =\n                state\n                    .animation\n                    .timed_transition(self.cycle_duration, self.rotation_duration, *now);\n\n            state.cache.clear();\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        use advanced::Renderer as _;\n\n        let state = tree.state.downcast_ref::<State>();\n        let bounds = layout.bounds();\n        let custom_style = <Theme as StyleSheet>::appearance(theme, &self.style);\n\n        let geometry = state.cache.draw(renderer, bounds.size(), |frame| {\n            let track_radius = frame.width() / 2.0 - self.bar_height;\n            let track_path = canvas::Path::circle(frame.center(), track_radius);\n\n            frame.stroke(\n                &track_path,\n                canvas::Stroke::default()\n                    .with_color(custom_style.track_color)\n                    .with_width(self.bar_height),\n            );\n\n            let mut builder = canvas::path::Builder::new();\n\n            let start = Radians(state.animation.rotation() * 2.0 * PI);\n\n            match state.animation {\n                Animation::Expanding { progress, .. } => {\n                    builder.arc(canvas::path::Arc {\n                        center: frame.center(),\n                        radius: track_radius,\n                        start_angle: start,\n                        end_angle: start + MIN_ANGLE + WRAP_ANGLE * (self.easing.y_at_x(progress)),\n                    });\n                }\n                Animation::Contracting { progress, .. } => {\n                    builder.arc(canvas::path::Arc {\n                        center: frame.center(),\n                        radius: track_radius,\n                        start_angle: start + WRAP_ANGLE * (self.easing.y_at_x(progress)),\n                        end_angle: start + MIN_ANGLE + WRAP_ANGLE,\n                    });\n                }\n            }\n\n            let bar_path = builder.build();\n\n            frame.stroke(\n                &bar_path,\n                canvas::Stroke::default()\n                    .with_color(custom_style.bar_color)\n                    .with_width(self.bar_height),\n            );\n        });\n\n        renderer.with_translation(Vector::new(bounds.x, bounds.y), |renderer| {\n            use iced::advanced::graphics::geometry::Renderer as _;\n\n            renderer.draw_geometry(geometry);\n        });\n    }\n}\n\nimpl<'a, Message, Theme> From<Circular<'a, Theme>> for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone + 'a,\n    Theme: StyleSheet + 'a,\n{\n    fn from(circular: Circular<'a, Theme>) -> Self {\n        Self::new(circular)\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\npub struct Appearance {\n    /// The [`Background`] of the progress indicator.\n    pub background: Option<Background>,\n    /// The track [`Color`] of the progress indicator.\n    pub track_color: Color,\n    /// The bar [`Color`] of the progress indicator.\n    pub bar_color: Color,\n}\n\nimpl std::default::Default for Appearance {\n    fn default() -> Self {\n        Self {\n            background: None,\n            track_color: Color::TRANSPARENT,\n            bar_color: Color::BLACK,\n        }\n    }\n}\n\n/// A set of rules that dictate the style of an indicator.\npub trait StyleSheet {\n    /// The supported style of the [`StyleSheet`].\n    type Style: Default;\n\n    /// Produces the active [`Appearance`] of a indicator.\n    fn appearance(&self, style: &Self::Style) -> Appearance;\n}\n\nimpl StyleSheet for iced::Theme {\n    type Style = ();\n\n    fn appearance(&self, _style: &Self::Style) -> Appearance {\n        let palette = self.palette();\n\n        Appearance {\n            background: None,\n            track_color: palette.background.weak.color,\n            bar_color: palette.primary.base.color,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/loading_spinners/src/easing.rs",
    "content": "use iced::Point;\n\nuse lyon_algorithms::measure::PathMeasurements;\nuse lyon_algorithms::path::{Path, builder::NoAttributes, path::BuilderImpl};\n\nuse std::sync::LazyLock;\n\npub static EMPHASIZED: LazyLock<Easing> = LazyLock::new(|| {\n    Easing::builder()\n        .cubic_bezier_to([0.05, 0.0], [0.133333, 0.06], [0.166666, 0.4])\n        .cubic_bezier_to([0.208333, 0.82], [0.25, 1.0], [1.0, 1.0])\n        .build()\n});\n\npub static EMPHASIZED_DECELERATE: LazyLock<Easing> = LazyLock::new(|| {\n    Easing::builder()\n        .cubic_bezier_to([0.05, 0.7], [0.1, 1.0], [1.0, 1.0])\n        .build()\n});\n\npub static EMPHASIZED_ACCELERATE: LazyLock<Easing> = LazyLock::new(|| {\n    Easing::builder()\n        .cubic_bezier_to([0.3, 0.0], [0.8, 0.15], [1.0, 1.0])\n        .build()\n});\n\npub static STANDARD: LazyLock<Easing> = LazyLock::new(|| {\n    Easing::builder()\n        .cubic_bezier_to([0.2, 0.0], [0.0, 1.0], [1.0, 1.0])\n        .build()\n});\n\npub static STANDARD_DECELERATE: LazyLock<Easing> = LazyLock::new(|| {\n    Easing::builder()\n        .cubic_bezier_to([0.0, 0.0], [0.0, 1.0], [1.0, 1.0])\n        .build()\n});\n\npub static STANDARD_ACCELERATE: LazyLock<Easing> = LazyLock::new(|| {\n    Easing::builder()\n        .cubic_bezier_to([0.3, 0.0], [1.0, 1.0], [1.0, 1.0])\n        .build()\n});\n\npub struct Easing {\n    path: Path,\n    measurements: PathMeasurements,\n}\n\nimpl Easing {\n    pub fn builder() -> Builder {\n        Builder::new()\n    }\n\n    pub fn y_at_x(&self, x: f32) -> f32 {\n        let mut sampler = self\n            .measurements\n            .create_sampler(&self.path, lyon_algorithms::measure::SampleType::Normalized);\n        let sample = sampler.sample(x);\n\n        sample.position().y\n    }\n}\n\npub struct Builder(NoAttributes<BuilderImpl>);\n\nimpl Builder {\n    pub fn new() -> Self {\n        let mut builder = Path::builder();\n        builder.begin(lyon_algorithms::geom::point(0.0, 0.0));\n\n        Self(builder)\n    }\n\n    /// Adds a line segment. Points must be between 0,0 and 1,1\n    pub fn line_to(mut self, to: impl Into<Point>) -> Self {\n        self.0.line_to(Self::point(to));\n\n        self\n    }\n\n    /// Adds a quadratic bézier curve. Points must be between 0,0 and 1,1\n    pub fn quadratic_bezier_to(mut self, ctrl: impl Into<Point>, to: impl Into<Point>) -> Self {\n        self.0\n            .quadratic_bezier_to(Self::point(ctrl), Self::point(to));\n\n        self\n    }\n\n    /// Adds a cubic bézier curve. Points must be between 0,0 and 1,1\n    pub fn cubic_bezier_to(\n        mut self,\n        ctrl1: impl Into<Point>,\n        ctrl2: impl Into<Point>,\n        to: impl Into<Point>,\n    ) -> Self {\n        self.0\n            .cubic_bezier_to(Self::point(ctrl1), Self::point(ctrl2), Self::point(to));\n\n        self\n    }\n\n    pub fn build(mut self) -> Easing {\n        self.0.line_to(lyon_algorithms::geom::point(1.0, 1.0));\n        self.0.end(false);\n\n        let path = self.0.build();\n        let measurements = PathMeasurements::from_path(&path, 0.0);\n\n        Easing { path, measurements }\n    }\n\n    fn point(p: impl Into<Point>) -> lyon_algorithms::geom::Point<f32> {\n        let p: Point = p.into();\n        lyon_algorithms::geom::point(p.x.clamp(0.0, 1.0), p.y.clamp(0.0, 1.0))\n    }\n}\n\nimpl Default for Builder {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n"
  },
  {
    "path": "examples/loading_spinners/src/linear.rs",
    "content": "//! Show a linear progress indicator.\nuse iced::advanced::layout;\nuse iced::advanced::renderer::{self, Quad};\nuse iced::advanced::widget::tree::{self, Tree};\nuse iced::advanced::{self, Layout, Shell, Widget};\nuse iced::mouse;\nuse iced::time::Instant;\nuse iced::window;\nuse iced::{Background, Color, Element, Event, Length, Rectangle, Size};\n\nuse super::easing::{self, Easing};\n\nuse std::time::Duration;\n\npub struct Linear<'a, Theme>\nwhere\n    Theme: StyleSheet,\n{\n    width: Length,\n    height: Length,\n    style: Theme::Style,\n    easing: &'a Easing,\n    cycle_duration: Duration,\n}\n\nimpl<'a, Theme> Linear<'a, Theme>\nwhere\n    Theme: StyleSheet,\n{\n    /// Creates a new [`Linear`] with the given content.\n    pub fn new() -> Self {\n        Linear {\n            width: Length::Fixed(100.0),\n            height: Length::Fixed(4.0),\n            style: Theme::Style::default(),\n            easing: &easing::STANDARD,\n            cycle_duration: Duration::from_millis(600),\n        }\n    }\n\n    /// Sets the width of the [`Linear`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Linear`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the style variant of this [`Linear`].\n    pub fn style(mut self, style: impl Into<Theme::Style>) -> Self {\n        self.style = style.into();\n        self\n    }\n\n    /// Sets the motion easing of this [`Linear`].\n    pub fn easing(mut self, easing: &'a Easing) -> Self {\n        self.easing = easing;\n        self\n    }\n\n    /// Sets the cycle duration of this [`Linear`].\n    pub fn cycle_duration(mut self, duration: Duration) -> Self {\n        self.cycle_duration = duration / 2;\n        self\n    }\n}\n\nimpl<Theme> Default for Linear<'_, Theme>\nwhere\n    Theme: StyleSheet,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[derive(Clone, Copy)]\nenum State {\n    Expanding { start: Instant, progress: f32 },\n    Contracting { start: Instant, progress: f32 },\n}\n\nimpl Default for State {\n    fn default() -> Self {\n        Self::Expanding {\n            start: Instant::now(),\n            progress: 0.0,\n        }\n    }\n}\n\nimpl State {\n    fn next(&self, now: Instant) -> Self {\n        match self {\n            Self::Expanding { .. } => Self::Contracting {\n                start: now,\n                progress: 0.0,\n            },\n            Self::Contracting { .. } => Self::Expanding {\n                start: now,\n                progress: 0.0,\n            },\n        }\n    }\n\n    fn start(&self) -> Instant {\n        match self {\n            Self::Expanding { start, .. } | Self::Contracting { start, .. } => *start,\n        }\n    }\n\n    fn timed_transition(&self, cycle_duration: Duration, now: Instant) -> Self {\n        let elapsed = now.duration_since(self.start());\n\n        match elapsed {\n            elapsed if elapsed > cycle_duration => self.next(now),\n            _ => self.with_elapsed(cycle_duration, elapsed),\n        }\n    }\n\n    fn with_elapsed(&self, cycle_duration: Duration, elapsed: Duration) -> Self {\n        let progress = elapsed.as_secs_f32() / cycle_duration.as_secs_f32();\n        match self {\n            Self::Expanding { start, .. } => Self::Expanding {\n                start: *start,\n                progress,\n            },\n            Self::Contracting { start, .. } => Self::Contracting {\n                start: *start,\n                progress,\n            },\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Linear<'a, Theme>\nwhere\n    Message: Clone + 'a,\n    Theme: StyleSheet + 'a,\n    Renderer: advanced::Renderer + 'a,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::atomic(limits, self.width, self.height)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        _layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_mut::<State>();\n\n        if let Event::Window(window::Event::RedrawRequested(now)) = event {\n            *state = state.timed_transition(self.cycle_duration, *now);\n\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n        let custom_style = theme.appearance(&self.style);\n        let state = tree.state.downcast_ref::<State>();\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: Rectangle {\n                    x: bounds.x,\n                    y: bounds.y,\n                    width: bounds.width,\n                    height: bounds.height,\n                },\n                ..renderer::Quad::default()\n            },\n            Background::Color(custom_style.track_color),\n        );\n\n        match state {\n            State::Expanding { progress, .. } => renderer.fill_quad(\n                renderer::Quad {\n                    bounds: Rectangle {\n                        x: bounds.x,\n                        y: bounds.y,\n                        width: self.easing.y_at_x(*progress) * bounds.width,\n                        height: bounds.height,\n                    },\n                    ..renderer::Quad::default()\n                },\n                Background::Color(custom_style.bar_color),\n            ),\n\n            State::Contracting { progress, .. } => renderer.fill_quad(\n                Quad {\n                    bounds: Rectangle {\n                        x: bounds.x + self.easing.y_at_x(*progress) * bounds.width,\n                        y: bounds.y,\n                        width: (1.0 - self.easing.y_at_x(*progress)) * bounds.width,\n                        height: bounds.height,\n                    },\n                    ..renderer::Quad::default()\n                },\n                Background::Color(custom_style.bar_color),\n            ),\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Linear<'a, Theme>> for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone + 'a,\n    Theme: StyleSheet + 'a,\n    Renderer: iced::advanced::Renderer + 'a,\n{\n    fn from(linear: Linear<'a, Theme>) -> Self {\n        Self::new(linear)\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\npub struct Appearance {\n    /// The track [`Color`] of the progress indicator.\n    pub track_color: Color,\n    /// The bar [`Color`] of the progress indicator.\n    pub bar_color: Color,\n}\n\nimpl Default for Appearance {\n    fn default() -> Self {\n        Self {\n            track_color: Color::TRANSPARENT,\n            bar_color: Color::BLACK,\n        }\n    }\n}\n\n/// A set of rules that dictate the style of an indicator.\npub trait StyleSheet {\n    /// The supported style of the [`StyleSheet`].\n    type Style: Default;\n\n    /// Produces the active [`Appearance`] of a indicator.\n    fn appearance(&self, style: &Self::Style) -> Appearance;\n}\n\nimpl StyleSheet for iced::Theme {\n    type Style = ();\n\n    fn appearance(&self, _style: &Self::Style) -> Appearance {\n        let palette = self.palette();\n\n        Appearance {\n            track_color: palette.background.weak.color,\n            bar_color: palette.primary.base.color,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/loading_spinners/src/main.rs",
    "content": "use iced::widget::{center, column, row, slider, text};\nuse iced::{Center, Element};\n\nuse std::time::Duration;\n\nmod circular;\nmod easing;\nmod linear;\n\nuse circular::Circular;\nuse linear::Linear;\n\npub fn main() -> iced::Result {\n    iced::application(\n        LoadingSpinners::default,\n        LoadingSpinners::update,\n        LoadingSpinners::view,\n    )\n    .run()\n}\n\nstruct LoadingSpinners {\n    cycle_duration: f32,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    CycleDurationChanged(f32),\n}\n\nimpl LoadingSpinners {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::CycleDurationChanged(duration) => {\n                self.cycle_duration = duration;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let column = [\n            &easing::EMPHASIZED,\n            &easing::EMPHASIZED_DECELERATE,\n            &easing::EMPHASIZED_ACCELERATE,\n            &easing::STANDARD,\n            &easing::STANDARD_DECELERATE,\n            &easing::STANDARD_ACCELERATE,\n        ]\n        .iter()\n        .zip([\n            \"Emphasized:\",\n            \"Emphasized Decelerate:\",\n            \"Emphasized Accelerate:\",\n            \"Standard:\",\n            \"Standard Decelerate:\",\n            \"Standard Accelerate:\",\n        ])\n        .fold(column![], |column, (easing, label)| {\n            column.push(\n                row![\n                    text(label).width(250),\n                    Linear::new()\n                        .easing(easing)\n                        .cycle_duration(Duration::from_secs_f32(self.cycle_duration)),\n                    Circular::new()\n                        .easing(easing)\n                        .cycle_duration(Duration::from_secs_f32(self.cycle_duration))\n                ]\n                .align_y(Center)\n                .spacing(20.0),\n            )\n        })\n        .spacing(20);\n\n        center(\n            column.push(\n                row![\n                    text(\"Cycle duration:\"),\n                    slider(1.0..=1000.0, self.cycle_duration * 100.0, |x| {\n                        Message::CycleDurationChanged(x / 100.0)\n                    })\n                    .width(200.0),\n                    text!(\"{:.2}s\", self.cycle_duration),\n                ]\n                .align_y(Center)\n                .spacing(20.0),\n            ),\n        )\n        .into()\n    }\n}\n\nimpl Default for LoadingSpinners {\n    fn default() -> Self {\n        Self {\n            cycle_duration: 2.0,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/loupe/Cargo.toml",
    "content": "[package]\nname = \"loupe\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"advanced\", \"debug\"]"
  },
  {
    "path": "examples/loupe/src/main.rs",
    "content": "use iced::widget::{button, center, column, text};\nuse iced::{Center, Element};\n\nuse loupe::loupe;\n\npub fn main() -> iced::Result {\n    iced::run(Loupe::update, Loupe::view)\n}\n\n#[derive(Default)]\nstruct Loupe {\n    value: i64,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Increment,\n    Decrement,\n}\n\nimpl Loupe {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Increment => {\n                self.value += 1;\n            }\n            Message::Decrement => {\n                self.value -= 1;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        center(loupe(\n            3.0,\n            column![\n                button(\"Increment\").on_press(Message::Increment),\n                text(self.value).size(50),\n                button(\"Decrement\").on_press(Message::Decrement)\n            ]\n            .padding(20)\n            .align_x(Center),\n        ))\n        .into()\n    }\n}\n\nmod loupe {\n    use iced::advanced::Renderer as _;\n    use iced::advanced::layout::{self, Layout};\n    use iced::advanced::renderer;\n    use iced::advanced::widget::{self, Widget};\n    use iced::mouse;\n    use iced::{Color, Element, Length, Rectangle, Renderer, Size, Theme, Transformation};\n\n    pub fn loupe<'a, Message>(\n        zoom: f32,\n        content: impl Into<Element<'a, Message>>,\n    ) -> Loupe<'a, Message>\n    where\n        Message: 'static,\n    {\n        Loupe {\n            zoom,\n            content: content.into().explain(Color::BLACK),\n        }\n    }\n\n    pub struct Loupe<'a, Message> {\n        zoom: f32,\n        content: Element<'a, Message>,\n    }\n\n    impl<Message> Widget<Message, Theme, Renderer> for Loupe<'_, Message> {\n        fn tag(&self) -> widget::tree::Tag {\n            self.content.as_widget().tag()\n        }\n\n        fn state(&self) -> widget::tree::State {\n            self.content.as_widget().state()\n        }\n\n        fn children(&self) -> Vec<widget::Tree> {\n            self.content.as_widget().children()\n        }\n\n        fn diff(&self, tree: &mut widget::Tree) {\n            self.content.as_widget().diff(tree);\n        }\n\n        fn size(&self) -> Size<Length> {\n            self.content.as_widget().size()\n        }\n\n        fn layout(\n            &mut self,\n            tree: &mut widget::Tree,\n            renderer: &Renderer,\n            limits: &layout::Limits,\n        ) -> layout::Node {\n            self.content.as_widget_mut().layout(tree, renderer, limits)\n        }\n\n        fn draw(\n            &self,\n            tree: &widget::Tree,\n            renderer: &mut Renderer,\n            theme: &Theme,\n            style: &renderer::Style,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            viewport: &Rectangle,\n        ) {\n            let bounds = layout.bounds();\n\n            if let Some(position) = cursor.position_in(bounds) {\n                renderer.with_layer(bounds, |renderer| {\n                    renderer.with_transformation(\n                        Transformation::translate(\n                            bounds.x + position.x * (1.0 - self.zoom),\n                            bounds.y + position.y * (1.0 - self.zoom),\n                        ) * Transformation::scale(self.zoom)\n                            * Transformation::translate(-bounds.x, -bounds.y),\n                        |renderer| {\n                            self.content.as_widget().draw(\n                                tree,\n                                renderer,\n                                theme,\n                                style,\n                                layout,\n                                mouse::Cursor::Unavailable,\n                                viewport,\n                            );\n                        },\n                    );\n                });\n            } else {\n                self.content\n                    .as_widget()\n                    .draw(tree, renderer, theme, style, layout, cursor, viewport);\n            }\n        }\n\n        fn mouse_interaction(\n            &self,\n            _tree: &widget::Tree,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            _viewport: &Rectangle,\n            _renderer: &Renderer,\n        ) -> mouse::Interaction {\n            if cursor.is_over(layout.bounds()) {\n                mouse::Interaction::ZoomIn\n            } else {\n                mouse::Interaction::None\n            }\n        }\n    }\n\n    impl<'a, Message> From<Loupe<'a, Message>> for Element<'a, Message, Theme, Renderer>\n    where\n        Message: 'a,\n    {\n        fn from(loupe: Loupe<'a, Message>) -> Self {\n            Self::new(loupe)\n        }\n    }\n}\n"
  },
  {
    "path": "examples/markdown/Cargo.toml",
    "content": "[package]\nname = \"markdown\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"markdown\", \"highlighter\", \"image\", \"tokio\", \"debug\"]\n\nreqwest.version = \"0.12\"\nreqwest.features = [\"json\"]\n\ntokio.workspace = true\ntokio.features = [\"fs\"]\n\nimage.workspace = true\nurl.workspace = true\n\nwebbrowser = \"1\"\n\n# Disabled to keep amount of build dependencies low\n# This can be re-enabled on demand\n# [build-dependencies]\n# iced_fontello = \"0.13\"\n"
  },
  {
    "path": "examples/markdown/build.rs",
    "content": "pub fn main() {\n    // println!(\"cargo::rerun-if-changed=fonts/markdown-icons.toml\");\n    // iced_fontello::build(\"fonts/markdown-icons.toml\")\n    //     .expect(\"Build icons font\");\n}\n"
  },
  {
    "path": "examples/markdown/fonts/markdown-icons.toml",
    "content": "module = \"icon\"\n\n[glyphs]\ncopy = \"fontawesome-docs\"\n"
  },
  {
    "path": "examples/markdown/overview.md",
    "content": "# Overview\n\nInspired by [The Elm Architecture], Iced expects you to split user interfaces into four different concepts:\n\n* __State__ — the state of your application\n* __Messages__ — user interactions or meaningful events that you care about\n* __View logic__ — a way to display your __state__ as widgets that may produce __messages__ on user interaction\n* __Update logic__ — a way to react to __messages__ and update your __state__\n\nWe can build something to see how this works! Let's say we want a simple counter that can be incremented and decremented using two buttons.\n\nWe start by modelling the __state__ of our application:\n\n```rust\n#[derive(Default)]\nstruct Counter {\n    value: i32,\n}\n```\n\nNext, we need to define the possible user interactions of our counter: the button presses. These interactions are our __messages__:\n\n```rust\n#[derive(Debug, Clone, Copy)]\npub enum Message {\n    Increment,\n    Decrement,\n}\n```\n\nNow, let's show the actual counter by putting it all together in our __view logic__:\n\n```rust\nuse iced::widget::{button, column, text, Column};\n\nimpl Counter {\n    pub fn view(&self) -> Column<'_, Message> {\n        // We use a column: a simple vertical layout\n        column![\n            // The increment button. We tell it to produce an\n            // `Increment` message when pressed\n            button(\"+\").on_press(Message::Increment),\n\n            // We show the value of the counter here\n            text(self.value).size(50),\n\n            // The decrement button. We tell it to produce a\n            // `Decrement` message when pressed\n            button(\"-\").on_press(Message::Decrement),\n        ]\n    }\n}\n```\n\nFinally, we need to be able to react to any produced __messages__ and change our __state__ accordingly in our __update logic__:\n\n```rust\nimpl Counter {\n    // ...\n\n    pub fn update(&mut self, message: Message) {\n        match message {\n            Message::Increment => {\n                self.value += 1;\n            }\n            Message::Decrement => {\n                self.value -= 1;\n            }\n        }\n    }\n}\n```\n\nAnd that's everything! We just wrote a whole user interface. Let's run it:\n\n```rust\nfn main() -> iced::Result {\n    iced::run(\"A cool counter\", Counter::update, Counter::view)\n}\n```\n\nIced will automatically:\n\n  1. Take the result of our __view logic__ and layout its widgets.\n  1. Process events from our system and produce __messages__ for our __update logic__.\n  1. Draw the resulting user interface.\n\nRead the [book], the [documentation], and the [examples] to learn more!\n\n[book]: https://book.iced.rs/\n[documentation]: https://docs.rs/iced/\n[examples]: https://github.com/iced-rs/iced/tree/master/examples#examples\n[The Elm Architecture]: https://guide.elm-lang.org/architecture/\n"
  },
  {
    "path": "examples/markdown/src/icon.rs",
    "content": "// Generated automatically by iced_fontello at build time.\n// Do not edit manually. Source: ../fonts/markdown-icons.toml\n// dcd2f0c969d603e2ee9237a4b70fa86b1a6e84d86f4689046d8fdd10440b06b9\nuse iced::widget::{Text, text};\n\npub const FONT: &[u8] = include_bytes!(\"../fonts/markdown-icons.ttf\");\n\npub fn copy<'a>() -> Text<'a> {\n    icon(\"\\u{F0C5}\")\n}\n\nfn icon(codepoint: &str) -> Text<'_> {\n    text(codepoint).font(\"markdown-icons\")\n}\n"
  },
  {
    "path": "examples/markdown/src/main.rs",
    "content": "mod icon;\n\nuse iced::animation;\nuse iced::clipboard;\nuse iced::highlighter;\nuse iced::time::{self, Instant, milliseconds};\nuse iced::widget::{\n    button, center_x, container, hover, image, markdown, operation, right, row, scrollable, sensor,\n    space, text_editor, toggler,\n};\nuse iced::window;\nuse iced::{Animation, Element, Fill, Font, Function, Subscription, Task, Theme};\n\nuse std::collections::HashMap;\nuse std::io;\nuse std::sync::Arc;\n\npub fn main() -> iced::Result {\n    iced::application::timed(\n        Markdown::new,\n        Markdown::update,\n        Markdown::subscription,\n        Markdown::view,\n    )\n    .font(icon::FONT)\n    .theme(Markdown::theme)\n    .run()\n}\n\nstruct Markdown {\n    content: markdown::Content,\n    raw: text_editor::Content,\n    images: HashMap<markdown::Uri, Image>,\n    mode: Mode,\n    theme: Theme,\n    now: Instant,\n}\n\nenum Mode {\n    Preview,\n    Stream { pending: String },\n}\n\nenum Image {\n    Loading,\n    Ready {\n        handle: image::Handle,\n        fade_in: Animation<bool>,\n    },\n    #[allow(dead_code)]\n    Errored(Error),\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    Edit(text_editor::Action),\n    Copy(String),\n    LinkClicked(markdown::Uri),\n    ImageShown(markdown::Uri),\n    ImageDownloaded(markdown::Uri, Result<image::Handle, Error>),\n    ToggleStream(bool),\n    NextToken,\n    Tick,\n}\n\nimpl Markdown {\n    fn new() -> (Self, Task<Message>) {\n        const INITIAL_CONTENT: &str = include_str!(\"../overview.md\");\n\n        (\n            Self {\n                content: markdown::Content::parse(INITIAL_CONTENT),\n                raw: text_editor::Content::with_text(INITIAL_CONTENT),\n                images: HashMap::new(),\n                mode: Mode::Preview,\n                theme: Theme::TokyoNight,\n                now: Instant::now(),\n            },\n            operation::focus_next(),\n        )\n    }\n\n    fn update(&mut self, message: Message, now: Instant) -> Task<Message> {\n        self.now = now;\n\n        match message {\n            Message::Edit(action) => {\n                let is_edit = action.is_edit();\n\n                self.raw.perform(action);\n\n                if is_edit {\n                    self.content = markdown::Content::parse(&self.raw.text());\n                    self.mode = Mode::Preview;\n                }\n\n                Task::none()\n            }\n            Message::Copy(content) => clipboard::write(content).discard(),\n            Message::LinkClicked(link) => {\n                let _ = webbrowser::open(&link);\n                Task::none()\n            }\n            Message::ImageShown(uri) => {\n                if self.images.contains_key(&uri) {\n                    return Task::none();\n                }\n\n                let _ = self.images.insert(uri.clone(), Image::Loading);\n\n                Task::perform(\n                    download_image(uri.clone()),\n                    Message::ImageDownloaded.with(uri),\n                )\n            }\n            Message::ImageDownloaded(url, result) => {\n                let _ = self.images.insert(\n                    url,\n                    result\n                        .map(|handle| Image::Ready {\n                            handle,\n                            fade_in: Animation::new(false)\n                                .quick()\n                                .easing(animation::Easing::EaseInOut)\n                                .go(true, self.now),\n                        })\n                        .unwrap_or_else(Image::Errored),\n                );\n\n                Task::none()\n            }\n            Message::ToggleStream(enable_stream) => {\n                if enable_stream {\n                    self.content = markdown::Content::new();\n\n                    self.mode = Mode::Stream {\n                        pending: self.raw.text(),\n                    };\n\n                    operation::snap_to_end(\"preview\")\n                } else {\n                    self.mode = Mode::Preview;\n\n                    Task::none()\n                }\n            }\n            Message::NextToken => {\n                match &mut self.mode {\n                    Mode::Preview => {}\n                    Mode::Stream { pending } => {\n                        if pending.is_empty() {\n                            self.mode = Mode::Preview;\n                        } else {\n                            let mut tokens = pending.split(' ');\n\n                            if let Some(token) = tokens.next() {\n                                self.content.push_str(&format!(\"{token} \"));\n                            }\n\n                            *pending = tokens.collect::<Vec<_>>().join(\" \");\n                        }\n                    }\n                }\n\n                Task::none()\n            }\n            Message::Tick => Task::none(),\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let editor = text_editor(&self.raw)\n            .placeholder(\"Type your Markdown here...\")\n            .on_action(Message::Edit)\n            .height(Fill)\n            .padding(10)\n            .font(Font::MONOSPACE)\n            .highlight(\"markdown\", highlighter::Theme::Base16Ocean);\n\n        let preview = markdown::view_with(\n            self.content.items(),\n            &self.theme,\n            &CustomViewer {\n                images: &self.images,\n                now: self.now,\n            },\n        );\n\n        row![\n            editor,\n            hover(\n                scrollable(preview)\n                    .spacing(10)\n                    .width(Fill)\n                    .height(Fill)\n                    .id(\"preview\"),\n                right(\n                    toggler(matches!(self.mode, Mode::Stream { .. }))\n                        .label(\"Stream\")\n                        .on_toggle(Message::ToggleStream)\n                )\n                .padding([0, 20])\n            )\n        ]\n        .spacing(10)\n        .padding(10)\n        .into()\n    }\n\n    fn theme(&self) -> Theme {\n        self.theme.clone()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        let listen_stream = match self.mode {\n            Mode::Preview => Subscription::none(),\n            Mode::Stream { .. } => time::every(milliseconds(10)).map(|_| Message::NextToken),\n        };\n\n        let animate = {\n            let is_animating = self.images.values().any(|image| match image {\n                Image::Ready { fade_in, .. } => fade_in.is_animating(self.now),\n                _ => false,\n            });\n\n            if is_animating {\n                window::frames().map(|_| Message::Tick)\n            } else {\n                Subscription::none()\n            }\n        };\n\n        Subscription::batch([listen_stream, animate])\n    }\n}\n\nstruct CustomViewer<'a> {\n    images: &'a HashMap<markdown::Uri, Image>,\n    now: Instant,\n}\n\nimpl<'a> markdown::Viewer<'a, Message> for CustomViewer<'a> {\n    fn on_link_click(url: markdown::Uri) -> Message {\n        Message::LinkClicked(url)\n    }\n\n    fn image(\n        &self,\n        _settings: markdown::Settings,\n        url: &'a markdown::Uri,\n        _title: &'a str,\n        _alt: &markdown::Text,\n    ) -> Element<'a, Message> {\n        if let Some(Image::Ready { handle, fade_in }) = self.images.get(url) {\n            center_x(\n                image(handle)\n                    .opacity(fade_in.interpolate(0.0, 1.0, self.now))\n                    .scale(fade_in.interpolate(1.2, 1.0, self.now)),\n            )\n            .into()\n        } else {\n            sensor(space())\n                .key_ref(url.as_str())\n                .delay(milliseconds(500))\n                .on_show(|_size| Message::ImageShown(url.clone()))\n                .into()\n        }\n    }\n\n    fn code_block(\n        &self,\n        settings: markdown::Settings,\n        _language: Option<&'a str>,\n        code: &'a str,\n        lines: &'a [markdown::Text],\n    ) -> Element<'a, Message> {\n        let code_block = markdown::code_block(settings, lines, Message::LinkClicked);\n\n        let copy = button(icon::copy().size(12))\n            .padding(2)\n            .on_press_with(|| Message::Copy(code.to_owned()))\n            .style(button::text);\n\n        hover(\n            code_block,\n            right(container(copy).style(container::dark)).padding(settings.spacing / 2),\n        )\n    }\n}\n\nasync fn download_image(uri: markdown::Uri) -> Result<image::Handle, Error> {\n    use std::io;\n    use tokio::task;\n    use url::Url;\n\n    let bytes = match Url::parse(&uri) {\n        Ok(url) if url.scheme() == \"http\" || url.scheme() == \"https\" => {\n            println!(\"Trying to download image: {url}\");\n\n            let client = reqwest::Client::new();\n\n            client\n                .get(url)\n                .send()\n                .await?\n                .error_for_status()?\n                .bytes()\n                .await?\n        }\n        _ => {\n            return Err(Error::IOFailed(Arc::new(io::Error::other(format!(\n                \"unsupported uri: {uri}\"\n            )))));\n        }\n    };\n\n    let image = task::spawn_blocking(move || {\n        Ok::<_, Error>(\n            ::image::ImageReader::new(io::Cursor::new(bytes))\n                .with_guessed_format()?\n                .decode()?\n                .to_rgba8(),\n        )\n    })\n    .await??;\n\n    Ok(image::Handle::from_rgba(\n        image.width(),\n        image.height(),\n        image.into_raw(),\n    ))\n}\n\n#[derive(Debug, Clone)]\npub enum Error {\n    RequestFailed(Arc<reqwest::Error>),\n    IOFailed(Arc<io::Error>),\n    JoinFailed(Arc<tokio::task::JoinError>),\n    ImageDecodingFailed(Arc<::image::ImageError>),\n}\n\nimpl From<reqwest::Error> for Error {\n    fn from(error: reqwest::Error) -> Self {\n        Self::RequestFailed(Arc::new(error))\n    }\n}\n\nimpl From<io::Error> for Error {\n    fn from(error: io::Error) -> Self {\n        Self::IOFailed(Arc::new(error))\n    }\n}\n\nimpl From<tokio::task::JoinError> for Error {\n    fn from(error: tokio::task::JoinError) -> Self {\n        Self::JoinFailed(Arc::new(error))\n    }\n}\n\nimpl From<::image::ImageError> for Error {\n    fn from(error: ::image::ImageError) -> Self {\n        Self::ImageDecodingFailed(Arc::new(error))\n    }\n}\n"
  },
  {
    "path": "examples/modal/Cargo.toml",
    "content": "[package]\nname = \"modal\"\nversion = \"0.1.0\"\nauthors = [\"tarkah <admin@tarkah.dev>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"advanced\"]\n"
  },
  {
    "path": "examples/modal/src/main.rs",
    "content": "use iced::event::{self, Event};\nuse iced::keyboard;\nuse iced::keyboard::key;\nuse iced::widget::{\n    button, center, column, container, mouse_area, opaque, operation, pick_list, row, space, stack,\n    text, text_input,\n};\nuse iced::{Bottom, Color, Element, Fill, Subscription, Task};\n\nuse std::fmt;\n\npub fn main() -> iced::Result {\n    iced::application(App::default, App::update, App::view)\n        .subscription(App::subscription)\n        .run()\n}\n\n#[derive(Default)]\nstruct App {\n    show_modal: bool,\n    email: String,\n    password: String,\n    plan: Plan,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    ShowModal,\n    HideModal,\n    Email(String),\n    Password(String),\n    Plan(Plan),\n    Submit,\n    Event(Event),\n}\n\nimpl App {\n    fn subscription(&self) -> Subscription<Message> {\n        event::listen().map(Message::Event)\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::ShowModal => {\n                self.show_modal = true;\n                operation::focus_next()\n            }\n            Message::HideModal => {\n                self.hide_modal();\n                Task::none()\n            }\n            Message::Email(email) => {\n                self.email = email;\n                Task::none()\n            }\n            Message::Password(password) => {\n                self.password = password;\n                Task::none()\n            }\n            Message::Plan(plan) => {\n                self.plan = plan;\n                Task::none()\n            }\n            Message::Submit => {\n                if !self.email.is_empty() && !self.password.is_empty() {\n                    self.hide_modal();\n                }\n\n                Task::none()\n            }\n            Message::Event(event) => match event {\n                Event::Keyboard(keyboard::Event::KeyPressed {\n                    key: keyboard::Key::Named(key::Named::Tab),\n                    modifiers,\n                    ..\n                }) => {\n                    if modifiers.shift() {\n                        operation::focus_previous()\n                    } else {\n                        operation::focus_next()\n                    }\n                }\n                Event::Keyboard(keyboard::Event::KeyPressed {\n                    key: keyboard::Key::Named(key::Named::Escape),\n                    ..\n                }) => {\n                    self.hide_modal();\n                    Task::none()\n                }\n                _ => Task::none(),\n            },\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let content = container(\n            column![\n                row![text(\"Top Left\"), space::horizontal(), text(\"Top Right\")].height(Fill),\n                center(button(text(\"Show Modal\")).on_press(Message::ShowModal)),\n                row![\n                    text(\"Bottom Left\"),\n                    space::horizontal(),\n                    text(\"Bottom Right\")\n                ]\n                .align_y(Bottom)\n                .height(Fill),\n            ]\n            .height(Fill),\n        )\n        .padding(10);\n\n        if self.show_modal {\n            let signup = container(\n                column![\n                    text(\"Sign Up\").size(24),\n                    column![\n                        column![\n                            text(\"Email\").size(12),\n                            text_input(\"abc@123.com\", &self.email,)\n                                .on_input(Message::Email)\n                                .on_submit(Message::Submit)\n                                .padding(5),\n                        ]\n                        .spacing(5),\n                        column![\n                            text(\"Password\").size(12),\n                            text_input(\"\", &self.password)\n                                .on_input(Message::Password)\n                                .on_submit(Message::Submit)\n                                .secure(true)\n                                .padding(5),\n                        ]\n                        .spacing(5),\n                        column![\n                            text(\"Plan\").size(12),\n                            pick_list(Some(self.plan), Plan::ALL, Plan::to_string)\n                                .on_select(Message::Plan)\n                                .padding(5),\n                        ]\n                        .spacing(5),\n                        button(text(\"Submit\")).on_press(Message::HideModal),\n                    ]\n                    .spacing(10)\n                ]\n                .spacing(20),\n            )\n            .width(300)\n            .padding(10)\n            .style(container::rounded_box);\n\n            modal(content, signup, Message::HideModal)\n        } else {\n            content.into()\n        }\n    }\n}\n\nimpl App {\n    fn hide_modal(&mut self) {\n        self.show_modal = false;\n        self.email.clear();\n        self.password.clear();\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\nenum Plan {\n    #[default]\n    Basic,\n    Pro,\n    Enterprise,\n}\n\nimpl Plan {\n    pub const ALL: &'static [Self] = &[Self::Basic, Self::Pro, Self::Enterprise];\n}\n\nimpl fmt::Display for Plan {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Plan::Basic => \"Basic\",\n            Plan::Pro => \"Pro\",\n            Plan::Enterprise => \"Enterprise\",\n        }\n        .fmt(f)\n    }\n}\n\nfn modal<'a, Message>(\n    base: impl Into<Element<'a, Message>>,\n    content: impl Into<Element<'a, Message>>,\n    on_blur: Message,\n) -> Element<'a, Message>\nwhere\n    Message: Clone + 'a,\n{\n    stack![\n        base.into(),\n        opaque(\n            mouse_area(center(opaque(content)).style(|_theme| {\n                container::Style {\n                    background: Some(\n                        Color {\n                            a: 0.8,\n                            ..Color::BLACK\n                        }\n                        .into(),\n                    ),\n                    ..container::Style::default()\n                }\n            }))\n            .on_press(on_blur)\n        )\n    ]\n    .into()\n}\n"
  },
  {
    "path": "examples/multi_window/Cargo.toml",
    "content": "[package]\nname = \"multi_window\"\nversion = \"0.1.0\"\nauthors = [\"Bingus <shankern@protonmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced = { path = \"../..\", features = [\"debug\"] }\n"
  },
  {
    "path": "examples/multi_window/src/main.rs",
    "content": "use iced::widget::{\n    button, center, center_x, column, container, operation, scrollable, space, text, text_input,\n};\nuse iced::window;\nuse iced::{Center, Element, Fill, Function, Subscription, Task, Theme, Vector};\n\nuse std::collections::BTreeMap;\n\nfn main() -> iced::Result {\n    iced::daemon(Example::new, Example::update, Example::view)\n        .subscription(Example::subscription)\n        .title(Example::title)\n        .theme(Example::theme)\n        .scale_factor(Example::scale_factor)\n        .run()\n}\n\nstruct Example {\n    windows: BTreeMap<window::Id, Window>,\n}\n\n#[derive(Debug)]\nstruct Window {\n    title: String,\n    scale_input: String,\n    current_scale: f32,\n    theme: Theme,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    OpenWindow,\n    WindowOpened(window::Id),\n    WindowClosed(window::Id),\n    ScaleInputChanged(window::Id, String),\n    ScaleChanged(window::Id, String),\n    TitleChanged(window::Id, String),\n}\n\nimpl Example {\n    fn new() -> (Self, Task<Message>) {\n        let (_, open) = window::open(window::Settings::default());\n\n        (\n            Self {\n                windows: BTreeMap::new(),\n            },\n            open.map(Message::WindowOpened),\n        )\n    }\n\n    fn title(&self, window: window::Id) -> String {\n        self.windows\n            .get(&window)\n            .map(|window| window.title.clone())\n            .unwrap_or_default()\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::OpenWindow => {\n                let Some(last_window) = self.windows.keys().last() else {\n                    return Task::none();\n                };\n\n                window::position(*last_window)\n                    .then(|last_position| {\n                        let position =\n                            last_position.map_or(window::Position::Default, |last_position| {\n                                window::Position::Specific(last_position + Vector::new(20.0, 20.0))\n                            });\n\n                        let (_, open) = window::open(window::Settings {\n                            position,\n                            ..window::Settings::default()\n                        });\n\n                        open\n                    })\n                    .map(Message::WindowOpened)\n            }\n            Message::WindowOpened(id) => {\n                let window = Window::new(self.windows.len() + 1);\n                let focus_input = operation::focus(format!(\"input-{id}\"));\n\n                self.windows.insert(id, window);\n\n                focus_input\n            }\n            Message::WindowClosed(id) => {\n                self.windows.remove(&id);\n\n                if self.windows.is_empty() {\n                    iced::exit()\n                } else {\n                    Task::none()\n                }\n            }\n            Message::ScaleInputChanged(id, scale) => {\n                if let Some(window) = self.windows.get_mut(&id) {\n                    window.scale_input = scale;\n                }\n\n                Task::none()\n            }\n            Message::ScaleChanged(id, scale) => {\n                if let Some(window) = self.windows.get_mut(&id) {\n                    window.current_scale = scale\n                        .parse()\n                        .unwrap_or(window.current_scale)\n                        .clamp(0.5, 5.0);\n                }\n\n                Task::none()\n            }\n            Message::TitleChanged(id, title) => {\n                if let Some(window) = self.windows.get_mut(&id) {\n                    window.title = title;\n                }\n\n                Task::none()\n            }\n        }\n    }\n\n    fn view(&self, window_id: window::Id) -> Element<'_, Message> {\n        if let Some(window) = self.windows.get(&window_id) {\n            center(window.view(window_id)).into()\n        } else {\n            space().into()\n        }\n    }\n\n    fn theme(&self, window: window::Id) -> Option<Theme> {\n        Some(self.windows.get(&window)?.theme.clone())\n    }\n\n    fn scale_factor(&self, window: window::Id) -> f32 {\n        self.windows\n            .get(&window)\n            .map(|window| window.current_scale)\n            .unwrap_or(1.0)\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        window::close_events().map(Message::WindowClosed)\n    }\n}\n\nimpl Window {\n    fn new(count: usize) -> Self {\n        Self {\n            title: format!(\"Window_{count}\"),\n            scale_input: \"1.0\".to_string(),\n            current_scale: 1.0,\n            theme: Theme::ALL[count % Theme::ALL.len()].clone(),\n        }\n    }\n\n    fn view(&self, id: window::Id) -> Element<'_, Message> {\n        let scale_input = column![\n            text(\"Window scale factor:\"),\n            text_input(\"Window Scale\", &self.scale_input)\n                .on_input(Message::ScaleInputChanged.with(id))\n                .on_submit(Message::ScaleChanged(id, self.scale_input.to_string()))\n        ];\n\n        let title_input = column![\n            text(\"Window title:\"),\n            text_input(\"Window Title\", &self.title)\n                .on_input(Message::TitleChanged.with(id))\n                .id(format!(\"input-{id}\"))\n        ];\n\n        let new_window_button = button(text(\"New Window\")).on_press(Message::OpenWindow);\n\n        let content = column![scale_input, title_input, new_window_button]\n            .spacing(50)\n            .width(Fill)\n            .align_x(Center)\n            .width(200);\n\n        container(scrollable(center_x(content))).padding(10).into()\n    }\n}\n"
  },
  {
    "path": "examples/multitouch/Cargo.toml",
    "content": "[package]\nname = \"multitouch\"\nversion = \"0.1.0\"\nauthors = [\"Artur Sapek <artur@kraken.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"canvas\", \"tokio\"]\n\ntracing-subscriber = \"0.3\"\nvoronator = \"0.2\"\n"
  },
  {
    "path": "examples/multitouch/src/main.rs",
    "content": "//! This example shows how to use touch events in `Canvas` to draw\n//! a circle around each fingertip. This only works on touch-enabled\n//! computers like Microsoft Surface.\nuse iced::mouse;\nuse iced::touch;\nuse iced::widget::canvas::stroke::{self, Stroke};\nuse iced::widget::canvas::{self, Canvas, Event, Geometry};\nuse iced::{Color, Element, Fill, Point, Rectangle, Renderer, Theme};\n\nuse std::collections::HashMap;\n\npub fn main() -> iced::Result {\n    tracing_subscriber::fmt::init();\n\n    iced::application(Multitouch::default, Multitouch::update, Multitouch::view)\n        .centered()\n        .run()\n}\n\n#[derive(Default)]\nstruct Multitouch {\n    cache: canvas::Cache,\n    fingers: HashMap<touch::Finger, Point>,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    FingerPressed { id: touch::Finger, position: Point },\n    FingerLifted { id: touch::Finger },\n}\n\nimpl Multitouch {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::FingerPressed { id, position } => {\n                self.fingers.insert(id, position);\n                self.cache.clear();\n            }\n            Message::FingerLifted { id } => {\n                self.fingers.remove(&id);\n                self.cache.clear();\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        Canvas::new(self).width(Fill).height(Fill).into()\n    }\n}\n\nimpl canvas::Program<Message> for Multitouch {\n    type State = ();\n\n    fn update(\n        &self,\n        _state: &mut Self::State,\n        event: &Event,\n        _bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Option<canvas::Action<Message>> {\n        let message = match event.clone() {\n            Event::Touch(\n                touch::Event::FingerPressed { id, position }\n                | touch::Event::FingerMoved { id, position },\n            ) => Some(Message::FingerPressed { id, position }),\n            Event::Touch(\n                touch::Event::FingerLifted { id, .. } | touch::Event::FingerLost { id, .. },\n            ) => Some(Message::FingerLifted { id }),\n            _ => None,\n        };\n\n        message\n            .map(canvas::Action::publish)\n            .map(canvas::Action::and_capture)\n    }\n\n    fn draw(\n        &self,\n        _state: &Self::State,\n        renderer: &Renderer,\n        _theme: &Theme,\n        bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Vec<Geometry> {\n        let fingerweb = self.cache.draw(renderer, bounds.size(), |frame| {\n            if self.fingers.len() < 2 {\n                return;\n            }\n\n            // Collect tuples of (id, point);\n            let mut zones: Vec<(u64, Point)> =\n                self.fingers.iter().map(|(id, pt)| (id.0, *pt)).collect();\n\n            // Sort by ID\n            zones.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());\n\n            // Generate sorted list of points\n            let vpoints: Vec<(f64, f64)> = zones\n                .iter()\n                .map(|(_, p)| (f64::from(p.x), f64::from(p.y)))\n                .collect();\n\n            let diagram: voronator::VoronoiDiagram<voronator::delaunator::Point> =\n                voronator::VoronoiDiagram::from_tuple(&(0.0, 0.0), &(700.0, 700.0), &vpoints)\n                    .expect(\"Generate Voronoi diagram\");\n\n            for (cell, zone) in diagram.cells().iter().zip(zones) {\n                let mut builder = canvas::path::Builder::new();\n\n                for (index, p) in cell.points().iter().enumerate() {\n                    let p = Point::new(p.x as f32, p.y as f32);\n\n                    match index {\n                        0 => builder.move_to(p),\n                        _ => builder.line_to(p),\n                    }\n                }\n\n                let path = builder.build();\n\n                let color_r = (10 % (zone.0 + 1)) as f32 / 20.0;\n                let color_g = (10 % (zone.0 + 8)) as f32 / 20.0;\n                let color_b = (10 % (zone.0 + 3)) as f32 / 20.0;\n\n                frame.fill(\n                    &path,\n                    Color {\n                        r: color_r,\n                        g: color_g,\n                        b: color_b,\n                        a: 1.0,\n                    },\n                );\n\n                frame.stroke(\n                    &path,\n                    Stroke {\n                        style: stroke::Style::Solid(Color::BLACK),\n                        width: 3.0,\n                        ..Stroke::default()\n                    },\n                );\n            }\n        });\n\n        vec![fingerweb]\n    }\n}\n"
  },
  {
    "path": "examples/pane_grid/Cargo.toml",
    "content": "[package]\nname = \"pane_grid\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\"]\n"
  },
  {
    "path": "examples/pane_grid/README.md",
    "content": "## Pane grid\n\nA grid of panes that can be split, resized, and reorganized.\n\nThis example showcases the `PaneGrid` widget, which features:\n\n* Vertical and horizontal splits\n* Tracking of the last active pane\n* Mouse-based resizing\n* Drag and drop to reorganize panes\n* Hotkey support\n* Configurable modifier keys\n* API to perform actions programmatically (`split`, `swap`, `resize`, etc.)\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/pane_grid.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package pane_grid\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/pane_grid/src/main.rs",
    "content": "use iced::keyboard;\nuse iced::widget::pane_grid::{self, PaneGrid};\nuse iced::widget::{button, center_y, column, container, responsive, row, scrollable, text};\nuse iced::{Center, Color, Element, Fill, Size, Subscription};\n\npub fn main() -> iced::Result {\n    iced::application(Example::default, Example::update, Example::view)\n        .subscription(Example::subscription)\n        .run()\n}\n\nstruct Example {\n    panes: pane_grid::State<Pane>,\n    panes_created: usize,\n    focus: Option<pane_grid::Pane>,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Split(pane_grid::Axis, pane_grid::Pane),\n    SplitFocused(pane_grid::Axis),\n    FocusAdjacent(pane_grid::Direction),\n    Clicked(pane_grid::Pane),\n    Dragged(pane_grid::DragEvent),\n    Resized(pane_grid::ResizeEvent),\n    TogglePin(pane_grid::Pane),\n    Maximize(pane_grid::Pane),\n    Restore,\n    Close(pane_grid::Pane),\n    CloseFocused,\n}\n\nimpl Example {\n    fn new() -> Self {\n        let (panes, _) = pane_grid::State::new(Pane::new(0));\n\n        Example {\n            panes,\n            panes_created: 1,\n            focus: None,\n        }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Split(axis, pane) => {\n                let result = self.panes.split(axis, pane, Pane::new(self.panes_created));\n\n                if let Some((pane, _)) = result {\n                    self.focus = Some(pane);\n                }\n\n                self.panes_created += 1;\n            }\n            Message::SplitFocused(axis) => {\n                if let Some(pane) = self.focus {\n                    let result = self.panes.split(axis, pane, Pane::new(self.panes_created));\n\n                    if let Some((pane, _)) = result {\n                        self.focus = Some(pane);\n                    }\n\n                    self.panes_created += 1;\n                }\n            }\n            Message::FocusAdjacent(direction) => {\n                if let Some(pane) = self.focus\n                    && let Some(adjacent) = self.panes.adjacent(pane, direction)\n                {\n                    self.focus = Some(adjacent);\n                }\n            }\n            Message::Clicked(pane) => {\n                self.focus = Some(pane);\n            }\n            Message::Resized(pane_grid::ResizeEvent { split, ratio }) => {\n                self.panes.resize(split, ratio);\n            }\n            Message::Dragged(pane_grid::DragEvent::Dropped { pane, target }) => {\n                self.panes.drop(pane, target);\n            }\n            Message::Dragged(_) => {}\n            Message::TogglePin(pane) => {\n                if let Some(Pane { is_pinned, .. }) = self.panes.get_mut(pane) {\n                    *is_pinned = !*is_pinned;\n                }\n            }\n            Message::Maximize(pane) => self.panes.maximize(pane),\n            Message::Restore => {\n                self.panes.restore();\n            }\n            Message::Close(pane) => {\n                if let Some((_, sibling)) = self.panes.close(pane) {\n                    self.focus = Some(sibling);\n                }\n            }\n            Message::CloseFocused => {\n                if let Some(pane) = self.focus\n                    && let Some(Pane { is_pinned, .. }) = self.panes.get(pane)\n                    && !is_pinned\n                    && let Some((_, sibling)) = self.panes.close(pane)\n                {\n                    self.focus = Some(sibling);\n                }\n            }\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        keyboard::listen().filter_map(|event| {\n            let keyboard::Event::KeyPressed { key, modifiers, .. } = event else {\n                return None;\n            };\n\n            if !modifiers.command() {\n                return None;\n            }\n\n            handle_hotkey(key)\n        })\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let focus = self.focus;\n        let total_panes = self.panes.len();\n\n        let pane_grid = PaneGrid::new(&self.panes, |id, pane, is_maximized| {\n            let is_focused = focus == Some(id);\n\n            let pin_button = button(text(if pane.is_pinned { \"Unpin\" } else { \"Pin\" }).size(14))\n                .on_press(Message::TogglePin(id))\n                .padding(3);\n\n            let title = row![\n                pin_button,\n                \"Pane\",\n                text(pane.id.to_string()).color(if is_focused {\n                    PANE_ID_COLOR_FOCUSED\n                } else {\n                    PANE_ID_COLOR_UNFOCUSED\n                }),\n            ]\n            .spacing(5);\n\n            let title_bar = pane_grid::TitleBar::new(title)\n                .controls(pane_grid::Controls::dynamic(\n                    view_controls(id, total_panes, pane.is_pinned, is_maximized),\n                    button(text(\"X\").size(14))\n                        .style(button::danger)\n                        .padding(3)\n                        .on_press_maybe(if total_panes > 1 && !pane.is_pinned {\n                            Some(Message::Close(id))\n                        } else {\n                            None\n                        }),\n                ))\n                .padding(10)\n                .style(if is_focused {\n                    style::title_bar_focused\n                } else {\n                    style::title_bar_active\n                });\n\n            pane_grid::Content::new(responsive(move |size| {\n                view_content(id, total_panes, pane.is_pinned, size)\n            }))\n            .title_bar(title_bar)\n            .style(if is_focused {\n                style::pane_focused\n            } else {\n                style::pane_active\n            })\n        })\n        .width(Fill)\n        .height(Fill)\n        .spacing(10)\n        .on_click(Message::Clicked)\n        .on_drag(Message::Dragged)\n        .on_resize(10, Message::Resized);\n\n        container(pane_grid).padding(10).into()\n    }\n}\n\nimpl Default for Example {\n    fn default() -> Self {\n        Example::new()\n    }\n}\n\nconst PANE_ID_COLOR_UNFOCUSED: Color = Color::from_rgb(\n    0xFF as f32 / 255.0,\n    0xC7 as f32 / 255.0,\n    0xC7 as f32 / 255.0,\n);\nconst PANE_ID_COLOR_FOCUSED: Color = Color::from_rgb(\n    0xFF as f32 / 255.0,\n    0x47 as f32 / 255.0,\n    0x47 as f32 / 255.0,\n);\n\nfn handle_hotkey(key: keyboard::Key) -> Option<Message> {\n    use keyboard::key::{self, Key};\n    use pane_grid::{Axis, Direction};\n\n    match key.as_ref() {\n        Key::Character(\"v\") => Some(Message::SplitFocused(Axis::Vertical)),\n        Key::Character(\"h\") => Some(Message::SplitFocused(Axis::Horizontal)),\n        Key::Character(\"w\") => Some(Message::CloseFocused),\n        Key::Named(key) => {\n            let direction = match key {\n                key::Named::ArrowUp => Some(Direction::Up),\n                key::Named::ArrowDown => Some(Direction::Down),\n                key::Named::ArrowLeft => Some(Direction::Left),\n                key::Named::ArrowRight => Some(Direction::Right),\n                _ => None,\n            };\n\n            direction.map(Message::FocusAdjacent)\n        }\n        _ => None,\n    }\n}\n\n#[derive(Clone, Copy)]\nstruct Pane {\n    id: usize,\n    pub is_pinned: bool,\n}\n\nimpl Pane {\n    fn new(id: usize) -> Self {\n        Self {\n            id,\n            is_pinned: false,\n        }\n    }\n}\n\nfn view_content<'a>(\n    pane: pane_grid::Pane,\n    total_panes: usize,\n    is_pinned: bool,\n    size: Size,\n) -> Element<'a, Message> {\n    let button = |label, message| {\n        button(text(label).width(Fill).align_x(Center).size(16))\n            .width(Fill)\n            .padding(8)\n            .on_press(message)\n    };\n\n    let controls = column![\n        button(\n            \"Split horizontally\",\n            Message::Split(pane_grid::Axis::Horizontal, pane),\n        ),\n        button(\n            \"Split vertically\",\n            Message::Split(pane_grid::Axis::Vertical, pane),\n        ),\n        if total_panes > 1 && !is_pinned {\n            Some(button(\"Close\", Message::Close(pane)).style(button::danger))\n        } else {\n            None\n        }\n    ]\n    .spacing(5)\n    .max_width(160);\n\n    let content = column![text!(\"{}x{}\", size.width, size.height).size(24), controls,]\n        .spacing(10)\n        .align_x(Center);\n\n    center_y(scrollable(content)).padding(5).into()\n}\n\nfn view_controls<'a>(\n    pane: pane_grid::Pane,\n    total_panes: usize,\n    is_pinned: bool,\n    is_maximized: bool,\n) -> Element<'a, Message> {\n    let maximize = if total_panes > 1 {\n        let (content, message) = if is_maximized {\n            (\"Restore\", Message::Restore)\n        } else {\n            (\"Maximize\", Message::Maximize(pane))\n        };\n\n        Some(\n            button(text(content).size(14))\n                .style(button::secondary)\n                .padding(3)\n                .on_press(message),\n        )\n    } else {\n        None\n    };\n\n    let close = button(text(\"Close\").size(14))\n        .style(button::danger)\n        .padding(3)\n        .on_press_maybe(if total_panes > 1 && !is_pinned {\n            Some(Message::Close(pane))\n        } else {\n            None\n        });\n\n    row![maximize, close].spacing(5).into()\n}\n\nmod style {\n    use iced::widget::container;\n    use iced::{Border, Theme};\n\n    pub fn title_bar_active(theme: &Theme) -> container::Style {\n        let palette = theme.palette();\n\n        container::Style {\n            text_color: Some(palette.background.strong.text),\n            background: Some(palette.background.strong.color.into()),\n            ..Default::default()\n        }\n    }\n\n    pub fn title_bar_focused(theme: &Theme) -> container::Style {\n        let palette = theme.palette();\n\n        container::Style {\n            text_color: Some(palette.primary.strong.text),\n            background: Some(palette.primary.strong.color.into()),\n            ..Default::default()\n        }\n    }\n\n    pub fn pane_active(theme: &Theme) -> container::Style {\n        let palette = theme.palette();\n\n        container::Style {\n            background: Some(palette.background.weak.color.into()),\n            border: Border {\n                width: 2.0,\n                color: palette.background.strong.color,\n                ..Border::default()\n            },\n            ..Default::default()\n        }\n    }\n\n    pub fn pane_focused(theme: &Theme) -> container::Style {\n        let palette = theme.palette();\n\n        container::Style {\n            background: Some(palette.background.weak.color.into()),\n            border: Border {\n                width: 2.0,\n                color: palette.primary.strong.color,\n                ..Border::default()\n            },\n            ..Default::default()\n        }\n    }\n}\n"
  },
  {
    "path": "examples/pick_list/Cargo.toml",
    "content": "[package]\nname = \"pick_list\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\"]\n"
  },
  {
    "path": "examples/pick_list/README.md",
    "content": "## Pick-list\n\nA dropdown list of selectable options.\n\nIt displays and positions an overlay based on the window position of the widget.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://user-images.githubusercontent.com/518289/87125075-2c232e80-c28a-11ea-95c2-769c610b8843.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package pick_list\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/pick_list/src/main.rs",
    "content": "use iced::widget::{column, pick_list, scrollable, space};\nuse iced::{Center, Element, Fill};\n\npub fn main() -> iced::Result {\n    iced::run(Example::update, Example::view)\n}\n\n#[derive(Default)]\nstruct Example {\n    selected_language: Option<Language>,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    LanguageSelected(Language),\n}\n\nimpl Example {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::LanguageSelected(language) => {\n                self.selected_language = Some(language);\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let languages = pick_list(self.selected_language, Language::ALL, Language::to_string)\n            .on_select(Message::LanguageSelected)\n            .placeholder(\"Choose a language...\");\n\n        let content = column![\n            space().height(600),\n            \"Which is your favorite language?\",\n            languages,\n            space().height(600),\n        ]\n        .width(Fill)\n        .align_x(Center)\n        .spacing(10);\n\n        scrollable(content).into()\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum Language {\n    #[default]\n    Rust,\n    Elm,\n    Ruby,\n    Haskell,\n    C,\n    Javascript,\n    Other,\n}\n\nimpl Language {\n    const ALL: &[Language] = &[\n        Language::C,\n        Language::Elm,\n        Language::Ruby,\n        Language::Haskell,\n        Language::Rust,\n        Language::Javascript,\n        Language::Other,\n    ];\n}\n\nimpl std::fmt::Display for Language {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"{}\",\n            match self {\n                Language::Rust => \"Rust\",\n                Language::Elm => \"Elm\",\n                Language::Ruby => \"Ruby\",\n                Language::Haskell => \"Haskell\",\n                Language::C => \"C\",\n                Language::Javascript => \"Javascript\",\n                Language::Other => \"Some other language\",\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "examples/pokedex/Cargo.toml",
    "content": "[package]\nname = \"pokedex\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"image\", \"debug\", \"tokio\"]\n\nserde_json = \"1.0\"\n\n[dependencies.serde]\nversion = \"1.0\"\nfeatures = [\"derive\"]\n\n[dependencies.reqwest]\nversion = \"0.12\"\nfeatures = [\"json\"]\n\n[dependencies.rand]\nversion = \"0.8\"\n\n[dependencies.getrandom]\nversion = \"0.2\"\nfeatures = [\"js\"]\n"
  },
  {
    "path": "examples/pokedex/README.md",
    "content": "# Pokédex\nAn application that loads a random Pokédex entry using the [PokéAPI].\n\nAll the example code can be found in the __[`main`](src/main.rs)__ file.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/pokedex.gif\">\n</div>\n\nYou can run it on native platforms with `cargo run`:\n```\ncargo run --package pokedex\n```\n\n[PokéAPI]: https://pokeapi.co/\n"
  },
  {
    "path": "examples/pokedex/src/main.rs",
    "content": "use iced::futures;\nuse iced::widget::{self, center, column, image, row, text};\nuse iced::{Center, Element, Fill, Right, Task};\n\npub fn main() -> iced::Result {\n    iced::application(Pokedex::new, Pokedex::update, Pokedex::view)\n        .title(Pokedex::title)\n        .run()\n}\n\n#[derive(Debug)]\nenum Pokedex {\n    Loading,\n    Loaded { pokemon: Pokemon },\n    Errored,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    PokemonFound(Result<Pokemon, Error>),\n    Search,\n}\n\nimpl Pokedex {\n    fn new() -> (Self, Task<Message>) {\n        (Self::Loading, Self::search())\n    }\n\n    fn search() -> Task<Message> {\n        Task::perform(Pokemon::search(), Message::PokemonFound)\n    }\n\n    fn title(&self) -> String {\n        let subtitle = match self {\n            Pokedex::Loading => \"Loading\",\n            Pokedex::Loaded { pokemon, .. } => &pokemon.name,\n            Pokedex::Errored => \"Whoops!\",\n        };\n\n        format!(\"{subtitle} - Pokédex\")\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::PokemonFound(Ok(pokemon)) => {\n                *self = Pokedex::Loaded { pokemon };\n\n                Task::none()\n            }\n            Message::PokemonFound(Err(_error)) => {\n                *self = Pokedex::Errored;\n\n                Task::none()\n            }\n            Message::Search => match self {\n                Pokedex::Loading => Task::none(),\n                _ => {\n                    *self = Pokedex::Loading;\n\n                    Self::search()\n                }\n            },\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let content: Element<_> = match self {\n            Pokedex::Loading => text(\"Searching for Pokémon...\").size(40).into(),\n            Pokedex::Loaded { pokemon } => column![\n                pokemon.view(),\n                button(\"Keep searching!\").on_press(Message::Search)\n            ]\n            .max_width(500)\n            .spacing(20)\n            .align_x(Right)\n            .into(),\n            Pokedex::Errored => column![\n                text(\"Whoops! Something went wrong...\").size(40),\n                button(\"Try again\").on_press(Message::Search)\n            ]\n            .spacing(20)\n            .align_x(Right)\n            .into(),\n        };\n\n        center(content).into()\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct Pokemon {\n    number: u16,\n    name: String,\n    description: String,\n    image: image::Handle,\n}\n\nimpl Pokemon {\n    const TOTAL: u16 = 807;\n\n    fn view(&self) -> Element<'_, Message> {\n        row![\n            image::viewer(self.image.clone()),\n            column![\n                row![\n                    text(&self.name).size(30).width(Fill),\n                    text!(\"#{}\", self.number).size(20).color([0.5, 0.5, 0.5]),\n                ]\n                .align_y(Center)\n                .spacing(20),\n                self.description.as_ref(),\n            ]\n            .spacing(20),\n        ]\n        .spacing(20)\n        .align_y(Center)\n        .into()\n    }\n\n    async fn search() -> Result<Pokemon, Error> {\n        use rand::Rng;\n        use serde::Deserialize;\n\n        #[derive(Debug, Deserialize)]\n        struct Entry {\n            name: String,\n            flavor_text_entries: Vec<FlavorText>,\n        }\n\n        #[derive(Debug, Deserialize)]\n        struct FlavorText {\n            flavor_text: String,\n            language: Language,\n        }\n\n        #[derive(Debug, Deserialize)]\n        struct Language {\n            name: String,\n        }\n\n        let id = {\n            let mut rng = rand::rngs::OsRng;\n\n            rng.gen_range(0..Pokemon::TOTAL)\n        };\n\n        let fetch_entry = async {\n            let url = format!(\"https://pokeapi.co/api/v2/pokemon-species/{id}\");\n\n            reqwest::get(&url).await?.json().await\n        };\n\n        let (entry, image): (Entry, _) =\n            futures::future::try_join(fetch_entry, Self::fetch_image(id)).await?;\n\n        let description = entry\n            .flavor_text_entries\n            .iter()\n            .find(|text| text.language.name == \"en\")\n            .ok_or(Error::LanguageError)?;\n\n        Ok(Pokemon {\n            number: id,\n            name: entry.name.to_uppercase(),\n            description: description\n                .flavor_text\n                .chars()\n                .map(|c| if c.is_control() { ' ' } else { c })\n                .collect(),\n            image,\n        })\n    }\n\n    async fn fetch_image(id: u16) -> Result<image::Handle, reqwest::Error> {\n        let url = format!(\n            \"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{id}.png\"\n        );\n\n        #[cfg(not(target_arch = \"wasm32\"))]\n        {\n            let bytes = reqwest::get(&url).await?.bytes().await?;\n\n            Ok(image::Handle::from_bytes(bytes))\n        }\n\n        #[cfg(target_arch = \"wasm32\")]\n        Ok(image::Handle::from_path(url))\n    }\n}\n\n#[derive(Debug, Clone)]\nenum Error {\n    APIError,\n    LanguageError,\n}\n\nimpl From<reqwest::Error> for Error {\n    fn from(error: reqwest::Error) -> Error {\n        dbg!(error);\n\n        Error::APIError\n    }\n}\n\nfn button(text: &str) -> widget::Button<'_, Message> {\n    widget::button(text).padding(10)\n}\n"
  },
  {
    "path": "examples/progress_bar/Cargo.toml",
    "content": "[package]\nname = \"progress_bar\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\n"
  },
  {
    "path": "examples/progress_bar/README.md",
    "content": "## Progress bar\n\nA simple progress bar that can be filled by using a slider.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/progress_bar.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package progress_bar\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/progress_bar/src/main.rs",
    "content": "use iced::Element;\nuse iced::widget::{\n    center, center_x, checkbox, column, progress_bar, row, slider, vertical_slider,\n};\n\npub fn main() -> iced::Result {\n    iced::run(Progress::update, Progress::view)\n}\n\n#[derive(Default)]\nstruct Progress {\n    value: f32,\n    is_vertical: bool,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    SliderChanged(f32),\n    ToggleVertical(bool),\n}\n\nimpl Progress {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::SliderChanged(x) => self.value = x,\n            Message::ToggleVertical(is_vertical) => self.is_vertical = is_vertical,\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let bar = progress_bar(0.0..=100.0, self.value);\n\n        column![\n            if self.is_vertical {\n                center(\n                    row![\n                        bar.vertical(),\n                        vertical_slider(0.0..=100.0, self.value, Message::SliderChanged).step(0.01)\n                    ]\n                    .spacing(20),\n                )\n            } else {\n                center(\n                    column![\n                        bar,\n                        slider(0.0..=100.0, self.value, Message::SliderChanged).step(0.01)\n                    ]\n                    .spacing(20),\n                )\n            },\n            center_x(\n                checkbox(self.is_vertical)\n                    .label(\"Vertical\")\n                    .on_toggle(Message::ToggleVertical)\n            ),\n        ]\n        .spacing(20)\n        .padding(20)\n        .into()\n    }\n}\n"
  },
  {
    "path": "examples/qr_code/Cargo.toml",
    "content": "[package]\nname = \"qr_code\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"qr_code\"]\n"
  },
  {
    "path": "examples/qr_code/README.md",
    "content": "## QR Code Generator\n\nA basic QR code generator that showcases the `QRCode` widget.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/qr_code.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package qr_code\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/qr_code/src/main.rs",
    "content": "use iced::widget::{center, column, pick_list, qr_code, row, slider, text, text_input, toggler};\nuse iced::{Center, Element, Theme};\n\nuse std::ops::RangeInclusive;\n\npub fn main() -> iced::Result {\n    iced::application(QRGenerator::default, QRGenerator::update, QRGenerator::view)\n        .theme(QRGenerator::theme)\n        .run()\n}\n\n#[derive(Default)]\nstruct QRGenerator {\n    data: String,\n    qr_code: Option<qr_code::Data>,\n    total_size: Option<f32>,\n    theme: Option<Theme>,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    DataChanged(String),\n    ToggleTotalSize(bool),\n    TotalSizeChanged(f32),\n    ThemeChanged(Theme),\n}\n\nimpl QRGenerator {\n    const SIZE_RANGE: RangeInclusive<f32> = 200.0..=400.0;\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::DataChanged(mut data) => {\n                data.truncate(100);\n\n                self.qr_code = if data.is_empty() {\n                    None\n                } else {\n                    qr_code::Data::new(&data).ok()\n                };\n\n                self.data = data;\n            }\n            Message::ToggleTotalSize(enabled) => {\n                self.total_size = enabled.then_some(\n                    Self::SIZE_RANGE.start()\n                        + (Self::SIZE_RANGE.end() - Self::SIZE_RANGE.start()) / 2.0,\n                );\n            }\n            Message::TotalSizeChanged(total_size) => {\n                self.total_size = Some(total_size);\n            }\n            Message::ThemeChanged(theme) => {\n                self.theme = Some(theme);\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let title = text(\"QR Code Generator\").size(70);\n\n        let input = text_input(\"Type the data of your QR code here...\", &self.data)\n            .on_input(Message::DataChanged)\n            .size(30)\n            .padding(15);\n\n        let toggle_total_size = toggler(self.total_size.is_some())\n            .on_toggle(Message::ToggleTotalSize)\n            .label(\"Limit Total Size\");\n\n        let choose_theme = row![\n            text(\"Theme:\"),\n            pick_list(self.theme.as_ref(), Theme::ALL, Theme::to_string)\n                .on_select(Message::ThemeChanged)\n                .placeholder(\"Theme\")\n        ]\n        .spacing(10)\n        .align_y(Center);\n\n        let content = column![\n            title,\n            input,\n            row![toggle_total_size, choose_theme]\n                .spacing(20)\n                .align_y(Center),\n            self.total_size.map(|total_size| {\n                slider(Self::SIZE_RANGE, total_size, Message::TotalSizeChanged)\n            }),\n            self.qr_code.as_ref().map(|data| {\n                if let Some(total_size) = self.total_size {\n                    qr_code(data).total_size(total_size)\n                } else {\n                    qr_code(data).cell_size(10.0)\n                }\n            })\n        ]\n        .width(700)\n        .spacing(20)\n        .align_x(Center);\n\n        center(content).padding(20).into()\n    }\n\n    fn theme(&self) -> Option<Theme> {\n        self.theme.clone()\n    }\n}\n"
  },
  {
    "path": "examples/sandpiles/Cargo.toml",
    "content": "[package]\nname = \"sandpiles\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector@hecrj.dev>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"canvas\", \"tokio\", \"debug\"]\n"
  },
  {
    "path": "examples/sandpiles/src/main.rs",
    "content": "use iced::mouse;\nuse iced::widget::{canvas, column, container, row, slider, text};\nuse iced::window;\nuse iced::{\n    Center, Element, Event, Fill, Font, Point, Rectangle, Renderer, Size, Subscription, Theme,\n    Vector,\n};\n\nuse std::collections::{HashMap, HashSet};\n\npub fn main() -> iced::Result {\n    iced::application(Sandpiles::new, Sandpiles::update, Sandpiles::view)\n        .subscription(Sandpiles::subscription)\n        .run()\n}\n\nstruct Sandpiles {\n    grid: Grid,\n    sandfalls: HashSet<Cell>,\n    cache: canvas::Cache,\n    speed: u32,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Tick,\n    Add(Cell),\n    SpeedChanged(u32),\n}\n\nimpl Sandpiles {\n    fn new() -> Self {\n        Self {\n            grid: Grid::new(),\n            sandfalls: HashSet::from_iter(\n                std::iter::once(Cell::ORIGIN).chain(\n                    [(-1, -1), (-1, 1), (1, -1), (1, 1)]\n                        .iter()\n                        .map(|(i, j)| Cell {\n                            row: 3 * i,\n                            column: 3 * j,\n                        }),\n                ),\n            ),\n            cache: canvas::Cache::new(),\n            speed: 1,\n        }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Tick => {\n                let topples = (0..self.speed).find(|_| !self.grid.topple());\n\n                if topples == Some(0) {\n                    for sandfall in &self.sandfalls {\n                        self.grid.add(*sandfall, 1);\n                    }\n                }\n\n                self.cache.clear();\n            }\n            Message::Add(sandfall) => {\n                self.sandfalls.insert(sandfall);\n                self.grid.add(sandfall, 1);\n            }\n            Message::SpeedChanged(speed) => {\n                self.speed = speed;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let viewer = canvas(Viewer {\n            grid: &self.grid,\n            cache: &self.cache,\n        })\n        .width(Fill)\n        .height(Fill);\n\n        let speed = container(\n            row![\n                text(\"Speed\").font(Font::MONOSPACE),\n                slider(1..=1000, self.speed, Message::SpeedChanged),\n                text!(\"x{:>04}\", self.speed)\n                    .font(Font::MONOSPACE)\n                    .align_x(Center)\n            ]\n            .spacing(10)\n            .padding(10)\n            .align_y(Center)\n            .width(500),\n        )\n        .width(Fill)\n        .align_x(Center)\n        .style(container::dark);\n\n        column![viewer, speed].into()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        if self.sandfalls.is_empty() {\n            return Subscription::none();\n        }\n\n        window::frames().map(|_| Message::Tick)\n    }\n}\n\n#[derive(Debug)]\nstruct Grid {\n    sand: HashMap<Cell, u32>,\n    saturated: HashSet<Cell>,\n}\n\nimpl Grid {\n    pub fn new() -> Self {\n        Self {\n            sand: HashMap::new(),\n            saturated: HashSet::new(),\n        }\n    }\n\n    pub fn add(&mut self, cell: Cell, amount: u32) {\n        let grains = self.sand.entry(cell).or_default();\n\n        *grains += amount;\n\n        if *grains >= 4 {\n            self.saturated.insert(cell);\n        }\n    }\n\n    pub fn topple(&mut self) -> bool {\n        let Some(cell) = self.saturated.iter().next().copied() else {\n            return false;\n        };\n\n        let grains = self.sand.entry(cell).or_default();\n        let amount = *grains / 4;\n        *grains %= 4;\n\n        for neighbor in cell.neighbors() {\n            self.add(neighbor, amount);\n        }\n\n        let _ = self.saturated.remove(&cell);\n\n        true\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\nstruct Cell {\n    row: isize,\n    column: isize,\n}\n\nimpl Cell {\n    pub const ORIGIN: Self = Self { row: 0, column: 0 };\n\n    pub fn neighbors(self) -> impl Iterator<Item = Cell> {\n        [(0, -1), (-1, 0), (1, 0), (0, 1)]\n            .into_iter()\n            .map(move |(i, j)| Cell {\n                row: self.row + i,\n                column: self.column + j,\n            })\n    }\n}\n\nstruct Viewer<'a> {\n    grid: &'a Grid,\n    cache: &'a canvas::Cache,\n}\n\nimpl Viewer<'_> {\n    const CELL_SIZE: f32 = 10.0;\n}\n\nimpl canvas::Program<Message> for Viewer<'_> {\n    type State = ();\n\n    fn update(\n        &self,\n        _state: &mut Self::State,\n        event: &Event,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> Option<canvas::Action<Message>> {\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {\n                let position = cursor.position_in(bounds)? - (bounds.center() - Point::ORIGIN);\n                let row = (position.x / Self::CELL_SIZE).round() as isize;\n                let column = (position.y / Self::CELL_SIZE).round() as isize;\n\n                Some(canvas::Action::publish(Message::Add(Cell { row, column })))\n            }\n            Event::Mouse(mouse::Event::CursorMoved { .. }) if cursor.is_over(bounds) => {\n                Some(canvas::Action::request_redraw())\n            }\n            _ => None,\n        }\n    }\n\n    fn draw(\n        &self,\n        _state: &Self::State,\n        renderer: &Renderer,\n        theme: &Theme,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> Vec<canvas::Geometry<Renderer>> {\n        let geometry = self.cache.draw(renderer, bounds.size(), |frame| {\n            let palette = theme.palette();\n\n            let cells_x = (frame.width() / Self::CELL_SIZE).ceil() as isize;\n            let cells_y = (frame.height() / Self::CELL_SIZE).ceil() as isize;\n\n            let rows = -cells_x / 2..=cells_x / 2;\n            let columns = -cells_y / 2..=cells_y / 2;\n\n            frame.translate(\n                frame.center()\n                    - Point::ORIGIN\n                    - Vector::new(Self::CELL_SIZE, Self::CELL_SIZE) / 2.0,\n            );\n\n            for row in rows {\n                for column in columns.clone() {\n                    let grains = self\n                        .grid\n                        .sand\n                        .get(&Cell { row, column })\n                        .copied()\n                        .unwrap_or_default();\n\n                    if grains == 0 {\n                        continue;\n                    }\n\n                    frame.fill_rectangle(\n                        Point::new(\n                            row as f32 * Self::CELL_SIZE,\n                            column as f32 * Self::CELL_SIZE,\n                        ),\n                        Size::new(Self::CELL_SIZE, Self::CELL_SIZE),\n                        match grains {\n                            4.. => palette.secondary.base.color,\n                            3 => palette.background.strongest.color,\n                            2 => palette.background.strong.color,\n                            _ => palette.background.weak.color,\n                        },\n                    );\n                }\n            }\n        });\n\n        let cursor = {\n            let mut frame = canvas::Frame::new(renderer, bounds.size());\n\n            if let Some(position) = cursor.position_in(bounds) {\n                let translation = frame.center() - Point::ORIGIN;\n                let position = position - translation;\n\n                frame.translate(translation - Vector::new(Self::CELL_SIZE, Self::CELL_SIZE) / 2.0);\n                frame.fill_rectangle(\n                    Point::new(\n                        (position.x / Self::CELL_SIZE).round() * Self::CELL_SIZE,\n                        (position.y / Self::CELL_SIZE).round() * Self::CELL_SIZE,\n                    ),\n                    Size::new(Self::CELL_SIZE, Self::CELL_SIZE),\n                    theme.seed().primary,\n                );\n            }\n\n            frame.into_geometry()\n        };\n\n        vec![geometry, cursor]\n    }\n\n    fn mouse_interaction(\n        &self,\n        _state: &Self::State,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> mouse::Interaction {\n        if cursor.is_over(bounds) {\n            mouse::Interaction::Crosshair\n        } else {\n            mouse::Interaction::None\n        }\n    }\n}\n"
  },
  {
    "path": "examples/screenshot/Cargo.toml",
    "content": "[package]\nname = \"screenshot\"\nversion = \"0.1.0\"\nauthors = [\"Bingus <shankern@protonmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"image\", \"advanced\", \"tokio\"]\n\nimage.workspace = true\nimage.features = [\"png\"]\n\ntokio.workspace = true\n\ntracing-subscriber = \"0.3\""
  },
  {
    "path": "examples/screenshot/src/main.rs",
    "content": "use iced::keyboard;\nuse iced::widget::{button, center_y, column, container, image, row, text, text_input};\nuse iced::window;\nuse iced::window::screenshot::{self, Screenshot};\nuse iced::{Center, ContentFit, Element, Fill, FillPortion, Rectangle, Subscription, Task};\n\nuse ::image as img;\nuse ::image::ColorType;\n\nfn main() -> iced::Result {\n    tracing_subscriber::fmt::init();\n\n    iced::application(Example::default, Example::update, Example::view)\n        .subscription(Example::subscription)\n        .run()\n}\n\n#[derive(Default)]\nstruct Example {\n    screenshot: Option<(Screenshot, image::Handle)>,\n    saved_png_path: Option<Result<String, PngError>>,\n    png_saving: bool,\n    crop_error: Option<screenshot::CropError>,\n    x_input_value: Option<u32>,\n    y_input_value: Option<u32>,\n    width_input_value: Option<u32>,\n    height_input_value: Option<u32>,\n}\n\n#[derive(Clone, Debug)]\nenum Message {\n    Crop,\n    Screenshot,\n    Screenshotted(Screenshot),\n    Png,\n    PngSaved(Result<String, PngError>),\n    XInputChanged(Option<u32>),\n    YInputChanged(Option<u32>),\n    WidthInputChanged(Option<u32>),\n    HeightInputChanged(Option<u32>),\n}\n\nimpl Example {\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::Screenshot => {\n                return window::latest()\n                    .and_then(window::screenshot)\n                    .map(Message::Screenshotted);\n            }\n            Message::Screenshotted(screenshot) => {\n                self.screenshot = Some((\n                    screenshot.clone(),\n                    image::Handle::from_rgba(\n                        screenshot.size.width,\n                        screenshot.size.height,\n                        screenshot.rgba,\n                    ),\n                ));\n            }\n            Message::Png => {\n                if let Some((screenshot, _handle)) = &self.screenshot {\n                    self.png_saving = true;\n\n                    return Task::perform(save_to_png(screenshot.clone()), Message::PngSaved);\n                }\n            }\n            Message::PngSaved(res) => {\n                self.png_saving = false;\n                self.saved_png_path = Some(res);\n            }\n            Message::XInputChanged(new_value) => {\n                self.x_input_value = new_value;\n            }\n            Message::YInputChanged(new_value) => {\n                self.y_input_value = new_value;\n            }\n            Message::WidthInputChanged(new_value) => {\n                self.width_input_value = new_value;\n            }\n            Message::HeightInputChanged(new_value) => {\n                self.height_input_value = new_value;\n            }\n            Message::Crop => {\n                if let Some((screenshot, _handle)) = &self.screenshot {\n                    let cropped = screenshot.crop(Rectangle::<u32> {\n                        x: self.x_input_value.unwrap_or(0),\n                        y: self.y_input_value.unwrap_or(0),\n                        width: self.width_input_value.unwrap_or(0),\n                        height: self.height_input_value.unwrap_or(0),\n                    });\n\n                    match cropped {\n                        Ok(screenshot) => {\n                            self.screenshot = Some((\n                                screenshot.clone(),\n                                image::Handle::from_rgba(\n                                    screenshot.size.width,\n                                    screenshot.size.height,\n                                    screenshot.rgba,\n                                ),\n                            ));\n                            self.crop_error = None;\n                        }\n                        Err(crop_error) => {\n                            self.crop_error = Some(crop_error);\n                        }\n                    }\n                }\n            }\n        }\n\n        Task::none()\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let image: Element<Message> = if let Some((_screenshot, handle)) = &self.screenshot {\n            image(handle)\n                .content_fit(ContentFit::Contain)\n                .width(Fill)\n                .height(Fill)\n                .into()\n        } else {\n            text(\"Press the button to take a screenshot!\").into()\n        };\n\n        let image = center_y(image)\n            .height(FillPortion(2))\n            .padding(10)\n            .style(container::rounded_box);\n\n        let crop_origin_controls = row![\n            text(\"X:\").width(30),\n            numeric_input(\"0\", self.x_input_value).map(Message::XInputChanged),\n            text(\"Y:\").width(30),\n            numeric_input(\"0\", self.y_input_value).map(Message::YInputChanged)\n        ]\n        .spacing(10)\n        .align_y(Center);\n\n        let crop_dimension_controls = row![\n            text(\"W:\").width(30),\n            numeric_input(\"0\", self.width_input_value).map(Message::WidthInputChanged),\n            text(\"H:\").width(30),\n            numeric_input(\"0\", self.height_input_value).map(Message::HeightInputChanged)\n        ]\n        .spacing(10)\n        .align_y(Center);\n\n        let crop_controls = column![\n            crop_origin_controls,\n            crop_dimension_controls,\n            self.crop_error\n                .as_ref()\n                .map(|error| text!(\"Crop error! \\n{error}\")),\n        ]\n        .spacing(10)\n        .align_x(Center);\n\n        let controls = {\n            let save_result = self\n                .saved_png_path\n                .as_ref()\n                .map(|png_result| match png_result {\n                    Ok(path) => format!(\"Png saved as: {path:?}!\"),\n                    Err(PngError(error)) => {\n                        format!(\"Png could not be saved due to:\\n{error}\")\n                    }\n                });\n\n            column![\n                column![\n                    button(centered_text(\"Screenshot!\"))\n                        .padding([10, 20])\n                        .width(Fill)\n                        .on_press(Message::Screenshot),\n                    if !self.png_saving {\n                        button(centered_text(\"Save as png\"))\n                            .on_press_maybe(self.screenshot.is_some().then(|| Message::Png))\n                    } else {\n                        button(centered_text(\"Saving...\")).style(button::secondary)\n                    }\n                    .style(button::secondary)\n                    .padding([10, 20])\n                    .width(Fill)\n                ]\n                .spacing(10),\n                column![\n                    crop_controls,\n                    button(centered_text(\"Crop\"))\n                        .on_press(Message::Crop)\n                        .style(button::danger)\n                        .padding([10, 20])\n                        .width(Fill),\n                ]\n                .spacing(10)\n                .align_x(Center),\n                save_result.map(text)\n            ]\n            .spacing(40)\n        };\n\n        let side_content = center_y(controls);\n\n        let content = row![side_content, image]\n            .spacing(10)\n            .width(Fill)\n            .height(Fill)\n            .align_y(Center);\n\n        container(content).padding(10).into()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        use keyboard::key;\n\n        keyboard::listen().filter_map(|event| {\n            if let keyboard::Event::KeyPressed {\n                modified_key: keyboard::Key::Named(key::Named::F5),\n                ..\n            } = event\n            {\n                Some(Message::Screenshot)\n            } else {\n                None\n            }\n        })\n    }\n}\n\nasync fn save_to_png(screenshot: Screenshot) -> Result<String, PngError> {\n    let path = \"screenshot.png\".to_string();\n\n    tokio::task::spawn_blocking(move || {\n        img::save_buffer(\n            &path,\n            &screenshot.rgba,\n            screenshot.size.width,\n            screenshot.size.height,\n            ColorType::Rgba8,\n        )\n        .map(|_| path)\n        .map_err(|error| PngError(error.to_string()))\n    })\n    .await\n    .expect(\"Blocking task to finish\")\n}\n\n#[derive(Clone, Debug)]\nstruct PngError(String);\n\nfn numeric_input(placeholder: &str, value: Option<u32>) -> Element<'_, Option<u32>> {\n    text_input(\n        placeholder,\n        &value.as_ref().map(ToString::to_string).unwrap_or_default(),\n    )\n    .on_input(move |text| {\n        if text.is_empty() {\n            None\n        } else if let Ok(new_value) = text.parse() {\n            Some(new_value)\n        } else {\n            value\n        }\n    })\n    .width(40)\n    .into()\n}\n\nfn centered_text(content: &str) -> Element<'_, Message> {\n    text(content).width(Fill).align_x(Center).into()\n}\n"
  },
  {
    "path": "examples/scrollable/Cargo.toml",
    "content": "[package]\nname = \"scrollable\"\nversion = \"0.1.0\"\nauthors = [\"Clark Moody <clark@clarkmoody.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\"]\n"
  },
  {
    "path": "examples/scrollable/README.md",
    "content": "# Scrollable\nAn example showcasing the various size and style options for the Scrollable.\n\nAll the example code is located in the __[`main`](src/main.rs)__ file.\n\n<div align=\"center\">\n  <a href=\"screenshot.png\">\n    <img src=\"screenshot.png\" height=\"640px\">\n  </a>\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package scrollable\n```\n"
  },
  {
    "path": "examples/scrollable/src/main.rs",
    "content": "use iced::widget::{\n    button, column, container, operation, progress_bar, radio, row, scrollable, slider, space, text,\n};\nuse iced::{Border, Center, Color, Element, Fill, Task, Theme};\n\npub fn main() -> iced::Result {\n    iced::application(\n        ScrollableDemo::default,\n        ScrollableDemo::update,\n        ScrollableDemo::view,\n    )\n    .theme(ScrollableDemo::theme)\n    .run()\n}\n\nstruct ScrollableDemo {\n    scrollable_direction: Direction,\n    scrollbar_width: u32,\n    scrollbar_margin: u32,\n    scroller_width: u32,\n    current_scroll_offset: scrollable::RelativeOffset,\n    anchor: scrollable::Anchor,\n}\n\n#[derive(Debug, Clone, Eq, PartialEq, Copy)]\nenum Direction {\n    Vertical,\n    Horizontal,\n    Multi,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    SwitchDirection(Direction),\n    AlignmentChanged(scrollable::Anchor),\n    ScrollbarWidthChanged(u32),\n    ScrollbarMarginChanged(u32),\n    ScrollerWidthChanged(u32),\n    ScrollToBeginning,\n    ScrollToEnd,\n    Scrolled(scrollable::Viewport),\n}\n\nimpl ScrollableDemo {\n    fn new() -> Self {\n        ScrollableDemo {\n            scrollable_direction: Direction::Vertical,\n            scrollbar_width: 10,\n            scrollbar_margin: 0,\n            scroller_width: 10,\n            current_scroll_offset: scrollable::RelativeOffset::START,\n            anchor: scrollable::Anchor::Start,\n        }\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::SwitchDirection(direction) => {\n                self.current_scroll_offset = scrollable::RelativeOffset::START;\n                self.scrollable_direction = direction;\n\n                operation::snap_to(SCROLLABLE, self.current_scroll_offset)\n            }\n            Message::AlignmentChanged(alignment) => {\n                self.current_scroll_offset = scrollable::RelativeOffset::START;\n                self.anchor = alignment;\n\n                operation::snap_to(SCROLLABLE, self.current_scroll_offset)\n            }\n            Message::ScrollbarWidthChanged(width) => {\n                self.scrollbar_width = width;\n\n                Task::none()\n            }\n            Message::ScrollbarMarginChanged(margin) => {\n                self.scrollbar_margin = margin;\n\n                Task::none()\n            }\n            Message::ScrollerWidthChanged(width) => {\n                self.scroller_width = width;\n\n                Task::none()\n            }\n            Message::ScrollToBeginning => {\n                self.current_scroll_offset = scrollable::RelativeOffset::START;\n\n                operation::snap_to(SCROLLABLE, self.current_scroll_offset)\n            }\n            Message::ScrollToEnd => {\n                self.current_scroll_offset = scrollable::RelativeOffset::END;\n\n                operation::snap_to(SCROLLABLE, self.current_scroll_offset)\n            }\n            Message::Scrolled(viewport) => {\n                self.current_scroll_offset = viewport.relative_offset();\n\n                Task::none()\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let scrollbar_width_slider =\n            slider(0..=15, self.scrollbar_width, Message::ScrollbarWidthChanged);\n        let scrollbar_margin_slider = slider(\n            0..=15,\n            self.scrollbar_margin,\n            Message::ScrollbarMarginChanged,\n        );\n        let scroller_width_slider =\n            slider(0..=15, self.scroller_width, Message::ScrollerWidthChanged);\n\n        let scroll_slider_controls = column![\n            text(\"Scrollbar width:\"),\n            scrollbar_width_slider,\n            text(\"Scrollbar margin:\"),\n            scrollbar_margin_slider,\n            text(\"Scroller width:\"),\n            scroller_width_slider,\n        ]\n        .spacing(10);\n\n        let scroll_orientation_controls = column![\n            text(\"Scrollbar direction:\"),\n            radio(\n                \"Vertical\",\n                Direction::Vertical,\n                Some(self.scrollable_direction),\n                Message::SwitchDirection,\n            ),\n            radio(\n                \"Horizontal\",\n                Direction::Horizontal,\n                Some(self.scrollable_direction),\n                Message::SwitchDirection,\n            ),\n            radio(\n                \"Both!\",\n                Direction::Multi,\n                Some(self.scrollable_direction),\n                Message::SwitchDirection,\n            ),\n        ]\n        .spacing(10);\n\n        let scroll_alignment_controls = column![\n            text(\"Scrollable alignment:\"),\n            radio(\n                \"Start\",\n                scrollable::Anchor::Start,\n                Some(self.anchor),\n                Message::AlignmentChanged,\n            ),\n            radio(\n                \"End\",\n                scrollable::Anchor::End,\n                Some(self.anchor),\n                Message::AlignmentChanged,\n            )\n        ]\n        .spacing(10);\n\n        let scroll_controls = row![\n            scroll_slider_controls,\n            scroll_orientation_controls,\n            scroll_alignment_controls\n        ]\n        .spacing(20);\n\n        let scroll_to_end_button = || {\n            button(\"Scroll to end\")\n                .padding(10)\n                .on_press(Message::ScrollToEnd)\n        };\n\n        let scroll_to_beginning_button = || {\n            button(\"Scroll to beginning\")\n                .padding(10)\n                .on_press(Message::ScrollToBeginning)\n        };\n\n        let scrollable_content: Element<Message> = Element::from(match self.scrollable_direction {\n            Direction::Vertical => scrollable(\n                column![\n                    scroll_to_end_button(),\n                    text(\"Beginning!\"),\n                    space().height(1200),\n                    text(\"Middle!\"),\n                    space().height(1200),\n                    text(\"End!\"),\n                    scroll_to_beginning_button(),\n                ]\n                .align_x(Center)\n                .padding([40, 0])\n                .spacing(40),\n            )\n            .direction(scrollable::Direction::Vertical(\n                scrollable::Scrollbar::new()\n                    .width(self.scrollbar_width)\n                    .margin(self.scrollbar_margin)\n                    .scroller_width(self.scroller_width)\n                    .anchor(self.anchor),\n            ))\n            .width(Fill)\n            .height(Fill)\n            .id(SCROLLABLE)\n            .on_scroll(Message::Scrolled)\n            .auto_scroll(true),\n            Direction::Horizontal => scrollable(\n                row![\n                    scroll_to_end_button(),\n                    text(\"Beginning!\"),\n                    space().width(1200),\n                    text(\"Middle!\"),\n                    space().width(1200),\n                    text(\"End!\"),\n                    scroll_to_beginning_button(),\n                ]\n                .height(450)\n                .align_y(Center)\n                .padding([0, 40])\n                .spacing(40),\n            )\n            .direction(scrollable::Direction::Horizontal(\n                scrollable::Scrollbar::new()\n                    .width(self.scrollbar_width)\n                    .margin(self.scrollbar_margin)\n                    .scroller_width(self.scroller_width)\n                    .anchor(self.anchor),\n            ))\n            .width(Fill)\n            .height(Fill)\n            .id(SCROLLABLE)\n            .on_scroll(Message::Scrolled)\n            .auto_scroll(true),\n            Direction::Multi => scrollable(\n                //horizontal content\n                row![\n                    column![text(\"Let's do some scrolling!\"), space().height(2400)],\n                    scroll_to_end_button(),\n                    text(\"Horizontal - Beginning!\"),\n                    space().width(1200),\n                    //vertical content\n                    column![\n                        text(\"Horizontal - Middle!\"),\n                        scroll_to_end_button(),\n                        text(\"Vertical - Beginning!\"),\n                        space().height(1200),\n                        text(\"Vertical - Middle!\"),\n                        space().height(1200),\n                        text(\"Vertical - End!\"),\n                        scroll_to_beginning_button(),\n                        space().height(40),\n                    ]\n                    .spacing(40),\n                    space().width(1200),\n                    text(\"Horizontal - End!\"),\n                    scroll_to_beginning_button(),\n                ]\n                .align_y(Center)\n                .padding([0, 40])\n                .spacing(40),\n            )\n            .direction({\n                let scrollbar = scrollable::Scrollbar::new()\n                    .width(self.scrollbar_width)\n                    .margin(self.scrollbar_margin)\n                    .scroller_width(self.scroller_width)\n                    .anchor(self.anchor);\n\n                scrollable::Direction::Both {\n                    horizontal: scrollbar,\n                    vertical: scrollbar,\n                }\n            })\n            .width(Fill)\n            .height(Fill)\n            .id(SCROLLABLE)\n            .on_scroll(Message::Scrolled)\n            .auto_scroll(true),\n        });\n\n        let progress_bars: Element<Message> = match self.scrollable_direction {\n            Direction::Vertical => progress_bar(0.0..=1.0, self.current_scroll_offset.y).into(),\n            Direction::Horizontal => progress_bar(0.0..=1.0, self.current_scroll_offset.x)\n                .style(progress_bar_custom_style)\n                .into(),\n            Direction::Multi => column![\n                progress_bar(0.0..=1.0, self.current_scroll_offset.y),\n                progress_bar(0.0..=1.0, self.current_scroll_offset.x)\n                    .style(progress_bar_custom_style)\n            ]\n            .spacing(10)\n            .into(),\n        };\n\n        let content: Element<Message> = column![scroll_controls, scrollable_content, progress_bars]\n            .align_x(Center)\n            .spacing(10)\n            .into();\n\n        container(content).padding(20).into()\n    }\n\n    fn theme(&self) -> Theme {\n        Theme::Dark\n    }\n}\n\nimpl Default for ScrollableDemo {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nfn progress_bar_custom_style(theme: &Theme) -> progress_bar::Style {\n    progress_bar::Style {\n        background: theme.palette().background.strong.color.into(),\n        bar: Color::from_rgb8(250, 85, 134).into(),\n        border: Border::default(),\n    }\n}\n\nconst SCROLLABLE: &str = \"scrollable\";\n"
  },
  {
    "path": "examples/sierpinski_triangle/Cargo.toml",
    "content": "[package]\nname = \"sierpinski_triangle\"\nversion = \"0.1.0\"\nauthors = [\"xkenmon <xkenmon@gmail.com>\"]\nedition = \"2018\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"canvas\"]\n\nrand = \"0.8\"\n"
  },
  {
    "path": "examples/sierpinski_triangle/README.md",
    "content": "## Sierpinski Triangle Emulator\n\nA simple [Sierpiński triangle](https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle) Emulator, use canvas and slider.\n\nLeft-click add fixed point, right-click remove fixed point.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/sierpinski_triangle.gif\">\n</div>\n\nYou can run with cargo:\n```\ncargo run --package sierpinski_triangle\n```"
  },
  {
    "path": "examples/sierpinski_triangle/src/main.rs",
    "content": "use iced::mouse;\nuse iced::widget::canvas::{self, Canvas, Event, Geometry};\nuse iced::widget::{column, row, slider, text};\nuse iced::{Center, Color, Element, Fill, Point, Rectangle, Renderer, Size, Theme};\n\nuse rand::Rng;\nuse std::fmt::Debug;\n\nfn main() -> iced::Result {\n    iced::application(\n        SierpinskiEmulator::default,\n        SierpinskiEmulator::update,\n        SierpinskiEmulator::view,\n    )\n    .run()\n}\n\n#[derive(Debug, Default)]\nstruct SierpinskiEmulator {\n    graph: SierpinskiGraph,\n}\n\n#[derive(Debug, Clone)]\npub enum Message {\n    IterationSet(i32),\n    PointAdded(Point),\n    PointRemoved,\n}\n\nimpl SierpinskiEmulator {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::IterationSet(cur_iter) => {\n                self.graph.iteration = cur_iter;\n            }\n            Message::PointAdded(point) => {\n                self.graph.fix_points.push(point);\n                self.graph.random_points.clear();\n            }\n            Message::PointRemoved => {\n                self.graph.fix_points.pop();\n                self.graph.random_points.clear();\n            }\n        }\n\n        self.graph.redraw();\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        column![\n            Canvas::new(&self.graph).width(Fill).height(Fill),\n            row![\n                text!(\"Iteration: {:?}\", self.graph.iteration),\n                slider(0..=10000, self.graph.iteration, Message::IterationSet)\n            ]\n            .padding(10)\n            .spacing(20),\n        ]\n        .align_x(Center)\n        .into()\n    }\n}\n\n#[derive(Default, Debug)]\nstruct SierpinskiGraph {\n    iteration: i32,\n    fix_points: Vec<Point>,\n    random_points: Vec<Point>,\n    cache: canvas::Cache,\n}\n\nimpl canvas::Program<Message> for SierpinskiGraph {\n    type State = ();\n\n    fn update(\n        &self,\n        _state: &mut Self::State,\n        event: &Event,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> Option<canvas::Action<Message>> {\n        let cursor_position = cursor.position_in(bounds)?;\n\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(button)) => match button {\n                mouse::Button::Left => Some(canvas::Action::publish(Message::PointAdded(\n                    cursor_position,\n                ))),\n                mouse::Button::Right => Some(canvas::Action::publish(Message::PointRemoved)),\n                _ => None,\n            },\n            _ => None,\n        }\n        .map(canvas::Action::and_capture)\n    }\n\n    fn draw(\n        &self,\n        _state: &Self::State,\n        renderer: &Renderer,\n        _theme: &Theme,\n        bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Vec<Geometry> {\n        let geom = self.cache.draw(renderer, bounds.size(), |frame| {\n            frame.stroke(\n                &canvas::Path::rectangle(Point::ORIGIN, frame.size()),\n                canvas::Stroke::default(),\n            );\n\n            if self.fix_points.is_empty() {\n                return;\n            }\n\n            let mut last = None;\n\n            for _ in 0..self.iteration {\n                let p = self.gen_rand_point(last);\n                let path = canvas::Path::rectangle(p, Size::new(1_f32, 1_f32));\n\n                frame.stroke(&path, canvas::Stroke::default());\n\n                last = Some(p);\n            }\n\n            self.fix_points.iter().for_each(|p| {\n                let path = canvas::Path::circle(*p, 5.0);\n                frame.fill(&path, Color::from_rgb8(0x12, 0x93, 0xD8));\n            });\n        });\n\n        vec![geom]\n    }\n}\n\nimpl SierpinskiGraph {\n    fn redraw(&mut self) {\n        self.cache.clear();\n    }\n\n    fn gen_rand_point(&self, last: Option<Point>) -> Point {\n        let dest_point_idx = rand::thread_rng().gen_range(0..self.fix_points.len());\n\n        let dest_point = self.fix_points[dest_point_idx];\n        let cur_point = last.or_else(|| Some(self.fix_points[0])).unwrap();\n\n        Point::new(\n            (dest_point.x + cur_point.x) / 2_f32,\n            (dest_point.y + cur_point.y) / 2_f32,\n        )\n    }\n}\n"
  },
  {
    "path": "examples/slider/Cargo.toml",
    "content": "[package]\nname = \"slider\"\nversion = \"0.1.0\"\nauthors = [\"Casper Rogild Storm<casper@rogildstorm.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"svg\"]\n"
  },
  {
    "path": "examples/slider/README.md",
    "content": "## Slider\n\nA `Slider` is a bar and a handle that selects a single value from a range of values.\nThere exists both `Slider` and `VerticalSlider` depending on which orientation you need.\n\n<div align=\"center\">\n    <img src=\"sliders.gif\">\n</div>\n\nYou can run it with `cargo run`:\n\n```\ncargo run --package slider\n```\n"
  },
  {
    "path": "examples/slider/src/main.rs",
    "content": "use iced::widget::{column, container, iced, slider, text, vertical_slider};\nuse iced::{Center, Element, Fill};\n\npub fn main() -> iced::Result {\n    iced::run(Slider::update, Slider::view)\n}\n\n#[derive(Debug, Clone)]\npub enum Message {\n    SliderChanged(u8),\n}\n\npub struct Slider {\n    value: u8,\n}\n\nimpl Slider {\n    fn new() -> Self {\n        Slider { value: 50 }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::SliderChanged(value) => {\n                self.value = value;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let h_slider = container(\n            slider(1..=100, self.value, Message::SliderChanged)\n                .default(50)\n                .shift_step(5),\n        )\n        .width(250);\n\n        let v_slider = container(\n            vertical_slider(1..=100, self.value, Message::SliderChanged)\n                .default(50)\n                .shift_step(5),\n        )\n        .height(200);\n\n        let text = text(self.value);\n\n        column![v_slider, h_slider, text, iced(self.value as f32),]\n            .width(Fill)\n            .align_x(Center)\n            .spacing(20)\n            .padding(20)\n            .into()\n    }\n}\n\nimpl Default for Slider {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n"
  },
  {
    "path": "examples/solar_system/Cargo.toml",
    "content": "[package]\nname = \"solar_system\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"canvas\", \"image\", \"tokio\"]\n\nrand = \"0.8.3\"\ntracing-subscriber = \"0.3\"\n"
  },
  {
    "path": "examples/solar_system/README.md",
    "content": "## Solar system\n\nAn animated solar system drawn using the `Canvas` widget and showcasing how to compose different transforms.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/solar_system.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package solar_system\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/solar_system/src/main.rs",
    "content": "//! An animated solar system.\n//!\n//! This example showcases how to use a `Canvas` widget with transforms to draw\n//! using different coordinate systems.\n//!\n//! Inspired by the example found in the MDN docs[1].\n//!\n//! [1]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations#An_animated_solar_system\nuse iced::mouse;\nuse iced::widget::canvas::stroke::{self, Stroke};\nuse iced::widget::canvas::{Geometry, Path};\nuse iced::widget::{canvas, image};\nuse iced::window;\nuse iced::{Color, Element, Fill, Point, Rectangle, Renderer, Size, Subscription, Theme, Vector};\n\nuse std::time::Instant;\n\npub fn main() -> iced::Result {\n    tracing_subscriber::fmt::init();\n\n    iced::application::timed(\n        SolarSystem::new,\n        SolarSystem::update,\n        SolarSystem::subscription,\n        SolarSystem::view,\n    )\n    .theme(SolarSystem::theme)\n    .run()\n}\n\nstruct SolarSystem {\n    state: State,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Tick,\n}\n\nimpl SolarSystem {\n    fn new() -> Self {\n        Self {\n            state: State::new(),\n        }\n    }\n\n    fn update(&mut self, message: Message, now: Instant) {\n        match message {\n            Message::Tick => {\n                self.state.update(now);\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        canvas(&self.state).width(Fill).height(Fill).into()\n    }\n\n    fn theme(&self) -> Theme {\n        Theme::Moonfly\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        window::frames().map(|_| Message::Tick)\n    }\n}\n\n#[derive(Debug)]\nstruct State {\n    sun: image::Handle,\n    earth: image::Handle,\n    moon: image::Handle,\n    space_cache: canvas::Cache,\n    system_cache: canvas::Cache,\n    start: Instant,\n    now: Instant,\n    stars: Vec<(Point, f32)>,\n}\n\nimpl State {\n    const SUN_RADIUS: f32 = 70.0;\n    const ORBIT_RADIUS: f32 = 150.0;\n    const EARTH_RADIUS: f32 = 12.0;\n    const MOON_RADIUS: f32 = 4.0;\n    const MOON_DISTANCE: f32 = 28.0;\n\n    pub fn new() -> State {\n        let now = Instant::now();\n        let size = window::Settings::default().size;\n\n        State {\n            sun: image::Handle::from_bytes(include_bytes!(\"../assets/sun.png\").as_slice()),\n            earth: image::Handle::from_bytes(include_bytes!(\"../assets/earth.png\").as_slice()),\n            moon: image::Handle::from_bytes(include_bytes!(\"../assets/moon.png\").as_slice()),\n            space_cache: canvas::Cache::default(),\n            system_cache: canvas::Cache::default(),\n            start: now,\n            now,\n            stars: Self::generate_stars(size.width, size.height),\n        }\n    }\n\n    pub fn update(&mut self, now: Instant) {\n        self.start = self.start.min(now);\n        self.now = now;\n        self.system_cache.clear();\n    }\n\n    fn generate_stars(width: f32, height: f32) -> Vec<(Point, f32)> {\n        use rand::Rng;\n\n        let mut rng = rand::thread_rng();\n\n        (0..100)\n            .map(|_| {\n                (\n                    Point::new(\n                        rng.gen_range((-width / 2.0)..(width / 2.0)),\n                        rng.gen_range((-height / 2.0)..(height / 2.0)),\n                    ),\n                    rng.gen_range(0.5..1.0),\n                )\n            })\n            .collect()\n    }\n}\n\nimpl<Message> canvas::Program<Message> for State {\n    type State = ();\n\n    fn draw(\n        &self,\n        _state: &Self::State,\n        renderer: &Renderer,\n        _theme: &Theme,\n        bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Vec<Geometry> {\n        use std::f32::consts::PI;\n\n        let background = self.space_cache.draw(renderer, bounds.size(), |frame| {\n            frame.fill_rectangle(Point::ORIGIN, frame.size(), Color::BLACK);\n\n            let stars = Path::new(|path| {\n                for (p, size) in &self.stars {\n                    path.rectangle(*p, Size::new(*size, *size));\n                }\n            });\n\n            frame.translate(frame.center() - Point::ORIGIN);\n            frame.fill(&stars, Color::WHITE);\n        });\n\n        let system = self.system_cache.draw(renderer, bounds.size(), |frame| {\n            let center = frame.center();\n            frame.translate(Vector::new(center.x, center.y));\n\n            frame.draw_image(Rectangle::with_radius(Self::SUN_RADIUS), &self.sun);\n\n            let orbit = Path::circle(Point::ORIGIN, Self::ORBIT_RADIUS);\n            frame.stroke(\n                &orbit,\n                Stroke {\n                    style: stroke::Style::Solid(Color::WHITE.scale_alpha(0.1)),\n                    width: 1.0,\n                    line_dash: canvas::LineDash {\n                        offset: 0,\n                        segments: &[3.0, 6.0],\n                    },\n                    ..Stroke::default()\n                },\n            );\n\n            let elapsed = self.now - self.start;\n            let rotation = (2.0 * PI / 60.0) * elapsed.as_secs() as f32\n                + (2.0 * PI / 60_000.0) * elapsed.subsec_millis() as f32;\n\n            frame.rotate(rotation);\n            frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0));\n\n            frame.draw_image(\n                Rectangle::with_radius(Self::EARTH_RADIUS),\n                canvas::Image::new(&self.earth).rotation(-rotation * 20.0),\n            );\n\n            frame.rotate(rotation * 10.0);\n            frame.translate(Vector::new(0.0, Self::MOON_DISTANCE));\n\n            frame.draw_image(Rectangle::with_radius(Self::MOON_RADIUS), &self.moon);\n        });\n\n        vec![background, system]\n    }\n}\n"
  },
  {
    "path": "examples/stopwatch/Cargo.toml",
    "content": "[package]\nname = \"stopwatch\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"smol\"]\n"
  },
  {
    "path": "examples/stopwatch/README.md",
    "content": "## Stopwatch\n\nA watch with start/stop and reset buttons showcasing how to listen to time.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/stopwatch.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package stopwatch\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/stopwatch/src/main.rs",
    "content": "use iced::keyboard;\nuse iced::time::{self, Duration, Instant, milliseconds};\nuse iced::widget::{button, center, column, row, text};\nuse iced::{Center, Element, Subscription};\n\npub fn main() -> iced::Result {\n    iced::application(Stopwatch::default, Stopwatch::update, Stopwatch::view)\n        .subscription(Stopwatch::subscription)\n        .run()\n}\n\n#[derive(Default)]\nstruct Stopwatch {\n    duration: Duration,\n    state: State,\n}\n\n#[derive(Default)]\nenum State {\n    #[default]\n    Idle,\n    Ticking {\n        last_tick: Instant,\n    },\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    Toggle,\n    Reset,\n    Tick(Instant),\n}\n\nimpl Stopwatch {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Toggle => match self.state {\n                State::Idle => {\n                    self.state = State::Ticking {\n                        last_tick: Instant::now(),\n                    };\n                }\n                State::Ticking { .. } => {\n                    self.state = State::Idle;\n                }\n            },\n            Message::Tick(now) => {\n                if let State::Ticking { last_tick } = &mut self.state {\n                    self.duration += now - *last_tick;\n                    *last_tick = now;\n                }\n            }\n            Message::Reset => {\n                self.duration = Duration::default();\n            }\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        let tick = match self.state {\n            State::Idle => Subscription::none(),\n            State::Ticking { .. } => time::every(milliseconds(10)).map(Message::Tick),\n        };\n\n        fn handle_hotkey(event: keyboard::Event) -> Option<Message> {\n            use keyboard::key;\n\n            let keyboard::Event::KeyPressed { modified_key, .. } = event else {\n                return None;\n            };\n\n            match modified_key.as_ref() {\n                keyboard::Key::Named(key::Named::Space) => Some(Message::Toggle),\n                keyboard::Key::Character(\"r\") => Some(Message::Reset),\n                _ => None,\n            }\n        }\n\n        Subscription::batch(vec![tick, keyboard::listen().filter_map(handle_hotkey)])\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        const MINUTE: u64 = 60;\n        const HOUR: u64 = 60 * MINUTE;\n\n        let seconds = self.duration.as_secs();\n\n        let duration = text!(\n            \"{:0>2}:{:0>2}:{:0>2}.{:0>2}\",\n            seconds / HOUR,\n            (seconds % HOUR) / MINUTE,\n            seconds % MINUTE,\n            self.duration.subsec_millis() / 10,\n        )\n        .size(40);\n\n        let button = |label| button(text(label).align_x(Center)).padding(10).width(80);\n\n        let toggle_button = {\n            let label = match self.state {\n                State::Idle => \"Start\",\n                State::Ticking { .. } => \"Stop\",\n            };\n\n            button(label).on_press(Message::Toggle)\n        };\n\n        let reset_button = button(\"Reset\")\n            .style(button::danger)\n            .on_press(Message::Reset);\n\n        let controls = row![toggle_button, reset_button].spacing(20);\n\n        let content = column![duration, controls].align_x(Center).spacing(20);\n\n        center(content).into()\n    }\n}\n"
  },
  {
    "path": "examples/styling/Cargo.toml",
    "content": "[package]\nname = \"styling\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\n\n[dev-dependencies]\niced_test.workspace = true\nrayon = \"1\"\n"
  },
  {
    "path": "examples/styling/README.md",
    "content": "# Styling\nAn example showcasing custom styling with a light and dark theme.\n\nAll the example code is located in the __[`main`](src/main.rs)__ file.\n\n<div align=\"center\">\n  <img src=\"https://iced.rs/examples/styling.gif\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package styling\n```\n"
  },
  {
    "path": "examples/styling/snapshots/catppuccin_frappé-tiny-skia.sha256",
    "content": "4a602409066a7506b35b7564187d9b91ad2a278c034a2a27047245d3603e106e"
  },
  {
    "path": "examples/styling/snapshots/catppuccin_latte-tiny-skia.sha256",
    "content": "05ff440c3ca4cfe27bd4540b68d3579f34082da2dc9b65195a2f3cb5c481f66d"
  },
  {
    "path": "examples/styling/snapshots/catppuccin_macchiato-tiny-skia.sha256",
    "content": "a887c61a62121e95d118ee11e5263e3ea6054a469d04e4e040b468dda2985eee"
  },
  {
    "path": "examples/styling/snapshots/catppuccin_mocha-tiny-skia.sha256",
    "content": "883a505d5c855d8c5400e2dc5231580cd320c8801600333478270a8d8ea42bbd"
  },
  {
    "path": "examples/styling/snapshots/dark-tiny-skia.sha256",
    "content": "e67c164f725d92837c0f67ec49ce676156d46e1302d382bc3dc67255087fcd1d"
  },
  {
    "path": "examples/styling/snapshots/dracula-tiny-skia.sha256",
    "content": "54bfddd255c34f469e3c98afec573cce6aca4bbe11df19111eb0b1055cb2f0d4"
  },
  {
    "path": "examples/styling/snapshots/ferra-tiny-skia.sha256",
    "content": "2159a7041d66a76d0eff150f2d3a50c6393d294859e67351b0858dd21fac6887"
  },
  {
    "path": "examples/styling/snapshots/gruvbox_dark-tiny-skia.sha256",
    "content": "88938aaeaed5f1ba0bd3dfc290764a93819b2321ac339e33dc58fdaf780bbea1"
  },
  {
    "path": "examples/styling/snapshots/gruvbox_light-tiny-skia.sha256",
    "content": "94f6071d7fb4a6d93a351f219194a48e93ddc9494a735ef2eaf89dbb7e719563"
  },
  {
    "path": "examples/styling/snapshots/kanagawa_dragon-tiny-skia.sha256",
    "content": "42fd4986288be2e3173499e5631018c112d1f139e92632531e21272c3f179274"
  },
  {
    "path": "examples/styling/snapshots/kanagawa_lotus-tiny-skia.sha256",
    "content": "de9aa60d77e94e586b9a8e4f411166cfa4377d17bcea491b60a0fd75cbfe887c"
  },
  {
    "path": "examples/styling/snapshots/kanagawa_wave-tiny-skia.sha256",
    "content": "9e85b76b1ab91c0dc0e9cb21ad0ce28445fff2a17924f8e1221fa25f24a646c5"
  },
  {
    "path": "examples/styling/snapshots/light-tiny-skia.sha256",
    "content": "3aa01b2e64fc23b85e2489c1f32a3295123a3dc8fa62f12652d7bd1524af7eec"
  },
  {
    "path": "examples/styling/snapshots/moonfly-tiny-skia.sha256",
    "content": "57e5e9f1eb3b1f2950e79a66a0e581f2e8dea74a35ec0c590fb93057d7de50eb"
  },
  {
    "path": "examples/styling/snapshots/nightfly-tiny-skia.sha256",
    "content": "1cac75136e18c821921d06b8ce349f15bb0886ea46fca85598c18e63890a447e"
  },
  {
    "path": "examples/styling/snapshots/nord-tiny-skia.sha256",
    "content": "b00759f66ce6c7e04efe48ad6480a2f374777ddf3b52291f0ba45734813f339d"
  },
  {
    "path": "examples/styling/snapshots/oxocarbon-tiny-skia.sha256",
    "content": "70d7e219c88ca56c1f77e6aa427cc0c8a7d20219a76f6c5738d38f1cd78c7fae"
  },
  {
    "path": "examples/styling/snapshots/solarized_dark-tiny-skia.sha256",
    "content": "06a9e730406f07f2619f980ac5d77db61075e54899ec0d3c82eaa7c9829c643d"
  },
  {
    "path": "examples/styling/snapshots/solarized_light-tiny-skia.sha256",
    "content": "e134aaba0aedddec5784f83950a32384071cc1341e6b7dfa703451dc5030a38e"
  },
  {
    "path": "examples/styling/snapshots/tokyo_night-tiny-skia.sha256",
    "content": "7d35f80b930fb45dd4de2884c5994d21024eaadf20b049d9ef9a3bb9b1c12e4b"
  },
  {
    "path": "examples/styling/snapshots/tokyo_night_light-tiny-skia.sha256",
    "content": "dc240086ba66e2fb97877c0b84e62df924b851996c2659c565cbdda7f23e17aa"
  },
  {
    "path": "examples/styling/snapshots/tokyo_night_storm-tiny-skia.sha256",
    "content": "bdca14fd8383405faf2f88ecd2cf9a248864294de68745be9b7547b2dcd25c51"
  },
  {
    "path": "examples/styling/src/main.rs",
    "content": "use iced::keyboard;\nuse iced::widget::{\n    button, center_x, center_y, checkbox, column, container, pick_list, progress_bar, row, rule,\n    scrollable, slider, space, text, text_input, toggler,\n};\nuse iced::{Center, Element, Fill, Shrink, Subscription, Theme};\n\npub fn main() -> iced::Result {\n    iced::application(Styling::default, Styling::update, Styling::view)\n        .subscription(Styling::subscription)\n        .theme(Styling::theme)\n        .run()\n}\n\n#[derive(Default)]\nstruct Styling {\n    theme: Option<Theme>,\n    input_value: String,\n    slider_value: f32,\n    checkbox_value: bool,\n    toggler_value: bool,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    ThemeChanged(Theme),\n    InputChanged(String),\n    ButtonPressed,\n    SliderChanged(f32),\n    CheckboxToggled(bool),\n    TogglerToggled(bool),\n    PreviousTheme,\n    NextTheme,\n    ClearTheme,\n}\n\nimpl Styling {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::ThemeChanged(theme) => {\n                self.theme = Some(theme);\n            }\n            Message::InputChanged(value) => self.input_value = value,\n            Message::ButtonPressed => {}\n            Message::SliderChanged(value) => self.slider_value = value,\n            Message::CheckboxToggled(value) => self.checkbox_value = value,\n            Message::TogglerToggled(value) => self.toggler_value = value,\n            Message::PreviousTheme | Message::NextTheme => {\n                let current = Theme::ALL\n                    .iter()\n                    .position(|candidate| self.theme.as_ref() == Some(candidate));\n\n                self.theme = Some(if matches!(message, Message::NextTheme) {\n                    Theme::ALL[current.map(|current| current + 1).unwrap_or(0) % Theme::ALL.len()]\n                        .clone()\n                } else {\n                    let current = current.unwrap_or(0);\n\n                    if current == 0 {\n                        Theme::ALL\n                            .last()\n                            .expect(\"Theme::ALL must not be empty\")\n                            .clone()\n                    } else {\n                        Theme::ALL[current - 1].clone()\n                    }\n                });\n            }\n            Message::ClearTheme => {\n                self.theme = None;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let choose_theme = column![\n            text(\"Theme:\"),\n            pick_list(self.theme.as_ref(), Theme::ALL, Theme::to_string)\n                .on_select(Message::ThemeChanged)\n                .width(Fill)\n                .placeholder(\"System\"),\n        ]\n        .spacing(10);\n\n        let text_input = text_input(\"Type something...\", &self.input_value)\n            .on_input(Message::InputChanged)\n            .padding(10)\n            .size(20);\n\n        let buttons = {\n            let styles = [\n                (\"Primary\", button::primary as fn(&Theme, _) -> _),\n                (\"Secondary\", button::secondary),\n                (\"Success\", button::success),\n                (\"Warning\", button::warning),\n                (\"Danger\", button::danger),\n            ];\n\n            let styled_button = |label| button(text(label).width(Fill).center()).padding(10);\n\n            column![\n                row(styles.into_iter().map(|(name, style)| styled_button(name)\n                    .on_press(Message::ButtonPressed)\n                    .style(style)\n                    .into()))\n                .spacing(10)\n                .align_y(Center),\n                row(styles\n                    .into_iter()\n                    .map(|(name, style)| styled_button(name).style(style).into()))\n                .spacing(10)\n                .align_y(Center),\n            ]\n            .spacing(10)\n        };\n\n        let slider = || slider(0.0..=100.0, self.slider_value, Message::SliderChanged);\n\n        let progress_bar = || progress_bar(0.0..=100.0, self.slider_value);\n\n        let scroll_me = scrollable(column![\"Scroll me!\", space().height(800), \"You did it!\"])\n            .width(Fill)\n            .height(Fill)\n            .auto_scroll(true);\n\n        let check = checkbox(self.checkbox_value)\n            .label(\"Check me!\")\n            .on_toggle(Message::CheckboxToggled);\n\n        let check_disabled = checkbox(self.checkbox_value).label(\"Disabled\");\n\n        let toggle = toggler(self.toggler_value)\n            .label(\"Toggle me!\")\n            .on_toggle(Message::TogglerToggled);\n\n        let disabled_toggle = toggler(self.toggler_value).label(\"Disabled\");\n\n        let card = {\n            container(column![text(\"Card Example\").size(24), slider(), progress_bar(),].spacing(20))\n                .width(Fill)\n                .padding(20)\n                .style(container::bordered_box)\n        };\n\n        let content = column![\n            choose_theme,\n            rule::horizontal(1),\n            text_input,\n            buttons,\n            slider(),\n            progress_bar(),\n            row![\n                scroll_me,\n                rule::vertical(1),\n                column![check, check_disabled, toggle, disabled_toggle].spacing(10),\n            ]\n            .spacing(10)\n            .height(Shrink)\n            .align_y(Center),\n            card\n        ]\n        .spacing(20)\n        .padding(20)\n        .max_width(600);\n\n        center_y(scrollable(center_x(content)).spacing(10))\n            .padding(10)\n            .into()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        keyboard::listen().filter_map(|event| {\n            let keyboard::Event::KeyPressed {\n                modified_key: keyboard::Key::Named(modified_key),\n                repeat: false,\n                ..\n            } = event\n            else {\n                return None;\n            };\n\n            match modified_key {\n                keyboard::key::Named::ArrowUp | keyboard::key::Named::ArrowLeft => {\n                    Some(Message::PreviousTheme)\n                }\n                keyboard::key::Named::ArrowDown | keyboard::key::Named::ArrowRight => {\n                    Some(Message::NextTheme)\n                }\n                keyboard::key::Named::Space => Some(Message::ClearTheme),\n                _ => None,\n            }\n        })\n    }\n\n    fn theme(&self) -> Option<Theme> {\n        self.theme.clone()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use rayon::prelude::*;\n\n    use iced_test::{Error, simulator};\n\n    #[test]\n    #[ignore]\n    fn it_showcases_every_theme() -> Result<(), Error> {\n        Theme::ALL\n            .par_iter()\n            .cloned()\n            .map(|theme| {\n                let mut styling = Styling::default();\n                styling.update(Message::ThemeChanged(theme.clone()));\n\n                let mut ui = simulator(styling.view());\n                let snapshot = ui.snapshot(&theme)?;\n\n                assert!(\n                    snapshot.matches_hash(format!(\n                        \"snapshots/{theme}\",\n                        theme = theme.to_string().to_ascii_lowercase().replace(\" \", \"_\")\n                    ))?,\n                    \"snapshots for {theme} should match!\"\n                );\n\n                Ok(())\n            })\n            .collect()\n    }\n}\n"
  },
  {
    "path": "examples/svg/Cargo.toml",
    "content": "[package]\nname = \"svg\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"svg\"]\n"
  },
  {
    "path": "examples/svg/README.md",
    "content": "## SVG\n\nAn application that renders the [Ghostscript Tiger] by leveraging the `Svg` widget.\n\nThe __[`main`]__ file contains all the code of the example.\n\n<div align=\"center\">\n  <img src=\"resources/tiger.svg\">\n</div>\n\nYou can run it with `cargo run`:\n```\ncargo run --package svg\n```\n\n[`main`]: src/main.rs\n[Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg\n"
  },
  {
    "path": "examples/svg/src/main.rs",
    "content": "use iced::widget::{center, center_x, checkbox, column, svg};\nuse iced::{Element, Fill, color};\n\npub fn main() -> iced::Result {\n    iced::run(Tiger::update, Tiger::view)\n}\n\n#[derive(Debug, Default)]\nstruct Tiger {\n    apply_color_filter: bool,\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum Message {\n    ToggleColorFilter(bool),\n}\n\nimpl Tiger {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::ToggleColorFilter(apply_color_filter) => {\n                self.apply_color_filter = apply_color_filter;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let svg = svg(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/resources/tiger.svg\"))\n            .width(Fill)\n            .height(Fill)\n            .style(|_theme, _status| svg::Style {\n                color: if self.apply_color_filter {\n                    Some(color!(0x0000ff))\n                } else {\n                    None\n                },\n            });\n\n        let apply_color_filter = checkbox(self.apply_color_filter)\n            .label(\"Apply a color filter\")\n            .on_toggle(Message::ToggleColorFilter);\n\n        center(column![svg, center_x(apply_color_filter)].spacing(20))\n            .padding(20)\n            .into()\n    }\n}\n"
  },
  {
    "path": "examples/system_information/Cargo.toml",
    "content": "[package]\nname = \"system_information\"\nversion = \"0.1.0\"\nauthors = [\"Richard <richardsoncusto@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"sysinfo\"]\n\nbytesize = \"1.1\"\n"
  },
  {
    "path": "examples/system_information/src/main.rs",
    "content": "use iced::system;\nuse iced::widget::{button, center, column, text};\nuse iced::{Element, Task};\n\npub fn main() -> iced::Result {\n    iced::application(Example::new, Example::update, Example::view).run()\n}\n\n#[derive(Default)]\n#[allow(clippy::large_enum_variant)]\nenum Example {\n    #[default]\n    Loading,\n    Loaded {\n        information: system::Information,\n    },\n}\n\n#[derive(Clone, Debug)]\n#[allow(clippy::large_enum_variant)]\nenum Message {\n    InformationReceived(system::Information),\n    Refresh,\n}\n\nimpl Example {\n    fn new() -> (Self, Task<Message>) {\n        (\n            Self::Loading,\n            system::information().map(Message::InformationReceived),\n        )\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::Refresh => {\n                let (state, refresh) = Self::new();\n\n                *self = state;\n\n                refresh\n            }\n            Message::InformationReceived(information) => {\n                *self = Self::Loaded { information };\n\n                Task::none()\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        use bytesize::ByteSize;\n\n        let content: Element<_> = match self {\n            Example::Loading => text(\"Loading...\").size(40).into(),\n            Example::Loaded { information } => {\n                let system_name = text!(\n                    \"System name: {}\",\n                    information\n                        .system_name\n                        .as_ref()\n                        .unwrap_or(&\"unknown\".to_string())\n                );\n\n                let system_kernel = text!(\n                    \"System kernel: {}\",\n                    information\n                        .system_kernel\n                        .as_ref()\n                        .unwrap_or(&\"unknown\".to_string())\n                );\n\n                let system_version = text!(\n                    \"System version: {}\",\n                    information\n                        .system_version\n                        .as_ref()\n                        .unwrap_or(&\"unknown\".to_string())\n                );\n\n                let system_short_version = text!(\n                    \"System short version: {}\",\n                    information\n                        .system_short_version\n                        .as_ref()\n                        .unwrap_or(&\"unknown\".to_string())\n                );\n\n                let cpu_brand = text!(\"Processor brand: {}\", information.cpu_brand);\n\n                let cpu_cores = text!(\n                    \"Processor cores: {}\",\n                    information\n                        .cpu_cores\n                        .map_or(\"unknown\".to_string(), |cores| cores.to_string())\n                );\n\n                let memory_readable = ByteSize::b(information.memory_total).to_string_as(true);\n\n                let memory_total = text!(\n                    \"Memory (total): {} bytes ({memory_readable})\",\n                    information.memory_total,\n                );\n\n                let memory_text = if let Some(memory_used) = information.memory_used {\n                    let memory_readable = ByteSize::b(memory_used).to_string_as(true);\n\n                    format!(\"{memory_used} bytes ({memory_readable})\")\n                } else {\n                    String::from(\"None\")\n                };\n\n                let memory_used = text!(\"Memory (used): {memory_text}\");\n\n                let graphics_adapter = text!(\"Graphics adapter: {}\", information.graphics_adapter);\n\n                let graphics_backend = text!(\"Graphics backend: {}\", information.graphics_backend);\n\n                column![\n                    system_name.size(30),\n                    system_kernel.size(30),\n                    system_version.size(30),\n                    system_short_version.size(30),\n                    cpu_brand.size(30),\n                    cpu_cores.size(30),\n                    memory_total.size(30),\n                    memory_used.size(30),\n                    graphics_adapter.size(30),\n                    graphics_backend.size(30),\n                    button(\"Refresh\").on_press(Message::Refresh)\n                ]\n                .spacing(10)\n                .into()\n            }\n        };\n\n        center(content).into()\n    }\n}\n"
  },
  {
    "path": "examples/table/Cargo.toml",
    "content": "[package]\nname = \"table\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\"]\n"
  },
  {
    "path": "examples/table/src/main.rs",
    "content": "use iced::font;\nuse iced::time::{Duration, hours, minutes};\nuse iced::widget::{\n    center_x, center_y, column, container, row, scrollable, slider, table, text, tooltip,\n};\nuse iced::{Center, Element, Fill, Font, Right, Theme};\n\npub fn main() -> iced::Result {\n    iced::application(Table::new, Table::update, Table::view)\n        .theme(Theme::CatppuccinMocha)\n        .run()\n}\n\nstruct Table {\n    events: Vec<Event>,\n    padding: (f32, f32),\n    separator: (f32, f32),\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    PaddingChanged(f32, f32),\n    SeparatorChanged(f32, f32),\n}\n\nimpl Table {\n    fn new() -> Self {\n        Self {\n            events: Event::list(),\n            padding: (10.0, 5.0),\n            separator: (1.0, 1.0),\n        }\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::PaddingChanged(x, y) => self.padding = (x, y),\n            Message::SeparatorChanged(x, y) => self.separator = (x, y),\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let table = {\n            let bold = |header| {\n                text(header).font(Font {\n                    weight: font::Weight::Bold,\n                    ..Font::DEFAULT\n                })\n            };\n\n            let columns = [\n                table::column(bold(\"Name\"), |event: &Event| text(&event.name)),\n                table::column(bold(\"Time\"), |event: &Event| {\n                    let minutes = event.duration.as_secs() / 60;\n\n                    text!(\"{minutes} min\").style(if minutes > 90 {\n                        text::warning\n                    } else {\n                        text::default\n                    })\n                })\n                .align_x(Right)\n                .align_y(Center),\n                table::column(bold(\"Price\"), |event: &Event| {\n                    if event.price > 0.0 {\n                        text!(\"${:.2}\", event.price).style(if event.price > 100.0 {\n                            text::warning\n                        } else {\n                            text::default\n                        })\n                    } else {\n                        text(\"Free\").style(text::success).width(Fill).center()\n                    }\n                })\n                .align_x(Right)\n                .align_y(Center),\n                table::column(bold(\"Rating\"), |event: &Event| {\n                    text!(\"{:.2}\", event.rating).style(if event.rating > 4.7 {\n                        text::success\n                    } else if event.rating < 2.0 {\n                        text::danger\n                    } else {\n                        text::default\n                    })\n                })\n                .align_x(Right)\n                .align_y(Center),\n            ];\n\n            table(columns, &self.events)\n                .padding_x(self.padding.0)\n                .padding_y(self.padding.1)\n                .separator_x(self.separator.0)\n                .separator_y(self.separator.1)\n        };\n\n        let controls = {\n            let labeled_slider =\n                |label,\n                 range: std::ops::RangeInclusive<f32>,\n                 (x, y),\n                 on_change: fn(f32, f32) -> Message| {\n                    row![\n                        text(label).font(Font::MONOSPACE).size(14).width(100),\n                        tooltip(\n                            slider(range.clone(), x, move |x| on_change(x, y)),\n                            text!(\"{x:.0}px\").font(Font::MONOSPACE).size(10),\n                            tooltip::Position::Left\n                        ),\n                        tooltip(\n                            slider(range, y, move |y| on_change(x, y)),\n                            text!(\"{y:.0}px\").font(Font::MONOSPACE).size(10),\n                            tooltip::Position::Right\n                        ),\n                    ]\n                    .spacing(10)\n                    .align_y(Center)\n                };\n\n            column![\n                labeled_slider(\"Padding\", 0.0..=30.0, self.padding, Message::PaddingChanged),\n                labeled_slider(\n                    \"Separator\",\n                    0.0..=5.0,\n                    self.separator,\n                    Message::SeparatorChanged\n                )\n            ]\n            .spacing(10)\n            .width(400)\n        };\n\n        column![\n            center_y(scrollable(center_x(table)).spacing(10)).padding(10),\n            center_x(controls).padding(10).style(container::dark)\n        ]\n        .into()\n    }\n}\n\nstruct Event {\n    name: String,\n    duration: Duration,\n    price: f32,\n    rating: f32,\n}\n\nimpl Event {\n    fn list() -> Vec<Self> {\n        vec![\n            Event {\n                name: \"Get lost in a hacker bookstore\".to_owned(),\n                duration: hours(2),\n                price: 0.0,\n                rating: 4.9,\n            },\n            Event {\n                name: \"Buy vintage synth at Noisebridge flea market\".to_owned(),\n                duration: hours(1),\n                price: 150.0,\n                rating: 4.8,\n            },\n            Event {\n                name: \"Eat a questionable hot dog at 2AM\".to_owned(),\n                duration: minutes(20),\n                price: 5.0,\n                rating: 1.7,\n            },\n            Event {\n                name: \"Ride the MUNI for the story\".to_owned(),\n                duration: minutes(60),\n                price: 3.0,\n                rating: 4.1,\n            },\n            Event {\n                name: \"Scream into the void from Twin Peaks\".to_owned(),\n                duration: minutes(40),\n                price: 0.0,\n                rating: 4.9,\n            },\n            Event {\n                name: \"Buy overpriced coffee and feel things\".to_owned(),\n                duration: minutes(25),\n                price: 6.5,\n                rating: 4.5,\n            },\n            Event {\n                name: \"Attend an underground robot poetry slam\".to_owned(),\n                duration: hours(1),\n                price: 12.0,\n                rating: 4.8,\n            },\n            Event {\n                name: \"Browse cursed tech at a retro computer fair\".to_owned(),\n                duration: hours(2),\n                price: 10.0,\n                rating: 4.7,\n            },\n            Event {\n                name: \"Try to order at a secret ramen place with no sign\".to_owned(),\n                duration: minutes(50),\n                price: 14.0,\n                rating: 4.6,\n            },\n            Event {\n                name: \"Join a spontaneous rooftop drone rave\".to_owned(),\n                duration: hours(3),\n                price: 0.0,\n                rating: 4.9,\n            },\n            Event {\n                name: \"Sketch a stranger at Dolores Park\".to_owned(),\n                duration: minutes(45),\n                price: 0.0,\n                rating: 4.4,\n            },\n            Event {\n                name: \"Visit the Museum of Obsolete APIs\".to_owned(),\n                duration: hours(1),\n                price: 9.99,\n                rating: 4.2,\n            },\n            Event {\n                name: \"Chase the last working payphone\".to_owned(),\n                duration: minutes(35),\n                price: 0.25,\n                rating: 4.0,\n            },\n            Event {\n                name: \"Trade zines with a punk on BART\".to_owned(),\n                duration: minutes(30),\n                price: 3.5,\n                rating: 4.7,\n            },\n            Event {\n                name: \"Get a tattoo of the Git logo\".to_owned(),\n                duration: hours(1),\n                price: 200.0,\n                rating: 4.6,\n            },\n        ]\n    }\n}\n"
  },
  {
    "path": "examples/text/Cargo.toml",
    "content": "[package]\nname = \"text\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\niced.workspace = true\niced.features = [\"webgl\", \"fira-sans\"]\n"
  },
  {
    "path": "examples/text/src/main.rs",
    "content": "use iced::event;\nuse iced::font;\nuse iced::widget::{center, column, pick_list, right, stack, text};\nuse iced::window;\nuse iced::{Element, Event, Font, Subscription, Task};\n\npub fn main() -> iced::Result {\n    iced::application(Text::new, Text::update, Text::view)\n        .subscription(Text::subscription)\n        .run()\n}\n\nstruct Text {\n    scale_factor: f32,\n    font: Font,\n    families: Vec<font::Family>,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    WindowRescaled(f32),\n    FontChanged(font::Family),\n    FontsListed(Vec<font::Family>),\n}\n\nimpl Text {\n    fn new() -> (Self, Task<Message>) {\n        (\n            Self {\n                font: Font::DEFAULT,\n                scale_factor: 1.0,\n                families: font::Family::VARIANTS.to_vec(),\n            },\n            Task::batch([\n                window::latest()\n                    .and_then(window::scale_factor)\n                    .map(Message::WindowRescaled),\n                font::list()\n                    .map(Result::ok)\n                    .and_then(Task::done)\n                    .map(Message::FontsListed),\n            ]),\n        )\n    }\n\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::WindowRescaled(scale_factor) => {\n                self.scale_factor = scale_factor;\n            }\n            Message::FontChanged(family) => {\n                self.font = Font::with_family(family);\n            }\n            Message::FontsListed(families) => {\n                self.families = families\n                    .into_iter()\n                    .chain(font::Family::VARIANTS.iter().copied())\n                    .collect();\n            }\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        event::listen_with(|event, _, _| {\n            let Event::Window(window::Event::Rescaled(scale_factor)) = event else {\n                return None;\n            };\n\n            Some(Message::WindowRescaled(scale_factor))\n        })\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let sizes = 5..=32;\n\n        let font_selector = pick_list(\n            Some(self.font.family),\n            self.families.as_slice(),\n            font::Family::to_string,\n        )\n        .on_select(Message::FontChanged);\n\n        stack![\n            center(\n                column(sizes.map(|physical_size| {\n                    let size = physical_size as f32 / self.scale_factor;\n\n                    text!(\n                        \"The quick brown fox jumps over the \\\n                        lazy dog ({physical_size}px)\"\n                    )\n                    .font(self.font)\n                    .size(size)\n                    .into()\n                }))\n                .spacing(10)\n            ),\n            right(font_selector).padding(10)\n        ]\n        .into()\n    }\n}\n"
  },
  {
    "path": "examples/the_matrix/Cargo.toml",
    "content": "[package]\nname = \"the_matrix\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"canvas\", \"tokio\", \"debug\"]\n\nrand = \"0.8\"\ntracing-subscriber = \"0.3\"\n"
  },
  {
    "path": "examples/the_matrix/src/main.rs",
    "content": "use iced::mouse;\nuse iced::time::{self, milliseconds};\nuse iced::widget::canvas;\nuse iced::{Color, Element, Fill, Font, Point, Rectangle, Renderer, Subscription, Theme};\n\nuse std::cell::RefCell;\n\npub fn main() -> iced::Result {\n    tracing_subscriber::fmt::init();\n\n    iced::application(TheMatrix::default, TheMatrix::update, TheMatrix::view)\n        .subscription(TheMatrix::subscription)\n        .run()\n}\n\n#[derive(Default)]\nstruct TheMatrix {\n    tick: usize,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    Tick,\n}\n\nimpl TheMatrix {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::Tick => {\n                self.tick += 1;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        canvas(self).width(Fill).height(Fill).into()\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        time::every(milliseconds(50)).map(|_| Message::Tick)\n    }\n}\n\nimpl<Message> canvas::Program<Message> for TheMatrix {\n    type State = RefCell<Vec<canvas::Cache>>;\n\n    fn draw(\n        &self,\n        state: &Self::State,\n        renderer: &Renderer,\n        _theme: &Theme,\n        bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Vec<canvas::Geometry> {\n        use rand::Rng;\n        use rand::distributions::Distribution;\n\n        const CELL_SIZE: f32 = 10.0;\n\n        let mut caches = state.borrow_mut();\n\n        if caches.is_empty() {\n            let group = canvas::Group::unique();\n\n            caches.resize_with(30, || canvas::Cache::with_group(group));\n        }\n\n        vec![\n            caches[self.tick % caches.len()].draw(renderer, bounds.size(), |frame| {\n                frame.fill_rectangle(Point::ORIGIN, frame.size(), Color::BLACK);\n\n                let mut rng = rand::thread_rng();\n                let rows = (frame.height() / CELL_SIZE).ceil() as usize;\n                let columns = (frame.width() / CELL_SIZE).ceil() as usize;\n\n                for row in 0..rows {\n                    for column in 0..columns {\n                        let position =\n                            Point::new(column as f32 * CELL_SIZE, row as f32 * CELL_SIZE);\n\n                        let alphas = [0.05, 0.1, 0.2, 0.5];\n                        let weights = [10, 4, 2, 1];\n                        let distribution = rand::distributions::WeightedIndex::new(weights)\n                            .expect(\"Create distribution\");\n\n                        frame.fill_text(canvas::Text {\n                            content: rng.gen_range('!'..'z').to_string(),\n                            position,\n                            color: Color {\n                                a: alphas[distribution.sample(&mut rng)],\n                                g: 1.0,\n                                ..Color::BLACK\n                            },\n                            size: CELL_SIZE.into(),\n                            font: Font::MONOSPACE,\n                            ..canvas::Text::default()\n                        });\n                    }\n                }\n            }),\n        ]\n    }\n}\n"
  },
  {
    "path": "examples/toast/Cargo.toml",
    "content": "[package]\nname = \"toast\"\nversion = \"0.1.0\"\nauthors = [\"tarkah <admin@tarkah.dev>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"advanced\"]\n"
  },
  {
    "path": "examples/toast/src/main.rs",
    "content": "use iced::event::{self, Event};\nuse iced::keyboard;\nuse iced::keyboard::key;\nuse iced::widget::{button, center, column, operation, pick_list, row, slider, text, text_input};\nuse iced::{Center, Element, Fill, Subscription, Task};\n\nuse toast::{Status, Toast};\n\npub fn main() -> iced::Result {\n    iced::application(App::default, App::update, App::view)\n        .subscription(App::subscription)\n        .run()\n}\n\nstruct App {\n    toasts: Vec<Toast>,\n    editing: Toast,\n    timeout_secs: u64,\n}\n\n#[derive(Debug, Clone)]\n#[allow(clippy::enum_variant_names)]\nenum Message {\n    Add,\n    Close(usize),\n    Title(String),\n    Body(String),\n    Status(Status),\n    Timeout(f64),\n    Event(Event),\n}\n\nimpl App {\n    fn new() -> Self {\n        App {\n            toasts: vec![Toast {\n                title: \"Example Toast\".into(),\n                body: \"Add more toasts in the form below!\".into(),\n                status: Status::Primary,\n            }],\n            timeout_secs: toast::DEFAULT_TIMEOUT,\n            editing: Toast::default(),\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        event::listen().map(Message::Event)\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::Add => {\n                if !self.editing.title.is_empty() && !self.editing.body.is_empty() {\n                    self.toasts.push(std::mem::take(&mut self.editing));\n                }\n                Task::none()\n            }\n            Message::Close(index) => {\n                self.toasts.remove(index);\n                Task::none()\n            }\n            Message::Title(title) => {\n                self.editing.title = title;\n                Task::none()\n            }\n            Message::Body(body) => {\n                self.editing.body = body;\n                Task::none()\n            }\n            Message::Status(status) => {\n                self.editing.status = status;\n                Task::none()\n            }\n            Message::Timeout(timeout) => {\n                self.timeout_secs = timeout as u64;\n                Task::none()\n            }\n            Message::Event(Event::Keyboard(keyboard::Event::KeyPressed {\n                key: keyboard::Key::Named(key::Named::Tab),\n                modifiers,\n                ..\n            })) if modifiers.shift() => operation::focus_previous(),\n            Message::Event(Event::Keyboard(keyboard::Event::KeyPressed {\n                key: keyboard::Key::Named(key::Named::Tab),\n                ..\n            })) => operation::focus_next(),\n            Message::Event(_) => Task::none(),\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let subtitle = |title, content: Element<'static, Message>| {\n            column![text(title).size(14), content].spacing(5)\n        };\n\n        let add_toast = button(\"Add Toast\").on_press_maybe(\n            (!self.editing.body.is_empty() && !self.editing.title.is_empty())\n                .then_some(Message::Add),\n        );\n\n        let content = center(\n            column![\n                subtitle(\n                    \"Title\",\n                    text_input(\"\", &self.editing.title)\n                        .on_input(Message::Title)\n                        .on_submit(Message::Add)\n                        .into()\n                ),\n                subtitle(\n                    \"Message\",\n                    text_input(\"\", &self.editing.body)\n                        .on_input(Message::Body)\n                        .on_submit(Message::Add)\n                        .into()\n                ),\n                subtitle(\n                    \"Status\",\n                    pick_list(\n                        Some(self.editing.status),\n                        toast::Status::ALL,\n                        toast::Status::to_string\n                    )\n                    .on_select(Message::Status)\n                    .width(Fill)\n                    .into()\n                ),\n                subtitle(\n                    \"Timeout\",\n                    row![\n                        text!(\"{:0>2} sec\", self.timeout_secs),\n                        slider(1.0..=30.0, self.timeout_secs as f64, Message::Timeout).step(1.0)\n                    ]\n                    .spacing(5)\n                    .into()\n                ),\n                column![add_toast].align_x(Center)\n            ]\n            .spacing(10)\n            .max_width(200),\n        );\n\n        toast::Manager::new(content, &self.toasts, Message::Close)\n            .timeout(self.timeout_secs)\n            .into()\n    }\n}\n\nimpl Default for App {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nmod toast {\n    use std::fmt;\n\n    use iced::advanced::layout::{self, Layout};\n    use iced::advanced::overlay;\n    use iced::advanced::renderer;\n    use iced::advanced::widget::{self, Operation, Tree};\n    use iced::advanced::{Shell, Widget};\n    use iced::mouse;\n    use iced::time::{self, Duration, Instant};\n    use iced::widget::{button, column, container, row, rule, space, text};\n    use iced::window;\n    use iced::{\n        Alignment, Center, Element, Event, Fill, Length, Point, Rectangle, Renderer, Size, Theme,\n        Vector,\n    };\n\n    pub const DEFAULT_TIMEOUT: u64 = 5;\n\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\n    pub enum Status {\n        #[default]\n        Primary,\n        Secondary,\n        Success,\n        Danger,\n        Warning,\n    }\n\n    impl Status {\n        pub const ALL: &'static [Self] = &[\n            Self::Primary,\n            Self::Secondary,\n            Self::Success,\n            Self::Danger,\n            Self::Warning,\n        ];\n    }\n\n    impl fmt::Display for Status {\n        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n            match self {\n                Status::Primary => \"Primary\",\n                Status::Secondary => \"Secondary\",\n                Status::Success => \"Success\",\n                Status::Danger => \"Danger\",\n                Status::Warning => \"Warning\",\n            }\n            .fmt(f)\n        }\n    }\n\n    #[derive(Debug, Clone, Default)]\n    pub struct Toast {\n        pub title: String,\n        pub body: String,\n        pub status: Status,\n    }\n\n    pub struct Manager<'a, Message> {\n        content: Element<'a, Message>,\n        toasts: Vec<Element<'a, Message>>,\n        timeout_secs: u64,\n        on_close: Box<dyn Fn(usize) -> Message + 'a>,\n    }\n\n    impl<'a, Message> Manager<'a, Message>\n    where\n        Message: 'a + Clone,\n    {\n        pub fn new(\n            content: impl Into<Element<'a, Message>>,\n            toasts: &'a [Toast],\n            on_close: impl Fn(usize) -> Message + 'a,\n        ) -> Self {\n            let toasts = toasts\n                .iter()\n                .enumerate()\n                .map(|(index, toast)| {\n                    container(column![\n                        container(\n                            row![\n                                text(toast.title.as_str()),\n                                space::horizontal(),\n                                button(\"X\").on_press((on_close)(index)).padding(3),\n                            ]\n                            .align_y(Center)\n                        )\n                        .width(Fill)\n                        .padding(5)\n                        .style(match toast.status {\n                            Status::Primary => container::primary,\n                            Status::Secondary => container::secondary,\n                            Status::Success => container::success,\n                            Status::Danger => container::danger,\n                            Status::Warning => container::warning,\n                        }),\n                        rule::horizontal(1),\n                        container(text(toast.body.as_str()))\n                            .width(Fill)\n                            .padding(5)\n                            .style(container::rounded_box),\n                    ])\n                    .max_width(200)\n                    .into()\n                })\n                .collect();\n\n            Self {\n                content: content.into(),\n                toasts,\n                timeout_secs: DEFAULT_TIMEOUT,\n                on_close: Box::new(on_close),\n            }\n        }\n\n        pub fn timeout(self, seconds: u64) -> Self {\n            Self {\n                timeout_secs: seconds,\n                ..self\n            }\n        }\n    }\n\n    impl<Message> Widget<Message, Theme, Renderer> for Manager<'_, Message> {\n        fn size(&self) -> Size<Length> {\n            self.content.as_widget().size()\n        }\n\n        fn layout(\n            &mut self,\n            tree: &mut Tree,\n            renderer: &Renderer,\n            limits: &layout::Limits,\n        ) -> layout::Node {\n            self.content\n                .as_widget_mut()\n                .layout(&mut tree.children[0], renderer, limits)\n        }\n\n        fn tag(&self) -> widget::tree::Tag {\n            struct Marker;\n            widget::tree::Tag::of::<Marker>()\n        }\n\n        fn state(&self) -> widget::tree::State {\n            widget::tree::State::new(Vec::<Option<Instant>>::new())\n        }\n\n        fn children(&self) -> Vec<Tree> {\n            std::iter::once(Tree::new(&self.content))\n                .chain(self.toasts.iter().map(Tree::new))\n                .collect()\n        }\n\n        fn diff(&self, tree: &mut Tree) {\n            let instants = tree.state.downcast_mut::<Vec<Option<Instant>>>();\n\n            // Invalidating removed instants to None allows us to remove\n            // them here so that diffing for removed / new toast instants\n            // is accurate\n            instants.retain(Option::is_some);\n\n            match (instants.len(), self.toasts.len()) {\n                (old, new) if old > new => {\n                    instants.truncate(new);\n                }\n                (old, new) if old < new => {\n                    instants.extend(std::iter::repeat_n(Some(Instant::now()), new - old));\n                }\n                _ => {}\n            }\n\n            tree.diff_children(\n                &std::iter::once(&self.content)\n                    .chain(self.toasts.iter())\n                    .collect::<Vec<_>>(),\n            );\n        }\n\n        fn operate(\n            &mut self,\n            tree: &mut Tree,\n            layout: Layout<'_>,\n            renderer: &Renderer,\n            operation: &mut dyn Operation,\n        ) {\n            operation.container(None, layout.bounds());\n            operation.traverse(&mut |operation| {\n                self.content.as_widget_mut().operate(\n                    &mut tree.children[0],\n                    layout,\n                    renderer,\n                    operation,\n                );\n            });\n        }\n\n        fn update(\n            &mut self,\n            tree: &mut Tree,\n            event: &Event,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            renderer: &Renderer,\n            shell: &mut Shell<'_, Message>,\n            viewport: &Rectangle,\n        ) {\n            self.content.as_widget_mut().update(\n                &mut tree.children[0],\n                event,\n                layout,\n                cursor,\n                renderer,\n                shell,\n                viewport,\n            );\n        }\n\n        fn draw(\n            &self,\n            tree: &Tree,\n            renderer: &mut Renderer,\n            theme: &Theme,\n            style: &renderer::Style,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            viewport: &Rectangle,\n        ) {\n            self.content.as_widget().draw(\n                &tree.children[0],\n                renderer,\n                theme,\n                style,\n                layout,\n                cursor,\n                viewport,\n            );\n        }\n\n        fn mouse_interaction(\n            &self,\n            tree: &Tree,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            viewport: &Rectangle,\n            renderer: &Renderer,\n        ) -> mouse::Interaction {\n            self.content.as_widget().mouse_interaction(\n                &tree.children[0],\n                layout,\n                cursor,\n                viewport,\n                renderer,\n            )\n        }\n\n        fn overlay<'b>(\n            &'b mut self,\n            tree: &'b mut Tree,\n            layout: Layout<'b>,\n            renderer: &Renderer,\n            viewport: &Rectangle,\n            translation: Vector,\n        ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n            let instants = tree.state.downcast_mut::<Vec<Option<Instant>>>();\n\n            let (content_state, toasts_state) = tree.children.split_at_mut(1);\n\n            let content = self.content.as_widget_mut().overlay(\n                &mut content_state[0],\n                layout,\n                renderer,\n                viewport,\n                translation,\n            );\n\n            let toasts = (!self.toasts.is_empty()).then(|| {\n                overlay::Element::new(Box::new(Overlay {\n                    position: layout.bounds().position() + translation,\n                    viewport: *viewport,\n                    toasts: &mut self.toasts,\n                    trees: toasts_state,\n                    instants,\n                    on_close: &self.on_close,\n                    timeout_secs: self.timeout_secs,\n                }))\n            });\n            let overlays = content.into_iter().chain(toasts).collect::<Vec<_>>();\n\n            (!overlays.is_empty()).then(|| overlay::Group::with_children(overlays).overlay())\n        }\n    }\n\n    struct Overlay<'a, 'b, Message> {\n        position: Point,\n        viewport: Rectangle,\n        toasts: &'b mut [Element<'a, Message>],\n        trees: &'b mut [Tree],\n        instants: &'b mut [Option<Instant>],\n        on_close: &'b dyn Fn(usize) -> Message,\n        timeout_secs: u64,\n    }\n\n    impl<Message> overlay::Overlay<Message, Theme, Renderer> for Overlay<'_, '_, Message> {\n        fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n            let limits = layout::Limits::new(Size::ZERO, bounds);\n\n            layout::flex::resolve(\n                layout::flex::Axis::Vertical,\n                renderer,\n                &limits,\n                Fill,\n                Fill,\n                10.into(),\n                10.0,\n                Alignment::End,\n                self.toasts,\n                self.trees,\n            )\n            .translate(Vector::new(self.position.x, self.position.y))\n        }\n\n        fn update(\n            &mut self,\n            event: &Event,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            renderer: &Renderer,\n            shell: &mut Shell<'_, Message>,\n        ) {\n            if let Event::Window(window::Event::RedrawRequested(now)) = &event {\n                self.instants\n                    .iter_mut()\n                    .enumerate()\n                    .for_each(|(index, maybe_instant)| {\n                        if let Some(instant) = maybe_instant.as_mut() {\n                            let remaining =\n                                time::seconds(self.timeout_secs).saturating_sub(instant.elapsed());\n\n                            if remaining == Duration::ZERO {\n                                maybe_instant.take();\n                                shell.publish((self.on_close)(index));\n                            } else {\n                                shell.request_redraw_at(*now + remaining);\n                            }\n                        }\n                    });\n            }\n\n            let viewport = layout.bounds();\n\n            for (((child, state), layout), instant) in self\n                .toasts\n                .iter_mut()\n                .zip(self.trees.iter_mut())\n                .zip(layout.children())\n                .zip(self.instants.iter_mut())\n            {\n                let mut local_messages = vec![];\n                let mut local_shell = Shell::new(&mut local_messages);\n\n                child.as_widget_mut().update(\n                    state,\n                    event,\n                    layout,\n                    cursor,\n                    renderer,\n                    &mut local_shell,\n                    &viewport,\n                );\n\n                if !local_shell.is_empty() {\n                    instant.take();\n                }\n\n                shell.merge(local_shell, std::convert::identity);\n            }\n        }\n\n        fn draw(\n            &self,\n            renderer: &mut Renderer,\n            theme: &Theme,\n            style: &renderer::Style,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n        ) {\n            let viewport = layout.bounds();\n\n            for ((child, tree), layout) in self\n                .toasts\n                .iter()\n                .zip(self.trees.iter())\n                .zip(layout.children())\n            {\n                child\n                    .as_widget()\n                    .draw(tree, renderer, theme, style, layout, cursor, &viewport);\n            }\n        }\n\n        fn operate(\n            &mut self,\n            layout: Layout<'_>,\n            renderer: &Renderer,\n            operation: &mut dyn widget::Operation,\n        ) {\n            operation.container(None, layout.bounds());\n            operation.traverse(&mut |operation| {\n                self.toasts\n                    .iter_mut()\n                    .zip(self.trees.iter_mut())\n                    .zip(layout.children())\n                    .for_each(|((child, state), layout)| {\n                        child\n                            .as_widget_mut()\n                            .operate(state, layout, renderer, operation);\n                    });\n            });\n        }\n\n        fn mouse_interaction(\n            &self,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            renderer: &Renderer,\n        ) -> mouse::Interaction {\n            self.toasts\n                .iter()\n                .zip(self.trees.iter())\n                .zip(layout.children())\n                .map(|((child, state), layout)| {\n                    child\n                        .as_widget()\n                        .mouse_interaction(state, layout, cursor, &self.viewport, renderer)\n                        .max(if cursor.is_over(layout.bounds()) {\n                            mouse::Interaction::Idle\n                        } else {\n                            Default::default()\n                        })\n                })\n                .max()\n                .unwrap_or_default()\n        }\n    }\n\n    impl<'a, Message> From<Manager<'a, Message>> for Element<'a, Message>\n    where\n        Message: 'a,\n    {\n        fn from(manager: Manager<'a, Message>) -> Self {\n            Element::new(manager)\n        }\n    }\n}\n"
  },
  {
    "path": "examples/todos/Cargo.toml",
    "content": "[package]\nname = \"todos\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[features]\ntester = [\"iced/tester\"]\n\n[dependencies]\niced.workspace = true\niced.features = [\"tokio\", \"debug\", \"time-travel\"]\n\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = \"1.0\"\nuuid = { version = \"1.0\", features = [\"v4\", \"fast-rng\", \"serde\"] }\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\ntokio.workspace = true\ntokio.features = [\"fs\", \"time\"]\ndirectories = \"6.0\"\ntracing-subscriber = \"0.3\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\niced.workspace = true\niced.features = [\"debug\", \"webgl\", \"fira-sans\"]\n\nuuid = { version = \"1.0\", features = [\"js\"] }\nweb-sys = { workspace = true, features = [\"Window\", \"Storage\"] }\nwasmtimer.workspace = true\n\n[dev-dependencies]\niced_test.workspace = true\n\n[package.metadata.deb]\nassets = [\n    [\"target/release-opt/todos\", \"usr/bin/iced-todos\", \"755\"],\n    [\"iced-todos.desktop\", \"usr/share/applications/\", \"644\"],\n]\n"
  },
  {
    "path": "examples/todos/README.md",
    "content": "## Todos\n\nA todos tracker inspired by [TodoMVC]. It showcases dynamic layout, text input, checkboxes, scrollables, icons, and async actions! It automatically saves your tasks in the background, even if you did not finish typing them.\n\nAll the example code is located in the __[`main`]__ file.\n\n<div align=\"center\">\n  <a href=\"https://iced.rs/examples/todos.mp4\">\n    <img src=\"https://iced.rs/examples/todos.gif\">\n  </a>\n</div>\n\nYou can run the native version with `cargo run`:\n```\ncargo run --package todos\n```\n\nThe web version can be run with [`trunk`]:\n\n```\ncd examples/todos\ntrunk serve\n```\n\n[`main`]: src/main.rs\n[TodoMVC]: http://todomvc.com/\n[`trunk`]: https://trunkrs.dev/\n"
  },
  {
    "path": "examples/todos/iced-todos.desktop",
    "content": "[Desktop Entry]\nName=Todos - Iced\nExec=iced-todos\nType=Application\n"
  },
  {
    "path": "examples/todos/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>Todos - Iced</title>\n    <base data-trunk-public-url />\n</head>\n<body>\n<link data-trunk rel=\"rust\" href=\"Cargo.toml\" data-wasm-opt=\"z\" data-bin=\"todos\" />\n</body>\n</html>\n"
  },
  {
    "path": "examples/todos/snapshots/creates_a_new_task-tiny-skia.sha256",
    "content": "0acb67235c6a11014a2d2b825e0a70069bca0c67bee0cdb38a0144fc72b25220"
  },
  {
    "path": "examples/todos/src/main.rs",
    "content": "use iced::keyboard;\nuse iced::widget::{\n    self, Text, button, center, center_x, checkbox, column, keyed_column, operation, row,\n    scrollable, text, text_input,\n};\nuse iced::window;\nuse iced::{\n    Application, Center, Element, Fill, Function, Preset, Program, Subscription, Task as Command,\n    Theme,\n};\n\nuse serde::{Deserialize, Serialize};\nuse uuid::Uuid;\n\npub fn main() -> iced::Result {\n    #[cfg(not(target_arch = \"wasm32\"))]\n    tracing_subscriber::fmt::init();\n\n    application().run()\n}\n\nfn application() -> Application<impl Program<Message = Message, Theme = Theme>> {\n    iced::application(Todos::new, Todos::update, Todos::view)\n        .subscription(Todos::subscription)\n        .title(Todos::title)\n        .font(Todos::ICON_FONT)\n        .window_size((500.0, 800.0))\n        .presets(presets())\n}\n\n#[derive(Debug)]\nenum Todos {\n    Loading,\n    Loaded(State),\n}\n\n#[derive(Debug, Default)]\nstruct State {\n    input_value: String,\n    filter: Filter,\n    tasks: Vec<Task>,\n    dirty: bool,\n    saving: bool,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    Loaded(Result<SavedState, LoadError>),\n    Saved(Result<(), SaveError>),\n    InputChanged(String),\n    CreateTask,\n    FilterChanged(Filter),\n    TaskMessage(usize, TaskMessage),\n    TabPressed { shift: bool },\n    ToggleFullscreen(window::Mode),\n}\n\nimpl Todos {\n    const ICON_FONT: &'static [u8] = include_bytes!(\"../fonts/icons.ttf\");\n\n    fn new() -> (Self, Command<Message>) {\n        (\n            Self::Loading,\n            Command::perform(SavedState::load(), Message::Loaded),\n        )\n    }\n\n    fn title(&self) -> String {\n        let dirty = match self {\n            Todos::Loading => false,\n            Todos::Loaded(state) => state.dirty,\n        };\n\n        format!(\"Todos{} - Iced\", if dirty { \"*\" } else { \"\" })\n    }\n\n    fn update(&mut self, message: Message) -> Command<Message> {\n        match self {\n            Todos::Loading => {\n                match message {\n                    Message::Loaded(Ok(state)) => {\n                        *self = Todos::Loaded(State {\n                            input_value: state.input_value,\n                            filter: state.filter,\n                            tasks: state.tasks,\n                            ..State::default()\n                        });\n                    }\n                    Message::Loaded(Err(_)) => {\n                        *self = Todos::Loaded(State::default());\n                    }\n                    _ => {}\n                }\n\n                operation::focus(\"new-task\")\n            }\n            Todos::Loaded(state) => {\n                let mut saved = false;\n\n                let command = match message {\n                    Message::InputChanged(value) => {\n                        state.input_value = value;\n\n                        Command::none()\n                    }\n                    Message::CreateTask => {\n                        if !state.input_value.is_empty() {\n                            state.tasks.push(Task::new(state.input_value.clone()));\n                            state.input_value.clear();\n                        }\n\n                        Command::none()\n                    }\n                    Message::FilterChanged(filter) => {\n                        state.filter = filter;\n\n                        Command::none()\n                    }\n                    Message::TaskMessage(i, TaskMessage::Delete) => {\n                        state.tasks.remove(i);\n\n                        Command::none()\n                    }\n                    Message::TaskMessage(i, task_message) => {\n                        if let Some(task) = state.tasks.get_mut(i) {\n                            let should_focus = matches!(task_message, TaskMessage::Edit);\n\n                            task.update(task_message);\n\n                            if should_focus {\n                                let id = Task::text_input_id(i);\n                                Command::batch(vec![\n                                    operation::focus(id.clone()),\n                                    operation::select_all(id),\n                                ])\n                            } else {\n                                Command::none()\n                            }\n                        } else {\n                            Command::none()\n                        }\n                    }\n                    Message::Saved(_result) => {\n                        state.saving = false;\n                        saved = true;\n\n                        Command::none()\n                    }\n                    Message::TabPressed { shift } => {\n                        if shift {\n                            operation::focus_previous()\n                        } else {\n                            operation::focus_next()\n                        }\n                    }\n                    Message::ToggleFullscreen(mode) => {\n                        window::latest().and_then(move |window| window::set_mode(window, mode))\n                    }\n                    Message::Loaded(_) => Command::none(),\n                };\n\n                if !saved {\n                    state.dirty = true;\n                }\n\n                let save = if state.dirty && !state.saving {\n                    state.dirty = false;\n                    state.saving = true;\n\n                    Command::perform(\n                        SavedState {\n                            input_value: state.input_value.clone(),\n                            filter: state.filter,\n                            tasks: state.tasks.clone(),\n                        }\n                        .save(),\n                        Message::Saved,\n                    )\n                } else {\n                    Command::none()\n                };\n\n                Command::batch(vec![command, save])\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        match self {\n            Todos::Loading => loading_message(),\n            Todos::Loaded(State {\n                input_value,\n                filter,\n                tasks,\n                ..\n            }) => {\n                let title = text(\"todos\")\n                    .width(Fill)\n                    .size(100)\n                    .style(subtle)\n                    .align_x(Center);\n\n                let input = text_input(\"What needs to be done?\", input_value)\n                    .id(\"new-task\")\n                    .on_input(Message::InputChanged)\n                    .on_submit(Message::CreateTask)\n                    .padding(15)\n                    .size(30)\n                    .align_x(Center);\n\n                let controls = view_controls(tasks, *filter);\n                let filtered_tasks = tasks.iter().filter(|task| filter.matches(task));\n\n                let tasks: Element<_> = if filtered_tasks.count() > 0 {\n                    keyed_column(\n                        tasks\n                            .iter()\n                            .enumerate()\n                            .filter(|(_, task)| filter.matches(task))\n                            .map(|(i, task)| {\n                                (task.id, task.view(i).map(Message::TaskMessage.with(i)))\n                            }),\n                    )\n                    .spacing(10)\n                    .into()\n                } else {\n                    empty_message(match filter {\n                        Filter::All => \"You have not created a task yet...\",\n                        Filter::Active => \"All your tasks are done! :D\",\n                        Filter::Completed => \"You have not completed a task yet...\",\n                    })\n                };\n\n                let content = column![title, input, controls, tasks]\n                    .spacing(20)\n                    .max_width(800);\n\n                scrollable(center_x(content).padding(40)).into()\n            }\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        use keyboard::key;\n\n        keyboard::listen().filter_map(|event| match event {\n            keyboard::Event::KeyPressed {\n                key: keyboard::Key::Named(key),\n                modifiers,\n                ..\n            } => match (key, modifiers) {\n                (key::Named::Tab, _) => Some(Message::TabPressed {\n                    shift: modifiers.shift(),\n                }),\n                (key::Named::ArrowUp, keyboard::Modifiers::SHIFT) => {\n                    Some(Message::ToggleFullscreen(window::Mode::Fullscreen))\n                }\n                (key::Named::ArrowDown, keyboard::Modifiers::SHIFT) => {\n                    Some(Message::ToggleFullscreen(window::Mode::Windowed))\n                }\n                _ => None,\n            },\n            _ => None,\n        })\n    }\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\nstruct Task {\n    #[serde(default = \"Uuid::new_v4\")]\n    id: Uuid,\n    description: String,\n    completed: bool,\n\n    #[serde(skip)]\n    state: TaskState,\n}\n\n#[derive(Debug, Clone, Default)]\npub enum TaskState {\n    #[default]\n    Idle,\n    Editing,\n}\n\n#[derive(Debug, Clone)]\npub enum TaskMessage {\n    Completed(bool),\n    Edit,\n    DescriptionEdited(String),\n    FinishEdition,\n    Delete,\n}\n\nimpl Task {\n    fn text_input_id(i: usize) -> widget::Id {\n        widget::Id::from(format!(\"task-{i}\"))\n    }\n\n    fn new(description: String) -> Self {\n        Task {\n            id: Uuid::new_v4(),\n            description,\n            completed: false,\n            state: TaskState::Idle,\n        }\n    }\n\n    fn update(&mut self, message: TaskMessage) {\n        match message {\n            TaskMessage::Completed(completed) => {\n                self.completed = completed;\n            }\n            TaskMessage::Edit => {\n                self.state = TaskState::Editing;\n            }\n            TaskMessage::DescriptionEdited(new_description) => {\n                self.description = new_description;\n            }\n            TaskMessage::FinishEdition => {\n                if !self.description.is_empty() {\n                    self.state = TaskState::Idle;\n                }\n            }\n            TaskMessage::Delete => {}\n        }\n    }\n\n    fn view(&self, i: usize) -> Element<'_, TaskMessage> {\n        match &self.state {\n            TaskState::Idle => {\n                let checkbox = checkbox(self.completed)\n                    .label(&self.description)\n                    .on_toggle(TaskMessage::Completed)\n                    .width(Fill)\n                    .size(17)\n                    .shaping(text::Shaping::Advanced);\n\n                row![\n                    checkbox,\n                    button(edit_icon())\n                        .on_press(TaskMessage::Edit)\n                        .padding(10)\n                        .style(button::text),\n                ]\n                .spacing(20)\n                .align_y(Center)\n                .into()\n            }\n            TaskState::Editing => {\n                let text_input = text_input(\"Describe your task...\", &self.description)\n                    .id(Self::text_input_id(i))\n                    .on_input(TaskMessage::DescriptionEdited)\n                    .on_submit(TaskMessage::FinishEdition)\n                    .padding(10);\n\n                row![\n                    text_input,\n                    button(row![delete_icon(), \"Delete\"].spacing(10).align_y(Center))\n                        .on_press(TaskMessage::Delete)\n                        .padding(10)\n                        .style(button::danger)\n                ]\n                .spacing(20)\n                .align_y(Center)\n                .into()\n            }\n        }\n    }\n}\n\nfn view_controls(tasks: &[Task], current_filter: Filter) -> Element<'_, Message> {\n    let tasks_left = tasks.iter().filter(|task| !task.completed).count();\n\n    let filter_button = |label, filter, current_filter| {\n        let label = text(label);\n\n        let button = button(label).style(if filter == current_filter {\n            button::primary\n        } else {\n            button::text\n        });\n\n        button.on_press(Message::FilterChanged(filter)).padding(8)\n    };\n\n    row![\n        text!(\n            \"{tasks_left} {} left\",\n            if tasks_left == 1 { \"task\" } else { \"tasks\" }\n        )\n        .width(Fill),\n        row![\n            filter_button(\"All\", Filter::All, current_filter),\n            filter_button(\"Active\", Filter::Active, current_filter),\n            filter_button(\"Completed\", Filter::Completed, current_filter,),\n        ]\n        .spacing(10)\n    ]\n    .spacing(20)\n    .align_y(Center)\n    .into()\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]\npub enum Filter {\n    #[default]\n    All,\n    Active,\n    Completed,\n}\n\nimpl Filter {\n    fn matches(self, task: &Task) -> bool {\n        match self {\n            Filter::All => true,\n            Filter::Active => !task.completed,\n            Filter::Completed => task.completed,\n        }\n    }\n}\n\nfn loading_message<'a>() -> Element<'a, Message> {\n    center(text(\"Loading...\").width(Fill).align_x(Center).size(50)).into()\n}\n\nfn empty_message(message: &str) -> Element<'_, Message> {\n    center(\n        text(message)\n            .width(Fill)\n            .size(25)\n            .align_x(Center)\n            .style(subtle),\n    )\n    .height(200)\n    .into()\n}\n\n// Fonts\n\nfn icon(unicode: char) -> Text<'static> {\n    text(unicode.to_string())\n        .font(\"Iced-Todos-Icons\")\n        .width(20)\n        .align_x(Center)\n        .shaping(text::Shaping::Basic)\n}\n\nfn edit_icon() -> Text<'static> {\n    icon('\\u{F303}')\n}\n\nfn delete_icon() -> Text<'static> {\n    icon('\\u{F1F8}')\n}\n\nfn subtle(theme: &Theme) -> text::Style {\n    text::Style {\n        color: Some(theme.palette().background.strongest.color),\n    }\n}\n\n// Persistence\n#[derive(Debug, Clone, Serialize, Deserialize)]\nstruct SavedState {\n    input_value: String,\n    filter: Filter,\n    tasks: Vec<Task>,\n}\n\n#[derive(Debug, Clone)]\nenum LoadError {\n    File,\n    Format,\n}\n\n#[derive(Debug, Clone)]\nenum SaveError {\n    Write,\n    Format,\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\nimpl SavedState {\n    fn path() -> std::path::PathBuf {\n        let mut path =\n            if let Some(project_dirs) = directories::ProjectDirs::from(\"rs\", \"Iced\", \"Todos\") {\n                project_dirs.data_dir().into()\n            } else {\n                std::env::current_dir().unwrap_or_default()\n            };\n\n        path.push(\"todos.json\");\n\n        path\n    }\n\n    async fn load() -> Result<SavedState, LoadError> {\n        let contents = tokio::fs::read_to_string(Self::path())\n            .await\n            .map_err(|_| LoadError::File)?;\n\n        serde_json::from_str(&contents).map_err(|_| LoadError::Format)\n    }\n\n    async fn save(self) -> Result<(), SaveError> {\n        use iced::time::milliseconds;\n\n        let json = serde_json::to_string_pretty(&self).map_err(|_| SaveError::Format)?;\n\n        let path = Self::path();\n\n        if let Some(dir) = path.parent() {\n            tokio::fs::create_dir_all(dir)\n                .await\n                .map_err(|_| SaveError::Write)?;\n        }\n\n        {\n            tokio::fs::write(path, json.as_bytes())\n                .await\n                .map_err(|_| SaveError::Write)?;\n        }\n\n        // This is a simple way to save at most twice every second\n        tokio::time::sleep(milliseconds(500)).await;\n\n        Ok(())\n    }\n}\n\n#[cfg(target_arch = \"wasm32\")]\nimpl SavedState {\n    fn storage() -> Option<web_sys::Storage> {\n        let window = web_sys::window()?;\n\n        window.local_storage().ok()?\n    }\n\n    async fn load() -> Result<SavedState, LoadError> {\n        let storage = Self::storage().ok_or(LoadError::File)?;\n\n        let contents = storage\n            .get_item(\"state\")\n            .map_err(|_| LoadError::File)?\n            .ok_or(LoadError::File)?;\n\n        serde_json::from_str(&contents).map_err(|_| LoadError::Format)\n    }\n\n    async fn save(self) -> Result<(), SaveError> {\n        let storage = Self::storage().ok_or(SaveError::Write)?;\n\n        let json = serde_json::to_string_pretty(&self).map_err(|_| SaveError::Format)?;\n\n        storage\n            .set_item(\"state\", &json)\n            .map_err(|_| SaveError::Write)?;\n\n        let _ = wasmtimer::tokio::sleep(std::time::Duration::from_secs(2)).await;\n\n        Ok(())\n    }\n}\n\nfn presets() -> impl IntoIterator<Item = Preset<Todos, Message>> {\n    [\n        Preset::new(\"Empty\", || {\n            (Todos::Loaded(State::default()), Command::none())\n        }),\n        Preset::new(\"Carl Sagan\", || {\n            (\n                Todos::Loaded(State {\n                    input_value: \"Make an apple pie\".to_owned(),\n                    filter: Filter::All,\n                    tasks: vec![Task {\n                        id: Uuid::new_v4(),\n                        description: \"Create the universe\".to_owned(),\n                        completed: false,\n                        state: TaskState::Idle,\n                    }],\n                    dirty: false,\n                    saving: false,\n                }),\n                Command::none(),\n            )\n        }),\n    ]\n    .into_iter()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    use iced::{Settings, Theme};\n    use iced_test::selector::id;\n    use iced_test::{Error, Simulator};\n\n    fn simulator(todos: &Todos) -> Simulator<'_, Message> {\n        Simulator::with_settings(\n            Settings {\n                fonts: vec![Todos::ICON_FONT.into()],\n                ..Settings::default()\n            },\n            todos.view(),\n        )\n    }\n\n    #[test]\n    #[ignore]\n    fn it_creates_a_new_task() -> Result<(), Error> {\n        let (mut todos, _command) = Todos::new();\n        let _command = todos.update(Message::Loaded(Err(LoadError::File)));\n\n        let mut ui = simulator(&todos);\n        let _input = ui.click(id(\"new-task\"))?;\n\n        let _ = ui.typewrite(\"Create the universe\");\n        let _ = ui.tap_key(keyboard::key::Named::Enter);\n\n        for message in ui.into_messages() {\n            let _command = todos.update(message);\n        }\n\n        let mut ui = simulator(&todos);\n        let _ = ui.find(\"Create the universe\")?;\n\n        let snapshot = ui.snapshot(&Theme::Dark)?;\n        assert!(\n            snapshot.matches_hash(\"snapshots/creates_a_new_task\")?,\n            \"snapshots should match!\"\n        );\n\n        Ok(())\n    }\n\n    #[test]\n    #[ignore]\n    fn it_passes_the_ice_tests() -> Result<(), Error> {\n        iced_test::run(\n            application(),\n            format!(\"{}/tests\", env!(\"CARGO_MANIFEST_DIR\")),\n        )\n    }\n}\n"
  },
  {
    "path": "examples/todos/tests/carl_sagan.ice",
    "content": "viewport: 500x800\nmode: Immediate\npreset: Empty\n-----\nclick #new-task\ntype \"Create the universe\"\ntype enter\ntype \"Make an apple pie\"\ntype enter\nexpect \"2 tasks left\"\nclick \"Create the universe\"\nexpect \"1 task left\"\nclick \"Make an apple pie\"\nexpect \"0 tasks left\"\n"
  },
  {
    "path": "examples/tooltip/Cargo.toml",
    "content": "[package]\nname = \"tooltip\"\nversion = \"0.1.0\"\nauthors = [\"Yusuf Bera Ertan <y.bera003.06@protonmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\"]\n"
  },
  {
    "path": "examples/tooltip/README.md",
    "content": "## Tooltip\n\nA tooltip.\n\nIt displays and positions a widget on another based on cursor position.\n\nThe __[`main`]__ file contains all the code of the example.\n\nYou can run it with `cargo run`:\n```\ncargo run --package tooltip\n```\n\n[`main`]: src/main.rs\n"
  },
  {
    "path": "examples/tooltip/src/main.rs",
    "content": "use iced::Element;\nuse iced::alignment;\nuse iced::time::seconds;\nuse iced::widget::tooltip::Position;\nuse iced::widget::{button, center, checkbox, column, container, tooltip};\n\npub fn main() -> iced::Result {\n    iced::run(Tooltip::update, Tooltip::view)\n}\n\n#[derive(Default)]\nstruct Tooltip {\n    position: Position,\n    delay: bool,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    ChangePosition,\n    ToggleDelay(bool),\n}\n\nimpl Tooltip {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::ChangePosition => {\n                let position = match &self.position {\n                    Position::Top => Position::Bottom,\n                    Position::Bottom => Position::Left,\n                    Position::Left => Position::Right,\n                    Position::Right => Position::FollowCursor,\n                    Position::FollowCursor => Position::Top,\n                };\n\n                self.position = position;\n            }\n            Message::ToggleDelay(is_immediate) => {\n                self.delay = is_immediate;\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let tooltip = tooltip(\n            button(\"Press to change position\").on_press(Message::ChangePosition),\n            position_to_text(self.position),\n            self.position,\n        )\n        .gap(10)\n        .delay(seconds(if self.delay { 1 } else { 0 }))\n        .style(container::rounded_box);\n\n        let checkbox = checkbox(self.delay)\n            .label(\"Delay\")\n            .on_toggle(Message::ToggleDelay);\n\n        center(\n            column![tooltip, checkbox]\n                .align_x(alignment::Horizontal::Center)\n                .spacing(10),\n        )\n        .into()\n    }\n}\n\nfn position_to_text<'a>(position: Position) -> &'a str {\n    match position {\n        Position::FollowCursor => \"Follow Cursor\",\n        Position::Top => \"Top\",\n        Position::Bottom => \"Bottom\",\n        Position::Left => \"Left\",\n        Position::Right => \"Right\",\n    }\n}\n"
  },
  {
    "path": "examples/tour/Cargo.toml",
    "content": "[package]\nname = \"tour\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"image\", \"debug\"]\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\ntracing-subscriber = \"0.3\"\nopen = \"5\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\niced.workspace = true\niced.features = [\"image\", \"debug\", \"webgl\", \"fira-sans\"]\n\nconsole_error_panic_hook = \"0.1\"\nconsole_log = \"1.0\"\n"
  },
  {
    "path": "examples/tour/README.md",
    "content": "## Tour\n\nA simple UI tour that can run both on native platforms and the web! It showcases different widgets that can be built using Iced.\n\nThe __[`main`]__ file contains all the code of the example! All the cross-platform GUI is defined in terms of __state__, __messages__, __update logic__ and __view logic__.\n\n<div align=\"center\">\n  <a href=\"https://iced.rs/examples/tour.mp4\">\n    <img src=\"https://iced.rs/examples/tour.gif\">\n  </a>\n</div>\n\n[`main`]: src/main.rs\n[`iced_winit`]: ../../winit\n[`iced_native`]: ../../native\n[`iced_wgpu`]: ../../wgpu\n[`iced_web`]: https://github.com/iced-rs/iced_web\n[`winit`]: https://github.com/rust-windowing/winit\n[`wgpu`]: https://github.com/gfx-rs/wgpu-rs\n\nYou can run the native version with `cargo run`:\n```\ncargo run --package tour\n```\n\nThe web version can be run with [`trunk`]:\n\n```\ncd examples/tour\ntrunk serve\n```\n\n[`trunk`]: https://trunkrs.dev/\n"
  },
  {
    "path": "examples/tour/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" style=\"height: 100%\">\n<head>\n    <meta charset=\"utf-8\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>Tour - Iced</title>\n    <base data-trunk-public-url />\n</head>\n<body style=\"height: 100%; margin: 0\">\n<link data-trunk rel=\"rust\" href=\"Cargo.toml\" data-wasm-opt=\"z\" data-bin=\"tour\" />\n</body>\n</html>\n"
  },
  {
    "path": "examples/tour/src/main.rs",
    "content": "use iced::widget::{Button, Column, Container, Slider};\nuse iced::widget::{\n    button, center_x, center_y, checkbox, column, image, radio, rich_text, row, scrollable, slider,\n    space, span, text, text_input, toggler,\n};\nuse iced::{Center, Color, Element, Fill, Font, Pixels, color};\n\npub fn main() -> iced::Result {\n    #[cfg(target_arch = \"wasm32\")]\n    {\n        console_log::init().expect(\"Initialize logger\");\n        std::panic::set_hook(Box::new(console_error_panic_hook::hook));\n    }\n\n    #[cfg(not(target_arch = \"wasm32\"))]\n    tracing_subscriber::fmt::init();\n\n    iced::application(Tour::default, Tour::update, Tour::view)\n        .title(Tour::title)\n        .centered()\n        .run()\n}\n\npub struct Tour {\n    screen: Screen,\n    slider: u8,\n    layout: Layout,\n    spacing: u32,\n    text_size: u32,\n    text_color: Color,\n    language: Option<Language>,\n    toggler: bool,\n    image_width: u32,\n    image_filter_method: image::FilterMethod,\n    input_value: String,\n    input_is_secure: bool,\n    input_is_showing_icon: bool,\n    debug: bool,\n}\n\n#[derive(Debug, Clone)]\npub enum Message {\n    BackPressed,\n    NextPressed,\n    SliderChanged(u8),\n    LayoutChanged(Layout),\n    SpacingChanged(u32),\n    TextSizeChanged(u32),\n    TextColorChanged(Color),\n    LanguageSelected(Language),\n    ImageWidthChanged(u32),\n    ImageUseNearestToggled(bool),\n    InputChanged(String),\n    ToggleSecureInput(bool),\n    ToggleTextInputIcon(bool),\n    DebugToggled(bool),\n    TogglerChanged(bool),\n    OpenTrunk,\n}\n\nimpl Tour {\n    fn title(&self) -> String {\n        let screen = match self.screen {\n            Screen::Welcome => \"Welcome\",\n            Screen::Radio => \"Radio button\",\n            Screen::Toggler => \"Toggler\",\n            Screen::Slider => \"Slider\",\n            Screen::Text => \"Text\",\n            Screen::Image => \"Image\",\n            Screen::RowsAndColumns => \"Rows and columns\",\n            Screen::Scrollable => \"Scrollable\",\n            Screen::TextInput => \"Text input\",\n            Screen::Debugger => \"Debugger\",\n            Screen::End => \"End\",\n        };\n\n        format!(\"{screen} - Iced\")\n    }\n\n    fn update(&mut self, event: Message) {\n        match event {\n            Message::BackPressed => {\n                if let Some(screen) = self.screen.previous() {\n                    self.screen = screen;\n                }\n            }\n            Message::NextPressed => {\n                if let Some(screen) = self.screen.next() {\n                    self.screen = screen;\n                }\n            }\n            Message::SliderChanged(value) => {\n                self.slider = value;\n            }\n            Message::LayoutChanged(layout) => {\n                self.layout = layout;\n            }\n            Message::SpacingChanged(spacing) => {\n                self.spacing = spacing;\n            }\n            Message::TextSizeChanged(text_size) => {\n                self.text_size = text_size;\n            }\n            Message::TextColorChanged(text_color) => {\n                self.text_color = text_color;\n            }\n            Message::LanguageSelected(language) => {\n                self.language = Some(language);\n            }\n            Message::ImageWidthChanged(image_width) => {\n                self.image_width = image_width;\n            }\n            Message::ImageUseNearestToggled(use_nearest) => {\n                self.image_filter_method = if use_nearest {\n                    image::FilterMethod::Nearest\n                } else {\n                    image::FilterMethod::Linear\n                };\n            }\n            Message::InputChanged(input_value) => {\n                self.input_value = input_value;\n            }\n            Message::ToggleSecureInput(is_secure) => {\n                self.input_is_secure = is_secure;\n            }\n            Message::ToggleTextInputIcon(show_icon) => {\n                self.input_is_showing_icon = show_icon;\n            }\n            Message::DebugToggled(debug) => {\n                self.debug = debug;\n            }\n            Message::TogglerChanged(toggler) => {\n                self.toggler = toggler;\n            }\n            Message::OpenTrunk => {\n                #[cfg(not(target_arch = \"wasm32\"))]\n                let _ = open::that_in_background(\"https://trunkrs.dev\");\n            }\n        }\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let controls = row![\n            self.screen.previous().is_some().then(|| {\n                padded_button(\"Back\")\n                    .on_press(Message::BackPressed)\n                    .style(button::secondary)\n            }),\n            space::horizontal(),\n            self.can_continue()\n                .then(|| { padded_button(\"Next\").on_press(Message::NextPressed) })\n        ];\n\n        let screen = match self.screen {\n            Screen::Welcome => self.welcome(),\n            Screen::Radio => self.radio(),\n            Screen::Toggler => self.toggler(),\n            Screen::Slider => self.slider(),\n            Screen::Text => self.text(),\n            Screen::Image => self.image(),\n            Screen::RowsAndColumns => self.rows_and_columns(),\n            Screen::Scrollable => self.scrollable(),\n            Screen::TextInput => self.text_input(),\n            Screen::Debugger => self.debugger(),\n            Screen::End => self.end(),\n        };\n\n        let content: Element<_> = column![screen, controls].max_width(540).spacing(20).into();\n\n        let scrollable = scrollable(center_x(if self.debug {\n            content.explain(Color::BLACK)\n        } else {\n            content\n        }))\n        .spacing(10)\n        .auto_scroll(true);\n\n        center_y(scrollable).padding(10).into()\n    }\n\n    fn can_continue(&self) -> bool {\n        match self.screen {\n            Screen::Welcome => true,\n            Screen::Radio => self.language == Some(Language::Rust),\n            Screen::Toggler => self.toggler,\n            Screen::Slider => true,\n            Screen::Text => true,\n            Screen::Image => true,\n            Screen::RowsAndColumns => true,\n            Screen::Scrollable => true,\n            Screen::TextInput => !self.input_value.is_empty(),\n            Screen::Debugger => true,\n            Screen::End => false,\n        }\n    }\n\n    fn welcome(&self) -> Column<'_, Message> {\n        Self::container(\"Welcome!\")\n            .push(\n                \"This is a simple tour meant to showcase a bunch of \\\n                widgets that come bundled in Iced.\",\n            )\n            .push(\n                \"Iced is a cross-platform GUI library for Rust focused on \\\n                 simplicity and type-safety. It is heavily inspired by Elm.\",\n            )\n            .push(\n                \"It was originally born as part of Coffee, an opinionated \\\n                 2D game engine for Rust.\",\n            )\n            .push(\n                \"On native platforms, Iced provides by default a renderer \\\n                 built on top of wgpu, a graphics library supporting Vulkan, \\\n                 Metal, DX11, and DX12.\",\n            )\n            .push(\n                rich_text![\n                    \"Additionally, this tour can also run on WebAssembly \",\n                    \"by leveraging \",\n                    span(\"trunk\")\n                        .color(color!(0x7777FF))\n                        .underline(true)\n                        .font(Font::MONOSPACE)\n                        .link(Message::OpenTrunk),\n                    \".\"\n                ]\n                .on_link_click(std::convert::identity),\n            )\n            .push(\n                \"You will need to interact with the UI in order to reach \\\n                 the end!\",\n            )\n    }\n\n    fn slider(&self) -> Column<'_, Message> {\n        Self::container(\"Slider\")\n            .push(\n                \"A slider allows you to smoothly select a value from a range \\\n                 of values.\",\n            )\n            .push(\n                \"The following slider lets you choose an integer from \\\n                 0 to 100:\",\n            )\n            .push(slider(0..=100, self.slider, Message::SliderChanged))\n            .push(text(self.slider.to_string()).width(Fill).align_x(Center))\n    }\n\n    fn rows_and_columns(&self) -> Column<'_, Message> {\n        let row_radio = radio(\n            \"Row\",\n            Layout::Row,\n            Some(self.layout),\n            Message::LayoutChanged,\n        );\n\n        let column_radio = radio(\n            \"Column\",\n            Layout::Column,\n            Some(self.layout),\n            Message::LayoutChanged,\n        );\n\n        let layout_section: Element<_> = match self.layout {\n            Layout::Row => row![row_radio, column_radio].spacing(self.spacing).into(),\n            Layout::Column => column![row_radio, column_radio]\n                .spacing(self.spacing)\n                .into(),\n        };\n\n        let spacing_section = column![\n            slider(0..=80, self.spacing, Message::SpacingChanged),\n            text!(\"{} px\", self.spacing).width(Fill).align_x(Center),\n        ]\n        .spacing(10);\n\n        Self::container(\"Rows and columns\")\n            .spacing(self.spacing)\n            .push(\n                \"Iced uses a layout model based on flexbox to position UI \\\n                 elements.\",\n            )\n            .push(\n                \"Rows and columns can be used to distribute content \\\n                 horizontally or vertically, respectively.\",\n            )\n            .push(layout_section)\n            .push(\"You can also easily change the spacing between elements:\")\n            .push(spacing_section)\n    }\n\n    fn text(&self) -> Column<'_, Message> {\n        let size = self.text_size;\n        let color = self.text_color;\n\n        let size_section = column![\n            \"You can change its size:\",\n            text!(\"This text is {size} pixels\").size(size),\n            slider(3..=70, size, Message::TextSizeChanged),\n        ]\n        .padding(20)\n        .spacing(20);\n\n        let color_sliders = row![\n            color_slider(color.r, move |r| Color { r, ..color }),\n            color_slider(color.g, move |g| Color { g, ..color }),\n            color_slider(color.b, move |b| Color { b, ..color }),\n        ]\n        .spacing(10);\n\n        let color_section = column![\n            \"And its color:\",\n            text!(\"{color:?}\").color(color),\n            color_sliders,\n        ]\n        .padding(20)\n        .spacing(20);\n\n        Self::container(\"Text\")\n            .push(\n                \"Text is probably the most essential widget for your UI. \\\n                 It will try to adapt to the dimensions of its container.\",\n            )\n            .push(size_section)\n            .push(color_section)\n    }\n\n    fn radio(&self) -> Column<'_, Message> {\n        let question = column![\n            text(\"Iced is written in...\").size(24),\n            column(\n                Language::all()\n                    .iter()\n                    .copied()\n                    .map(|language| {\n                        radio(language, language, self.language, Message::LanguageSelected)\n                    })\n                    .map(Element::from)\n            )\n            .spacing(10)\n        ]\n        .padding(20)\n        .spacing(10);\n\n        Self::container(\"Radio button\")\n            .push(\n                \"A radio button is normally used to represent a choice... \\\n                 Surprise test!\",\n            )\n            .push(question)\n            .push(\n                \"Iced works very well with iterators! The list above is \\\n                 basically created by folding a column over the different \\\n                 choices, creating a radio button for each one of them!\",\n            )\n    }\n\n    fn toggler(&self) -> Column<'_, Message> {\n        Self::container(\"Toggler\")\n            .push(\"A toggler is mostly used to enable or disable something.\")\n            .push(\n                Container::new(\n                    toggler(self.toggler)\n                        .label(\"Toggle me to continue...\")\n                        .on_toggle(Message::TogglerChanged),\n                )\n                .padding([0, 40]),\n            )\n    }\n\n    fn image(&self) -> Column<'_, Message> {\n        let width = self.image_width;\n        let filter_method = self.image_filter_method;\n\n        Self::container(\"Image\")\n            .push(\"An image that tries to keep its aspect ratio.\")\n            .push(ferris(width, filter_method))\n            .push(slider(100..=500, width, Message::ImageWidthChanged))\n            .push(text!(\"Width: {width} px\").width(Fill).align_x(Center))\n            .push(\n                checkbox(filter_method == image::FilterMethod::Nearest)\n                    .label(\"Use nearest interpolation\")\n                    .on_toggle(Message::ImageUseNearestToggled),\n            )\n            .align_x(Center)\n    }\n\n    fn scrollable(&self) -> Column<'_, Message> {\n        Self::container(\"Scrollable\")\n            .push(\n                \"Iced supports scrollable content. Try it out! Find the \\\n                 button further below.\",\n            )\n            .push(text(\"Tip: You can use the scrollbar to scroll down faster!\").size(16))\n            .push(space().height(4096))\n            .push(\n                text(\"You are halfway there!\")\n                    .width(Fill)\n                    .size(30)\n                    .align_x(Center),\n            )\n            .push(space().height(4096))\n            .push(ferris(300, image::FilterMethod::Linear))\n            .push(text(\"You made it!\").width(Fill).size(50).align_x(Center))\n    }\n\n    fn text_input(&self) -> Column<'_, Message> {\n        let value = &self.input_value;\n        let is_secure = self.input_is_secure;\n        let is_showing_icon = self.input_is_showing_icon;\n\n        let mut text_input = text_input(\"Type something to continue...\", value)\n            .on_input(Message::InputChanged)\n            .padding(10)\n            .size(30);\n\n        if is_showing_icon {\n            text_input = text_input.icon(text_input::Icon {\n                font: Font::default(),\n                code_point: '🚀',\n                size: Some(Pixels(28.0)),\n                spacing: 10.0,\n                side: text_input::Side::Right,\n            });\n        }\n\n        Self::container(\"Text input\")\n            .push(\"Use a text input to ask for different kinds of information.\")\n            .push(text_input.secure(is_secure))\n            .push(\n                checkbox(is_secure)\n                    .label(\"Enable password mode\")\n                    .on_toggle(Message::ToggleSecureInput),\n            )\n            .push(\n                checkbox(is_showing_icon)\n                    .label(\"Show icon\")\n                    .on_toggle(Message::ToggleTextInputIcon),\n            )\n            .push(\n                \"A text input produces a message every time it changes. It is \\\n                 very easy to keep track of its contents:\",\n            )\n            .push(\n                text(if value.is_empty() {\n                    \"You have not typed anything yet...\"\n                } else {\n                    value\n                })\n                .width(Fill)\n                .align_x(Center),\n            )\n    }\n\n    fn debugger(&self) -> Column<'_, Message> {\n        Self::container(\"Debugger\")\n            .push(\n                \"You can ask Iced to visually explain the layouting of the \\\n                 different elements comprising your UI!\",\n            )\n            .push(\n                \"Give it a shot! Check the following checkbox to be able to \\\n                 see element boundaries.\",\n            )\n            .push(\n                checkbox(self.debug)\n                    .label(\"Explain layout\")\n                    .on_toggle(Message::DebugToggled),\n            )\n            .push(\"Feel free to go back and take a look.\")\n    }\n\n    fn end(&self) -> Column<'_, Message> {\n        Self::container(\"You reached the end!\")\n            .push(\"This tour will be updated as more features are added.\")\n            .push(\"Make sure to keep an eye on it!\")\n    }\n\n    fn container(title: &str) -> Column<'_, Message> {\n        column![text(title).size(50)].spacing(20)\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\nenum Screen {\n    Welcome,\n    Slider,\n    RowsAndColumns,\n    Text,\n    Radio,\n    Toggler,\n    Image,\n    Scrollable,\n    TextInput,\n    Debugger,\n    End,\n}\n\nimpl Screen {\n    const ALL: &'static [Self] = &[\n        Self::Welcome,\n        Self::Slider,\n        Self::RowsAndColumns,\n        Self::Text,\n        Self::Radio,\n        Self::Toggler,\n        Self::Image,\n        Self::Scrollable,\n        Self::TextInput,\n        Self::Debugger,\n        Self::End,\n    ];\n\n    pub fn next(self) -> Option<Screen> {\n        Self::ALL\n            .get(\n                Self::ALL\n                    .iter()\n                    .copied()\n                    .position(|screen| screen == self)\n                    .expect(\"Screen must exist\")\n                    + 1,\n            )\n            .copied()\n    }\n\n    pub fn previous(self) -> Option<Screen> {\n        let position = Self::ALL\n            .iter()\n            .copied()\n            .position(|screen| screen == self)\n            .expect(\"Screen must exist\");\n\n        if position > 0 {\n            Some(Self::ALL[position - 1])\n        } else {\n            None\n        }\n    }\n}\n\nfn ferris<'a>(width: u32, filter_method: image::FilterMethod) -> Container<'a, Message> {\n    center_x(\n        // This should go away once we unify resource loading on native\n        // platforms\n        if cfg!(target_arch = \"wasm32\") {\n            image(\"tour/images/ferris.png\")\n        } else {\n            image(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/images/ferris.png\"))\n        }\n        .filter_method(filter_method)\n        .width(width),\n    )\n}\n\nfn padded_button<Message: Clone>(label: &str) -> Button<'_, Message> {\n    button(text(label)).padding([12, 24])\n}\n\nfn color_slider<'a>(\n    component: f32,\n    update: impl Fn(f32) -> Color + 'a,\n) -> Slider<'a, f64, Message> {\n    slider(0.0..=1.0, f64::from(component), move |c| {\n        Message::TextColorChanged(update(c as f32))\n    })\n    .step(0.01)\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Language {\n    Rust,\n    Elm,\n    Ruby,\n    Haskell,\n    C,\n    Other,\n}\n\nimpl Language {\n    fn all() -> [Language; 6] {\n        [\n            Language::C,\n            Language::Elm,\n            Language::Ruby,\n            Language::Haskell,\n            Language::Rust,\n            Language::Other,\n        ]\n    }\n}\n\nimpl From<Language> for String {\n    fn from(language: Language) -> String {\n        String::from(match language {\n            Language::Rust => \"Rust\",\n            Language::Elm => \"Elm\",\n            Language::Ruby => \"Ruby\",\n            Language::Haskell => \"Haskell\",\n            Language::C => \"C\",\n            Language::Other => \"Other\",\n        })\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Layout {\n    Row,\n    Column,\n}\n\nimpl Default for Tour {\n    fn default() -> Self {\n        Self {\n            screen: Screen::Welcome,\n            slider: 50,\n            layout: Layout::Row,\n            spacing: 20,\n            text_size: 30,\n            text_color: Color::BLACK,\n            language: None,\n            toggler: false,\n            image_width: 300,\n            image_filter_method: image::FilterMethod::Linear,\n            input_value: String::new(),\n            input_is_secure: false,\n            input_is_showing_icon: false,\n            debug: false,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/url_handler/Cargo.toml",
    "content": "[package]\nname = \"url_handler\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\n"
  },
  {
    "path": "examples/url_handler/src/main.rs",
    "content": "use iced::event;\nuse iced::widget::{center, text};\nuse iced::{Element, Subscription};\n\npub fn main() -> iced::Result {\n    iced::application(App::default, App::update, App::view)\n        .subscription(App::subscription)\n        .run()\n}\n\n#[derive(Debug, Default)]\nstruct App {\n    url: Option<String>,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    UrlReceived(String),\n}\n\nimpl App {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::UrlReceived(url) => {\n                self.url = Some(url);\n            }\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        event::listen_url().map(Message::UrlReceived)\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let content = match &self.url {\n            Some(url) => text(url),\n            None => text(\"No URL received yet!\"),\n        };\n\n        center(content.size(48)).into()\n    }\n}\n"
  },
  {
    "path": "examples/vectorial_text/Cargo.toml",
    "content": "[package]\nname = \"vectorial_text\"\nversion = \"0.1.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced = { path = \"../..\", features = [\"canvas\", \"debug\"] }\n"
  },
  {
    "path": "examples/vectorial_text/src/main.rs",
    "content": "use iced::alignment;\nuse iced::mouse;\nuse iced::widget::{canvas, checkbox, column, row, slider, space, text};\nuse iced::{Center, Element, Fill, Point, Rectangle, Renderer, Theme, Vector};\n\npub fn main() -> iced::Result {\n    iced::application(\n        VectorialText::default,\n        VectorialText::update,\n        VectorialText::view,\n    )\n    .theme(Theme::Dark)\n    .run()\n}\n\n#[derive(Default)]\nstruct VectorialText {\n    state: State,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Message {\n    SizeChanged(f32),\n    AngleChanged(f32),\n    ScaleChanged(f32),\n    ToggleJapanese(bool),\n}\n\nimpl VectorialText {\n    fn update(&mut self, message: Message) {\n        match message {\n            Message::SizeChanged(size) => {\n                self.state.size = size;\n            }\n            Message::AngleChanged(angle) => {\n                self.state.angle = angle;\n            }\n            Message::ScaleChanged(scale) => {\n                self.state.scale = scale;\n            }\n            Message::ToggleJapanese(use_japanese) => {\n                self.state.use_japanese = use_japanese;\n            }\n        }\n\n        self.state.cache.clear();\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let slider_with_label = |label, range, value, message: fn(f32) -> _| {\n            column![\n                row![text(label), space::horizontal(), text!(\"{:.2}\", value)],\n                slider(range, value, message).step(0.01)\n            ]\n            .spacing(2)\n        };\n\n        column![\n            canvas(&self.state).width(Fill).height(Fill),\n            column![\n                checkbox(self.state.use_japanese,)\n                    .label(\"Use Japanese\")\n                    .on_toggle(Message::ToggleJapanese),\n                row![\n                    slider_with_label(\n                        \"Size\",\n                        2.0..=80.0,\n                        self.state.size,\n                        Message::SizeChanged,\n                    ),\n                    slider_with_label(\n                        \"Angle\",\n                        0.0..=360.0,\n                        self.state.angle,\n                        Message::AngleChanged,\n                    ),\n                    slider_with_label(\n                        \"Scale\",\n                        1.0..=20.0,\n                        self.state.scale,\n                        Message::ScaleChanged,\n                    ),\n                ]\n                .spacing(20),\n            ]\n            .align_x(Center)\n            .spacing(10)\n        ]\n        .spacing(10)\n        .padding(20)\n        .into()\n    }\n}\n\nstruct State {\n    size: f32,\n    angle: f32,\n    scale: f32,\n    use_japanese: bool,\n    cache: canvas::Cache,\n}\n\nimpl State {\n    pub fn new() -> Self {\n        Self {\n            size: 40.0,\n            angle: 0.0,\n            scale: 1.0,\n            use_japanese: false,\n            cache: canvas::Cache::new(),\n        }\n    }\n}\n\nimpl<Message> canvas::Program<Message> for State {\n    type State = ();\n\n    fn draw(\n        &self,\n        _tree: &Self::State,\n        renderer: &Renderer,\n        theme: &Theme,\n        bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Vec<canvas::Geometry> {\n        let geometry = self.cache.draw(renderer, bounds.size(), |frame| {\n            let palette = theme.seed();\n            let center = bounds.center();\n\n            frame.translate(Vector::new(center.x, center.y));\n            frame.scale(self.scale);\n            frame.rotate(self.angle * std::f32::consts::PI / 180.0);\n\n            frame.fill_text(canvas::Text {\n                position: Point::new(0.0, 0.0),\n                color: palette.text,\n                size: self.size.into(),\n                content: String::from(if self.use_japanese {\n                    \"ベクトルテキスト🎉\"\n                } else {\n                    \"Vectorial Text! 🎉\"\n                }),\n                align_x: text::Alignment::Center,\n                align_y: alignment::Vertical::Center,\n                shaping: text::Shaping::Advanced,\n                ..canvas::Text::default()\n            });\n        });\n\n        vec![geometry]\n    }\n}\n\nimpl Default for State {\n    fn default() -> Self {\n        State::new()\n    }\n}\n"
  },
  {
    "path": "examples/websocket/Cargo.toml",
    "content": "[package]\nname = \"websocket\"\nversion = \"1.0.0\"\nauthors = [\"Héctor Ramón Jiménez <hector0193@gmail.com>\"]\nedition = \"2024\"\npublish = false\n\n[dependencies]\niced.workspace = true\niced.features = [\"debug\", \"tokio\", \"sipper\"]\n\nwarp = \"0.3\"\n\n[dependencies.async-tungstenite]\nversion = \"0.25\"\nfeatures = [\"tokio-rustls-webpki-roots\"]\n\n[dependencies.tokio]\nworkspace = true\nfeatures = [\"time\"]\n"
  },
  {
    "path": "examples/websocket/README.md",
    "content": "## Websocket\n\nA simple example that keeps a WebSocket connection open to an echo server.\n\nThe example consists of 3 modules:\n- [`main`] contains the `Application` logic.\n- [`echo`] implements a WebSocket client for the [`echo::server`] with `async-tungstenite`.\n- [`echo::server`] implements a simple WebSocket echo server with `warp`.\n\nYou can run it with `cargo run`:\n```\ncargo run --package websocket\n```\n\n[`main`]: src/main.rs\n[`echo`]: src/echo.rs\n[`echo::server`]: src/echo/server.rs\n"
  },
  {
    "path": "examples/websocket/src/echo/server.rs",
    "content": "use iced::futures;\n\nuse futures::channel::mpsc;\nuse futures::{SinkExt, StreamExt};\nuse warp::Filter;\nuse warp::ws::WebSocket;\n\n// Basic WebSocket echo server adapted from:\n// https://github.com/seanmonstar/warp/blob/3ff2eaf41eb5ac9321620e5a6434d5b5ec6f313f/examples/websockets_chat.rs\n//\n// Copyright (c) 2018-2020 Sean McArthur\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\npub async fn run() {\n    let routes = warp::path::end()\n        .and(warp::ws())\n        .map(|ws: warp::ws::Ws| ws.on_upgrade(user_connected));\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n\nasync fn user_connected(ws: WebSocket) {\n    let (mut user_ws_tx, mut user_ws_rx) = ws.split();\n    let (mut tx, mut rx) = mpsc::unbounded();\n\n    tokio::task::spawn(async move {\n        while let Some(message) = rx.next().await {\n            user_ws_tx.send(message).await.unwrap_or_else(|e| {\n                eprintln!(\"websocket send error: {e}\");\n            });\n        }\n    });\n\n    while let Some(result) = user_ws_rx.next().await {\n        let Ok(msg) = result else { break };\n\n        let _ = tx.send(msg).await;\n    }\n}\n"
  },
  {
    "path": "examples/websocket/src/echo.rs",
    "content": "pub mod server;\n\nuse iced::futures;\nuse iced::task::{Never, Sipper, sipper};\nuse iced::widget::text;\n\nuse futures::channel::mpsc;\nuse futures::sink::SinkExt;\nuse futures::stream::StreamExt;\n\nuse async_tungstenite::tungstenite;\nuse std::fmt;\n\npub fn connect() -> impl Sipper<Never, Event> {\n    sipper(async |mut output| {\n        loop {\n            const ECHO_SERVER: &str = \"ws://127.0.0.1:3030\";\n\n            let (mut websocket, mut input) =\n                match async_tungstenite::tokio::connect_async(ECHO_SERVER).await {\n                    Ok((websocket, _)) => {\n                        let (sender, receiver) = mpsc::channel(100);\n\n                        output.send(Event::Connected(Connection(sender))).await;\n\n                        (websocket.fuse(), receiver)\n                    }\n                    Err(_) => {\n                        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;\n\n                        continue;\n                    }\n                };\n\n            loop {\n                futures::select! {\n                    received = websocket.select_next_some() => {\n                        match received {\n                            Ok(tungstenite::Message::Text(message)) => {\n                                output.send(Event::MessageReceived(Message::User(message))).await;\n                            }\n                            Err(_) => {\n                                output.send(Event::Disconnected).await;\n                                break;\n                            }\n                            Ok(_) => {},\n                        }\n                    }\n                    message = input.select_next_some() => {\n                        let result = websocket.send(tungstenite::Message::Text(message.to_string())).await;\n\n                        if result.is_err() {\n                            output.send(Event::Disconnected).await;\n                        }\n                    }\n                }\n            }\n        }\n    })\n}\n\n#[derive(Debug, Clone)]\npub enum Event {\n    Connected(Connection),\n    Disconnected,\n    MessageReceived(Message),\n}\n\n#[derive(Debug, Clone)]\npub struct Connection(mpsc::Sender<Message>);\n\nimpl Connection {\n    pub fn send(&mut self, message: Message) {\n        self.0\n            .try_send(message)\n            .expect(\"Send message to echo server\");\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum Message {\n    Connected,\n    Disconnected,\n    User(String),\n}\n\nimpl Message {\n    pub fn new(message: &str) -> Option<Self> {\n        if message.is_empty() {\n            None\n        } else {\n            Some(Self::User(message.to_string()))\n        }\n    }\n\n    pub fn connected() -> Self {\n        Message::Connected\n    }\n\n    pub fn disconnected() -> Self {\n        Message::Disconnected\n    }\n\n    pub fn as_str(&self) -> &str {\n        match self {\n            Message::Connected => \"Connected successfully!\",\n            Message::Disconnected => \"Connection lost... Retrying...\",\n            Message::User(message) => message.as_str(),\n        }\n    }\n}\n\nimpl fmt::Display for Message {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.as_str())\n    }\n}\n\nimpl<'a> text::IntoFragment<'a> for &'a Message {\n    fn into_fragment(self) -> text::Fragment<'a> {\n        text::Fragment::Borrowed(self.as_str())\n    }\n}\n"
  },
  {
    "path": "examples/websocket/src/main.rs",
    "content": "mod echo;\n\nuse iced::widget::{button, center, column, operation, row, scrollable, text, text_input};\nuse iced::{Center, Element, Fill, Subscription, Task, color};\n\npub fn main() -> iced::Result {\n    iced::application(WebSocket::new, WebSocket::update, WebSocket::view)\n        .subscription(WebSocket::subscription)\n        .run()\n}\n\nstruct WebSocket {\n    messages: Vec<echo::Message>,\n    new_message: String,\n    state: State,\n}\n\n#[derive(Debug, Clone)]\nenum Message {\n    NewMessageChanged(String),\n    Send(echo::Message),\n    Echo(echo::Event),\n}\n\nimpl WebSocket {\n    fn new() -> (Self, Task<Message>) {\n        (\n            Self {\n                messages: Vec::new(),\n                new_message: String::new(),\n                state: State::Disconnected,\n            },\n            Task::batch([\n                Task::future(echo::server::run()).discard(),\n                operation::focus_next(),\n            ]),\n        )\n    }\n\n    fn update(&mut self, message: Message) -> Task<Message> {\n        match message {\n            Message::NewMessageChanged(new_message) => {\n                self.new_message = new_message;\n\n                Task::none()\n            }\n            Message::Send(message) => match &mut self.state {\n                State::Connected(connection) => {\n                    self.new_message.clear();\n\n                    connection.send(message);\n\n                    Task::none()\n                }\n                State::Disconnected => Task::none(),\n            },\n            Message::Echo(event) => match event {\n                echo::Event::Connected(connection) => {\n                    self.state = State::Connected(connection);\n\n                    self.messages.push(echo::Message::connected());\n\n                    Task::none()\n                }\n                echo::Event::Disconnected => {\n                    self.state = State::Disconnected;\n\n                    self.messages.push(echo::Message::disconnected());\n\n                    Task::none()\n                }\n                echo::Event::MessageReceived(message) => {\n                    self.messages.push(message);\n\n                    operation::snap_to_end(MESSAGE_LOG)\n                }\n            },\n        }\n    }\n\n    fn subscription(&self) -> Subscription<Message> {\n        Subscription::run(echo::connect).map(Message::Echo)\n    }\n\n    fn view(&self) -> Element<'_, Message> {\n        let message_log: Element<_> = if self.messages.is_empty() {\n            center(text(\"Your messages will appear here...\").color(color!(0x888888))).into()\n        } else {\n            scrollable(column(self.messages.iter().map(text).map(Element::from)).spacing(10))\n                .id(MESSAGE_LOG)\n                .height(Fill)\n                .spacing(10)\n                .into()\n        };\n\n        let new_message_input = {\n            let mut input = text_input(\"Type a message...\", &self.new_message)\n                .on_input(Message::NewMessageChanged)\n                .padding(10);\n\n            let mut button = button(text(\"Send\").height(40).align_y(Center)).padding([0, 20]);\n\n            if matches!(self.state, State::Connected(_))\n                && let Some(message) = echo::Message::new(&self.new_message)\n            {\n                input = input.on_submit(Message::Send(message.clone()));\n                button = button.on_press(Message::Send(message));\n            }\n\n            row![input, button].spacing(10).align_y(Center)\n        };\n\n        column![message_log, new_message_input]\n            .height(Fill)\n            .padding(20)\n            .spacing(10)\n            .into()\n    }\n}\n\nenum State {\n    Disconnected,\n    Connected(echo::Connection),\n}\n\nconst MESSAGE_LOG: &str = \"message_log\";\n"
  },
  {
    "path": "futures/Cargo.toml",
    "content": "[package]\nname = \"iced_futures\"\ndescription = \"Commands, subscriptions, and future executors for iced\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--cfg\", \"docsrs\"]\nall-features = true\n\n[features]\nthread-pool = [\"futures/thread-pool\"]\n\n[dependencies]\niced_core.workspace = true\nfutures.workspace = true\nlog.workspace = true\nrustc-hash.workspace = true\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\nsmol.workspace = true\nsmol.optional = true\n\ntokio.workspace = true\ntokio.optional = true\ntokio.features = [\"rt\", \"rt-multi-thread\", \"time\"]\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen-futures.workspace = true\nwasmtimer.workspace = true\n"
  },
  {
    "path": "futures/src/backend/default.rs",
    "content": "//! A default, cross-platform backend.\n//!\n//! - On native platforms, it will use:\n//!   - `backend::native::tokio` when the `tokio` feature is enabled.\n//!   - `backend::native::smol` when the `smol` feature is enabled.\n//!   - `backend::native::thread_pool` when the `thread-pool` feature is enabled.\n//!   - `backend::null` otherwise.\n//!\n//! - On Wasm, it will use `backend::wasm::wasm_bindgen`.\n#[cfg(not(target_arch = \"wasm32\"))]\nmod platform {\n    #[cfg(feature = \"tokio\")]\n    pub use crate::backend::native::tokio::*;\n\n    #[cfg(all(feature = \"smol\", not(feature = \"tokio\"),))]\n    pub use crate::backend::native::smol::*;\n\n    #[cfg(all(feature = \"thread-pool\", not(any(feature = \"tokio\", feature = \"smol\"))))]\n    pub use crate::backend::native::thread_pool::*;\n\n    #[cfg(not(any(feature = \"tokio\", feature = \"smol\", feature = \"thread-pool\")))]\n    pub use crate::backend::null::*;\n}\n\n#[cfg(target_arch = \"wasm32\")]\nmod platform {\n    pub use crate::backend::wasm::wasm_bindgen::*;\n}\n\npub use platform::*;\n"
  },
  {
    "path": "futures/src/backend/native/smol.rs",
    "content": "//! A `smol` backend.\n\n/// A `smol` executor.\n#[derive(Debug)]\npub struct Executor;\n\nimpl crate::Executor for Executor {\n    fn new() -> Result<Self, futures::io::Error> {\n        Ok(Self)\n    }\n\n    fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {\n        smol::spawn(future).detach();\n    }\n\n    fn block_on<T>(&self, future: impl Future<Output = T>) -> T {\n        smol::block_on(future)\n    }\n}\n\npub mod time {\n    //! Listen and react to time.\n    use crate::MaybeSend;\n    use crate::core::time::{Duration, Instant};\n    use crate::subscription::Subscription;\n\n    use futures::stream;\n\n    /// Returns a [`Subscription`] that produces messages at a set interval.\n    ///\n    /// The first message is produced after a `duration`, and then continues to\n    /// produce more messages every `duration` after that.\n    pub fn every(duration: Duration) -> Subscription<Instant> {\n        Subscription::run_with(duration, |duration| {\n            use futures::stream::StreamExt;\n\n            let start = Instant::now() + *duration;\n\n            smol::Timer::interval_at(start, *duration).boxed()\n        })\n    }\n\n    /// Returns a [`Subscription`] that runs the given async function at a\n    /// set interval; producing the result of the function as output.\n    pub fn repeat<F, T>(f: fn() -> F, interval: Duration) -> Subscription<T>\n    where\n        F: Future<Output = T> + MaybeSend + 'static,\n        T: MaybeSend + 'static,\n    {\n        Subscription::run_with((f, interval), |(f, interval)| {\n            let f = *f;\n            let interval = *interval;\n\n            stream::unfold(0, move |i| async move {\n                if i > 0 {\n                    _ = smol::Timer::after(interval).await;\n                }\n\n                Some((f().await, i + 1))\n            })\n        })\n    }\n}\n"
  },
  {
    "path": "futures/src/backend/native/thread_pool.rs",
    "content": "//! A `ThreadPool` backend.\n\n/// A thread pool executor for futures.\npub type Executor = futures::executor::ThreadPool;\n\nimpl crate::Executor for Executor {\n    fn new() -> Result<Self, futures::io::Error> {\n        futures::executor::ThreadPool::new()\n    }\n\n    fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {\n        self.spawn_ok(future);\n    }\n\n    fn block_on<T>(&self, future: impl Future<Output = T>) -> T {\n        futures::executor::block_on(future)\n    }\n}\n\npub mod time {\n    //! Listen and react to time.\n}\n"
  },
  {
    "path": "futures/src/backend/native/tokio.rs",
    "content": "//! A `tokio` backend.\n\n/// A `tokio` executor.\npub type Executor = tokio::runtime::Runtime;\n\nimpl crate::Executor for Executor {\n    fn new() -> Result<Self, futures::io::Error> {\n        tokio::runtime::Runtime::new()\n    }\n\n    #[allow(clippy::let_underscore_future)]\n    fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {\n        let _ = tokio::runtime::Runtime::spawn(self, future);\n    }\n\n    fn enter<R>(&self, f: impl FnOnce() -> R) -> R {\n        let _guard = tokio::runtime::Runtime::enter(self);\n        f()\n    }\n\n    fn block_on<T>(&self, future: impl Future<Output = T>) -> T {\n        self.block_on(future)\n    }\n}\n\npub mod time {\n    //! Listen and react to time.\n    use crate::MaybeSend;\n    use crate::core::time::{Duration, Instant};\n    use crate::subscription::Subscription;\n\n    use futures::stream;\n\n    /// Returns a [`Subscription`] that produces messages at a set interval.\n    ///\n    /// The first message is produced after a `duration`, and then continues to\n    /// produce more messages every `duration` after that.\n    pub fn every(duration: Duration) -> Subscription<Instant> {\n        Subscription::run_with(duration, |duration| {\n            use futures::stream::StreamExt;\n\n            let start = tokio::time::Instant::now() + *duration;\n\n            let mut interval = tokio::time::interval_at(start, *duration);\n            interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);\n\n            let stream = {\n                futures::stream::unfold(interval, |mut interval| async move {\n                    Some((interval.tick().await, interval))\n                })\n            };\n\n            stream.map(tokio::time::Instant::into_std).boxed()\n        })\n    }\n\n    /// Returns a [`Subscription`] that runs the given async function at a\n    /// set interval; producing the result of the function as output.\n    pub fn repeat<F, T>(f: fn() -> F, interval: Duration) -> Subscription<T>\n    where\n        F: Future<Output = T> + MaybeSend + 'static,\n        T: MaybeSend + 'static,\n    {\n        Subscription::run_with((f, interval), |(f, interval)| {\n            let f = *f;\n            let interval = *interval;\n\n            stream::unfold(0, move |i| async move {\n                if i > 0 {\n                    tokio::time::sleep(interval).await;\n                }\n\n                Some((f().await, i + 1))\n            })\n        })\n    }\n}\n"
  },
  {
    "path": "futures/src/backend/native.rs",
    "content": "//! Backends that are only available in native platforms: Windows, macOS, or Linux.\n#[cfg(feature = \"tokio\")]\npub mod tokio;\n\n#[cfg(feature = \"smol\")]\npub mod smol;\n\n#[cfg(feature = \"thread-pool\")]\npub mod thread_pool;\n"
  },
  {
    "path": "futures/src/backend/null.rs",
    "content": "//! A backend that does nothing!\nuse crate::MaybeSend;\n\n/// An executor that drops all the futures, instead of spawning them.\n#[derive(Debug)]\npub struct Executor;\n\nimpl crate::Executor for Executor {\n    fn new() -> Result<Self, futures::io::Error> {\n        Ok(Self)\n    }\n\n    fn spawn(&self, _future: impl Future<Output = ()> + MaybeSend + 'static) {}\n\n    #[cfg(not(target_arch = \"wasm32\"))]\n    fn block_on<T>(&self, _future: impl Future<Output = T>) -> T {\n        unimplemented!()\n    }\n}\n\npub mod time {\n    //! Listen and react to time.\n}\n"
  },
  {
    "path": "futures/src/backend/wasm/wasm_bindgen.rs",
    "content": "//! A `wasm-bindgen-futures` backend.\n\n/// A `wasm-bindgen-futures` executor.\n#[derive(Debug)]\npub struct Executor;\n\nimpl crate::Executor for Executor {\n    fn new() -> Result<Self, futures::io::Error> {\n        Ok(Self)\n    }\n\n    fn spawn(&self, future: impl futures::Future<Output = ()> + 'static) {\n        wasm_bindgen_futures::spawn_local(future);\n    }\n}\n\npub mod time {\n    //! Listen and react to time.\n    use crate::subscription::Subscription;\n\n    use wasmtimer::std::Instant;\n\n    /// Returns a [`Subscription`] that produces messages at a set interval.\n    ///\n    /// The first message is produced after a `duration`, and then continues to\n    /// produce more messages every `duration` after that.\n    pub fn every(duration: std::time::Duration) -> Subscription<Instant> {\n        Subscription::run_with(duration, |duration| {\n            use futures::stream::StreamExt;\n\n            let mut interval = wasmtimer::tokio::interval(*duration);\n            interval.set_missed_tick_behavior(wasmtimer::tokio::MissedTickBehavior::Skip);\n\n            let stream = {\n                futures::stream::unfold(interval, |mut interval| async move {\n                    Some((interval.tick().await, interval))\n                })\n            };\n\n            stream.boxed()\n        })\n    }\n}\n"
  },
  {
    "path": "futures/src/backend/wasm.rs",
    "content": "//! Backends that are only available on Wasm targets.\npub mod wasm_bindgen;\n"
  },
  {
    "path": "futures/src/backend.rs",
    "content": "//! The underlying implementations of the `iced_futures` contract!\npub mod null;\n\n#[cfg(not(target_arch = \"wasm32\"))]\npub mod native;\n\n#[cfg(target_arch = \"wasm32\")]\npub mod wasm;\n\npub mod default;\n"
  },
  {
    "path": "futures/src/event.rs",
    "content": "//! Listen to runtime events.\nuse crate::MaybeSend;\nuse crate::core::event::{self, Event};\nuse crate::core::window;\nuse crate::subscription::{self, Subscription};\n\n/// Returns a [`Subscription`] to all the ignored runtime events.\n///\n/// This subscription will notify your application of any [`Event`] that was\n/// not captured by any widget.\npub fn listen() -> Subscription<Event> {\n    listen_with(|event, status, _window| match status {\n        event::Status::Ignored => Some(event),\n        event::Status::Captured => None,\n    })\n}\n\n/// Creates a [`Subscription`] that listens and filters all the runtime events\n/// with the provided function, producing messages accordingly.\n///\n/// This subscription will call the provided function for every [`Event`]\n/// handled by the runtime. If the function:\n///\n/// - Returns `None`, the [`Event`] will be discarded.\n/// - Returns `Some` message, the `Message` will be produced.\npub fn listen_with<Message>(\n    f: fn(Event, event::Status, window::Id) -> Option<Message>,\n) -> Subscription<Message>\nwhere\n    Message: 'static + MaybeSend,\n{\n    #[derive(Hash)]\n    struct EventsWith;\n\n    subscription::filter_map((EventsWith, f), move |event| match event {\n        subscription::Event::Interaction {\n            event: Event::Window(window::Event::RedrawRequested(_)),\n            ..\n        }\n        | subscription::Event::SystemThemeChanged(_)\n        | subscription::Event::PlatformSpecific(_) => None,\n        subscription::Event::Interaction {\n            window,\n            event,\n            status,\n        } => f(event, status, window),\n    })\n}\n\n/// Creates a [`Subscription`] that produces a message for every runtime event,\n/// including the redraw request events.\n///\n/// **Warning:** This [`Subscription`], if unfiltered, may produce messages in\n/// an infinite loop.\npub fn listen_raw<Message>(\n    f: fn(Event, event::Status, window::Id) -> Option<Message>,\n) -> Subscription<Message>\nwhere\n    Message: 'static + MaybeSend,\n{\n    #[derive(Hash)]\n    struct RawEvents;\n\n    subscription::filter_map((RawEvents, f), move |event| match event {\n        subscription::Event::Interaction {\n            window,\n            event,\n            status,\n        } => f(event, status, window),\n        subscription::Event::SystemThemeChanged(_) | subscription::Event::PlatformSpecific(_) => {\n            None\n        }\n    })\n}\n\n/// Creates a [`Subscription`] that notifies of custom application URL\n/// received from the system.\n///\n/// _**Note:** Currently, it only triggers on macOS and the executable needs to be properly [bundled]!_\n///\n/// [bundled]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW19\npub fn listen_url() -> Subscription<String> {\n    #[derive(Hash)]\n    struct ListenUrl;\n\n    subscription::filter_map(ListenUrl, move |event| match event {\n        subscription::Event::PlatformSpecific(subscription::PlatformSpecific::MacOS(\n            subscription::MacOS::ReceivedUrl(url),\n        )) => Some(url),\n        _ => None,\n    })\n}\n"
  },
  {
    "path": "futures/src/executor.rs",
    "content": "//! Choose your preferred executor to power a runtime.\nuse crate::MaybeSend;\n\n/// A type that can run futures.\npub trait Executor: Sized {\n    /// Creates a new [`Executor`].\n    fn new() -> Result<Self, futures::io::Error>\n    where\n        Self: Sized;\n\n    /// Spawns a future in the [`Executor`].\n    fn spawn(&self, future: impl Future<Output = ()> + MaybeSend + 'static);\n\n    /// Runs a future to completion in the current thread within the [`Executor`].\n    #[cfg(not(target_arch = \"wasm32\"))]\n    fn block_on<T>(&self, future: impl Future<Output = T>) -> T;\n\n    /// Runs the given closure inside the [`Executor`].\n    ///\n    /// Some executors, like `tokio`, require some global state to be in place\n    /// before creating futures. This method can be leveraged to set up this\n    /// global state, call a function, restore the state, and obtain the result\n    /// of the call.\n    fn enter<R>(&self, f: impl FnOnce() -> R) -> R {\n        f()\n    }\n}\n"
  },
  {
    "path": "futures/src/keyboard.rs",
    "content": "//! Listen to keyboard events.\nuse crate::core;\nuse crate::core::keyboard::Event;\nuse crate::subscription::{self, Subscription};\n\n/// Returns a [`Subscription`] that listens to ignored keyboard events.\npub fn listen() -> Subscription<Event> {\n    #[derive(Hash)]\n    struct Listen;\n\n    subscription::filter_map(Listen, move |event| match event {\n        subscription::Event::Interaction {\n            event: core::Event::Keyboard(event),\n            status: core::event::Status::Ignored,\n            ..\n        } => Some(event),\n        _ => None,\n    })\n}\n"
  },
  {
    "path": "futures/src/lib.rs",
    "content": "//! Asynchronous tasks for GUI programming, inspired by Elm.\n//!\n//! ![The foundations of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/foundations.png?raw=true)\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg\"\n)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\npub use futures;\npub use iced_core as core;\n\nmod maybe;\nmod runtime;\n\npub mod backend;\npub mod event;\npub mod executor;\npub mod keyboard;\npub mod stream;\npub mod subscription;\n\npub use executor::Executor;\npub use maybe::{MaybeSend, MaybeSync};\npub use platform::*;\npub use runtime::Runtime;\npub use subscription::Subscription;\n\n#[cfg(not(target_arch = \"wasm32\"))]\nmod platform {\n    /// A boxed static future.\n    ///\n    /// - On native platforms, it needs a `Send` requirement.\n    /// - On the Web platform, it does not need a `Send` requirement.\n    pub type BoxFuture<T> = futures::future::BoxFuture<'static, T>;\n\n    /// A boxed static stream.\n    ///\n    /// - On native platforms, it needs a `Send` requirement.\n    /// - On the Web platform, it does not need a `Send` requirement.\n    pub type BoxStream<T> = futures::stream::BoxStream<'static, T>;\n\n    /// Boxes a stream.\n    ///\n    /// - On native platforms, it needs a `Send` requirement.\n    /// - On the Web platform, it does not need a `Send` requirement.\n    pub fn boxed_stream<T, S>(stream: S) -> BoxStream<T>\n    where\n        S: futures::Stream<Item = T> + Send + 'static,\n    {\n        futures::stream::StreamExt::boxed(stream)\n    }\n}\n\n#[cfg(target_arch = \"wasm32\")]\nmod platform {\n    /// A boxed static future.\n    ///\n    /// - On native platforms, it needs a `Send` requirement.\n    /// - On the Web platform, it does not need a `Send` requirement.\n    pub type BoxFuture<T> = futures::future::LocalBoxFuture<'static, T>;\n\n    /// A boxed static stream.\n    ///\n    /// - On native platforms, it needs a `Send` requirement.\n    /// - On the Web platform, it does not need a `Send` requirement.\n    pub type BoxStream<T> = futures::stream::LocalBoxStream<'static, T>;\n\n    /// Boxes a stream.\n    ///\n    /// - On native platforms, it needs a `Send` requirement.\n    /// - On the Web platform, it does not need a `Send` requirement.\n    pub fn boxed_stream<T, S>(stream: S) -> BoxStream<T>\n    where\n        S: futures::Stream<Item = T> + 'static,\n    {\n        futures::stream::StreamExt::boxed_local(stream)\n    }\n}\n"
  },
  {
    "path": "futures/src/maybe.rs",
    "content": "#[cfg(not(target_arch = \"wasm32\"))]\nmod platform {\n    /// An extension trait that enforces `Send` only on native platforms.\n    ///\n    /// Useful for writing cross-platform async code!\n    pub trait MaybeSend: Send {}\n\n    impl<T> MaybeSend for T where T: Send {}\n\n    /// An extension trait that enforces `Sync` only on native platforms.\n    ///\n    /// Useful for writing cross-platform async code!\n    pub trait MaybeSync: Sync {}\n\n    impl<T> MaybeSync for T where T: Sync {}\n}\n\n#[cfg(target_arch = \"wasm32\")]\nmod platform {\n    /// An extension trait that enforces `Send` only on native platforms.\n    ///\n    /// Useful for writing cross-platform async code!\n    pub trait MaybeSend {}\n\n    impl<T> MaybeSend for T {}\n\n    /// An extension trait that enforces `Sync` only on native platforms.\n    ///\n    /// Useful for writing cross-platform async code!\n    pub trait MaybeSync {}\n\n    impl<T> MaybeSync for T {}\n}\n\npub use platform::{MaybeSend, MaybeSync};\n"
  },
  {
    "path": "futures/src/runtime.rs",
    "content": "//! Run commands and keep track of subscriptions.\nuse crate::subscription;\nuse crate::{BoxStream, Executor, MaybeSend};\n\nuse futures::{Sink, SinkExt, channel::mpsc};\nuse std::marker::PhantomData;\n\n/// A batteries-included runtime of commands and subscriptions.\n///\n/// If you have an [`Executor`], a [`Runtime`] can be leveraged to run any\n/// `Command` or [`Subscription`] and get notified of the results!\n///\n/// [`Subscription`]: crate::Subscription\n#[derive(Debug)]\npub struct Runtime<Executor, Sender, Message> {\n    executor: Executor,\n    sender: Sender,\n    subscriptions: subscription::Tracker,\n    _message: PhantomData<Message>,\n}\n\nimpl<Executor, Sender, Message> Runtime<Executor, Sender, Message>\nwhere\n    Executor: self::Executor,\n    Sender: Sink<Message, Error = mpsc::SendError> + Unpin + MaybeSend + Clone + 'static,\n    Message: MaybeSend + 'static,\n{\n    /// Creates a new empty [`Runtime`].\n    ///\n    /// You need to provide:\n    /// - an [`Executor`] to spawn futures\n    /// - a `Sender` implementing `Sink` to receive the results\n    pub fn new(executor: Executor, sender: Sender) -> Self {\n        Self {\n            executor,\n            sender,\n            subscriptions: subscription::Tracker::new(),\n            _message: PhantomData,\n        }\n    }\n\n    /// Runs the given closure inside the [`Executor`] of the [`Runtime`].\n    ///\n    /// See [`Executor::enter`] to learn more.\n    pub fn enter<R>(&self, f: impl FnOnce() -> R) -> R {\n        self.executor.enter(f)\n    }\n\n    /// Runs a future to completion in the current thread within the [`Runtime`].\n    #[cfg(not(target_arch = \"wasm32\"))]\n    pub fn block_on<T>(&mut self, future: impl Future<Output = T>) -> T {\n        self.executor.block_on(future)\n    }\n\n    /// Runs a [`Stream`] in the [`Runtime`] until completion.\n    ///\n    /// The resulting `Message`s will be forwarded to the `Sender` of the\n    /// [`Runtime`].\n    ///\n    /// [`Stream`]: BoxStream\n    pub fn run(&mut self, stream: BoxStream<Message>) {\n        use futures::{FutureExt, StreamExt};\n\n        let sender = self.sender.clone();\n        let future = stream.map(Ok).forward(sender).map(|result| match result {\n            Ok(()) => (),\n            Err(error) => {\n                log::warn!(\"Stream could not run until completion: {error}\");\n            }\n        });\n\n        self.executor.spawn(future);\n    }\n\n    /// Sends a message concurrently through the [`Runtime`].\n    pub fn send(&mut self, message: Message) {\n        let mut sender = self.sender.clone();\n\n        self.executor.spawn(async move {\n            let _ = sender.send(message).await;\n        });\n    }\n\n    /// Tracks a [`Subscription`] in the [`Runtime`].\n    ///\n    /// It will spawn new streams or close old ones as necessary! See\n    /// [`Tracker::update`] to learn more about this!\n    ///\n    /// [`Tracker::update`]: subscription::Tracker::update\n    /// [`Subscription`]: crate::Subscription\n    pub fn track(\n        &mut self,\n        recipes: impl IntoIterator<Item = Box<dyn subscription::Recipe<Output = Message>>>,\n    ) {\n        let Runtime {\n            executor,\n            subscriptions,\n            sender,\n            ..\n        } = self;\n\n        let futures = executor.enter(|| subscriptions.update(recipes.into_iter(), sender.clone()));\n\n        for future in futures {\n            executor.spawn(future);\n        }\n    }\n\n    /// Broadcasts an event to all the subscriptions currently alive in the\n    /// [`Runtime`].\n    ///\n    /// See [`Tracker::broadcast`] to learn more.\n    ///\n    /// [`Tracker::broadcast`]: subscription::Tracker::broadcast\n    pub fn broadcast(&mut self, event: subscription::Event) {\n        self.subscriptions.broadcast(event);\n    }\n}\n"
  },
  {
    "path": "futures/src/stream.rs",
    "content": "//! Create asynchronous streams of data.\nuse futures::channel::mpsc;\nuse futures::stream::{self, Stream, StreamExt};\n\n/// Creates a new [`Stream`] that produces the items sent from a [`Future`]\n/// to the [`mpsc::Sender`] provided to the closure.\n///\n/// This is a more ergonomic [`stream::unfold`], which allows you to go\n/// from the \"world of futures\" to the \"world of streams\" by simply looping\n/// and publishing to an async channel from inside a [`Future`].\npub fn channel<T>(size: usize, f: impl AsyncFnOnce(mpsc::Sender<T>)) -> impl Stream<Item = T> {\n    let (sender, receiver) = mpsc::channel(size);\n\n    let runner = stream::once(f(sender)).filter_map(|_| async { None });\n\n    stream::select(receiver, runner)\n}\n\n/// Creates a new [`Stream`] that produces the items sent from a [`Future`]\n/// that can fail to the [`mpsc::Sender`] provided to the closure.\npub fn try_channel<T, E>(\n    size: usize,\n    f: impl AsyncFnOnce(mpsc::Sender<T>) -> Result<(), E>,\n) -> impl Stream<Item = Result<T, E>> {\n    let (sender, receiver) = mpsc::channel(size);\n\n    let runner = stream::once(f(sender)).filter_map(|result| async {\n        match result {\n            Ok(()) => None,\n            Err(error) => Some(Err(error)),\n        }\n    });\n\n    stream::select(receiver.map(Ok), runner)\n}\n"
  },
  {
    "path": "futures/src/subscription/tracker.rs",
    "content": "use crate::subscription::{Event, Hasher, Recipe};\nuse crate::{BoxFuture, MaybeSend};\n\nuse futures::channel::mpsc;\nuse futures::sink::{Sink, SinkExt};\nuse rustc_hash::FxHashMap;\n\nuse std::hash::Hasher as _;\n\n/// A registry of subscription streams.\n///\n/// If you have an application that continuously returns a [`Subscription`],\n/// you can use a [`Tracker`] to keep track of the different recipes and keep\n/// its executions alive.\n///\n/// [`Subscription`]: crate::Subscription\n#[derive(Debug, Default)]\npub struct Tracker {\n    subscriptions: FxHashMap<u64, Execution>,\n}\n\n#[derive(Debug)]\npub struct Execution {\n    _cancel: futures::channel::oneshot::Sender<()>,\n    listener: Option<futures::channel::mpsc::Sender<Event>>,\n}\n\nimpl Tracker {\n    /// Creates a new empty [`Tracker`].\n    pub fn new() -> Self {\n        Self {\n            subscriptions: FxHashMap::default(),\n        }\n    }\n\n    /// Updates the [`Tracker`] with the given [`Subscription`].\n    ///\n    /// A [`Subscription`] can cause new streams to be spawned or old streams\n    /// to be closed.\n    ///\n    /// The [`Tracker`] keeps track of these streams between calls to this\n    /// method:\n    ///\n    /// - If the provided [`Subscription`] contains a new [`Recipe`] that is\n    ///   currently not being run, it will spawn a new stream and keep it alive.\n    /// - On the other hand, if a [`Recipe`] is currently in execution and the\n    ///   provided [`Subscription`] does not contain it anymore, then the\n    ///   [`Tracker`] will close and drop the relevant stream.\n    ///\n    /// It returns a list of futures that need to be spawned to materialize\n    /// the [`Tracker`] changes.\n    ///\n    /// [`Recipe`]: crate::subscription::Recipe\n    /// [`Subscription`]: crate::Subscription\n    pub fn update<Message, Receiver>(\n        &mut self,\n        recipes: impl Iterator<Item = Box<dyn Recipe<Output = Message>>>,\n        receiver: Receiver,\n    ) -> Vec<BoxFuture<()>>\n    where\n        Message: 'static + MaybeSend,\n        Receiver: 'static + Sink<Message, Error = mpsc::SendError> + Unpin + MaybeSend + Clone,\n    {\n        use futures::stream::StreamExt;\n\n        let mut futures: Vec<BoxFuture<()>> = Vec::new();\n        let mut alive = std::collections::HashSet::new();\n\n        for recipe in recipes {\n            let id = {\n                let mut hasher = Hasher::default();\n                recipe.hash(&mut hasher);\n\n                hasher.finish()\n            };\n\n            let _ = alive.insert(id);\n\n            if self.subscriptions.contains_key(&id) {\n                continue;\n            }\n\n            let (cancel, mut canceled) = futures::channel::oneshot::channel();\n\n            // TODO: Use bus if/when it supports async\n            let (event_sender, event_receiver) = futures::channel::mpsc::channel(100);\n\n            let mut receiver = receiver.clone();\n            let mut stream = recipe.stream(event_receiver.boxed());\n\n            let future = async move {\n                loop {\n                    let select = futures::future::select(&mut canceled, stream.next());\n\n                    match select.await {\n                        futures::future::Either::Left(_)\n                        | futures::future::Either::Right((None, _)) => break,\n                        futures::future::Either::Right((Some(message), _)) => {\n                            let _ = receiver.send(message).await;\n                        }\n                    }\n                }\n            };\n\n            let _ = self.subscriptions.insert(\n                id,\n                Execution {\n                    _cancel: cancel,\n                    listener: if event_sender.is_closed() {\n                        None\n                    } else {\n                        Some(event_sender)\n                    },\n                },\n            );\n\n            futures.push(Box::pin(future));\n        }\n\n        self.subscriptions.retain(|id, _| alive.contains(id));\n\n        futures\n    }\n\n    /// Broadcasts an event to the subscriptions currently alive.\n    ///\n    /// A subscription's [`Recipe::stream`] always receives a stream of events\n    /// as input. This stream can be used by some subscription to listen to\n    /// shell events.\n    ///\n    /// This method publishes the given event to all the subscription streams\n    /// currently open.\n    ///\n    /// [`Recipe::stream`]: crate::subscription::Recipe::stream\n    pub fn broadcast(&mut self, event: Event) {\n        self.subscriptions\n            .values_mut()\n            .filter_map(|connection| connection.listener.as_mut())\n            .for_each(|listener| {\n                if let Err(error) = listener.try_send(event.clone()) {\n                    log::warn!(\"Error sending event to subscription: {error:?}\");\n                }\n            });\n    }\n}\n"
  },
  {
    "path": "futures/src/subscription.rs",
    "content": "//! Listen to external events in your application.\nmod tracker;\n\npub use tracker::Tracker;\n\nuse crate::core::event;\nuse crate::core::theme;\nuse crate::core::window;\nuse crate::futures::Stream;\nuse crate::{BoxStream, MaybeSend};\n\nuse std::any::TypeId;\nuse std::hash::Hash;\n\n/// A subscription event.\n#[derive(Debug, Clone, PartialEq)]\npub enum Event {\n    /// A user interacted with a user interface in a window.\n    Interaction {\n        /// The window holding the interface of the interaction.\n        window: window::Id,\n        /// The [`Event`] describing the interaction.\n        ///\n        /// [`Event`]: event::Event\n        event: event::Event,\n\n        /// The [`event::Status`] of the interaction.\n        status: event::Status,\n    },\n\n    /// The system theme has changed.\n    SystemThemeChanged(theme::Mode),\n\n    /// A platform specific event.\n    PlatformSpecific(PlatformSpecific),\n}\n\n/// A platform specific event\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum PlatformSpecific {\n    /// A MacOS specific event\n    MacOS(MacOS),\n}\n\n/// Describes an event specific to MacOS\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum MacOS {\n    /// Triggered when the app receives an URL from the system\n    ///\n    /// _**Note:** For this event to be triggered, the executable needs to be properly [bundled]!_\n    ///\n    /// [bundled]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW19\n    ReceivedUrl(String),\n}\n\n/// A stream of runtime events.\n///\n/// It is the input of a [`Subscription`].\npub type EventStream = BoxStream<Event>;\n\n/// The hasher used for identifying subscriptions.\npub type Hasher = rustc_hash::FxHasher;\n\n/// A request to listen to external events.\n///\n/// Besides performing async actions on demand with `Task`, most\n/// applications also need to listen to external events passively.\n///\n/// A [`Subscription`] is normally provided to some runtime, like a `Task`,\n/// and it will generate events as long as the user keeps requesting it.\n///\n/// For instance, you can use a [`Subscription`] to listen to a `WebSocket`\n/// connection, keyboard presses, mouse events, time ticks, etc.\n///\n/// # The Lifetime of a [`Subscription`]\n/// Much like a [`Future`] or a [`Stream`], a [`Subscription`] does not produce any effects\n/// on its own. For a [`Subscription`] to run, it must be returned to the iced runtime—normally\n/// in the `subscription` function of an `application` or a `daemon`.\n///\n/// When a [`Subscription`] is provided to the runtime for the first time, the runtime will\n/// start running it asynchronously. Running a [`Subscription`] consists in building its underlying\n/// [`Stream`] and executing it in an async runtime.\n///\n/// Therefore, you can think of a [`Subscription`] as a \"stream builder\". It simply represents a way\n/// to build a certain [`Stream`] together with some way to _identify_ it.\n///\n/// Identification is important because when a specific [`Subscription`] stops being returned to the\n/// iced runtime, the runtime will kill its associated [`Stream`]. The runtime uses the identity of a\n/// [`Subscription`] to keep track of it.\n///\n/// This way, iced allows you to declaratively __subscribe__ to particular streams of data temporarily\n/// and whenever necessary.\n///\n/// ```\n/// # mod iced {\n/// #     pub mod time {\n/// #         pub use iced_futures::backend::default::time::every;\n/// #         pub use std::time::{Duration, Instant};\n/// #     }\n/// #\n/// #     pub use iced_futures::Subscription;\n/// # }\n/// use iced::time::{self, Duration, Instant};\n/// use iced::Subscription;\n///\n/// struct State {\n///     timer_enabled: bool,\n/// }\n///\n/// fn subscription(state: &State) -> Subscription<Instant> {\n///     if state.timer_enabled {\n///         time::every(Duration::from_secs(1))\n///     } else {\n///         Subscription::none()\n///     }\n/// }\n/// ```\n///\n/// [`Future`]: std::future::Future\n#[must_use = \"`Subscription` must be returned to the runtime to take effect; normally in your `subscription` function.\"]\npub struct Subscription<T> {\n    recipes: Vec<Box<dyn Recipe<Output = T>>>,\n}\n\nimpl<T> Subscription<T> {\n    /// Returns an empty [`Subscription`] that will not produce any output.\n    pub fn none() -> Self {\n        Self {\n            recipes: Vec::new(),\n        }\n    }\n\n    /// Returns a [`Subscription`] that will call the given function to create and\n    /// asynchronously run the given [`Stream`].\n    ///\n    /// # Creating an asynchronous worker with bidirectional communication\n    /// You can leverage this helper to create a [`Subscription`] that spawns\n    /// an asynchronous worker in the background and establish a channel of\n    /// communication with an `iced` application.\n    ///\n    /// You can achieve this by creating an `mpsc` channel inside the closure\n    /// and returning the `Sender` as a `Message` for the `Application`:\n    ///\n    /// ```\n    /// # mod iced {\n    /// #     pub use iced_futures::Subscription;   \n    /// #     pub use iced_futures::futures;\n    /// #     pub use iced_futures::stream;\n    /// # }\n    /// use iced::futures::channel::mpsc;\n    /// use iced::futures::sink::SinkExt;\n    /// use iced::futures::Stream;\n    /// use iced::stream;\n    /// use iced::Subscription;\n    ///\n    /// pub enum Event {\n    ///     Ready(mpsc::Sender<Input>),\n    ///     WorkFinished,\n    ///     // ...\n    /// }\n    ///\n    /// enum Input {\n    ///     DoSomeWork,\n    ///     // ...\n    /// }\n    ///\n    /// fn some_worker() -> impl Stream<Item = Event> {\n    ///     stream::channel(100, async |mut output| {\n    ///         // Create channel\n    ///         let (sender, mut receiver) = mpsc::channel(100);\n    ///\n    ///         // Send the sender back to the application\n    ///         output.send(Event::Ready(sender)).await;\n    ///\n    ///         loop {\n    ///             use iced_futures::futures::StreamExt;\n    ///\n    ///             // Read next input sent from `Application`\n    ///             let input = receiver.select_next_some().await;\n    ///\n    ///             match input {\n    ///                 Input::DoSomeWork => {\n    ///                     // Do some async work...\n    ///\n    ///                     // Finally, we can optionally produce a message to tell the\n    ///                     // `Application` the work is done\n    ///                     output.send(Event::WorkFinished).await;\n    ///                 }\n    ///             }\n    ///         }\n    ///     })\n    /// }\n    ///\n    /// fn subscription() -> Subscription<Event> {\n    ///     Subscription::run(some_worker)\n    /// }\n    /// ```\n    ///\n    /// Check out the [`websocket`] example, which showcases this pattern to maintain a `WebSocket`\n    /// connection open.\n    ///\n    /// [`websocket`]: https://github.com/iced-rs/iced/tree/master/examples/websocket\n    pub fn run<S>(builder: fn() -> S) -> Self\n    where\n        S: Stream<Item = T> + MaybeSend + 'static,\n        T: 'static,\n    {\n        from_recipe(Runner {\n            data: builder,\n            spawn: |builder, _| builder(),\n        })\n    }\n\n    /// Returns a [`Subscription`] that will create and asynchronously run the\n    /// given [`Stream`].\n    ///\n    /// Both the `data` and the function pointer will be used to uniquely identify\n    /// the [`Subscription`].\n    pub fn run_with<D, S>(data: D, builder: fn(&D) -> S) -> Self\n    where\n        D: Hash + 'static,\n        S: Stream<Item = T> + MaybeSend + 'static,\n        T: 'static,\n    {\n        from_recipe(Runner {\n            data: (data, builder),\n            spawn: |(data, builder), _| builder(data),\n        })\n    }\n\n    /// Batches all the provided subscriptions and returns the resulting\n    /// [`Subscription`].\n    pub fn batch(subscriptions: impl IntoIterator<Item = Subscription<T>>) -> Self {\n        Self {\n            recipes: subscriptions\n                .into_iter()\n                .flat_map(|subscription| subscription.recipes)\n                .collect(),\n        }\n    }\n\n    /// Adds a value to the [`Subscription`] context.\n    ///\n    /// The value will be part of the identity of a [`Subscription`].\n    pub fn with<A>(self, value: A) -> Subscription<(A, T)>\n    where\n        T: 'static,\n        A: std::hash::Hash + Clone + Send + Sync + 'static,\n    {\n        struct With<A, B> {\n            recipe: Box<dyn Recipe<Output = A>>,\n            value: B,\n        }\n\n        impl<A, B> Recipe for With<A, B>\n        where\n            A: 'static,\n            B: 'static + std::hash::Hash + Clone + Send + Sync,\n        {\n            type Output = (B, A);\n\n            fn hash(&self, state: &mut Hasher) {\n                std::any::TypeId::of::<B>().hash(state);\n                self.value.hash(state);\n                self.recipe.hash(state);\n            }\n\n            fn stream(self: Box<Self>, input: EventStream) -> BoxStream<Self::Output> {\n                use futures::StreamExt;\n\n                let value = self.value;\n\n                Box::pin(\n                    self.recipe\n                        .stream(input)\n                        .map(move |element| (value.clone(), element)),\n                )\n            }\n        }\n\n        Subscription {\n            recipes: self\n                .recipes\n                .into_iter()\n                .map(|recipe| {\n                    Box::new(With {\n                        recipe,\n                        value: value.clone(),\n                    }) as Box<dyn Recipe<Output = (A, T)>>\n                })\n                .collect(),\n        }\n    }\n\n    /// Transforms the [`Subscription`] output with the given function.\n    ///\n    /// The closure provided must be a non-capturing closure.\n    pub fn map<F, A>(self, f: F) -> Subscription<A>\n    where\n        T: 'static,\n        F: Fn(T) -> A + MaybeSend + Clone + 'static,\n        A: 'static,\n    {\n        const {\n            check_zero_sized::<F>();\n        }\n\n        struct Map<A, B, F>\n        where\n            F: Fn(A) -> B + 'static,\n        {\n            recipe: Box<dyn Recipe<Output = A>>,\n            mapper: F,\n        }\n\n        impl<A, B, F> Recipe for Map<A, B, F>\n        where\n            A: 'static,\n            B: 'static,\n            F: Fn(A) -> B + 'static + MaybeSend,\n        {\n            type Output = B;\n\n            fn hash(&self, state: &mut Hasher) {\n                TypeId::of::<F>().hash(state);\n                self.recipe.hash(state);\n            }\n\n            fn stream(self: Box<Self>, input: EventStream) -> BoxStream<Self::Output> {\n                use futures::StreamExt;\n\n                Box::pin(self.recipe.stream(input).map(self.mapper))\n            }\n        }\n\n        Subscription {\n            recipes: self\n                .recipes\n                .into_iter()\n                .map(|recipe| {\n                    Box::new(Map {\n                        recipe,\n                        mapper: f.clone(),\n                    }) as Box<dyn Recipe<Output = A>>\n                })\n                .collect(),\n        }\n    }\n\n    /// Transforms the [`Subscription`] output with the given function, yielding only\n    /// values only when the function returns `Some(A)`.\n    ///\n    /// The closure provided must be a non-capturing closure.\n    pub fn filter_map<F, A>(mut self, f: F) -> Subscription<A>\n    where\n        T: MaybeSend + 'static,\n        F: Fn(T) -> Option<A> + MaybeSend + Clone + 'static,\n        A: MaybeSend + 'static,\n    {\n        const {\n            check_zero_sized::<F>();\n        }\n\n        struct FilterMap<A, B, F>\n        where\n            F: Fn(A) -> Option<B> + 'static,\n        {\n            recipe: Box<dyn Recipe<Output = A>>,\n            mapper: F,\n        }\n\n        impl<A, B, F> Recipe for FilterMap<A, B, F>\n        where\n            A: 'static,\n            B: 'static + MaybeSend,\n            F: Fn(A) -> Option<B> + MaybeSend,\n        {\n            type Output = B;\n\n            fn hash(&self, state: &mut Hasher) {\n                TypeId::of::<F>().hash(state);\n                self.recipe.hash(state);\n            }\n\n            fn stream(self: Box<Self>, input: EventStream) -> BoxStream<Self::Output> {\n                use futures::StreamExt;\n                use futures::future;\n\n                let mapper = self.mapper;\n\n                Box::pin(\n                    self.recipe\n                        .stream(input)\n                        .filter_map(move |a| future::ready(mapper(a))),\n                )\n            }\n        }\n\n        Subscription {\n            recipes: self\n                .recipes\n                .drain(..)\n                .map(|recipe| {\n                    Box::new(FilterMap {\n                        recipe,\n                        mapper: f.clone(),\n                    }) as Box<dyn Recipe<Output = A>>\n                })\n                .collect(),\n        }\n    }\n\n    /// Returns the amount of recipe units in this [`Subscription`].\n    pub fn units(&self) -> usize {\n        self.recipes.len()\n    }\n}\n\n/// Creates a [`Subscription`] from a [`Recipe`] describing it.\npub fn from_recipe<T>(recipe: impl Recipe<Output = T> + 'static) -> Subscription<T> {\n    Subscription {\n        recipes: vec![Box::new(recipe)],\n    }\n}\n\n/// Returns the different recipes of the [`Subscription`].\npub fn into_recipes<T>(subscription: Subscription<T>) -> Vec<Box<dyn Recipe<Output = T>>> {\n    subscription.recipes\n}\n\nimpl<T> std::fmt::Debug for Subscription<T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Subscription\").finish()\n    }\n}\n\n/// The description of a [`Subscription`].\n///\n/// A [`Recipe`] is the internal definition of a [`Subscription`]. It is used\n/// by runtimes to run and identify subscriptions. You can use it to create your\n/// own!\npub trait Recipe {\n    /// The events that will be produced by a [`Subscription`] with this\n    /// [`Recipe`].\n    type Output;\n\n    /// Hashes the [`Recipe`].\n    ///\n    /// This is used by runtimes to uniquely identify a [`Subscription`].\n    fn hash(&self, state: &mut Hasher);\n\n    /// Executes the [`Recipe`] and produces the stream of events of its\n    /// [`Subscription`].\n    fn stream(self: Box<Self>, input: EventStream) -> BoxStream<Self::Output>;\n}\n\n/// Creates a [`Subscription`] from a hashable id and a filter function.\npub fn filter_map<I, F, T>(id: I, f: F) -> Subscription<T>\nwhere\n    I: Hash + 'static,\n    F: Fn(Event) -> Option<T> + MaybeSend + 'static,\n    T: 'static + MaybeSend,\n{\n    from_recipe(Runner {\n        data: id,\n        spawn: |_, events| {\n            use futures::future;\n            use futures::stream::StreamExt;\n\n            events.filter_map(move |event| future::ready(f(event)))\n        },\n    })\n}\n\nstruct Runner<I, F, S, T>\nwhere\n    F: FnOnce(&I, EventStream) -> S,\n    S: Stream<Item = T>,\n{\n    data: I,\n    spawn: F,\n}\n\nimpl<I, F, S, T> Recipe for Runner<I, F, S, T>\nwhere\n    I: Hash + 'static,\n    F: FnOnce(&I, EventStream) -> S,\n    S: Stream<Item = T> + MaybeSend + 'static,\n{\n    type Output = T;\n\n    fn hash(&self, state: &mut Hasher) {\n        std::any::TypeId::of::<I>().hash(state);\n        self.data.hash(state);\n    }\n\n    fn stream(self: Box<Self>, input: EventStream) -> BoxStream<Self::Output> {\n        crate::boxed_stream((self.spawn)(&self.data, input))\n    }\n}\n\nconst fn check_zero_sized<T>() {\n    if std::mem::size_of::<T>() != 0 {\n        panic!(\n            \"The Subscription closure provided is not non-capturing. \\\n            Closures given to Subscription::map or filter_map cannot \\\n            capture external variables. If you need to capture state, \\\n            consider using Subscription::with.\"\n        );\n    }\n}\n"
  },
  {
    "path": "graphics/Cargo.toml",
    "content": "[package]\nname = \"iced_graphics\"\ndescription = \"A bunch of backend-agnostic types that can be leveraged to build a renderer for iced\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--cfg\", \"docsrs\"]\nall-features = true\n\n[features]\ngeometry = [\"lyon_path\"]\nimage = [\"dep:image\", \"kamadak-exif\"]\nsvg = []\nweb-colors = []\nfira-sans = []\n\n[dependencies]\niced_core.workspace = true\niced_futures.workspace = true\n\nbitflags.workspace = true\nbytemuck.workspace = true\ncosmic-text.workspace = true\nhalf.workspace = true\nlog.workspace = true\nraw-window-handle.workspace = true\nrustc-hash.workspace = true\nthiserror.workspace = true\nunicode-segmentation.workspace = true\n\nimage.workspace = true\nimage.optional = true\n\nkamadak-exif.workspace = true\nkamadak-exif.optional = true\n\nlyon_path.workspace = true\nlyon_path.optional = true\n"
  },
  {
    "path": "graphics/src/antialiasing.rs",
    "content": "/// An antialiasing strategy.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Antialiasing {\n    /// Multisample AA with 2 samples\n    MSAAx2,\n    /// Multisample AA with 4 samples\n    MSAAx4,\n    /// Multisample AA with 8 samples\n    MSAAx8,\n    /// Multisample AA with 16 samples\n    MSAAx16,\n}\n\nimpl Antialiasing {\n    /// Returns the amount of samples of the [`Antialiasing`].\n    pub fn sample_count(self) -> u32 {\n        match self {\n            Antialiasing::MSAAx2 => 2,\n            Antialiasing::MSAAx4 => 4,\n            Antialiasing::MSAAx8 => 8,\n            Antialiasing::MSAAx16 => 16,\n        }\n    }\n}\n"
  },
  {
    "path": "graphics/src/cache.rs",
    "content": "//! Cache computations and efficiently reuse them.\nuse std::cell::RefCell;\nuse std::fmt;\nuse std::mem;\nuse std::sync::atomic::{self, AtomicU64};\n\n/// A simple cache that stores generated values to avoid recomputation.\n///\n/// Keeps track of the last generated value after clearing.\npub struct Cache<T> {\n    group: Group,\n    state: RefCell<State<T>>,\n}\n\nimpl<T> Cache<T> {\n    /// Creates a new empty [`Cache`].\n    pub fn new() -> Self {\n        Cache {\n            group: Group::singleton(),\n            state: RefCell::new(State::Empty { previous: None }),\n        }\n    }\n\n    /// Creates a new empty [`Cache`] with the given [`Group`].\n    ///\n    /// Caches within the same group may reuse internal rendering storage.\n    ///\n    /// You should generally group caches that are likely to change\n    /// together.\n    pub fn with_group(group: Group) -> Self {\n        assert!(\n            !group.is_singleton(),\n            \"The group {group:?} cannot be shared!\"\n        );\n\n        Cache {\n            group,\n            state: RefCell::new(State::Empty { previous: None }),\n        }\n    }\n\n    /// Returns the [`Group`] of the [`Cache`].\n    pub fn group(&self) -> Group {\n        self.group\n    }\n\n    /// Puts the given value in the [`Cache`].\n    ///\n    /// Notice that, given this is a cache, a mutable reference is not\n    /// necessary to call this method. You can safely update the cache in\n    /// rendering code.\n    pub fn put(&self, value: T) {\n        *self.state.borrow_mut() = State::Filled { current: value };\n    }\n\n    /// Returns a reference cell to the internal [`State`] of the [`Cache`].\n    pub fn state(&self) -> &RefCell<State<T>> {\n        &self.state\n    }\n\n    /// Clears the [`Cache`].\n    pub fn clear(&self) {\n        let mut state = self.state.borrow_mut();\n\n        let previous = mem::replace(&mut *state, State::Empty { previous: None });\n\n        let previous = match previous {\n            State::Empty { previous } => previous,\n            State::Filled { current } => Some(current),\n        };\n\n        *state = State::Empty { previous };\n    }\n}\n\n/// A cache group.\n///\n/// Caches that share the same group generally change together.\n///\n/// A cache group can be used to implement certain performance\n/// optimizations during rendering, like batching or sharing atlases.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct Group {\n    id: u64,\n    is_singleton: bool,\n}\n\nimpl Group {\n    /// Generates a new unique cache [`Group`].\n    pub fn unique() -> Self {\n        static NEXT: AtomicU64 = AtomicU64::new(0);\n\n        Self {\n            id: NEXT.fetch_add(1, atomic::Ordering::Relaxed),\n            is_singleton: false,\n        }\n    }\n\n    /// Returns `true` if the [`Group`] can only ever have a\n    /// single [`Cache`] in it.\n    ///\n    /// This is the default kind of [`Group`] assigned when using\n    /// [`Cache::new`].\n    ///\n    /// Knowing that a [`Group`] will never be shared may be\n    /// useful for rendering backends to perform additional\n    /// optimizations.\n    pub fn is_singleton(self) -> bool {\n        self.is_singleton\n    }\n\n    fn singleton() -> Self {\n        Self {\n            is_singleton: true,\n            ..Self::unique()\n        }\n    }\n}\n\nimpl<T> fmt::Debug for Cache<T>\nwhere\n    T: fmt::Debug,\n{\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        use std::ops::Deref;\n\n        let state = self.state.borrow();\n\n        match state.deref() {\n            State::Empty { previous } => {\n                write!(f, \"Cache::Empty {{ previous: {previous:?} }}\")\n            }\n            State::Filled { current } => {\n                write!(f, \"Cache::Filled {{ current: {current:?} }}\")\n            }\n        }\n    }\n}\n\nimpl<T> Default for Cache<T> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// The state of a [`Cache`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum State<T> {\n    /// The [`Cache`] is empty.\n    Empty {\n        /// The previous value of the [`Cache`].\n        previous: Option<T>,\n    },\n    /// The [`Cache`] is filled.\n    Filled {\n        /// The current value of the [`Cache`]\n        current: T,\n    },\n}\n\n/// A piece of data that can be cached.\npub trait Cached: Sized {\n    /// The type of cache produced.\n    type Cache: Clone;\n\n    /// Loads the [`Cache`] into a proper instance.\n    ///\n    /// [`Cache`]: Self::Cache\n    fn load(cache: &Self::Cache) -> Self;\n\n    /// Caches this value, producing its corresponding [`Cache`].\n    ///\n    /// [`Cache`]: Self::Cache\n    fn cache(self, group: Group, previous: Option<Self::Cache>) -> Self::Cache;\n}\n\n#[cfg(debug_assertions)]\nimpl Cached for () {\n    type Cache = ();\n\n    fn load(_cache: &Self::Cache) -> Self {}\n\n    fn cache(self, _group: Group, _previous: Option<Self::Cache>) -> Self::Cache {}\n}\n"
  },
  {
    "path": "graphics/src/color.rs",
    "content": "//! Manage colors for shaders.\nuse crate::core::Color;\n\nuse bytemuck::{Pod, Zeroable};\n\n/// A color packed as 4 floats representing RGBA channels.\n#[derive(Debug, Clone, Copy, PartialEq, Zeroable, Pod)]\n#[repr(C)]\npub struct Packed([f32; 4]);\n\nimpl Packed {\n    /// Returns the internal components of the [`Packed`] color.\n    pub fn components(self) -> [f32; 4] {\n        self.0\n    }\n}\n\n/// A flag that indicates whether the renderer should perform gamma correction.\npub const GAMMA_CORRECTION: bool = internal::GAMMA_CORRECTION;\n\n/// Packs a [`Color`].\npub fn pack(color: impl Into<Color>) -> Packed {\n    Packed(internal::pack(color.into()))\n}\n\n#[cfg(not(feature = \"web-colors\"))]\nmod internal {\n    use crate::core::Color;\n\n    pub const GAMMA_CORRECTION: bool = true;\n\n    pub fn pack(color: Color) -> [f32; 4] {\n        color.into_linear()\n    }\n}\n\n#[cfg(feature = \"web-colors\")]\nmod internal {\n    use crate::core::Color;\n\n    pub const GAMMA_CORRECTION: bool = false;\n\n    pub fn pack(color: Color) -> [f32; 4] {\n        [color.r, color.g, color.b, color.a]\n    }\n}\n"
  },
  {
    "path": "graphics/src/compositor.rs",
    "content": "//! A compositor is responsible for initializing a renderer and managing window\n//! surfaces.\nuse crate::core;\nuse crate::core::Color;\nuse crate::core::font;\nuse crate::core::renderer;\nuse crate::futures::{MaybeSend, MaybeSync};\nuse crate::{Antialiasing, Error, Shell, Viewport};\n\nuse raw_window_handle::{HasDisplayHandle, HasWindowHandle};\nuse thiserror::Error;\n\nuse std::borrow::Cow;\n\n/// A graphics compositor that can draw to windows.\npub trait Compositor: Sized {\n    /// The iced renderer of the backend.\n    type Renderer;\n\n    /// The surface of the backend.\n    type Surface;\n\n    /// Creates a new [`Compositor`].\n    fn new(\n        settings: Settings,\n        display: impl Display + Clone,\n        compatible_window: impl Window + Clone,\n        shell: Shell,\n    ) -> impl Future<Output = Result<Self, Error>> {\n        Self::with_backend(settings, display, compatible_window, shell, None)\n    }\n\n    /// Creates a new [`Compositor`] with a backend preference.\n    ///\n    /// If the backend does not match the preference, it will return\n    /// [`Error::GraphicsAdapterNotFound`].\n    fn with_backend(\n        settings: Settings,\n        display: impl Display + Clone,\n        compatible_window: impl Window + Clone,\n        shell: Shell,\n        backend: Option<&str>,\n    ) -> impl Future<Output = Result<Self, Error>>;\n\n    /// Creates a [`Self::Renderer`] for the [`Compositor`].\n    fn create_renderer(&self, settings: renderer::Settings) -> Self::Renderer;\n\n    /// Crates a new [`Surface`] for the given window.\n    ///\n    /// [`Surface`]: Self::Surface\n    fn create_surface<W: Window + Clone>(\n        &mut self,\n        window: W,\n        width: u32,\n        height: u32,\n    ) -> Self::Surface;\n\n    /// Configures a new [`Surface`] with the given dimensions.\n    ///\n    /// [`Surface`]: Self::Surface\n    fn configure_surface(&mut self, surface: &mut Self::Surface, width: u32, height: u32);\n\n    /// Returns [`Information`] used by this [`Compositor`].\n    fn information(&self) -> Information;\n\n    /// Loads a font from its bytes.\n    fn load_font(&mut self, font: Cow<'static, [u8]>) -> Result<(), font::Error> {\n        crate::text::font_system()\n            .write()\n            .expect(\"Write to font system\")\n            .load_font(font);\n\n        // TODO: Error handling\n        Ok(())\n    }\n\n    /// Lists all the available font families.\n    fn list_fonts(&mut self) -> Result<Vec<font::Family>, font::Error> {\n        use std::collections::BTreeSet;\n\n        let font_system = crate::text::font_system()\n            .read()\n            .expect(\"Read from font system\");\n\n        let families = BTreeSet::from_iter(font_system.families());\n\n        Ok(families.into_iter().map(font::Family::name).collect())\n    }\n\n    /// Presents the [`Renderer`] primitives to the next frame of the given [`Surface`].\n    ///\n    /// [`Renderer`]: Self::Renderer\n    /// [`Surface`]: Self::Surface\n    fn present(\n        &mut self,\n        renderer: &mut Self::Renderer,\n        surface: &mut Self::Surface,\n        viewport: &Viewport,\n        background_color: Color,\n        on_pre_present: impl FnOnce(),\n    ) -> Result<(), SurfaceError>;\n\n    /// Screenshots the current [`Renderer`] primitives to an offscreen texture, and returns the bytes of\n    /// the texture ordered as `RGBA` in the `sRGB` color space.\n    ///\n    /// [`Renderer`]: Self::Renderer\n    fn screenshot(\n        &mut self,\n        renderer: &mut Self::Renderer,\n        viewport: &Viewport,\n        background_color: Color,\n    ) -> Vec<u8>;\n}\n\n/// The settings of a [`Compositor`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Settings {\n    /// The antialiasing strategy that will be used for triangle primitives.\n    ///\n    /// By default, it is `None`.\n    pub antialiasing: Option<Antialiasing>,\n\n    /// Whether or not to synchronize frames.\n    ///\n    /// By default, it is `true`.\n    pub vsync: bool,\n}\n\nimpl ::core::default::Default for Settings {\n    fn default() -> Settings {\n        Settings {\n            antialiasing: None,\n            vsync: true,\n        }\n    }\n}\n\nimpl From<&core::Settings> for Settings {\n    fn from(settings: &core::Settings) -> Self {\n        Self {\n            antialiasing: settings.antialiasing.then_some(Antialiasing::MSAAx4),\n            vsync: settings.vsync,\n        }\n    }\n}\n\n/// A window that can be used in a [`Compositor`].\n///\n/// This is just a convenient super trait of the `raw-window-handle`\n/// traits.\npub trait Window: HasWindowHandle + HasDisplayHandle + MaybeSend + MaybeSync + 'static {}\n\nimpl<T> Window for T where T: HasWindowHandle + HasDisplayHandle + MaybeSend + MaybeSync + 'static {}\n\n/// An owned display handle that can be used in a [`Compositor`].\n///\n/// This is just a convenient super trait of the `raw-window-handle`\n/// trait.\npub trait Display: HasDisplayHandle + MaybeSend + MaybeSync + 'static {}\n\nimpl<T> Display for T where T: HasDisplayHandle + MaybeSend + MaybeSync + 'static {}\n\n/// Defines the default compositor of a renderer.\npub trait Default {\n    /// The compositor of the renderer.\n    type Compositor: Compositor<Renderer = Self>;\n}\n\n/// Result of an unsuccessful call to [`Compositor::present`].\n#[derive(Clone, PartialEq, Eq, Debug, Error)]\npub enum SurfaceError {\n    /// A timeout was encountered while trying to acquire the next frame.\n    #[error(\"A timeout was encountered while trying to acquire the next frame\")]\n    Timeout,\n    /// The underlying surface has changed, and therefore the surface must be updated.\n    #[error(\"The underlying surface has changed, and therefore the surface must be updated.\")]\n    Outdated,\n    /// The swap chain has been lost and needs to be recreated.\n    #[error(\"The surface has been lost and needs to be recreated\")]\n    Lost,\n    /// There is no more memory left to allocate a new frame.\n    #[error(\"There is no more memory left to allocate a new frame\")]\n    OutOfMemory,\n    /// Acquiring a texture failed with a generic error.\n    #[error(\"Acquiring a texture failed with a generic error\")]\n    Other,\n}\n\n/// Contains information about the graphics (e.g. graphics adapter, graphics backend).\n#[derive(Debug)]\npub struct Information {\n    /// Contains the graphics adapter.\n    pub adapter: String,\n    /// Contains the graphics backend.\n    pub backend: String,\n}\n\n#[cfg(debug_assertions)]\nimpl Compositor for () {\n    type Renderer = ();\n    type Surface = ();\n\n    async fn with_backend(\n        _settings: Settings,\n        _display: impl Display,\n        _compatible_window: impl Window + Clone,\n        _shell: Shell,\n        _preferred_backend: Option<&str>,\n    ) -> Result<Self, Error> {\n        Ok(())\n    }\n\n    fn create_renderer(&self, _settings: renderer::Settings) -> Self::Renderer {}\n\n    fn create_surface<W: Window + Clone>(\n        &mut self,\n        _window: W,\n        _width: u32,\n        _height: u32,\n    ) -> Self::Surface {\n    }\n\n    fn configure_surface(&mut self, _surface: &mut Self::Surface, _width: u32, _height: u32) {}\n\n    fn load_font(&mut self, _font: Cow<'static, [u8]>) -> Result<(), font::Error> {\n        Ok(())\n    }\n\n    fn list_fonts(&mut self) -> Result<Vec<font::Family>, font::Error> {\n        Ok(Vec::new())\n    }\n\n    fn information(&self) -> Information {\n        Information {\n            adapter: String::from(\"Null Renderer\"),\n            backend: String::from(\"Null\"),\n        }\n    }\n\n    fn present(\n        &mut self,\n        _renderer: &mut Self::Renderer,\n        _surface: &mut Self::Surface,\n        _viewport: &Viewport,\n        _background_color: Color,\n        _on_pre_present: impl FnOnce(),\n    ) -> Result<(), SurfaceError> {\n        Ok(())\n    }\n\n    fn screenshot(\n        &mut self,\n        _renderer: &mut Self::Renderer,\n        _viewport: &Viewport,\n        _background_color: Color,\n    ) -> Vec<u8> {\n        vec![]\n    }\n}\n\n#[cfg(debug_assertions)]\nimpl Default for () {\n    type Compositor = ();\n}\n"
  },
  {
    "path": "graphics/src/damage.rs",
    "content": "//! Compute the damage between frames.\nuse crate::core::{Point, Rectangle};\n\n/// Diffs the damage regions given some previous and current primitives.\npub fn diff<T>(\n    previous: &[T],\n    current: &[T],\n    bounds: impl Fn(&T) -> Vec<Rectangle>,\n    diff: impl Fn(&T, &T) -> Vec<Rectangle>,\n) -> Vec<Rectangle> {\n    let damage = previous.iter().zip(current).flat_map(|(a, b)| diff(a, b));\n\n    if previous.len() == current.len() {\n        damage.collect()\n    } else {\n        let (smaller, bigger) = if previous.len() < current.len() {\n            (previous, current)\n        } else {\n            (current, previous)\n        };\n\n        // Extend damage by the added/removed primitives\n        damage\n            .chain(bigger[smaller.len()..].iter().flat_map(bounds))\n            .collect()\n    }\n}\n\n/// Computes the damage regions given some previous and current primitives.\npub fn list<T>(\n    previous: &[T],\n    current: &[T],\n    bounds: impl Fn(&T) -> Vec<Rectangle>,\n    are_equal: impl Fn(&T, &T) -> bool,\n) -> Vec<Rectangle> {\n    diff(previous, current, &bounds, |a, b| {\n        if are_equal(a, b) {\n            vec![]\n        } else {\n            bounds(a).into_iter().chain(bounds(b)).collect()\n        }\n    })\n}\n\n/// Groups the given damage regions that are close together inside the given\n/// bounds.\npub fn group(mut damage: Vec<Rectangle>, bounds: Rectangle) -> Vec<Rectangle> {\n    const AREA_THRESHOLD: f32 = 20_000.0;\n\n    damage.sort_by(|a, b| {\n        a.center()\n            .distance(Point::ORIGIN)\n            .total_cmp(&b.center().distance(Point::ORIGIN))\n    });\n\n    let mut output = Vec::new();\n    let mut scaled = damage\n        .into_iter()\n        .filter_map(|region| region.intersection(&bounds))\n        .filter(|region| region.width >= 1.0 && region.height >= 1.0);\n\n    if let Some(mut current) = scaled.next() {\n        for region in scaled {\n            let union = current.union(&region);\n\n            if union.area() - current.area() - region.area() <= AREA_THRESHOLD {\n                current = union;\n            } else {\n                output.push(current);\n                current = region;\n            }\n        }\n\n        output.push(current);\n    }\n\n    output\n}\n"
  },
  {
    "path": "graphics/src/error.rs",
    "content": "//! See what can go wrong when creating graphical backends.\n\n/// An error that occurred while creating an application's graphical context.\n#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]\npub enum Error {\n    /// The requested backend version is not supported.\n    #[error(\"the requested backend version is not supported\")]\n    VersionNotSupported,\n\n    /// Failed to find any pixel format that matches the criteria.\n    #[error(\"failed to find any pixel format that matches the criteria\")]\n    NoAvailablePixelFormat,\n\n    /// A suitable graphics adapter or device could not be found.\n    #[error(\"a suitable graphics adapter or device could not be found\")]\n    GraphicsAdapterNotFound {\n        /// The name of the backend where the error happened\n        backend: &'static str,\n        /// The reason why this backend could not be used\n        reason: Reason,\n    },\n\n    /// An error occurred in the context's internal backend\n    #[error(\"an error occurred in the context's internal backend\")]\n    BackendError(String),\n\n    /// Multiple errors occurred\n    #[error(\"multiple errors occurred: {0:?}\")]\n    List(Vec<Self>),\n}\n\n/// The reason why a graphics adapter could not be found\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum Reason {\n    /// The backend did not match the preference\n    DidNotMatch {\n        /// The preferred backend\n        preferred_backend: String,\n    },\n    /// The request to create the backend failed\n    RequestFailed(String),\n}\n"
  },
  {
    "path": "graphics/src/geometry/cache.rs",
    "content": "use crate::cache::{self, Cached};\nuse crate::core::{Rectangle, Size};\nuse crate::geometry::{self, Frame};\n\npub use cache::Group;\n\n/// A simple cache that stores generated geometry to avoid recomputation.\n///\n/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer\n/// change or it is explicitly cleared.\npub struct Cache<Renderer>\nwhere\n    Renderer: geometry::Renderer,\n{\n    raw: crate::Cache<Data<<Renderer::Geometry as Cached>::Cache>>,\n}\n\n#[derive(Debug, Clone)]\nstruct Data<T> {\n    bounds: Rectangle,\n    geometry: T,\n}\n\nimpl<Renderer> Cache<Renderer>\nwhere\n    Renderer: geometry::Renderer,\n{\n    /// Creates a new empty [`Cache`].\n    pub fn new() -> Self {\n        Cache {\n            raw: cache::Cache::new(),\n        }\n    }\n\n    /// Creates a new empty [`Cache`] with the given [`Group`].\n    ///\n    /// Caches within the same group may reuse internal rendering storage.\n    ///\n    /// You should generally group caches that are likely to change\n    /// together.\n    pub fn with_group(group: Group) -> Self {\n        Cache {\n            raw: crate::Cache::with_group(group),\n        }\n    }\n\n    /// Clears the [`Cache`], forcing a redraw the next time it is used.\n    pub fn clear(&self) {\n        self.raw.clear();\n    }\n\n    /// Draws geometry using the provided closure and stores it in the\n    /// [`Cache`].\n    ///\n    /// The closure will only be called when\n    /// - the size has changed since the previous draw call.\n    /// - the [`Cache`] is empty or has been explicitly cleared.\n    ///\n    /// Otherwise, the previously stored geometry will be returned. The\n    /// [`Cache`] is not cleared in this case. In other words, it will keep\n    /// returning the stored geometry if needed.\n    pub fn draw(\n        &self,\n        renderer: &Renderer,\n        size: Size,\n        draw_fn: impl FnOnce(&mut Frame<Renderer>),\n    ) -> Renderer::Geometry {\n        self.draw_with_bounds(renderer, Rectangle::with_size(size), draw_fn)\n    }\n\n    /// Draws geometry using the provided closure and stores it in the\n    /// [`Cache`].\n    ///\n    /// Analogous to [`draw`](Self::draw), but takes a clipping [`Rectangle`] instead of\n    /// a [`Size`].\n    pub fn draw_with_bounds(\n        &self,\n        renderer: &Renderer,\n        bounds: Rectangle,\n        draw_fn: impl FnOnce(&mut Frame<Renderer>),\n    ) -> Renderer::Geometry {\n        use std::ops::Deref;\n\n        let state = self.raw.state();\n\n        let previous = match state.borrow().deref() {\n            cache::State::Empty { previous } => previous.as_ref().map(|data| data.geometry.clone()),\n            cache::State::Filled { current } => {\n                if current.bounds == bounds {\n                    return Cached::load(&current.geometry);\n                }\n\n                Some(current.geometry.clone())\n            }\n        };\n\n        let mut frame = Frame::with_bounds(renderer, bounds);\n        draw_fn(&mut frame);\n\n        let geometry = frame.into_geometry().cache(self.raw.group(), previous);\n        let result = Cached::load(&geometry);\n\n        *state.borrow_mut() = cache::State::Filled {\n            current: Data { bounds, geometry },\n        };\n\n        result\n    }\n}\n\nimpl<Renderer> std::fmt::Debug for Cache<Renderer>\nwhere\n    Renderer: geometry::Renderer,\n    <Renderer::Geometry as Cached>::Cache: std::fmt::Debug,\n{\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{:?}\", &self.raw)\n    }\n}\n\nimpl<Renderer> Default for Cache<Renderer>\nwhere\n    Renderer: geometry::Renderer,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n"
  },
  {
    "path": "graphics/src/geometry/fill.rs",
    "content": "//! Fill [`Geometry`] with a certain style.\n//!\n//! [`Geometry`]: super::Renderer::Geometry\npub use crate::geometry::Style;\n\nuse crate::core::Color;\nuse crate::gradient::{self, Gradient};\n\n/// The style used to fill geometry.\n#[derive(Debug, Clone, Copy)]\npub struct Fill {\n    /// The color or gradient of the fill.\n    ///\n    /// By default, it is set to [`Style::Solid`] with [`Color::BLACK`].\n    pub style: Style,\n\n    /// The fill rule defines how to determine what is inside and what is\n    /// outside of a shape.\n    ///\n    /// See the [SVG specification][1] for more details.\n    ///\n    /// By default, it is set to `NonZero`.\n    ///\n    /// [1]: https://www.w3.org/TR/SVG/painting.html#FillRuleProperty\n    pub rule: Rule,\n}\n\nimpl Default for Fill {\n    fn default() -> Self {\n        Self {\n            style: Style::Solid(Color::BLACK),\n            rule: Rule::NonZero,\n        }\n    }\n}\n\nimpl From<Color> for Fill {\n    fn from(color: Color) -> Fill {\n        Fill {\n            style: Style::Solid(color),\n            ..Fill::default()\n        }\n    }\n}\n\nimpl From<Gradient> for Fill {\n    fn from(gradient: Gradient) -> Self {\n        Fill {\n            style: Style::Gradient(gradient),\n            ..Default::default()\n        }\n    }\n}\n\nimpl From<gradient::Linear> for Fill {\n    fn from(gradient: gradient::Linear) -> Self {\n        Fill {\n            style: Style::Gradient(Gradient::Linear(gradient)),\n            ..Default::default()\n        }\n    }\n}\n\n/// The fill rule defines how to determine what is inside and what is outside of\n/// a shape.\n///\n/// See the [SVG specification][1].\n///\n/// [1]: https://www.w3.org/TR/SVG/painting.html#FillRuleProperty\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[allow(missing_docs)]\npub enum Rule {\n    NonZero,\n    EvenOdd,\n}\n"
  },
  {
    "path": "graphics/src/geometry/frame.rs",
    "content": "//! Draw and generate geometry.\nuse crate::core::{Point, Radians, Rectangle, Size, Vector};\nuse crate::geometry::{self, Fill, Image, Path, Stroke, Svg, Text};\n\n/// The region of a surface that can be used to draw geometry.\npub struct Frame<Renderer>\nwhere\n    Renderer: geometry::Renderer,\n{\n    raw: Renderer::Frame,\n}\n\nimpl<Renderer> Frame<Renderer>\nwhere\n    Renderer: geometry::Renderer,\n{\n    /// Creates a new [`Frame`] with the given dimensions.\n    ///\n    /// Any geometry drawn outside of the dimensions will be clipped.\n    /// If you need further control, use [`with_bounds`](Self::with_bounds).\n    pub fn new(renderer: &Renderer, size: Size) -> Self {\n        Self::with_bounds(renderer, Rectangle::with_size(size))\n    }\n\n    /// Creates a new [`Frame`] with the given clip bounds.\n    pub fn with_bounds(renderer: &Renderer, bounds: Rectangle) -> Self {\n        Self {\n            raw: renderer.new_frame(bounds),\n        }\n    }\n\n    /// Returns the width of the [`Frame`].\n    pub fn width(&self) -> f32 {\n        self.raw.width()\n    }\n\n    /// Returns the height of the [`Frame`].\n    pub fn height(&self) -> f32 {\n        self.raw.height()\n    }\n\n    /// Returns the dimensions of the [`Frame`].\n    pub fn size(&self) -> Size {\n        self.raw.size()\n    }\n\n    /// Returns the coordinate of the center of the [`Frame`].\n    pub fn center(&self) -> Point {\n        self.raw.center()\n    }\n\n    /// Draws the given [`Path`] on the [`Frame`] by filling it with the\n    /// provided style.\n    pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {\n        self.raw.fill(path, fill);\n    }\n\n    /// Draws an axis-aligned rectangle given its top-left corner coordinate and\n    /// its `Size` on the [`Frame`] by filling it with the provided style.\n    pub fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>) {\n        self.raw.fill_rectangle(top_left, size, fill);\n    }\n\n    /// Draws the stroke of the given [`Path`] on the [`Frame`] with the\n    /// provided style.\n    pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {\n        self.raw.stroke(path, stroke);\n    }\n\n    /// Draws the stroke of an axis-aligned rectangle with the provided style\n    /// given its top-left corner coordinate and its `Size` on the [`Frame`] .\n    pub fn stroke_rectangle<'a>(\n        &mut self,\n        top_left: Point,\n        size: Size,\n        stroke: impl Into<Stroke<'a>>,\n    ) {\n        self.raw.stroke_rectangle(top_left, size, stroke);\n    }\n\n    /// Draws the characters of the given [`Text`] on the [`Frame`], filling\n    /// them with the given color.\n    ///\n    /// __Warning:__ All text will be rendered on top of all the layers of\n    /// a `Canvas`. Therefore, it is currently only meant to be used for\n    /// overlays, which is the most common use case.\n    pub fn fill_text(&mut self, text: impl Into<Text>) {\n        self.raw.fill_text(text);\n    }\n\n    /// Draws the given [`Image`] on the [`Frame`] inside the given bounds.\n    #[cfg(feature = \"image\")]\n    pub fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {\n        self.raw.draw_image(bounds, image);\n    }\n\n    /// Draws the given [`Svg`] on the [`Frame`] inside the given bounds.\n    #[cfg(feature = \"svg\")]\n    pub fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {\n        self.raw.draw_svg(bounds, svg);\n    }\n\n    /// Stores the current transform of the [`Frame`] and executes the given\n    /// drawing operations, restoring the transform afterwards.\n    ///\n    /// This method is useful to compose transforms and perform drawing\n    /// operations in different coordinate systems.\n    #[inline]\n    pub fn with_save<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {\n        self.push_transform();\n\n        let result = f(self);\n\n        self.pop_transform();\n\n        result\n    }\n\n    /// Pushes the current transform in the transform stack.\n    pub fn push_transform(&mut self) {\n        self.raw.push_transform();\n    }\n\n    /// Pops a transform from the transform stack and sets it as the current transform.\n    pub fn pop_transform(&mut self) {\n        self.raw.pop_transform();\n    }\n\n    /// Executes the given drawing operations within a [`Rectangle`] region,\n    /// clipping any geometry that overflows its bounds. Any transformations\n    /// performed are local to the provided closure.\n    ///\n    /// This method is useful to perform drawing operations that need to be\n    /// clipped.\n    #[inline]\n    pub fn with_clip<R>(&mut self, region: Rectangle, f: impl FnOnce(&mut Self) -> R) -> R {\n        let mut frame = self.draft(region);\n\n        let result = f(&mut frame);\n        self.paste(frame);\n\n        result\n    }\n\n    /// Creates a new [`Frame`] with the given [`Size`].\n    ///\n    /// Draw its contents back to this [`Frame`] with [`paste`].\n    ///\n    /// [`paste`]: Self::paste\n    fn draft(&mut self, clip_bounds: Rectangle) -> Self {\n        Self {\n            raw: self.raw.draft(clip_bounds),\n        }\n    }\n\n    /// Draws the contents of the given [`Frame`] with origin at the given [`Point`].\n    fn paste(&mut self, frame: Self) {\n        self.raw.paste(frame.raw);\n    }\n\n    /// Applies a translation to the current transform of the [`Frame`].\n    pub fn translate(&mut self, translation: Vector) {\n        self.raw.translate(translation);\n    }\n\n    /// Applies a rotation in radians to the current transform of the [`Frame`].\n    pub fn rotate(&mut self, angle: impl Into<Radians>) {\n        self.raw.rotate(angle);\n    }\n\n    /// Applies a uniform scaling to the current transform of the [`Frame`].\n    pub fn scale(&mut self, scale: impl Into<f32>) {\n        self.raw.scale(scale);\n    }\n\n    /// Applies a non-uniform scaling to the current transform of the [`Frame`].\n    pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {\n        self.raw.scale_nonuniform(scale);\n    }\n\n    /// Turns the [`Frame`] into its underlying geometry.\n    pub fn into_geometry(self) -> Renderer::Geometry {\n        self.raw.into_geometry()\n    }\n}\n\n/// The internal implementation of a [`Frame`].\n///\n/// Analogous to [`Frame`]. See [`Frame`] for the documentation\n/// of each method.\n#[allow(missing_docs)]\npub trait Backend: Sized {\n    type Geometry;\n\n    fn width(&self) -> f32;\n    fn height(&self) -> f32;\n    fn size(&self) -> Size;\n    fn center(&self) -> Point;\n\n    fn push_transform(&mut self);\n    fn pop_transform(&mut self);\n\n    fn translate(&mut self, translation: Vector);\n    fn rotate(&mut self, angle: impl Into<Radians>);\n    fn scale(&mut self, scale: impl Into<f32>);\n    fn scale_nonuniform(&mut self, scale: impl Into<Vector>);\n\n    fn draft(&mut self, clip_bounds: Rectangle) -> Self;\n    fn paste(&mut self, frame: Self);\n\n    fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>);\n    fn stroke_rectangle<'a>(&mut self, top_left: Point, size: Size, stroke: impl Into<Stroke<'a>>);\n    fn stroke_text<'a>(&mut self, text: impl Into<Text>, stroke: impl Into<Stroke<'a>>);\n\n    fn fill(&mut self, path: &Path, fill: impl Into<Fill>);\n    fn fill_text(&mut self, text: impl Into<Text>);\n    fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>);\n\n    fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>);\n    fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>);\n\n    fn into_geometry(self) -> Self::Geometry;\n}\n\n#[cfg(debug_assertions)]\nimpl Backend for () {\n    type Geometry = ();\n\n    fn width(&self) -> f32 {\n        0.0\n    }\n\n    fn height(&self) -> f32 {\n        0.0\n    }\n\n    fn size(&self) -> Size {\n        Size::ZERO\n    }\n\n    fn center(&self) -> Point {\n        Point::ORIGIN\n    }\n\n    fn push_transform(&mut self) {}\n    fn pop_transform(&mut self) {}\n\n    fn translate(&mut self, _translation: Vector) {}\n    fn rotate(&mut self, _angle: impl Into<Radians>) {}\n    fn scale(&mut self, _scale: impl Into<f32>) {}\n    fn scale_nonuniform(&mut self, _scale: impl Into<Vector>) {}\n\n    fn draft(&mut self, _clip_bounds: Rectangle) -> Self {}\n    fn paste(&mut self, _frame: Self) {}\n\n    fn stroke<'a>(&mut self, _path: &Path, _stroke: impl Into<Stroke<'a>>) {}\n    fn stroke_rectangle<'a>(\n        &mut self,\n        _top_left: Point,\n        _size: Size,\n        _stroke: impl Into<Stroke<'a>>,\n    ) {\n    }\n    fn stroke_text<'a>(&mut self, _text: impl Into<Text>, _stroke: impl Into<Stroke<'a>>) {}\n\n    fn fill(&mut self, _path: &Path, _fill: impl Into<Fill>) {}\n    fn fill_text(&mut self, _text: impl Into<Text>) {}\n    fn fill_rectangle(&mut self, _top_left: Point, _size: Size, _fill: impl Into<Fill>) {}\n\n    fn draw_image(&mut self, _bounds: Rectangle, _image: impl Into<Image>) {}\n    fn draw_svg(&mut self, _bounds: Rectangle, _svg: impl Into<Svg>) {}\n\n    fn into_geometry(self) -> Self::Geometry {}\n}\n"
  },
  {
    "path": "graphics/src/geometry/path/arc.rs",
    "content": "//! Build and draw curves.\nuse iced_core::{Point, Radians, Vector};\n\n/// A segment of a differentiable curve.\n#[derive(Debug, Clone, Copy)]\npub struct Arc {\n    /// The center of the arc.\n    pub center: Point,\n    /// The radius of the arc.\n    pub radius: f32,\n    /// The start of the segment's angle, clockwise rotation from positive x-axis.\n    pub start_angle: Radians,\n    /// The end of the segment's angle, clockwise rotation from positive x-axis.\n    pub end_angle: Radians,\n}\n\n/// An elliptical [`Arc`].\n#[derive(Debug, Clone, Copy)]\npub struct Elliptical {\n    /// The center of the arc.\n    pub center: Point,\n    /// The radii of the arc's ellipse. The horizontal and vertical half-dimensions of the ellipse will match the x and y values of the radii vector.\n    pub radii: Vector,\n    /// The clockwise rotation of the arc's ellipse.\n    pub rotation: Radians,\n    /// The start of the segment's angle, clockwise rotation from positive x-axis.\n    pub start_angle: Radians,\n    /// The end of the segment's angle, clockwise rotation from positive x-axis.\n    pub end_angle: Radians,\n}\n\nimpl From<Arc> for Elliptical {\n    fn from(arc: Arc) -> Elliptical {\n        Elliptical {\n            center: arc.center,\n            radii: Vector::new(arc.radius, arc.radius),\n            rotation: Radians(0.0),\n            start_angle: arc.start_angle,\n            end_angle: arc.end_angle,\n        }\n    }\n}\n"
  },
  {
    "path": "graphics/src/geometry/path/builder.rs",
    "content": "use crate::geometry::path::{Arc, Path, arc};\n\nuse crate::core::border;\nuse crate::core::{Point, Radians, Size};\n\nuse lyon_path::builder::{self, SvgPathBuilder};\nuse lyon_path::geom;\nuse lyon_path::math;\n\n/// A [`Path`] builder.\n///\n/// Once a [`Path`] is built, it can no longer be mutated.\npub struct Builder {\n    raw: builder::WithSvg<lyon_path::path::BuilderImpl>,\n}\n\nimpl Builder {\n    /// Creates a new [`Builder`].\n    pub fn new() -> Builder {\n        Builder {\n            raw: lyon_path::Path::builder().with_svg(),\n        }\n    }\n\n    /// Moves the starting point of a new sub-path to the given `Point`.\n    #[inline]\n    pub fn move_to(&mut self, point: Point) {\n        let _ = self.raw.move_to(math::Point::new(point.x, point.y));\n    }\n\n    /// Connects the last point in the [`Path`] to the given `Point` with a\n    /// straight line.\n    #[inline]\n    pub fn line_to(&mut self, point: Point) {\n        let _ = self.raw.line_to(math::Point::new(point.x, point.y));\n    }\n\n    /// Adds an [`Arc`] to the [`Path`] from `start_angle` to `end_angle` in\n    /// a clockwise direction.\n    #[inline]\n    pub fn arc(&mut self, arc: Arc) {\n        self.ellipse(arc.into());\n    }\n\n    /// Adds a circular arc to the [`Path`] with the given control points and\n    /// radius.\n    ///\n    /// This essentially draws a straight line segment from the current\n    /// position to `a`, but fits a circular arc of `radius` tangent to that\n    /// segment and tangent to the line between `a` and `b`.\n    ///\n    /// With another `.line_to(b)`, the result will be a path connecting the\n    /// starting point and `b` with straight line segments towards `a` and a\n    /// circular arc smoothing out the corner at `a`.\n    ///\n    /// See [the HTML5 specification of `arcTo`](https://html.spec.whatwg.org/multipage/canvas.html#building-paths:dom-context-2d-arcto)\n    /// for more details and examples.\n    pub fn arc_to(&mut self, a: Point, b: Point, radius: f32) {\n        let start = self.raw.current_position();\n        let mid = math::Point::new(a.x, a.y);\n        let end = math::Point::new(b.x, b.y);\n\n        if start == mid || mid == end || radius == 0.0 {\n            let _ = self.raw.line_to(mid);\n            return;\n        }\n\n        let double_area =\n            start.x * (mid.y - end.y) + mid.x * (end.y - start.y) + end.x * (start.y - mid.y);\n\n        if double_area == 0.0 {\n            let _ = self.raw.line_to(mid);\n            return;\n        }\n\n        let to_start = (start - mid).normalize();\n        let to_end = (end - mid).normalize();\n\n        let inner_angle = to_start.dot(to_end).acos();\n\n        let origin_angle = inner_angle / 2.0;\n\n        let origin_adjacent = radius / origin_angle.tan();\n\n        let arc_start = mid + to_start * origin_adjacent;\n        let arc_end = mid + to_end * origin_adjacent;\n\n        let sweep = to_start.cross(to_end) < 0.0;\n\n        let _ = self.raw.line_to(arc_start);\n\n        self.raw.arc_to(\n            math::Vector::new(radius, radius),\n            math::Angle::radians(0.0),\n            lyon_path::ArcFlags {\n                large_arc: false,\n                sweep,\n            },\n            arc_end,\n        );\n    }\n\n    /// Adds an ellipse to the [`Path`] using a clockwise direction.\n    pub fn ellipse(&mut self, arc: arc::Elliptical) {\n        let arc = geom::Arc {\n            center: math::Point::new(arc.center.x, arc.center.y),\n            radii: math::Vector::new(arc.radii.x, arc.radii.y),\n            x_rotation: math::Angle::radians(arc.rotation.0),\n            start_angle: math::Angle::radians(arc.start_angle.0),\n            sweep_angle: math::Angle::radians((arc.end_angle - arc.start_angle).0),\n        };\n\n        let _ = self.raw.move_to(arc.sample(0.0));\n\n        arc.cast::<f64>().for_each_quadratic_bezier(&mut |curve| {\n            let curve = curve.cast::<f32>();\n            let _ = self.raw.quadratic_bezier_to(curve.ctrl, curve.to);\n        });\n    }\n\n    /// Adds a cubic Bézier curve to the [`Path`] given its two control points\n    /// and its end point.\n    #[inline]\n    pub fn bezier_curve_to(&mut self, control_a: Point, control_b: Point, to: Point) {\n        let _ = self.raw.cubic_bezier_to(\n            math::Point::new(control_a.x, control_a.y),\n            math::Point::new(control_b.x, control_b.y),\n            math::Point::new(to.x, to.y),\n        );\n    }\n\n    /// Adds a quadratic Bézier curve to the [`Path`] given its control point\n    /// and its end point.\n    #[inline]\n    pub fn quadratic_curve_to(&mut self, control: Point, to: Point) {\n        let _ = self.raw.quadratic_bezier_to(\n            math::Point::new(control.x, control.y),\n            math::Point::new(to.x, to.y),\n        );\n    }\n\n    /// Adds a rectangle to the [`Path`] given its top-left corner coordinate\n    /// and its `Size`.\n    #[inline]\n    pub fn rectangle(&mut self, top_left: Point, size: Size) {\n        self.move_to(top_left);\n        self.line_to(Point::new(top_left.x + size.width, top_left.y));\n        self.line_to(Point::new(\n            top_left.x + size.width,\n            top_left.y + size.height,\n        ));\n        self.line_to(Point::new(top_left.x, top_left.y + size.height));\n        self.close();\n    }\n\n    /// Adds a rounded rectangle to the [`Path`] given its top-left\n    /// corner coordinate its [`Size`] and [`border::Radius`].\n    #[inline]\n    pub fn rounded_rectangle(&mut self, top_left: Point, size: Size, radius: border::Radius) {\n        let min_size = (size.height / 2.0).min(size.width / 2.0);\n        let [\n            top_left_corner,\n            top_right_corner,\n            bottom_right_corner,\n            bottom_left_corner,\n        ] = radius.into();\n\n        self.move_to(Point::new(\n            top_left.x + min_size.min(top_left_corner),\n            top_left.y,\n        ));\n        self.line_to(Point::new(\n            top_left.x + size.width - min_size.min(top_right_corner),\n            top_left.y,\n        ));\n        self.arc_to(\n            Point::new(top_left.x + size.width, top_left.y),\n            Point::new(\n                top_left.x + size.width,\n                top_left.y + min_size.min(top_right_corner),\n            ),\n            min_size.min(top_right_corner),\n        );\n        self.line_to(Point::new(\n            top_left.x + size.width,\n            top_left.y + size.height - min_size.min(bottom_right_corner),\n        ));\n        self.arc_to(\n            Point::new(top_left.x + size.width, top_left.y + size.height),\n            Point::new(\n                top_left.x + size.width - min_size.min(bottom_right_corner),\n                top_left.y + size.height,\n            ),\n            min_size.min(bottom_right_corner),\n        );\n        self.line_to(Point::new(\n            top_left.x + min_size.min(bottom_left_corner),\n            top_left.y + size.height,\n        ));\n        self.arc_to(\n            Point::new(top_left.x, top_left.y + size.height),\n            Point::new(\n                top_left.x,\n                top_left.y + size.height - min_size.min(bottom_left_corner),\n            ),\n            min_size.min(bottom_left_corner),\n        );\n        self.line_to(Point::new(\n            top_left.x,\n            top_left.y + min_size.min(top_left_corner),\n        ));\n        self.arc_to(\n            Point::new(top_left.x, top_left.y),\n            Point::new(top_left.x + min_size.min(top_left_corner), top_left.y),\n            min_size.min(top_left_corner),\n        );\n        self.close();\n    }\n\n    /// Adds a circle to the [`Path`] given its center coordinate and its\n    /// radius.\n    #[inline]\n    pub fn circle(&mut self, center: Point, radius: f32) {\n        self.arc(Arc {\n            center,\n            radius,\n            start_angle: Radians(0.0),\n            end_angle: Radians(2.0 * std::f32::consts::PI),\n        });\n    }\n\n    /// Closes the current sub-path in the [`Path`] with a straight line to\n    /// the starting point.\n    #[inline]\n    pub fn close(&mut self) {\n        self.raw.close();\n    }\n\n    /// Builds the [`Path`] of this [`Builder`].\n    #[inline]\n    pub fn build(self) -> Path {\n        Path {\n            raw: self.raw.build(),\n        }\n    }\n}\n\nimpl Default for Builder {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n"
  },
  {
    "path": "graphics/src/geometry/path.rs",
    "content": "//! Build different kinds of 2D shapes.\npub mod arc;\n\nmod builder;\n\n#[doc(no_inline)]\npub use arc::Arc;\npub use builder::Builder;\n\npub use lyon_path;\n\nuse crate::core::border;\nuse crate::core::{Point, Size};\n\n/// An immutable set of points that may or may not be connected.\n///\n/// A single [`Path`] can represent different kinds of 2D shapes!\n#[derive(Debug, Clone)]\npub struct Path {\n    raw: lyon_path::Path,\n}\n\nimpl Path {\n    /// Creates a new [`Path`] with the provided closure.\n    ///\n    /// Use the [`Builder`] to configure your [`Path`].\n    pub fn new(f: impl FnOnce(&mut Builder)) -> Self {\n        let mut builder = Builder::new();\n\n        // TODO: Make it pure instead of side-effect-based (?)\n        f(&mut builder);\n\n        builder.build()\n    }\n\n    /// Creates a new [`Path`] representing a line segment given its starting\n    /// and end points.\n    pub fn line(from: Point, to: Point) -> Self {\n        Self::new(|p| {\n            p.move_to(from);\n            p.line_to(to);\n        })\n    }\n\n    /// Creates a new [`Path`] representing a rectangle given its top-left\n    /// corner coordinate and its `Size`.\n    pub fn rectangle(top_left: Point, size: Size) -> Self {\n        Self::new(|p| p.rectangle(top_left, size))\n    }\n\n    /// Creates a new [`Path`] representing a rounded rectangle given its top-left\n    /// corner coordinate, its [`Size`] and [`border::Radius`].\n    pub fn rounded_rectangle(top_left: Point, size: Size, radius: border::Radius) -> Self {\n        Self::new(|p| p.rounded_rectangle(top_left, size, radius))\n    }\n\n    /// Creates a new [`Path`] representing a circle given its center\n    /// coordinate and its radius.\n    pub fn circle(center: Point, radius: f32) -> Self {\n        Self::new(|p| {\n            p.circle(center, radius);\n            p.close();\n        })\n    }\n\n    /// Returns the internal [`lyon_path::Path`].\n    #[inline]\n    pub fn raw(&self) -> &lyon_path::Path {\n        &self.raw\n    }\n\n    /// Returns the current [`Path`] with the given transform applied to it.\n    #[inline]\n    pub fn transform(&self, transform: &lyon_path::math::Transform) -> Path {\n        Path {\n            raw: self.raw.clone().transformed(transform),\n        }\n    }\n}\n"
  },
  {
    "path": "graphics/src/geometry/stroke.rs",
    "content": "//! Create lines from a [`Path`] and assigns them various attributes/styles.\n//!\n//! [`Path`]: super::Path\npub use crate::geometry::Style;\n\nuse iced_core::Color;\n\n/// The style of a stroke.\n#[derive(Debug, Clone, Copy)]\npub struct Stroke<'a> {\n    /// The color or gradient of the stroke.\n    ///\n    /// By default, it is set to a [`Style::Solid`] with [`Color::BLACK`].\n    pub style: Style,\n    /// The distance between the two edges of the stroke.\n    pub width: f32,\n    /// The shape to be used at the end of open subpaths when they are stroked.\n    pub line_cap: LineCap,\n    /// The shape to be used at the corners of paths or basic shapes when they\n    /// are stroked.\n    pub line_join: LineJoin,\n    /// The dash pattern used when stroking the line.\n    pub line_dash: LineDash<'a>,\n}\n\nimpl Stroke<'_> {\n    /// Sets the color of the [`Stroke`].\n    pub fn with_color(self, color: Color) -> Self {\n        Stroke {\n            style: Style::Solid(color),\n            ..self\n        }\n    }\n\n    /// Sets the width of the [`Stroke`].\n    pub fn with_width(self, width: f32) -> Self {\n        Stroke { width, ..self }\n    }\n\n    /// Sets the [`LineCap`] of the [`Stroke`].\n    pub fn with_line_cap(self, line_cap: LineCap) -> Self {\n        Stroke { line_cap, ..self }\n    }\n\n    /// Sets the [`LineJoin`] of the [`Stroke`].\n    pub fn with_line_join(self, line_join: LineJoin) -> Self {\n        Stroke { line_join, ..self }\n    }\n}\n\nimpl Default for Stroke<'_> {\n    fn default() -> Self {\n        Stroke {\n            style: Style::Solid(Color::BLACK),\n            width: 1.0,\n            line_cap: LineCap::default(),\n            line_join: LineJoin::default(),\n            line_dash: LineDash::default(),\n        }\n    }\n}\n\n/// The shape used at the end of open subpaths when they are stroked.\n#[derive(Debug, Clone, Copy, Default)]\npub enum LineCap {\n    /// The stroke for each sub-path does not extend beyond its two endpoints.\n    #[default]\n    Butt,\n    /// At the end of each sub-path, the shape representing the stroke will be\n    /// extended by a square.\n    Square,\n    /// At the end of each sub-path, the shape representing the stroke will be\n    /// extended by a semicircle.\n    Round,\n}\n\n/// The shape used at the corners of paths or basic shapes when they are\n/// stroked.\n#[derive(Debug, Clone, Copy, Default)]\npub enum LineJoin {\n    /// A sharp corner.\n    #[default]\n    Miter,\n    /// A round corner.\n    Round,\n    /// A bevelled corner.\n    Bevel,\n}\n\n/// The dash pattern used when stroking the line.\n#[derive(Debug, Clone, Copy, Default)]\npub struct LineDash<'a> {\n    /// The alternating lengths of lines and gaps which describe the pattern.\n    pub segments: &'a [f32],\n\n    /// The offset of [`LineDash::segments`] to start the pattern.\n    pub offset: usize,\n}\n"
  },
  {
    "path": "graphics/src/geometry/style.rs",
    "content": "use crate::core::Color;\nuse crate::geometry::Gradient;\n\n/// The coloring style of some drawing.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Style {\n    /// A solid [`Color`].\n    Solid(Color),\n\n    /// A [`Gradient`] color.\n    Gradient(Gradient),\n}\n\nimpl From<Color> for Style {\n    fn from(color: Color) -> Self {\n        Self::Solid(color)\n    }\n}\n\nimpl From<Gradient> for Style {\n    fn from(gradient: Gradient) -> Self {\n        Self::Gradient(gradient)\n    }\n}\n"
  },
  {
    "path": "graphics/src/geometry/text.rs",
    "content": "use crate::core;\nuse crate::core::alignment;\nuse crate::core::text::{Alignment, Ellipsis, LineHeight, Paragraph, Shaping, Wrapping};\nuse crate::core::{Color, Font, Pixels, Point, Size, Vector};\nuse crate::geometry::Path;\nuse crate::text;\n\n/// A bunch of text that can be drawn to a canvas\n#[derive(Debug, Clone)]\npub struct Text {\n    /// The contents of the text\n    pub content: String,\n    /// The position of the text relative to the alignment properties.\n    ///\n    /// By default, this position will be relative to the top-left corner coordinate meaning that\n    /// if the horizontal and vertical alignments are unchanged, this property will tell where the\n    /// top-left corner of the text should be placed.\n    ///\n    /// By changing the horizontal_alignment and vertical_alignment properties, you are are able to\n    /// change what part of text is placed at this positions.\n    ///\n    /// For example, when the horizontal_alignment and vertical_alignment are set to Center, the\n    /// center of the text will be placed at the given position NOT the top-left coordinate.\n    pub position: Point,\n    /// The maximum horizontal space available for this [`Text`].\n    ///\n    /// Text will break into new lines when the width is reached.\n    pub max_width: f32,\n    /// The color of the text\n    pub color: Color,\n    /// The size of the text\n    pub size: Pixels,\n    /// The line height of the text.\n    pub line_height: LineHeight,\n    /// The font of the text\n    pub font: Font,\n    /// The horizontal alignment of the text\n    pub align_x: Alignment,\n    /// The vertical alignment of the text\n    pub align_y: alignment::Vertical,\n    /// The shaping strategy of the text.\n    pub shaping: Shaping,\n    /// The wrapping strategy of the text.\n    pub wrapping: Wrapping,\n    /// The ellipsis strategy of the text.\n    pub ellipsis: Ellipsis,\n}\n\nimpl Text {\n    /// Computes the [`Path`]s of the [`Text`] and draws them using\n    /// the given closure.\n    pub fn draw_with(&self, mut f: impl FnMut(Path, Color)) {\n        let paragraph = text::Paragraph::with_text(core::text::Text {\n            content: &self.content,\n            bounds: Size::new(self.max_width, f32::INFINITY),\n            size: self.size,\n            line_height: self.line_height,\n            font: self.font,\n            align_x: self.align_x,\n            align_y: self.align_y,\n            shaping: self.shaping,\n            wrapping: Wrapping::default(),\n            ellipsis: Ellipsis::default(),\n            hint_factor: None,\n        });\n\n        let translation_x = match self.align_x {\n            Alignment::Default | Alignment::Left | Alignment::Justified => self.position.x,\n            Alignment::Center => self.position.x - paragraph.min_width() / 2.0,\n            Alignment::Right => self.position.x - paragraph.min_width(),\n        };\n\n        let translation_y = {\n            match self.align_y {\n                alignment::Vertical::Top => self.position.y,\n                alignment::Vertical::Center => self.position.y - paragraph.min_height() / 2.0,\n                alignment::Vertical::Bottom => self.position.y - paragraph.min_height(),\n            }\n        };\n\n        let buffer = paragraph.buffer();\n        let mut swash_cache = cosmic_text::SwashCache::new();\n\n        let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n        for run in buffer.layout_runs() {\n            for glyph in run.glyphs.iter() {\n                let physical_glyph = glyph.physical((0.0, 0.0), 1.0);\n\n                let start_x = translation_x + glyph.x + glyph.x_offset;\n                let start_y = translation_y + glyph.y_offset + run.line_y;\n                let offset = Vector::new(start_x, start_y);\n\n                if let Some(commands) =\n                    swash_cache.get_outline_commands(font_system.raw(), physical_glyph.cache_key)\n                {\n                    let glyph = Path::new(|path| {\n                        use cosmic_text::Command;\n\n                        for command in commands {\n                            match command {\n                                Command::MoveTo(p) => {\n                                    path.move_to(Point::new(p.x, -p.y) + offset);\n                                }\n                                Command::LineTo(p) => {\n                                    path.line_to(Point::new(p.x, -p.y) + offset);\n                                }\n                                Command::CurveTo(control_a, control_b, to) => {\n                                    path.bezier_curve_to(\n                                        Point::new(control_a.x, -control_a.y) + offset,\n                                        Point::new(control_b.x, -control_b.y) + offset,\n                                        Point::new(to.x, -to.y) + offset,\n                                    );\n                                }\n                                Command::QuadTo(control, to) => {\n                                    path.quadratic_curve_to(\n                                        Point::new(control.x, -control.y) + offset,\n                                        Point::new(to.x, -to.y) + offset,\n                                    );\n                                }\n                                Command::Close => {\n                                    path.close();\n                                }\n                            }\n                        }\n                    });\n\n                    f(glyph, self.color);\n                } else {\n                    // TODO: Raster image support for `Canvas`\n                    let [r, g, b, a] = self.color.into_rgba8();\n\n                    swash_cache.with_pixels(\n                        font_system.raw(),\n                        physical_glyph.cache_key,\n                        cosmic_text::Color::rgba(r, g, b, a),\n                        |x, y, color| {\n                            f(\n                                Path::rectangle(\n                                    Point::new(x as f32, y as f32) + offset,\n                                    Size::new(1.0, 1.0),\n                                ),\n                                Color::from_rgba8(\n                                    color.r(),\n                                    color.g(),\n                                    color.b(),\n                                    color.a() as f32 / 255.0,\n                                ),\n                            );\n                        },\n                    );\n                }\n            }\n        }\n    }\n}\n\nimpl Default for Text {\n    fn default() -> Text {\n        Text {\n            content: String::new(),\n            position: Point::ORIGIN,\n            max_width: f32::INFINITY,\n            color: Color::BLACK,\n            size: Pixels(16.0),\n            line_height: LineHeight::Relative(1.2),\n            font: Font::default(),\n            align_x: Alignment::Default,\n            align_y: alignment::Vertical::Top,\n            shaping: Shaping::default(),\n            wrapping: Wrapping::default(),\n            ellipsis: Ellipsis::default(),\n        }\n    }\n}\n\nimpl From<String> for Text {\n    fn from(content: String) -> Text {\n        Text {\n            content,\n            ..Default::default()\n        }\n    }\n}\n\nimpl From<&str> for Text {\n    fn from(content: &str) -> Text {\n        String::from(content).into()\n    }\n}\n"
  },
  {
    "path": "graphics/src/geometry.rs",
    "content": "//! Build and draw geometry.\npub mod fill;\npub mod frame;\npub mod path;\npub mod stroke;\n\nmod cache;\nmod style;\nmod text;\n\npub use cache::Cache;\npub use fill::Fill;\npub use frame::Frame;\npub use path::Path;\npub use stroke::{LineCap, LineDash, LineJoin, Stroke};\npub use style::Style;\npub use text::Text;\n\npub use crate::core::{Image, Svg};\npub use crate::gradient::{self, Gradient};\n\nuse crate::cache::Cached;\nuse crate::core::{self, Rectangle};\n\n/// A renderer capable of drawing some [`Self::Geometry`].\npub trait Renderer: core::Renderer {\n    /// The kind of geometry this renderer can draw.\n    type Geometry: Cached;\n\n    /// The kind of [`Frame`] this renderer supports.\n    type Frame: frame::Backend<Geometry = Self::Geometry>;\n\n    /// Creates a new [`Self::Frame`].\n    fn new_frame(&self, bounds: Rectangle) -> Self::Frame;\n\n    /// Draws the given [`Self::Geometry`].\n    fn draw_geometry(&mut self, geometry: Self::Geometry);\n}\n\n#[cfg(debug_assertions)]\nimpl Renderer for () {\n    type Geometry = ();\n    type Frame = ();\n\n    fn new_frame(&self, _bounds: Rectangle) -> Self::Frame {}\n\n    fn draw_geometry(&mut self, _geometry: Self::Geometry) {}\n}\n"
  },
  {
    "path": "graphics/src/gradient.rs",
    "content": "//! A gradient that can be used as a fill for some geometry.\n//!\n//! For a gradient that you can use as a background variant for a widget, see [`Gradient`].\nuse crate::color;\nuse crate::core::gradient::ColorStop;\nuse crate::core::{self, Color, Point, Rectangle};\n\nuse bytemuck::{Pod, Zeroable};\nuse half::f16;\nuse std::cmp::Ordering;\n\n#[derive(Debug, Clone, Copy, PartialEq)]\n/// A fill which linearly interpolates colors along a direction.\n///\n/// For a gradient which can be used as a fill for a background of a widget, see [`crate::core::Gradient`].\npub enum Gradient {\n    /// A linear gradient interpolates colors along a direction from its `start` to its `end`\n    /// point.\n    Linear(Linear),\n}\n\nimpl From<Linear> for Gradient {\n    fn from(gradient: Linear) -> Self {\n        Self::Linear(gradient)\n    }\n}\n\nimpl Gradient {\n    /// Packs the [`Gradient`] for use in shader code.\n    pub fn pack(&self) -> Packed {\n        match self {\n            Gradient::Linear(linear) => linear.pack(),\n        }\n    }\n}\n\n/// A linear gradient.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Linear {\n    /// The absolute starting position of the gradient.\n    pub start: Point,\n\n    /// The absolute ending position of the gradient.\n    pub end: Point,\n\n    /// [`ColorStop`]s along the linear gradient direction.\n    pub stops: [Option<ColorStop>; 8],\n}\n\nimpl Linear {\n    /// Creates a new [`Linear`] builder.\n    pub fn new(start: Point, end: Point) -> Self {\n        Self {\n            start,\n            end,\n            stops: [None; 8],\n        }\n    }\n\n    /// Adds a new [`ColorStop`], defined by an offset and a color, to the gradient.\n    ///\n    /// Any `offset` that is not within `0.0..=1.0` will be silently ignored.\n    ///\n    /// Any stop added after the 8th will be silently ignored.\n    pub fn add_stop(mut self, offset: f32, color: Color) -> Self {\n        if offset.is_finite() && (0.0..=1.0).contains(&offset) {\n            let (Ok(index) | Err(index)) = self.stops.binary_search_by(|stop| match stop {\n                None => Ordering::Greater,\n                Some(stop) => stop.offset.partial_cmp(&offset).unwrap(),\n            });\n\n            if index < 8 {\n                self.stops[index] = Some(ColorStop { offset, color });\n            }\n        } else {\n            log::warn!(\"Gradient: ColorStop must be within 0.0..=1.0 range.\");\n        };\n\n        self\n    }\n\n    /// Adds multiple [`ColorStop`]s to the gradient.\n    ///\n    /// Any stop added after the 8th will be silently ignored.\n    pub fn add_stops(mut self, stops: impl IntoIterator<Item = ColorStop>) -> Self {\n        for stop in stops {\n            self = self.add_stop(stop.offset, stop.color);\n        }\n\n        self\n    }\n\n    /// Packs the [`Gradient`] for use in shader code.\n    pub fn pack(&self) -> Packed {\n        let mut colors = [[0u32; 2]; 8];\n        let mut offsets = [f16::from(0u8); 8];\n\n        for (index, stop) in self.stops.iter().enumerate() {\n            let [r, g, b, a] = color::pack(stop.map_or(Color::default(), |s| s.color)).components();\n\n            colors[index] = [\n                pack_f16s([f16::from_f32(r), f16::from_f32(g)]),\n                pack_f16s([f16::from_f32(b), f16::from_f32(a)]),\n            ];\n\n            offsets[index] = stop.map_or(f16::from_f32(2.0), |s| f16::from_f32(s.offset));\n        }\n\n        let offsets = [\n            pack_f16s([offsets[0], offsets[1]]),\n            pack_f16s([offsets[2], offsets[3]]),\n            pack_f16s([offsets[4], offsets[5]]),\n            pack_f16s([offsets[6], offsets[7]]),\n        ];\n\n        let direction = [self.start.x, self.start.y, self.end.x, self.end.y];\n\n        Packed {\n            colors,\n            offsets,\n            direction,\n        }\n    }\n}\n\n/// Packed [`Gradient`] data for use in shader code.\n#[derive(Debug, Copy, Clone, PartialEq, Zeroable, Pod)]\n#[repr(C)]\npub struct Packed {\n    // 8 colors, each channel = 16 bit float, 2 colors packed into 1 u32\n    colors: [[u32; 2]; 8],\n    // 8 offsets, 8x 16 bit floats packed into 4 u32s\n    offsets: [u32; 4],\n    direction: [f32; 4],\n}\n\n/// Creates a new [`Packed`] gradient for use in shader code.\npub fn pack(gradient: &core::Gradient, bounds: Rectangle) -> Packed {\n    match gradient {\n        core::Gradient::Linear(linear) => {\n            let mut colors = [[0u32; 2]; 8];\n            let mut offsets = [f16::from(0u8); 8];\n\n            for (index, stop) in linear.stops.iter().enumerate() {\n                let [r, g, b, a] =\n                    color::pack(stop.map_or(Color::default(), |s| s.color)).components();\n\n                colors[index] = [\n                    pack_f16s([f16::from_f32(r), f16::from_f32(g)]),\n                    pack_f16s([f16::from_f32(b), f16::from_f32(a)]),\n                ];\n\n                offsets[index] = stop.map_or(f16::from_f32(2.0), |s| f16::from_f32(s.offset));\n            }\n\n            let offsets = [\n                pack_f16s([offsets[0], offsets[1]]),\n                pack_f16s([offsets[2], offsets[3]]),\n                pack_f16s([offsets[4], offsets[5]]),\n                pack_f16s([offsets[6], offsets[7]]),\n            ];\n\n            let (start, end) = linear.angle.to_distance(&bounds);\n\n            let direction = [start.x, start.y, end.x, end.y];\n\n            Packed {\n                colors,\n                offsets,\n                direction,\n            }\n        }\n    }\n}\n\n/// Packs two f16s into one u32.\nfn pack_f16s(f: [f16; 2]) -> u32 {\n    let one = (f[0].to_bits() as u32) << 16;\n    let two = f[1].to_bits() as u32;\n\n    one | two\n}\n"
  },
  {
    "path": "graphics/src/image/storage.rs",
    "content": "//! Store images.\nuse iced_core::Size;\n\nuse std::fmt::Debug;\n\n/// Stores cached image data for use in rendering\npub trait Storage {\n    /// The type of an [`Entry`] in the [`Storage`].\n    type Entry: Entry;\n\n    /// State provided to upload or remove a [`Self::Entry`].\n    type State<'a>;\n\n    /// Upload the image data of a [`Self::Entry`].\n    fn upload(\n        &mut self,\n        width: u32,\n        height: u32,\n        data: &[u8],\n        state: &mut Self::State<'_>,\n    ) -> Option<Self::Entry>;\n\n    /// Remove a [`Self::Entry`] from the [`Storage`].\n    fn remove(&mut self, entry: &Self::Entry, state: &mut Self::State<'_>);\n}\n\n/// An entry in some [`Storage`],\npub trait Entry: Debug {\n    /// The [`Size`] of the [`Entry`].\n    fn size(&self) -> Size<u32>;\n}\n"
  },
  {
    "path": "graphics/src/image.rs",
    "content": "//! Load and operate on images.\n#[cfg(feature = \"image\")]\nuse crate::core::Bytes;\n\nuse crate::core::Rectangle;\nuse crate::core::image;\nuse crate::core::svg;\n\n/// A raster or vector image.\n#[allow(missing_docs)]\n#[derive(Debug, Clone, PartialEq)]\npub enum Image {\n    /// A raster image.\n    Raster {\n        image: image::Image,\n        bounds: Rectangle,\n        clip_bounds: Rectangle,\n    },\n\n    /// A vector image.\n    Vector {\n        svg: svg::Svg,\n        bounds: Rectangle,\n        clip_bounds: Rectangle,\n    },\n}\n\nimpl Image {\n    /// Returns the bounds of the [`Image`].\n    pub fn bounds(&self) -> Rectangle {\n        match self {\n            Image::Raster { image, bounds, .. } => bounds.rotate(image.rotation),\n            Image::Vector { svg, bounds, .. } => bounds.rotate(svg.rotation),\n        }\n    }\n}\n\n/// An image buffer.\n#[cfg(feature = \"image\")]\npub type Buffer = ::image::ImageBuffer<::image::Rgba<u8>, Bytes>;\n\n#[cfg(feature = \"image\")]\n/// Tries to load an image by its [`Handle`].\n///\n/// [`Handle`]: image::Handle\npub fn load(handle: &image::Handle) -> Result<Buffer, image::Error> {\n    use bitflags::bitflags;\n\n    bitflags! {\n        struct Operation: u8 {\n            const FLIP_HORIZONTALLY = 0b1;\n            const ROTATE_180 = 0b10;\n            const FLIP_VERTICALLY= 0b100;\n            const ROTATE_90 = 0b1000;\n            const ROTATE_270 = 0b10000;\n        }\n    }\n\n    impl Operation {\n        // Meaning of the returned value is described e.g. at:\n        // https://magnushoff.com/articles/jpeg-orientation/\n        fn from_exif<R>(reader: &mut R) -> Result<Self, exif::Error>\n        where\n            R: std::io::BufRead + std::io::Seek,\n        {\n            let exif = exif::Reader::new().read_from_container(reader)?;\n\n            Ok(exif\n                .get_field(exif::Tag::Orientation, exif::In::PRIMARY)\n                .and_then(|field| field.value.get_uint(0))\n                .and_then(|value| u8::try_from(value).ok())\n                .map(|value| match value {\n                    1 => Operation::empty(),\n                    2 => Operation::FLIP_HORIZONTALLY,\n                    3 => Operation::ROTATE_180,\n                    4 => Operation::FLIP_VERTICALLY,\n                    5 => Operation::ROTATE_90 | Operation::FLIP_HORIZONTALLY,\n                    6 => Operation::ROTATE_90,\n                    7 => Operation::ROTATE_90 | Operation::FLIP_VERTICALLY,\n                    8 => Operation::ROTATE_270,\n                    _ => Operation::empty(),\n                })\n                .unwrap_or_else(Self::empty))\n        }\n\n        fn perform(self, mut image: ::image::DynamicImage) -> ::image::DynamicImage {\n            use ::image::imageops;\n\n            if self.contains(Operation::ROTATE_90) {\n                image = imageops::rotate90(&image).into();\n            }\n\n            if self.contains(Self::ROTATE_180) {\n                imageops::rotate180_in_place(&mut image);\n            }\n\n            if self.contains(Operation::ROTATE_270) {\n                image = imageops::rotate270(&image).into();\n            }\n\n            if self.contains(Self::FLIP_VERTICALLY) {\n                imageops::flip_vertical_in_place(&mut image);\n            }\n\n            if self.contains(Self::FLIP_HORIZONTALLY) {\n                imageops::flip_horizontal_in_place(&mut image);\n            }\n\n            image\n        }\n    }\n\n    let (width, height, pixels) = match handle {\n        image::Handle::Path(_, path) => {\n            let image = ::image::open(path).map_err(to_error)?;\n\n            let operation = std::fs::File::open(path)\n                .ok()\n                .map(std::io::BufReader::new)\n                .and_then(|mut reader| Operation::from_exif(&mut reader).ok())\n                .unwrap_or_else(Operation::empty);\n\n            let rgba = operation.perform(image).into_rgba8();\n\n            (rgba.width(), rgba.height(), Bytes::from(rgba.into_raw()))\n        }\n        image::Handle::Bytes(_, bytes) => {\n            let image = ::image::load_from_memory(bytes).map_err(to_error)?;\n\n            let operation = Operation::from_exif(&mut std::io::Cursor::new(bytes))\n                .ok()\n                .unwrap_or_else(Operation::empty);\n\n            let rgba = operation.perform(image).into_rgba8();\n\n            (rgba.width(), rgba.height(), Bytes::from(rgba.into_raw()))\n        }\n        image::Handle::Rgba {\n            width,\n            height,\n            pixels,\n            ..\n        } => (*width, *height, pixels.clone()),\n    };\n\n    if let Some(image) = ::image::ImageBuffer::from_raw(width, height, pixels) {\n        Ok(image)\n    } else {\n        Err(to_error(::image::error::ImageError::Limits(\n            ::image::error::LimitError::from_kind(::image::error::LimitErrorKind::DimensionError),\n        )))\n    }\n}\n\n#[cfg(feature = \"image\")]\nfn to_error(error: ::image::ImageError) -> image::Error {\n    use std::sync::Arc;\n\n    match error {\n        ::image::ImageError::IoError(error) => image::Error::Inaccessible(Arc::new(error)),\n        error => image::Error::Invalid(Arc::new(error)),\n    }\n}\n"
  },
  {
    "path": "graphics/src/layer.rs",
    "content": "//! Draw and stack layers of graphical primitives.\nuse crate::core::{Rectangle, Transformation};\n\n/// A layer of graphical primitives.\n///\n/// Layers normally dictate a set of primitives that are\n/// rendered in a specific order.\npub trait Layer: Default {\n    /// Creates a new [`Layer`] with the given bounds.\n    fn with_bounds(bounds: Rectangle) -> Self;\n\n    /// Returns the current bounds of the [`Layer`].\n    fn bounds(&self) -> Rectangle;\n\n    /// Flushes and settles any pending group of primitives in the [`Layer`].\n    ///\n    /// This will be called when a [`Layer`] is finished. It allows layers to efficiently\n    /// record primitives together and defer grouping until the end.\n    fn flush(&mut self);\n\n    /// Resizes the [`Layer`] to the given bounds.\n    fn resize(&mut self, bounds: Rectangle);\n\n    /// Clears all the layers contents and resets its bounds.\n    fn reset(&mut self);\n\n    /// Returns the start level of the [`Layer`].\n    ///\n    /// A level is a \"sublayer\" index inside of a [`Layer`].\n    ///\n    /// A [`Layer`] may draw multiple primitive types in a certain order.\n    /// The level represents the lowest index of the primitive types it\n    /// contains.\n    ///\n    /// Two layers A and B can therefore be merged if they have the same bounds,\n    /// and the end level of A is lower or equal than the start level of B.\n    fn start(&self) -> usize;\n\n    /// Returns the end level of the [`Layer`].\n    fn end(&self) -> usize;\n\n    /// Merges a [`Layer`] with the current one.\n    fn merge(&mut self, _layer: &mut Self);\n}\n\n/// A stack of layers used for drawing.\n#[derive(Debug)]\npub struct Stack<T: Layer> {\n    layers: Vec<T>,\n    transformations: Vec<Transformation>,\n    previous: Vec<usize>,\n    current: usize,\n    active_count: usize,\n}\n\nimpl<T: Layer> Stack<T> {\n    /// Creates a new empty [`Stack`].\n    pub fn new() -> Self {\n        Self {\n            layers: vec![T::default()],\n            transformations: vec![Transformation::IDENTITY],\n            previous: vec![],\n            current: 0,\n            active_count: 1,\n        }\n    }\n\n    /// Returns a mutable reference to the current [`Layer`] of the [`Stack`], together with\n    /// the current [`Transformation`].\n    #[inline]\n    pub fn current_mut(&mut self) -> (&mut T, Transformation) {\n        let transformation = self.transformation();\n\n        (&mut self.layers[self.current], transformation)\n    }\n\n    /// Returns the current [`Transformation`] of the [`Stack`].\n    #[inline]\n    pub fn transformation(&self) -> Transformation {\n        self.transformations.last().copied().unwrap()\n    }\n\n    /// Pushes a new clipping region in the [`Stack`]; creating a new layer in the\n    /// process.\n    pub fn push_clip(&mut self, bounds: Rectangle) {\n        self.previous.push(self.current);\n\n        self.current = self.active_count;\n        self.active_count += 1;\n\n        let bounds = bounds * self.transformation();\n\n        if self.current == self.layers.len() {\n            self.layers.push(T::with_bounds(bounds));\n        } else {\n            self.layers[self.current].resize(bounds);\n        }\n    }\n\n    /// Pops the current clipping region from the [`Stack`] and restores the previous one.\n    ///\n    /// The current layer will be recorded for drawing.\n    pub fn pop_clip(&mut self) {\n        self.flush();\n\n        self.current = self.previous.pop().unwrap();\n    }\n\n    /// Pushes a new [`Transformation`] in the [`Stack`].\n    ///\n    /// Future drawing operations will be affected by this new [`Transformation`] until\n    /// it is popped using [`pop_transformation`].\n    ///\n    /// [`pop_transformation`]: Self::pop_transformation\n    pub fn push_transformation(&mut self, transformation: Transformation) {\n        self.transformations\n            .push(self.transformation() * transformation);\n    }\n\n    /// Pops the current [`Transformation`] in the [`Stack`].\n    pub fn pop_transformation(&mut self) {\n        let _ = self.transformations.pop();\n    }\n\n    /// Returns an iterator over immutable references to the layers in the [`Stack`].\n    pub fn iter(&self) -> impl Iterator<Item = &T> {\n        self.layers[..self.active_count].iter()\n    }\n\n    /// Returns the slice of layers in the [`Stack`].\n    pub fn as_slice(&self) -> &[T] {\n        &self.layers[..self.active_count]\n    }\n\n    /// Flushes and settles any primitives in the [`Stack`].\n    pub fn flush(&mut self) {\n        self.layers[self.current].flush();\n    }\n\n    /// Performs layer merging wherever possible.\n    ///\n    /// Flushes and settles any primitives in the [`Stack`].\n    pub fn merge(&mut self) {\n        self.flush();\n\n        // These are the layers left to process\n        let mut left = self.active_count;\n\n        // There must be at least 2 or more layers to merge\n        while left > 1 {\n            // We set our target as the topmost layer left to process\n            let mut current = left - 1;\n            let mut target = &self.layers[current];\n            let mut target_start = target.start();\n            let mut target_index = current;\n\n            // We scan downwards for a contiguous block of mergeable layer candidates\n            while current > 0 {\n                let candidate = &self.layers[current - 1];\n                let start = candidate.start();\n                let end = candidate.end();\n\n                // We skip empty layers\n                if end == 0 {\n                    current -= 1;\n                    continue;\n                }\n\n                // Candidate can be merged if primitive sublayers do not overlap with\n                // previous targets and the clipping bounds match\n                if end > target_start || candidate.bounds() != target.bounds() {\n                    break;\n                }\n\n                // Candidate is not empty and can be merged into\n                target = candidate;\n                target_start = start;\n                target_index = current;\n                current -= 1;\n            }\n\n            // We merge all the layers scanned into the target\n            //\n            // Since we use `target_index` instead of `current`, we\n            // deliberately avoid merging into empty layers.\n            //\n            // If no candidates were mergeable, this is a no-op.\n            let (head, tail) = self.layers.split_at_mut(target_index + 1);\n            let layer = &mut head[target_index];\n\n            for middle in &mut tail[0..left - target_index - 1] {\n                layer.merge(middle);\n            }\n\n            // Empty layers found after the target can be skipped\n            left = current;\n        }\n    }\n\n    /// Clears the layers of the [`Stack`], allowing reuse.\n    ///\n    /// It resizes the base layer bounds to the `new_bounds`.\n    ///\n    /// This will normally keep layer allocations for future drawing operations.\n    pub fn reset(&mut self, new_bounds: Rectangle) {\n        for layer in self.layers[..self.active_count].iter_mut() {\n            layer.reset();\n        }\n\n        self.layers[0].resize(new_bounds);\n        self.current = 0;\n        self.active_count = 1;\n        self.previous.clear();\n    }\n}\n\nimpl<T: Layer> Default for Stack<T> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n"
  },
  {
    "path": "graphics/src/lib.rs",
    "content": "//! A bunch of backend-agnostic types that can be leveraged to build a renderer\n//! for [`iced`].\n//!\n//! ![The native path of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)\n//!\n//! [`iced`]: https://github.com/iced-rs/iced\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg\"\n)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\nmod antialiasing;\nmod viewport;\n\npub mod cache;\npub mod color;\npub mod compositor;\npub mod damage;\npub mod error;\npub mod gradient;\npub mod image;\npub mod layer;\npub mod mesh;\npub mod shell;\npub mod text;\n\n#[cfg(feature = \"geometry\")]\npub mod geometry;\n\npub use antialiasing::Antialiasing;\npub use cache::Cache;\npub use compositor::Compositor;\npub use error::Error;\npub use gradient::Gradient;\npub use image::Image;\npub use layer::Layer;\npub use mesh::Mesh;\npub use shell::Shell;\npub use text::Text;\npub use viewport::Viewport;\n\npub use iced_core as core;\npub use iced_futures as futures;\n"
  },
  {
    "path": "graphics/src/mesh.rs",
    "content": "//! Draw triangles!\nuse crate::color;\nuse crate::core::{Rectangle, Transformation};\nuse crate::gradient;\n\nuse bytemuck::{Pod, Zeroable};\n\nuse std::sync::Arc;\nuse std::sync::atomic::{self, AtomicU64};\n\n/// A low-level primitive to render a mesh of triangles.\n#[derive(Debug, Clone, PartialEq)]\npub enum Mesh {\n    /// A mesh with a solid color.\n    Solid {\n        /// The vertices and indices of the mesh.\n        buffers: Indexed<SolidVertex2D>,\n\n        /// The [`Transformation`] for the vertices of the [`Mesh`].\n        transformation: Transformation,\n\n        /// The clip bounds of the [`Mesh`].\n        clip_bounds: Rectangle,\n    },\n    /// A mesh with a gradient.\n    Gradient {\n        /// The vertices and indices of the mesh.\n        buffers: Indexed<GradientVertex2D>,\n\n        /// The [`Transformation`] for the vertices of the [`Mesh`].\n        transformation: Transformation,\n\n        /// The clip bounds of the [`Mesh`].\n        clip_bounds: Rectangle,\n    },\n}\n\nimpl Mesh {\n    /// Returns the indices of the [`Mesh`].\n    pub fn indices(&self) -> &[u32] {\n        match self {\n            Self::Solid { buffers, .. } => &buffers.indices,\n            Self::Gradient { buffers, .. } => &buffers.indices,\n        }\n    }\n\n    /// Returns the [`Transformation`] of the [`Mesh`].\n    pub fn transformation(&self) -> Transformation {\n        match self {\n            Self::Solid { transformation, .. } | Self::Gradient { transformation, .. } => {\n                *transformation\n            }\n        }\n    }\n\n    /// Returns the clip bounds of the [`Mesh`].\n    pub fn clip_bounds(&self) -> Rectangle {\n        match self {\n            Self::Solid {\n                clip_bounds,\n                transformation,\n                ..\n            }\n            | Self::Gradient {\n                clip_bounds,\n                transformation,\n                ..\n            } => *clip_bounds * *transformation,\n        }\n    }\n}\n\n/// A set of vertices and indices representing a list of triangles.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct Indexed<T> {\n    /// The vertices of the mesh\n    pub vertices: Vec<T>,\n\n    /// The list of vertex indices that defines the triangles of the mesh.\n    ///\n    /// Therefore, this list should always have a length that is a multiple of 3.\n    pub indices: Vec<u32>,\n}\n\n/// A two-dimensional vertex with a color.\n#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)]\n#[repr(C)]\npub struct SolidVertex2D {\n    /// The vertex position in 2D space.\n    pub position: [f32; 2],\n\n    /// The color of the vertex in __linear__ RGBA.\n    pub color: color::Packed,\n}\n\n/// A vertex which contains 2D position & packed gradient data.\n#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)]\n#[repr(C)]\npub struct GradientVertex2D {\n    /// The vertex position in 2D space.\n    pub position: [f32; 2],\n\n    /// The packed vertex data of the gradient.\n    pub gradient: gradient::Packed,\n}\n\n/// The result of counting the attributes of a set of meshes.\n#[derive(Debug, Clone, Copy, Default)]\npub struct AttributeCount {\n    /// The total amount of solid vertices.\n    pub solid_vertices: usize,\n\n    /// The total amount of solid meshes.\n    pub solids: usize,\n\n    /// The total amount of gradient vertices.\n    pub gradient_vertices: usize,\n\n    /// The total amount of gradient meshes.\n    pub gradients: usize,\n\n    /// The total amount of indices.\n    pub indices: usize,\n}\n\n/// Returns the number of total vertices & total indices of all [`Mesh`]es.\npub fn attribute_count_of(meshes: &[Mesh]) -> AttributeCount {\n    meshes\n        .iter()\n        .fold(AttributeCount::default(), |mut count, mesh| {\n            match mesh {\n                Mesh::Solid { buffers, .. } => {\n                    count.solids += 1;\n                    count.solid_vertices += buffers.vertices.len();\n                    count.indices += buffers.indices.len();\n                }\n                Mesh::Gradient { buffers, .. } => {\n                    count.gradients += 1;\n                    count.gradient_vertices += buffers.vertices.len();\n                    count.indices += buffers.indices.len();\n                }\n            }\n\n            count\n        })\n}\n\n/// A cache of multiple meshes.\n#[derive(Debug, Clone)]\npub struct Cache {\n    id: Id,\n    batch: Arc<[Mesh]>,\n    version: usize,\n}\n\n/// The unique id of a [`Cache`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct Id(u64);\n\nimpl Cache {\n    /// Creates a new [`Cache`] for the given meshes.\n    pub fn new(meshes: Arc<[Mesh]>) -> Self {\n        static NEXT_ID: AtomicU64 = AtomicU64::new(0);\n\n        Self {\n            id: Id(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)),\n            batch: meshes,\n            version: 0,\n        }\n    }\n\n    /// Returns the [`Id`] of the [`Cache`].\n    pub fn id(&self) -> Id {\n        self.id\n    }\n\n    /// Returns the current version of the [`Cache`].\n    pub fn version(&self) -> usize {\n        self.version\n    }\n\n    /// Returns the batch of meshes in the [`Cache`].\n    pub fn batch(&self) -> &Arc<[Mesh]> {\n        &self.batch\n    }\n\n    /// Returns true if the [`Cache`] is empty.\n    pub fn is_empty(&self) -> bool {\n        self.batch.is_empty()\n    }\n\n    /// Updates the [`Cache`] with the given meshes.\n    pub fn update(&mut self, meshes: Arc<[Mesh]>) {\n        self.batch = meshes;\n        self.version += 1;\n    }\n}\n\n/// A renderer capable of drawing a [`Mesh`].\npub trait Renderer {\n    /// Draws the given [`Mesh`].\n    fn draw_mesh(&mut self, mesh: Mesh);\n\n    /// Draws the given [`Cache`].\n    fn draw_mesh_cache(&mut self, cache: Cache);\n}\n"
  },
  {
    "path": "graphics/src/shell.rs",
    "content": "//! Control the windowing runtime from a renderer.\nuse std::sync::Arc;\n\n/// A windowing shell.\n#[derive(Clone)]\npub struct Shell(Arc<dyn Notifier>);\n\nimpl Shell {\n    /// Creates a new [`Shell`].\n    pub fn new(notifier: impl Notifier) -> Self {\n        Self(Arc::new(notifier))\n    }\n\n    /// Creates a headless [`Shell`].\n    pub fn headless() -> Self {\n        struct Headless;\n\n        impl Notifier for Headless {\n            fn tick(&self) {}\n            fn request_redraw(&self) {}\n            fn invalidate_layout(&self) {}\n        }\n\n        Self::new(Headless)\n    }\n\n    /// Requests for [`Renderer::tick`](crate::core::Renderer::tick) to\n    /// be called by the [`Shell`].\n    pub fn tick(&self) {\n        self.0.tick();\n    }\n\n    /// Requests for all windows of the [`Shell`] to be redrawn.\n    pub fn request_redraw(&self) {\n        self.0.request_redraw();\n    }\n\n    /// Requests for all layouts of the [`Shell`] to be recomputed.\n    pub fn invalidate_layout(&self) {\n        self.0.invalidate_layout();\n    }\n}\n\n/// A type that can notify a shell of certain events.\npub trait Notifier: Send + Sync + 'static {\n    /// Requests for [`Renderer::tick`](crate::core::Renderer::tick) to\n    /// be called by the [`Shell`].\n    fn tick(&self);\n\n    /// Requests for all windows of the [`Shell`] to be redrawn.\n    fn request_redraw(&self);\n\n    /// Requests for all layouts of the [`Shell`] to be recomputed.\n    fn invalidate_layout(&self);\n}\n"
  },
  {
    "path": "graphics/src/text/cache.rs",
    "content": "//! Cache text.\nuse crate::core::{Font, Size};\nuse crate::text;\n\nuse rustc_hash::{FxHashMap, FxHashSet, FxHasher};\nuse std::collections::hash_map;\nuse std::hash::{Hash, Hasher};\n\n/// A store of recently used sections of text.\n#[derive(Debug, Default)]\npub struct Cache {\n    entries: FxHashMap<KeyHash, Entry>,\n    aliases: FxHashMap<KeyHash, KeyHash>,\n    recently_used: FxHashSet<KeyHash>,\n}\n\nimpl Cache {\n    /// Creates a new empty [`Cache`].\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Gets the text [`Entry`] with the given [`KeyHash`].\n    pub fn get(&self, key: &KeyHash) -> Option<&Entry> {\n        self.entries.get(key)\n    }\n\n    /// Allocates a text [`Entry`] if it is not already present in the [`Cache`].\n    pub fn allocate(\n        &mut self,\n        font_system: &mut cosmic_text::FontSystem,\n        key: Key<'_>,\n    ) -> (KeyHash, &mut Entry) {\n        let hash = key.hash(FxHasher::default());\n\n        if let Some(hash) = self.aliases.get(&hash) {\n            let _ = self.recently_used.insert(*hash);\n\n            return (*hash, self.entries.get_mut(hash).unwrap());\n        }\n\n        if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) {\n            let metrics =\n                cosmic_text::Metrics::new(key.size, key.line_height.max(f32::MIN_POSITIVE));\n            let mut buffer = cosmic_text::Buffer::new(font_system, metrics);\n\n            let max_height = key.bounds.height.max(key.line_height);\n\n            buffer.set_size(font_system, Some(key.bounds.width), Some(max_height));\n\n            buffer.set_wrap(font_system, text::to_wrap(key.wrapping));\n            buffer.set_ellipsize(font_system, text::to_ellipsize(key.ellipsis, max_height));\n\n            buffer.set_text(\n                font_system,\n                key.content,\n                &text::to_attributes(key.font),\n                text::to_shaping(key.shaping, key.content),\n                None,\n            );\n\n            let bounds = text::align(&mut buffer, font_system, key.align_x);\n\n            let _ = entry.insert(Entry {\n                buffer,\n                min_bounds: bounds,\n            });\n\n            for bounds in [\n                bounds,\n                Size {\n                    width: key.bounds.width,\n                    ..bounds\n                },\n            ] {\n                if key.bounds != bounds {\n                    let _ = self\n                        .aliases\n                        .insert(Key { bounds, ..key }.hash(FxHasher::default()), hash);\n                }\n            }\n        }\n\n        let _ = self.recently_used.insert(hash);\n\n        (hash, self.entries.get_mut(&hash).unwrap())\n    }\n\n    /// Trims the [`Cache`].\n    ///\n    /// This will clear the sections of text that have not been used since the last `trim`.\n    pub fn trim(&mut self) {\n        self.entries\n            .retain(|key, _| self.recently_used.contains(key));\n\n        self.aliases\n            .retain(|_, value| self.recently_used.contains(value));\n\n        self.recently_used.clear();\n    }\n}\n\n/// A cache key representing a section of text.\n#[derive(Debug, Clone, Copy)]\npub struct Key<'a> {\n    /// The content of the text.\n    pub content: &'a str,\n    /// The size of the text.\n    pub size: f32,\n    /// The line height of the text.\n    pub line_height: f32,\n    /// The [`Font`] of the text.\n    pub font: Font,\n    /// The bounds of the text.\n    pub bounds: Size,\n    /// The shaping strategy of the text.\n    pub shaping: text::Shaping,\n    /// The alignment of the text.\n    pub align_x: text::Alignment,\n    /// The wrapping strategy of the text.\n    pub wrapping: text::Wrapping,\n    /// The ellipsis strategy of the text.\n    pub ellipsis: text::Ellipsis,\n}\n\nimpl Key<'_> {\n    fn hash<H: Hasher>(self, mut hasher: H) -> KeyHash {\n        self.content.hash(&mut hasher);\n        self.size.to_bits().hash(&mut hasher);\n        self.line_height.to_bits().hash(&mut hasher);\n        self.font.hash(&mut hasher);\n        self.bounds.width.to_bits().hash(&mut hasher);\n        self.bounds.height.to_bits().hash(&mut hasher);\n        self.shaping.hash(&mut hasher);\n        self.align_x.hash(&mut hasher);\n\n        hasher.finish()\n    }\n}\n\n/// The hash of a [`Key`].\npub type KeyHash = u64;\n\n/// A cache entry.\n#[derive(Debug)]\npub struct Entry {\n    /// The buffer of text, ready for drawing.\n    pub buffer: cosmic_text::Buffer,\n    /// The minimum bounds of the text.\n    pub min_bounds: Size,\n}\n"
  },
  {
    "path": "graphics/src/text/editor.rs",
    "content": "//! Draw and edit text.\nuse crate::core::text::editor::{\n    self, Action, Cursor, Direction, Edit, Motion, Position, Selection,\n};\nuse crate::core::text::highlighter::{self, Highlighter};\nuse crate::core::text::{LineHeight, Wrapping};\nuse crate::core::{Font, Pixels, Point, Rectangle, Size};\nuse crate::text;\n\nuse cosmic_text::Edit as _;\n\nuse std::borrow::Cow;\nuse std::fmt;\nuse std::sync::{self, Arc, RwLock};\n\n/// A multi-line text editor.\n#[derive(Debug, PartialEq)]\npub struct Editor(Option<Arc<Internal>>);\n\nstruct Internal {\n    editor: cosmic_text::Editor<'static>,\n    selection: RwLock<Option<Selection>>,\n    font: Font,\n    bounds: Size,\n    topmost_line_changed: Option<usize>,\n    hint: bool,\n    hint_factor: f32,\n    version: text::Version,\n}\n\nimpl Editor {\n    /// Creates a new empty [`Editor`].\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Returns the buffer of the [`Editor`].\n    pub fn buffer(&self) -> &cosmic_text::Buffer {\n        buffer_from_editor(&self.internal().editor)\n    }\n\n    /// Creates a [`Weak`] reference to the [`Editor`].\n    ///\n    /// This is useful to avoid cloning the [`Editor`] when\n    /// referential guarantees are unnecessary. For instance,\n    /// when creating a rendering tree.\n    pub fn downgrade(&self) -> Weak {\n        let editor = self.internal();\n\n        Weak {\n            raw: Arc::downgrade(editor),\n            bounds: editor.bounds,\n        }\n    }\n\n    fn internal(&self) -> &Arc<Internal> {\n        self.0\n            .as_ref()\n            .expect(\"Editor should always be initialized\")\n    }\n\n    fn with_internal_mut<T>(&mut self, f: impl FnOnce(&mut Internal) -> T) -> T {\n        let editor = self.0.take().expect(\"Editor should always be initialized\");\n\n        // TODO: Handle multiple strong references somehow\n        let mut internal =\n            Arc::try_unwrap(editor).expect(\"Editor cannot have multiple strong references\");\n\n        // Clear cursor cache\n        let _ = internal\n            .selection\n            .write()\n            .expect(\"Write to cursor cache\")\n            .take();\n\n        let result = f(&mut internal);\n\n        self.0 = Some(Arc::new(internal));\n\n        result\n    }\n}\n\nimpl editor::Editor for Editor {\n    type Font = Font;\n\n    fn with_text(text: &str) -> Self {\n        let mut buffer = cosmic_text::Buffer::new_empty(cosmic_text::Metrics {\n            font_size: 1.0,\n            line_height: 1.0,\n        });\n\n        let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n        buffer.set_text(\n            font_system.raw(),\n            text,\n            &cosmic_text::Attrs::new(),\n            cosmic_text::Shaping::Advanced,\n            None,\n        );\n\n        Editor(Some(Arc::new(Internal {\n            editor: cosmic_text::Editor::new(buffer),\n            version: font_system.version(),\n            ..Default::default()\n        })))\n    }\n\n    fn is_empty(&self) -> bool {\n        let buffer = self.buffer();\n\n        buffer.lines.is_empty() || (buffer.lines.len() == 1 && buffer.lines[0].text().is_empty())\n    }\n\n    fn line(&self, index: usize) -> Option<editor::Line<'_>> {\n        self.buffer().lines.get(index).map(|line| editor::Line {\n            text: Cow::Borrowed(line.text()),\n            ending: match line.ending() {\n                cosmic_text::LineEnding::Lf => editor::LineEnding::Lf,\n                cosmic_text::LineEnding::CrLf => editor::LineEnding::CrLf,\n                cosmic_text::LineEnding::Cr => editor::LineEnding::Cr,\n                cosmic_text::LineEnding::LfCr => editor::LineEnding::LfCr,\n                cosmic_text::LineEnding::None => editor::LineEnding::None,\n            },\n        })\n    }\n\n    fn line_count(&self) -> usize {\n        self.buffer().lines.len()\n    }\n\n    fn copy(&self) -> Option<String> {\n        self.internal().editor.copy_selection()\n    }\n\n    fn selection(&self) -> editor::Selection {\n        let internal = self.internal();\n\n        if let Ok(Some(cursor)) = internal.selection.read().as_deref() {\n            return cursor.clone();\n        }\n\n        let cursor = internal.editor.cursor();\n        let buffer = buffer_from_editor(&internal.editor);\n\n        let cursor = match internal.editor.selection_bounds() {\n            Some((start, end)) => {\n                let line_height = buffer.metrics().line_height;\n                let selected_lines = end.line - start.line + 1;\n\n                let visual_lines_offset = visual_lines_offset(start.line, buffer);\n\n                let regions = buffer\n                    .lines\n                    .iter()\n                    .skip(start.line)\n                    .take(selected_lines)\n                    .enumerate()\n                    .flat_map(|(i, line)| {\n                        highlight_line(\n                            line,\n                            if i == 0 { start.index } else { 0 },\n                            if i == selected_lines - 1 {\n                                end.index\n                            } else {\n                                line.text().len()\n                            },\n                        )\n                    })\n                    .enumerate()\n                    .filter_map(|(visual_line, (x, width))| {\n                        if width > 0.0 {\n                            Some(\n                                Rectangle {\n                                    x,\n                                    width,\n                                    y: (visual_line as i32 + visual_lines_offset) as f32\n                                        * line_height\n                                        - buffer.scroll().vertical,\n                                    height: line_height,\n                                } * (1.0 / internal.hint_factor),\n                            )\n                        } else {\n                            None\n                        }\n                    })\n                    .collect();\n\n                Selection::Range(regions)\n            }\n            _ => {\n                let line_height = buffer.metrics().line_height;\n\n                let visual_lines_offset = visual_lines_offset(cursor.line, buffer);\n\n                let line = buffer\n                    .lines\n                    .get(cursor.line)\n                    .expect(\"Cursor line should be present\");\n\n                let layout = line.layout_opt().expect(\"Line layout should be cached\");\n\n                let mut lines = layout.iter().enumerate();\n\n                let (visual_line, offset) = lines\n                    .find_map(|(i, line)| {\n                        let start = line.glyphs.first().map(|glyph| glyph.start).unwrap_or(0);\n                        let end = line.glyphs.last().map(|glyph| glyph.end).unwrap_or(0);\n\n                        let is_cursor_before_start = start > cursor.index;\n\n                        let is_cursor_before_end = match cursor.affinity {\n                            cosmic_text::Affinity::Before => cursor.index <= end,\n                            cosmic_text::Affinity::After => cursor.index < end,\n                        };\n\n                        if is_cursor_before_start {\n                            // Sometimes, the glyph we are looking for is right\n                            // between lines. This can happen when a line wraps\n                            // on a space.\n                            // In that case, we can assume the cursor is at the\n                            // end of the previous line.\n                            // i is guaranteed to be > 0 because `start` is always\n                            // 0 for the first line, so there is no way for the\n                            // cursor to be before it.\n                            Some((i - 1, layout[i - 1].w))\n                        } else if is_cursor_before_end {\n                            let offset = line\n                                .glyphs\n                                .iter()\n                                .take_while(|glyph| cursor.index > glyph.start)\n                                .map(|glyph| glyph.w)\n                                .sum();\n\n                            Some((i, offset))\n                        } else {\n                            None\n                        }\n                    })\n                    .unwrap_or((\n                        layout.len().saturating_sub(1),\n                        layout.last().map(|line| line.w).unwrap_or(0.0),\n                    ));\n\n                Selection::Caret(Point::new(\n                    offset / internal.hint_factor,\n                    ((visual_lines_offset + visual_line as i32) as f32 * line_height\n                        - buffer.scroll().vertical)\n                        / internal.hint_factor,\n                ))\n            }\n        };\n\n        *internal.selection.write().expect(\"Write to cursor cache\") = Some(cursor.clone());\n\n        cursor\n    }\n\n    fn cursor(&self) -> Cursor {\n        let editor = &self.internal().editor;\n\n        let position = {\n            let cursor = editor.cursor();\n\n            Position {\n                line: cursor.line,\n                column: cursor.index,\n            }\n        };\n\n        let selection = match editor.selection() {\n            cosmic_text::Selection::None => None,\n            cosmic_text::Selection::Normal(cursor)\n            | cosmic_text::Selection::Line(cursor)\n            | cosmic_text::Selection::Word(cursor) => Some(Position {\n                line: cursor.line,\n                column: cursor.index,\n            }),\n        };\n\n        Cursor {\n            position,\n            selection,\n        }\n    }\n\n    fn perform(&mut self, action: Action) {\n        let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n        self.with_internal_mut(|internal| {\n            let editor = &mut internal.editor;\n\n            match action {\n                // Motion events\n                Action::Move(motion) => {\n                    if let Some((start, end)) = editor.selection_bounds() {\n                        editor.set_selection(cosmic_text::Selection::None);\n\n                        match motion {\n                            // These motions are performed as-is even when a selection\n                            // is present\n                            Motion::Home\n                            | Motion::End\n                            | Motion::DocumentStart\n                            | Motion::DocumentEnd => {\n                                editor.action(\n                                    font_system.raw(),\n                                    cosmic_text::Action::Motion(to_motion(motion)),\n                                );\n                            }\n                            // Other motions simply move the cursor to one end of the selection\n                            _ => editor.set_cursor(match motion.direction() {\n                                Direction::Left => start,\n                                Direction::Right => end,\n                            }),\n                        }\n                    } else {\n                        editor.action(\n                            font_system.raw(),\n                            cosmic_text::Action::Motion(to_motion(motion)),\n                        );\n                    }\n                }\n\n                // Selection events\n                Action::Select(motion) => {\n                    let cursor = editor.cursor();\n\n                    if editor.selection_bounds().is_none() {\n                        editor.set_selection(cosmic_text::Selection::Normal(cursor));\n                    }\n\n                    editor.action(\n                        font_system.raw(),\n                        cosmic_text::Action::Motion(to_motion(motion)),\n                    );\n\n                    // Deselect if selection matches cursor position\n                    if let Some((start, end)) = editor.selection_bounds()\n                        && start.line == end.line\n                        && start.index == end.index\n                    {\n                        editor.set_selection(cosmic_text::Selection::None);\n                    }\n                }\n                Action::SelectWord => {\n                    let cursor = editor.cursor();\n\n                    editor.set_selection(cosmic_text::Selection::Word(cursor));\n                }\n                Action::SelectLine => {\n                    let cursor = editor.cursor();\n\n                    editor.set_selection(cosmic_text::Selection::Line(cursor));\n                }\n                Action::SelectAll => {\n                    let buffer = buffer_from_editor(editor);\n\n                    if buffer.lines.len() > 1\n                        || buffer\n                            .lines\n                            .first()\n                            .is_some_and(|line| !line.text().is_empty())\n                    {\n                        let cursor = editor.cursor();\n\n                        editor.set_selection(cosmic_text::Selection::Normal(cosmic_text::Cursor {\n                            line: 0,\n                            index: 0,\n                            ..cursor\n                        }));\n\n                        editor.action(\n                            font_system.raw(),\n                            cosmic_text::Action::Motion(cosmic_text::Motion::BufferEnd),\n                        );\n                    }\n                }\n\n                // Editing events\n                Action::Edit(edit) => {\n                    let topmost_line_before_edit = editor\n                        .selection_bounds()\n                        .map(|(start, _)| start)\n                        .unwrap_or_else(|| editor.cursor())\n                        .line;\n\n                    match edit {\n                        Edit::Insert(c) => {\n                            editor.action(font_system.raw(), cosmic_text::Action::Insert(c));\n                        }\n                        Edit::Paste(text) => {\n                            editor.insert_string(&text, None);\n                        }\n                        Edit::Indent => {\n                            editor.action(font_system.raw(), cosmic_text::Action::Indent);\n                        }\n                        Edit::Unindent => {\n                            editor.action(font_system.raw(), cosmic_text::Action::Unindent);\n                        }\n                        Edit::Enter => {\n                            editor.action(font_system.raw(), cosmic_text::Action::Enter);\n                        }\n                        Edit::Backspace => {\n                            editor.action(font_system.raw(), cosmic_text::Action::Backspace);\n                        }\n                        Edit::Delete => {\n                            editor.action(font_system.raw(), cosmic_text::Action::Delete);\n                        }\n                    }\n\n                    let cursor = editor.cursor();\n                    let selection_start = editor\n                        .selection_bounds()\n                        .map(|(start, _)| start)\n                        .unwrap_or(cursor);\n\n                    internal.topmost_line_changed =\n                        Some(selection_start.line.min(topmost_line_before_edit));\n                }\n\n                // Mouse events\n                Action::Click(position) => {\n                    editor.action(\n                        font_system.raw(),\n                        cosmic_text::Action::Click {\n                            x: (position.x * internal.hint_factor) as i32,\n                            y: (position.y * internal.hint_factor) as i32,\n                        },\n                    );\n                }\n                Action::Drag(position) => {\n                    editor.action(\n                        font_system.raw(),\n                        cosmic_text::Action::Drag {\n                            x: (position.x * internal.hint_factor) as i32,\n                            y: (position.y * internal.hint_factor) as i32,\n                        },\n                    );\n\n                    // Deselect if selection matches cursor position\n                    if let Some((start, end)) = editor.selection_bounds()\n                        && start.line == end.line\n                        && start.index == end.index\n                    {\n                        editor.set_selection(cosmic_text::Selection::None);\n                    }\n                }\n                Action::Scroll { lines } => {\n                    editor.action(\n                        font_system.raw(),\n                        cosmic_text::Action::Scroll {\n                            pixels: lines as f32 * buffer_from_editor(editor).metrics().line_height,\n                        },\n                    );\n                }\n            }\n        });\n    }\n\n    fn move_to(&mut self, cursor: Cursor) {\n        self.with_internal_mut(|internal| {\n            // TODO: Expose `Affinity`\n            internal.editor.set_cursor(cosmic_text::Cursor {\n                line: cursor.position.line,\n                index: cursor.position.column,\n                affinity: cosmic_text::Affinity::Before,\n            });\n\n            if let Some(selection) = cursor.selection {\n                internal\n                    .editor\n                    .set_selection(cosmic_text::Selection::Normal(cosmic_text::Cursor {\n                        line: selection.line,\n                        index: selection.column,\n                        affinity: cosmic_text::Affinity::Before,\n                    }));\n            }\n        });\n    }\n\n    fn bounds(&self) -> Size {\n        self.internal().bounds\n    }\n\n    fn min_bounds(&self) -> Size {\n        let internal = self.internal();\n\n        let (bounds, _has_rtl) = text::measure(buffer_from_editor(&internal.editor));\n\n        bounds * (1.0 / internal.hint_factor)\n    }\n\n    fn hint_factor(&self) -> Option<f32> {\n        let internal = self.internal();\n\n        internal.hint.then_some(internal.hint_factor)\n    }\n\n    fn update(\n        &mut self,\n        new_bounds: Size,\n        new_font: Font,\n        new_size: Pixels,\n        new_line_height: LineHeight,\n        new_wrapping: Wrapping,\n        new_hint_factor: Option<f32>,\n        new_highlighter: &mut impl Highlighter,\n    ) {\n        self.with_internal_mut(|internal| {\n            let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n            let buffer = buffer_mut_from_editor(&mut internal.editor);\n\n            if font_system.version() != internal.version {\n                log::trace!(\"Updating `FontSystem` of `Editor`...\");\n\n                for line in buffer.lines.iter_mut() {\n                    line.reset();\n                }\n\n                internal.version = font_system.version();\n                internal.topmost_line_changed = Some(0);\n            }\n\n            if new_font != internal.font {\n                log::trace!(\"Updating font of `Editor`...\");\n\n                for line in buffer.lines.iter_mut() {\n                    let _ = line.set_attrs_list(cosmic_text::AttrsList::new(&text::to_attributes(\n                        new_font,\n                    )));\n                }\n\n                internal.font = new_font;\n                internal.topmost_line_changed = Some(0);\n            }\n\n            let metrics = buffer.metrics();\n            let new_line_height = new_line_height.to_absolute(new_size);\n            let mut hinting_changed = false;\n\n            let new_hint_factor = text::hint_factor(new_size, new_hint_factor);\n\n            if new_hint_factor != internal.hint.then_some(internal.hint_factor) {\n                internal.hint = new_hint_factor.is_some();\n                internal.hint_factor = new_hint_factor.unwrap_or(1.0);\n\n                buffer.set_hinting(\n                    font_system.raw(),\n                    if internal.hint {\n                        cosmic_text::Hinting::Enabled\n                    } else {\n                        cosmic_text::Hinting::Disabled\n                    },\n                );\n\n                hinting_changed = true;\n            }\n\n            if new_size.0 != metrics.font_size\n                || new_line_height.0 != metrics.line_height\n                || hinting_changed\n            {\n                log::trace!(\"Updating `Metrics` of `Editor`...\");\n\n                buffer.set_metrics(\n                    font_system.raw(),\n                    cosmic_text::Metrics::new(\n                        new_size.0 * internal.hint_factor,\n                        new_line_height.0 * internal.hint_factor,\n                    ),\n                );\n            }\n\n            let new_wrap = text::to_wrap(new_wrapping);\n\n            if new_wrap != buffer.wrap() {\n                log::trace!(\"Updating `Wrap` strategy of `Editor`...\");\n\n                buffer.set_wrap(font_system.raw(), new_wrap);\n            }\n\n            if new_bounds != internal.bounds || hinting_changed {\n                log::trace!(\"Updating size of `Editor`...\");\n\n                buffer.set_size(\n                    font_system.raw(),\n                    Some(new_bounds.width * internal.hint_factor),\n                    Some(new_bounds.height * internal.hint_factor),\n                );\n\n                internal.bounds = new_bounds;\n            }\n\n            if let Some(topmost_line_changed) = internal.topmost_line_changed.take() {\n                log::trace!(\n                    \"Notifying highlighter of line \\\n                    change: {topmost_line_changed}\"\n                );\n\n                new_highlighter.change_line(topmost_line_changed);\n            }\n\n            internal.editor.shape_as_needed(font_system.raw(), false);\n        });\n    }\n\n    fn highlight<H: Highlighter>(\n        &mut self,\n        font: Self::Font,\n        highlighter: &mut H,\n        format_highlight: impl Fn(&H::Highlight) -> highlighter::Format<Self::Font>,\n    ) {\n        let internal = self.internal();\n        let buffer = buffer_from_editor(&internal.editor);\n\n        let scroll = buffer.scroll();\n        let mut window = (internal.bounds.height * internal.hint_factor\n            / buffer.metrics().line_height)\n            .ceil() as i32;\n\n        let last_visible_line = buffer.lines[scroll.line..]\n            .iter()\n            .enumerate()\n            .find_map(|(i, line)| {\n                let visible_lines = line\n                    .layout_opt()\n                    .as_ref()\n                    .expect(\"Line layout should be cached\")\n                    .len() as i32;\n\n                if window > visible_lines {\n                    window -= visible_lines;\n                    None\n                } else {\n                    Some(scroll.line + i)\n                }\n            })\n            .unwrap_or(buffer.lines.len().saturating_sub(1));\n\n        let current_line = highlighter.current_line();\n\n        if current_line > last_visible_line {\n            return;\n        }\n\n        let editor = self.0.take().expect(\"Editor should always be initialized\");\n\n        let mut internal =\n            Arc::try_unwrap(editor).expect(\"Editor cannot have multiple strong references\");\n\n        let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n        let attributes = text::to_attributes(font);\n\n        for line in &mut buffer_mut_from_editor(&mut internal.editor).lines\n            [current_line..=last_visible_line]\n        {\n            let mut list = cosmic_text::AttrsList::new(&attributes);\n\n            for (range, highlight) in highlighter.highlight_line(line.text()) {\n                let format = format_highlight(&highlight);\n\n                if format.color.is_some() || format.font.is_some() {\n                    list.add_span(\n                        range,\n                        &cosmic_text::Attrs {\n                            color_opt: format.color.map(text::to_color),\n                            ..if let Some(font) = format.font {\n                                text::to_attributes(font)\n                            } else {\n                                attributes.clone()\n                            }\n                        },\n                    );\n                }\n            }\n\n            let _ = line.set_attrs_list(list);\n        }\n\n        internal.editor.shape_as_needed(font_system.raw(), false);\n\n        self.0 = Some(Arc::new(internal));\n    }\n}\n\nimpl Default for Editor {\n    fn default() -> Self {\n        Self(Some(Arc::new(Internal::default())))\n    }\n}\n\nimpl PartialEq for Internal {\n    fn eq(&self, other: &Self) -> bool {\n        self.font == other.font\n            && self.bounds == other.bounds\n            && buffer_from_editor(&self.editor).metrics()\n                == buffer_from_editor(&other.editor).metrics()\n    }\n}\n\nimpl Default for Internal {\n    fn default() -> Self {\n        Self {\n            editor: cosmic_text::Editor::new(cosmic_text::Buffer::new_empty(\n                cosmic_text::Metrics {\n                    font_size: 1.0,\n                    line_height: 1.0,\n                },\n            )),\n            selection: RwLock::new(None),\n            font: Font::default(),\n            bounds: Size::ZERO,\n            topmost_line_changed: None,\n            hint: false,\n            hint_factor: 1.0,\n            version: text::Version::default(),\n        }\n    }\n}\n\nimpl fmt::Debug for Internal {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Internal\")\n            .field(\"font\", &self.font)\n            .field(\"bounds\", &self.bounds)\n            .finish()\n    }\n}\n\n/// A weak reference to an [`Editor`].\n#[derive(Debug, Clone)]\npub struct Weak {\n    raw: sync::Weak<Internal>,\n    /// The bounds of the [`Editor`].\n    pub bounds: Size,\n}\n\nimpl Weak {\n    /// Tries to update the reference into an [`Editor`].\n    pub fn upgrade(&self) -> Option<Editor> {\n        self.raw.upgrade().map(Some).map(Editor)\n    }\n}\n\nimpl PartialEq for Weak {\n    fn eq(&self, other: &Self) -> bool {\n        match (self.raw.upgrade(), other.raw.upgrade()) {\n            (Some(p1), Some(p2)) => p1 == p2,\n            _ => false,\n        }\n    }\n}\n\nfn highlight_line(\n    line: &cosmic_text::BufferLine,\n    from: usize,\n    to: usize,\n) -> impl Iterator<Item = (f32, f32)> + '_ {\n    let layout = line.layout_opt().map(Vec::as_slice).unwrap_or_default();\n\n    layout.iter().map(move |visual_line| {\n        let start = visual_line\n            .glyphs\n            .first()\n            .map(|glyph| glyph.start)\n            .unwrap_or(0);\n        let end = visual_line\n            .glyphs\n            .last()\n            .map(|glyph| glyph.end)\n            .unwrap_or(0);\n\n        let range = start.max(from)..end.min(to);\n\n        if range.is_empty() {\n            (0.0, 0.0)\n        } else if range.start == start && range.end == end {\n            (0.0, visual_line.w)\n        } else {\n            let first_glyph = visual_line\n                .glyphs\n                .iter()\n                .position(|glyph| range.start <= glyph.start)\n                .unwrap_or(0);\n\n            let mut glyphs = visual_line.glyphs.iter();\n\n            let x = glyphs.by_ref().take(first_glyph).map(|glyph| glyph.w).sum();\n\n            let width: f32 = glyphs\n                .take_while(|glyph| range.end > glyph.start)\n                .map(|glyph| glyph.w)\n                .sum();\n\n            (x, width)\n        }\n    })\n}\n\nfn visual_lines_offset(line: usize, buffer: &cosmic_text::Buffer) -> i32 {\n    let scroll = buffer.scroll();\n\n    let start = scroll.line.min(line);\n    let end = scroll.line.max(line);\n\n    let visual_lines_offset: usize = buffer.lines[start..]\n        .iter()\n        .take(end - start)\n        .map(|line| line.layout_opt().map(Vec::len).unwrap_or_default())\n        .sum();\n\n    visual_lines_offset as i32 * if scroll.line < line { 1 } else { -1 }\n}\n\nfn to_motion(motion: Motion) -> cosmic_text::Motion {\n    match motion {\n        Motion::Left => cosmic_text::Motion::Left,\n        Motion::Right => cosmic_text::Motion::Right,\n        Motion::Up => cosmic_text::Motion::Up,\n        Motion::Down => cosmic_text::Motion::Down,\n        Motion::WordLeft => cosmic_text::Motion::LeftWord,\n        Motion::WordRight => cosmic_text::Motion::RightWord,\n        Motion::Home => cosmic_text::Motion::Home,\n        Motion::End => cosmic_text::Motion::End,\n        Motion::PageUp => cosmic_text::Motion::PageUp,\n        Motion::PageDown => cosmic_text::Motion::PageDown,\n        Motion::DocumentStart => cosmic_text::Motion::BufferStart,\n        Motion::DocumentEnd => cosmic_text::Motion::BufferEnd,\n    }\n}\n\nfn buffer_from_editor<'a, 'b>(editor: &'a impl cosmic_text::Edit<'b>) -> &'a cosmic_text::Buffer\nwhere\n    'b: 'a,\n{\n    match editor.buffer_ref() {\n        cosmic_text::BufferRef::Owned(buffer) => buffer,\n        cosmic_text::BufferRef::Borrowed(buffer) => buffer,\n        cosmic_text::BufferRef::Arc(buffer) => buffer,\n    }\n}\n\nfn buffer_mut_from_editor<'a, 'b>(\n    editor: &'a mut impl cosmic_text::Edit<'b>,\n) -> &'a mut cosmic_text::Buffer\nwhere\n    'b: 'a,\n{\n    match editor.buffer_ref_mut() {\n        cosmic_text::BufferRef::Owned(buffer) => buffer,\n        cosmic_text::BufferRef::Borrowed(buffer) => buffer,\n        cosmic_text::BufferRef::Arc(_buffer) => unreachable!(),\n    }\n}\n"
  },
  {
    "path": "graphics/src/text/paragraph.rs",
    "content": "//! Draw paragraphs.\nuse crate::core;\nuse crate::core::alignment;\nuse crate::core::text::{Alignment, Ellipsis, Hit, LineHeight, Shaping, Span, Text, Wrapping};\nuse crate::core::{Font, Pixels, Point, Rectangle, Size};\nuse crate::text;\n\nuse std::fmt;\nuse std::sync::{self, Arc};\n\n/// A bunch of text.\n#[derive(Clone, PartialEq)]\npub struct Paragraph(Arc<Internal>);\n\n#[derive(Clone)]\nstruct Internal {\n    buffer: cosmic_text::Buffer,\n    font: Font,\n    shaping: Shaping,\n    wrapping: Wrapping,\n    ellipsis: Ellipsis,\n    align_x: Alignment,\n    align_y: alignment::Vertical,\n    bounds: Size,\n    min_bounds: Size,\n    version: text::Version,\n    hint: bool,\n    hint_factor: f32,\n}\n\nimpl Paragraph {\n    /// Creates a new empty [`Paragraph`].\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Returns the buffer of the [`Paragraph`].\n    pub fn buffer(&self) -> &cosmic_text::Buffer {\n        &self.internal().buffer\n    }\n\n    /// Creates a [`Weak`] reference to the [`Paragraph`].\n    ///\n    /// This is useful to avoid cloning the [`Paragraph`] when\n    /// referential guarantees are unnecessary. For instance,\n    /// when creating a rendering tree.\n    pub fn downgrade(&self) -> Weak {\n        let paragraph = self.internal();\n\n        Weak {\n            raw: Arc::downgrade(paragraph),\n            min_bounds: paragraph.min_bounds,\n            align_x: paragraph.align_x,\n            align_y: paragraph.align_y,\n        }\n    }\n\n    fn internal(&self) -> &Arc<Internal> {\n        &self.0\n    }\n}\n\nimpl core::text::Paragraph for Paragraph {\n    type Font = Font;\n\n    fn with_text(text: Text<&str>) -> Self {\n        log::trace!(\"Allocating plain paragraph: {}\", text.content);\n\n        let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n        let (hint, hint_factor) = match text::hint_factor(text.size, text.hint_factor) {\n            Some(hint_factor) => (true, hint_factor),\n            _ => (false, 1.0),\n        };\n\n        let mut buffer = cosmic_text::Buffer::new(\n            font_system.raw(),\n            cosmic_text::Metrics::new(\n                f32::from(text.size) * hint_factor,\n                f32::from(text.line_height.to_absolute(text.size)) * hint_factor,\n            ),\n        );\n\n        if hint {\n            buffer.set_hinting(font_system.raw(), cosmic_text::Hinting::Enabled);\n        }\n\n        buffer.set_size(\n            font_system.raw(),\n            Some(text.bounds.width * hint_factor),\n            Some(text.bounds.height * hint_factor),\n        );\n\n        buffer.set_wrap(font_system.raw(), text::to_wrap(text.wrapping));\n        buffer.set_ellipsize(\n            font_system.raw(),\n            text::to_ellipsize(text.ellipsis, text.bounds.height * hint_factor),\n        );\n\n        buffer.set_text(\n            font_system.raw(),\n            text.content,\n            &text::to_attributes(text.font),\n            text::to_shaping(text.shaping, text.content),\n            None,\n        );\n\n        let min_bounds = text::align(&mut buffer, font_system.raw(), text.align_x) / hint_factor;\n\n        Self(Arc::new(Internal {\n            buffer,\n            hint,\n            hint_factor,\n            font: text.font,\n            align_x: text.align_x,\n            align_y: text.align_y,\n            shaping: text.shaping,\n            wrapping: text.wrapping,\n            ellipsis: text.ellipsis,\n            bounds: text.bounds,\n            min_bounds,\n            version: font_system.version(),\n        }))\n    }\n\n    fn with_spans<Link>(text: Text<&[Span<'_, Link>]>) -> Self {\n        log::trace!(\"Allocating rich paragraph: {} spans\", text.content.len());\n\n        let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n        let (hint, hint_factor) = match text::hint_factor(text.size, text.hint_factor) {\n            Some(hint_factor) => (true, hint_factor),\n            _ => (false, 1.0),\n        };\n\n        let mut buffer = cosmic_text::Buffer::new(\n            font_system.raw(),\n            cosmic_text::Metrics::new(\n                f32::from(text.size) * hint_factor,\n                f32::from(text.line_height.to_absolute(text.size)) * hint_factor,\n            ),\n        );\n\n        if hint {\n            buffer.set_hinting(font_system.raw(), cosmic_text::Hinting::Enabled);\n        }\n\n        buffer.set_size(\n            font_system.raw(),\n            Some(text.bounds.width * hint_factor),\n            Some(text.bounds.height * hint_factor),\n        );\n\n        buffer.set_wrap(font_system.raw(), text::to_wrap(text.wrapping));\n\n        buffer.set_rich_text(\n            font_system.raw(),\n            text.content.iter().enumerate().map(|(i, span)| {\n                let attrs = text::to_attributes(span.font.unwrap_or(text.font));\n\n                let attrs = match (span.size, span.line_height) {\n                    (None, None) => attrs,\n                    _ => {\n                        let size = span.size.unwrap_or(text.size);\n\n                        attrs.metrics(cosmic_text::Metrics::new(\n                            f32::from(size) * hint_factor,\n                            f32::from(\n                                span.line_height\n                                    .unwrap_or(text.line_height)\n                                    .to_absolute(size),\n                            ) * hint_factor,\n                        ))\n                    }\n                };\n\n                let attrs = if let Some(color) = span.color {\n                    attrs.color(text::to_color(color))\n                } else {\n                    attrs\n                };\n\n                (span.text.as_ref(), attrs.metadata(i))\n            }),\n            &text::to_attributes(text.font),\n            cosmic_text::Shaping::Advanced,\n            None,\n        );\n\n        let min_bounds = text::align(&mut buffer, font_system.raw(), text.align_x) / hint_factor;\n\n        Self(Arc::new(Internal {\n            buffer,\n            hint,\n            hint_factor,\n            font: text.font,\n            align_x: text.align_x,\n            align_y: text.align_y,\n            shaping: text.shaping,\n            wrapping: text.wrapping,\n            ellipsis: text.ellipsis,\n            bounds: text.bounds,\n            min_bounds,\n            version: font_system.version(),\n        }))\n    }\n\n    fn resize(&mut self, new_bounds: Size) {\n        let paragraph = Arc::make_mut(&mut self.0);\n\n        let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n        paragraph.buffer.set_size(\n            font_system.raw(),\n            Some(new_bounds.width * paragraph.hint_factor),\n            Some(new_bounds.height * paragraph.hint_factor),\n        );\n\n        let min_bounds = text::align(&mut paragraph.buffer, font_system.raw(), paragraph.align_x)\n            / paragraph.hint_factor;\n\n        paragraph.bounds = new_bounds;\n        paragraph.min_bounds = min_bounds;\n    }\n\n    fn compare(&self, text: Text<()>) -> core::text::Difference {\n        let font_system = text::font_system().read().expect(\"Read font system\");\n        let paragraph = self.internal();\n        let metrics = paragraph.buffer.metrics();\n\n        if paragraph.version != font_system.version\n            || metrics.font_size != text.size.0 * paragraph.hint_factor\n            || metrics.line_height\n                != text.line_height.to_absolute(text.size).0 * paragraph.hint_factor\n            || paragraph.font != text.font\n            || paragraph.shaping != text.shaping\n            || paragraph.wrapping != text.wrapping\n            || paragraph.ellipsis != text.ellipsis\n            || paragraph.align_x != text.align_x\n            || paragraph.align_y != text.align_y\n            || paragraph.hint.then_some(paragraph.hint_factor)\n                != text::hint_factor(text.size, text.hint_factor)\n        {\n            core::text::Difference::Shape\n        } else if paragraph.bounds != text.bounds {\n            core::text::Difference::Bounds\n        } else {\n            core::text::Difference::None\n        }\n    }\n\n    fn hint_factor(&self) -> Option<f32> {\n        self.0.hint.then_some(self.0.hint_factor)\n    }\n\n    fn size(&self) -> Pixels {\n        Pixels(self.0.buffer.metrics().font_size / self.0.hint_factor)\n    }\n\n    fn font(&self) -> Font {\n        self.0.font\n    }\n\n    fn line_height(&self) -> LineHeight {\n        LineHeight::Absolute(Pixels(\n            self.0.buffer.metrics().line_height / self.0.hint_factor,\n        ))\n    }\n\n    fn align_x(&self) -> Alignment {\n        self.internal().align_x\n    }\n\n    fn align_y(&self) -> alignment::Vertical {\n        self.internal().align_y\n    }\n\n    fn wrapping(&self) -> Wrapping {\n        self.0.wrapping\n    }\n\n    fn ellipsis(&self) -> Ellipsis {\n        self.0.ellipsis\n    }\n\n    fn shaping(&self) -> Shaping {\n        self.0.shaping\n    }\n\n    fn bounds(&self) -> Size {\n        self.0.bounds\n    }\n\n    fn min_bounds(&self) -> Size {\n        self.internal().min_bounds\n    }\n\n    fn hit_test(&self, point: Point) -> Option<Hit> {\n        let cursor = self\n            .internal()\n            .buffer\n            .hit(point.x * self.0.hint_factor, point.y * self.0.hint_factor)?;\n\n        Some(Hit::CharOffset(cursor.index))\n    }\n\n    fn hit_span(&self, point: Point) -> Option<usize> {\n        let internal = self.internal();\n\n        let cursor = internal\n            .buffer\n            .hit(point.x * self.0.hint_factor, point.y * self.0.hint_factor)?;\n        let line = internal.buffer.lines.get(cursor.line)?;\n\n        if cursor.index >= line.text().len() {\n            return None;\n        }\n\n        let index = match cursor.affinity {\n            cosmic_text::Affinity::Before => cursor.index.saturating_sub(1),\n            cosmic_text::Affinity::After => cursor.index,\n        };\n\n        let mut hit = None;\n        let glyphs = line\n            .layout_opt()\n            .as_ref()?\n            .iter()\n            .flat_map(|line| line.glyphs.iter());\n\n        for glyph in glyphs {\n            if glyph.start <= index && index < glyph.end {\n                hit = Some(glyph);\n                break;\n            }\n        }\n\n        Some(hit?.metadata)\n    }\n\n    fn span_bounds(&self, index: usize) -> Vec<Rectangle> {\n        let internal = self.internal();\n\n        let mut bounds = Vec::new();\n        let mut current_bounds = None;\n\n        let glyphs = internal\n            .buffer\n            .layout_runs()\n            .flat_map(|run| {\n                let line_top = run.line_top;\n                let line_height = run.line_height;\n\n                run.glyphs\n                    .iter()\n                    .map(move |glyph| (line_top, line_height, glyph))\n            })\n            .skip_while(|(_, _, glyph)| glyph.metadata != index)\n            .take_while(|(_, _, glyph)| glyph.metadata == index);\n\n        for (line_top, line_height, glyph) in glyphs {\n            let y = line_top + glyph.y;\n\n            let new_bounds = || {\n                Rectangle::new(\n                    Point::new(glyph.x, y),\n                    Size::new(glyph.w, glyph.line_height_opt.unwrap_or(line_height)),\n                ) * (1.0 / self.0.hint_factor)\n            };\n\n            match current_bounds.as_mut() {\n                None => {\n                    current_bounds = Some(new_bounds());\n                }\n                Some(current_bounds) if y != current_bounds.y => {\n                    bounds.push(*current_bounds);\n                    *current_bounds = new_bounds();\n                }\n                Some(current_bounds) => {\n                    current_bounds.width += glyph.w / self.0.hint_factor;\n                }\n            }\n        }\n\n        bounds.extend(current_bounds);\n        bounds\n    }\n\n    fn grapheme_position(&self, line: usize, index: usize) -> Option<Point> {\n        use unicode_segmentation::UnicodeSegmentation;\n\n        let run = self.internal().buffer.layout_runs().nth(line)?;\n\n        // index represents a grapheme, not a glyph\n        // Let's find the first glyph for the given grapheme cluster\n        let mut last_start = None;\n        let mut last_grapheme_count = 0;\n        let mut graphemes_seen = 0;\n\n        let glyph = run\n            .glyphs\n            .iter()\n            .find(|glyph| {\n                if Some(glyph.start) != last_start {\n                    last_grapheme_count = run.text[glyph.start..glyph.end].graphemes(false).count();\n                    last_start = Some(glyph.start);\n                    graphemes_seen += last_grapheme_count;\n                }\n\n                graphemes_seen >= index\n            })\n            .or_else(|| run.glyphs.last())?;\n\n        let advance = if index == 0 {\n            0.0\n        } else {\n            glyph.w\n                * (1.0\n                    - graphemes_seen.saturating_sub(index) as f32\n                        / last_grapheme_count.max(1) as f32)\n        };\n\n        Some(Point::new(\n            (glyph.x + glyph.x_offset * glyph.font_size + advance) / self.0.hint_factor,\n            (glyph.y - glyph.y_offset * glyph.font_size) / self.0.hint_factor,\n        ))\n    }\n}\n\nimpl Default for Paragraph {\n    fn default() -> Self {\n        Self(Arc::new(Internal::default()))\n    }\n}\n\nimpl fmt::Debug for Paragraph {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let paragraph = self.internal();\n\n        f.debug_struct(\"Paragraph\")\n            .field(\"font\", &paragraph.font)\n            .field(\"shaping\", &paragraph.shaping)\n            .field(\"horizontal_alignment\", &paragraph.align_x)\n            .field(\"vertical_alignment\", &paragraph.align_y)\n            .field(\"bounds\", &paragraph.bounds)\n            .field(\"min_bounds\", &paragraph.min_bounds)\n            .finish()\n    }\n}\n\nimpl PartialEq for Internal {\n    fn eq(&self, other: &Self) -> bool {\n        self.font == other.font\n            && self.shaping == other.shaping\n            && self.align_x == other.align_x\n            && self.align_y == other.align_y\n            && self.bounds == other.bounds\n            && self.min_bounds == other.min_bounds\n            && self.buffer.metrics() == other.buffer.metrics()\n    }\n}\n\nimpl Default for Internal {\n    fn default() -> Self {\n        Self {\n            buffer: cosmic_text::Buffer::new_empty(cosmic_text::Metrics {\n                font_size: 1.0,\n                line_height: 1.0,\n            }),\n            font: Font::default(),\n            shaping: Shaping::default(),\n            wrapping: Wrapping::default(),\n            ellipsis: Ellipsis::default(),\n            align_x: Alignment::Default,\n            align_y: alignment::Vertical::Top,\n            bounds: Size::ZERO,\n            min_bounds: Size::ZERO,\n            version: text::Version::default(),\n            hint: false,\n            hint_factor: 1.0,\n        }\n    }\n}\n\n/// A weak reference to a [`Paragraph`].\n#[derive(Debug, Clone)]\npub struct Weak {\n    raw: sync::Weak<Internal>,\n    /// The minimum bounds of the [`Paragraph`].\n    pub min_bounds: Size,\n    /// The horizontal alignment of the [`Paragraph`].\n    pub align_x: Alignment,\n    /// The vertical alignment of the [`Paragraph`].\n    pub align_y: alignment::Vertical,\n}\n\nimpl Weak {\n    /// Tries to update the reference into a [`Paragraph`].\n    pub fn upgrade(&self) -> Option<Paragraph> {\n        self.raw.upgrade().map(Paragraph)\n    }\n}\n\nimpl PartialEq for Weak {\n    fn eq(&self, other: &Self) -> bool {\n        match (self.raw.upgrade(), other.raw.upgrade()) {\n            (Some(p1), Some(p2)) => p1 == p2,\n            _ => false,\n        }\n    }\n}\n"
  },
  {
    "path": "graphics/src/text.rs",
    "content": "//! Draw text.\npub mod cache;\npub mod editor;\npub mod paragraph;\n\npub use cache::Cache;\npub use editor::Editor;\npub use paragraph::Paragraph;\n\npub use cosmic_text;\n\nuse crate::core::alignment;\nuse crate::core::font::{self, Font};\nuse crate::core::text::{Alignment, Ellipsis, Shaping, Wrapping};\nuse crate::core::{Color, Pixels, Point, Rectangle, Size, Transformation};\n\nuse std::borrow::Cow;\nuse std::collections::HashSet;\nuse std::sync::{Arc, OnceLock, RwLock, Weak};\n\n/// A text primitive.\n#[derive(Debug, Clone, PartialEq)]\npub enum Text {\n    /// A paragraph.\n    #[allow(missing_docs)]\n    Paragraph {\n        paragraph: paragraph::Weak,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    },\n    /// An editor.\n    #[allow(missing_docs)]\n    Editor {\n        editor: editor::Weak,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    },\n    /// Some cached text.\n    Cached {\n        /// The contents of the text.\n        content: String,\n        /// The bounds of the text.\n        bounds: Rectangle,\n        /// The color of the text.\n        color: Color,\n        /// The size of the text in logical pixels.\n        size: Pixels,\n        /// The line height of the text.\n        line_height: Pixels,\n        /// The font of the text.\n        font: Font,\n        /// The horizontal alignment of the text.\n        align_x: Alignment,\n        /// The vertical alignment of the text.\n        align_y: alignment::Vertical,\n        /// The shaping strategy of the text.\n        shaping: Shaping,\n        /// The wrapping strategy of the text.\n        wrapping: Wrapping,\n        /// The ellipsis strategy of the text.\n        ellipsis: Ellipsis,\n        /// The clip bounds of the text.\n        clip_bounds: Rectangle,\n    },\n    /// Some raw text.\n    #[allow(missing_docs)]\n    Raw {\n        raw: Raw,\n        transformation: Transformation,\n    },\n}\n\nimpl Text {\n    /// Returns the visible bounds of the [`Text`].\n    pub fn visible_bounds(&self) -> Option<Rectangle> {\n        match self {\n            Text::Paragraph {\n                position,\n                paragraph,\n                clip_bounds,\n                transformation,\n                ..\n            } => Rectangle::new(*position, paragraph.min_bounds)\n                .intersection(clip_bounds)\n                .map(|bounds| bounds * *transformation),\n            Text::Editor {\n                editor,\n                position,\n                clip_bounds,\n                transformation,\n                ..\n            } => Rectangle::new(*position, editor.bounds)\n                .intersection(clip_bounds)\n                .map(|bounds| bounds * *transformation),\n            Text::Cached {\n                bounds,\n                clip_bounds,\n                ..\n            } => bounds.intersection(clip_bounds),\n            Text::Raw { raw, .. } => Some(raw.clip_bounds),\n        }\n    }\n}\n\n/// The regular variant of the [Fira Sans] font.\n///\n/// It is loaded as part of the default fonts when the `fira-sans`\n/// feature is enabled.\n///\n/// [Fira Sans]: https://mozilla.github.io/Fira/\n#[cfg(feature = \"fira-sans\")]\npub const FIRA_SANS_REGULAR: &[u8] = include_bytes!(\"../fonts/FiraSans-Regular.ttf\").as_slice();\n\n/// Returns the global [`FontSystem`].\npub fn font_system() -> &'static RwLock<FontSystem> {\n    static FONT_SYSTEM: OnceLock<RwLock<FontSystem>> = OnceLock::new();\n\n    FONT_SYSTEM.get_or_init(|| {\n        #[allow(unused_mut)]\n        let mut raw = cosmic_text::FontSystem::new_with_fonts([\n            cosmic_text::fontdb::Source::Binary(Arc::new(\n                include_bytes!(\"../fonts/Iced-Icons.ttf\").as_slice(),\n            )),\n            #[cfg(feature = \"fira-sans\")]\n            cosmic_text::fontdb::Source::Binary(Arc::new(\n                include_bytes!(\"../fonts/FiraSans-Regular.ttf\").as_slice(),\n            )),\n        ]);\n\n        #[cfg(feature = \"fira-sans\")]\n        raw.db_mut().set_sans_serif_family(\"Fira Sans\");\n\n        RwLock::new(FontSystem {\n            raw,\n            loaded_fonts: HashSet::new(),\n            version: Version::default(),\n        })\n    })\n}\n\n/// A set of system fonts.\npub struct FontSystem {\n    raw: cosmic_text::FontSystem,\n    loaded_fonts: HashSet<usize>,\n    version: Version,\n}\n\nimpl FontSystem {\n    /// Returns the raw [`cosmic_text::FontSystem`].\n    pub fn raw(&mut self) -> &mut cosmic_text::FontSystem {\n        &mut self.raw\n    }\n\n    /// Loads a font from its bytes.\n    pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) {\n        if let Cow::Borrowed(bytes) = bytes {\n            let address = bytes.as_ptr() as usize;\n\n            if !self.loaded_fonts.insert(address) {\n                return;\n            }\n        }\n\n        let _ = self\n            .raw\n            .db_mut()\n            .load_font_source(cosmic_text::fontdb::Source::Binary(Arc::new(\n                bytes.into_owned(),\n            )));\n\n        self.version = Version(self.version.0 + 1);\n    }\n\n    /// Returns an iterator over the family names of all font faces\n    /// in the font database.\n    pub fn families(&self) -> impl Iterator<Item = &str> {\n        self.raw\n            .db()\n            .faces()\n            .filter_map(|face| face.families.first())\n            .map(|(name, _)| name.as_str())\n    }\n\n    /// Returns the current [`Version`] of the [`FontSystem`].\n    ///\n    /// Loading a font will increase the version of a [`FontSystem`].\n    pub fn version(&self) -> Version {\n        self.version\n    }\n}\n\n/// A version number.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]\npub struct Version(u32);\n\n/// A weak reference to a [`cosmic_text::Buffer`] that can be drawn.\n#[derive(Debug, Clone)]\npub struct Raw {\n    /// A weak reference to a [`cosmic_text::Buffer`].\n    pub buffer: Weak<cosmic_text::Buffer>,\n    /// The position of the text.\n    pub position: Point,\n    /// The color of the text.\n    pub color: Color,\n    /// The clip bounds of the text.\n    pub clip_bounds: Rectangle,\n}\n\nimpl PartialEq for Raw {\n    fn eq(&self, _other: &Self) -> bool {\n        // TODO: There is no proper way to compare raw buffers\n        // For now, no two instances of `Raw` text will be equal.\n        // This should be fine, but could trigger unnecessary redraws\n        // in the future.\n        false\n    }\n}\n\n/// Measures the dimensions of the given [`cosmic_text::Buffer`].\npub fn measure(buffer: &cosmic_text::Buffer) -> (Size, bool) {\n    let (width, height, has_rtl) =\n        buffer\n            .layout_runs()\n            .fold((0.0, 0.0, false), |(width, height, has_rtl), run| {\n                (\n                    run.line_w.max(width),\n                    height + run.line_height,\n                    has_rtl || run.rtl,\n                )\n            });\n\n    (Size::new(width, height), has_rtl)\n}\n\n/// Aligns the given [`cosmic_text::Buffer`] with the given [`Alignment`]\n/// and returns its minimum [`Size`].\npub fn align(\n    buffer: &mut cosmic_text::Buffer,\n    font_system: &mut cosmic_text::FontSystem,\n    alignment: Alignment,\n) -> Size {\n    let (min_bounds, has_rtl) = measure(buffer);\n    let mut needs_relayout = has_rtl;\n\n    if let Some(align) = to_align(alignment) {\n        let has_multiple_lines = buffer.lines.len() > 1\n            || buffer\n                .lines\n                .first()\n                .is_some_and(|line| line.layout_opt().is_some_and(|layout| layout.len() > 1));\n\n        if has_multiple_lines {\n            for line in &mut buffer.lines {\n                let _ = line.set_align(Some(align));\n            }\n\n            needs_relayout = true;\n        } else if let Some(line) = buffer.lines.first_mut() {\n            needs_relayout = line.set_align(None);\n        }\n    }\n\n    // TODO: Avoid relayout with some changes to `cosmic-text` (?)\n    if needs_relayout {\n        log::trace!(\"Relayouting paragraph...\");\n\n        buffer.set_size(font_system, Some(min_bounds.width), Some(min_bounds.height));\n    }\n\n    min_bounds\n}\n\n/// Returns the attributes of the given [`Font`].\npub fn to_attributes(font: Font) -> cosmic_text::Attrs<'static> {\n    cosmic_text::Attrs::new()\n        .family(to_family(font.family))\n        .weight(to_weight(font.weight))\n        .stretch(to_stretch(font.stretch))\n        .style(to_style(font.style))\n}\n\nfn to_family(family: font::Family) -> cosmic_text::Family<'static> {\n    match family {\n        font::Family::Name(name) => cosmic_text::Family::Name(name),\n        font::Family::SansSerif => cosmic_text::Family::SansSerif,\n        font::Family::Serif => cosmic_text::Family::Serif,\n        font::Family::Cursive => cosmic_text::Family::Cursive,\n        font::Family::Fantasy => cosmic_text::Family::Fantasy,\n        font::Family::Monospace => cosmic_text::Family::Monospace,\n    }\n}\n\nfn to_weight(weight: font::Weight) -> cosmic_text::Weight {\n    match weight {\n        font::Weight::Thin => cosmic_text::Weight::THIN,\n        font::Weight::ExtraLight => cosmic_text::Weight::EXTRA_LIGHT,\n        font::Weight::Light => cosmic_text::Weight::LIGHT,\n        font::Weight::Normal => cosmic_text::Weight::NORMAL,\n        font::Weight::Medium => cosmic_text::Weight::MEDIUM,\n        font::Weight::Semibold => cosmic_text::Weight::SEMIBOLD,\n        font::Weight::Bold => cosmic_text::Weight::BOLD,\n        font::Weight::ExtraBold => cosmic_text::Weight::EXTRA_BOLD,\n        font::Weight::Black => cosmic_text::Weight::BLACK,\n    }\n}\n\nfn to_stretch(stretch: font::Stretch) -> cosmic_text::Stretch {\n    match stretch {\n        font::Stretch::UltraCondensed => cosmic_text::Stretch::UltraCondensed,\n        font::Stretch::ExtraCondensed => cosmic_text::Stretch::ExtraCondensed,\n        font::Stretch::Condensed => cosmic_text::Stretch::Condensed,\n        font::Stretch::SemiCondensed => cosmic_text::Stretch::SemiCondensed,\n        font::Stretch::Normal => cosmic_text::Stretch::Normal,\n        font::Stretch::SemiExpanded => cosmic_text::Stretch::SemiExpanded,\n        font::Stretch::Expanded => cosmic_text::Stretch::Expanded,\n        font::Stretch::ExtraExpanded => cosmic_text::Stretch::ExtraExpanded,\n        font::Stretch::UltraExpanded => cosmic_text::Stretch::UltraExpanded,\n    }\n}\n\nfn to_style(style: font::Style) -> cosmic_text::Style {\n    match style {\n        font::Style::Normal => cosmic_text::Style::Normal,\n        font::Style::Italic => cosmic_text::Style::Italic,\n        font::Style::Oblique => cosmic_text::Style::Oblique,\n    }\n}\n\nfn to_align(alignment: Alignment) -> Option<cosmic_text::Align> {\n    match alignment {\n        Alignment::Default => None,\n        Alignment::Left => Some(cosmic_text::Align::Left),\n        Alignment::Center => Some(cosmic_text::Align::Center),\n        Alignment::Right => Some(cosmic_text::Align::Right),\n        Alignment::Justified => Some(cosmic_text::Align::Justified),\n    }\n}\n\n/// Converts some [`Shaping`] strategy to a [`cosmic_text::Shaping`] strategy.\npub fn to_shaping(shaping: Shaping, text: &str) -> cosmic_text::Shaping {\n    match shaping {\n        Shaping::Auto => {\n            if text.is_ascii() {\n                cosmic_text::Shaping::Basic\n            } else {\n                cosmic_text::Shaping::Advanced\n            }\n        }\n        Shaping::Basic => cosmic_text::Shaping::Basic,\n        Shaping::Advanced => cosmic_text::Shaping::Advanced,\n    }\n}\n\n/// Converts some [`Wrapping`] strategy to a [`cosmic_text::Wrap`] strategy.\npub fn to_wrap(wrapping: Wrapping) -> cosmic_text::Wrap {\n    match wrapping {\n        Wrapping::None => cosmic_text::Wrap::None,\n        Wrapping::Word => cosmic_text::Wrap::Word,\n        Wrapping::Glyph => cosmic_text::Wrap::Glyph,\n        Wrapping::WordOrGlyph => cosmic_text::Wrap::WordOrGlyph,\n    }\n}\n\n/// Converts some [`Ellipsis`] strategy to a [`cosmic_text::Ellipsize`] strategy.\npub fn to_ellipsize(ellipsis: Ellipsis, max_height: f32) -> cosmic_text::Ellipsize {\n    let limit = cosmic_text::EllipsizeHeightLimit::Height(max_height);\n\n    match ellipsis {\n        Ellipsis::None => cosmic_text::Ellipsize::None,\n        Ellipsis::Start => cosmic_text::Ellipsize::Start(limit),\n        Ellipsis::Middle => cosmic_text::Ellipsize::Middle(limit),\n        Ellipsis::End => cosmic_text::Ellipsize::End(limit),\n    }\n}\n\n/// Converts some [`Color`] to a [`cosmic_text::Color`].\npub fn to_color(color: Color) -> cosmic_text::Color {\n    let [r, g, b, a] = color.into_rgba8();\n\n    cosmic_text::Color::rgba(r, g, b, a)\n}\n\n/// Returns the ideal hint factor given the size and scale factor of some text.\npub fn hint_factor(_size: Pixels, _scale_factor: Option<f32>) -> Option<f32> {\n    // TODO: Fix hinting in `cosmic-text`\n    // const MAX_HINTING_SIZE: f32 = 18.0;\n\n    // let hint_factor = scale_factor?;\n\n    // if size.0 * hint_factor < MAX_HINTING_SIZE {\n    //     Some(hint_factor)\n    // } else {\n    //     None\n    // }\n\n    None // Disable all text hinting for now\n}\n\n/// A text renderer coupled to `iced_graphics`.\npub trait Renderer {\n    /// Draws the given [`Raw`] text.\n    fn fill_raw(&mut self, raw: Raw);\n}\n"
  },
  {
    "path": "graphics/src/viewport.rs",
    "content": "use crate::core::{Size, Transformation};\n\n/// A viewing region for displaying computer graphics.\n#[derive(Debug, Clone)]\npub struct Viewport {\n    physical_size: Size<u32>,\n    logical_size: Size<f32>,\n    scale_factor: f32,\n    projection: Transformation,\n}\n\nimpl Viewport {\n    /// Creates a new [`Viewport`] with the given physical dimensions and scale\n    /// factor.\n    pub fn with_physical_size(size: Size<u32>, scale_factor: f32) -> Viewport {\n        Viewport {\n            physical_size: size,\n            logical_size: Size::new(\n                size.width as f32 / scale_factor,\n                size.height as f32 / scale_factor,\n            ),\n            scale_factor,\n            projection: Transformation::orthographic(size.width, size.height),\n        }\n    }\n\n    /// Returns the physical size of the [`Viewport`].\n    pub fn physical_size(&self) -> Size<u32> {\n        self.physical_size\n    }\n\n    /// Returns the physical width of the [`Viewport`].\n    pub fn physical_width(&self) -> u32 {\n        self.physical_size.width\n    }\n\n    /// Returns the physical height of the [`Viewport`].\n    pub fn physical_height(&self) -> u32 {\n        self.physical_size.height\n    }\n\n    /// Returns the logical size of the [`Viewport`].\n    pub fn logical_size(&self) -> Size<f32> {\n        self.logical_size\n    }\n\n    /// Returns the scale factor of the [`Viewport`].\n    pub fn scale_factor(&self) -> f32 {\n        self.scale_factor\n    }\n\n    /// Returns the projection transformation of the [`Viewport`].\n    pub fn projection(&self) -> Transformation {\n        self.projection\n    }\n}\n"
  },
  {
    "path": "highlighter/Cargo.toml",
    "content": "[package]\nname = \"iced_highlighter\"\ndescription = \"A syntax highlighter for iced\"\nversion.workspace = true\nauthors.workspace = true\nedition.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\niced_core.workspace = true\n\ntwo-face.workspace = true\n"
  },
  {
    "path": "highlighter/src/lib.rs",
    "content": "//! A syntax highlighter for iced.\nuse iced_core as core;\n\nuse crate::core::Color;\nuse crate::core::font::{self, Font};\nuse crate::core::text::highlighter::{self, Format};\n\nuse std::ops::Range;\nuse std::sync::LazyLock;\n\nuse syntect::highlighting;\nuse syntect::parsing;\nuse two_face::re_exports::syntect;\n\nstatic SYNTAXES: LazyLock<parsing::SyntaxSet> = LazyLock::new(two_face::syntax::extra_no_newlines);\n\nstatic THEMES: LazyLock<highlighting::ThemeSet> =\n    LazyLock::new(highlighting::ThemeSet::load_defaults);\n\nconst LINES_PER_SNAPSHOT: usize = 50;\n\n/// A syntax highlighter.\n#[derive(Debug)]\npub struct Highlighter {\n    syntax: &'static parsing::SyntaxReference,\n    highlighter: highlighting::Highlighter<'static>,\n    caches: Vec<(parsing::ParseState, parsing::ScopeStack)>,\n    current_line: usize,\n}\n\nimpl highlighter::Highlighter for Highlighter {\n    type Settings = Settings;\n    type Highlight = Highlight;\n\n    type Iterator<'a> = Box<dyn Iterator<Item = (Range<usize>, Self::Highlight)> + 'a>;\n\n    fn new(settings: &Self::Settings) -> Self {\n        let syntax = SYNTAXES\n            .find_syntax_by_token(&settings.token)\n            .unwrap_or_else(|| SYNTAXES.find_syntax_plain_text());\n\n        let highlighter = highlighting::Highlighter::new(&THEMES.themes[settings.theme.key()]);\n\n        let parser = parsing::ParseState::new(syntax);\n        let stack = parsing::ScopeStack::new();\n\n        Highlighter {\n            syntax,\n            highlighter,\n            caches: vec![(parser, stack)],\n            current_line: 0,\n        }\n    }\n\n    fn update(&mut self, new_settings: &Self::Settings) {\n        self.syntax = SYNTAXES\n            .find_syntax_by_token(&new_settings.token)\n            .unwrap_or_else(|| SYNTAXES.find_syntax_plain_text());\n\n        self.highlighter = highlighting::Highlighter::new(&THEMES.themes[new_settings.theme.key()]);\n\n        // Restart the highlighter\n        self.change_line(0);\n    }\n\n    fn change_line(&mut self, line: usize) {\n        let snapshot = line / LINES_PER_SNAPSHOT;\n\n        if snapshot <= self.caches.len() {\n            self.caches.truncate(snapshot);\n            self.current_line = snapshot * LINES_PER_SNAPSHOT;\n        } else {\n            self.caches.truncate(1);\n            self.current_line = 0;\n        }\n\n        let (parser, stack) = self.caches.last().cloned().unwrap_or_else(|| {\n            (\n                parsing::ParseState::new(self.syntax),\n                parsing::ScopeStack::new(),\n            )\n        });\n\n        self.caches.push((parser, stack));\n    }\n\n    fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_> {\n        if self.current_line / LINES_PER_SNAPSHOT >= self.caches.len() {\n            let (parser, stack) = self.caches.last().expect(\"Caches must not be empty\");\n\n            self.caches.push((parser.clone(), stack.clone()));\n        }\n\n        self.current_line += 1;\n\n        let (parser, stack) = self.caches.last_mut().expect(\"Caches must not be empty\");\n\n        let ops = parser.parse_line(line, &SYNTAXES).unwrap_or_default();\n\n        Box::new(scope_iterator(ops, line, stack, &self.highlighter))\n    }\n\n    fn current_line(&self) -> usize {\n        self.current_line\n    }\n}\n\nfn scope_iterator<'a>(\n    ops: Vec<(usize, parsing::ScopeStackOp)>,\n    line: &str,\n    stack: &'a mut parsing::ScopeStack,\n    highlighter: &'a highlighting::Highlighter<'static>,\n) -> impl Iterator<Item = (Range<usize>, Highlight)> + 'a {\n    ScopeRangeIterator {\n        ops,\n        line_length: line.len(),\n        index: 0,\n        last_str_index: 0,\n    }\n    .filter_map(move |(range, scope)| {\n        let _ = stack.apply(&scope);\n\n        if range.is_empty() {\n            None\n        } else {\n            Some((\n                range,\n                Highlight(highlighter.style_mod_for_stack(&stack.scopes)),\n            ))\n        }\n    })\n}\n\n/// A streaming syntax highlighter.\n///\n/// It can efficiently highlight an immutable stream of tokens.\n#[derive(Debug)]\npub struct Stream {\n    syntax: &'static parsing::SyntaxReference,\n    highlighter: highlighting::Highlighter<'static>,\n    commit: (parsing::ParseState, parsing::ScopeStack),\n    state: parsing::ParseState,\n    stack: parsing::ScopeStack,\n}\n\nimpl Stream {\n    /// Creates a new [`Stream`] highlighter.\n    pub fn new(settings: &Settings) -> Self {\n        let syntax = SYNTAXES\n            .find_syntax_by_token(&settings.token)\n            .unwrap_or_else(|| SYNTAXES.find_syntax_plain_text());\n\n        let highlighter = highlighting::Highlighter::new(&THEMES.themes[settings.theme.key()]);\n\n        let state = parsing::ParseState::new(syntax);\n        let stack = parsing::ScopeStack::new();\n\n        Self {\n            syntax,\n            highlighter,\n            commit: (state.clone(), stack.clone()),\n            state,\n            stack,\n        }\n    }\n\n    /// Highlights the given line from the last commit.\n    pub fn highlight_line(\n        &mut self,\n        line: &str,\n    ) -> impl Iterator<Item = (Range<usize>, Highlight)> + '_ {\n        self.state = self.commit.0.clone();\n        self.stack = self.commit.1.clone();\n\n        let ops = self.state.parse_line(line, &SYNTAXES).unwrap_or_default();\n        scope_iterator(ops, line, &mut self.stack, &self.highlighter)\n    }\n\n    /// Commits the last highlighted line.\n    pub fn commit(&mut self) {\n        self.commit = (self.state.clone(), self.stack.clone());\n    }\n\n    /// Resets the [`Stream`] highlighter.\n    pub fn reset(&mut self) {\n        self.state = parsing::ParseState::new(self.syntax);\n        self.stack = parsing::ScopeStack::new();\n        self.commit = (self.state.clone(), self.stack.clone());\n    }\n}\n\n/// The settings of a [`Highlighter`].\n#[derive(Debug, Clone, PartialEq)]\npub struct Settings {\n    /// The [`Theme`] of the [`Highlighter`].\n    ///\n    /// It dictates the color scheme that will be used for highlighting.\n    pub theme: Theme,\n    /// The extension of the file or the name of the language to highlight.\n    ///\n    /// The [`Highlighter`] will use the token to automatically determine\n    /// the grammar to use for highlighting.\n    pub token: String,\n}\n\n/// A highlight produced by a [`Highlighter`].\n#[derive(Debug)]\npub struct Highlight(highlighting::StyleModifier);\n\nimpl Highlight {\n    /// Returns the color of this [`Highlight`].\n    ///\n    /// If `None`, the original text color should be unchanged.\n    pub fn color(&self) -> Option<Color> {\n        self.0\n            .foreground\n            .map(|color| Color::from_rgba8(color.r, color.g, color.b, color.a as f32 / 255.0))\n    }\n\n    /// Returns the font of this [`Highlight`].\n    ///\n    /// If `None`, the original font should be unchanged.\n    pub fn font(&self) -> Option<Font> {\n        self.0.font_style.and_then(|style| {\n            let bold = style.contains(highlighting::FontStyle::BOLD);\n            let italic = style.contains(highlighting::FontStyle::ITALIC);\n\n            if bold || italic {\n                Some(Font {\n                    weight: if bold {\n                        font::Weight::Bold\n                    } else {\n                        font::Weight::Normal\n                    },\n                    style: if italic {\n                        font::Style::Italic\n                    } else {\n                        font::Style::Normal\n                    },\n                    ..Font::MONOSPACE\n                })\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the [`Format`] of the [`Highlight`].\n    ///\n    /// It contains both the [`color`] and the [`font`].\n    ///\n    /// [`color`]: Self::color\n    /// [`font`]: Self::font\n    pub fn to_format(&self) -> Format<Font> {\n        Format {\n            color: self.color(),\n            font: self.font(),\n        }\n    }\n}\n\n/// A highlighting theme.\n#[allow(missing_docs)]\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Theme {\n    SolarizedDark,\n    Base16Mocha,\n    Base16Ocean,\n    Base16Eighties,\n    InspiredGitHub,\n}\n\nimpl Theme {\n    /// A static slice containing all the available themes.\n    pub const ALL: &'static [Self] = &[\n        Self::SolarizedDark,\n        Self::Base16Mocha,\n        Self::Base16Ocean,\n        Self::Base16Eighties,\n        Self::InspiredGitHub,\n    ];\n\n    /// Returns `true` if the [`Theme`] is dark, and false otherwise.\n    pub fn is_dark(self) -> bool {\n        match self {\n            Self::SolarizedDark | Self::Base16Mocha | Self::Base16Ocean | Self::Base16Eighties => {\n                true\n            }\n            Self::InspiredGitHub => false,\n        }\n    }\n\n    fn key(self) -> &'static str {\n        match self {\n            Theme::SolarizedDark => \"Solarized (dark)\",\n            Theme::Base16Mocha => \"base16-mocha.dark\",\n            Theme::Base16Ocean => \"base16-ocean.dark\",\n            Theme::Base16Eighties => \"base16-eighties.dark\",\n            Theme::InspiredGitHub => \"InspiredGitHub\",\n        }\n    }\n}\n\nimpl std::fmt::Display for Theme {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Theme::SolarizedDark => write!(f, \"Solarized Dark\"),\n            Theme::Base16Mocha => write!(f, \"Mocha\"),\n            Theme::Base16Ocean => write!(f, \"Ocean\"),\n            Theme::Base16Eighties => write!(f, \"Eighties\"),\n            Theme::InspiredGitHub => write!(f, \"Inspired GitHub\"),\n        }\n    }\n}\n\nstruct ScopeRangeIterator {\n    ops: Vec<(usize, parsing::ScopeStackOp)>,\n    line_length: usize,\n    index: usize,\n    last_str_index: usize,\n}\n\nimpl Iterator for ScopeRangeIterator {\n    type Item = (std::ops::Range<usize>, parsing::ScopeStackOp);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if self.index > self.ops.len() {\n            return None;\n        }\n\n        let next_str_i = if self.index == self.ops.len() {\n            self.line_length\n        } else {\n            self.ops[self.index].0\n        };\n\n        let range = self.last_str_index..next_str_i;\n        self.last_str_index = next_str_i;\n\n        let op = if self.index == 0 {\n            parsing::ScopeStackOp::Noop\n        } else {\n            self.ops[self.index - 1].1.clone()\n        };\n\n        self.index += 1;\n        Some((range, op))\n    }\n}\n"
  },
  {
    "path": "program/Cargo.toml",
    "content": "[package]\nname = \"iced_program\"\ndescription = \"The definition of an iced program\"\nversion.workspace = true\nauthors.workspace = true\nedition.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\nrust-version.workspace = true\n\n[lints]\nworkspace = true\n\n[features]\ndebug = []\ntime-travel = []\n\n[dependencies]\niced_graphics.workspace = true\niced_runtime.workspace = true\n"
  },
  {
    "path": "program/src/lib.rs",
    "content": "//! The definition of an iced program.\npub use iced_graphics as graphics;\npub use iced_runtime as runtime;\npub use iced_runtime::core;\npub use iced_runtime::futures;\n\npub mod message;\n\nmod preset;\n\npub use preset::Preset;\n\nuse crate::core::renderer;\nuse crate::core::text;\nuse crate::core::theme;\nuse crate::core::window;\nuse crate::core::{Element, Font, Settings};\nuse crate::futures::{Executor, Subscription};\nuse crate::graphics::compositor;\nuse crate::runtime::Task;\n\n/// An interactive, native, cross-platform, multi-windowed application.\n///\n/// A [`Program`] can execute asynchronous actions by returning a\n/// [`Task`] in some of its methods.\n#[allow(missing_docs)]\npub trait Program: Sized {\n    /// The state of the program.\n    type State;\n\n    /// The message of the program.\n    type Message: Send + 'static;\n\n    /// The theme of the program.\n    type Theme: theme::Base;\n\n    /// The renderer of the program.\n    type Renderer: Renderer;\n\n    /// The executor of the program.\n    type Executor: Executor;\n\n    /// Returns the unique name of the [`Program`].\n    fn name() -> &'static str;\n\n    fn settings(&self) -> Settings;\n\n    fn window(&self) -> Option<window::Settings>;\n\n    fn boot(&self) -> (Self::State, Task<Self::Message>);\n\n    fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message>;\n\n    fn view<'a>(\n        &self,\n        state: &'a Self::State,\n        window: window::Id,\n    ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer>;\n\n    fn title(&self, _state: &Self::State, _window: window::Id) -> String {\n        let mut title = String::new();\n\n        for (i, part) in Self::name().split(\"_\").enumerate() {\n            use std::borrow::Cow;\n\n            let part = match part {\n                \"a\" | \"an\" | \"of\" | \"in\" | \"and\" => Cow::Borrowed(part),\n                _ => {\n                    let mut part = part.to_owned();\n\n                    if let Some(first_letter) = part.get_mut(0..1) {\n                        first_letter.make_ascii_uppercase();\n                    }\n\n                    Cow::Owned(part)\n                }\n            };\n\n            if i > 0 {\n                title.push(' ');\n            }\n\n            title.push_str(&part);\n        }\n\n        format!(\"{title} - Iced\")\n    }\n\n    fn subscription(&self, _state: &Self::State) -> Subscription<Self::Message> {\n        Subscription::none()\n    }\n\n    fn theme(&self, _state: &Self::State, _window: window::Id) -> Option<Self::Theme> {\n        None\n    }\n\n    fn style(&self, _state: &Self::State, theme: &Self::Theme) -> theme::Style {\n        theme::Base::base(theme)\n    }\n\n    fn scale_factor(&self, _state: &Self::State, _window: window::Id) -> f32 {\n        1.0\n    }\n\n    fn presets(&self) -> &[Preset<Self::State, Self::Message>] {\n        &[]\n    }\n}\n\n/// Decorates a [`Program`] with the given title function.\npub fn with_title<P: Program>(\n    program: P,\n    title: impl Fn(&P::State, window::Id) -> String,\n) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {\n    struct WithTitle<P, Title> {\n        program: P,\n        title: Title,\n    }\n\n    impl<P, Title> Program for WithTitle<P, Title>\n    where\n        P: Program,\n        Title: Fn(&P::State, window::Id) -> String,\n    {\n        type State = P::State;\n        type Message = P::Message;\n        type Theme = P::Theme;\n        type Renderer = P::Renderer;\n        type Executor = P::Executor;\n\n        fn title(&self, state: &Self::State, window: window::Id) -> String {\n            (self.title)(state, window)\n        }\n\n        fn name() -> &'static str {\n            P::name()\n        }\n\n        fn settings(&self) -> Settings {\n            self.program.settings()\n        }\n\n        fn window(&self) -> Option<window::Settings> {\n            self.program.window()\n        }\n\n        fn boot(&self) -> (Self::State, Task<Self::Message>) {\n            self.program.boot()\n        }\n\n        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n            self.program.update(state, message)\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            self.program.view(state, window)\n        }\n\n        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {\n            self.program.theme(state, window)\n        }\n\n        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n            self.program.subscription(state)\n        }\n\n        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n            self.program.style(state, theme)\n        }\n\n        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n            self.program.scale_factor(state, window)\n        }\n    }\n\n    WithTitle { program, title }\n}\n\n/// Decorates a [`Program`] with the given subscription function.\npub fn with_subscription<P: Program>(\n    program: P,\n    f: impl Fn(&P::State) -> Subscription<P::Message>,\n) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {\n    struct WithSubscription<P, F> {\n        program: P,\n        subscription: F,\n    }\n\n    impl<P: Program, F> Program for WithSubscription<P, F>\n    where\n        F: Fn(&P::State) -> Subscription<P::Message>,\n    {\n        type State = P::State;\n        type Message = P::Message;\n        type Theme = P::Theme;\n        type Renderer = P::Renderer;\n        type Executor = P::Executor;\n\n        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n            (self.subscription)(state)\n        }\n\n        fn name() -> &'static str {\n            P::name()\n        }\n\n        fn settings(&self) -> Settings {\n            self.program.settings()\n        }\n\n        fn window(&self) -> Option<window::Settings> {\n            self.program.window()\n        }\n\n        fn boot(&self) -> (Self::State, Task<Self::Message>) {\n            self.program.boot()\n        }\n\n        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n            self.program.update(state, message)\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            self.program.view(state, window)\n        }\n\n        fn title(&self, state: &Self::State, window: window::Id) -> String {\n            self.program.title(state, window)\n        }\n\n        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {\n            self.program.theme(state, window)\n        }\n\n        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n            self.program.style(state, theme)\n        }\n\n        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n            self.program.scale_factor(state, window)\n        }\n    }\n\n    WithSubscription {\n        program,\n        subscription: f,\n    }\n}\n\n/// Decorates a [`Program`] with the given theme function.\npub fn with_theme<P: Program>(\n    program: P,\n    f: impl Fn(&P::State, window::Id) -> Option<P::Theme>,\n) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {\n    struct WithTheme<P, F> {\n        program: P,\n        theme: F,\n    }\n\n    impl<P: Program, F> Program for WithTheme<P, F>\n    where\n        F: Fn(&P::State, window::Id) -> Option<P::Theme>,\n    {\n        type State = P::State;\n        type Message = P::Message;\n        type Theme = P::Theme;\n        type Renderer = P::Renderer;\n        type Executor = P::Executor;\n\n        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {\n            (self.theme)(state, window)\n        }\n\n        fn name() -> &'static str {\n            P::name()\n        }\n\n        fn settings(&self) -> Settings {\n            self.program.settings()\n        }\n\n        fn window(&self) -> Option<window::Settings> {\n            self.program.window()\n        }\n\n        fn boot(&self) -> (Self::State, Task<Self::Message>) {\n            self.program.boot()\n        }\n\n        fn title(&self, state: &Self::State, window: window::Id) -> String {\n            self.program.title(state, window)\n        }\n\n        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n            self.program.update(state, message)\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            self.program.view(state, window)\n        }\n\n        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n            self.program.subscription(state)\n        }\n\n        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n            self.program.style(state, theme)\n        }\n\n        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n            self.program.scale_factor(state, window)\n        }\n    }\n\n    WithTheme { program, theme: f }\n}\n\n/// Decorates a [`Program`] with the given style function.\npub fn with_style<P: Program>(\n    program: P,\n    f: impl Fn(&P::State, &P::Theme) -> theme::Style,\n) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {\n    struct WithStyle<P, F> {\n        program: P,\n        style: F,\n    }\n\n    impl<P: Program, F> Program for WithStyle<P, F>\n    where\n        F: Fn(&P::State, &P::Theme) -> theme::Style,\n    {\n        type State = P::State;\n        type Message = P::Message;\n        type Theme = P::Theme;\n        type Renderer = P::Renderer;\n        type Executor = P::Executor;\n\n        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n            (self.style)(state, theme)\n        }\n\n        fn name() -> &'static str {\n            P::name()\n        }\n\n        fn settings(&self) -> Settings {\n            self.program.settings()\n        }\n\n        fn window(&self) -> Option<window::Settings> {\n            self.program.window()\n        }\n\n        fn boot(&self) -> (Self::State, Task<Self::Message>) {\n            self.program.boot()\n        }\n\n        fn title(&self, state: &Self::State, window: window::Id) -> String {\n            self.program.title(state, window)\n        }\n\n        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n            self.program.update(state, message)\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            self.program.view(state, window)\n        }\n\n        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n            self.program.subscription(state)\n        }\n\n        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {\n            self.program.theme(state, window)\n        }\n\n        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n            self.program.scale_factor(state, window)\n        }\n    }\n\n    WithStyle { program, style: f }\n}\n\n/// Decorates a [`Program`] with the given scale factor function.\npub fn with_scale_factor<P: Program>(\n    program: P,\n    f: impl Fn(&P::State, window::Id) -> f32,\n) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {\n    struct WithScaleFactor<P, F> {\n        program: P,\n        scale_factor: F,\n    }\n\n    impl<P: Program, F> Program for WithScaleFactor<P, F>\n    where\n        F: Fn(&P::State, window::Id) -> f32,\n    {\n        type State = P::State;\n        type Message = P::Message;\n        type Theme = P::Theme;\n        type Renderer = P::Renderer;\n        type Executor = P::Executor;\n\n        fn title(&self, state: &Self::State, window: window::Id) -> String {\n            self.program.title(state, window)\n        }\n\n        fn name() -> &'static str {\n            P::name()\n        }\n\n        fn settings(&self) -> Settings {\n            self.program.settings()\n        }\n\n        fn window(&self) -> Option<window::Settings> {\n            self.program.window()\n        }\n\n        fn boot(&self) -> (Self::State, Task<Self::Message>) {\n            self.program.boot()\n        }\n\n        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n            self.program.update(state, message)\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            self.program.view(state, window)\n        }\n\n        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n            self.program.subscription(state)\n        }\n\n        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {\n            self.program.theme(state, window)\n        }\n\n        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n            self.program.style(state, theme)\n        }\n\n        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n            (self.scale_factor)(state, window)\n        }\n    }\n\n    WithScaleFactor {\n        program,\n        scale_factor: f,\n    }\n}\n\n/// Decorates a [`Program`] with the given executor function.\npub fn with_executor<P: Program, E: Executor>(\n    program: P,\n) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> {\n    use std::marker::PhantomData;\n\n    struct WithExecutor<P, E> {\n        program: P,\n        executor: PhantomData<E>,\n    }\n\n    impl<P: Program, E> Program for WithExecutor<P, E>\n    where\n        E: Executor,\n    {\n        type State = P::State;\n        type Message = P::Message;\n        type Theme = P::Theme;\n        type Renderer = P::Renderer;\n        type Executor = E;\n\n        fn title(&self, state: &Self::State, window: window::Id) -> String {\n            self.program.title(state, window)\n        }\n\n        fn name() -> &'static str {\n            P::name()\n        }\n\n        fn settings(&self) -> Settings {\n            self.program.settings()\n        }\n\n        fn window(&self) -> Option<window::Settings> {\n            self.program.window()\n        }\n\n        fn boot(&self) -> (Self::State, Task<Self::Message>) {\n            self.program.boot()\n        }\n\n        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n            self.program.update(state, message)\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            self.program.view(state, window)\n        }\n\n        fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n            self.program.subscription(state)\n        }\n\n        fn theme(&self, state: &Self::State, window: window::Id) -> Option<Self::Theme> {\n            self.program.theme(state, window)\n        }\n\n        fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n            self.program.style(state, theme)\n        }\n\n        fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n            self.program.scale_factor(state, window)\n        }\n    }\n\n    WithExecutor {\n        program,\n        executor: PhantomData::<E>,\n    }\n}\n\n/// The renderer of some [`Program`].\npub trait Renderer: text::Renderer<Font = Font> + compositor::Default + renderer::Headless {}\n\nimpl<T> Renderer for T where\n    T: text::Renderer<Font = Font> + compositor::Default + renderer::Headless\n{\n}\n\n/// A particular instance of a running [`Program`].\npub struct Instance<P: Program> {\n    program: P,\n    state: P::State,\n}\n\nimpl<P: Program> Instance<P> {\n    /// Creates a new [`Instance`] of the given [`Program`].\n    pub fn new(program: P) -> (Self, Task<P::Message>) {\n        let (state, task) = program.boot();\n\n        (Self { program, state }, task)\n    }\n\n    /// Returns the current title of the [`Instance`].\n    pub fn title(&self, window: window::Id) -> String {\n        self.program.title(&self.state, window)\n    }\n\n    /// Processes the given message and updates the [`Instance`].\n    pub fn update(&mut self, message: P::Message) -> Task<P::Message> {\n        self.program.update(&mut self.state, message)\n    }\n\n    /// Produces the current widget tree of the [`Instance`].\n    pub fn view(&self, window: window::Id) -> Element<'_, P::Message, P::Theme, P::Renderer> {\n        self.program.view(&self.state, window)\n    }\n\n    /// Returns the current [`Subscription`] of the [`Instance`].\n    pub fn subscription(&self) -> Subscription<P::Message> {\n        self.program.subscription(&self.state)\n    }\n\n    /// Returns the current theme of the [`Instance`].\n    pub fn theme(&self, window: window::Id) -> Option<P::Theme> {\n        self.program.theme(&self.state, window)\n    }\n\n    /// Returns the current [`theme::Style`] of the [`Instance`].\n    pub fn style(&self, theme: &P::Theme) -> theme::Style {\n        self.program.style(&self.state, theme)\n    }\n\n    /// Returns the current scale factor of the [`Instance`].\n    pub fn scale_factor(&self, window: window::Id) -> f32 {\n        self.program.scale_factor(&self.state, window)\n    }\n}\n"
  },
  {
    "path": "program/src/message.rs",
    "content": "//! Traits for the message type of a [`Program`](crate::Program).\n\n/// A trait alias for [`Clone`], but only when the `time-travel`\n/// feature is enabled.\n#[cfg(feature = \"time-travel\")]\npub trait MaybeClone: Clone {}\n\n#[cfg(feature = \"time-travel\")]\nimpl<T> MaybeClone for T where T: Clone {}\n\n/// A trait alias for [`Clone`], but only when the `time-travel`\n/// feature is enabled.\n#[cfg(not(feature = \"time-travel\"))]\npub trait MaybeClone {}\n\n#[cfg(not(feature = \"time-travel\"))]\nimpl<T> MaybeClone for T {}\n\n/// A trait alias for [`Debug`](std::fmt::Debug), but only when the\n/// `debug` feature is enabled.\n#[cfg(feature = \"debug\")]\npub trait MaybeDebug: std::fmt::Debug {}\n\n#[cfg(feature = \"debug\")]\nimpl<T> MaybeDebug for T where T: std::fmt::Debug {}\n\n/// A trait alias for [`Debug`](std::fmt::Debug), but only when the\n/// `debug` feature is enabled.\n#[cfg(not(feature = \"debug\"))]\npub trait MaybeDebug {}\n\n#[cfg(not(feature = \"debug\"))]\nimpl<T> MaybeDebug for T {}\n"
  },
  {
    "path": "program/src/preset.rs",
    "content": "use crate::runtime::Task;\n\nuse std::borrow::Cow;\nuse std::fmt;\n\n/// A specific boot strategy for a [`Program`](crate::Program).\npub struct Preset<State, Message> {\n    name: Cow<'static, str>,\n    boot: Box<dyn Fn() -> (State, Task<Message>)>,\n}\n\nimpl<State, Message> Preset<State, Message> {\n    /// Creates a new [`Preset`] with the given name and boot strategy.\n    pub fn new(\n        name: impl Into<Cow<'static, str>>,\n        boot: impl Fn() -> (State, Task<Message>) + 'static,\n    ) -> Self {\n        Self {\n            name: name.into(),\n            boot: Box::new(boot),\n        }\n    }\n\n    /// Returns the name of the [`Preset`].\n    pub fn name(&self) -> &str {\n        &self.name\n    }\n\n    /// Boots the [`Preset`], returning the initial [`Program`](crate::Program) state and\n    /// a [`Task`] for concurrent booting.\n    pub fn boot(&self) -> (State, Task<Message>) {\n        (self.boot)()\n    }\n}\n\nimpl<State, Message> fmt::Debug for Preset<State, Message> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Preset\")\n            .field(\"name\", &self.name)\n            .finish_non_exhaustive()\n    }\n}\n"
  },
  {
    "path": "renderer/Cargo.toml",
    "content": "[package]\nname = \"iced_renderer\"\ndescription = \"The official renderer for iced\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[features]\nwgpu = [\"iced_wgpu/default\"]\nwgpu-bare = [\"iced_wgpu\"]\ntiny-skia = [\"iced_tiny_skia\"]\nimage = [\"iced_tiny_skia?/image\", \"iced_wgpu?/image\"]\nsvg = [\"iced_tiny_skia?/svg\", \"iced_wgpu?/svg\"]\ngeometry = [\"iced_graphics/geometry\", \"iced_tiny_skia?/geometry\", \"iced_wgpu?/geometry\"]\nweb-colors = [\"iced_wgpu?/web-colors\"]\nwebgl = [\"iced_wgpu?/webgl\"]\nfira-sans = [\"iced_graphics/fira-sans\"]\nstrict-assertions = [\"iced_wgpu?/strict-assertions\"]\nx11 = [\"iced_tiny_skia?/x11\"]\nwayland = [\"iced_tiny_skia?/wayland\"]\n\n[dependencies]\niced_graphics.workspace = true\n\niced_tiny_skia.workspace = true\niced_tiny_skia.optional = true\n\niced_wgpu.workspace = true\niced_wgpu.optional = true\n\nlog.workspace = true\nthiserror.workspace = true\n"
  },
  {
    "path": "renderer/src/fallback.rs",
    "content": "//! Compose existing renderers and create type-safe fallback strategies.\nuse crate::core::font;\nuse crate::core::image;\nuse crate::core::renderer;\nuse crate::core::svg;\nuse crate::core::{self, Background, Color, Image, Point, Rectangle, Size, Svg, Transformation};\nuse crate::graphics::compositor;\nuse crate::graphics::mesh;\nuse crate::graphics::text;\nuse crate::graphics::{self, Shell};\n\nuse std::borrow::Cow;\n\n/// A renderer `A` with a fallback strategy `B`.\n///\n/// This type can be used to easily compose existing renderers and\n/// create custom, type-safe fallback strategies.\n#[derive(Debug)]\npub enum Renderer<A, B> {\n    /// The primary rendering option.\n    Primary(A),\n    /// The secondary (or fallback) rendering option.\n    Secondary(B),\n}\n\nmacro_rules! delegate {\n    ($renderer:expr, $name:ident, $body:expr) => {\n        match $renderer {\n            Self::Primary($name) => $body,\n            Self::Secondary($name) => $body,\n        }\n    };\n}\n\nimpl<A, B> core::Renderer for Renderer<A, B>\nwhere\n    A: core::Renderer,\n    B: core::Renderer,\n{\n    fn fill_quad(&mut self, quad: renderer::Quad, background: impl Into<Background>) {\n        delegate!(self, renderer, renderer.fill_quad(quad, background.into()));\n    }\n\n    fn start_layer(&mut self, bounds: Rectangle) {\n        delegate!(self, renderer, renderer.start_layer(bounds));\n    }\n\n    fn end_layer(&mut self) {\n        delegate!(self, renderer, renderer.end_layer());\n    }\n\n    fn start_transformation(&mut self, transformation: Transformation) {\n        delegate!(\n            self,\n            renderer,\n            renderer.start_transformation(transformation)\n        );\n    }\n\n    fn end_transformation(&mut self) {\n        delegate!(self, renderer, renderer.end_transformation());\n    }\n\n    fn allocate_image(\n        &mut self,\n        handle: &image::Handle,\n        callback: impl FnOnce(Result<image::Allocation, image::Error>) + Send + 'static,\n    ) {\n        delegate!(self, renderer, renderer.allocate_image(handle, callback));\n    }\n\n    fn hint(&mut self, scale_factor: f32) {\n        delegate!(self, renderer, renderer.hint(scale_factor));\n    }\n\n    fn scale_factor(&self) -> Option<f32> {\n        delegate!(self, renderer, renderer.scale_factor())\n    }\n\n    fn tick(&mut self) {\n        delegate!(self, renderer, renderer.tick());\n    }\n\n    fn reset(&mut self, new_bounds: Rectangle) {\n        delegate!(self, renderer, renderer.reset(new_bounds));\n    }\n}\n\nimpl<A, B> core::text::Renderer for Renderer<A, B>\nwhere\n    A: core::text::Renderer,\n    B: core::text::Renderer<Font = A::Font, Paragraph = A::Paragraph, Editor = A::Editor>,\n{\n    type Font = A::Font;\n    type Paragraph = A::Paragraph;\n    type Editor = A::Editor;\n\n    const ICON_FONT: Self::Font = A::ICON_FONT;\n    const CHECKMARK_ICON: char = A::CHECKMARK_ICON;\n    const ARROW_DOWN_ICON: char = A::ARROW_DOWN_ICON;\n    const SCROLL_UP_ICON: char = A::SCROLL_UP_ICON;\n    const SCROLL_DOWN_ICON: char = A::SCROLL_DOWN_ICON;\n    const SCROLL_LEFT_ICON: char = A::SCROLL_LEFT_ICON;\n    const SCROLL_RIGHT_ICON: char = A::SCROLL_RIGHT_ICON;\n    const ICED_LOGO: char = A::ICED_LOGO;\n\n    fn default_font(&self) -> Self::Font {\n        delegate!(self, renderer, renderer.default_font())\n    }\n\n    fn default_size(&self) -> core::Pixels {\n        delegate!(self, renderer, renderer.default_size())\n    }\n\n    fn fill_paragraph(\n        &mut self,\n        text: &Self::Paragraph,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        delegate!(\n            self,\n            renderer,\n            renderer.fill_paragraph(text, position, color, clip_bounds)\n        );\n    }\n\n    fn fill_editor(\n        &mut self,\n        editor: &Self::Editor,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        delegate!(\n            self,\n            renderer,\n            renderer.fill_editor(editor, position, color, clip_bounds)\n        );\n    }\n\n    fn fill_text(\n        &mut self,\n        text: core::Text<String, Self::Font>,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        delegate!(\n            self,\n            renderer,\n            renderer.fill_text(text, position, color, clip_bounds)\n        );\n    }\n}\n\nimpl<A, B> text::Renderer for Renderer<A, B>\nwhere\n    A: text::Renderer,\n    B: text::Renderer,\n{\n    fn fill_raw(&mut self, raw: text::Raw) {\n        delegate!(self, renderer, renderer.fill_raw(raw));\n    }\n}\n\nimpl<A, B> image::Renderer for Renderer<A, B>\nwhere\n    A: image::Renderer,\n    B: image::Renderer<Handle = A::Handle>,\n{\n    type Handle = A::Handle;\n\n    fn load_image(&self, handle: &Self::Handle) -> Result<image::Allocation, image::Error> {\n        delegate!(self, renderer, renderer.load_image(handle))\n    }\n\n    fn measure_image(&self, handle: &Self::Handle) -> Option<Size<u32>> {\n        delegate!(self, renderer, renderer.measure_image(handle))\n    }\n\n    fn draw_image(&mut self, image: Image<A::Handle>, bounds: Rectangle, clip_bounds: Rectangle) {\n        delegate!(\n            self,\n            renderer,\n            renderer.draw_image(image, bounds, clip_bounds)\n        );\n    }\n}\n\nimpl<A, B> svg::Renderer for Renderer<A, B>\nwhere\n    A: svg::Renderer,\n    B: svg::Renderer,\n{\n    fn measure_svg(&self, handle: &svg::Handle) -> Size<u32> {\n        delegate!(self, renderer, renderer.measure_svg(handle))\n    }\n\n    fn draw_svg(&mut self, svg: Svg, bounds: Rectangle, clip_bounds: Rectangle) {\n        delegate!(self, renderer, renderer.draw_svg(svg, bounds, clip_bounds));\n    }\n}\n\nimpl<A, B> mesh::Renderer for Renderer<A, B>\nwhere\n    A: mesh::Renderer,\n    B: mesh::Renderer,\n{\n    fn draw_mesh(&mut self, mesh: graphics::Mesh) {\n        delegate!(self, renderer, renderer.draw_mesh(mesh));\n    }\n\n    fn draw_mesh_cache(&mut self, cache: mesh::Cache) {\n        delegate!(self, renderer, renderer.draw_mesh_cache(cache));\n    }\n}\n\n/// A compositor `A` with a fallback strategy `B`.\n///\n/// It works analogously to [`Renderer`].\n#[derive(Debug)]\npub enum Compositor<A, B>\nwhere\n    A: graphics::Compositor,\n    B: graphics::Compositor,\n{\n    /// The primary compositing option.\n    Primary(A),\n    /// The secondary (or fallback) compositing option.\n    Secondary(B),\n}\n\n/// A surface `A` with a fallback strategy `B`.\n///\n/// It works analogously to [`Renderer`].\n#[derive(Debug)]\npub enum Surface<A, B> {\n    /// The primary surface option.\n    Primary(A),\n    /// The secondary (or fallback) surface option.\n    Secondary(B),\n}\n\nimpl<A, B> graphics::Compositor for Compositor<A, B>\nwhere\n    A: graphics::Compositor,\n    B: graphics::Compositor,\n{\n    type Renderer = Renderer<A::Renderer, B::Renderer>;\n    type Surface = Surface<A::Surface, B::Surface>;\n\n    async fn with_backend(\n        settings: compositor::Settings,\n        display: impl compositor::Display + Clone,\n        compatible_window: impl compositor::Window + Clone,\n        shell: Shell,\n        backend: Option<&str>,\n    ) -> Result<Self, graphics::Error> {\n        use std::env;\n\n        let backends = backend\n            .map(str::to_owned)\n            .or_else(|| env::var(\"ICED_BACKEND\").ok());\n\n        let mut candidates: Vec<_> = backends\n            .map(|backends| {\n                backends\n                    .split(',')\n                    .filter(|candidate| !candidate.is_empty())\n                    .map(str::to_owned)\n                    .map(Some)\n                    .collect()\n            })\n            .unwrap_or_default();\n\n        if candidates.is_empty() {\n            candidates.push(None);\n        }\n\n        let mut errors = vec![];\n\n        for backend in candidates.iter().map(Option::as_deref) {\n            match A::with_backend(\n                settings,\n                display.clone(),\n                compatible_window.clone(),\n                shell.clone(),\n                backend,\n            )\n            .await\n            {\n                Ok(compositor) => return Ok(Self::Primary(compositor)),\n                Err(error) => {\n                    errors.push(error);\n                }\n            }\n\n            match B::with_backend(\n                settings,\n                display.clone(),\n                compatible_window.clone(),\n                shell.clone(),\n                backend,\n            )\n            .await\n            {\n                Ok(compositor) => return Ok(Self::Secondary(compositor)),\n                Err(error) => {\n                    errors.push(error);\n                }\n            }\n        }\n\n        Err(graphics::Error::List(errors))\n    }\n\n    fn create_renderer(&self, settings: renderer::Settings) -> Self::Renderer {\n        match self {\n            Self::Primary(compositor) => Renderer::Primary(compositor.create_renderer(settings)),\n            Self::Secondary(compositor) => {\n                Renderer::Secondary(compositor.create_renderer(settings))\n            }\n        }\n    }\n\n    fn create_surface<W: compositor::Window + Clone>(\n        &mut self,\n        window: W,\n        width: u32,\n        height: u32,\n    ) -> Self::Surface {\n        match self {\n            Self::Primary(compositor) => {\n                Surface::Primary(compositor.create_surface(window, width, height))\n            }\n            Self::Secondary(compositor) => {\n                Surface::Secondary(compositor.create_surface(window, width, height))\n            }\n        }\n    }\n\n    fn configure_surface(&mut self, surface: &mut Self::Surface, width: u32, height: u32) {\n        match (self, surface) {\n            (Self::Primary(compositor), Surface::Primary(surface)) => {\n                compositor.configure_surface(surface, width, height);\n            }\n            (Self::Secondary(compositor), Surface::Secondary(surface)) => {\n                compositor.configure_surface(surface, width, height);\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    fn load_font(&mut self, font: Cow<'static, [u8]>) -> Result<(), font::Error> {\n        delegate!(self, compositor, compositor.load_font(font))\n    }\n\n    fn list_fonts(&mut self) -> Result<Vec<font::Family>, font::Error> {\n        delegate!(self, compositor, compositor.list_fonts())\n    }\n\n    fn information(&self) -> compositor::Information {\n        delegate!(self, compositor, compositor.information())\n    }\n\n    fn present(\n        &mut self,\n        renderer: &mut Self::Renderer,\n        surface: &mut Self::Surface,\n        viewport: &graphics::Viewport,\n        background_color: Color,\n        on_pre_present: impl FnOnce(),\n    ) -> Result<(), compositor::SurfaceError> {\n        match (self, renderer, surface) {\n            (Self::Primary(compositor), Renderer::Primary(renderer), Surface::Primary(surface)) => {\n                compositor.present(\n                    renderer,\n                    surface,\n                    viewport,\n                    background_color,\n                    on_pre_present,\n                )\n            }\n            (\n                Self::Secondary(compositor),\n                Renderer::Secondary(renderer),\n                Surface::Secondary(surface),\n            ) => compositor.present(\n                renderer,\n                surface,\n                viewport,\n                background_color,\n                on_pre_present,\n            ),\n            _ => unreachable!(),\n        }\n    }\n\n    fn screenshot(\n        &mut self,\n        renderer: &mut Self::Renderer,\n        viewport: &graphics::Viewport,\n        background_color: Color,\n    ) -> Vec<u8> {\n        match (self, renderer) {\n            (Self::Primary(compositor), Renderer::Primary(renderer)) => {\n                compositor.screenshot(renderer, viewport, background_color)\n            }\n            (Self::Secondary(compositor), Renderer::Secondary(renderer)) => {\n                compositor.screenshot(renderer, viewport, background_color)\n            }\n            _ => unreachable!(),\n        }\n    }\n}\n\n#[cfg(feature = \"wgpu-bare\")]\nimpl<A, B> iced_wgpu::primitive::Renderer for Renderer<A, B>\nwhere\n    A: iced_wgpu::primitive::Renderer,\n    B: core::Renderer,\n{\n    fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl iced_wgpu::Primitive) {\n        match self {\n            Self::Primary(renderer) => {\n                renderer.draw_primitive(bounds, primitive);\n            }\n            Self::Secondary(_) => {\n                log::warn!(\"Custom shader primitive is not supported with this renderer.\");\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"geometry\")]\nmod geometry {\n    use super::Renderer;\n    use crate::core::{Point, Radians, Rectangle, Size, Svg, Vector};\n    use crate::graphics::cache::{self, Cached};\n    use crate::graphics::geometry::{self, Fill, Image, Path, Stroke, Text};\n\n    impl<A, B> geometry::Renderer for Renderer<A, B>\n    where\n        A: geometry::Renderer,\n        B: geometry::Renderer,\n    {\n        type Geometry = Geometry<A::Geometry, B::Geometry>;\n        type Frame = Frame<A::Frame, B::Frame>;\n\n        fn new_frame(&self, bounds: Rectangle) -> Self::Frame {\n            match self {\n                Self::Primary(renderer) => Frame::Primary(renderer.new_frame(bounds)),\n                Self::Secondary(renderer) => Frame::Secondary(renderer.new_frame(bounds)),\n            }\n        }\n\n        fn draw_geometry(&mut self, geometry: Self::Geometry) {\n            match (self, geometry) {\n                (Self::Primary(renderer), Geometry::Primary(geometry)) => {\n                    renderer.draw_geometry(geometry);\n                }\n                (Self::Secondary(renderer), Geometry::Secondary(geometry)) => {\n                    renderer.draw_geometry(geometry);\n                }\n                _ => unreachable!(),\n            }\n        }\n    }\n\n    #[derive(Debug, Clone)]\n    pub enum Geometry<A, B> {\n        Primary(A),\n        Secondary(B),\n    }\n\n    impl<A, B> Cached for Geometry<A, B>\n    where\n        A: Cached,\n        B: Cached,\n    {\n        type Cache = Geometry<A::Cache, B::Cache>;\n\n        fn load(cache: &Self::Cache) -> Self {\n            match cache {\n                Geometry::Primary(cache) => Self::Primary(A::load(cache)),\n                Geometry::Secondary(cache) => Self::Secondary(B::load(cache)),\n            }\n        }\n\n        fn cache(self, group: cache::Group, previous: Option<Self::Cache>) -> Self::Cache {\n            match (self, previous) {\n                (Self::Primary(geometry), Some(Geometry::Primary(previous))) => {\n                    Geometry::Primary(geometry.cache(group, Some(previous)))\n                }\n                (Self::Primary(geometry), None) => Geometry::Primary(geometry.cache(group, None)),\n                (Self::Secondary(geometry), Some(Geometry::Secondary(previous))) => {\n                    Geometry::Secondary(geometry.cache(group, Some(previous)))\n                }\n                (Self::Secondary(geometry), None) => {\n                    Geometry::Secondary(geometry.cache(group, None))\n                }\n                _ => unreachable!(),\n            }\n        }\n    }\n\n    #[derive(Debug)]\n    pub enum Frame<A, B> {\n        Primary(A),\n        Secondary(B),\n    }\n\n    impl<A, B> geometry::frame::Backend for Frame<A, B>\n    where\n        A: geometry::frame::Backend,\n        B: geometry::frame::Backend,\n    {\n        type Geometry = Geometry<A::Geometry, B::Geometry>;\n\n        fn width(&self) -> f32 {\n            delegate!(self, frame, frame.width())\n        }\n\n        fn height(&self) -> f32 {\n            delegate!(self, frame, frame.height())\n        }\n\n        fn size(&self) -> Size {\n            delegate!(self, frame, frame.size())\n        }\n\n        fn center(&self) -> Point {\n            delegate!(self, frame, frame.center())\n        }\n\n        fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {\n            delegate!(self, frame, frame.fill(path, fill));\n        }\n\n        fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>) {\n            delegate!(self, frame, frame.fill_rectangle(top_left, size, fill));\n        }\n\n        fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {\n            delegate!(self, frame, frame.stroke(path, stroke));\n        }\n\n        fn stroke_rectangle<'a>(\n            &mut self,\n            top_left: Point,\n            size: Size,\n            stroke: impl Into<Stroke<'a>>,\n        ) {\n            delegate!(self, frame, frame.stroke_rectangle(top_left, size, stroke));\n        }\n\n        fn stroke_text<'a>(&mut self, text: impl Into<Text>, stroke: impl Into<Stroke<'a>>) {\n            delegate!(self, frame, frame.stroke_text(text, stroke));\n        }\n\n        fn fill_text(&mut self, text: impl Into<Text>) {\n            delegate!(self, frame, frame.fill_text(text));\n        }\n\n        fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {\n            delegate!(self, frame, frame.draw_image(bounds, image));\n        }\n\n        fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {\n            delegate!(self, frame, frame.draw_svg(bounds, svg));\n        }\n\n        fn push_transform(&mut self) {\n            delegate!(self, frame, frame.push_transform());\n        }\n\n        fn pop_transform(&mut self) {\n            delegate!(self, frame, frame.pop_transform());\n        }\n\n        fn draft(&mut self, bounds: Rectangle) -> Self {\n            match self {\n                Self::Primary(frame) => Self::Primary(frame.draft(bounds)),\n                Self::Secondary(frame) => Self::Secondary(frame.draft(bounds)),\n            }\n        }\n\n        fn paste(&mut self, frame: Self) {\n            match (self, frame) {\n                (Self::Primary(target), Self::Primary(source)) => {\n                    target.paste(source);\n                }\n                (Self::Secondary(target), Self::Secondary(source)) => {\n                    target.paste(source);\n                }\n                _ => unreachable!(),\n            }\n        }\n\n        fn translate(&mut self, translation: Vector) {\n            delegate!(self, frame, frame.translate(translation));\n        }\n\n        fn rotate(&mut self, angle: impl Into<Radians>) {\n            delegate!(self, frame, frame.rotate(angle));\n        }\n\n        fn scale(&mut self, scale: impl Into<f32>) {\n            delegate!(self, frame, frame.scale(scale));\n        }\n\n        fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {\n            delegate!(self, frame, frame.scale_nonuniform(scale));\n        }\n\n        fn into_geometry(self) -> Self::Geometry {\n            match self {\n                Frame::Primary(frame) => Geometry::Primary(frame.into_geometry()),\n                Frame::Secondary(frame) => Geometry::Secondary(frame.into_geometry()),\n            }\n        }\n    }\n}\n\nimpl<A, B> renderer::Headless for Renderer<A, B>\nwhere\n    A: renderer::Headless,\n    B: renderer::Headless,\n{\n    async fn new(settings: renderer::Settings, backend: Option<&str>) -> Option<Self> {\n        if let Some(renderer) = A::new(settings, backend).await {\n            return Some(Self::Primary(renderer));\n        }\n\n        B::new(settings, backend).await.map(Self::Secondary)\n    }\n\n    fn name(&self) -> String {\n        delegate!(self, renderer, renderer.name())\n    }\n\n    fn screenshot(\n        &mut self,\n        size: Size<u32>,\n        scale_factor: f32,\n        background_color: Color,\n    ) -> Vec<u8> {\n        match self {\n            crate::fallback::Renderer::Primary(renderer) => {\n                renderer.screenshot(size, scale_factor, background_color)\n            }\n            crate::fallback::Renderer::Secondary(renderer) => {\n                renderer.screenshot(size, scale_factor, background_color)\n            }\n        }\n    }\n}\n\nimpl<A, B> compositor::Default for Renderer<A, B>\nwhere\n    A: compositor::Default,\n    B: compositor::Default,\n{\n    type Compositor = Compositor<A::Compositor, B::Compositor>;\n}\n"
  },
  {
    "path": "renderer/src/lib.rs",
    "content": "//! The official renderer for iced.\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[cfg(feature = \"wgpu-bare\")]\npub use iced_wgpu as wgpu;\n\npub mod fallback;\n\npub use iced_graphics as graphics;\npub use iced_graphics::core;\n\n#[cfg(feature = \"geometry\")]\npub use iced_graphics::geometry;\n\n/// The default graphics renderer for [`iced`].\n///\n/// [`iced`]: https://github.com/iced-rs/iced\npub type Renderer = renderer::Renderer;\n\n/// The default graphics compositor for [`iced`].\n///\n/// [`iced`]: https://github.com/iced-rs/iced\npub type Compositor = renderer::Compositor;\n\n#[cfg(all(feature = \"wgpu-bare\", feature = \"tiny-skia\"))]\nmod renderer {\n    pub type Renderer = crate::fallback::Renderer<iced_wgpu::Renderer, iced_tiny_skia::Renderer>;\n\n    pub type Compositor = crate::fallback::Compositor<\n        iced_wgpu::window::Compositor,\n        iced_tiny_skia::window::Compositor,\n    >;\n}\n\n#[cfg(all(feature = \"wgpu-bare\", not(feature = \"tiny-skia\")))]\nmod renderer {\n    pub type Renderer = iced_wgpu::Renderer;\n    pub type Compositor = iced_wgpu::window::Compositor;\n}\n\n#[cfg(all(not(feature = \"wgpu-bare\"), feature = \"tiny-skia\"))]\nmod renderer {\n    pub type Renderer = iced_tiny_skia::Renderer;\n    pub type Compositor = iced_tiny_skia::window::Compositor;\n}\n\n#[cfg(not(any(feature = \"wgpu-bare\", feature = \"tiny-skia\")))]\nmod renderer {\n    #[cfg(not(debug_assertions))]\n    compile_error!(\n        \"Cannot compile `iced_renderer` in release mode \\\n        without a renderer feature enabled. \\\n        Enable either the `wgpu` or `tiny-skia` feature, or both.\"\n    );\n\n    pub type Renderer = ();\n    pub type Compositor = ();\n}\n"
  },
  {
    "path": "runtime/Cargo.toml",
    "content": "[package]\nname = \"iced_runtime\"\ndescription = \"A renderer-agnostic runtime for iced\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[features]\nselector = [\"dep:iced_selector\"]\nimage = [\"iced_core/image\"]\n\n[lints]\nworkspace = true\n\n[dependencies]\nbytes.workspace = true\niced_core.workspace = true\niced_futures.workspace = true\n\nraw-window-handle.workspace = true\nthiserror.workspace = true\n\nsipper.workspace = true\nsipper.optional = true\n\niced_selector.workspace = true\niced_selector.optional = true\n"
  },
  {
    "path": "runtime/README.md",
    "content": "# `iced_runtime`\n[![Documentation](https://docs.rs/iced_runtime/badge.svg)][documentation]\n[![Crates.io](https://img.shields.io/crates/v/iced_runtime.svg)](https://crates.io/crates/iced_runtime)\n[![License](https://img.shields.io/crates/l/iced_runtime.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)\n[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)\n\n`iced_runtime` takes [`iced_core`] and builds a runtime on top of it.\n\n[documentation]: https://docs.rs/iced_runtime\n[`iced_core`]: ../core\n[`iced_winit`]: ../winit\n[`druid`]: https://github.com/xi-editor/druid\n[`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle\n\n__Iced moves fast and the `master` branch can contain breaking changes!__ If\nyou want to learn about a specific release, check out [the release list].\n\n[the release list]: https://github.com/iced-rs/iced/releases\n"
  },
  {
    "path": "runtime/src/clipboard.rs",
    "content": "//! Access the clipboard.\nuse crate::core::clipboard::{Content, Error, Kind};\nuse crate::futures::futures::channel::oneshot;\nuse crate::task::{self, Task};\n\nuse std::path::PathBuf;\nuse std::sync::Arc;\n\n/// A clipboard action to be performed by some [`Task`].\n///\n/// [`Task`]: crate::Task\n#[derive(Debug)]\npub enum Action {\n    /// Read the clipboard and produce `T` with the result.\n    Read {\n        /// The [`Kind`] of [`Content`] to read.\n        kind: Kind,\n        /// The channel to send the read contents.\n        channel: oneshot::Sender<Result<Content, Error>>,\n    },\n\n    /// Write the given contents to the clipboard.\n    Write {\n        /// The [`Content`] to be written.\n        content: Content,\n\n        /// The channel to send the write result.\n        channel: oneshot::Sender<Result<(), Error>>,\n    },\n}\n\n/// Read the given [`Kind`] of [`Content`] from the clipboard.\npub fn read(kind: Kind) -> Task<Result<Arc<Content>, Error>> {\n    task::oneshot(|channel| crate::Action::Clipboard(Action::Read { kind, channel }))\n        .map(|result| result.map(Arc::new))\n}\n\n/// Read the current text contents of the clipboard.\npub fn read_text() -> Task<Result<Arc<String>, Error>> {\n    task::oneshot(|channel| {\n        crate::Action::Clipboard(Action::Read {\n            kind: Kind::Text,\n            channel,\n        })\n    })\n    .map(|result| {\n        let Ok(Content::Text(text)) = result else {\n            return Err(Error::ContentNotAvailable);\n        };\n\n        Ok(Arc::new(text))\n    })\n}\n\n/// Read the current HTML contents of the clipboard.\npub fn read_html() -> Task<Result<Arc<String>, Error>> {\n    task::oneshot(|channel| {\n        crate::Action::Clipboard(Action::Read {\n            kind: Kind::Html,\n            channel,\n        })\n    })\n    .map(|result| {\n        let Ok(Content::Html(html)) = result else {\n            return Err(Error::ContentNotAvailable);\n        };\n\n        Ok(Arc::new(html))\n    })\n}\n\n/// Read the current file paths of the clipboard.\npub fn read_files() -> Task<Result<Arc<[PathBuf]>, Error>> {\n    task::oneshot(|channel| {\n        crate::Action::Clipboard(Action::Read {\n            kind: Kind::Files,\n            channel,\n        })\n    })\n    .map(|result| {\n        let Ok(Content::Files(files)) = result else {\n            return Err(Error::ContentNotAvailable);\n        };\n\n        Ok(Arc::from(files))\n    })\n}\n\n/// Read the current [`Image`](crate::core::clipboard::Image) of the clipboard.\n#[cfg(feature = \"image\")]\npub fn read_image() -> Task<Result<crate::core::clipboard::Image, Error>> {\n    task::oneshot(|channel| {\n        crate::Action::Clipboard(Action::Read {\n            kind: Kind::Image,\n            channel,\n        })\n    })\n    .map(|result| {\n        let Ok(Content::Image(image)) = result else {\n            return Err(Error::ContentNotAvailable);\n        };\n\n        Ok(image)\n    })\n}\n\n/// Write the given [`Content`] to the clipboard.\npub fn write(content: impl Into<Content>) -> Task<Result<(), Error>> {\n    let content = content.into();\n\n    task::oneshot(|channel| crate::Action::Clipboard(Action::Write { content, channel }))\n}\n"
  },
  {
    "path": "runtime/src/font.rs",
    "content": "//! Load and use fonts.\nuse crate::core::Pixels;\nuse crate::core::font::{Error, Family, Font};\nuse crate::futures::futures::channel::oneshot;\nuse crate::task::{self, Task};\n\nuse std::borrow::Cow;\nuse std::fmt;\n\n/// A font action.\npub enum Action {\n    /// Load a font from its bytes.\n    Load {\n        /// The bytes of the font to load.\n        bytes: Cow<'static, [u8]>,\n        /// The channel to send back the load result.\n        channel: oneshot::Sender<Result<(), Error>>,\n    },\n\n    /// Lists all system font families.\n    List {\n        /// The channel to send back the list result.\n        channel: oneshot::Sender<Result<Vec<Family>, Error>>,\n    },\n\n    /// Sets the new font defaults for the running application.\n    SetDefaults {\n        /// The new default [`Font`].\n        font: Font,\n        /// The new default text size.\n        text_size: Pixels,\n    },\n}\n\nimpl fmt::Debug for Action {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Load { .. } => f.write_str(\"Load\"),\n            Self::List { .. } => f.write_str(\"List\"),\n            Self::SetDefaults { font, text_size } => f\n                .debug_struct(\"SetDefaults\")\n                .field(\"font\", font)\n                .field(\"text_size\", text_size)\n                .finish(),\n        }\n    }\n}\n\n/// Load a font from its bytes.\npub fn load(bytes: impl Into<Cow<'static, [u8]>>) -> Task<Result<(), Error>> {\n    task::oneshot(|channel| {\n        crate::Action::Font(Action::Load {\n            bytes: bytes.into(),\n            channel,\n        })\n    })\n}\n\n/// Lists all the available font families in the system.\npub fn list() -> Task<Result<Vec<Family>, Error>> {\n    task::oneshot(|channel| crate::Action::Font(Action::List { channel }))\n}\n\n/// Sets a new default [`Font`] and text size for the running application.\npub fn set_defaults<Message>(font: Font, text_size: impl Into<Pixels>) -> Task<Message> {\n    task::effect(crate::Action::Font(Action::SetDefaults {\n        font,\n        text_size: text_size.into(),\n    }))\n}\n"
  },
  {
    "path": "runtime/src/image.rs",
    "content": "//! Allocate images explicitly to control presentation.\nuse crate::core::image::Handle;\nuse crate::futures::futures::channel::oneshot;\nuse crate::task::{self, Task};\n\npub use crate::core::image::{Allocation, Error};\n\n/// An image action.\n#[derive(Debug)]\npub enum Action {\n    /// Allocates the given [`Handle`].\n    Allocate(Handle, oneshot::Sender<Result<Allocation, Error>>),\n}\n\n/// Allocates an image [`Handle`].\n///\n/// When you obtain an [`Allocation`] explicitly, you get the guarantee\n/// that using a [`Handle`] will draw the corresponding image immediately\n/// in the next frame.\npub fn allocate(handle: impl Into<Handle>) -> Task<Result<Allocation, Error>> {\n    task::oneshot(|sender| crate::Action::Image(Action::Allocate(handle.into(), sender)))\n}\n"
  },
  {
    "path": "runtime/src/keyboard.rs",
    "content": "//! Track keyboard events.\npub use iced_core::keyboard::*;\n"
  },
  {
    "path": "runtime/src/lib.rs",
    "content": "//! A renderer-agnostic native GUI runtime.\n//!\n//! ![The native path of the Iced ecosystem](https://github.com/iced-rs/iced/blob/master/docs/graphs/native.png?raw=true)\n//!\n//! `iced_runtime` takes [`iced_core`] and builds a native runtime on top of it.\n//!\n//! [`iced_core`]: https://github.com/iced-rs/iced/tree/master/core\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg\"\n)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\npub mod clipboard;\npub mod font;\npub mod image;\npub mod keyboard;\npub mod system;\npub mod task;\npub mod user_interface;\npub mod widget;\npub mod window;\n\npub use iced_core as core;\npub use iced_futures as futures;\n\npub use task::Task;\npub use user_interface::UserInterface;\npub use window::Window;\n\nuse crate::core::Event;\n\nuse std::fmt;\n\n/// An action that the iced runtime can perform.\npub enum Action<T> {\n    /// Output some value.\n    Output(T),\n\n    /// Run a widget operation.\n    Widget(Box<dyn core::widget::Operation>),\n\n    /// Run a clipboard action.\n    Clipboard(clipboard::Action),\n\n    /// Run a window action.\n    Window(window::Action),\n\n    /// Run a system action.\n    System(system::Action),\n\n    /// Run a font action.\n    Font(font::Action),\n\n    /// Run an image action.\n    Image(image::Action),\n\n    /// Produce an event.\n    Event {\n        /// The [`window::Id`](core::window::Id) of the event.\n        window: core::window::Id,\n        /// The [`Event`] to be produced.\n        event: Event,\n    },\n\n    /// Poll any resources that may have pending computations.\n    Tick,\n\n    /// Recreate all user interfaces and redraw all windows.\n    Reload,\n\n    /// Exits the runtime.\n    ///\n    /// This will normally close any application windows and\n    /// terminate the runtime loop.\n    Exit,\n}\n\nimpl<T> Action<T> {\n    /// Creates a new [`Action::Widget`] with the given [`widget::Operation`](core::widget::Operation).\n    pub fn widget(operation: impl core::widget::Operation + 'static) -> Self {\n        Self::Widget(Box::new(operation))\n    }\n\n    fn output<O>(self) -> Result<T, Action<O>> {\n        match self {\n            Action::Output(output) => Ok(output),\n            Action::Widget(operation) => Err(Action::Widget(operation)),\n            Action::Clipboard(action) => Err(Action::Clipboard(action)),\n            Action::Window(action) => Err(Action::Window(action)),\n            Action::System(action) => Err(Action::System(action)),\n            Action::Font(action) => Err(Action::Font(action)),\n            Action::Image(action) => Err(Action::Image(action)),\n            Action::Event { window, event } => Err(Action::Event { window, event }),\n            Action::Tick => Err(Action::Tick),\n            Action::Reload => Err(Action::Reload),\n            Action::Exit => Err(Action::Exit),\n        }\n    }\n}\n\nimpl<T> fmt::Debug for Action<T>\nwhere\n    T: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Action::Output(output) => write!(f, \"Action::Output({output:?})\"),\n            Action::Widget { .. } => {\n                write!(f, \"Action::Widget\")\n            }\n            Action::Clipboard(action) => {\n                write!(f, \"Action::Clipboard({action:?})\")\n            }\n            Action::Window(_) => write!(f, \"Action::Window\"),\n            Action::System(action) => write!(f, \"Action::System({action:?})\"),\n            Action::Font(action) => {\n                write!(f, \"Action::Font({action:?})\")\n            }\n            Action::Image(_) => write!(f, \"Action::Image\"),\n            Action::Event { window, event } => write!(\n                f,\n                \"Action::Event {{ window: {window:?}, event: {event:?} }}\"\n            ),\n            Action::Tick => write!(f, \"Action::Tick\"),\n            Action::Reload => write!(f, \"Action::Reload\"),\n            Action::Exit => write!(f, \"Action::Exit\"),\n        }\n    }\n}\n\n/// Creates a [`Task`] that exits the iced runtime.\n///\n/// This will normally close any application windows and\n/// terminate the runtime loop.\npub fn exit<T>() -> Task<T> {\n    task::effect(Action::Exit)\n}\n"
  },
  {
    "path": "runtime/src/system.rs",
    "content": "//! Access the native system.\nuse crate::core::theme;\nuse crate::futures::futures::channel::oneshot;\nuse crate::futures::subscription::{self, Subscription};\nuse crate::task::{self, Task};\n\n/// An operation to be performed on the system.\n#[derive(Debug)]\npub enum Action {\n    /// Send available system information.\n    GetInformation(oneshot::Sender<Information>),\n\n    /// Send the current system theme mode.\n    GetTheme(oneshot::Sender<theme::Mode>),\n\n    /// Notify to the runtime that the system theme has changed.\n    NotifyTheme(theme::Mode),\n}\n\n/// Contains information about the system (e.g. system name, processor, memory, graphics adapter).\n#[derive(Clone, Debug)]\npub struct Information {\n    /// The operating system name\n    pub system_name: Option<String>,\n    /// Operating system kernel version\n    pub system_kernel: Option<String>,\n    /// Long operating system version\n    ///\n    /// Examples:\n    /// - MacOS 10.15 Catalina\n    /// - Windows 10 Pro\n    /// - Ubuntu 20.04 LTS (Focal Fossa)\n    pub system_version: Option<String>,\n    /// Short operating system version number\n    pub system_short_version: Option<String>,\n    /// Detailed processor model information\n    pub cpu_brand: String,\n    /// The number of physical cores on the processor\n    pub cpu_cores: Option<usize>,\n    /// Total RAM size, in bytes\n    pub memory_total: u64,\n    /// Memory used by this process, in bytes\n    pub memory_used: Option<u64>,\n    /// Underlying graphics backend for rendering\n    pub graphics_backend: String,\n    /// Model information for the active graphics adapter\n    pub graphics_adapter: String,\n}\n\n/// Returns available system information.\npub fn information() -> Task<Information> {\n    task::oneshot(|channel| crate::Action::System(Action::GetInformation(channel)))\n}\n\n/// Returns the current system theme.\npub fn theme() -> Task<theme::Mode> {\n    task::oneshot(|sender| crate::Action::System(Action::GetTheme(sender)))\n}\n\n/// Subscribes to system theme changes.\npub fn theme_changes() -> Subscription<theme::Mode> {\n    #[derive(Hash)]\n    struct ThemeChanges;\n\n    subscription::filter_map(ThemeChanges, |event| {\n        let subscription::Event::SystemThemeChanged(mode) = event else {\n            return None;\n        };\n\n        Some(mode)\n    })\n}\n"
  },
  {
    "path": "runtime/src/task.rs",
    "content": "//! Create runtime tasks.\nuse crate::Action;\nuse crate::core::widget;\nuse crate::futures::futures::channel::mpsc;\nuse crate::futures::futures::channel::oneshot;\nuse crate::futures::futures::future::{self, FutureExt};\nuse crate::futures::futures::stream::{self, Stream, StreamExt};\nuse crate::futures::{BoxStream, MaybeSend, boxed_stream};\n\nuse std::convert::Infallible;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::task;\nuse std::thread;\n\n#[cfg(feature = \"sipper\")]\n#[doc(no_inline)]\npub use sipper::{Never, Sender, Sipper, Straw, sipper, stream};\n\n/// A set of concurrent actions to be performed by the iced runtime.\n///\n/// A [`Task`] _may_ produce a bunch of values of type `T`.\n#[must_use = \"`Task` must be returned to the runtime to take effect; normally in your `update` or `new` functions.\"]\npub struct Task<T> {\n    stream: Option<BoxStream<Action<T>>>,\n    units: usize,\n}\n\nimpl<T> Task<T> {\n    /// Creates a [`Task`] that does nothing.\n    pub fn none() -> Self {\n        Self {\n            stream: None,\n            units: 0,\n        }\n    }\n\n    /// Creates a new [`Task`] that instantly produces the given value.\n    pub fn done(value: T) -> Self\n    where\n        T: MaybeSend + 'static,\n    {\n        Self {\n            stream: Some(boxed_stream(stream::once(future::ready(Action::Output(\n                value,\n            ))))),\n            units: 0,\n        }\n    }\n\n    /// Creates a [`Task`] that runs the given [`Future`] to completion and maps its\n    /// output with the given closure.\n    pub fn perform<A>(\n        future: impl Future<Output = A> + MaybeSend + 'static,\n        f: impl FnOnce(A) -> T + MaybeSend + 'static,\n    ) -> Self\n    where\n        T: MaybeSend + 'static,\n        A: MaybeSend + 'static,\n    {\n        Self::future(future.map(f))\n    }\n\n    /// Creates a [`Task`] that runs the given [`Stream`] to completion and maps each\n    /// item with the given closure.\n    pub fn run<A>(\n        stream: impl Stream<Item = A> + MaybeSend + 'static,\n        f: impl Fn(A) -> T + MaybeSend + 'static,\n    ) -> Self\n    where\n        T: 'static,\n    {\n        Self::stream(stream.map(f))\n    }\n\n    /// Creates a [`Task`] that runs the given [`Sipper`] to completion, mapping\n    /// progress with the first closure and the output with the second one.\n    #[cfg(feature = \"sipper\")]\n    pub fn sip<S>(\n        sipper: S,\n        on_progress: impl FnMut(S::Progress) -> T + MaybeSend + 'static,\n        on_output: impl FnOnce(<S as Future>::Output) -> T + MaybeSend + 'static,\n    ) -> Self\n    where\n        S: sipper::Core + MaybeSend + 'static,\n        T: MaybeSend + 'static,\n    {\n        Self::stream(stream(sipper::sipper(move |sender| async move {\n            on_output(sipper.with(on_progress).run(sender).await)\n        })))\n    }\n\n    /// Combines the given tasks and produces a single [`Task`] that will run all of them\n    /// in parallel.\n    pub fn batch(tasks: impl IntoIterator<Item = Self>) -> Self\n    where\n        T: 'static,\n    {\n        let mut select_all = stream::SelectAll::new();\n        let mut units = 0;\n\n        for task in tasks.into_iter() {\n            if let Some(stream) = task.stream {\n                select_all.push(stream);\n            }\n\n            units += task.units;\n        }\n\n        Self {\n            stream: Some(boxed_stream(select_all)),\n            units,\n        }\n    }\n\n    /// Maps the output of a [`Task`] with the given closure.\n    pub fn map<O>(self, mut f: impl FnMut(T) -> O + MaybeSend + 'static) -> Task<O>\n    where\n        T: MaybeSend + 'static,\n        O: MaybeSend + 'static,\n    {\n        self.then(move |output| Task::done(f(output)))\n    }\n\n    /// Performs a new [`Task`] for every output of the current [`Task`] using the\n    /// given closure.\n    ///\n    /// This is the monadic interface of [`Task`]—analogous to [`Future`] and\n    /// [`Stream`].\n    pub fn then<O>(self, mut f: impl FnMut(T) -> Task<O> + MaybeSend + 'static) -> Task<O>\n    where\n        T: MaybeSend + 'static,\n        O: MaybeSend + 'static,\n    {\n        Task {\n            stream: match self.stream {\n                None => None,\n                Some(stream) => Some(boxed_stream(stream.flat_map(move |action| {\n                    match action.output() {\n                        Ok(output) => f(output)\n                            .stream\n                            .unwrap_or_else(|| boxed_stream(stream::empty())),\n                        Err(action) => boxed_stream(stream::once(async move { action })),\n                    }\n                }))),\n            },\n            units: self.units,\n        }\n    }\n\n    /// Chains a new [`Task`] to be performed once the current one finishes completely.\n    pub fn chain(self, task: Self) -> Self\n    where\n        T: 'static,\n    {\n        match self.stream {\n            None => task,\n            Some(first) => match task.stream {\n                None => Self {\n                    stream: Some(first),\n                    units: self.units,\n                },\n                Some(second) => Self {\n                    stream: Some(boxed_stream(first.chain(second))),\n                    units: self.units + task.units,\n                },\n            },\n        }\n    }\n\n    /// Creates a new [`Task`] that collects all the output of the current one into a [`Vec`].\n    pub fn collect(self) -> Task<Vec<T>>\n    where\n        T: MaybeSend + 'static,\n    {\n        match self.stream {\n            None => Task::done(Vec::new()),\n            Some(stream) => Task {\n                stream: Some(boxed_stream(\n                    stream::unfold(\n                        (stream, Some(Vec::new())),\n                        move |(mut stream, outputs)| async move {\n                            let mut outputs = outputs?;\n\n                            let Some(action) = stream.next().await else {\n                                return Some((Some(Action::Output(outputs)), (stream, None)));\n                            };\n\n                            match action.output() {\n                                Ok(output) => {\n                                    outputs.push(output);\n\n                                    Some((None, (stream, Some(outputs))))\n                                }\n                                Err(action) => Some((Some(action), (stream, Some(outputs)))),\n                            }\n                        },\n                    )\n                    .filter_map(future::ready),\n                )),\n                units: self.units,\n            },\n        }\n    }\n\n    /// Creates a new [`Task`] that discards the result of the current one.\n    ///\n    /// Useful if you only care about the side effects of a [`Task`].\n    pub fn discard<O>(self) -> Task<O>\n    where\n        T: MaybeSend + 'static,\n        O: MaybeSend + 'static,\n    {\n        self.then(|_| Task::none())\n    }\n\n    /// Creates a new [`Task`] that can be aborted with the returned [`Handle`].\n    pub fn abortable(self) -> (Self, Handle)\n    where\n        T: 'static,\n    {\n        let (stream, handle) = match self.stream {\n            Some(stream) => {\n                let (stream, handle) = stream::abortable(stream);\n\n                (Some(boxed_stream(stream)), InternalHandle::Manual(handle))\n            }\n            None => (\n                None,\n                InternalHandle::Manual(stream::AbortHandle::new_pair().0),\n            ),\n        };\n\n        (\n            Self {\n                stream,\n                units: self.units,\n            },\n            Handle { internal: handle },\n        )\n    }\n\n    /// Creates a new [`Task`] that runs the given [`Future`] and produces\n    /// its output.\n    pub fn future(future: impl Future<Output = T> + MaybeSend + 'static) -> Self\n    where\n        T: 'static,\n    {\n        Self::stream(stream::once(future))\n    }\n\n    /// Creates a new [`Task`] that runs the given [`Stream`] and produces\n    /// each of its items.\n    pub fn stream(stream: impl Stream<Item = T> + MaybeSend + 'static) -> Self\n    where\n        T: 'static,\n    {\n        Self {\n            stream: Some(boxed_stream(\n                stream::once(yield_now())\n                    .filter_map(|_| async { None })\n                    .chain(stream.map(Action::Output)),\n            )),\n            units: 1,\n        }\n    }\n\n    /// Returns the amount of work \"units\" of the [`Task`].\n    pub fn units(&self) -> usize {\n        self.units\n    }\n}\n\nimpl<T> std::fmt::Debug for Task<T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(&format!(\"Task<{}>\", std::any::type_name::<T>()))\n            .field(\"units\", &self.units)\n            .finish()\n    }\n}\n\n/// A handle to a [`Task`] that can be used for aborting it.\n#[derive(Debug, Clone)]\npub struct Handle {\n    internal: InternalHandle,\n}\n\n#[derive(Debug, Clone)]\nenum InternalHandle {\n    Manual(stream::AbortHandle),\n    AbortOnDrop(Arc<stream::AbortHandle>),\n}\n\nimpl InternalHandle {\n    pub fn as_ref(&self) -> &stream::AbortHandle {\n        match self {\n            InternalHandle::Manual(handle) => handle,\n            InternalHandle::AbortOnDrop(handle) => handle.as_ref(),\n        }\n    }\n}\n\nimpl Handle {\n    /// Aborts the [`Task`] of this [`Handle`].\n    pub fn abort(&self) {\n        self.internal.as_ref().abort();\n    }\n\n    /// Returns a new [`Handle`] that will call [`Handle::abort`] whenever\n    /// all of its instances are dropped.\n    ///\n    /// If a [`Handle`] is cloned, [`Handle::abort`] will only be called\n    /// once all of the clones are dropped.\n    ///\n    /// This can be really useful if you do not want to worry about calling\n    /// [`Handle::abort`] yourself.\n    pub fn abort_on_drop(self) -> Self {\n        match &self.internal {\n            InternalHandle::Manual(handle) => Self {\n                internal: InternalHandle::AbortOnDrop(Arc::new(handle.clone())),\n            },\n            InternalHandle::AbortOnDrop(_) => self,\n        }\n    }\n\n    /// Returns `true` if the [`Task`] of this [`Handle`] has been aborted.\n    pub fn is_aborted(&self) -> bool {\n        self.internal.as_ref().is_aborted()\n    }\n}\n\nimpl Drop for Handle {\n    fn drop(&mut self) {\n        if let InternalHandle::AbortOnDrop(handle) = &mut self.internal {\n            let handle = std::mem::replace(handle, Arc::new(stream::AbortHandle::new_pair().0));\n\n            if let Some(handle) = Arc::into_inner(handle) {\n                handle.abort();\n            }\n        }\n    }\n}\n\nimpl<T> Task<Option<T>> {\n    /// Executes a new [`Task`] after this one, only when it produces `Some` value.\n    ///\n    /// The value is provided to the closure to create the subsequent [`Task`].\n    pub fn and_then<A>(self, f: impl Fn(T) -> Task<A> + MaybeSend + 'static) -> Task<A>\n    where\n        T: MaybeSend + 'static,\n        A: MaybeSend + 'static,\n    {\n        self.then(move |option| option.map_or_else(Task::none, &f))\n    }\n}\n\nimpl<T, E> Task<Result<T, E>> {\n    /// Executes a new [`Task`] after this one, only when it succeeds with an `Ok` value.\n    ///\n    /// The success value is provided to the closure to create the subsequent [`Task`].\n    pub fn and_then<A>(\n        self,\n        f: impl Fn(T) -> Task<Result<A, E>> + MaybeSend + 'static,\n    ) -> Task<Result<A, E>>\n    where\n        T: MaybeSend + 'static,\n        E: MaybeSend + 'static,\n        A: MaybeSend + 'static,\n    {\n        self.then(move |result| result.map_or_else(|error| Task::done(Err(error)), &f))\n    }\n\n    /// Maps the error type of this [`Task`] to a different one using the given\n    /// function.\n    pub fn map_err<E2>(self, f: impl Fn(E) -> E2 + MaybeSend + 'static) -> Task<Result<T, E2>>\n    where\n        T: MaybeSend + 'static,\n        E: MaybeSend + 'static,\n        E2: MaybeSend + 'static,\n    {\n        self.map(move |result| result.map_err(&f))\n    }\n}\n\nimpl<T> Default for Task<T> {\n    fn default() -> Self {\n        Self::none()\n    }\n}\n\nimpl<T> From<()> for Task<T> {\n    fn from(_value: ()) -> Self {\n        Self::none()\n    }\n}\n\n/// Creates a new [`Task`] that runs the given [`widget::Operation`] and produces\n/// its output.\npub fn widget<T>(operation: impl widget::Operation<T> + 'static) -> Task<T>\nwhere\n    T: Send + 'static,\n{\n    channel(move |sender| {\n        let operation = widget::operation::map(Box::new(operation), move |value| {\n            let _ = sender.clone().try_send(value);\n        });\n\n        Action::Widget(Box::new(operation))\n    })\n}\n\n/// Creates a new [`Task`] that executes the [`Action`] returned by the closure and\n/// produces the value fed to the [`oneshot::Sender`].\npub fn oneshot<T>(f: impl FnOnce(oneshot::Sender<T>) -> Action<T>) -> Task<T>\nwhere\n    T: MaybeSend + 'static,\n{\n    let (sender, receiver) = oneshot::channel();\n\n    let action = f(sender);\n\n    Task {\n        stream: Some(boxed_stream(\n            stream::once(async move { action }).chain(\n                receiver\n                    .into_stream()\n                    .filter_map(|result| async move { Some(Action::Output(result.ok()?)) }),\n            ),\n        )),\n        units: 1,\n    }\n}\n\n/// Creates a new [`Task`] that executes the [`Action`] returned by the closure and\n/// produces the values fed to the [`mpsc::Sender`].\npub fn channel<T>(f: impl FnOnce(mpsc::Sender<T>) -> Action<T>) -> Task<T>\nwhere\n    T: MaybeSend + 'static,\n{\n    let (sender, receiver) = mpsc::channel(1);\n\n    let action = f(sender);\n\n    Task {\n        stream: Some(boxed_stream(\n            stream::once(async move { action })\n                .chain(receiver.map(|result| Action::Output(result))),\n        )),\n        units: 1,\n    }\n}\n\n/// Creates a new [`Task`] that executes the given [`Action`] and produces no output.\npub fn effect<T>(action: impl Into<Action<Infallible>>) -> Task<T> {\n    let action = action.into();\n\n    Task {\n        stream: Some(boxed_stream(stream::once(async move {\n            action.output().expect_err(\"no output\")\n        }))),\n        units: 1,\n    }\n}\n\n/// Returns the underlying [`Stream`] of the [`Task`].\npub fn into_stream<T>(task: Task<T>) -> Option<BoxStream<Action<T>>> {\n    task.stream\n}\n\n/// Creates a new [`Task`] that will run the given closure in a new thread.\n///\n/// Any data sent by the closure through the [`mpsc::Sender`] will be produced\n/// by the [`Task`].\npub fn blocking<T>(f: impl FnOnce(mpsc::Sender<T>) + Send + 'static) -> Task<T>\nwhere\n    T: Send + 'static,\n{\n    let (sender, receiver) = mpsc::channel(1);\n\n    let _ = thread::spawn(move || {\n        f(sender);\n    });\n\n    Task::stream(receiver)\n}\n\n/// Creates a new [`Task`] that will run the given closure that can fail in a new\n/// thread.\n///\n/// Any data sent by the closure through the [`mpsc::Sender`] will be produced\n/// by the [`Task`].\npub fn try_blocking<T, E>(\n    f: impl FnOnce(mpsc::Sender<T>) -> Result<(), E> + Send + 'static,\n) -> Task<Result<T, E>>\nwhere\n    T: Send + 'static,\n    E: Send + 'static,\n{\n    let (sender, receiver) = mpsc::channel(1);\n    let (error_sender, error_receiver) = oneshot::channel();\n\n    let _ = thread::spawn(move || {\n        if let Err(error) = f(sender) {\n            let _ = error_sender.send(Err(error));\n        }\n    });\n\n    Task::stream(stream::select(\n        receiver.map(Ok),\n        stream::once(error_receiver).filter_map(async |result| result.ok()),\n    ))\n}\n\nasync fn yield_now() {\n    struct YieldNow {\n        yielded: bool,\n    }\n\n    impl Future for YieldNow {\n        type Output = ();\n\n        fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<()> {\n            if self.yielded {\n                return task::Poll::Ready(());\n            }\n\n            self.yielded = true;\n\n            cx.waker().wake_by_ref();\n\n            task::Poll::Pending\n        }\n    }\n\n    YieldNow { yielded: false }.await;\n}\n"
  },
  {
    "path": "runtime/src/user_interface.rs",
    "content": "//! Implement your own event loop to drive a user interface.\nuse crate::core::event::{self, Event};\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget;\nuse crate::core::window;\nuse crate::core::{Clipboard, Element, InputMethod, Layout, Rectangle, Shell, Size, Vector};\n\n/// A set of interactive graphical elements with a specific [`Layout`].\n///\n/// It can be updated and drawn.\n///\n/// Iced tries to avoid dictating how to write your event loop. You are in\n/// charge of using this type in your system in any way you want.\n///\n/// # Example\n/// The [`integration`] example uses a [`UserInterface`] to integrate Iced in an\n/// existing graphical application.\n///\n/// [`integration`]: https://github.com/iced-rs/iced/tree/master/examples/integration\npub struct UserInterface<'a, Message, Theme, Renderer> {\n    root: Element<'a, Message, Theme, Renderer>,\n    base: layout::Node,\n    state: widget::Tree,\n    overlay: Option<Overlay>,\n    bounds: Size,\n}\n\nstruct Overlay {\n    layout: layout::Node,\n    interaction: mouse::Interaction,\n}\n\nimpl<'a, Message, Theme, Renderer> UserInterface<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    /// Builds a user interface for an [`Element`].\n    ///\n    /// It is able to avoid expensive computations when using a [`Cache`]\n    /// obtained from a previous instance of a [`UserInterface`].\n    ///\n    /// # Example\n    /// Imagine we want to build a [`UserInterface`] for\n    /// [the counter example that we previously wrote](index.html#usage). Here\n    /// is naive way to set up our application loop:\n    ///\n    /// ```no_run\n    /// # mod iced_wgpu {\n    /// #     pub type Renderer = ();\n    /// # }\n    /// #\n    /// # pub struct Counter;\n    /// #\n    /// # impl Counter {\n    /// #     pub fn new() -> Self { Counter }\n    /// #     pub fn view(&self) -> iced_core::Element<(), (), Renderer> { unimplemented!() }\n    /// #     pub fn update(&mut self, _: ()) {}\n    /// # }\n    /// use iced_runtime::core::Size;\n    /// use iced_runtime::user_interface::{self, UserInterface};\n    /// use iced_wgpu::Renderer;\n    ///\n    /// // Initialization\n    /// let mut counter = Counter::new();\n    /// let mut cache = user_interface::Cache::new();\n    /// let mut renderer = Renderer::default();\n    /// let mut window_size = Size::new(1024.0, 768.0);\n    ///\n    /// // Application loop\n    /// loop {\n    ///     // Process system events here...\n    ///\n    ///     // Build the user interface\n    ///     let user_interface = UserInterface::build(\n    ///         counter.view(),\n    ///         window_size,\n    ///         cache,\n    ///         &mut renderer,\n    ///     );\n    ///\n    ///     // Update and draw the user interface here...\n    ///     // ...\n    ///\n    ///     // Obtain the cache for the next iteration\n    ///     cache = user_interface.into_cache();\n    /// }\n    /// ```\n    pub fn build<E: Into<Element<'a, Message, Theme, Renderer>>>(\n        root: E,\n        bounds: Size,\n        cache: Cache,\n        renderer: &mut Renderer,\n    ) -> Self {\n        let mut root = root.into();\n\n        let Cache { mut state } = cache;\n        state.diff(root.as_widget());\n\n        let base = root.as_widget_mut().layout(\n            &mut state,\n            renderer,\n            &layout::Limits::new(Size::ZERO, bounds),\n        );\n\n        UserInterface {\n            root,\n            base,\n            state,\n            overlay: None,\n            bounds,\n        }\n    }\n\n    /// Updates the [`UserInterface`] by processing each provided [`Event`].\n    ///\n    /// It returns __messages__ that may have been produced as a result of user\n    /// interactions. You should feed these to your __update logic__.\n    ///\n    /// # Example\n    /// Let's allow our [counter](index.html#usage) to change state by\n    /// completing [the previous example](#example):\n    ///\n    /// ```no_run\n    /// # mod iced_wgpu {\n    /// #     pub type Renderer = ();\n    /// # }\n    /// #\n    /// # pub struct Counter;\n    /// #\n    /// # impl Counter {\n    /// #     pub fn new() -> Self { Counter }\n    /// #     pub fn view(&self) -> iced_core::Element<(), (), Renderer> { unimplemented!() }\n    /// #     pub fn update(&mut self, _: ()) {}\n    /// # }\n    /// use iced_runtime::core::mouse;\n    /// use iced_runtime::core::Size;\n    /// use iced_runtime::user_interface::{self, UserInterface};\n    /// use iced_wgpu::Renderer;\n    ///\n    /// let mut counter = Counter::new();\n    /// let mut cache = user_interface::Cache::new();\n    /// let mut renderer = Renderer::default();\n    /// let mut window_size = Size::new(1024.0, 768.0);\n    /// let mut cursor = mouse::Cursor::default();\n    ///\n    /// // Initialize our event storage\n    /// let mut events = Vec::new();\n    /// let mut messages = Vec::new();\n    ///\n    /// loop {\n    ///     // Obtain system events...\n    ///\n    ///     let mut user_interface = UserInterface::build(\n    ///         counter.view(),\n    ///         window_size,\n    ///         cache,\n    ///         &mut renderer,\n    ///     );\n    ///\n    ///     // Update the user interface\n    ///     let (state, event_statuses) = user_interface.update(\n    ///         &events,\n    ///         cursor,\n    ///         &mut renderer,\n    ///         &mut messages\n    ///     );\n    ///\n    ///     cache = user_interface.into_cache();\n    ///\n    ///     // Process the produced messages\n    ///     for message in messages.drain(..) {\n    ///         counter.update(message);\n    ///     }\n    /// }\n    /// ```\n    pub fn update(\n        &mut self,\n        events: &[Event],\n        cursor: mouse::Cursor,\n        renderer: &mut Renderer,\n        messages: &mut Vec<Message>,\n    ) -> (State, Vec<event::Status>) {\n        let mut outdated = false;\n        let mut redraw_request = window::RedrawRequest::Wait;\n        let mut input_method = InputMethod::Disabled;\n        let mut clipboard = Clipboard::new();\n        let mut has_layout_changed = false;\n        let viewport = Rectangle::with_size(self.bounds);\n\n        let mut maybe_overlay = self\n            .root\n            .as_widget_mut()\n            .overlay(\n                &mut self.state,\n                Layout::new(&self.base),\n                renderer,\n                &viewport,\n                Vector::ZERO,\n            )\n            .map(overlay::Nested::new);\n\n        let (base_cursor, overlay_statuses, overlay_interaction) = if maybe_overlay.is_some() {\n            let bounds = self.bounds;\n\n            let mut overlay = maybe_overlay.as_mut().unwrap();\n            let mut layout = overlay.layout(renderer, bounds);\n            let mut event_statuses = Vec::new();\n\n            for event in events {\n                let mut shell = Shell::new(messages);\n\n                overlay.update(event, Layout::new(&layout), cursor, renderer, &mut shell);\n\n                event_statuses.push(shell.event_status());\n                redraw_request = redraw_request.min(shell.redraw_request());\n                input_method.merge(shell.input_method());\n                clipboard.merge(shell.clipboard_mut());\n\n                if shell.is_layout_invalid() {\n                    drop(maybe_overlay);\n\n                    self.base = self.root.as_widget_mut().layout(\n                        &mut self.state,\n                        renderer,\n                        &layout::Limits::new(Size::ZERO, self.bounds),\n                    );\n\n                    maybe_overlay = self\n                        .root\n                        .as_widget_mut()\n                        .overlay(\n                            &mut self.state,\n                            Layout::new(&self.base),\n                            renderer,\n                            &viewport,\n                            Vector::ZERO,\n                        )\n                        .map(overlay::Nested::new);\n\n                    if maybe_overlay.is_none() {\n                        break;\n                    }\n\n                    overlay = maybe_overlay.as_mut().unwrap();\n\n                    shell.revalidate_layout(|| {\n                        layout = overlay.layout(renderer, bounds);\n                        has_layout_changed = true;\n                    });\n                }\n\n                if shell.are_widgets_invalid() {\n                    outdated = true;\n                }\n            }\n\n            let (base_cursor, interaction) = if let Some(overlay) = maybe_overlay.as_mut() {\n                let interaction = cursor\n                    .position()\n                    .map(|cursor_position| {\n                        overlay.mouse_interaction(\n                            Layout::new(&layout),\n                            mouse::Cursor::Available(cursor_position),\n                            renderer,\n                        )\n                    })\n                    .unwrap_or_default();\n\n                if interaction == mouse::Interaction::None {\n                    (cursor, mouse::Interaction::None)\n                } else {\n                    (mouse::Cursor::Unavailable, interaction)\n                }\n            } else {\n                (cursor, mouse::Interaction::None)\n            };\n\n            self.overlay = Some(Overlay {\n                layout,\n                interaction,\n            });\n\n            (base_cursor, event_statuses, interaction)\n        } else {\n            (\n                cursor,\n                vec![event::Status::Ignored; events.len()],\n                mouse::Interaction::None,\n            )\n        };\n\n        drop(maybe_overlay);\n\n        let event_statuses = events\n            .iter()\n            .zip(overlay_statuses)\n            .map(|(event, overlay_status)| {\n                if matches!(overlay_status, event::Status::Captured) {\n                    return overlay_status;\n                }\n\n                let mut shell = Shell::new(messages);\n\n                self.root.as_widget_mut().update(\n                    &mut self.state,\n                    event,\n                    Layout::new(&self.base),\n                    base_cursor,\n                    renderer,\n                    &mut shell,\n                    &viewport,\n                );\n\n                if shell.event_status() == event::Status::Captured {\n                    self.overlay = None;\n                }\n\n                redraw_request = redraw_request.min(shell.redraw_request());\n                input_method.merge(shell.input_method());\n                clipboard.merge(shell.clipboard_mut());\n\n                shell.revalidate_layout(|| {\n                    has_layout_changed = true;\n\n                    self.base = self.root.as_widget_mut().layout(\n                        &mut self.state,\n                        renderer,\n                        &layout::Limits::new(Size::ZERO, self.bounds),\n                    );\n\n                    if let Some(mut overlay) = self\n                        .root\n                        .as_widget_mut()\n                        .overlay(\n                            &mut self.state,\n                            Layout::new(&self.base),\n                            renderer,\n                            &viewport,\n                            Vector::ZERO,\n                        )\n                        .map(overlay::Nested::new)\n                    {\n                        let layout = overlay.layout(renderer, self.bounds);\n                        let interaction =\n                            overlay.mouse_interaction(Layout::new(&layout), cursor, renderer);\n\n                        self.overlay = Some(Overlay {\n                            layout,\n                            interaction,\n                        });\n                    }\n                });\n\n                if shell.are_widgets_invalid() {\n                    outdated = true;\n                }\n\n                shell.event_status().merge(overlay_status)\n            })\n            .collect();\n\n        let mouse_interaction = if overlay_interaction == mouse::Interaction::None {\n            self.root.as_widget().mouse_interaction(\n                &self.state,\n                Layout::new(&self.base),\n                base_cursor,\n                &viewport,\n                renderer,\n            )\n        } else {\n            overlay_interaction\n        };\n\n        (\n            if outdated {\n                State::Outdated\n            } else {\n                State::Updated {\n                    mouse_interaction,\n                    redraw_request,\n                    input_method,\n                    clipboard,\n                    has_layout_changed,\n                }\n            },\n            event_statuses,\n        )\n    }\n\n    /// Draws the [`UserInterface`] with the provided [`Renderer`].\n    ///\n    /// It returns the current [`mouse::Interaction`]. You should update the\n    /// icon of the mouse cursor accordingly in your system.\n    ///\n    /// [`Renderer`]: crate::core::Renderer\n    ///\n    /// # Example\n    /// We can finally draw our [counter](index.html#usage) by\n    /// [completing the last example](#example-1):\n    ///\n    /// ```no_run\n    /// # mod iced_wgpu {\n    /// #     pub type Renderer = ();\n    /// #     pub type Theme = ();\n    /// # }\n    /// #\n    /// # pub struct Counter;\n    /// #\n    /// # impl Counter {\n    /// #     pub fn new() -> Self { Counter }\n    /// #     pub fn view(&self) -> Element<(), (), Renderer> { unimplemented!() }\n    /// #     pub fn update(&mut self, _: ()) {}\n    /// # }\n    /// use iced_runtime::core::mouse;\n    /// use iced_runtime::core::renderer;\n    /// use iced_runtime::core::{Element, Size};\n    /// use iced_runtime::user_interface::{self, UserInterface};\n    /// use iced_wgpu::{Renderer, Theme};\n    ///\n    /// let mut counter = Counter::new();\n    /// let mut cache = user_interface::Cache::new();\n    /// let mut renderer = Renderer::default();\n    /// let mut window_size = Size::new(1024.0, 768.0);\n    /// let mut cursor = mouse::Cursor::default();\n    /// let mut events = Vec::new();\n    /// let mut messages = Vec::new();\n    /// let mut theme = Theme::default();\n    ///\n    /// loop {\n    ///     // Obtain system events...\n    ///\n    ///     let mut user_interface = UserInterface::build(\n    ///         counter.view(),\n    ///         window_size,\n    ///         cache,\n    ///         &mut renderer,\n    ///     );\n    ///\n    ///     // Update the user interface\n    ///     let event_statuses = user_interface.update(\n    ///         &events,\n    ///         cursor,\n    ///         &mut renderer,\n    ///         &mut messages\n    ///     );\n    ///\n    ///     // Draw the user interface\n    ///     let mouse_interaction = user_interface.draw(&mut renderer, &theme, &renderer::Style::default(), cursor);\n    ///\n    ///     cache = user_interface.into_cache();\n    ///\n    ///     for message in messages.drain(..) {\n    ///         counter.update(message);\n    ///     }\n    ///\n    ///     // Update mouse cursor icon...\n    ///     // Flush rendering operations...\n    /// }\n    /// ```\n    pub fn draw(\n        &mut self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        cursor: mouse::Cursor,\n    ) {\n        let viewport = Rectangle::with_size(self.bounds);\n        renderer.reset(viewport);\n\n        let base_cursor = match &self.overlay {\n            None\n            | Some(Overlay {\n                interaction: mouse::Interaction::None,\n                ..\n            }) => cursor,\n            _ => mouse::Cursor::Unavailable,\n        };\n\n        self.root.as_widget().draw(\n            &self.state,\n            renderer,\n            theme,\n            style,\n            Layout::new(&self.base),\n            base_cursor,\n            &viewport,\n        );\n\n        let Self {\n            overlay,\n            root,\n            base,\n            ..\n        } = self;\n\n        let Some(Overlay { layout, .. }) = overlay.as_ref() else {\n            return;\n        };\n\n        let overlay = root\n            .as_widget_mut()\n            .overlay(\n                &mut self.state,\n                Layout::new(base),\n                renderer,\n                &viewport,\n                Vector::ZERO,\n            )\n            .map(overlay::Nested::new);\n\n        if let Some(mut overlay) = overlay {\n            overlay.draw(renderer, theme, style, Layout::new(layout), cursor);\n        }\n    }\n\n    /// Applies a [`widget::Operation`] to the [`UserInterface`].\n    pub fn operate(&mut self, renderer: &Renderer, operation: &mut dyn widget::Operation) {\n        let viewport = Rectangle::with_size(self.bounds);\n\n        self.root.as_widget_mut().operate(\n            &mut self.state,\n            Layout::new(&self.base),\n            renderer,\n            operation,\n        );\n\n        if let Some(mut overlay) = self\n            .root\n            .as_widget_mut()\n            .overlay(\n                &mut self.state,\n                Layout::new(&self.base),\n                renderer,\n                &viewport,\n                Vector::ZERO,\n            )\n            .map(overlay::Nested::new)\n        {\n            if self.overlay.is_none() {\n                self.overlay = Some(Overlay {\n                    layout: overlay.layout(renderer, self.bounds),\n                    interaction: mouse::Interaction::None,\n                });\n            }\n\n            overlay.operate(\n                Layout::new(&self.overlay.as_ref().unwrap().layout),\n                renderer,\n                operation,\n            );\n        }\n    }\n\n    /// Relayouts and returns a new  [`UserInterface`] using the provided\n    /// bounds.\n    pub fn relayout(self, bounds: Size, renderer: &mut Renderer) -> Self {\n        Self::build(self.root, bounds, Cache { state: self.state }, renderer)\n    }\n\n    /// Extract the [`Cache`] of the [`UserInterface`], consuming it in the\n    /// process.\n    pub fn into_cache(self) -> Cache {\n        Cache { state: self.state }\n    }\n}\n\n/// Reusable data of a specific [`UserInterface`].\n#[derive(Debug)]\npub struct Cache {\n    state: widget::Tree,\n}\n\nimpl Cache {\n    /// Creates an empty [`Cache`].\n    ///\n    /// You should use this to initialize a [`Cache`] before building your first\n    /// [`UserInterface`].\n    pub fn new() -> Cache {\n        Cache {\n            state: widget::Tree::empty(),\n        }\n    }\n}\n\nimpl Default for Cache {\n    fn default() -> Cache {\n        Cache::new()\n    }\n}\n\n/// The resulting state after updating a [`UserInterface`].\n#[derive(Debug)]\npub enum State {\n    /// The [`UserInterface`] is outdated and needs to be rebuilt.\n    Outdated,\n\n    /// The [`UserInterface`] is up-to-date and can be reused without\n    /// rebuilding.\n    Updated {\n        /// The current [`mouse::Interaction`] of the user interface.\n        mouse_interaction: mouse::Interaction,\n        /// The [`window::RedrawRequest`] describing when a redraw should be performed.\n        redraw_request: window::RedrawRequest,\n        /// The current [`InputMethod`] strategy of the user interface.\n        input_method: InputMethod,\n        /// The set of [`Clipboard`] requests that the user interface has produced.\n        clipboard: Clipboard,\n        /// Whether the layout of the [`UserInterface`] has changed.\n        has_layout_changed: bool,\n    },\n}\n\nimpl State {\n    /// Returns whether the layout of the [`UserInterface`] has changed.\n    pub fn has_layout_changed(&self) -> bool {\n        match self {\n            State::Outdated => true,\n            State::Updated {\n                has_layout_changed, ..\n            } => *has_layout_changed,\n        }\n    }\n}\n"
  },
  {
    "path": "runtime/src/widget/operation.rs",
    "content": "//! Change internal widget state.\nuse crate::core::widget::Id;\nuse crate::core::widget::operation;\nuse crate::task;\nuse crate::{Action, Task};\n\npub use crate::core::widget::operation::scrollable::{AbsoluteOffset, RelativeOffset};\n\n/// Snaps the scrollable with the given [`Id`] to the provided [`RelativeOffset`].\npub fn snap_to<T>(id: impl Into<Id>, offset: impl Into<RelativeOffset<Option<f32>>>) -> Task<T> {\n    task::effect(Action::widget(operation::scrollable::snap_to(\n        id.into(),\n        offset.into(),\n    )))\n}\n\n/// Snaps the scrollable with the given [`Id`] to the [`RelativeOffset::END`].\npub fn snap_to_end<T>(id: impl Into<Id>) -> Task<T> {\n    task::effect(Action::widget(operation::scrollable::snap_to(\n        id.into(),\n        RelativeOffset::END.into(),\n    )))\n}\n\n/// Scrolls the scrollable with the given [`Id`] to the provided [`AbsoluteOffset`].\npub fn scroll_to<T>(id: impl Into<Id>, offset: impl Into<AbsoluteOffset<Option<f32>>>) -> Task<T> {\n    task::effect(Action::widget(operation::scrollable::scroll_to(\n        id.into(),\n        offset.into(),\n    )))\n}\n\n/// Scrolls the scrollable with the given [`Id`] by the provided [`AbsoluteOffset`].\npub fn scroll_by<T>(id: impl Into<Id>, offset: AbsoluteOffset) -> Task<T> {\n    task::effect(Action::widget(operation::scrollable::scroll_by(\n        id.into(),\n        offset,\n    )))\n}\n\n/// Focuses the previous focusable widget.\npub fn focus_previous<T>() -> Task<T> {\n    task::effect(Action::widget(operation::focusable::focus_previous()))\n}\n\n/// Focuses the next focusable widget.\npub fn focus_next<T>() -> Task<T> {\n    task::effect(Action::widget(operation::focusable::focus_next()))\n}\n\n/// Returns whether the widget with the given [`Id`] is focused or not.\npub fn is_focused(id: impl Into<Id>) -> Task<bool> {\n    task::widget(operation::focusable::is_focused(id.into()))\n}\n\n/// Focuses the widget with the given [`Id`].\npub fn focus<T>(id: impl Into<Id>) -> Task<T> {\n    task::effect(Action::widget(operation::focusable::focus(id.into())))\n}\n\n/// Moves the cursor of the widget with the given [`Id`] to the end.\npub fn move_cursor_to_end<T>(id: impl Into<Id>) -> Task<T> {\n    task::effect(Action::widget(operation::text_input::move_cursor_to_end(\n        id.into(),\n    )))\n}\n\n/// Moves the cursor of the widget with the given [`Id`] to the front.\npub fn move_cursor_to_front<T>(id: impl Into<Id>) -> Task<T> {\n    task::effect(Action::widget(operation::text_input::move_cursor_to_front(\n        id.into(),\n    )))\n}\n\n/// Moves the cursor of the widget with the given [`Id`] to the provided position.\npub fn move_cursor_to<T>(id: impl Into<Id>, position: usize) -> Task<T> {\n    task::effect(Action::widget(operation::text_input::move_cursor_to(\n        id.into(),\n        position,\n    )))\n}\n\n/// Selects all the content of the widget with the given [`Id`].\npub fn select_all<T>(id: impl Into<Id>) -> Task<T> {\n    task::effect(Action::widget(operation::text_input::select_all(id.into())))\n}\n\n/// Selects the given content range of the widget with the given [`Id`].\npub fn select_range<T>(id: impl Into<Id>, start: usize, end: usize) -> Task<T> {\n    task::effect(Action::widget(operation::text_input::select_range(\n        id.into(),\n        start,\n        end,\n    )))\n}\n"
  },
  {
    "path": "runtime/src/widget/selector.rs",
    "content": "//! Find and query widgets in your applications.\npub use iced_selector::{Bounded, Candidate, Selector, Target, Text, id, is_focused};\n\nuse crate::Task;\nuse crate::task;\n\n/// Finds a widget matching the given [`Selector`].\npub fn find<S>(selector: S) -> Task<Option<S::Output>>\nwhere\n    S: Selector + Send + 'static,\n    S::Output: Send + Clone + 'static,\n{\n    task::widget(selector.find())\n}\n\n/// Finds all widgets matching the given [`Selector`].\npub fn find_all<S>(selector: S) -> Task<Vec<S::Output>>\nwhere\n    S: Selector + Send + 'static,\n    S::Output: Send + Clone + 'static,\n{\n    task::widget(selector.find_all())\n}\n"
  },
  {
    "path": "runtime/src/widget.rs",
    "content": "//! Operate on widgets and query them at runtime.\npub mod operation;\n\n#[cfg(feature = \"selector\")]\npub mod selector;\n"
  },
  {
    "path": "runtime/src/window.rs",
    "content": "//! Build window-based GUI applications.\nuse crate::core::time::Instant;\nuse crate::core::window::{\n    Direction, Event, Icon, Id, Level, Mode, Screenshot, Settings, UserAttention,\n};\nuse crate::core::{Point, Size};\nuse crate::futures::Subscription;\nuse crate::futures::event;\nuse crate::futures::futures::channel::oneshot;\nuse crate::task::{self, Task};\n\npub use raw_window_handle;\n\nuse raw_window_handle::{HasDisplayHandle, HasWindowHandle};\n\n/// An operation to be performed on some window.\npub enum Action {\n    /// Open a new window with some [`Settings`].\n    Open(Id, Settings, oneshot::Sender<Id>),\n\n    /// Close the window and exits the application.\n    Close(Id),\n\n    /// Gets the [`Id`] of the oldest window.\n    GetOldest(oneshot::Sender<Option<Id>>),\n\n    /// Gets the [`Id`] of the latest window.\n    GetLatest(oneshot::Sender<Option<Id>>),\n\n    /// Move the window with the left mouse button until the button is\n    /// released.\n    ///\n    /// There's no guarantee that this will work unless the left mouse\n    /// button was pressed immediately before this function is called.\n    Drag(Id),\n\n    /// Resize the window with the left mouse button until the button is\n    /// released.\n    ///\n    /// There's no guarantee that this will work unless the left mouse\n    /// button was pressed immediately before this function is called.\n    DragResize(Id, Direction),\n\n    /// Resize the window to the given logical dimensions.\n    Resize(Id, Size),\n\n    /// Get the current logical dimensions of the window.\n    GetSize(Id, oneshot::Sender<Size>),\n\n    /// Get if the current window is maximized or not.\n    GetMaximized(Id, oneshot::Sender<bool>),\n\n    /// Set the window to maximized or back\n    Maximize(Id, bool),\n\n    /// Get if the current window is minimized or not.\n    ///\n    /// ## Platform-specific\n    /// - **Wayland:** Always `None`.\n    GetMinimized(Id, oneshot::Sender<Option<bool>>),\n\n    /// Set the window to minimized or back\n    Minimize(Id, bool),\n\n    /// Get the current logical coordinates of the window.\n    GetPosition(Id, oneshot::Sender<Option<Point>>),\n\n    /// Get the current scale factor (DPI) of the window.\n    GetScaleFactor(Id, oneshot::Sender<f32>),\n\n    /// Move the window to the given logical coordinates.\n    ///\n    /// Unsupported on Wayland.\n    Move(Id, Point),\n\n    /// Change the [`Mode`] of the window.\n    SetMode(Id, Mode),\n\n    /// Get the current [`Mode`] of the window.\n    GetMode(Id, oneshot::Sender<Mode>),\n\n    /// Toggle the window to maximized or back\n    ToggleMaximize(Id),\n\n    /// Toggle whether window has decorations.\n    ///\n    /// ## Platform-specific\n    /// - **X11:** Not implemented.\n    /// - **Web:** Unsupported.\n    ToggleDecorations(Id),\n\n    /// Request user attention to the window, this has no effect if the application\n    /// is already focused. How requesting for user attention manifests is platform dependent,\n    /// see [`UserAttention`] for details.\n    ///\n    /// Providing `None` will unset the request for user attention. Unsetting the request for\n    /// user attention might not be done automatically by the WM when the window receives input.\n    ///\n    /// ## Platform-specific\n    ///\n    /// - **iOS / Android / Web:** Unsupported.\n    /// - **macOS:** `None` has no effect.\n    /// - **X11:** Requests for user attention must be manually cleared.\n    /// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.\n    RequestUserAttention(Id, Option<UserAttention>),\n\n    /// Bring the window to the front and sets input focus. Has no effect if the window is\n    /// already in focus, minimized, or not visible.\n    ///\n    /// This method steals input focus from other applications. Do not use this method unless\n    /// you are certain that's what the user wants. Focus stealing can cause an extremely disruptive\n    /// user experience.\n    ///\n    /// ## Platform-specific\n    ///\n    /// - **Web / Wayland:** Unsupported.\n    GainFocus(Id),\n\n    /// Change the window [`Level`].\n    SetLevel(Id, Level),\n\n    /// Show the system menu at cursor position.\n    ///\n    /// ## Platform-specific\n    /// Android / iOS / macOS / Orbital / Web / X11: Unsupported.\n    ShowSystemMenu(Id),\n\n    /// Get the raw identifier unique to the window.\n    GetRawId(Id, oneshot::Sender<u64>),\n\n    /// Change the window [`Icon`].\n    ///\n    /// On Windows and X11, this is typically the small icon in the top-left\n    /// corner of the titlebar.\n    ///\n    /// ## Platform-specific\n    ///\n    /// - **Web / Wayland / macOS:** Unsupported.\n    ///\n    /// - **Windows:** Sets `ICON_SMALL`. The base size for a window icon is 16x16, but it's\n    ///   recommended to account for screen scaling and pick a multiple of that, i.e. 32x32.\n    ///\n    /// - **X11:** Has no universal guidelines for icon sizes, so you're at the whims of the WM. That\n    ///   said, it's usually in the same ballpark as on Windows.\n    SetIcon(Id, Icon),\n\n    /// Runs the closure with a reference to the [`Window`] with the given [`Id`].\n    Run(Id, Box<dyn FnOnce(&dyn Window) + Send>),\n\n    /// Screenshot the viewport of the window.\n    Screenshot(Id, oneshot::Sender<Screenshot>),\n\n    /// Enable mouse passthrough for the given window.\n    ///\n    /// This disables mouse events for the window and passes mouse events\n    /// through to whatever window is underneath.\n    EnableMousePassthrough(Id),\n\n    /// Disable mouse passthrough for the given window.\n    ///\n    /// This enables mouse events for the window and stops mouse events\n    /// from being passed to whatever is underneath.\n    DisableMousePassthrough(Id),\n\n    /// Set the minimum inner window size.\n    SetMinSize(Id, Option<Size>),\n\n    /// Set the maximum inner window size.\n    SetMaxSize(Id, Option<Size>),\n\n    /// Set the window to be resizable or not.\n    SetResizable(Id, bool),\n\n    /// Set the window size increment.\n    SetResizeIncrements(Id, Option<Size>),\n\n    /// Get the logical dimensions of the monitor containing the window with the given [`Id`].\n    GetMonitorSize(Id, oneshot::Sender<Option<Size>>),\n\n    /// Set whether the system can automatically organize windows into tabs.\n    ///\n    /// See <https://developer.apple.com/documentation/appkit/nswindow/1646657-allowsautomaticwindowtabbing>\n    SetAllowAutomaticTabbing(bool),\n\n    /// Redraw all the windows.\n    RedrawAll,\n\n    /// Recompute the layouts of all the windows.\n    RelayoutAll,\n}\n\n/// A window managed by iced.\n///\n/// It implements both [`HasWindowHandle`] and [`HasDisplayHandle`].\npub trait Window: HasWindowHandle + HasDisplayHandle {}\n\nimpl<T> Window for T where T: HasWindowHandle + HasDisplayHandle {}\n\n/// Subscribes to the frames of the window of the running application.\n///\n/// The resulting [`Subscription`] will produce items at a rate equal to the\n/// refresh rate of the first application window. Note that this rate may be variable, as it is\n/// normally managed by the graphics driver and/or the OS.\n///\n/// In any case, this [`Subscription`] is useful to smoothly draw application-driven\n/// animations without missing any frames.\npub fn frames() -> Subscription<Instant> {\n    event::listen_raw(|event, _status, _window| match event {\n        crate::core::Event::Window(Event::RedrawRequested(at)) => Some(at),\n        _ => None,\n    })\n}\n\n/// Subscribes to all window events of the running application.\npub fn events() -> Subscription<(Id, Event)> {\n    event::listen_with(|event, _status, id| {\n        if let crate::core::Event::Window(event) = event {\n            Some((id, event))\n        } else {\n            None\n        }\n    })\n}\n\n/// Subscribes to all [`Event::Opened`] occurrences in the running application.\npub fn open_events() -> Subscription<Id> {\n    event::listen_with(|event, _status, id| {\n        if let crate::core::Event::Window(Event::Opened { .. }) = event {\n            Some(id)\n        } else {\n            None\n        }\n    })\n}\n\n/// Subscribes to all [`Event::Closed`] occurrences in the running application.\npub fn close_events() -> Subscription<Id> {\n    event::listen_with(|event, _status, id| {\n        if let crate::core::Event::Window(Event::Closed) = event {\n            Some(id)\n        } else {\n            None\n        }\n    })\n}\n\n/// Subscribes to all [`Event::Resized`] occurrences in the running application.\npub fn resize_events() -> Subscription<(Id, Size)> {\n    event::listen_with(|event, _status, id| {\n        if let crate::core::Event::Window(Event::Resized(size)) = event {\n            Some((id, size))\n        } else {\n            None\n        }\n    })\n}\n\n/// Subscribes to all [`Event::CloseRequested`] occurrences in the running application.\npub fn close_requests() -> Subscription<Id> {\n    event::listen_with(|event, _status, id| {\n        if let crate::core::Event::Window(Event::CloseRequested) = event {\n            Some(id)\n        } else {\n            None\n        }\n    })\n}\n\n/// Opens a new window with the given [`Settings`]; producing the [`Id`]\n/// of the new window on completion.\npub fn open(settings: Settings) -> (Id, Task<Id>) {\n    let id = Id::unique();\n\n    (\n        id,\n        task::oneshot(|channel| crate::Action::Window(Action::Open(id, settings, channel))),\n    )\n}\n\n/// Closes the window with `id`.\npub fn close<T>(id: Id) -> Task<T> {\n    task::effect(crate::Action::Window(Action::Close(id)))\n}\n\n/// Gets the window [`Id`] of the oldest window.\npub fn oldest() -> Task<Option<Id>> {\n    task::oneshot(|channel| crate::Action::Window(Action::GetOldest(channel)))\n}\n\n/// Gets the window [`Id`] of the latest window.\npub fn latest() -> Task<Option<Id>> {\n    task::oneshot(|channel| crate::Action::Window(Action::GetLatest(channel)))\n}\n\n/// Begins dragging the window while the left mouse button is held.\npub fn drag<T>(id: Id) -> Task<T> {\n    task::effect(crate::Action::Window(Action::Drag(id)))\n}\n\n/// Begins resizing the window while the left mouse button is held.\npub fn drag_resize<T>(id: Id, direction: Direction) -> Task<T> {\n    task::effect(crate::Action::Window(Action::DragResize(id, direction)))\n}\n\n/// Resizes the window to the given logical dimensions.\npub fn resize<T>(id: Id, new_size: Size) -> Task<T> {\n    task::effect(crate::Action::Window(Action::Resize(id, new_size)))\n}\n\n/// Set the window to be resizable or not.\npub fn set_resizable<T>(id: Id, resizable: bool) -> Task<T> {\n    task::effect(crate::Action::Window(Action::SetResizable(id, resizable)))\n}\n\n/// Set the inner maximum size of the window.\npub fn set_max_size<T>(id: Id, size: Option<Size>) -> Task<T> {\n    task::effect(crate::Action::Window(Action::SetMaxSize(id, size)))\n}\n\n/// Set the inner minimum size of the window.\npub fn set_min_size<T>(id: Id, size: Option<Size>) -> Task<T> {\n    task::effect(crate::Action::Window(Action::SetMinSize(id, size)))\n}\n\n/// Set the window size increment.\n///\n/// This is usually used by apps such as terminal emulators that need \"blocky\" resizing.\npub fn set_resize_increments<T>(id: Id, increments: Option<Size>) -> Task<T> {\n    task::effect(crate::Action::Window(Action::SetResizeIncrements(\n        id, increments,\n    )))\n}\n\n/// Gets the window size in logical dimensions.\npub fn size(id: Id) -> Task<Size> {\n    task::oneshot(move |channel| crate::Action::Window(Action::GetSize(id, channel)))\n}\n\n/// Gets the maximized state of the window with the given [`Id`].\npub fn is_maximized(id: Id) -> Task<bool> {\n    task::oneshot(move |channel| crate::Action::Window(Action::GetMaximized(id, channel)))\n}\n\n/// Maximizes the window.\npub fn maximize<T>(id: Id, maximized: bool) -> Task<T> {\n    task::effect(crate::Action::Window(Action::Maximize(id, maximized)))\n}\n\n/// Gets the minimized state of the window with the given [`Id`].\npub fn is_minimized(id: Id) -> Task<Option<bool>> {\n    task::oneshot(move |channel| crate::Action::Window(Action::GetMinimized(id, channel)))\n}\n\n/// Minimizes the window.\npub fn minimize<T>(id: Id, minimized: bool) -> Task<T> {\n    task::effect(crate::Action::Window(Action::Minimize(id, minimized)))\n}\n\n/// Gets the position in logical coordinates of the window with the given [`Id`].\npub fn position(id: Id) -> Task<Option<Point>> {\n    task::oneshot(move |channel| crate::Action::Window(Action::GetPosition(id, channel)))\n}\n\n/// Gets the scale factor of the window with the given [`Id`].\npub fn scale_factor(id: Id) -> Task<f32> {\n    task::oneshot(move |channel| crate::Action::Window(Action::GetScaleFactor(id, channel)))\n}\n\n/// Moves the window to the given logical coordinates.\npub fn move_to<T>(id: Id, position: Point) -> Task<T> {\n    task::effect(crate::Action::Window(Action::Move(id, position)))\n}\n\n/// Gets the current [`Mode`] of the window.\npub fn mode(id: Id) -> Task<Mode> {\n    task::oneshot(move |channel| crate::Action::Window(Action::GetMode(id, channel)))\n}\n\n/// Changes the [`Mode`] of the window.\npub fn set_mode<T>(id: Id, mode: Mode) -> Task<T> {\n    task::effect(crate::Action::Window(Action::SetMode(id, mode)))\n}\n\n/// Toggles the window to maximized or back.\npub fn toggle_maximize<T>(id: Id) -> Task<T> {\n    task::effect(crate::Action::Window(Action::ToggleMaximize(id)))\n}\n\n/// Toggles the window decorations.\npub fn toggle_decorations<T>(id: Id) -> Task<T> {\n    task::effect(crate::Action::Window(Action::ToggleDecorations(id)))\n}\n\n/// Requests user attention to the window. This has no effect if the application\n/// is already focused. How requesting for user attention manifests is platform dependent,\n/// see [`UserAttention`] for details.\n///\n/// Providing `None` will unset the request for user attention. Unsetting the request for\n/// user attention might not be done automatically by the WM when the window receives input.\npub fn request_user_attention<T>(id: Id, user_attention: Option<UserAttention>) -> Task<T> {\n    task::effect(crate::Action::Window(Action::RequestUserAttention(\n        id,\n        user_attention,\n    )))\n}\n\n/// Brings the window to the front and sets input focus. Has no effect if the window is\n/// already in focus, minimized, or not visible.\n///\n/// This [`Task`] steals input focus from other applications. Do not use this method unless\n/// you are certain that's what the user wants. Focus stealing can cause an extremely disruptive\n/// user experience.\npub fn gain_focus<T>(id: Id) -> Task<T> {\n    task::effect(crate::Action::Window(Action::GainFocus(id)))\n}\n\n/// Changes the window [`Level`].\npub fn set_level<T>(id: Id, level: Level) -> Task<T> {\n    task::effect(crate::Action::Window(Action::SetLevel(id, level)))\n}\n\n/// Shows the [system menu] at cursor position.\n///\n/// [system menu]: https://en.wikipedia.org/wiki/Common_menus_in_Microsoft_Windows#System_menu\npub fn show_system_menu<T>(id: Id) -> Task<T> {\n    task::effect(crate::Action::Window(Action::ShowSystemMenu(id)))\n}\n\n/// Gets an identifier unique to the window, provided by the underlying windowing system. This is\n/// not to be confused with [`Id`].\npub fn raw_id<Message>(id: Id) -> Task<u64> {\n    task::oneshot(|channel| crate::Action::Window(Action::GetRawId(id, channel)))\n}\n\n/// Changes the [`Icon`] of the window.\npub fn set_icon<T>(id: Id, icon: Icon) -> Task<T> {\n    task::effect(crate::Action::Window(Action::SetIcon(id, icon)))\n}\n\n/// Runs the given callback with a reference to the [`Window`] with the given [`Id`].\n///\n/// Note that if the window closes before this call is processed the callback will not be run.\npub fn run<T>(id: Id, f: impl FnOnce(&dyn Window) -> T + Send + 'static) -> Task<T>\nwhere\n    T: Send + 'static,\n{\n    task::oneshot(move |channel| {\n        crate::Action::Window(Action::Run(\n            id,\n            Box::new(move |handle| {\n                let _ = channel.send(f(handle));\n            }),\n        ))\n    })\n}\n\n/// Captures a [`Screenshot`] from the window.\npub fn screenshot(id: Id) -> Task<Screenshot> {\n    task::oneshot(move |channel| crate::Action::Window(Action::Screenshot(id, channel)))\n}\n\n/// Enables mouse passthrough for the given window.\n///\n/// This disables mouse events for the window and passes mouse events\n/// through to whatever window is underneath.\npub fn enable_mouse_passthrough<Message>(id: Id) -> Task<Message> {\n    task::effect(crate::Action::Window(Action::EnableMousePassthrough(id)))\n}\n\n/// Disables mouse passthrough for the given window.\n///\n/// This enables mouse events for the window and stops mouse events\n/// from being passed to whatever is underneath.\npub fn disable_mouse_passthrough<Message>(id: Id) -> Task<Message> {\n    task::effect(crate::Action::Window(Action::DisableMousePassthrough(id)))\n}\n\n/// Gets the logical dimensions of the monitor containing the window with the given [`Id`].\npub fn monitor_size(id: Id) -> Task<Option<Size>> {\n    task::oneshot(move |channel| crate::Action::Window(Action::GetMonitorSize(id, channel)))\n}\n\n/// Sets whether the system can automatically organize windows into tabs.\n///\n/// See <https://developer.apple.com/documentation/appkit/nswindow/1646657-allowsautomaticwindowtabbing>\npub fn allow_automatic_tabbing<T>(enabled: bool) -> Task<T> {\n    task::effect(crate::Action::Window(Action::SetAllowAutomaticTabbing(\n        enabled,\n    )))\n}\n"
  },
  {
    "path": "selector/Cargo.toml",
    "content": "[package]\nname = \"iced_selector\"\ndescription = \"A set of abstractions for selecting data from the widget tree\"\nversion.workspace = true\nauthors.workspace = true\nedition.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\nrust-version.workspace = true\n\n[dependencies]\niced_core.workspace = true\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "selector/src/find.rs",
    "content": "use crate::Selector;\nuse crate::core::widget::operation::{Focusable, Outcome, Scrollable, TextInput};\nuse crate::core::widget::{Id, Operation};\nuse crate::core::{Rectangle, Vector};\nuse crate::target::Candidate;\n\nuse std::any::Any;\n\n/// An [`Operation`] that runs the [`Selector`] and stops after\n/// the first [`Output`](Selector::Output) is produced.\npub type Find<S> = Finder<One<S>>;\n\n/// An [`Operation`] that runs the [`Selector`] for the entire\n/// widget tree and aggregates all of its [`Output`](Selector::Output).\npub type FindAll<S> = Finder<All<S>>;\n\n#[derive(Debug)]\npub struct One<S>\nwhere\n    S: Selector,\n{\n    selector: S,\n    output: Option<S::Output>,\n}\n\nimpl<S> One<S>\nwhere\n    S: Selector,\n{\n    pub fn new(selector: S) -> Self {\n        Self {\n            selector,\n            output: None,\n        }\n    }\n}\n\nimpl<S> Strategy for One<S>\nwhere\n    S: Selector,\n    S::Output: Clone,\n{\n    type Output = Option<S::Output>;\n\n    fn feed(&mut self, target: Candidate<'_>) {\n        if let Some(output) = self.selector.select(target) {\n            self.output = Some(output);\n        }\n    }\n\n    fn is_done(&self) -> bool {\n        self.output.is_some()\n    }\n\n    fn finish(&self) -> Self::Output {\n        self.output.clone()\n    }\n}\n\n#[derive(Debug)]\npub struct All<S>\nwhere\n    S: Selector,\n{\n    selector: S,\n    outputs: Vec<S::Output>,\n}\n\nimpl<S> All<S>\nwhere\n    S: Selector,\n{\n    pub fn new(selector: S) -> Self {\n        Self {\n            selector,\n            outputs: Vec::new(),\n        }\n    }\n}\n\nimpl<S> Strategy for All<S>\nwhere\n    S: Selector,\n    S::Output: Clone,\n{\n    type Output = Vec<S::Output>;\n\n    fn feed(&mut self, target: Candidate<'_>) {\n        if let Some(output) = self.selector.select(target) {\n            self.outputs.push(output);\n        }\n    }\n\n    fn is_done(&self) -> bool {\n        false\n    }\n\n    fn finish(&self) -> Self::Output {\n        self.outputs.clone()\n    }\n}\n\npub trait Strategy {\n    type Output;\n\n    fn feed(&mut self, target: Candidate<'_>);\n\n    fn is_done(&self) -> bool;\n\n    fn finish(&self) -> Self::Output;\n}\n\n#[derive(Debug)]\npub struct Finder<S> {\n    strategy: S,\n    stack: Vec<(Rectangle, Vector)>,\n    viewport: Rectangle,\n    translation: Vector,\n}\n\nimpl<S> Finder<S> {\n    pub fn new(strategy: S) -> Self {\n        Self {\n            strategy,\n            stack: vec![(Rectangle::INFINITE, Vector::ZERO)],\n            viewport: Rectangle::INFINITE,\n            translation: Vector::ZERO,\n        }\n    }\n}\n\nimpl<S> Operation<S::Output> for Finder<S>\nwhere\n    S: Strategy + Send,\n    S::Output: Send,\n{\n    fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<S::Output>)) {\n        if self.strategy.is_done() {\n            return;\n        }\n\n        self.stack.push((self.viewport, self.translation));\n        operate(self);\n        let _ = self.stack.pop();\n\n        let (viewport, translation) = self.stack.last().unwrap();\n        self.viewport = *viewport;\n        self.translation = *translation;\n    }\n\n    fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {\n        if self.strategy.is_done() {\n            return;\n        }\n\n        self.strategy.feed(Candidate::Container {\n            id,\n            bounds,\n            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),\n        });\n    }\n\n    fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {\n        if self.strategy.is_done() {\n            return;\n        }\n\n        self.strategy.feed(Candidate::Focusable {\n            id,\n            bounds,\n            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),\n            state,\n        });\n    }\n\n    fn scrollable(\n        &mut self,\n        id: Option<&Id>,\n        bounds: Rectangle,\n        content_bounds: Rectangle,\n        translation: Vector,\n        state: &mut dyn Scrollable,\n    ) {\n        if self.strategy.is_done() {\n            return;\n        }\n\n        let visible_bounds = self.viewport.intersection(&(bounds + self.translation));\n\n        self.strategy.feed(Candidate::Scrollable {\n            id,\n            bounds,\n            visible_bounds,\n            content_bounds,\n            translation,\n            state,\n        });\n\n        self.translation -= translation;\n        self.viewport = visible_bounds.unwrap_or_default();\n    }\n\n    fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {\n        if self.strategy.is_done() {\n            return;\n        }\n\n        self.strategy.feed(Candidate::TextInput {\n            id,\n            bounds,\n            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),\n            state,\n        });\n    }\n\n    fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {\n        if self.strategy.is_done() {\n            return;\n        }\n\n        self.strategy.feed(Candidate::Text {\n            id,\n            bounds,\n            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),\n            content: text,\n        });\n    }\n\n    fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {\n        if self.strategy.is_done() {\n            return;\n        }\n\n        self.strategy.feed(Candidate::Custom {\n            id,\n            bounds,\n            visible_bounds: self.viewport.intersection(&(bounds + self.translation)),\n            state,\n        });\n    }\n\n    fn finish(&self) -> Outcome<S::Output> {\n        Outcome::Some(self.strategy.finish())\n    }\n}\n"
  },
  {
    "path": "selector/src/lib.rs",
    "content": "//! Select data from the widget tree.\nuse iced_core as core;\n\nmod find;\nmod target;\n\npub use find::{Find, FindAll};\npub use target::{Bounded, Candidate, Target, Text};\n\nuse crate::core::Point;\nuse crate::core::widget;\n\n/// A type that traverses the widget tree to \"select\" data and produce some output.\npub trait Selector {\n    /// The output type of the [`Selector`].\n    ///\n    /// For most selectors, this will normally be a [`Target`]. However, some\n    /// selectors may want to return a more limited type to encode the selection\n    /// guarantees in the type system.\n    ///\n    /// For instance, the implementations of [`String`] and [`str`] of [`Selector`]\n    /// return a [`target::Text`] instead of a generic [`Target`], since they are\n    /// guaranteed to only select text.\n    type Output;\n\n    /// Performs a selection of the given [`Candidate`], if applicable.\n    ///\n    /// This method traverses the widget tree in depth-first order.\n    fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output>;\n\n    /// Returns a short description of the [`Selector`] for debugging purposes.\n    fn description(&self) -> String;\n\n    /// Returns a [`widget::Operation`] that runs the [`Selector`] and stops after\n    /// the first [`Output`](Self::Output) is produced.\n    fn find(self) -> Find<Self>\n    where\n        Self: Sized,\n    {\n        Find::new(find::One::new(self))\n    }\n\n    /// Returns a [`widget::Operation`] that runs the [`Selector`] for the entire\n    /// widget tree and aggregates all of its [`Output`](Self::Output).\n    fn find_all(self) -> FindAll<Self>\n    where\n        Self: Sized,\n    {\n        FindAll::new(find::All::new(self))\n    }\n}\n\nimpl Selector for &str {\n    type Output = target::Text;\n\n    fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {\n        match candidate {\n            Candidate::TextInput {\n                id,\n                bounds,\n                visible_bounds,\n                state,\n            } if state.text() == *self => Some(target::Text::Input {\n                id: id.cloned(),\n                bounds,\n                visible_bounds,\n            }),\n            Candidate::Text {\n                id,\n                bounds,\n                visible_bounds,\n                content,\n            } if content == *self => Some(target::Text::Raw {\n                id: id.cloned(),\n                bounds,\n                visible_bounds,\n            }),\n            _ => None,\n        }\n    }\n\n    fn description(&self) -> String {\n        format!(\"text == {self:?}\")\n    }\n}\n\nimpl Selector for String {\n    type Output = target::Text;\n\n    fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {\n        self.as_str().select(candidate)\n    }\n\n    fn description(&self) -> String {\n        self.as_str().description()\n    }\n}\n\nimpl Selector for widget::Id {\n    type Output = Target;\n\n    fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {\n        if candidate.id() != Some(self) {\n            return None;\n        }\n\n        Some(Target::from(candidate))\n    }\n\n    fn description(&self) -> String {\n        format!(\"id == {self:?}\")\n    }\n}\n\nimpl Selector for Point {\n    type Output = Target;\n\n    fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {\n        candidate\n            .visible_bounds()\n            .is_some_and(|visible_bounds| visible_bounds.contains(*self))\n            .then(|| Target::from(candidate))\n    }\n\n    fn description(&self) -> String {\n        format!(\"bounds contains {self:?}\")\n    }\n}\n\nimpl<F, T> Selector for F\nwhere\n    F: FnMut(Candidate<'_>) -> Option<T>,\n{\n    type Output = T;\n\n    fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {\n        (self)(candidate)\n    }\n\n    fn description(&self) -> String {\n        format!(\"custom selector: {}\", std::any::type_name_of_val(self))\n    }\n}\n\n/// Creates a new [`Selector`] that matches widgets with the given [`widget::Id`].\npub fn id(id: impl Into<widget::Id>) -> impl Selector<Output = Target> {\n    id.into()\n}\n\n/// Returns a [`Selector`] that matches widgets that are currently focused.\npub fn is_focused() -> impl Selector<Output = Target> {\n    struct IsFocused;\n\n    impl Selector for IsFocused {\n        type Output = Target;\n\n        fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {\n            if let Candidate::Focusable { state, .. } = candidate\n                && state.is_focused()\n            {\n                Some(Target::from(candidate))\n            } else {\n                None\n            }\n        }\n\n        fn description(&self) -> String {\n            \"is focused\".to_owned()\n        }\n    }\n\n    IsFocused\n}\n"
  },
  {
    "path": "selector/src/target.rs",
    "content": "use crate::core::widget::Id;\nuse crate::core::widget::operation::{Focusable, Scrollable, TextInput};\nuse crate::core::{Rectangle, Vector};\n\nuse std::any::Any;\n\n/// A generic widget match produced during selection.\n#[allow(missing_docs)]\n#[derive(Debug, Clone, PartialEq)]\npub enum Target {\n    Container {\n        id: Option<Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n    },\n    Focusable {\n        id: Option<Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n    },\n    Scrollable {\n        id: Option<Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n        content_bounds: Rectangle,\n        translation: Vector,\n    },\n    TextInput {\n        id: Option<Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n        content: String,\n    },\n    Text {\n        id: Option<Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n        content: String,\n    },\n    Custom {\n        id: Option<Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n    },\n}\n\nimpl Target {\n    /// Returns the layout bounds of the [`Target`].\n    pub fn bounds(&self) -> Rectangle {\n        match self {\n            Target::Container { bounds, .. }\n            | Target::Focusable { bounds, .. }\n            | Target::Scrollable { bounds, .. }\n            | Target::TextInput { bounds, .. }\n            | Target::Text { bounds, .. }\n            | Target::Custom { bounds, .. } => *bounds,\n        }\n    }\n\n    /// Returns the visible bounds of the [`Target`], in screen coordinates.\n    pub fn visible_bounds(&self) -> Option<Rectangle> {\n        match self {\n            Target::Container { visible_bounds, .. }\n            | Target::Focusable { visible_bounds, .. }\n            | Target::Scrollable { visible_bounds, .. }\n            | Target::TextInput { visible_bounds, .. }\n            | Target::Text { visible_bounds, .. }\n            | Target::Custom { visible_bounds, .. } => *visible_bounds,\n        }\n    }\n}\n\nimpl From<Candidate<'_>> for Target {\n    fn from(candidate: Candidate<'_>) -> Self {\n        match candidate {\n            Candidate::Container {\n                id,\n                bounds,\n                visible_bounds,\n            } => Self::Container {\n                id: id.cloned(),\n                bounds,\n                visible_bounds,\n            },\n            Candidate::Focusable {\n                id,\n                bounds,\n                visible_bounds,\n                ..\n            } => Self::Focusable {\n                id: id.cloned(),\n                bounds,\n                visible_bounds,\n            },\n            Candidate::Scrollable {\n                id,\n                bounds,\n                visible_bounds,\n                content_bounds,\n                translation,\n                ..\n            } => Self::Scrollable {\n                id: id.cloned(),\n                bounds,\n                visible_bounds,\n                content_bounds,\n                translation,\n            },\n            Candidate::TextInput {\n                id,\n                bounds,\n                visible_bounds,\n                state,\n            } => Self::TextInput {\n                id: id.cloned(),\n                bounds,\n                visible_bounds,\n                content: state.text().to_owned(),\n            },\n            Candidate::Text {\n                id,\n                bounds,\n                visible_bounds,\n                content,\n            } => Self::Text {\n                id: id.cloned(),\n                bounds,\n                visible_bounds,\n                content: content.to_owned(),\n            },\n            Candidate::Custom {\n                id,\n                bounds,\n                visible_bounds,\n                ..\n            } => Self::Custom {\n                id: id.cloned(),\n                bounds,\n                visible_bounds,\n            },\n        }\n    }\n}\n\nimpl Bounded for Target {\n    fn bounds(&self) -> Rectangle {\n        self.bounds()\n    }\n\n    fn visible_bounds(&self) -> Option<Rectangle> {\n        self.visible_bounds()\n    }\n}\n\n/// A selection candidate.\n///\n/// This is provided to [`Selector::select`](crate::Selector::select).\n#[allow(missing_docs)]\n#[derive(Clone)]\npub enum Candidate<'a> {\n    Container {\n        id: Option<&'a Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n    },\n    Focusable {\n        id: Option<&'a Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n        state: &'a dyn Focusable,\n    },\n    Scrollable {\n        id: Option<&'a Id>,\n        bounds: Rectangle,\n        content_bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n        translation: Vector,\n        state: &'a dyn Scrollable,\n    },\n    TextInput {\n        id: Option<&'a Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n        state: &'a dyn TextInput,\n    },\n    Text {\n        id: Option<&'a Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n        content: &'a str,\n    },\n    Custom {\n        id: Option<&'a Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n        state: &'a dyn Any,\n    },\n}\n\nimpl<'a> Candidate<'a> {\n    /// Returns the widget [`Id`] of the [`Candidate`].\n    pub fn id(&self) -> Option<&'a Id> {\n        match self {\n            Candidate::Container { id, .. }\n            | Candidate::Focusable { id, .. }\n            | Candidate::Scrollable { id, .. }\n            | Candidate::TextInput { id, .. }\n            | Candidate::Text { id, .. }\n            | Candidate::Custom { id, .. } => *id,\n        }\n    }\n\n    /// Returns the layout bounds of the [`Candidate`].\n    pub fn bounds(&self) -> Rectangle {\n        match self {\n            Candidate::Container { bounds, .. }\n            | Candidate::Focusable { bounds, .. }\n            | Candidate::Scrollable { bounds, .. }\n            | Candidate::TextInput { bounds, .. }\n            | Candidate::Text { bounds, .. }\n            | Candidate::Custom { bounds, .. } => *bounds,\n        }\n    }\n\n    /// Returns the visible bounds of the [`Candidate`], in screen coordinates.\n    pub fn visible_bounds(&self) -> Option<Rectangle> {\n        match self {\n            Candidate::Container { visible_bounds, .. }\n            | Candidate::Focusable { visible_bounds, .. }\n            | Candidate::Scrollable { visible_bounds, .. }\n            | Candidate::TextInput { visible_bounds, .. }\n            | Candidate::Text { visible_bounds, .. }\n            | Candidate::Custom { visible_bounds, .. } => *visible_bounds,\n        }\n    }\n}\n\n/// A bounded type has both layout bounds and visible bounds.\n///\n/// This trait lets us write generic code over the [`Output`](crate::Selector::Output)\n/// of a [`Selector`](crate::Selector).\npub trait Bounded: std::fmt::Debug {\n    /// Returns the layout bounds.\n    fn bounds(&self) -> Rectangle;\n\n    /// Returns the visible bounds, in screen coordinates.\n    fn visible_bounds(&self) -> Option<Rectangle>;\n}\n\n/// A text match.\n#[allow(missing_docs)]\n#[derive(Debug, Clone, PartialEq)]\npub enum Text {\n    Raw {\n        id: Option<Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n    },\n    Input {\n        id: Option<Id>,\n        bounds: Rectangle,\n        visible_bounds: Option<Rectangle>,\n    },\n}\n\nimpl Text {\n    /// Returns the layout bounds of the [`Text`].\n    pub fn bounds(&self) -> Rectangle {\n        match self {\n            Text::Raw { bounds, .. } | Text::Input { bounds, .. } => *bounds,\n        }\n    }\n\n    /// Returns the visible bounds of the [`Text`], in screen coordinates.\n    pub fn visible_bounds(&self) -> Option<Rectangle> {\n        match self {\n            Text::Raw { visible_bounds, .. } | Text::Input { visible_bounds, .. } => {\n                *visible_bounds\n            }\n        }\n    }\n}\n\nimpl Bounded for Text {\n    fn bounds(&self) -> Rectangle {\n        self.bounds()\n    }\n\n    fn visible_bounds(&self) -> Option<Rectangle> {\n        self.visible_bounds()\n    }\n}\n"
  },
  {
    "path": "src/advanced.rs",
    "content": "//! Leverage advanced concepts like custom widgets.\npub mod subscription {\n    //! Write your own subscriptions.\n    pub use crate::runtime::futures::subscription::{\n        Event, EventStream, Hasher, MacOS, PlatformSpecific, Recipe, from_recipe, into_recipes,\n    };\n}\n\npub mod widget {\n    //! Create custom widgets and operate on them.\n    pub use crate::core::widget::*;\n    pub use crate::runtime::task::widget as operate;\n}\n\npub use crate::core::Shell;\npub use crate::core::clipboard;\npub use crate::core::image;\npub use crate::core::input_method::{self, InputMethod};\npub use crate::core::layout::{self, Layout};\npub use crate::core::mouse;\npub use crate::core::overlay::{self, Overlay};\npub use crate::core::renderer::{self, Renderer};\npub use crate::core::svg;\npub use crate::core::text::{self, Text};\npub use crate::renderer::graphics;\n\npub use widget::Widget;\n"
  },
  {
    "path": "src/application/timed.rs",
    "content": "//! An [`Application`] that receives an [`Instant`] in update logic.\nuse crate::application::{Application, BootFn, ViewFn};\nuse crate::program;\nuse crate::theme;\nuse crate::time::Instant;\nuse crate::window;\nuse crate::{Element, Program, Settings, Subscription, Task};\n\nuse iced_debug as debug;\n\n/// Creates an [`Application`] with an `update` function that also\n/// takes the [`Instant`] of each `Message`.\n///\n/// This constructor is useful to create animated applications that\n/// are _pure_ (e.g. without relying on side-effect calls like [`Instant::now`]).\n///\n/// Purity is needed when you want your application to end up in the\n/// same exact state given the same history of messages. This property\n/// enables proper time traveling debugging with [`comet`].\n///\n/// [`comet`]: https://github.com/iced-rs/comet\npub fn timed<State, Message, Theme, Renderer>(\n    boot: impl BootFn<State, Message>,\n    update: impl UpdateFn<State, Message>,\n    subscription: impl Fn(&State) -> Subscription<Message>,\n    view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>,\n) -> Application<impl Program<State = State, Message = (Message, Instant), Theme = Theme>>\nwhere\n    State: 'static,\n    Message: Send + 'static,\n    Theme: theme::Base + 'static,\n    Renderer: program::Renderer + 'static,\n{\n    use std::marker::PhantomData;\n\n    struct Instance<State, Message, Theme, Renderer, Boot, Update, Subscription, View> {\n        boot: Boot,\n        update: Update,\n        subscription: Subscription,\n        view: View,\n        _state: PhantomData<State>,\n        _message: PhantomData<Message>,\n        _theme: PhantomData<Theme>,\n        _renderer: PhantomData<Renderer>,\n    }\n\n    impl<State, Message, Theme, Renderer, Boot, Update, Subscription, View> Program\n        for Instance<State, Message, Theme, Renderer, Boot, Update, Subscription, View>\n    where\n        Message: Send + 'static,\n        Theme: theme::Base + 'static,\n        Renderer: program::Renderer + 'static,\n        Boot: self::BootFn<State, Message>,\n        Update: self::UpdateFn<State, Message>,\n        Subscription: Fn(&State) -> self::Subscription<Message>,\n        View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>,\n    {\n        type State = State;\n        type Message = (Message, Instant);\n        type Theme = Theme;\n        type Renderer = Renderer;\n        type Executor = iced_futures::backend::default::Executor;\n\n        fn name() -> &'static str {\n            let name = std::any::type_name::<State>();\n\n            name.split(\"::\").next().unwrap_or(\"a_cool_application\")\n        }\n\n        fn settings(&self) -> Settings {\n            Settings::default()\n        }\n\n        fn window(&self) -> Option<iced_core::window::Settings> {\n            Some(window::Settings::default())\n        }\n\n        fn boot(&self) -> (State, Task<Self::Message>) {\n            let (state, task) = self.boot.boot();\n\n            (state, task.map(|message| (message, Instant::now())))\n        }\n\n        fn update(\n            &self,\n            state: &mut Self::State,\n            (message, now): Self::Message,\n        ) -> Task<Self::Message> {\n            debug::hot(move || {\n                self.update\n                    .update(state, message, now)\n                    .into()\n                    .map(|message| (message, Instant::now()))\n            })\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            _window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            debug::hot(|| {\n                self.view\n                    .view(state)\n                    .map(|message| (message, Instant::now()))\n            })\n        }\n\n        fn subscription(&self, state: &Self::State) -> self::Subscription<Self::Message> {\n            debug::hot(|| (self.subscription)(state).map(|message| (message, Instant::now())))\n        }\n    }\n\n    Application {\n        raw: Instance {\n            boot,\n            update,\n            subscription,\n            view,\n            _state: PhantomData,\n            _message: PhantomData,\n            _theme: PhantomData,\n            _renderer: PhantomData,\n        },\n        settings: Settings::default(),\n        window: window::Settings::default(),\n        presets: Vec::new(),\n    }\n}\n\n/// The update logic of some timed [`Application`].\n///\n/// This is like [`application::UpdateFn`](super::UpdateFn),\n/// but it also takes an [`Instant`].\npub trait UpdateFn<State, Message> {\n    /// Processes the message and updates the state of the [`Application`].\n    fn update(&self, state: &mut State, message: Message, now: Instant)\n    -> impl Into<Task<Message>>;\n}\n\nimpl<State, Message> UpdateFn<State, Message> for () {\n    fn update(\n        &self,\n        _state: &mut State,\n        _message: Message,\n        _now: Instant,\n    ) -> impl Into<Task<Message>> {\n    }\n}\n\nimpl<T, State, Message, C> UpdateFn<State, Message> for T\nwhere\n    T: Fn(&mut State, Message, Instant) -> C,\n    C: Into<Task<Message>>,\n{\n    fn update(\n        &self,\n        state: &mut State,\n        message: Message,\n        now: Instant,\n    ) -> impl Into<Task<Message>> {\n        self(state, message, now)\n    }\n}\n"
  },
  {
    "path": "src/application.rs",
    "content": "//! Create and run iced applications step by step.\n//!\n//! # Example\n//! ```no_run,standalone_crate\n//! use iced::widget::{button, column, text, Column};\n//! use iced::Theme;\n//!\n//! pub fn main() -> iced::Result {\n//!     iced::application(u64::default, update, view)\n//!         .theme(Theme::Dark)\n//!         .centered()\n//!         .run()\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     Increment,\n//! }\n//!\n//! fn update(value: &mut u64, message: Message) {\n//!     match message {\n//!         Message::Increment => *value += 1,\n//!     }\n//! }\n//!\n//! fn view(value: &u64) -> Column<Message> {\n//!     column![\n//!         text(value),\n//!         button(\"+\").on_press(Message::Increment),\n//!     ]\n//! }\n//! ```\nuse crate::message;\nuse crate::program::{self, Program};\nuse crate::shell;\nuse crate::theme;\nuse crate::window;\nuse crate::{\n    Element, Executor, Font, Never, Preset, Result, Settings, Size, Subscription, Task, Theme,\n};\n\nuse iced_debug as debug;\n\nuse std::borrow::Cow;\n\npub mod timed;\n\npub use timed::timed;\n\n/// Creates an iced [`Application`] given its boot, update, and view logic.\n///\n/// # Example\n/// ```no_run,standalone_crate\n/// use iced::widget::{button, column, text, Column};\n///\n/// pub fn main() -> iced::Result {\n///     iced::application(u64::default, update, view).run()\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     Increment,\n/// }\n///\n/// fn update(value: &mut u64, message: Message) {\n///     match message {\n///         Message::Increment => *value += 1,\n///     }\n/// }\n///\n/// fn view(value: &u64) -> Column<Message> {\n///     column![\n///         text(value),\n///         button(\"+\").on_press(Message::Increment),\n///     ]\n/// }\n/// ```\npub fn application<State, Message, Theme, Renderer>(\n    boot: impl BootFn<State, Message>,\n    update: impl UpdateFn<State, Message>,\n    view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>,\n) -> Application<impl Program<State = State, Message = Message, Theme = Theme>>\nwhere\n    State: 'static,\n    Message: Send + 'static,\n    Theme: theme::Base,\n    Renderer: program::Renderer,\n{\n    use std::marker::PhantomData;\n\n    struct Instance<State, Message, Theme, Renderer, Boot, Update, View> {\n        boot: Boot,\n        update: Update,\n        view: View,\n        _state: PhantomData<State>,\n        _message: PhantomData<Message>,\n        _theme: PhantomData<Theme>,\n        _renderer: PhantomData<Renderer>,\n    }\n\n    impl<State, Message, Theme, Renderer, Boot, Update, View> Program\n        for Instance<State, Message, Theme, Renderer, Boot, Update, View>\n    where\n        Message: Send + 'static,\n        Theme: theme::Base,\n        Renderer: program::Renderer,\n        Boot: self::BootFn<State, Message>,\n        Update: self::UpdateFn<State, Message>,\n        View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>,\n    {\n        type State = State;\n        type Message = Message;\n        type Theme = Theme;\n        type Renderer = Renderer;\n        type Executor = iced_futures::backend::default::Executor;\n\n        fn name() -> &'static str {\n            let name = std::any::type_name::<State>();\n\n            name.split(\"::\").next().unwrap_or(\"a_cool_application\")\n        }\n\n        fn boot(&self) -> (State, Task<Message>) {\n            self.boot.boot()\n        }\n\n        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n            self.update.update(state, message)\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            _window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            self.view.view(state)\n        }\n\n        fn settings(&self) -> Settings {\n            Settings::default()\n        }\n\n        fn window(&self) -> Option<iced_core::window::Settings> {\n            Some(window::Settings::default())\n        }\n    }\n\n    Application {\n        raw: Instance {\n            boot,\n            update,\n            view,\n            _state: PhantomData,\n            _message: PhantomData,\n            _theme: PhantomData,\n            _renderer: PhantomData,\n        },\n        settings: Settings::default(),\n        window: window::Settings::default(),\n        presets: Vec::new(),\n    }\n}\n\n/// The underlying definition and configuration of an iced application.\n///\n/// You can use this API to create and run iced applications\n/// step by step—without coupling your logic to a trait\n/// or a specific type.\n///\n/// You can create an [`Application`] with the [`application`] helper.\n#[derive(Debug)]\npub struct Application<P: Program> {\n    raw: P,\n    settings: Settings,\n    window: window::Settings,\n    presets: Vec<Preset<P::State, P::Message>>,\n}\n\nimpl<P: Program> Application<P> {\n    /// Runs the [`Application`].\n    pub fn run(self) -> Result\n    where\n        Self: 'static,\n        P::Message: message::MaybeDebug + message::MaybeClone,\n    {\n        #[cfg(feature = \"debug\")]\n        iced_debug::init(iced_debug::Metadata {\n            name: P::name(),\n            theme: None,\n            can_time_travel: cfg!(feature = \"time-travel\"),\n        });\n\n        #[cfg(feature = \"tester\")]\n        let program = iced_tester::attach(self);\n\n        #[cfg(all(\n            feature = \"debug\",\n            not(feature = \"tester\"),\n            not(target_arch = \"wasm32\")\n        ))]\n        let program = iced_devtools::attach(self);\n\n        #[cfg(not(any(\n            feature = \"tester\",\n            all(feature = \"debug\", not(target_arch = \"wasm32\"))\n        )))]\n        let program = self;\n\n        Ok(shell::run(program)?)\n    }\n\n    /// Sets the [`Settings`] that will be used to run the [`Application`].\n    pub fn settings(self, settings: Settings) -> Self {\n        Self { settings, ..self }\n    }\n\n    /// Sets the [`Settings::antialiasing`] of the [`Application`].\n    pub fn antialiasing(self, antialiasing: bool) -> Self {\n        Self {\n            settings: Settings {\n                antialiasing,\n                ..self.settings\n            },\n            ..self\n        }\n    }\n\n    /// Sets the default [`Font`] of the [`Application`].\n    pub fn default_font(self, default_font: Font) -> Self {\n        Self {\n            settings: Settings {\n                default_font,\n                ..self.settings\n            },\n            ..self\n        }\n    }\n\n    /// Adds a font to the list of fonts that will be loaded at the start of the [`Application`].\n    pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {\n        self.settings.fonts.push(font.into());\n        self\n    }\n\n    /// Sets the [`window::Settings`] of the [`Application`].\n    ///\n    /// Overwrites any previous [`window::Settings`].\n    pub fn window(self, window: window::Settings) -> Self {\n        Self { window, ..self }\n    }\n\n    /// Sets the [`window::Settings::position`] to [`window::Position::Centered`] in the [`Application`].\n    pub fn centered(self) -> Self {\n        Self {\n            window: window::Settings {\n                position: window::Position::Centered,\n                ..self.window\n            },\n            ..self\n        }\n    }\n\n    /// Sets the [`window::Settings::exit_on_close_request`] of the [`Application`].\n    pub fn exit_on_close_request(self, exit_on_close_request: bool) -> Self {\n        Self {\n            window: window::Settings {\n                exit_on_close_request,\n                ..self.window\n            },\n            ..self\n        }\n    }\n\n    /// Sets the [`window::Settings::size`] of the [`Application`].\n    pub fn window_size(self, size: impl Into<Size>) -> Self {\n        Self {\n            window: window::Settings {\n                size: size.into(),\n                ..self.window\n            },\n            ..self\n        }\n    }\n\n    /// Sets the [`window::Settings::transparent`] of the [`Application`].\n    pub fn transparent(self, transparent: bool) -> Self {\n        Self {\n            window: window::Settings {\n                transparent,\n                ..self.window\n            },\n            ..self\n        }\n    }\n\n    /// Sets the [`window::Settings::resizable`] of the [`Application`].\n    pub fn resizable(self, resizable: bool) -> Self {\n        Self {\n            window: window::Settings {\n                resizable,\n                ..self.window\n            },\n            ..self\n        }\n    }\n\n    /// Sets the [`window::Settings::decorations`] of the [`Application`].\n    pub fn decorations(self, decorations: bool) -> Self {\n        Self {\n            window: window::Settings {\n                decorations,\n                ..self.window\n            },\n            ..self\n        }\n    }\n\n    /// Sets the [`window::Settings::position`] of the [`Application`].\n    pub fn position(self, position: window::Position) -> Self {\n        Self {\n            window: window::Settings {\n                position,\n                ..self.window\n            },\n            ..self\n        }\n    }\n\n    /// Sets the [`window::Settings::level`] of the [`Application`].\n    pub fn level(self, level: window::Level) -> Self {\n        Self {\n            window: window::Settings {\n                level,\n                ..self.window\n            },\n            ..self\n        }\n    }\n\n    /// Sets the title of the [`Application`].\n    pub fn title(\n        self,\n        title: impl TitleFn<P::State>,\n    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Application {\n            raw: program::with_title(self.raw, move |state, _window| title.title(state)),\n            settings: self.settings,\n            window: self.window,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the subscription logic of the [`Application`].\n    pub fn subscription(\n        self,\n        f: impl Fn(&P::State) -> Subscription<P::Message>,\n    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Application {\n            raw: program::with_subscription(self.raw, f),\n            settings: self.settings,\n            window: self.window,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the theme logic of the [`Application`].\n    pub fn theme(\n        self,\n        f: impl ThemeFn<P::State, P::Theme>,\n    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Application {\n            raw: program::with_theme(self.raw, move |state, _window| f.theme(state)),\n            settings: self.settings,\n            window: self.window,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the style logic of the [`Application`].\n    pub fn style(\n        self,\n        f: impl Fn(&P::State, &P::Theme) -> theme::Style,\n    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Application {\n            raw: program::with_style(self.raw, f),\n            settings: self.settings,\n            window: self.window,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the scale factor of the [`Application`].\n    pub fn scale_factor(\n        self,\n        f: impl Fn(&P::State) -> f32,\n    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Application {\n            raw: program::with_scale_factor(self.raw, move |state, _window| f(state)),\n            settings: self.settings,\n            window: self.window,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the executor of the [`Application`].\n    pub fn executor<E>(\n        self,\n    ) -> Application<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>>\n    where\n        E: Executor,\n    {\n        Application {\n            raw: program::with_executor::<P, E>(self.raw),\n            settings: self.settings,\n            window: self.window,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the boot presets of the [`Application`].\n    ///\n    /// Presets can be used to override the default booting strategy\n    /// of your application during testing to create reproducible\n    /// environments.\n    pub fn presets(self, presets: impl IntoIterator<Item = Preset<P::State, P::Message>>) -> Self {\n        Self {\n            presets: presets.into_iter().collect(),\n            ..self\n        }\n    }\n}\n\nimpl<P: Program> Program for Application<P> {\n    type State = P::State;\n    type Message = P::Message;\n    type Theme = P::Theme;\n    type Renderer = P::Renderer;\n    type Executor = P::Executor;\n\n    fn name() -> &'static str {\n        P::name()\n    }\n\n    fn settings(&self) -> Settings {\n        self.settings.clone()\n    }\n\n    fn window(&self) -> Option<window::Settings> {\n        Some(self.window.clone())\n    }\n\n    fn boot(&self) -> (Self::State, Task<Self::Message>) {\n        self.raw.boot()\n    }\n\n    fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n        debug::hot(|| self.raw.update(state, message))\n    }\n\n    fn view<'a>(\n        &self,\n        state: &'a Self::State,\n        window: window::Id,\n    ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n        debug::hot(|| self.raw.view(state, window))\n    }\n\n    fn title(&self, state: &Self::State, window: window::Id) -> String {\n        debug::hot(|| self.raw.title(state, window))\n    }\n\n    fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n        debug::hot(|| self.raw.subscription(state))\n    }\n\n    fn theme(&self, state: &Self::State, window: iced_core::window::Id) -> Option<Self::Theme> {\n        debug::hot(|| self.raw.theme(state, window))\n    }\n\n    fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n        debug::hot(|| self.raw.style(state, theme))\n    }\n\n    fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n        debug::hot(|| self.raw.scale_factor(state, window))\n    }\n\n    fn presets(&self) -> &[Preset<Self::State, Self::Message>] {\n        &self.presets\n    }\n}\n\n/// The logic to initialize the `State` of some [`Application`].\n///\n/// This trait is implemented for both `Fn() -> State` and\n/// `Fn() -> (State, Task<Message>)`.\n///\n/// In practice, this means that [`application`] can both take\n/// simple functions like `State::default` and more advanced ones\n/// that return a [`Task`].\npub trait BootFn<State, Message> {\n    /// Initializes the [`Application`] state.\n    fn boot(&self) -> (State, Task<Message>);\n}\n\nimpl<T, C, State, Message> BootFn<State, Message> for T\nwhere\n    T: Fn() -> C,\n    C: IntoBoot<State, Message>,\n{\n    fn boot(&self) -> (State, Task<Message>) {\n        self().into_boot()\n    }\n}\n\n/// The initial state of some [`Application`].\npub trait IntoBoot<State, Message> {\n    /// Turns some type into the initial state of some [`Application`].\n    fn into_boot(self) -> (State, Task<Message>);\n}\n\nimpl<State, Message> IntoBoot<State, Message> for State {\n    fn into_boot(self) -> (State, Task<Message>) {\n        (self, Task::none())\n    }\n}\n\nimpl<State, Message> IntoBoot<State, Message> for (State, Task<Message>) {\n    fn into_boot(self) -> (State, Task<Message>) {\n        self\n    }\n}\n\n/// The title logic of some [`Application`].\n///\n/// This trait is implemented both for `&static str` and\n/// any closure `Fn(&State) -> String`.\n///\n/// This trait allows the [`application`] builder to take any of them.\npub trait TitleFn<State> {\n    /// Produces the title of the [`Application`].\n    fn title(&self, state: &State) -> String;\n}\n\nimpl<State> TitleFn<State> for &'static str {\n    fn title(&self, _state: &State) -> String {\n        self.to_string()\n    }\n}\n\nimpl<T, State> TitleFn<State> for T\nwhere\n    T: Fn(&State) -> String,\n{\n    fn title(&self, state: &State) -> String {\n        self(state)\n    }\n}\n\n/// The update logic of some [`Application`].\n///\n/// This trait allows the [`application`] builder to take any closure that\n/// returns any `Into<Task<Message>>`.\npub trait UpdateFn<State, Message> {\n    /// Processes the message and updates the state of the [`Application`].\n    fn update(&self, state: &mut State, message: Message) -> Task<Message>;\n}\n\nimpl<State> UpdateFn<State, Never> for () {\n    fn update(&self, _state: &mut State, _message: Never) -> Task<Never> {\n        Task::none()\n    }\n}\n\nimpl<T, State, Message, C> UpdateFn<State, Message> for T\nwhere\n    T: Fn(&mut State, Message) -> C,\n    C: Into<Task<Message>>,\n{\n    fn update(&self, state: &mut State, message: Message) -> Task<Message> {\n        self(state, message).into()\n    }\n}\n\n/// The view logic of some [`Application`].\n///\n/// This trait allows the [`application`] builder to take any closure that\n/// returns any `Into<Element<'_, Message>>`.\npub trait ViewFn<'a, State, Message, Theme, Renderer> {\n    /// Produces the widget of the [`Application`].\n    fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer>;\n}\n\nimpl<'a, T, State, Message, Theme, Renderer, Widget> ViewFn<'a, State, Message, Theme, Renderer>\n    for T\nwhere\n    T: Fn(&'a State) -> Widget,\n    State: 'static,\n    Widget: Into<Element<'a, Message, Theme, Renderer>>,\n{\n    fn view(&self, state: &'a State) -> Element<'a, Message, Theme, Renderer> {\n        self(state).into()\n    }\n}\n\n/// The theme logic of some [`Application`].\n///\n/// Any implementors of this trait can be provided as an argument to\n/// [`Application::theme`].\n///\n/// `iced` provides two implementors:\n/// - the built-in [`Theme`] itself\n/// - and any `Fn(&State) -> impl Into<Option<Theme>>`.\npub trait ThemeFn<State, Theme> {\n    /// Returns the theme of the [`Application`] for the current state.\n    ///\n    /// If `None` is returned, `iced` will try to use a theme that\n    /// matches the system color scheme.\n    fn theme(&self, state: &State) -> Option<Theme>;\n}\n\nimpl<State> ThemeFn<State, Theme> for Theme {\n    fn theme(&self, _state: &State) -> Option<Theme> {\n        Some(self.clone())\n    }\n}\n\nimpl<F, T, State, Theme> ThemeFn<State, Theme> for F\nwhere\n    F: Fn(&State) -> T,\n    T: Into<Option<Theme>>,\n{\n    fn theme(&self, state: &State) -> Option<Theme> {\n        (self)(state).into()\n    }\n}\n"
  },
  {
    "path": "src/daemon.rs",
    "content": "//! Create and run daemons that run in the background.\nuse crate::application;\nuse crate::message;\nuse crate::program::{self, Program};\nuse crate::shell;\nuse crate::theme;\nuse crate::window;\nuse crate::{Element, Executor, Font, Preset, Result, Settings, Subscription, Task, Theme};\n\nuse iced_debug as debug;\n\nuse std::borrow::Cow;\n\n/// Creates an iced [`Daemon`] given its boot, update, and view logic.\n///\n/// A [`Daemon`] will not open a window by default, but will run silently\n/// instead until a [`Task`] from [`window::open`] is returned by its update logic.\n///\n/// Furthermore, a [`Daemon`] will not stop running when all its windows are closed.\n/// In order to completely terminate a [`Daemon`], its process must be interrupted or\n/// its update logic must produce a [`Task`] from [`exit`].\n///\n/// [`exit`]: crate::exit\npub fn daemon<State, Message, Theme, Renderer>(\n    boot: impl application::BootFn<State, Message>,\n    update: impl application::UpdateFn<State, Message>,\n    view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>,\n) -> Daemon<impl Program<State = State, Message = Message, Theme = Theme>>\nwhere\n    State: 'static,\n    Message: Send + 'static,\n    Theme: theme::Base,\n    Renderer: program::Renderer,\n{\n    use std::marker::PhantomData;\n\n    struct Instance<State, Message, Theme, Renderer, Boot, Update, View> {\n        boot: Boot,\n        update: Update,\n        view: View,\n        _state: PhantomData<State>,\n        _message: PhantomData<Message>,\n        _theme: PhantomData<Theme>,\n        _renderer: PhantomData<Renderer>,\n    }\n\n    impl<State, Message, Theme, Renderer, Boot, Update, View> Program\n        for Instance<State, Message, Theme, Renderer, Boot, Update, View>\n    where\n        Message: Send + 'static,\n        Theme: theme::Base,\n        Renderer: program::Renderer,\n        Boot: application::BootFn<State, Message>,\n        Update: application::UpdateFn<State, Message>,\n        View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>,\n    {\n        type State = State;\n        type Message = Message;\n        type Theme = Theme;\n        type Renderer = Renderer;\n        type Executor = iced_futures::backend::default::Executor;\n\n        fn name() -> &'static str {\n            let name = std::any::type_name::<State>();\n\n            name.split(\"::\").next().unwrap_or(\"a_cool_daemon\")\n        }\n\n        fn settings(&self) -> Settings {\n            Settings::default()\n        }\n\n        fn window(&self) -> Option<iced_core::window::Settings> {\n            None\n        }\n\n        fn boot(&self) -> (Self::State, Task<Self::Message>) {\n            self.boot.boot()\n        }\n\n        fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n            self.update.update(state, message)\n        }\n\n        fn view<'a>(\n            &self,\n            state: &'a Self::State,\n            window: window::Id,\n        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n            self.view.view(state, window)\n        }\n    }\n\n    Daemon {\n        raw: Instance {\n            boot,\n            update,\n            view,\n            _state: PhantomData,\n            _message: PhantomData,\n            _theme: PhantomData,\n            _renderer: PhantomData,\n        },\n        settings: Settings::default(),\n        presets: Vec::new(),\n    }\n}\n\n/// The underlying definition and configuration of an iced daemon.\n///\n/// You can use this API to create and run iced applications\n/// step by step—without coupling your logic to a trait\n/// or a specific type.\n///\n/// You can create a [`Daemon`] with the [`daemon`] helper.\n#[derive(Debug)]\npub struct Daemon<P: Program> {\n    raw: P,\n    settings: Settings,\n    presets: Vec<Preset<P::State, P::Message>>,\n}\n\nimpl<P: Program> Daemon<P> {\n    /// Runs the [`Daemon`].\n    pub fn run(self) -> Result\n    where\n        Self: 'static,\n        P::Message: message::MaybeDebug + message::MaybeClone,\n    {\n        #[cfg(feature = \"debug\")]\n        iced_debug::init(iced_debug::Metadata {\n            name: P::name(),\n            theme: None,\n            can_time_travel: cfg!(feature = \"time-travel\"),\n        });\n\n        #[cfg(feature = \"tester\")]\n        let program = iced_tester::attach(self);\n\n        #[cfg(all(feature = \"debug\", not(feature = \"tester\")))]\n        let program = iced_devtools::attach(self);\n\n        #[cfg(not(any(feature = \"tester\", feature = \"debug\")))]\n        let program = self;\n\n        Ok(shell::run(program)?)\n    }\n\n    /// Sets the [`Settings`] that will be used to run the [`Daemon`].\n    pub fn settings(self, settings: Settings) -> Self {\n        Self { settings, ..self }\n    }\n\n    /// Sets the [`Settings::antialiasing`] of the [`Daemon`].\n    pub fn antialiasing(self, antialiasing: bool) -> Self {\n        Self {\n            settings: Settings {\n                antialiasing,\n                ..self.settings\n            },\n            ..self\n        }\n    }\n\n    /// Sets the default [`Font`] of the [`Daemon`].\n    pub fn default_font(self, default_font: Font) -> Self {\n        Self {\n            settings: Settings {\n                default_font,\n                ..self.settings\n            },\n            ..self\n        }\n    }\n\n    /// Adds a font to the list of fonts that will be loaded at the start of the [`Daemon`].\n    pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {\n        self.settings.fonts.push(font.into());\n        self\n    }\n\n    /// Sets the title of the [`Daemon`].\n    pub fn title(\n        self,\n        title: impl TitleFn<P::State>,\n    ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Daemon {\n            raw: program::with_title(self.raw, move |state, window| title.title(state, window)),\n            settings: self.settings,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the subscription logic of the [`Daemon`].\n    pub fn subscription(\n        self,\n        f: impl Fn(&P::State) -> Subscription<P::Message>,\n    ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Daemon {\n            raw: program::with_subscription(self.raw, f),\n            settings: self.settings,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the theme logic of the [`Daemon`].\n    pub fn theme(\n        self,\n        f: impl ThemeFn<P::State, P::Theme>,\n    ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Daemon {\n            raw: program::with_theme(self.raw, move |state, window| f.theme(state, window)),\n            settings: self.settings,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the style logic of the [`Daemon`].\n    pub fn style(\n        self,\n        f: impl Fn(&P::State, &P::Theme) -> theme::Style,\n    ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Daemon {\n            raw: program::with_style(self.raw, f),\n            settings: self.settings,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the scale factor of the [`Daemon`].\n    pub fn scale_factor(\n        self,\n        f: impl Fn(&P::State, window::Id) -> f32,\n    ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>> {\n        Daemon {\n            raw: program::with_scale_factor(self.raw, f),\n            settings: self.settings,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the executor of the [`Daemon`].\n    pub fn executor<E>(\n        self,\n    ) -> Daemon<impl Program<State = P::State, Message = P::Message, Theme = P::Theme>>\n    where\n        E: Executor,\n    {\n        Daemon {\n            raw: program::with_executor::<P, E>(self.raw),\n            settings: self.settings,\n            presets: self.presets,\n        }\n    }\n\n    /// Sets the boot presets of the [`Daemon`].\n    ///\n    /// Presets can be used to override the default booting strategy\n    /// of your application during testing to create reproducible\n    /// environments.\n    pub fn presets(self, presets: impl IntoIterator<Item = Preset<P::State, P::Message>>) -> Self {\n        Self {\n            presets: presets.into_iter().collect(),\n            ..self\n        }\n    }\n}\n\nimpl<P: Program> Program for Daemon<P> {\n    type State = P::State;\n    type Message = P::Message;\n    type Theme = P::Theme;\n    type Renderer = P::Renderer;\n    type Executor = P::Executor;\n\n    fn name() -> &'static str {\n        P::name()\n    }\n\n    fn settings(&self) -> Settings {\n        self.settings.clone()\n    }\n\n    fn window(&self) -> Option<window::Settings> {\n        None\n    }\n\n    fn boot(&self) -> (Self::State, Task<Self::Message>) {\n        self.raw.boot()\n    }\n\n    fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n        debug::hot(|| self.raw.update(state, message))\n    }\n\n    fn view<'a>(\n        &self,\n        state: &'a Self::State,\n        window: window::Id,\n    ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n        debug::hot(|| self.raw.view(state, window))\n    }\n\n    fn title(&self, state: &Self::State, window: window::Id) -> String {\n        debug::hot(|| self.raw.title(state, window))\n    }\n\n    fn subscription(&self, state: &Self::State) -> Subscription<Self::Message> {\n        debug::hot(|| self.raw.subscription(state))\n    }\n\n    fn theme(&self, state: &Self::State, window: iced_core::window::Id) -> Option<Self::Theme> {\n        debug::hot(|| self.raw.theme(state, window))\n    }\n\n    fn style(&self, state: &Self::State, theme: &Self::Theme) -> theme::Style {\n        debug::hot(|| self.raw.style(state, theme))\n    }\n\n    fn scale_factor(&self, state: &Self::State, window: window::Id) -> f32 {\n        debug::hot(|| self.raw.scale_factor(state, window))\n    }\n\n    fn presets(&self) -> &[Preset<Self::State, Self::Message>] {\n        &self.presets\n    }\n}\n\n/// The title logic of some [`Daemon`].\n///\n/// This trait is implemented both for `&static str` and\n/// any closure `Fn(&State, window::Id) -> String`.\n///\n/// This trait allows the [`daemon`] builder to take any of them.\npub trait TitleFn<State> {\n    /// Produces the title of the [`Daemon`].\n    fn title(&self, state: &State, window: window::Id) -> String;\n}\n\nimpl<State> TitleFn<State> for &'static str {\n    fn title(&self, _state: &State, _window: window::Id) -> String {\n        self.to_string()\n    }\n}\n\nimpl<T, State> TitleFn<State> for T\nwhere\n    T: Fn(&State, window::Id) -> String,\n{\n    fn title(&self, state: &State, window: window::Id) -> String {\n        self(state, window)\n    }\n}\n\n/// The view logic of some [`Daemon`].\n///\n/// This trait allows the [`daemon`] builder to take any closure that\n/// returns any `Into<Element<'_, Message>>`.\npub trait ViewFn<'a, State, Message, Theme, Renderer> {\n    /// Produces the widget of the [`Daemon`].\n    fn view(&self, state: &'a State, window: window::Id) -> Element<'a, Message, Theme, Renderer>;\n}\n\nimpl<'a, T, State, Message, Theme, Renderer, Widget> ViewFn<'a, State, Message, Theme, Renderer>\n    for T\nwhere\n    T: Fn(&'a State, window::Id) -> Widget,\n    State: 'static,\n    Widget: Into<Element<'a, Message, Theme, Renderer>>,\n{\n    fn view(&self, state: &'a State, window: window::Id) -> Element<'a, Message, Theme, Renderer> {\n        self(state, window).into()\n    }\n}\n\n/// The theme logic of some [`Daemon`].\n///\n/// Any implementors of this trait can be provided as an argument to\n/// [`Daemon::theme`].\n///\n/// `iced` provides two implementors:\n/// - the built-in [`Theme`] itself\n/// - and any `Fn(&State, window::Id) -> impl Into<Option<Theme>>`.\npub trait ThemeFn<State, Theme> {\n    /// Returns the theme of the [`Daemon`] for the current state and window.\n    ///\n    /// If `None` is returned, `iced` will try to use a theme that\n    /// matches the system color scheme.\n    fn theme(&self, state: &State, window: window::Id) -> Option<Theme>;\n}\n\nimpl<State> ThemeFn<State, Theme> for Theme {\n    fn theme(&self, _state: &State, _window: window::Id) -> Option<Theme> {\n        Some(self.clone())\n    }\n}\n\nimpl<F, T, State, Theme> ThemeFn<State, Theme> for F\nwhere\n    F: Fn(&State, window::Id) -> T,\n    T: Into<Option<Theme>>,\n{\n    fn theme(&self, state: &State, window: window::Id) -> Option<Theme> {\n        (self)(state, window).into()\n    }\n}\n"
  },
  {
    "path": "src/error.rs",
    "content": "use crate::futures;\nuse crate::graphics;\nuse crate::shell;\n\n/// An error that occurred while running an application.\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    /// The futures executor could not be created.\n    #[error(\"the futures executor could not be created\")]\n    ExecutorCreationFailed(futures::io::Error),\n\n    /// The application window could not be created.\n    #[error(\"the application window could not be created\")]\n    WindowCreationFailed(Box<dyn std::error::Error + Send + Sync>),\n\n    /// The application graphics context could not be created.\n    #[error(\"the application graphics context could not be created\")]\n    GraphicsCreationFailed(graphics::Error),\n}\n\nimpl From<shell::Error> for Error {\n    fn from(error: shell::Error) -> Error {\n        match error {\n            shell::Error::ExecutorCreationFailed(error) => Error::ExecutorCreationFailed(error),\n            shell::Error::WindowCreationFailed(error) => {\n                Error::WindowCreationFailed(Box::new(error))\n            }\n            shell::Error::GraphicsCreationFailed(error) => Error::GraphicsCreationFailed(error),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn assert_send_sync() {\n        fn _assert<T: Send + Sync>() {}\n        _assert::<Error>();\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "//! iced is a cross-platform GUI library focused on simplicity and type-safety.\n//! Inspired by [Elm].\n//!\n//! [Elm]: https://elm-lang.org/\n//!\n//! # Disclaimer\n//! iced is __experimental__ software. If you expect the documentation to hold your hand\n//! as you learn the ropes, you are in for a frustrating experience.\n//!\n//! The library leverages Rust to its full extent: ownership, borrowing, lifetimes, futures,\n//! streams, first-class functions, trait bounds, closures, and more. This documentation\n//! is not meant to teach you any of these. Far from it, it will assume you have __mastered__\n//! all of them.\n//!\n//! Furthermore—just like Rust—iced is very unforgiving. It will not let you easily cut corners.\n//! The type signatures alone can be used to learn how to use most of the library.\n//! Everything is connected.\n//!\n//! Therefore, iced is easy to learn for __advanced__ Rust programmers; but plenty of patient\n//! beginners have learned it and had a good time with it. Since it leverages a lot of what\n//! Rust has to offer in a type-safe way, it can be a great way to discover Rust itself.\n//!\n//! If you don't like the sound of that, you expect to be spoonfed, or you feel frustrated\n//! and struggle to use the library; then I recommend you to wait patiently until [the book]\n//! is finished.\n//!\n//! [the book]: https://book.iced.rs\n//!\n//! # The Pocket Guide\n//! Start by calling [`run`]:\n//!\n//! ```no_run,standalone_crate\n//! pub fn main() -> iced::Result {\n//!     iced::run(update, view)\n//! }\n//! # fn update(state: &mut (), message: ()) {}\n//! # fn view(state: &()) -> iced::Element<'_, ()> { iced::widget::text(\"\").into() }\n//! ```\n//!\n//! Define an `update` function to __change__ your state:\n//!\n//! ```standalone_crate\n//! fn update(counter: &mut u64, message: Message) {\n//!     match message {\n//!         Message::Increment => *counter += 1,\n//!     }\n//! }\n//! # #[derive(Clone)]\n//! # enum Message { Increment }\n//! ```\n//!\n//! Define a `view` function to __display__ your state:\n//!\n//! ```standalone_crate\n//! use iced::widget::{button, text};\n//! use iced::Element;\n//!\n//! fn view(counter: &u64) -> Element<'_, Message> {\n//!     button(text(counter)).on_press(Message::Increment).into()\n//! }\n//! # #[derive(Clone)]\n//! # enum Message { Increment }\n//! ```\n//!\n//! And create a `Message` enum to __connect__ `view` and `update` together:\n//!\n//! ```standalone_crate\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     Increment,\n//! }\n//! ```\n//!\n//! ## Custom State\n//! You can define your own struct for your state:\n//!\n//! ```standalone_crate\n//! #[derive(Default)]\n//! struct Counter {\n//!     value: u64,\n//! }\n//! ```\n//!\n//! But you have to change `update` and `view` accordingly:\n//!\n//! ```standalone_crate\n//! # struct Counter { value: u64 }\n//! # #[derive(Clone)]\n//! # enum Message { Increment }\n//! # use iced::widget::{button, text};\n//! # use iced::Element;\n//! fn update(counter: &mut Counter, message: Message) {\n//!     match message {\n//!         Message::Increment => counter.value += 1,\n//!     }\n//! }\n//!\n//! fn view(counter: &Counter) -> Element<'_, Message> {\n//!     button(text(counter.value)).on_press(Message::Increment).into()\n//! }\n//! ```\n//!\n//! ## Widgets and Elements\n//! The `view` function must return an [`Element`]. An [`Element`] is just a generic [`widget`].\n//!\n//! The [`widget`] module contains a bunch of functions to help you build\n//! and use widgets.\n//!\n//! Widgets are configured using the builder pattern:\n//!\n//! ```standalone_crate\n//! # struct Counter { value: u64 }\n//! # #[derive(Clone)]\n//! # enum Message { Increment }\n//! use iced::widget::{button, column, text};\n//! use iced::Element;\n//!\n//! fn view(counter: &Counter) -> Element<'_, Message> {\n//!     column![\n//!         text(counter.value).size(20),\n//!         button(\"Increment\").on_press(Message::Increment),\n//!     ]\n//!     .spacing(10)\n//!     .into()\n//! }\n//! ```\n//!\n//! A widget can be turned into an [`Element`] by calling `into`.\n//!\n//! Widgets and elements are generic over the message type they produce. The\n//! [`Element`] returned by `view` must have the same `Message` type as\n//! your `update`.\n//!\n//! ## Layout\n//! There is no unified layout system in iced. Instead, each widget implements\n//! its own layout strategy.\n//!\n//! Building your layout will often consist in using a combination of\n//! [rows], [columns], and [containers]:\n//!\n//! ```standalone_crate\n//! # struct State;\n//! # enum Message {}\n//! use iced::widget::{column, container, row};\n//! use iced::{Fill, Element};\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     container(\n//!         column![\n//!             \"Top\",\n//!             row![\"Left\", \"Right\"].spacing(10),\n//!             \"Bottom\"\n//!         ]\n//!         .spacing(10)\n//!     )\n//!     .padding(10)\n//!     .center_x(Fill)\n//!     .center_y(Fill)\n//!     .into()\n//! }\n//! ```\n//!\n//! Rows and columns lay out their children horizontally and vertically,\n//! respectively. [Spacing] can be easily added between elements.\n//!\n//! Containers position or align a single widget inside their bounds.\n//!\n//! [rows]: widget::Row\n//! [columns]: widget::Column\n//! [containers]: widget::Container\n//! [Spacing]: widget::Column::spacing\n//!\n//! ## Sizing\n//! The width and height of widgets can generally be defined using a [`Length`].\n//!\n//! - [`Fill`] will make the widget take all the available space in a given axis.\n//! - [`Shrink`] will make the widget use its intrinsic size.\n//!\n//! Most widgets use a [`Shrink`] sizing strategy by default, but will inherit\n//! a [`Fill`] strategy from their children.\n//!\n//! A fixed numeric [`Length`] in [`Pixels`] can also be used:\n//!\n//! ```standalone_crate\n//! # struct State;\n//! # enum Message {}\n//! use iced::widget::container;\n//! use iced::Element;\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     container(\"I am 300px tall!\").height(300).into()\n//! }\n//! ```\n//!\n//! ## Theming\n//! The default [`Theme`] of an application can be changed by defining a `theme`\n//! function and leveraging the [`Application`] builder, instead of directly\n//! calling [`run`]:\n//!\n//! ```no_run,standalone_crate\n//! # struct State;\n//! use iced::Theme;\n//!\n//! pub fn main() -> iced::Result {\n//!     iced::application(new, update, view)\n//!         .theme(theme)\n//!         .run()\n//! }\n//!\n//! fn new() -> State {\n//!     // ...\n//!     # State\n//! }\n//!\n//! fn theme(state: &State) -> Theme {\n//!     Theme::TokyoNight\n//! }\n//! # fn update(state: &mut State, message: ()) {}\n//! # fn view(state: &State) -> iced::Element<'_, ()> { iced::widget::text(\"\").into() }\n//! ```\n//!\n//! The `theme` function takes the current state of the application, allowing the\n//! returned [`Theme`] to be completely dynamic—just like `view`.\n//!\n//! There are a bunch of built-in [`Theme`] variants at your disposal, but you can\n//! also [create your own](Theme::custom).\n//!\n//! ## Styling\n//! As with layout, iced does not have a unified styling system. However, all\n//! of the built-in widgets follow the same styling approach.\n//!\n//! The appearance of a widget can be changed by calling its `style` method:\n//!\n//! ```standalone_crate\n//! # struct State;\n//! # enum Message {}\n//! use iced::widget::container;\n//! use iced::Element;\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     container(\"I am a rounded box!\").style(container::rounded_box).into()\n//! }\n//! ```\n//!\n//! The `style` method of a widget takes a closure that, given the current active\n//! [`Theme`], returns the widget style:\n//!\n//! ```standalone_crate\n//! # struct State;\n//! # #[derive(Clone)]\n//! # enum Message {}\n//! use iced::widget::button;\n//! use iced::{Element, Theme};\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     button(\"I am a styled button!\").style(|theme: &Theme, status| {\n//!         let palette = theme.palette();\n//!\n//!         match status {\n//!             button::Status::Active => {\n//!                 button::Style::default()\n//!                    .with_background(palette.success.strong.color)\n//!             }\n//!             _ => button::primary(theme, status),\n//!         }\n//!     })\n//!     .into()\n//! }\n//! ```\n//!\n//! Widgets that can be in multiple different states will also provide the closure\n//! with some [`Status`], allowing you to use a different style for each state.\n//!\n//! You can extract the [`Palette`] colors of a [`Theme`] with the [`palette`] method.\n//!\n//! Most widgets provide styling functions for your convenience in their respective modules;\n//! like [`container::rounded_box`], [`button::primary`], or [`text::danger`].\n//!\n//! [`Status`]: widget::button::Status\n//! [`palette`]: Theme::palette\n//! [`container::rounded_box`]: widget::container::rounded_box\n//! [`button::primary`]: widget::button::primary\n//! [`text::danger`]: widget::text::danger\n//!\n//! ## Concurrent Tasks\n//! The `update` function can _optionally_ return a [`Task`].\n//!\n//! A [`Task`] can be leveraged to perform asynchronous work, like running a\n//! future or a stream:\n//!\n//! ```standalone_crate\n//! # #[derive(Clone)]\n//! # struct Weather;\n//! use iced::Task;\n//!\n//! struct State {\n//!     weather: Option<Weather>,\n//! }\n//!\n//! enum Message {\n//!    FetchWeather,\n//!    WeatherFetched(Weather),\n//! }\n//!\n//! fn update(state: &mut State, message: Message) -> Task<Message> {\n//!     match message {\n//!         Message::FetchWeather => Task::perform(\n//!             fetch_weather(),\n//!             Message::WeatherFetched,\n//!         ),\n//!         Message::WeatherFetched(weather) => {\n//!             state.weather = Some(weather);\n//!\n//!             Task::none()\n//!        }\n//!     }\n//! }\n//!\n//! async fn fetch_weather() -> Weather {\n//!     // ...\n//!     # unimplemented!()\n//! }\n//! ```\n//!\n//! Tasks can also be used to interact with the iced runtime. Some modules\n//! expose functions that create tasks for different purposes—like [changing\n//! window settings](window#functions), [focusing a widget](widget::operation::focus_next), or\n//! [querying its visible bounds](widget::selector::find).\n//!\n//! Like futures and streams, tasks expose [a monadic interface](Task::then)—but they can also be\n//! [mapped](Task::map), [chained](Task::chain), [batched](Task::batch), [canceled](Task::abortable),\n//! and more.\n//!\n//! ## Passive Subscriptions\n//! Applications can subscribe to passive sources of data—like time ticks or runtime events.\n//!\n//! You will need to define a `subscription` function and use the [`Application`] builder:\n//!\n//! ```no_run,standalone_crate\n//! # struct State;\n//! use iced::window;\n//! use iced::{Size, Subscription};\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     WindowResized(Size),\n//! }\n//!\n//! pub fn main() -> iced::Result {\n//!     iced::application(new, update, view)\n//!         .subscription(subscription)\n//!         .run()\n//! }\n//!\n//! fn subscription(state: &State) -> Subscription<Message> {\n//!     window::resize_events().map(|(_id, size)| Message::WindowResized(size))\n//! }\n//! # fn new() -> State { State }\n//! # fn update(state: &mut State, message: Message) {}\n//! # fn view(state: &State) -> iced::Element<'_, Message> { iced::widget::text(\"\").into() }\n//! ```\n//!\n//! A [`Subscription`] is [a _declarative_ builder of streams](Subscription#the-lifetime-of-a-subscription)\n//! that are not allowed to end on their own. Only the `subscription` function\n//! dictates the active subscriptions—just like `view` fully dictates the\n//! visible widgets of your user interface, at every moment.\n//!\n//! As with tasks, some modules expose convenient functions that build a [`Subscription`] for you—like\n//! [`time::every`] which can be used to listen to time, or [`keyboard::listen`] which will notify you\n//! of any keyboard events. But you can also create your own with [`Subscription::run`] and [`run_with`].\n//!\n//! [`run_with`]: Subscription::run_with\n//!\n//! ## Scaling Applications\n//! The `update`, `view`, and `Message` triplet composes very nicely.\n//!\n//! A common pattern is to leverage this composability to split an\n//! application into different screens:\n//!\n//! ```standalone_crate\n//! # mod contacts {\n//! #     use iced::{Element, Task};\n//! #     pub struct Contacts;\n//! #     impl Contacts {\n//! #         pub fn update(&mut self, message: Message) -> Action { unimplemented!() }\n//! #         pub fn view(&self) -> Element<Message> { unimplemented!() }\n//! #     }\n//! #     #[derive(Debug, Clone)]\n//! #     pub enum Message {}\n//! #     pub enum Action { None, Run(Task<Message>), Chat(()) }\n//! # }\n//! # mod conversation {\n//! #     use iced::{Element, Task};\n//! #     pub struct Conversation;\n//! #     impl Conversation {\n//! #         pub fn new(contact: ()) -> (Self, Task<Message>) { unimplemented!() }\n//! #         pub fn update(&mut self, message: Message) -> Task<Message> { unimplemented!() }\n//! #         pub fn view(&self) -> Element<Message> { unimplemented!() }\n//! #     }\n//! #     #[derive(Debug, Clone)]\n//! #     pub enum Message {}\n//! # }\n//! use contacts::Contacts;\n//! use conversation::Conversation;\n//!\n//! use iced::{Element, Task};\n//!\n//! struct State {\n//!     screen: Screen,\n//! }\n//!\n//! enum Screen {\n//!     Contacts(Contacts),\n//!     Conversation(Conversation),\n//! }\n//!\n//! enum Message {\n//!    Contacts(contacts::Message),\n//!    Conversation(conversation::Message)\n//! }\n//!\n//! fn update(state: &mut State, message: Message) -> Task<Message> {\n//!     match message {\n//!         Message::Contacts(message) => {\n//!             if let Screen::Contacts(contacts) = &mut state.screen {\n//!                 let action = contacts.update(message);\n//!\n//!                 match action {\n//!                     contacts::Action::None => Task::none(),\n//!                     contacts::Action::Run(task) => task.map(Message::Contacts),\n//!                     contacts::Action::Chat(contact) => {\n//!                         let (conversation, task) = Conversation::new(contact);\n//!\n//!                         state.screen = Screen::Conversation(conversation);\n//!\n//!                         task.map(Message::Conversation)\n//!                     }\n//!                  }\n//!             } else {\n//!                 Task::none()    \n//!             }\n//!         }\n//!         Message::Conversation(message) => {\n//!             if let Screen::Conversation(conversation) = &mut state.screen {\n//!                 conversation.update(message).map(Message::Conversation)\n//!             } else {\n//!                 Task::none()    \n//!             }\n//!         }\n//!     }\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     match &state.screen {\n//!         Screen::Contacts(contacts) => contacts.view().map(Message::Contacts),\n//!         Screen::Conversation(conversation) => conversation.view().map(Message::Conversation),\n//!     }\n//! }\n//! ```\n//!\n//! The `update` method of a screen can return an `Action` enum that can be leveraged by the parent to\n//! execute a task or transition to a completely different screen altogether. The variants of `Action` can\n//! have associated data. For instance, in the example above, the `Conversation` screen is created when\n//! `Contacts::update` returns an `Action::Chat` with the selected contact.\n//!\n//! Effectively, this approach lets you \"tell a story\" to connect different screens together in a type safe\n//! way.\n//!\n//! Furthermore, functor methods like [`Task::map`], [`Element::map`], and [`Subscription::map`] make composition\n//! seamless.\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/iced-rs/iced/bdf0430880f5c29443f5f0a0ae4895866dfef4c6/docs/logo.svg\"\n)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\nuse iced_widget::graphics;\nuse iced_widget::renderer;\nuse iced_winit as shell;\nuse iced_winit::core;\nuse iced_winit::program;\nuse iced_winit::runtime;\n\npub use iced_futures::futures;\npub use iced_futures::stream;\n\n#[cfg(not(any(\n    target_arch = \"wasm32\",\n    feature = \"thread-pool\",\n    feature = \"tokio\",\n    feature = \"smol\"\n)))]\ncompile_error!(\n    \"No futures executor has been enabled! You must enable an \\\n    executor feature.\\n\\\n    Available options: thread-pool, tokio, or smol.\"\n);\n\n#[cfg(all(\n    target_family = \"unix\",\n    not(target_os = \"macos\"),\n    not(feature = \"wayland\"),\n    not(feature = \"x11\"),\n))]\ncompile_error!(\n    \"No Unix display server backend has been enabled. You must enable a \\\n    display server feature.\\n\\\n    Available options: x11, wayland.\"\n);\n\n#[cfg(feature = \"highlighter\")]\npub use iced_highlighter as highlighter;\n\n#[cfg(feature = \"wgpu\")]\npub use iced_renderer::wgpu::wgpu;\n\nmod error;\n\npub mod application;\npub mod daemon;\npub mod time;\npub mod window;\n\n#[cfg(feature = \"advanced\")]\npub mod advanced;\n\npub use crate::core::alignment;\npub use crate::core::animation;\npub use crate::core::border;\npub use crate::core::color;\npub use crate::core::gradient;\npub use crate::core::padding;\npub use crate::core::theme;\npub use crate::core::{\n    Alignment, Animation, Background, Border, Color, ContentFit, Degrees, Function, Gradient,\n    Length, Never, Padding, Pixels, Point, Radians, Rectangle, Rotation, Settings, Shadow, Size,\n    Theme, Transformation, Vector, never,\n};\npub use crate::program::Preset;\npub use crate::program::message;\npub use crate::runtime::exit;\npub use iced_futures::Subscription;\n\npub use Alignment::Center;\npub use Length::{Fill, FillPortion, Shrink};\npub use alignment::Horizontal::{Left, Right};\npub use alignment::Vertical::{Bottom, Top};\n\npub mod debug {\n    //! Debug your applications.\n    pub use iced_debug::{Span, time, time_with};\n}\n\npub mod task {\n    //! Create runtime tasks.\n    pub use crate::runtime::task::{Handle, Task};\n\n    #[cfg(feature = \"sipper\")]\n    pub use crate::runtime::task::{Never, Sipper, Straw, sipper, stream};\n}\n\npub mod clipboard {\n    //! Access the clipboard.\n    pub use crate::core::clipboard::{Content, Error, Kind};\n    pub use crate::runtime::clipboard::{read, read_files, read_html, read_text, write};\n\n    #[cfg(feature = \"image\")]\n    pub use crate::core::clipboard::Image;\n\n    #[cfg(feature = \"image\")]\n    pub use crate::runtime::clipboard::read_image;\n}\n\npub mod executor {\n    //! Choose your preferred executor to power your application.\n    pub use iced_futures::Executor;\n    pub use iced_futures::backend::default::Executor as Default;\n}\n\npub mod font {\n    //! Load and use fonts.\n    pub use crate::core::font::*;\n    pub use crate::runtime::font::*;\n}\n\npub mod event {\n    //! Handle events of a user interface.\n    pub use crate::core::event::{Event, Status};\n    pub use iced_futures::event::{listen, listen_raw, listen_url, listen_with};\n}\n\npub mod keyboard {\n    //! Listen and react to keyboard events.\n    pub use crate::core::keyboard::key;\n    pub use crate::core::keyboard::{Event, Key, Location, Modifiers};\n    pub use iced_futures::keyboard::listen;\n}\n\npub mod mouse {\n    //! Listen and react to mouse events.\n    pub use crate::core::mouse::{Button, Cursor, Event, Interaction, ScrollDelta};\n}\n\npub mod system {\n    //! Retrieve system information.\n    pub use crate::runtime::system::{theme, theme_changes};\n\n    #[cfg(feature = \"sysinfo\")]\n    pub use crate::runtime::system::{Information, information};\n}\n\npub mod overlay {\n    //! Display interactive elements on top of other widgets.\n\n    /// A generic overlay.\n    ///\n    /// This is an alias of an [`overlay::Element`] with a default `Renderer`.\n    ///\n    /// [`overlay::Element`]: crate::core::overlay::Element\n    pub type Element<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> =\n        crate::core::overlay::Element<'a, Message, Theme, Renderer>;\n\n    pub use iced_widget::overlay::*;\n}\n\npub mod touch {\n    //! Listen and react to touch events.\n    pub use crate::core::touch::{Event, Finger};\n}\n\n#[allow(hidden_glob_reexports)]\npub mod widget {\n    //! Use the built-in widgets or create your own.\n    pub use iced_runtime::widget::*;\n    pub use iced_widget::*;\n\n    #[cfg(feature = \"image\")]\n    pub mod image {\n        //! Images display raster graphics in different formats (PNG, JPG, etc.).\n        pub use iced_runtime::image::{Allocation, Error, allocate};\n        pub use iced_widget::image::*;\n    }\n\n    // We hide the re-exported modules by `iced_widget`\n    mod core {}\n    mod graphics {}\n    mod renderer {}\n}\n\npub use application::Application;\npub use daemon::Daemon;\npub use error::Error;\npub use event::Event;\npub use executor::Executor;\npub use font::Font;\npub use program::Program;\npub use renderer::Renderer;\npub use task::Task;\npub use window::Window;\n\n#[doc(inline)]\npub use application::application;\n#[doc(inline)]\npub use daemon::daemon;\n\n/// A generic widget.\n///\n/// This is an alias of an `iced_native` element with a default `Renderer`.\npub type Element<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> =\n    crate::core::Element<'a, Message, Theme, Renderer>;\n\n/// The result of running an iced program.\npub type Result = std::result::Result<(), Error>;\n\n/// Runs a basic iced application with default [`Settings`] given its update\n/// and view logic.\n///\n/// This is equivalent to chaining [`application()`] with [`Application::run`].\n///\n/// # Example\n/// ```no_run,standalone_crate\n/// use iced::widget::{button, column, text, Column};\n///\n/// pub fn main() -> iced::Result {\n///     iced::run(update, view)\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     Increment,\n/// }\n///\n/// fn update(value: &mut u64, message: Message) {\n///     match message {\n///         Message::Increment => *value += 1,\n///     }\n/// }\n///\n/// fn view(value: &u64) -> Column<Message> {\n///     column![\n///         text(value),\n///         button(\"+\").on_press(Message::Increment),\n///     ]\n/// }\n/// ```\npub fn run<State, Message, Theme, Renderer>(\n    update: impl application::UpdateFn<State, Message> + 'static,\n    view: impl for<'a> application::ViewFn<'a, State, Message, Theme, Renderer> + 'static,\n) -> Result\nwhere\n    State: Default + 'static,\n    Message: Send + message::MaybeDebug + message::MaybeClone + 'static,\n    Theme: theme::Base + 'static,\n    Renderer: program::Renderer + 'static,\n{\n    application(State::default, update, view).run()\n}\n"
  },
  {
    "path": "src/time.rs",
    "content": "//! Listen and react to time.\npub use crate::core::time::*;\n\n#[allow(unused_imports)]\n#[cfg_attr(\n    docsrs,\n    doc(cfg(any(feature = \"tokio\", feature = \"smol\", target_arch = \"wasm32\")))\n)]\npub use iced_futures::backend::default::time::*;\n\nuse crate::Task;\n\n/// Returns a [`Task`] that produces the current [`Instant`]\n/// by calling [`Instant::now`].\n///\n/// While you can call [`Instant::now`] directly in your application;\n/// that renders your application \"impure\" (i.e. no referential transparency).\n///\n/// You may care about purity if you want to leverage the `time-travel`\n/// feature properly.\npub fn now() -> Task<Instant> {\n    Task::future(async { Instant::now() })\n}\n"
  },
  {
    "path": "src/touch.rs",
    "content": "//! Listen and react to touch events.\npub use crate::core::touch::{Event, Finger};\n"
  },
  {
    "path": "src/window/icon.rs",
    "content": "//! Attach an icon to the window of your application.\npub use crate::core::window::icon::*;\n\nuse crate::core::window::icon;\n\nuse std::io;\n\n#[cfg(feature = \"image\")]\nuse std::path::Path;\n\n/// Creates an icon from an image file.\n///\n/// This will return an error in case the file is missing at run-time. You may prefer [`from_file_data`] instead.\n#[cfg(feature = \"image\")]\npub fn from_file<P: AsRef<Path>>(icon_path: P) -> Result<Icon, Error> {\n    let icon = image::ImageReader::open(icon_path)?.decode()?.to_rgba8();\n\n    Ok(icon::from_rgba(icon.to_vec(), icon.width(), icon.height())?)\n}\n\n/// Creates an icon from the content of an image file.\n///\n/// This content can be included in your application at compile-time, e.g. using the `include_bytes!` macro.\n/// You can pass an explicit file format. Otherwise, the file format will be guessed at runtime.\n#[cfg(feature = \"image\")]\npub fn from_file_data(\n    data: &[u8],\n    explicit_format: Option<image::ImageFormat>,\n) -> Result<Icon, Error> {\n    let mut icon = image::ImageReader::new(std::io::Cursor::new(data));\n\n    let icon_with_format = match explicit_format {\n        Some(format) => {\n            icon.set_format(format);\n            icon\n        }\n        None => icon.with_guessed_format()?,\n    };\n\n    let pixels = icon_with_format.decode()?.to_rgba8();\n\n    Ok(icon::from_rgba(\n        pixels.to_vec(),\n        pixels.width(),\n        pixels.height(),\n    )?)\n}\n\n/// An error produced when creating an [`Icon`].\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    /// The [`Icon`] is not valid.\n    #[error(\"The icon is invalid: {0}\")]\n    InvalidError(#[from] icon::Error),\n\n    /// The underlying OS failed to create the icon.\n    #[error(\"The underlying OS failed to create the window icon: {0}\")]\n    OsError(#[from] io::Error),\n\n    /// The `image` crate reported an error.\n    #[cfg(feature = \"image\")]\n    #[error(\"Unable to create icon from a file: {0}\")]\n    ImageError(#[from] image::error::ImageError),\n}\n"
  },
  {
    "path": "src/window.rs",
    "content": "//! Configure the window of your application in native platforms.\n\npub mod icon;\n\npub use icon::Icon;\n\npub use crate::core::window::*;\npub use crate::runtime::window::*;\n"
  },
  {
    "path": "test/Cargo.toml",
    "content": "[package]\nname = \"iced_test\"\ndescription = \"A library for testing iced applications in headless mode\"\nversion.workspace = true\nauthors.workspace = true\nedition.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\nrust-version.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\niced_runtime.workspace = true\niced_program.workspace = true\niced_selector.workspace = true\n\niced_futures.workspace = true\niced_futures.features = [\"thread-pool\"]\n\niced_renderer.workspace = true\niced_renderer.features = [\"fira-sans\"]\n\nnom.workspace = true\npng.workspace = true\nsha2.workspace = true\nthiserror.workspace = true\n"
  },
  {
    "path": "test/src/emulator.rs",
    "content": "//! Run your application in a headless runtime.\nuse crate::core;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::time::Instant;\nuse crate::core::widget;\nuse crate::core::window;\nuse crate::core::{Bytes, Element, Point, Size};\nuse crate::instruction;\nuse crate::program;\nuse crate::program::Program;\nuse crate::runtime;\nuse crate::runtime::futures::futures::StreamExt;\nuse crate::runtime::futures::futures::channel::mpsc;\nuse crate::runtime::futures::futures::stream;\nuse crate::runtime::futures::subscription;\nuse crate::runtime::futures::{Executor, Runtime};\nuse crate::runtime::task;\nuse crate::runtime::user_interface;\nuse crate::runtime::{Task, UserInterface};\nuse crate::{Instruction, Selector};\n\nuse std::fmt;\n\n/// A headless runtime that can run iced applications and execute\n/// [instructions](crate::Instruction).\n///\n/// An [`Emulator`] runs its program as faithfully as possible to the real thing.\n/// It will run subscriptions and tasks with the [`Executor`](Program::Executor) of\n/// the [`Program`].\n///\n/// If you want to run a simulation without side effects, use a [`Simulator`](crate::Simulator)\n/// instead.\npub struct Emulator<P: Program> {\n    state: P::State,\n    runtime: Runtime<P::Executor, mpsc::Sender<Event<P>>, Event<P>>,\n    renderer: P::Renderer,\n    mode: Mode,\n    size: Size,\n    window: core::window::Id,\n    cursor: mouse::Cursor,\n    cache: Option<user_interface::Cache>,\n    pending_tasks: usize,\n}\n\n/// An emulation event.\npub enum Event<P: Program> {\n    /// An action that must be [performed](Emulator::perform) by the [`Emulator`].\n    Action(Action<P>),\n    /// An [`Instruction`] failed to be executed.\n    Failed(Instruction),\n    /// The [`Emulator`] is ready.\n    Ready,\n}\n\n/// An action that must be [performed](Emulator::perform) by the [`Emulator`].\npub struct Action<P: Program>(Action_<P>);\n\nenum Action_<P: Program> {\n    Runtime(runtime::Action<P::Message>),\n    CountDown,\n}\n\nimpl<P: Program + 'static> Emulator<P> {\n    /// Creates a new [`Emulator`] of the [`Program`] with the given [`Mode`] and [`Size`].\n    ///\n    /// The [`Emulator`] will send [`Event`] notifications through the provided [`mpsc::Sender`].\n    ///\n    /// When the [`Emulator`] has finished booting, an [`Event::Ready`] will be produced.\n    pub fn new(sender: mpsc::Sender<Event<P>>, program: &P, mode: Mode, size: Size) -> Emulator<P> {\n        Self::with_preset(sender, program, mode, size, None)\n    }\n\n    /// Creates a new [`Emulator`] analogously to [`new`](Self::new), but it also takes a\n    /// [`program::Preset`] that will be used as the initial state.\n    ///\n    /// When the [`Emulator`] has finished booting, an [`Event::Ready`] will be produced.\n    pub fn with_preset(\n        sender: mpsc::Sender<Event<P>>,\n        program: &P,\n        mode: Mode,\n        size: Size,\n        preset: Option<&program::Preset<P::State, P::Message>>,\n    ) -> Emulator<P> {\n        use renderer::Headless;\n\n        let settings = program.settings();\n\n        // TODO: Error handling\n        let executor = P::Executor::new().expect(\"Create emulator executor\");\n\n        let renderer = executor\n            .block_on(P::Renderer::new(renderer::Settings::from(&settings), None))\n            .expect(\"Create emulator renderer\");\n\n        let runtime = Runtime::new(executor, sender);\n\n        let (state, task) = runtime.enter(|| {\n            if let Some(preset) = preset {\n                preset.boot()\n            } else {\n                program.boot()\n            }\n        });\n\n        let mut emulator = Self {\n            state,\n            runtime,\n            renderer,\n            mode,\n            size,\n            cursor: mouse::Cursor::Unavailable,\n            window: core::window::Id::unique(),\n            cache: Some(user_interface::Cache::default()),\n            pending_tasks: 0,\n        };\n\n        emulator.resubscribe(program);\n        emulator.wait_for(task);\n\n        emulator\n    }\n\n    /// Updates the state of the [`Emulator`] program.\n    ///\n    /// This is equivalent to calling the [`Program::update`] function,\n    /// resubscribing to any subscriptions, and running the resulting tasks\n    /// concurrently.\n    pub fn update(&mut self, program: &P, message: P::Message) {\n        let task = self\n            .runtime\n            .enter(|| program.update(&mut self.state, message));\n\n        self.resubscribe(program);\n\n        match self.mode {\n            Mode::Zen if self.pending_tasks > 0 => self.wait_for(task),\n            _ => {\n                if let Some(stream) = task::into_stream(task) {\n                    self.runtime.run(\n                        stream\n                            .map(Action_::Runtime)\n                            .map(Action)\n                            .map(Event::Action)\n                            .boxed(),\n                    );\n                }\n            }\n        }\n    }\n\n    /// Performs an [`Action`].\n    ///\n    /// Whenever an [`Emulator`] sends an [`Event::Action`], this\n    /// method must be called to proceed with the execution.\n    pub fn perform(&mut self, program: &P, action: Action<P>) {\n        match action.0 {\n            Action_::CountDown => {\n                if self.pending_tasks > 0 {\n                    self.pending_tasks -= 1;\n\n                    if self.pending_tasks == 0 {\n                        self.runtime.send(Event::Ready);\n                    }\n                }\n            }\n            Action_::Runtime(action) => match action {\n                runtime::Action::Output(message) => {\n                    self.update(program, message);\n                }\n                runtime::Action::Widget(operation) => {\n                    let mut user_interface = UserInterface::build(\n                        program.view(&self.state, self.window),\n                        self.size,\n                        self.cache.take().unwrap(),\n                        &mut self.renderer,\n                    );\n\n                    let mut operation = Some(operation);\n\n                    while let Some(mut current) = operation.take() {\n                        user_interface.operate(&self.renderer, &mut current);\n\n                        match current.finish() {\n                            widget::operation::Outcome::None => {}\n                            widget::operation::Outcome::Some(()) => {}\n                            widget::operation::Outcome::Chain(next) => {\n                                operation = Some(next);\n                            }\n                        }\n                    }\n\n                    self.cache = Some(user_interface.into_cache());\n                }\n                runtime::Action::Clipboard(action) => {\n                    // TODO\n                    dbg!(action);\n                }\n                runtime::Action::Window(action) => {\n                    use crate::runtime::window;\n\n                    match action {\n                        window::Action::Open(id, _settings, sender) => {\n                            self.window = id;\n\n                            let _ = sender.send(self.window);\n                        }\n                        window::Action::GetOldest(sender) | window::Action::GetLatest(sender) => {\n                            let _ = sender.send(Some(self.window));\n                        }\n                        window::Action::GetSize(id, sender) => {\n                            if id == self.window {\n                                let _ = sender.send(self.size);\n                            }\n                        }\n                        window::Action::GetMaximized(id, sender) => {\n                            if id == self.window {\n                                let _ = sender.send(false);\n                            }\n                        }\n                        window::Action::GetMinimized(id, sender) => {\n                            if id == self.window {\n                                let _ = sender.send(None);\n                            }\n                        }\n                        window::Action::GetPosition(id, sender) => {\n                            if id == self.window {\n                                let _ = sender.send(Some(Point::ORIGIN));\n                            }\n                        }\n                        window::Action::GetScaleFactor(id, sender) => {\n                            if id == self.window {\n                                let _ = sender.send(1.0);\n                            }\n                        }\n                        window::Action::GetMode(id, sender) => {\n                            if id == self.window {\n                                let _ = sender.send(core::window::Mode::Windowed);\n                            }\n                        }\n                        _ => {\n                            // Ignored\n                        }\n                    }\n                }\n                runtime::Action::System(action) => {\n                    // TODO\n                    dbg!(action);\n                }\n                runtime::Action::Font(action) => {\n                    // TODO\n                    dbg!(action);\n                }\n                runtime::Action::Image(action) => {\n                    // TODO\n                    dbg!(action);\n                }\n                iced_runtime::Action::Event { window, event } => {\n                    // TODO\n                    dbg!(window, event);\n                }\n                runtime::Action::Tick => {\n                    // TODO\n                }\n                runtime::Action::Exit => {\n                    // TODO\n                }\n                runtime::Action::Reload => {\n                    // TODO\n                }\n            },\n        }\n    }\n\n    /// Runs an [`Instruction`].\n    ///\n    /// If the [`Instruction`] executes successfully, an [`Event::Ready`] will be\n    /// produced by the [`Emulator`].\n    ///\n    /// Otherwise, an [`Event::Failed`] will be triggered.\n    pub fn run(&mut self, program: &P, instruction: &Instruction) {\n        let mut user_interface = UserInterface::build(\n            program.view(&self.state, self.window),\n            self.size,\n            self.cache.take().unwrap(),\n            &mut self.renderer,\n        );\n\n        let mut messages = Vec::new();\n\n        match instruction {\n            Instruction::Interact(interaction) => {\n                let Some(events) = interaction.events(|target| match target {\n                    instruction::Target::Id(id) => {\n                        use widget::Operation;\n\n                        let mut operation = Selector::find(widget::Id::from(id.to_owned()));\n\n                        user_interface.operate(\n                            &self.renderer,\n                            &mut widget::operation::black_box(&mut operation),\n                        );\n\n                        match operation.finish() {\n                            widget::operation::Outcome::Some(widget) => {\n                                Some(widget?.visible_bounds()?.center())\n                            }\n                            _ => None,\n                        }\n                    }\n                    instruction::Target::Text(text) => {\n                        use widget::Operation;\n\n                        let mut operation = Selector::find(text.as_str());\n\n                        user_interface.operate(\n                            &self.renderer,\n                            &mut widget::operation::black_box(&mut operation),\n                        );\n\n                        match operation.finish() {\n                            widget::operation::Outcome::Some(text) => {\n                                Some(text?.visible_bounds()?.center())\n                            }\n                            _ => None,\n                        }\n                    }\n                    instruction::Target::Point(position) => Some(*position),\n                }) else {\n                    self.runtime.send(Event::Failed(instruction.clone()));\n                    self.cache = Some(user_interface.into_cache());\n                    return;\n                };\n\n                for event in &events {\n                    if let core::Event::Mouse(mouse::Event::CursorMoved { position }) = event {\n                        self.cursor = mouse::Cursor::Available(*position);\n                    }\n                }\n\n                let (_state, _status) =\n                    user_interface.update(&events, self.cursor, &mut self.renderer, &mut messages);\n\n                self.cache = Some(user_interface.into_cache());\n\n                let task = self.runtime.enter(|| {\n                    Task::batch(\n                        messages\n                            .into_iter()\n                            .map(|message| program.update(&mut self.state, message)),\n                    )\n                });\n\n                self.resubscribe(program);\n                self.wait_for(task);\n            }\n            Instruction::Expect(expectation) => match expectation {\n                instruction::Expectation::Text(text) => {\n                    use widget::Operation;\n\n                    let mut operation = Selector::find(text.as_str());\n\n                    user_interface.operate(\n                        &self.renderer,\n                        &mut widget::operation::black_box(&mut operation),\n                    );\n\n                    match operation.finish() {\n                        widget::operation::Outcome::Some(Some(_text)) => {\n                            self.runtime.send(Event::Ready);\n                        }\n                        _ => {\n                            self.runtime.send(Event::Failed(instruction.clone()));\n                        }\n                    }\n\n                    self.cache = Some(user_interface.into_cache());\n                }\n            },\n        }\n    }\n\n    fn wait_for(&mut self, task: Task<P::Message>) {\n        if let Some(stream) = task::into_stream(task) {\n            match self.mode {\n                Mode::Zen => {\n                    self.pending_tasks += 1;\n\n                    self.runtime.run(\n                        stream\n                            .map(Action_::Runtime)\n                            .map(Action)\n                            .map(Event::Action)\n                            .chain(stream::once(async {\n                                Event::Action(Action(Action_::CountDown))\n                            }))\n                            .boxed(),\n                    );\n                }\n                Mode::Patient => {\n                    self.runtime.run(\n                        stream\n                            .map(Action_::Runtime)\n                            .map(Action)\n                            .map(Event::Action)\n                            .chain(stream::once(async { Event::Ready }))\n                            .boxed(),\n                    );\n                }\n                Mode::Immediate => {\n                    self.runtime.run(\n                        stream\n                            .map(Action_::Runtime)\n                            .map(Action)\n                            .map(Event::Action)\n                            .boxed(),\n                    );\n                    self.runtime.send(Event::Ready);\n                }\n            }\n        } else if self.pending_tasks == 0 {\n            self.runtime.send(Event::Ready);\n        }\n    }\n\n    fn resubscribe(&mut self, program: &P) {\n        self.runtime\n            .track(subscription::into_recipes(self.runtime.enter(|| {\n                program.subscription(&self.state).map(|message| {\n                    Event::Action(Action(Action_::Runtime(runtime::Action::Output(message))))\n                })\n            })));\n    }\n\n    /// Returns the current view of the [`Emulator`].\n    pub fn view(&self, program: &P) -> Element<'_, P::Message, P::Theme, P::Renderer> {\n        program.view(&self.state, self.window)\n    }\n\n    /// Returns the current theme of the [`Emulator`].\n    pub fn theme(&self, program: &P) -> Option<P::Theme> {\n        program.theme(&self.state, self.window)\n    }\n\n    /// Takes a [`window::Screenshot`] of the current state of the [`Emulator`].\n    pub fn screenshot(\n        &mut self,\n        program: &P,\n        theme: &P::Theme,\n        scale_factor: f32,\n    ) -> window::Screenshot {\n        use core::renderer::Headless;\n\n        let style = program.style(&self.state, theme);\n\n        let mut user_interface = UserInterface::build(\n            program.view(&self.state, self.window),\n            self.size,\n            self.cache.take().unwrap(),\n            &mut self.renderer,\n        );\n\n        // TODO: Nested redraws!\n        let _ = user_interface.update(\n            &[core::Event::Window(window::Event::RedrawRequested(\n                Instant::now(),\n            ))],\n            mouse::Cursor::Unavailable,\n            &mut self.renderer,\n            &mut Vec::new(),\n        );\n\n        user_interface.draw(\n            &mut self.renderer,\n            theme,\n            &renderer::Style {\n                text_color: style.text_color,\n            },\n            mouse::Cursor::Unavailable,\n        );\n\n        let physical_size = Size::new(\n            (self.size.width * scale_factor).round() as u32,\n            (self.size.height * scale_factor).round() as u32,\n        );\n\n        let rgba = self\n            .renderer\n            .screenshot(physical_size, scale_factor, style.background_color);\n\n        window::Screenshot {\n            rgba: Bytes::from(rgba),\n            size: physical_size,\n            scale_factor,\n        }\n    }\n\n    /// Turns the [`Emulator`] into its internal state.\n    pub fn into_state(self) -> (P::State, core::window::Id) {\n        (self.state, self.window)\n    }\n}\n\n/// The strategy used by an [`Emulator`] when waiting for tasks to finish.\n///\n/// A [`Mode`] can be used to make an [`Emulator`] wait for side effects to finish before\n/// continuing execution.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum Mode {\n    /// Waits for all tasks spawned by an [`Instruction`], as well as all tasks indirectly\n    /// spawned by the the results of those tasks.\n    ///\n    /// This is the default.\n    #[default]\n    Zen,\n    /// Waits only for the tasks directly spawned by an [`Instruction`].\n    Patient,\n    /// Never waits for any tasks to finish.\n    Immediate,\n}\n\nimpl Mode {\n    /// A list of all the available modes.\n    pub const ALL: &[Self] = &[Self::Zen, Self::Patient, Self::Immediate];\n}\n\nimpl fmt::Display for Mode {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(match self {\n            Self::Zen => \"Zen\",\n            Self::Patient => \"Patient\",\n            Self::Immediate => \"Immediate\",\n        })\n    }\n}\n"
  },
  {
    "path": "test/src/error.rs",
    "content": "use crate::Instruction;\nuse crate::ice;\n\nuse std::io;\nuse std::path::PathBuf;\nuse std::sync::Arc;\n\n/// A test error.\n#[derive(Debug, Clone, thiserror::Error)]\npub enum Error {\n    /// No matching widget was found for the [`Selector`](crate::Selector).\n    #[error(\"no matching widget was found for the selector: {selector}\")]\n    SelectorNotFound {\n        /// A description of the selector.\n        selector: String,\n    },\n    /// A target matched, but is not visible.\n    #[error(\"the matching target is not visible: {target:?}\")]\n    TargetNotVisible {\n        /// The target\n        target: Arc<dyn std::fmt::Debug + Send + Sync>,\n    },\n    /// An IO operation failed.\n    #[error(\"an IO operation failed: {0}\")]\n    IOFailed(Arc<io::Error>),\n    /// The decoding of some PNG image failed.\n    #[error(\"the decoding of some PNG image failed: {0}\")]\n    PngDecodingFailed(Arc<png::DecodingError>),\n    /// The encoding of some PNG image failed.\n    #[error(\"the encoding of some PNG image failed: {0}\")]\n    PngEncodingFailed(Arc<png::EncodingError>),\n    /// The parsing of an [`Ice`](crate::Ice) test failed.\n    #[error(\"the ice test ({file}) is invalid: {error}\")]\n    IceParsingFailed {\n        /// The path of the test.\n        file: PathBuf,\n        /// The parse error.\n        error: ice::ParseError,\n    },\n    /// The execution of an [`Ice`](crate::Ice) test failed.\n    #[error(\"the ice test ({file}) failed\")]\n    IceTestingFailed {\n        /// The path of the test.\n        file: PathBuf,\n        /// The [`Instruction`] that failed.\n        instruction: Instruction,\n    },\n    /// The [`Preset`](crate::program::Preset) of a program could not be found.\n    #[error(\"the preset \\\"{name}\\\" does not exist (available presets: {available:?})\")]\n    PresetNotFound {\n        /// The name of the [`Preset`](crate::program::Preset).\n        name: String,\n        /// The available set of presets.\n        available: Vec<String>,\n    },\n}\n\nimpl From<io::Error> for Error {\n    fn from(error: io::Error) -> Self {\n        Self::IOFailed(Arc::new(error))\n    }\n}\n\nimpl From<png::DecodingError> for Error {\n    fn from(error: png::DecodingError) -> Self {\n        Self::PngDecodingFailed(Arc::new(error))\n    }\n}\n\nimpl From<png::EncodingError> for Error {\n    fn from(error: png::EncodingError) -> Self {\n        Self::PngEncodingFailed(Arc::new(error))\n    }\n}\n"
  },
  {
    "path": "test/src/ice.rs",
    "content": "//! A shareable, simple format of end-to-end tests.\nuse crate::Instruction;\nuse crate::core::Size;\nuse crate::emulator;\nuse crate::instruction;\n\n/// An end-to-end test for iced applications.\n///\n/// Ice tests encode a certain configuration together with a sequence of instructions.\n/// An ice test passes if all the instructions can be executed successfully.\n///\n/// Normally, ice tests are run by an [`Emulator`](crate::Emulator) in continuous\n/// integration pipelines.\n///\n/// Ice tests can be easily run by saving them as `.ice` files in a folder and simply\n/// calling [`run`](crate::run). These test files can be recorded by enabling the `tester`\n/// feature flag in the root crate.\n#[derive(Debug, Clone, PartialEq)]\npub struct Ice {\n    /// The viewport [`Size`] that must be used for the test.\n    pub viewport: Size,\n    /// The [`emulator::Mode`] that must be used for the test.\n    pub mode: emulator::Mode,\n    /// The name of the [`Preset`](crate::program::Preset) that must be used for the test.\n    pub preset: Option<String>,\n    /// The sequence of instructions of the test.\n    pub instructions: Vec<Instruction>,\n}\n\nimpl Ice {\n    /// Parses an [`Ice`] test from its textual representation.\n    ///\n    /// Here is an example of the [`Ice`] test syntax:\n    ///\n    /// ```text\n    /// viewport: 500x800\n    /// mode: Immediate\n    /// preset: Empty\n    /// -----\n    /// click \"What needs to be done?\"\n    /// type \"Create the universe\"\n    /// type enter\n    /// type \"Make an apple pie\"\n    /// type enter\n    /// expect \"2 tasks left\"\n    /// click \"Create the universe\"\n    /// expect \"1 task left\"\n    /// click \"Make an apple pie\"\n    /// expect \"0 tasks left\"\n    /// ```\n    ///\n    /// This syntax is _very_ experimental and extremely likely to change often.\n    /// For this reason, it is reserved for advanced users that want to early test it.\n    ///\n    /// Currently, in order to use it, you will need to earn the right and prove you understand\n    /// its experimental nature by reading the code!\n    pub fn parse(content: &str) -> Result<Self, ParseError> {\n        let Some((metadata, rest)) = content.split_once(\"-\") else {\n            return Err(ParseError::NoMetadata);\n        };\n\n        let mut viewport = None;\n        let mut mode = None;\n        let mut preset = None;\n\n        for (i, line) in metadata.lines().enumerate() {\n            if line.trim().is_empty() {\n                continue;\n            }\n\n            let Some((field, value)) = line.split_once(':') else {\n                return Err(ParseError::InvalidMetadata {\n                    line: i,\n                    content: line.to_owned(),\n                });\n            };\n\n            match field.trim() {\n                \"viewport\" => {\n                    viewport = Some(\n                        if let Some((width, height)) = value.trim().split_once('x')\n                            && let Ok(width) = width.parse()\n                            && let Ok(height) = height.parse()\n                        {\n                            Size::new(width, height)\n                        } else {\n                            return Err(ParseError::InvalidViewport {\n                                line: i,\n                                value: value.to_owned(),\n                            });\n                        },\n                    );\n                }\n                \"mode\" => {\n                    mode = Some(match value.trim().to_lowercase().as_str() {\n                        \"zen\" => emulator::Mode::Zen,\n                        \"patient\" => emulator::Mode::Patient,\n                        \"immediate\" => emulator::Mode::Immediate,\n                        _ => {\n                            return Err(ParseError::InvalidMode {\n                                line: i,\n                                value: value.to_owned(),\n                            });\n                        }\n                    });\n                }\n                \"preset\" => {\n                    preset = Some(value.trim().to_owned());\n                }\n                field => {\n                    return Err(ParseError::UnknownField {\n                        line: i,\n                        field: field.to_owned(),\n                    });\n                }\n            }\n        }\n\n        let Some(viewport) = viewport else {\n            return Err(ParseError::MissingViewport);\n        };\n\n        let Some(mode) = mode else {\n            return Err(ParseError::MissingMode);\n        };\n\n        let instructions = rest\n            .lines()\n            .skip(1)\n            .enumerate()\n            .map(|(i, line)| {\n                Instruction::parse(line).map_err(|error| ParseError::InvalidInstruction {\n                    line: metadata.lines().count() + 1 + i,\n                    instruction: line.to_owned(),\n                    error,\n                })\n            })\n            .collect::<Result<Vec<_>, _>>()?;\n\n        Ok(Self {\n            viewport,\n            mode,\n            preset,\n            instructions,\n        })\n    }\n}\n\nimpl std::fmt::Display for Ice {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        writeln!(\n            f,\n            \"viewport: {width}x{height}\",\n            width = self.viewport.width as u32,   // TODO\n            height = self.viewport.height as u32, // TODO\n        )?;\n\n        writeln!(f, \"mode: {}\", self.mode)?;\n\n        if let Some(preset) = &self.preset {\n            writeln!(f, \"preset: {preset}\")?;\n        }\n\n        f.write_str(\"-----\\n\")?;\n\n        for instruction in &self.instructions {\n            instruction.fmt(f)?;\n            f.write_str(\"\\n\")?;\n        }\n\n        Ok(())\n    }\n}\n\n/// An error produced during [`Ice::parse`].\n#[derive(Debug, Clone, thiserror::Error)]\npub enum ParseError {\n    /// No metadata is present.\n    #[error(\"the ice test has no metadata\")]\n    NoMetadata,\n\n    /// The metadata is invalid.\n    #[error(\"invalid metadata in line {line}: \\\"{content}\\\"\")]\n    InvalidMetadata {\n        /// The number of the invalid line.\n        line: usize,\n        /// The content of the invalid line.\n        content: String,\n    },\n\n    /// The viewport is invalid.\n    #[error(\"invalid viewport in line {line}: \\\"{value}\\\"\")]\n    InvalidViewport {\n        /// The number of the invalid line.\n        line: usize,\n\n        /// The invalid value.\n        value: String,\n    },\n\n    /// The [`emulator::Mode`] is invalid.\n    #[error(\"invalid mode in line {line}: \\\"{value}\\\"\")]\n    InvalidMode {\n        /// The number of the invalid line.\n        line: usize,\n        /// The invalid value.\n        value: String,\n    },\n\n    /// A metadata field is unknown.\n    #[error(\"unknown metadata field in line {line}: \\\"{field}\\\"\")]\n    UnknownField {\n        /// The number of the invalid line.\n        line: usize,\n        /// The name of the unknown field.\n        field: String,\n    },\n\n    /// Viewport metadata is missing.\n    #[error(\"metadata is missing the viewport field\")]\n    MissingViewport,\n\n    /// [`emulator::Mode`] metadata is missing.\n    #[error(\"metadata is missing the mode field\")]\n    MissingMode,\n\n    /// An [`Instruction`] failed to parse.\n    #[error(\"invalid instruction in line {line}: {error}\")]\n    InvalidInstruction {\n        /// The number of the invalid line.\n        line: usize,\n        /// The invalid instruction.\n        instruction: String,\n        /// The parse error.\n        error: instruction::ParseError,\n    },\n}\n"
  },
  {
    "path": "test/src/instruction.rs",
    "content": "//! A step in an end-to-end test.\nuse crate::core::keyboard;\nuse crate::core::mouse;\nuse crate::core::{Event, Point};\nuse crate::simulator;\n\nuse std::fmt;\n\n/// A step in an end-to-end test.\n///\n/// An [`Instruction`] can be run by an [`Emulator`](crate::Emulator).\n#[derive(Debug, Clone, PartialEq)]\npub enum Instruction {\n    /// A user [`Interaction`].\n    Interact(Interaction),\n    /// A testing [`Expectation`].\n    Expect(Expectation),\n}\n\nimpl Instruction {\n    /// Parses an [`Instruction`] from its textual representation.\n    pub fn parse(line: &str) -> Result<Self, ParseError> {\n        parser::run(line)\n    }\n}\n\nimpl fmt::Display for Instruction {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Instruction::Interact(interaction) => interaction.fmt(f),\n            Instruction::Expect(expectation) => expectation.fmt(f),\n        }\n    }\n}\n\n/// A user interaction.\n#[derive(Debug, Clone, PartialEq)]\npub enum Interaction {\n    /// A mouse interaction.\n    Mouse(Mouse),\n    /// A keyboard interaction.\n    Keyboard(Keyboard),\n}\n\nimpl Interaction {\n    /// Creates an [`Interaction`] from a runtime [`Event`].\n    ///\n    /// This can be useful for recording tests during real usage.\n    pub fn from_event(event: &Event) -> Option<Self> {\n        Some(match event {\n            Event::Mouse(mouse) => Self::Mouse(match mouse {\n                mouse::Event::CursorMoved { position } => Mouse::Move(Target::Point(*position)),\n                mouse::Event::ButtonPressed(button) => Mouse::Press {\n                    button: *button,\n                    target: None,\n                },\n                mouse::Event::ButtonReleased(button) => Mouse::Release {\n                    button: *button,\n                    target: None,\n                },\n                _ => None?,\n            }),\n            Event::Keyboard(keyboard) => Self::Keyboard(match keyboard {\n                keyboard::Event::KeyPressed { key, text, .. } => match key {\n                    keyboard::Key::Named(keyboard::key::Named::Enter) => {\n                        Keyboard::Press(Key::Enter)\n                    }\n                    keyboard::Key::Named(keyboard::key::Named::Escape) => {\n                        Keyboard::Press(Key::Escape)\n                    }\n                    keyboard::Key::Named(keyboard::key::Named::Tab) => Keyboard::Press(Key::Tab),\n                    keyboard::Key::Named(keyboard::key::Named::Backspace) => {\n                        Keyboard::Press(Key::Backspace)\n                    }\n                    _ => Keyboard::Typewrite(text.as_ref()?.to_string()),\n                },\n                keyboard::Event::KeyReleased { key, .. } => match key {\n                    keyboard::Key::Named(keyboard::key::Named::Enter) => {\n                        Keyboard::Release(Key::Enter)\n                    }\n                    keyboard::Key::Named(keyboard::key::Named::Escape) => {\n                        Keyboard::Release(Key::Escape)\n                    }\n                    keyboard::Key::Named(keyboard::key::Named::Tab) => Keyboard::Release(Key::Tab),\n                    keyboard::Key::Named(keyboard::key::Named::Backspace) => {\n                        Keyboard::Release(Key::Backspace)\n                    }\n                    _ => None?,\n                },\n                keyboard::Event::ModifiersChanged(_) => None?,\n            }),\n            _ => None?,\n        })\n    }\n\n    /// Merges two interactions together, if possible.\n    ///\n    /// This method can turn certain sequences of interactions into a single one.\n    /// For instance, a mouse movement, left button press, and left button release\n    /// can all be merged into a single click interaction.\n    ///\n    /// Merging is lossy and, therefore, it is not always desirable if you are recording\n    /// a test and want full reproducibility.\n    ///\n    /// If the interactions cannot be merged, the `next` interaction will be\n    /// returned as the second element of the tuple.\n    pub fn merge(self, next: Self) -> (Self, Option<Self>) {\n        match (self, next) {\n            (Self::Mouse(current), Self::Mouse(next)) => match (current, next) {\n                (Mouse::Move(_), Mouse::Move(to)) => (Self::Mouse(Mouse::Move(to)), None),\n                (\n                    Mouse::Move(to),\n                    Mouse::Press {\n                        button,\n                        target: None,\n                    },\n                ) => (\n                    Self::Mouse(Mouse::Press {\n                        button,\n                        target: Some(to),\n                    }),\n                    None,\n                ),\n                (\n                    Mouse::Move(to),\n                    Mouse::Release {\n                        button,\n                        target: None,\n                    },\n                ) => (\n                    Self::Mouse(Mouse::Release {\n                        button,\n                        target: Some(to),\n                    }),\n                    None,\n                ),\n                (\n                    Mouse::Press {\n                        button: press,\n                        target: press_at,\n                    },\n                    Mouse::Release {\n                        button: release,\n                        target: release_at,\n                    },\n                ) if press == release\n                    && release_at\n                        .as_ref()\n                        .is_none_or(|release_at| Some(release_at) == press_at.as_ref()) =>\n                {\n                    (\n                        Self::Mouse(Mouse::Click {\n                            button: press,\n                            target: press_at,\n                        }),\n                        None,\n                    )\n                }\n                (\n                    Mouse::Press {\n                        button,\n                        target: Some(press_at),\n                    },\n                    Mouse::Move(move_at),\n                ) if press_at == move_at => (\n                    Self::Mouse(Mouse::Press {\n                        button,\n                        target: Some(press_at),\n                    }),\n                    None,\n                ),\n                (\n                    Mouse::Click {\n                        button,\n                        target: Some(click_at),\n                    },\n                    Mouse::Move(move_at),\n                ) if click_at == move_at => (\n                    Self::Mouse(Mouse::Click {\n                        button,\n                        target: Some(click_at),\n                    }),\n                    None,\n                ),\n                (current, next) => (Self::Mouse(current), Some(Self::Mouse(next))),\n            },\n            (Self::Keyboard(current), Self::Keyboard(next)) => match (current, next) {\n                (Keyboard::Typewrite(current), Keyboard::Typewrite(next)) => (\n                    Self::Keyboard(Keyboard::Typewrite(format!(\"{current}{next}\"))),\n                    None,\n                ),\n                (Keyboard::Press(current), Keyboard::Release(next)) if current == next => {\n                    (Self::Keyboard(Keyboard::Type(current)), None)\n                }\n                (current, next) => (Self::Keyboard(current), Some(Self::Keyboard(next))),\n            },\n            (current, next) => (current, Some(next)),\n        }\n    }\n\n    /// Returns a list of runtime events representing the [`Interaction`].\n    ///\n    /// The `find_target` closure must convert a [`Target`] into its screen\n    /// coordinates.\n    pub fn events(&self, find_target: impl FnOnce(&Target) -> Option<Point>) -> Option<Vec<Event>> {\n        let mouse_move_ = |to| Event::Mouse(mouse::Event::CursorMoved { position: to });\n\n        let mouse_press = |button| Event::Mouse(mouse::Event::ButtonPressed(button));\n\n        let mouse_release = |button| Event::Mouse(mouse::Event::ButtonReleased(button));\n\n        let key_press = |key| simulator::press_key(key, None);\n\n        let key_release = |key| simulator::release_key(key);\n\n        Some(match self {\n            Interaction::Mouse(mouse) => match mouse {\n                Mouse::Move(to) => vec![mouse_move_(find_target(to)?)],\n                Mouse::Press {\n                    button,\n                    target: Some(at),\n                } => vec![mouse_move_(find_target(at)?), mouse_press(*button)],\n                Mouse::Press {\n                    button,\n                    target: None,\n                } => {\n                    vec![mouse_press(*button)]\n                }\n                Mouse::Release {\n                    button,\n                    target: Some(at),\n                } => {\n                    vec![mouse_move_(find_target(at)?), mouse_release(*button)]\n                }\n                Mouse::Release {\n                    button,\n                    target: None,\n                } => {\n                    vec![mouse_release(*button)]\n                }\n                Mouse::Click {\n                    button,\n                    target: Some(at),\n                } => {\n                    vec![\n                        mouse_move_(find_target(at)?),\n                        mouse_press(*button),\n                        mouse_release(*button),\n                    ]\n                }\n                Mouse::Click {\n                    button,\n                    target: None,\n                } => {\n                    vec![mouse_press(*button), mouse_release(*button)]\n                }\n            },\n            Interaction::Keyboard(keyboard) => match keyboard {\n                Keyboard::Press(key) => vec![key_press(*key)],\n                Keyboard::Release(key) => vec![key_release(*key)],\n                Keyboard::Type(key) => vec![key_press(*key), key_release(*key)],\n                Keyboard::Typewrite(text) => simulator::typewrite(text).collect(),\n            },\n        })\n    }\n}\n\nimpl fmt::Display for Interaction {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Interaction::Mouse(mouse) => mouse.fmt(f),\n            Interaction::Keyboard(keyboard) => keyboard.fmt(f),\n        }\n    }\n}\n\n/// A mouse interaction.\n#[derive(Debug, Clone, PartialEq)]\npub enum Mouse {\n    /// The mouse was moved.\n    Move(Target),\n    /// A button was pressed.\n    Press {\n        /// The button.\n        button: mouse::Button,\n        /// The location of the press.\n        target: Option<Target>,\n    },\n    /// A button was released.\n    Release {\n        /// The button.\n        button: mouse::Button,\n        /// The location of the release.\n        target: Option<Target>,\n    },\n    /// A button was clicked.\n    Click {\n        /// The button.\n        button: mouse::Button,\n        /// The location of the click.\n        target: Option<Target>,\n    },\n}\n\nimpl fmt::Display for Mouse {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Mouse::Move(target) => {\n                write!(f, \"move {}\", target)\n            }\n            Mouse::Press { button, target } => {\n                write!(f, \"press {}\", format::button_at(*button, target.as_ref()))\n            }\n            Mouse::Release { button, target } => {\n                write!(f, \"release {}\", format::button_at(*button, target.as_ref()))\n            }\n            Mouse::Click { button, target } => {\n                write!(f, \"click {}\", format::button_at(*button, target.as_ref()))\n            }\n        }\n    }\n}\n\n/// The target of an interaction.\n#[derive(Debug, Clone, PartialEq)]\npub enum Target {\n    /// A widget with the given identifier.\n    Id(String),\n    /// A UI element containing the given text.\n    Text(String),\n    /// A specific point of the viewport.\n    Point(Point),\n}\n\nimpl fmt::Display for Target {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Id(id) => f.write_str(&format::id(id)),\n            Self::Point(point) => f.write_str(&format::point(*point)),\n            Self::Text(text) => f.write_str(&format::string(text)),\n        }\n    }\n}\n\n/// A keyboard interaction.\n#[derive(Debug, Clone, PartialEq)]\npub enum Keyboard {\n    /// A key was pressed.\n    Press(Key),\n    /// A key was released.\n    Release(Key),\n    /// A key was \"typed\" (press and released).\n    Type(Key),\n    /// A bunch of text was typed.\n    Typewrite(String),\n}\n\nimpl fmt::Display for Keyboard {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Keyboard::Press(key) => {\n                write!(f, \"press {}\", format::key(*key))\n            }\n            Keyboard::Release(key) => {\n                write!(f, \"release {}\", format::key(*key))\n            }\n            Keyboard::Type(key) => {\n                write!(f, \"type {}\", format::key(*key))\n            }\n            Keyboard::Typewrite(text) => {\n                write!(f, \"type \\\"{text}\\\"\")\n            }\n        }\n    }\n}\n\n/// A keyboard key.\n///\n/// Only a small subset of keys is supported currently!\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[allow(missing_docs)]\npub enum Key {\n    Enter,\n    Escape,\n    Tab,\n    Backspace,\n}\n\nimpl From<Key> for keyboard::Key {\n    fn from(key: Key) -> Self {\n        match key {\n            Key::Enter => Self::Named(keyboard::key::Named::Enter),\n            Key::Escape => Self::Named(keyboard::key::Named::Escape),\n            Key::Tab => Self::Named(keyboard::key::Named::Tab),\n            Key::Backspace => Self::Named(keyboard::key::Named::Backspace),\n        }\n    }\n}\n\nmod format {\n    use super::*;\n\n    pub fn button_at(button: mouse::Button, at: Option<&Target>) -> String {\n        let button = self::button(button);\n\n        if let Some(at) = at {\n            if button.is_empty() {\n                at.to_string()\n            } else {\n                format!(\"{} {}\", button, at)\n            }\n        } else {\n            button.to_owned()\n        }\n    }\n\n    pub fn button(button: mouse::Button) -> &'static str {\n        match button {\n            mouse::Button::Left => \"\",\n            mouse::Button::Right => \"right\",\n            mouse::Button::Middle => \"middle\",\n            mouse::Button::Back => \"back\",\n            mouse::Button::Forward => \"forward\",\n            mouse::Button::Other(_) => \"other\",\n        }\n    }\n\n    pub fn point(point: Point) -> String {\n        format!(\"({:.2}, {:.2})\", point.x, point.y)\n    }\n\n    pub fn key(key: Key) -> &'static str {\n        match key {\n            Key::Enter => \"enter\",\n            Key::Escape => \"escape\",\n            Key::Tab => \"tab\",\n            Key::Backspace => \"backspace\",\n        }\n    }\n\n    pub fn string(text: &str) -> String {\n        format!(\"\\\"{}\\\"\", text.escape_default())\n    }\n\n    pub fn id(id: &str) -> String {\n        format!(\"#{id}\")\n    }\n}\n\n/// A testing assertion.\n///\n/// Expectations are instructions that verify the current state of\n/// the user interface of an application.\n#[derive(Debug, Clone, PartialEq)]\npub enum Expectation {\n    /// Expect some element to contain some text.\n    Text(String),\n}\n\nimpl fmt::Display for Expectation {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Expectation::Text(text) => {\n                write!(f, \"expect {}\", format::string(text))\n            }\n        }\n    }\n}\n\npub use parser::Error as ParseError;\n\nmod parser {\n    use super::*;\n\n    use nom::branch::alt;\n    use nom::bytes::complete::tag;\n    use nom::bytes::{is_not, take_while_m_n};\n    use nom::character::complete::{alphanumeric1, char, multispace0, multispace1};\n    use nom::combinator::{map, map_opt, map_res, opt, recognize, success, value, verify};\n    use nom::error::ParseError;\n    use nom::multi::{fold, many1_count};\n    use nom::number::float;\n    use nom::sequence::{delimited, preceded, separated_pair};\n    use nom::{Finish, IResult, Parser};\n\n    /// A parsing error.\n    #[derive(Debug, Clone, thiserror::Error)]\n    #[error(\"parse error: {0}\")]\n    pub struct Error(nom::error::Error<String>);\n\n    pub fn run(input: &str) -> Result<Instruction, Error> {\n        match instruction.parse_complete(input).finish() {\n            Ok((_rest, instruction)) => Ok(instruction),\n            Err(error) => Err(Error(error.cloned())),\n        }\n    }\n\n    fn instruction(input: &str) -> IResult<&str, Instruction> {\n        alt((\n            map(interaction, Instruction::Interact),\n            map(expectation, Instruction::Expect),\n        ))\n        .parse(input)\n    }\n\n    fn interaction(input: &str) -> IResult<&str, Interaction> {\n        alt((\n            map(mouse, Interaction::Mouse),\n            map(keyboard, Interaction::Keyboard),\n        ))\n        .parse(input)\n    }\n\n    fn mouse(input: &str) -> IResult<&str, Mouse> {\n        let mouse_move = preceded(tag(\"move \"), target).map(Mouse::Move);\n\n        alt((mouse_move, mouse_click, mouse_press, mouse_release)).parse(input)\n    }\n\n    fn mouse_click(input: &str) -> IResult<&str, Mouse> {\n        let (input, _) = tag(\"click \")(input)?;\n        let (input, (button, target)) = mouse_button_at(input)?;\n\n        Ok((input, Mouse::Click { button, target }))\n    }\n\n    fn mouse_press(input: &str) -> IResult<&str, Mouse> {\n        let (input, _) = tag(\"press \")(input)?;\n        let (input, (button, target)) = mouse_button_at(input)?;\n\n        Ok((input, Mouse::Press { button, target }))\n    }\n\n    fn mouse_release(input: &str) -> IResult<&str, Mouse> {\n        let (input, _) = tag(\"release \")(input)?;\n        let (input, (button, target)) = mouse_button_at(input)?;\n\n        Ok((input, Mouse::Release { button, target }))\n    }\n\n    fn mouse_button_at(input: &str) -> IResult<&str, (mouse::Button, Option<Target>)> {\n        let (input, button) = mouse_button(input)?;\n        let (input, at) = opt(target).parse(input)?;\n\n        Ok((input, (button, at)))\n    }\n\n    fn target(input: &str) -> IResult<&str, Target> {\n        alt((\n            id.map(String::from).map(Target::Id),\n            string.map(Target::Text),\n            point.map(Target::Point),\n        ))\n        .parse(input)\n    }\n\n    fn mouse_button(input: &str) -> IResult<&str, mouse::Button> {\n        alt((\n            tag(\"right\").map(|_| mouse::Button::Right),\n            success(mouse::Button::Left),\n        ))\n        .parse(input)\n    }\n\n    fn keyboard(input: &str) -> IResult<&str, Keyboard> {\n        alt((\n            map(preceded(tag(\"type \"), string), Keyboard::Typewrite),\n            map(preceded(tag(\"type \"), key), Keyboard::Type),\n        ))\n        .parse(input)\n    }\n\n    fn expectation(input: &str) -> IResult<&str, Expectation> {\n        map(preceded(tag(\"expect \"), string), |text| {\n            Expectation::Text(text)\n        })\n        .parse(input)\n    }\n\n    fn key(input: &str) -> IResult<&str, Key> {\n        alt((\n            map(tag(\"enter\"), |_| Key::Enter),\n            map(tag(\"escape\"), |_| Key::Escape),\n            map(tag(\"tab\"), |_| Key::Tab),\n            map(tag(\"backspace\"), |_| Key::Backspace),\n        ))\n        .parse(input)\n    }\n\n    fn id(input: &str) -> IResult<&str, &str> {\n        preceded(\n            char('#'),\n            recognize(many1_count(alt((alphanumeric1, tag(\"_\"), tag(\"-\"))))),\n        )\n        .parse(input)\n    }\n\n    fn point(input: &str) -> IResult<&str, Point> {\n        let comma = whitespace(char(','));\n\n        map(\n            delimited(\n                char('('),\n                separated_pair(float(), comma, float()),\n                char(')'),\n            ),\n            |(x, y)| Point { x, y },\n        )\n        .parse(input)\n    }\n\n    pub fn whitespace<'a, O, E: ParseError<&'a str>, F>(\n        inner: F,\n    ) -> impl Parser<&'a str, Output = O, Error = E>\n    where\n        F: Parser<&'a str, Output = O, Error = E>,\n    {\n        delimited(multispace0, inner, multispace0)\n    }\n\n    // Taken from https://github.com/rust-bakery/nom/blob/51c3c4e44fa78a8a09b413419372b97b2cc2a787/examples/string.rs\n    //\n    // Copyright (c) 2014-2019 Geoffroy Couprie\n    //\n    // Permission is hereby granted, free of charge, to any person obtaining\n    // a copy of this software and associated documentation files (the\n    // \"Software\"), to deal in the Software without restriction, including\n    // without limitation the rights to use, copy, modify, merge, publish,\n    // distribute, sublicense, and/or sell copies of the Software, and to\n    // permit persons to whom the Software is furnished to do so, subject to\n    // the following conditions:\n    //\n    // The above copyright notice and this permission notice shall be\n    // included in all copies or substantial portions of the Software.\n    //\n    // THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n    // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n    // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n    // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n    // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n    // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n    fn string(input: &str) -> IResult<&str, String> {\n        #[derive(Debug, Clone, Copy)]\n        enum Fragment<'a> {\n            Literal(&'a str),\n            EscapedChar(char),\n            EscapedWS,\n        }\n\n        fn fragment(input: &str) -> IResult<&str, Fragment<'_>> {\n            alt((\n                map(string_literal, Fragment::Literal),\n                map(escaped_char, Fragment::EscapedChar),\n                value(Fragment::EscapedWS, escaped_whitespace),\n            ))\n            .parse(input)\n        }\n\n        fn string_literal<'a, E: ParseError<&'a str>>(\n            input: &'a str,\n        ) -> IResult<&'a str, &'a str, E> {\n            let not_quote_slash = is_not(\"\\\"\\\\\");\n\n            verify(not_quote_slash, |s: &str| !s.is_empty()).parse(input)\n        }\n\n        fn unicode(input: &str) -> IResult<&str, char> {\n            let parse_hex = take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit());\n\n            let parse_delimited_hex =\n                preceded(char('u'), delimited(char('{'), parse_hex, char('}')));\n\n            let parse_u32 = map_res(parse_delimited_hex, move |hex| u32::from_str_radix(hex, 16));\n\n            map_opt(parse_u32, std::char::from_u32).parse(input)\n        }\n\n        fn escaped_char(input: &str) -> IResult<&str, char> {\n            preceded(\n                char('\\\\'),\n                alt((\n                    unicode,\n                    value('\\n', char('n')),\n                    value('\\r', char('r')),\n                    value('\\t', char('t')),\n                    value('\\u{08}', char('b')),\n                    value('\\u{0C}', char('f')),\n                    value('\\\\', char('\\\\')),\n                    value('/', char('/')),\n                    value('\"', char('\"')),\n                )),\n            )\n            .parse(input)\n        }\n\n        fn escaped_whitespace(input: &str) -> IResult<&str, &str> {\n            preceded(char('\\\\'), multispace1).parse(input)\n        }\n\n        let build_string = fold(0.., fragment, String::new, |mut string, fragment| {\n            match fragment {\n                Fragment::Literal(s) => string.push_str(s),\n                Fragment::EscapedChar(c) => string.push(c),\n                Fragment::EscapedWS => {}\n            }\n            string\n        });\n\n        delimited(char('\"'), build_string, char('\"')).parse(input)\n    }\n}\n"
  },
  {
    "path": "test/src/lib.rs",
    "content": "//! Test your `iced` applications in headless mode.\n//!\n//! # Basic Usage\n//! Let's assume we want to test [the classical counter interface].\n//!\n//! First, we will want to create a [`Simulator`] of our interface:\n//!\n//! ```rust,no_run\n//! # struct Counter { value: i64 }\n//! # impl Counter {\n//! #    pub fn view(&self) -> iced_runtime::core::Element<(), iced_runtime::core::Theme, iced_renderer::Renderer> { unimplemented!() }\n//! # }\n//! use iced_test::simulator;\n//!\n//! let mut counter = Counter { value: 0 };\n//! let mut ui = simulator(counter.view());\n//! ```\n//!\n//! Now we can simulate a user interacting with our interface. Let's use [`Simulator::click`] to click\n//! the counter buttons:\n//!\n//! ```rust,no_run\n//! # struct Counter { value: i64 }\n//! # impl Counter {\n//! #    pub fn view(&self) -> iced_runtime::core::Element<(), iced_runtime::core::Theme, iced_renderer::Renderer> { unimplemented!() }\n//! # }\n//! # use iced_test::simulator;\n//! #\n//! # let mut counter = Counter { value: 0 };\n//! # let mut ui = simulator(counter.view());\n//! #\n//! let _ = ui.click(\"+\");\n//! let _ = ui.click(\"+\");\n//! let _ = ui.click(\"-\");\n//! ```\n//!\n//! [`Simulator::click`] takes a type implementing the [`Selector`] trait. A [`Selector`] describes a way to query the widgets of an interface.\n//! In this case, we leverage the [`Selector`] implementation of `&str`, which selects a widget by the text it contains.\n//!\n//! We can now process any messages produced by these interactions and then assert that the final value of our counter is\n//! indeed `1`!\n//!\n//! ```rust,no_run\n//! # struct Counter { value: i64 }\n//! # impl Counter {\n//! #    pub fn update(&mut self, message: ()) {}\n//! #    pub fn view(&self) -> iced_runtime::core::Element<(), iced_runtime::core::Theme, iced_renderer::Renderer> { unimplemented!() }\n//! # }\n//! # use iced_test::simulator;\n//! #\n//! # let mut counter = Counter { value: 0 };\n//! # let mut ui = simulator(counter.view());\n//! #\n//! # let _ = ui.click(\"+\");\n//! # let _ = ui.click(\"+\");\n//! # let _ = ui.click(\"-\");\n//! #\n//! for message in ui.into_messages() {\n//!     counter.update(message);\n//! }\n//!\n//! assert_eq!(counter.value, 1);\n//! ```\n//!\n//! We can even rebuild the interface to make sure the counter _displays_ the proper value with [`Simulator::find`]:\n//!\n//! ```rust,no_run\n//! # struct Counter { value: i64 }\n//! # impl Counter {\n//! #    pub fn view(&self) -> iced_runtime::core::Element<(), iced_runtime::core::Theme, iced_renderer::Renderer> { unimplemented!() }\n//! # }\n//! # use iced_test::simulator;\n//! #\n//! # let mut counter = Counter { value: 0 };\n//! let mut ui = simulator(counter.view());\n//!\n//! assert!(ui.find(\"1\").is_ok(), \"Counter should display 1!\");\n//! ```\n//!\n//! And that's it! That's the gist of testing `iced` applications!\n//!\n//! [`Simulator`] contains additional operations you can use to simulate more interactions—like [`tap_key`](Simulator::tap_key) or\n//! [`typewrite`](Simulator::typewrite)—and even perform [_snapshot testing_](Simulator::snapshot)!\n//!\n//! [the classical counter interface]: https://book.iced.rs/architecture.html#dissecting-an-interface\npub use iced_futures as futures;\npub use iced_program as program;\npub use iced_renderer as renderer;\npub use iced_runtime as runtime;\npub use iced_runtime::core;\n\npub use iced_selector as selector;\n\npub mod emulator;\npub mod ice;\npub mod instruction;\npub mod simulator;\n\nmod error;\n\npub use emulator::Emulator;\npub use error::Error;\npub use ice::Ice;\npub use instruction::Instruction;\npub use selector::Selector;\npub use simulator::{Simulator, simulator};\n\nuse crate::core::Size;\nuse crate::core::theme;\nuse crate::core::time::{Duration, Instant};\nuse crate::core::window;\n\nuse std::path::Path;\n\n/// Runs an [`Ice`] test suite for the given [`Program`](program::Program).\n///\n/// Any `.ice` tests will be parsed from the given directory and executed in\n/// an [`Emulator`] of the given [`Program`](program::Program).\n///\n/// Remember that an [`Emulator`] executes the real thing! Side effects _will_\n/// take place. It is up to you to ensure your tests have reproducible environments\n/// by leveraging [`Preset`][program::Preset].\npub fn run<P: program::Program + 'static>(\n    program: P,\n    tests_dir: impl AsRef<Path>,\n) -> Result<(), Error> {\n    use crate::futures::futures::StreamExt;\n    use crate::futures::futures::channel::mpsc;\n    use crate::futures::futures::executor;\n\n    use std::ffi::OsStr;\n    use std::fs;\n\n    let errors_dir = tests_dir.as_ref().join(\"errors\");\n\n    if errors_dir.exists() {\n        fs::remove_dir_all(&errors_dir)?;\n    }\n\n    let files = fs::read_dir(tests_dir)?;\n    let mut tests = Vec::new();\n\n    for file in files {\n        let file = file?;\n\n        if file.path().extension().and_then(OsStr::to_str) != Some(\"ice\") {\n            continue;\n        }\n\n        let content = fs::read_to_string(file.path())?;\n\n        match Ice::parse(&content) {\n            Ok(ice) => {\n                let preset = if let Some(preset) = &ice.preset {\n                    let Some(preset) = program\n                        .presets()\n                        .iter()\n                        .find(|candidate| candidate.name() == preset)\n                    else {\n                        return Err(Error::PresetNotFound {\n                            name: preset.to_owned(),\n                            available: program\n                                .presets()\n                                .iter()\n                                .map(program::Preset::name)\n                                .map(str::to_owned)\n                                .collect(),\n                        });\n                    };\n\n                    Some(preset)\n                } else {\n                    None\n                };\n\n                tests.push((file, ice, preset));\n            }\n            Err(error) => {\n                return Err(Error::IceParsingFailed {\n                    file: file.path().to_path_buf(),\n                    error,\n                });\n            }\n        }\n    }\n\n    // TODO: Concurrent runtimes\n    for (file, ice, preset) in tests {\n        let (sender, mut receiver) = mpsc::channel(1);\n\n        let mut emulator = Emulator::with_preset(sender, &program, ice.mode, ice.viewport, preset);\n\n        let mut instructions = ice.instructions.iter();\n        let mut current = 0;\n\n        loop {\n            let event = executor::block_on(receiver.next())\n                .expect(\"emulator runtime should never stop on its own\");\n\n            match event {\n                emulator::Event::Action(action) => {\n                    emulator.perform(&program, action);\n                }\n                emulator::Event::Failed(instruction) => {\n                    fs::create_dir_all(&errors_dir)?;\n\n                    let theme = emulator\n                        .theme(&program)\n                        .unwrap_or_else(|| <P::Theme as theme::Base>::default(theme::Mode::None));\n\n                    let screenshot = emulator.screenshot(&program, &theme, 2.0);\n\n                    let image = fs::File::create(\n                        errors_dir.join(\n                            file.path()\n                                .with_extension(\"png\")\n                                .file_name()\n                                .expect(\"Test must have a filename\"),\n                        ),\n                    )?;\n\n                    let mut encoder =\n                        png::Encoder::new(image, screenshot.size.width, screenshot.size.height);\n                    encoder.set_color(png::ColorType::Rgba);\n\n                    let mut writer = encoder.write_header()?;\n                    writer.write_image_data(&screenshot.rgba)?;\n                    writer.finish()?;\n\n                    let reproduction = Ice {\n                        viewport: ice.viewport,\n                        mode: ice.mode,\n                        preset: ice.preset,\n                        instructions: ice.instructions[..current].to_vec(),\n                    };\n\n                    fs::write(errors_dir.join(file.file_name()), reproduction.to_string())?;\n\n                    return Err(Error::IceTestingFailed {\n                        file: file.path().to_path_buf(),\n                        instruction,\n                    });\n                }\n                emulator::Event::Ready => {\n                    let Some(instruction) = instructions.next() else {\n                        break;\n                    };\n\n                    emulator.run(&program, instruction);\n                    current += 1;\n                }\n            }\n        }\n    }\n\n    Ok(())\n}\n\n/// Takes a screenshot of the given [`Program`](program::Program) with the given theme, viewport,\n/// and scale factor after running it for the given [`Duration`].\npub fn screenshot<P: program::Program + 'static>(\n    program: &P,\n    theme: &P::Theme,\n    viewport: impl Into<Size>,\n    scale_factor: f32,\n    duration: Duration,\n) -> window::Screenshot {\n    use crate::runtime::futures::futures::channel::mpsc;\n\n    let (sender, mut receiver) = mpsc::channel(100);\n\n    let mut emulator = Emulator::new(sender, program, emulator::Mode::Immediate, viewport.into());\n\n    let start = Instant::now();\n\n    loop {\n        if let Ok(event) = receiver.try_recv() {\n            match event {\n                emulator::Event::Action(action) => {\n                    emulator.perform(program, action);\n                }\n                emulator::Event::Failed(_) => {\n                    unreachable!(\"no instructions should be executed during a screenshot\");\n                }\n                emulator::Event::Ready => {}\n            }\n        }\n\n        if start.elapsed() >= duration {\n            break;\n        }\n\n        std::thread::sleep(Duration::from_millis(1));\n    }\n\n    emulator.screenshot(program, theme, scale_factor)\n}\n"
  },
  {
    "path": "test/src/simulator.rs",
    "content": "//! Run a simulation of your application without side effects.\nuse crate::core;\nuse crate::core::event;\nuse crate::core::keyboard;\nuse crate::core::mouse;\nuse crate::core::theme;\nuse crate::core::time;\nuse crate::core::widget;\nuse crate::core::window;\nuse crate::core::{Element, Event, Point, Settings, Size, SmolStr};\nuse crate::renderer;\nuse crate::runtime::UserInterface;\nuse crate::runtime::user_interface;\nuse crate::selector::Bounded;\nuse crate::{Error, Selector};\n\nuse std::borrow::Cow;\nuse std::env;\nuse std::fs;\nuse std::io;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\n/// A user interface that can be interacted with and inspected programmatically.\npub struct Simulator<'a, Message, Theme = core::Theme, Renderer = renderer::Renderer> {\n    raw: UserInterface<'a, Message, Theme, Renderer>,\n    renderer: Renderer,\n    size: Size,\n    cursor: mouse::Cursor,\n    messages: Vec<Message>,\n}\n\nimpl<'a, Message, Theme, Renderer> Simulator<'a, Message, Theme, Renderer>\nwhere\n    Theme: theme::Base,\n    Renderer: core::Renderer + core::renderer::Headless,\n{\n    /// Creates a new [`Simulator`] with default [`Settings`] and a default size (1024x768).\n    pub fn new(element: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self::with_settings(Settings::default(), element)\n    }\n\n    /// Creates a new [`Simulator`] with the given [`Settings`] and a default size (1024x768).\n    pub fn with_settings(\n        settings: Settings,\n        element: impl Into<Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        Self::with_size(settings, window::Settings::default().size, element)\n    }\n\n    /// Creates a new [`Simulator`] with the given [`Settings`] and size.\n    pub fn with_size(\n        settings: Settings,\n        size: impl Into<Size>,\n        element: impl Into<Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        let size = size.into();\n\n        for font in settings.fonts {\n            load_font(font).expect(\"Font must be valid\");\n        }\n\n        let mut renderer = {\n            let backend = env::var(\"ICED_TEST_BACKEND\").ok();\n\n            crate::futures::futures::executor::block_on(Renderer::new(\n                core::renderer::Settings {\n                    default_font: settings.default_font,\n                    default_text_size: settings.default_text_size,\n                },\n                backend.as_deref(),\n            ))\n            .expect(\"Create new headless renderer\")\n        };\n\n        let raw = UserInterface::build(\n            element,\n            size,\n            user_interface::Cache::default(),\n            &mut renderer,\n        );\n\n        Simulator {\n            raw,\n            renderer,\n            size,\n            cursor: mouse::Cursor::Unavailable,\n            messages: Vec::new(),\n        }\n    }\n\n    /// Finds the target of the given widget [`Selector`] in the [`Simulator`].\n    pub fn find<S>(&mut self, selector: S) -> Result<S::Output, Error>\n    where\n        S: Selector + Send,\n        S::Output: Clone + Send,\n    {\n        use widget::Operation;\n\n        let description = selector.description();\n        let mut operation = selector.find();\n\n        self.raw.operate(\n            &self.renderer,\n            &mut widget::operation::black_box(&mut operation),\n        );\n\n        match operation.finish() {\n            widget::operation::Outcome::Some(output) => output.ok_or(Error::SelectorNotFound {\n                selector: description,\n            }),\n            _ => Err(Error::SelectorNotFound {\n                selector: description,\n            }),\n        }\n    }\n\n    /// Points the mouse cursor at the given position in the [`Simulator`].\n    ///\n    /// This does _not_ produce mouse movement events!\n    pub fn point_at(&mut self, position: impl Into<Point>) {\n        self.cursor = mouse::Cursor::Available(position.into());\n    }\n\n    /// Clicks the [`Bounded`] target found by the given [`Selector`], if any.\n    ///\n    /// This consists in:\n    /// - Pointing the mouse cursor at the center of the [`Bounded`] target.\n    /// - Simulating a [`click`].\n    pub fn click<S>(&mut self, selector: S) -> Result<S::Output, Error>\n    where\n        S: Selector + Send,\n        S::Output: Bounded + Clone + Send + Sync + 'static,\n    {\n        let target = self.find(selector)?;\n\n        let Some(visible_bounds) = target.visible_bounds() else {\n            return Err(Error::TargetNotVisible {\n                target: Arc::new(target),\n            });\n        };\n\n        self.point_at(visible_bounds.center());\n\n        let _ = self.simulate(click());\n\n        Ok(target)\n    }\n\n    /// Simulates a key press, followed by a release, in the [`Simulator`].\n    pub fn tap_key(&mut self, key: impl Into<keyboard::Key>) -> event::Status {\n        self.simulate(tap_key(key, None))\n            .first()\n            .copied()\n            .unwrap_or(event::Status::Ignored)\n    }\n\n    /// Simulates a user typing in the keyboard the given text in the [`Simulator`].\n    pub fn typewrite(&mut self, text: &str) -> event::Status {\n        let statuses = self.simulate(typewrite(text));\n\n        statuses\n            .into_iter()\n            .fold(event::Status::Ignored, event::Status::merge)\n    }\n\n    /// Simulates the given raw sequence of events in the [`Simulator`].\n    pub fn simulate(&mut self, events: impl IntoIterator<Item = Event>) -> Vec<event::Status> {\n        let events: Vec<Event> = events.into_iter().collect();\n\n        let (_state, statuses) =\n            self.raw\n                .update(&events, self.cursor, &mut self.renderer, &mut self.messages);\n\n        statuses\n    }\n\n    /// Draws and takes a [`Snapshot`] of the interface in the [`Simulator`].\n    pub fn snapshot(&mut self, theme: &Theme) -> Result<Snapshot, Error> {\n        let base = theme.base();\n\n        let _ = self.raw.update(\n            &[Event::Window(window::Event::RedrawRequested(\n                time::Instant::now(),\n            ))],\n            self.cursor,\n            &mut self.renderer,\n            &mut self.messages,\n        );\n\n        self.raw.draw(\n            &mut self.renderer,\n            theme,\n            &core::renderer::Style {\n                text_color: base.text_color,\n            },\n            self.cursor,\n        );\n\n        let scale_factor = 2.0;\n\n        let physical_size = Size::new(\n            (self.size.width * scale_factor).round() as u32,\n            (self.size.height * scale_factor).round() as u32,\n        );\n\n        let rgba = self\n            .renderer\n            .screenshot(physical_size, scale_factor, base.background_color);\n\n        Ok(Snapshot {\n            screenshot: window::Screenshot::new(rgba, physical_size, scale_factor),\n            renderer: self.renderer.name(),\n        })\n    }\n\n    /// Turns the [`Simulator`] into the sequence of messages produced by any interactions.\n    pub fn into_messages(self) -> impl Iterator<Item = Message> + use<Message, Theme, Renderer> {\n        self.messages.into_iter()\n    }\n}\n\n/// A frame of a user interface rendered by a [`Simulator`].\n#[derive(Debug, Clone)]\npub struct Snapshot {\n    screenshot: window::Screenshot,\n    renderer: String,\n}\n\nimpl Snapshot {\n    /// Compares the [`Snapshot`] with the PNG image found in the given path, returning\n    /// `true` if they are identical.\n    ///\n    /// If the PNG image does not exist, it will be created by the [`Snapshot`] for future\n    /// testing and `true` will be returned.\n    pub fn matches_image(&self, path: impl AsRef<Path>) -> Result<bool, Error> {\n        let path = self.path(path, \"png\");\n\n        if path.exists() {\n            let file = fs::File::open(&path)?;\n            let decoder = png::Decoder::new(io::BufReader::new(file));\n\n            let mut reader = decoder.read_info()?;\n            let n = reader\n                .output_buffer_size()\n                .expect(\"snapshot should fit in memory\");\n            let mut bytes = vec![0; n];\n            let info = reader.next_frame(&mut bytes)?;\n\n            Ok(self.screenshot.rgba == bytes[..info.buffer_size()])\n        } else {\n            if let Some(directory) = path.parent() {\n                fs::create_dir_all(directory)?;\n            }\n\n            let file = fs::File::create(path)?;\n\n            let mut encoder = png::Encoder::new(\n                file,\n                self.screenshot.size.width,\n                self.screenshot.size.height,\n            );\n            encoder.set_color(png::ColorType::Rgba);\n\n            let mut writer = encoder.write_header()?;\n            writer.write_image_data(&self.screenshot.rgba)?;\n            writer.finish()?;\n\n            Ok(true)\n        }\n    }\n\n    /// Compares the [`Snapshot`] with the SHA-256 hash file found in the given path, returning\n    /// `true` if they are identical.\n    ///\n    /// If the hash file does not exist, it will be created by the [`Snapshot`] for future\n    /// testing and `true` will be returned.\n    pub fn matches_hash(&self, path: impl AsRef<Path>) -> Result<bool, Error> {\n        use sha2::{Digest, Sha256};\n\n        let path = self.path(path, \"sha256\");\n\n        let hash = {\n            let mut hasher = Sha256::new();\n            hasher.update(&self.screenshot.rgba);\n            format!(\"{:x}\", hasher.finalize())\n        };\n\n        if path.exists() {\n            let saved_hash = fs::read_to_string(&path)?;\n\n            Ok(hash == saved_hash)\n        } else {\n            if let Some(directory) = path.parent() {\n                fs::create_dir_all(directory)?;\n            }\n\n            fs::write(path, hash)?;\n            Ok(true)\n        }\n    }\n\n    fn path(&self, path: impl AsRef<Path>, extension: &str) -> PathBuf {\n        let path = path.as_ref();\n\n        path.with_file_name(format!(\n            \"{name}-{renderer}\",\n            name = path\n                .file_stem()\n                .map(std::ffi::OsStr::to_string_lossy)\n                .unwrap_or_default(),\n            renderer = self.renderer\n        ))\n        .with_extension(extension)\n    }\n}\n\n/// Creates a new [`Simulator`].\n///\n/// This is just a function version of [`Simulator::new`].\npub fn simulator<'a, Message, Theme, Renderer>(\n    element: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Simulator<'a, Message, Theme, Renderer>\nwhere\n    Theme: theme::Base,\n    Renderer: core::Renderer + core::renderer::Headless,\n{\n    Simulator::new(element)\n}\n\n/// Returns the sequence of events of a click.\npub fn click() -> impl Iterator<Item = Event> {\n    [\n        Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),\n        Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)),\n    ]\n    .into_iter()\n}\n\n/// Returns the sequence of events of a key press.\npub fn press_key(key: impl Into<keyboard::Key>, text: Option<SmolStr>) -> Event {\n    let key = key.into();\n\n    Event::Keyboard(keyboard::Event::KeyPressed {\n        key: key.clone(),\n        modified_key: key,\n        physical_key: keyboard::key::Physical::Unidentified(\n            keyboard::key::NativeCode::Unidentified,\n        ),\n        location: keyboard::Location::Standard,\n        modifiers: keyboard::Modifiers::default(),\n        repeat: false,\n        text,\n    })\n}\n\n/// Returns the sequence of events of a key release.\npub fn release_key(key: impl Into<keyboard::Key>) -> Event {\n    let key = key.into();\n\n    Event::Keyboard(keyboard::Event::KeyReleased {\n        key: key.clone(),\n        modified_key: key,\n        physical_key: keyboard::key::Physical::Unidentified(\n            keyboard::key::NativeCode::Unidentified,\n        ),\n        location: keyboard::Location::Standard,\n        modifiers: keyboard::Modifiers::default(),\n    })\n}\n\n/// Returns the sequence of events of a \"key tap\" (i.e. pressing and releasing a key).\npub fn tap_key(\n    key: impl Into<keyboard::Key>,\n    text: Option<SmolStr>,\n) -> impl Iterator<Item = Event> {\n    let key = key.into();\n\n    [press_key(key.clone(), text), release_key(key)].into_iter()\n}\n\n/// Returns the sequence of events of typewriting the given text in a keyboard.\npub fn typewrite(text: &str) -> impl Iterator<Item = Event> + '_ {\n    text.chars()\n        .map(|c| SmolStr::new_inline(&c.to_string()))\n        .flat_map(|c| tap_key(keyboard::Key::Character(c.clone()), Some(c)))\n}\n\nfn load_font(font: impl Into<Cow<'static, [u8]>>) -> Result<(), Error> {\n    renderer::graphics::text::font_system()\n        .write()\n        .expect(\"Write to font system\")\n        .load_font(font.into());\n\n    Ok(())\n}\n"
  },
  {
    "path": "tester/Cargo.toml",
    "content": "[package]\nname = \"iced_tester\"\ndescription = \"A test recorder, editor, and runner for your iced applications\"\nversion.workspace = true\nauthors.workspace = true\nedition.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\nrust-version.workspace = true\n\n[dependencies]\niced_test.workspace = true\niced_widget.workspace = true\nlog.workspace = true\nrfd.workspace = true\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "tester/fonts/iced_tester-icons.toml",
    "content": "module = \"icon\"\n\n[glyphs]\nplay = \"entypo-play\"\nstop = \"entypo-stop\"\npause = \"entypo-pause\"\nrecord = \"entypo-record\"\nlightbulb = \"fontawesome-lightbulb\"\ncheck = \"entypo-check\"\ncancel = \"entypo-cancel\"\nfolder = \"entypo-folder\"\nfloppy = \"entypo-floppy\"\npencil = \"entypo-pencil\"\nmouse_pointer = \"fontawesome-mouse-pointer\"\nkeyboard = \"entypo-keyboard\"\n"
  },
  {
    "path": "tester/src/icon.rs",
    "content": "#![allow(unused)]\nuse crate::core::Font;\nuse crate::program;\nuse crate::widget::{Text, text};\n\npub const FONT: &[u8] = include_bytes!(\"../fonts/iced_tester-icons.ttf\");\n\npub fn cancel<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{2715}\")\n}\n\npub fn check<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{2713}\")\n}\n\npub fn floppy<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{1F4BE}\")\n}\n\npub fn folder<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{1F4C1}\")\n}\n\npub fn keyboard<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{2328}\")\n}\n\npub fn lightbulb<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{F0EB}\")\n}\n\npub fn mouse_pointer<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{F245}\")\n}\n\npub fn pause<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{2389}\")\n}\n\npub fn pencil<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{270E}\")\n}\n\npub fn play<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{25B6}\")\n}\n\npub fn record<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{26AB}\")\n}\n\npub fn stop<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{25A0}\")\n}\n\npub fn tape<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    icon(\"\\u{2707}\")\n}\n\nfn icon<'a, Theme, Renderer>(codepoint: &'a str) -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: program::Renderer,\n{\n    text(codepoint).font(\"iced_devtools-icons\")\n}\n"
  },
  {
    "path": "tester/src/lib.rs",
    "content": "//! Record, edit, and run end-to-end tests for your iced applications.\npub use iced_test as test;\npub use iced_test::core;\npub use iced_test::program;\npub use iced_test::runtime;\npub use iced_test::runtime::futures;\npub use iced_widget as widget;\n\nmod icon;\nmod recorder;\n\nuse recorder::recorder;\n\nuse crate::core::Alignment::Center;\nuse crate::core::Length::Fill;\nuse crate::core::alignment::Horizontal::Right;\nuse crate::core::border;\nuse crate::core::mouse;\nuse crate::core::theme;\nuse crate::core::window;\nuse crate::core::{Color, Element, Font, Settings, Size, Theme};\nuse crate::futures::futures::channel::mpsc;\nuse crate::program::Program;\nuse crate::runtime::task::{self, Task};\nuse crate::test::emulator;\nuse crate::test::ice;\nuse crate::test::instruction;\nuse crate::test::{Emulator, Ice, Instruction};\nuse crate::widget::{\n    button, center, column, combo_box, container, pick_list, row, rule, scrollable, slider, space,\n    stack, text, text_editor, themer,\n};\n\nuse std::ops::RangeInclusive;\n\n/// Attaches a [`Tester`] to the given [`Program`].\npub fn attach<P: Program + 'static>(program: P) -> Attach<P> {\n    Attach { program }\n}\n\n/// A [`Program`] with a [`Tester`] attached to it.\n#[derive(Debug)]\npub struct Attach<P> {\n    /// The original [`Program`] attached to the [`Tester`].\n    pub program: P,\n}\n\nimpl<P> Program for Attach<P>\nwhere\n    P: Program + 'static,\n{\n    type State = Tester<P>;\n    type Message = Message<P>;\n    type Theme = Theme;\n    type Renderer = P::Renderer;\n    type Executor = P::Executor;\n\n    fn name() -> &'static str {\n        P::name()\n    }\n\n    fn settings(&self) -> Settings {\n        let mut settings = self.program.settings();\n        settings.fonts.push(icon::FONT.into());\n        settings\n    }\n\n    fn window(&self) -> Option<window::Settings> {\n        Some(\n            self.program\n                .window()\n                .map(|window| window::Settings {\n                    size: window.size + Size::new(300.0, 80.0),\n                    ..window\n                })\n                .unwrap_or_default(),\n        )\n    }\n\n    fn boot(&self) -> (Self::State, Task<Self::Message>) {\n        (Tester::new(&self.program), Task::none())\n    }\n\n    fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> {\n        state.tick(&self.program, message.0).map(Message)\n    }\n\n    fn view<'a>(\n        &self,\n        state: &'a Self::State,\n        window: window::Id,\n    ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {\n        state.view(&self.program, window).map(Message)\n    }\n\n    fn theme(&self, state: &Self::State, window: window::Id) -> Option<Theme> {\n        state\n            .theme(&self.program, window)\n            .as_ref()\n            .and_then(theme::Base::seed)\n            .map(|seed| Theme::custom(\"Tester\", seed))\n    }\n}\n\n/// A tester decorates a [`Program`] definition and attaches a test recorder on top.\n///\n/// It can be used to both record and play [`Ice`] tests.\npub struct Tester<P: Program> {\n    viewport: Size,\n    mode: emulator::Mode,\n    presets: combo_box::State<String>,\n    preset: Option<String>,\n    instructions: Vec<Instruction>,\n    state: State<P>,\n    edit: Option<text_editor::Content<P::Renderer>>,\n}\n\nenum State<P: Program> {\n    Empty,\n    Idle {\n        state: P::State,\n    },\n    Recording {\n        emulator: Emulator<P>,\n    },\n    Asserting {\n        state: P::State,\n        window: window::Id,\n        last_interaction: Option<instruction::Interaction>,\n    },\n    Playing {\n        emulator: Emulator<P>,\n        current: usize,\n        outcome: Outcome,\n    },\n}\n\nenum Outcome {\n    Running,\n    Failed,\n    Success,\n}\n\n/// The message of a [`Tester`].\npub struct Message<P: Program>(Tick<P>);\n\n#[derive(Debug, Clone)]\nenum Event {\n    ViewportChanged(Size),\n    ModeSelected(emulator::Mode),\n    PresetSelected(String),\n    Record,\n    Stop,\n    Play,\n    Import,\n    Export,\n    Imported(Result<Ice, ice::ParseError>),\n    Edit,\n    Edited(text_editor::Action),\n    Confirm,\n}\n\nenum Tick<P: Program> {\n    Tester(Event),\n    Program(P::Message),\n    Emulator(emulator::Event<P>),\n    Record(instruction::Interaction),\n    Assert(instruction::Interaction),\n}\n\nimpl<P: Program + 'static> Tester<P> {\n    fn new(program: &P) -> Self {\n        let (state, _) = program.boot();\n        let window = program.window().unwrap_or_default();\n\n        Self {\n            mode: emulator::Mode::default(),\n            viewport: window.size,\n            presets: combo_box::State::new(\n                program\n                    .presets()\n                    .iter()\n                    .map(program::Preset::name)\n                    .map(str::to_owned)\n                    .collect(),\n            ),\n            preset: None,\n            instructions: Vec::new(),\n            state: State::Idle { state },\n            edit: None,\n        }\n    }\n\n    fn is_busy(&self) -> bool {\n        matches!(\n            self.state,\n            State::Recording { .. }\n                | State::Playing {\n                    outcome: Outcome::Running,\n                    ..\n                }\n        )\n    }\n\n    fn update(&mut self, program: &P, event: Event) -> Task<Tick<P>> {\n        match event {\n            Event::ViewportChanged(viewport) => {\n                self.viewport = viewport;\n\n                Task::none()\n            }\n            Event::ModeSelected(mode) => {\n                self.mode = mode;\n\n                Task::none()\n            }\n            Event::PresetSelected(preset) => {\n                self.preset = Some(preset);\n\n                let (state, _) = self\n                    .preset(program)\n                    .map(program::Preset::boot)\n                    .unwrap_or_else(|| program.boot());\n\n                self.state = State::Idle { state };\n\n                Task::none()\n            }\n            Event::Record => {\n                self.edit = None;\n                self.instructions.clear();\n\n                let (sender, receiver) = mpsc::channel(1);\n\n                let emulator = Emulator::with_preset(\n                    sender,\n                    program,\n                    self.mode,\n                    self.viewport,\n                    self.preset(program),\n                );\n\n                self.state = State::Recording { emulator };\n\n                Task::run(receiver, Tick::Emulator)\n            }\n            Event::Stop => {\n                let State::Recording { emulator } =\n                    std::mem::replace(&mut self.state, State::Empty)\n                else {\n                    return Task::none();\n                };\n\n                while let Some(Instruction::Interact(instruction::Interaction::Mouse(\n                    instruction::Mouse::Move(_),\n                ))) = self.instructions.last()\n                {\n                    let _ = self.instructions.pop();\n                }\n\n                let (state, window) = emulator.into_state();\n\n                self.state = State::Asserting {\n                    state,\n                    window,\n                    last_interaction: None,\n                };\n\n                Task::none()\n            }\n            Event::Play => {\n                self.confirm();\n\n                let (sender, receiver) = mpsc::channel(1);\n\n                let emulator = Emulator::with_preset(\n                    sender,\n                    program,\n                    self.mode,\n                    self.viewport,\n                    self.preset(program),\n                );\n\n                self.state = State::Playing {\n                    emulator,\n                    current: 0,\n                    outcome: Outcome::Running,\n                };\n\n                Task::run(receiver, Tick::Emulator)\n            }\n            Event::Import => {\n                use std::fs;\n\n                let import = rfd::AsyncFileDialog::new()\n                    .add_filter(\"ice\", &[\"ice\"])\n                    .pick_file();\n\n                Task::future(import)\n                    .and_then(|file| {\n                        task::blocking(move |mut sender| {\n                            let _ = sender.try_send(Ice::parse(\n                                &fs::read_to_string(file.path()).unwrap_or_default(),\n                            ));\n                        })\n                    })\n                    .map(Event::Imported)\n                    .map(Tick::Tester)\n            }\n            Event::Export => {\n                use std::fs;\n                use std::thread;\n\n                self.confirm();\n\n                let ice = Ice {\n                    viewport: self.viewport,\n                    mode: self.mode,\n                    preset: self.preset.clone(),\n                    instructions: self.instructions.clone(),\n                };\n\n                let export = rfd::AsyncFileDialog::new()\n                    .add_filter(\"ice\", &[\"ice\"])\n                    .save_file();\n\n                Task::future(async move {\n                    let Some(file) = export.await else {\n                        return;\n                    };\n\n                    let _ = thread::spawn(move || fs::write(file.path(), ice.to_string()));\n                })\n                .discard()\n            }\n            Event::Imported(Ok(ice)) => {\n                self.viewport = ice.viewport;\n                self.mode = ice.mode;\n                self.preset = ice.preset;\n                self.instructions = ice.instructions;\n                self.edit = None;\n\n                let (state, _) = self\n                    .preset(program)\n                    .map(program::Preset::boot)\n                    .unwrap_or_else(|| program.boot());\n\n                self.state = State::Idle { state };\n\n                Task::none()\n            }\n            Event::Edit => {\n                if self.is_busy() {\n                    return Task::none();\n                }\n\n                self.edit = Some(text_editor::Content::with_text(\n                    &self\n                        .instructions\n                        .iter()\n                        .map(Instruction::to_string)\n                        .collect::<Vec<_>>()\n                        .join(\"\\n\"),\n                ));\n\n                Task::none()\n            }\n            Event::Edited(action) => {\n                if let Some(edit) = &mut self.edit {\n                    edit.perform(action);\n                }\n\n                Task::none()\n            }\n            Event::Confirm => {\n                self.confirm();\n\n                Task::none()\n            }\n            Event::Imported(Err(error)) => {\n                log::error!(\"{error}\");\n\n                Task::none()\n            }\n        }\n    }\n\n    fn confirm(&mut self) {\n        let Some(edit) = &mut self.edit else {\n            return;\n        };\n\n        self.instructions = edit\n            .lines()\n            .filter(|line| !line.text.trim().is_empty())\n            .filter_map(|line| Instruction::parse(&line.text).ok())\n            .collect();\n\n        self.edit = None;\n    }\n\n    fn theme(&self, program: &P, window: window::Id) -> Option<P::Theme> {\n        match &self.state {\n            State::Empty => None,\n            State::Idle { state } => program.theme(state, window),\n            State::Recording { emulator } | State::Playing { emulator, .. } => {\n                emulator.theme(program)\n            }\n            State::Asserting { state, window, .. } => program.theme(state, *window),\n        }\n    }\n\n    fn preset<'a>(&self, program: &'a P) -> Option<&'a program::Preset<P::State, P::Message>> {\n        self.preset.as_ref().and_then(|preset| {\n            program\n                .presets()\n                .iter()\n                .find(|candidate| candidate.name() == preset)\n        })\n    }\n\n    fn tick(&mut self, program: &P, tick: Tick<P>) -> Task<Tick<P>> {\n        match tick {\n            Tick::Tester(message) => self.update(program, message),\n            Tick::Program(message) => {\n                let State::Recording { emulator } = &mut self.state else {\n                    return Task::none();\n                };\n\n                emulator.update(program, message);\n\n                Task::none()\n            }\n            Tick::Emulator(event) => {\n                match &mut self.state {\n                    State::Recording { emulator } => {\n                        if let emulator::Event::Action(action) = event {\n                            emulator.perform(program, action);\n                        }\n                    }\n                    State::Playing {\n                        emulator,\n                        current,\n                        outcome,\n                    } => match event {\n                        emulator::Event::Action(action) => {\n                            emulator.perform(program, action);\n                        }\n                        emulator::Event::Failed(_instruction) => {\n                            *outcome = Outcome::Failed;\n                        }\n                        emulator::Event::Ready => {\n                            *current += 1;\n\n                            if let Some(instruction) = self.instructions.get(*current - 1) {\n                                emulator.run(program, instruction);\n                            }\n\n                            if *current >= self.instructions.len() {\n                                *outcome = Outcome::Success;\n                            }\n                        }\n                    },\n                    State::Empty | State::Idle { .. } | State::Asserting { .. } => {}\n                }\n\n                Task::none()\n            }\n            Tick::Record(interaction) => {\n                let mut interaction = Some(interaction);\n\n                while let Some(new_interaction) = interaction.take() {\n                    if let Some(Instruction::Interact(last_interaction)) = self.instructions.pop() {\n                        let (merged_interaction, new_interaction) =\n                            last_interaction.merge(new_interaction);\n\n                        if let Some(new_interaction) = new_interaction {\n                            self.instructions\n                                .push(Instruction::Interact(merged_interaction));\n\n                            self.instructions\n                                .push(Instruction::Interact(new_interaction));\n                        } else {\n                            interaction = Some(merged_interaction);\n                        }\n                    } else {\n                        self.instructions\n                            .push(Instruction::Interact(new_interaction));\n                    }\n                }\n\n                Task::none()\n            }\n            Tick::Assert(interaction) => {\n                let State::Asserting {\n                    last_interaction, ..\n                } = &mut self.state\n                else {\n                    return Task::none();\n                };\n\n                *last_interaction = if let Some(last_interaction) = last_interaction.take() {\n                    let (merged, new) = last_interaction.merge(interaction);\n\n                    Some(new.unwrap_or(merged))\n                } else {\n                    Some(interaction)\n                };\n\n                let Some(interaction) = last_interaction.take() else {\n                    return Task::none();\n                };\n\n                let instruction::Interaction::Mouse(instruction::Mouse::Click {\n                    button: mouse::Button::Left,\n                    target: Some(instruction::Target::Text(text)),\n                }) = interaction\n                else {\n                    *last_interaction = Some(interaction);\n                    return Task::none();\n                };\n\n                self.instructions\n                    .push(Instruction::Expect(instruction::Expectation::Text(text)));\n\n                Task::none()\n            }\n        }\n    }\n\n    fn view<'a>(\n        &'a self,\n        program: &P,\n        window: window::Id,\n    ) -> Element<'a, Tick<P>, Theme, P::Renderer> {\n        let status = {\n            let (icon, label) = match &self.state {\n                State::Empty | State::Idle { .. } => (text(\"\"), \"Idle\"),\n                State::Recording { .. } => (icon::record(), \"Recording\"),\n                State::Asserting { .. } => (icon::lightbulb(), \"Asserting\"),\n                State::Playing { outcome, .. } => match outcome {\n                    Outcome::Running => (icon::play(), \"Playing\"),\n                    Outcome::Failed => (icon::cancel(), \"Failed\"),\n                    Outcome::Success => (icon::check(), \"Success\"),\n                },\n            };\n\n            container(row![icon.size(14), label].align_y(Center).spacing(8)).style(\n                |theme: &Theme| {\n                    let palette = theme.palette();\n\n                    container::Style {\n                        text_color: Some(match &self.state {\n                            State::Empty | State::Idle { .. } => palette.background.strongest.color,\n                            State::Recording { .. } => palette.danger.base.color,\n                            State::Asserting { .. } => palette.warning.base.color,\n                            State::Playing { outcome, .. } => match outcome {\n                                Outcome::Running => palette.primary.base.color,\n                                Outcome::Failed => palette.danger.base.color,\n                                Outcome::Success => palette.success.strong.color,\n                            },\n                        }),\n                        ..container::Style::default()\n                    }\n                },\n            )\n        };\n\n        let view = match &self.state {\n            State::Empty => Element::from(space()),\n            State::Idle { state } => program.view(state, window).map(Tick::Program),\n            State::Recording { emulator } => recorder(emulator.view(program).map(Tick::Program))\n                .on_record(Tick::Record)\n                .into(),\n            State::Asserting { state, window, .. } => {\n                recorder(program.view(state, *window).map(Tick::Program))\n                    .on_record(Tick::Assert)\n                    .into()\n            }\n            State::Playing { emulator, .. } => emulator.view(program).map(Tick::Program),\n        };\n\n        let viewport = container(\n            scrollable(\n                container(themer(self.theme(program, window), view))\n                    .width(self.viewport.width)\n                    .height(self.viewport.height),\n            )\n            .direction(scrollable::Direction::Both {\n                vertical: scrollable::Scrollbar::default(),\n                horizontal: scrollable::Scrollbar::default(),\n            }),\n        )\n        .style(|theme: &Theme| {\n            let palette = theme.palette();\n\n            container::Style {\n                border: border::width(2.0).color(match &self.state {\n                    State::Empty | State::Idle { .. } => palette.background.strongest.color,\n                    State::Recording { .. } => palette.danger.base.color,\n                    State::Asserting { .. } => palette.warning.weak.color,\n                    State::Playing { outcome, .. } => match outcome {\n                        Outcome::Running => palette.primary.base.color,\n                        Outcome::Failed => palette.danger.strong.color,\n                        Outcome::Success => palette.success.strong.color,\n                    },\n                }),\n                ..container::Style::default()\n            }\n        })\n        .padding(10);\n\n        row![\n            center(column![status, viewport].spacing(10).align_x(Right)).padding(10),\n            rule::vertical(1).style(rule::weak),\n            container(self.controls().map(Tick::Tester))\n                .width(250)\n                .padding(10)\n                .style(|theme| container::Style::default()\n                    .background(theme.palette().background.weakest.color)),\n        ]\n        .into()\n    }\n\n    fn controls(&self) -> Element<'_, Event, Theme, P::Renderer> {\n        let viewport = column![\n            labeled_slider(\n                \"Width\",\n                100.0..=2000.0,\n                self.viewport.width,\n                |width| Event::ViewportChanged(Size {\n                    width,\n                    ..self.viewport\n                }),\n                |width| format!(\"{width:.0}\"),\n            ),\n            labeled_slider(\n                \"Height\",\n                100.0..=2000.0,\n                self.viewport.height,\n                |height| Event::ViewportChanged(Size {\n                    height,\n                    ..self.viewport\n                }),\n                |height| format!(\"{height:.0}\"),\n            ),\n        ]\n        .spacing(10);\n\n        let preset = combo_box(\n            &self.presets,\n            \"Default\",\n            self.preset.as_ref(),\n            Event::PresetSelected,\n        )\n        .size(14)\n        .width(Fill);\n\n        let mode = pick_list(\n            Some(self.mode),\n            emulator::Mode::ALL,\n            emulator::Mode::to_string,\n        )\n        .on_select(Event::ModeSelected)\n        .text_size(14)\n        .width(Fill);\n\n        let player = {\n            let instructions = if let Some(edit) = &self.edit {\n                text_editor(edit)\n                    .size(12)\n                    .height(Fill)\n                    .font(Font::MONOSPACE)\n                    .on_action(Event::Edited)\n                    .into()\n            } else if self.instructions.is_empty() {\n                Element::from(center(\n                    text(\"No instructions recorded yet!\")\n                        .size(14)\n                        .font(Font::MONOSPACE)\n                        .width(Fill)\n                        .center(),\n                ))\n            } else {\n                scrollable(\n                    column(\n                        self.instructions\n                            .iter()\n                            .enumerate()\n                            .map(|(i, instruction)| {\n                                text(instruction.to_string())\n                                    .wrapping(text::Wrapping::None) // TODO: Ellipsize?\n                                    .size(10)\n                                    .font(Font::MONOSPACE)\n                                    .style(move |theme: &Theme| text::Style {\n                                        color: match &self.state {\n                                            State::Playing {\n                                                current, outcome, ..\n                                            } => {\n                                                if *current == i + 1 {\n                                                    Some(match outcome {\n                                                        Outcome::Running => {\n                                                            theme.palette().primary.base.color\n                                                        }\n                                                        Outcome::Failed => {\n                                                            theme.palette().danger.strong.color\n                                                        }\n                                                        Outcome::Success => {\n                                                            theme.palette().success.strong.color\n                                                        }\n                                                    })\n                                                } else if *current > i + 1 {\n                                                    Some(theme.palette().success.strong.color)\n                                                } else {\n                                                    None\n                                                }\n                                            }\n                                            _ => None,\n                                        },\n                                    })\n                                    .into()\n                            }),\n                    )\n                    .spacing(5),\n                )\n                .width(Fill)\n                .height(Fill)\n                .spacing(5)\n                .into()\n            };\n\n            let control = |icon: text::Text<'static, _, _>| {\n                button(icon.size(14).width(Fill).height(Fill).center())\n            };\n\n            let play = control(icon::play()).on_press_maybe(\n                (!matches!(self.state, State::Recording { .. }) && !self.instructions.is_empty())\n                    .then_some(Event::Play),\n            );\n\n            let record = if let State::Recording { .. } = &self.state {\n                control(icon::stop())\n                    .on_press(Event::Stop)\n                    .style(button::success)\n            } else {\n                control(icon::record())\n                    .on_press_maybe((!self.is_busy()).then_some(Event::Record))\n                    .style(button::danger)\n            };\n\n            let import = control(icon::folder())\n                .on_press_maybe((!self.is_busy()).then_some(Event::Import))\n                .style(button::secondary);\n\n            let export = control(icon::floppy())\n                .on_press_maybe(\n                    (!matches!(self.state, State::Recording { .. })\n                        && !self.instructions.is_empty())\n                    .then_some(Event::Export),\n                )\n                .style(button::success);\n\n            let controls = row![import, export, play, record].height(30).spacing(10);\n\n            column![instructions, controls].spacing(10).align_x(Center)\n        };\n\n        let edit = if self.is_busy() {\n            Element::from(space::horizontal())\n        } else if self.edit.is_none() {\n            button(icon::pencil().size(14))\n                .padding(0)\n                .on_press(Event::Edit)\n                .style(button::text)\n                .into()\n        } else {\n            button(icon::check().size(14))\n                .padding(0)\n                .on_press(Event::Confirm)\n                .style(button::text)\n                .into()\n        };\n\n        column![\n            labeled(\"Viewport\", viewport),\n            labeled(\"Mode\", mode),\n            labeled(\"Preset\", preset),\n            labeled_with(\"Instructions\", edit, player)\n        ]\n        .spacing(10)\n        .into()\n    }\n}\n\nfn labeled<'a, Message, Renderer>(\n    fragment: impl text::IntoFragment<'a>,\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Renderer: program::Renderer + 'a,\n{\n    column![\n        text(fragment).size(14).font(Font::MONOSPACE),\n        content.into()\n    ]\n    .spacing(5)\n    .into()\n}\n\nfn labeled_with<'a, Message, Renderer>(\n    fragment: impl text::IntoFragment<'a>,\n    control: impl Into<Element<'a, Message, Theme, Renderer>>,\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Renderer: program::Renderer + 'a,\n{\n    column![\n        row![\n            text(fragment).size(14).font(Font::MONOSPACE),\n            space::horizontal(),\n            control.into()\n        ]\n        .spacing(5)\n        .align_y(Center),\n        content.into()\n    ]\n    .spacing(5)\n    .into()\n}\n\nfn labeled_slider<'a, Message, Renderer>(\n    label: impl text::IntoFragment<'a>,\n    range: RangeInclusive<f32>,\n    current: f32,\n    on_change: impl Fn(f32) -> Message + 'a,\n    to_string: impl Fn(&f32) -> String,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone + 'a,\n    Renderer: core::text::Renderer + 'a,\n{\n    stack![\n        container(\n            slider(range, current, on_change)\n                .step(10.0)\n                .width(Fill)\n                .height(24)\n                .style(|theme: &core::Theme, status| {\n                    let palette = theme.palette();\n\n                    slider::Style {\n                        rail: slider::Rail {\n                            backgrounds: (\n                                match status {\n                                    slider::Status::Active | slider::Status::Dragged => {\n                                        palette.background.strongest.color\n                                    }\n                                    slider::Status::Hovered => palette.background.stronger.color,\n                                }\n                                .into(),\n                                Color::TRANSPARENT.into(),\n                            ),\n                            width: 24.0,\n                            border: border::rounded(2),\n                        },\n                        handle: slider::Handle {\n                            shape: slider::HandleShape::Circle { radius: 0.0 },\n                            background: Color::TRANSPARENT.into(),\n                            border_width: 0.0,\n                            border_color: Color::TRANSPARENT,\n                        },\n                    }\n                })\n        )\n        .style(|theme| container::Style::default()\n            .background(theme.palette().background.weak.color)\n            .border(border::rounded(2))),\n        row![\n            text(label).size(14).style(|theme: &core::Theme| {\n                text::Style {\n                    color: Some(theme.palette().background.weak.text),\n                }\n            }),\n            space::horizontal(),\n            text(to_string(&current)).size(14)\n        ]\n        .padding([0, 10])\n        .height(Fill)\n        .align_y(Center),\n    ]\n    .into()\n}\n"
  },
  {
    "path": "tester/src/recorder.rs",
    "content": "use crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::theme;\nuse crate::core::widget;\nuse crate::core::widget::operation;\nuse crate::core::widget::tree;\nuse crate::core::{\n    self, Color, Element, Event, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget,\n};\nuse crate::test::Selector;\nuse crate::test::instruction::{Interaction, Mouse, Target};\nuse crate::test::selector;\n\npub fn recorder<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Recorder<'a, Message, Theme, Renderer> {\n    Recorder::new(content)\n}\n\npub struct Recorder<'a, Message, Theme, Renderer> {\n    content: Element<'a, Message, Theme, Renderer>,\n    on_record: Option<Box<dyn Fn(Interaction) -> Message + 'a>>,\n    has_overlay: bool,\n}\n\nimpl<'a, Message, Theme, Renderer> Recorder<'a, Message, Theme, Renderer> {\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            content: content.into(),\n            on_record: None,\n            has_overlay: false,\n        }\n    }\n\n    pub fn on_record(mut self, on_record: impl Fn(Interaction) -> Message + 'a) -> Self {\n        self.on_record = Some(Box::new(on_record));\n        self\n    }\n}\n\nstruct State {\n    last_hovered: Option<Rectangle>,\n    last_hovered_overlay: Option<Rectangle>,\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Recorder<'_, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n    Theme: theme::Base,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State {\n            last_hovered: None,\n            last_hovered_overlay: None,\n        })\n    }\n\n    fn children(&self) -> Vec<widget::Tree> {\n        vec![widget::Tree::new(&self.content)]\n    }\n\n    fn diff(&self, tree: &mut tree::Tree) {\n        tree.diff_children(std::slice::from_ref(&self.content));\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.content.as_widget().size()\n    }\n\n    fn size_hint(&self) -> Size<Length> {\n        self.content.as_widget().size_hint()\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut widget::Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        if shell.is_event_captured() {\n            return;\n        }\n\n        if !self.has_overlay\n            && let Some(on_record) = &self.on_record\n        {\n            let state = tree.state.downcast_mut::<State>();\n\n            record(\n                event,\n                cursor,\n                shell,\n                layout.bounds(),\n                &mut state.last_hovered,\n                on_record,\n                |operation| {\n                    self.content.as_widget_mut().operate(\n                        &mut tree.children[0],\n                        layout,\n                        renderer,\n                        operation,\n                    );\n                },\n            );\n        }\n\n        self.content.as_widget_mut().update(\n            &mut tree.children[0],\n            event,\n            layout,\n            cursor,\n            renderer,\n            shell,\n            viewport,\n        );\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut widget::Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.content\n            .as_widget_mut()\n            .layout(&mut tree.children[0], renderer, limits)\n    }\n\n    fn draw(\n        &self,\n        tree: &widget::Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget().draw(\n            &tree.children[0],\n            renderer,\n            theme,\n            style,\n            layout,\n            cursor,\n            viewport,\n        );\n\n        let state = tree.state.downcast_ref::<State>();\n\n        let Some(last_hovered) = &state.last_hovered else {\n            return;\n        };\n\n        renderer.with_layer(*viewport, |renderer| {\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds: *last_hovered,\n                    ..renderer::Quad::default()\n                },\n                highlight(theme).scale_alpha(0.7),\n            );\n        });\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &widget::Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.content.as_widget().mouse_interaction(\n            &tree.children[0],\n            layout,\n            cursor,\n            viewport,\n            renderer,\n        )\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut widget::Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.content\n            .as_widget_mut()\n            .operate(&mut tree.children[0], layout, renderer, operation);\n    }\n\n    fn overlay<'a>(\n        &'a mut self,\n        tree: &'a mut widget::Tree,\n        layout: Layout<'a>,\n        renderer: &Renderer,\n        _viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {\n        self.has_overlay = false;\n\n        self.content\n            .as_widget_mut()\n            .overlay(\n                &mut tree.children[0],\n                layout,\n                renderer,\n                &layout.bounds(),\n                translation,\n            )\n            .map(|raw| {\n                self.has_overlay = true;\n\n                let state = tree.state.downcast_mut::<State>();\n\n                overlay::Element::new(Box::new(Overlay {\n                    raw,\n                    bounds: layout.bounds(),\n                    last_hovered: &mut state.last_hovered_overlay,\n                    on_record: self.on_record.as_deref(),\n                }))\n            })\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Recorder<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: theme::Base + 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(recorder: Recorder<'a, Message, Theme, Renderer>) -> Self {\n        Element::new(recorder)\n    }\n}\n\nstruct Overlay<'a, Message, Theme, Renderer> {\n    raw: overlay::Element<'a, Message, Theme, Renderer>,\n    bounds: Rectangle,\n    last_hovered: &'a mut Option<Rectangle>,\n    on_record: Option<&'a dyn Fn(Interaction) -> Message>,\n}\n\nimpl<'a, Message, Theme, Renderer> core::Overlay<Message, Theme, Renderer>\n    for Overlay<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer + 'a,\n    Theme: theme::Base + 'a,\n{\n    fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n        self.raw.as_overlay_mut().layout(renderer, bounds)\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) {\n        self.raw\n            .as_overlay()\n            .draw(renderer, theme, style, layout, cursor);\n\n        let Some(last_hovered) = &self.last_hovered else {\n            return;\n        };\n\n        renderer.with_layer(self.bounds, |renderer| {\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds: *last_hovered,\n                    ..renderer::Quad::default()\n                },\n                highlight(theme).scale_alpha(0.7),\n            );\n        });\n    }\n\n    fn operate(\n        &mut self,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.raw\n            .as_overlay_mut()\n            .operate(layout, renderer, operation);\n    }\n\n    fn update(\n        &mut self,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n    ) {\n        if shell.is_event_captured() {\n            return;\n        }\n\n        if let Some(on_event) = &self.on_record {\n            record(\n                event,\n                cursor,\n                shell,\n                self.bounds,\n                self.last_hovered,\n                on_event,\n                |operation| {\n                    self.raw\n                        .as_overlay_mut()\n                        .operate(layout, renderer, operation);\n                },\n            );\n        }\n\n        self.raw\n            .as_overlay_mut()\n            .update(event, layout, cursor, renderer, shell);\n    }\n\n    fn mouse_interaction(\n        &self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.raw\n            .as_overlay()\n            .mouse_interaction(layout, cursor, renderer)\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.raw\n            .as_overlay_mut()\n            .overlay(layout, renderer)\n            .map(|raw| {\n                overlay::Element::new(Box::new(Overlay {\n                    raw,\n                    bounds: self.bounds,\n                    last_hovered: self.last_hovered,\n                    on_record: self.on_record,\n                }))\n            })\n    }\n\n    fn index(&self) -> f32 {\n        self.raw.as_overlay().index()\n    }\n}\n\nfn record<Message>(\n    event: &Event,\n    cursor: mouse::Cursor,\n    shell: &mut Shell<'_, Message>,\n    bounds: Rectangle,\n    last_hovered: &mut Option<Rectangle>,\n    on_record: impl Fn(Interaction) -> Message,\n    operate: impl FnMut(&mut dyn widget::Operation),\n) {\n    if let Event::Mouse(_) = event\n        && !cursor.is_over(bounds)\n    {\n        return;\n    }\n\n    let interaction = if let Event::Mouse(mouse::Event::CursorMoved { position }) = event {\n        Interaction::from_event(&Event::Mouse(mouse::Event::CursorMoved {\n            position: *position - (bounds.position() - Point::ORIGIN),\n        }))\n    } else {\n        Interaction::from_event(event)\n    };\n\n    let Some(mut interaction) = interaction else {\n        return;\n    };\n\n    let Interaction::Mouse(\n        Mouse::Move(target)\n        | Mouse::Press {\n            target: Some(target),\n            ..\n        }\n        | Mouse::Release {\n            target: Some(target),\n            ..\n        }\n        | Mouse::Click {\n            target: Some(target),\n            ..\n        },\n    ) = &mut interaction\n    else {\n        shell.publish(on_record(interaction));\n        return;\n    };\n\n    let Target::Point(position) = *target else {\n        shell.publish(on_record(interaction));\n        return;\n    };\n\n    if let Some((content, visible_bounds)) =\n        find_text(position + (bounds.position() - Point::ORIGIN), operate)\n    {\n        *target = Target::Text(content);\n        *last_hovered = visible_bounds;\n    } else {\n        *last_hovered = None;\n    }\n\n    shell.publish(on_record(interaction));\n}\n\nfn find_text(\n    position: Point,\n    mut operate: impl FnMut(&mut dyn widget::Operation),\n) -> Option<(String, Option<Rectangle>)> {\n    use widget::Operation;\n\n    let mut by_position = position.find_all();\n    operate(&mut operation::black_box(&mut by_position));\n\n    let operation::Outcome::Some(targets) = by_position.finish() else {\n        return None;\n    };\n\n    let (content, visible_bounds) = targets.into_iter().rev().find_map(|target| {\n        if let selector::Target::Text {\n            content,\n            visible_bounds,\n            ..\n        }\n        | selector::Target::TextInput {\n            content,\n            visible_bounds,\n            ..\n        } = target\n        {\n            Some((content, visible_bounds))\n        } else {\n            None\n        }\n    })?;\n\n    let mut by_text = content.clone().find_all();\n    operate(&mut operation::black_box(&mut by_text));\n\n    let operation::Outcome::Some(texts) = by_text.finish() else {\n        return None;\n    };\n\n    if texts.len() > 1 {\n        return None;\n    }\n\n    Some((content, visible_bounds))\n}\n\nfn highlight(theme: &impl theme::Base) -> Color {\n    theme\n        .seed()\n        .map(|seed| seed.primary)\n        .unwrap_or(Color::from_rgb(0.0, 0.0, 1.0))\n}\n"
  },
  {
    "path": "tiny_skia/Cargo.toml",
    "content": "[package]\nname = \"iced_tiny_skia\"\ndescription = \"A software renderer for iced on top of tiny-skia\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[features]\ndefault = [\"x11\", \"wayland\"]\nimage = [\"iced_graphics/image\"]\nsvg = [\"iced_graphics/svg\", \"resvg\"]\ngeometry = [\"iced_graphics/geometry\"]\nx11 = [\"softbuffer/x11\", \"softbuffer/x11-dlopen\"]\nwayland = [\"softbuffer/wayland\", \"softbuffer/wayland-dlopen\"]\n\n[dependencies]\niced_debug.workspace = true\niced_graphics.workspace = true\n\nbytemuck.workspace = true\ncosmic-text.workspace = true\nkurbo.workspace = true\nlog.workspace = true\nrustc-hash.workspace = true\nsoftbuffer.workspace = true\ntiny-skia.workspace = true\n\nresvg.workspace = true\nresvg.optional = true\n"
  },
  {
    "path": "tiny_skia/src/engine.rs",
    "content": "use crate::Primitive;\nuse crate::core::renderer::Quad;\nuse crate::core::{Background, Color, Gradient, Rectangle, Size, Transformation, Vector};\nuse crate::graphics::{Image, Text};\nuse crate::text;\n\n#[derive(Debug)]\npub struct Engine {\n    text_pipeline: text::Pipeline,\n\n    #[cfg(feature = \"image\")]\n    pub(crate) raster_pipeline: crate::raster::Pipeline,\n    #[cfg(feature = \"svg\")]\n    pub(crate) vector_pipeline: crate::vector::Pipeline,\n}\n\nimpl Engine {\n    pub fn new() -> Self {\n        Self {\n            text_pipeline: text::Pipeline::new(),\n            #[cfg(feature = \"image\")]\n            raster_pipeline: crate::raster::Pipeline::new(),\n            #[cfg(feature = \"svg\")]\n            vector_pipeline: crate::vector::Pipeline::new(),\n        }\n    }\n\n    pub fn draw_quad(\n        &mut self,\n        quad: &Quad,\n        background: &Background,\n        transformation: Transformation,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        clip_mask: &mut tiny_skia::Mask,\n        clip_bounds: Rectangle,\n    ) {\n        let physical_bounds = quad.bounds * transformation;\n\n        if !clip_bounds.intersects(&physical_bounds) {\n            return;\n        }\n\n        let transform = into_transform(transformation);\n\n        // Make sure the border radius is not larger than the bounds\n        let border_width = quad\n            .border\n            .width\n            .min(quad.bounds.width / 2.0)\n            .min(quad.bounds.height / 2.0);\n\n        let mut fill_border_radius = <[f32; 4]>::from(quad.border.radius);\n\n        for radius in &mut fill_border_radius {\n            *radius = (*radius)\n                .min(quad.bounds.width / 2.0)\n                .min(quad.bounds.height / 2.0);\n        }\n\n        let path = rounded_rectangle(quad.bounds, fill_border_radius);\n\n        let shadow = quad.shadow;\n\n        if shadow.color.a > 0.0 {\n            let shadow_bounds = Rectangle {\n                x: quad.bounds.x + shadow.offset.x - shadow.blur_radius,\n                y: quad.bounds.y + shadow.offset.y - shadow.blur_radius,\n                width: quad.bounds.width + shadow.blur_radius * 2.0,\n                height: quad.bounds.height + shadow.blur_radius * 2.0,\n            } * transformation;\n\n            let radii = fill_border_radius\n                .into_iter()\n                .map(|radius| radius * transformation.scale_factor())\n                .collect::<Vec<_>>();\n            let (x, y, width, height) = (\n                shadow_bounds.x as u32,\n                shadow_bounds.y as u32,\n                shadow_bounds.width as u32,\n                shadow_bounds.height as u32,\n            );\n            let half_width = physical_bounds.width / 2.0;\n            let half_height = physical_bounds.height / 2.0;\n\n            let colors = (y..y + height)\n                .flat_map(|y| (x..x + width).map(move |x| (x as f32, y as f32)))\n                .filter_map(|(x, y)| {\n                    tiny_skia::Size::from_wh(half_width, half_height).map(|size| {\n                        let shadow_distance = rounded_box_sdf(\n                            Vector::new(\n                                x - physical_bounds.position().x\n                                    - (shadow.offset.x * transformation.scale_factor())\n                                    - half_width,\n                                y - physical_bounds.position().y\n                                    - (shadow.offset.y * transformation.scale_factor())\n                                    - half_height,\n                            ),\n                            size,\n                            &radii,\n                        )\n                        .max(0.0);\n                        let shadow_alpha = 1.0\n                            - smoothstep(\n                                -shadow.blur_radius * transformation.scale_factor(),\n                                shadow.blur_radius * transformation.scale_factor(),\n                                shadow_distance,\n                            );\n\n                        let mut color = into_color(shadow.color);\n                        color.apply_opacity(shadow_alpha);\n\n                        color.to_color_u8().premultiply()\n                    })\n                })\n                .collect();\n\n            if let Some(pixmap) = tiny_skia::IntSize::from_wh(width, height)\n                .and_then(|size| tiny_skia::Pixmap::from_vec(bytemuck::cast_vec(colors), size))\n            {\n                pixels.draw_pixmap(\n                    x as i32,\n                    y as i32,\n                    pixmap.as_ref(),\n                    &tiny_skia::PixmapPaint::default(),\n                    tiny_skia::Transform::default(),\n                    Some(clip_mask),\n                );\n            }\n        }\n\n        let clip_mask = (!physical_bounds.is_within(&clip_bounds)).then_some(clip_mask as &_);\n\n        pixels.fill_path(\n            &path,\n            &tiny_skia::Paint {\n                shader: match background {\n                    Background::Color(color) => tiny_skia::Shader::SolidColor(into_color(*color)),\n                    Background::Gradient(Gradient::Linear(linear)) => {\n                        let (start, end) = linear.angle.to_distance(&quad.bounds);\n\n                        let stops: Vec<tiny_skia::GradientStop> = linear\n                            .stops\n                            .into_iter()\n                            .flatten()\n                            .map(|stop| {\n                                tiny_skia::GradientStop::new(\n                                    stop.offset,\n                                    tiny_skia::Color::from_rgba(\n                                        stop.color.b,\n                                        stop.color.g,\n                                        stop.color.r,\n                                        stop.color.a,\n                                    )\n                                    .expect(\"Create color\"),\n                                )\n                            })\n                            .collect();\n\n                        tiny_skia::LinearGradient::new(\n                            tiny_skia::Point {\n                                x: start.x,\n                                y: start.y,\n                            },\n                            tiny_skia::Point { x: end.x, y: end.y },\n                            if stops.is_empty() {\n                                vec![tiny_skia::GradientStop::new(0.0, tiny_skia::Color::BLACK)]\n                            } else {\n                                stops\n                            },\n                            tiny_skia::SpreadMode::Pad,\n                            tiny_skia::Transform::identity(),\n                        )\n                        .expect(\"Create linear gradient\")\n                    }\n                },\n                anti_alias: true,\n                ..tiny_skia::Paint::default()\n            },\n            tiny_skia::FillRule::EvenOdd,\n            transform,\n            clip_mask,\n        );\n\n        if border_width > 0.0 {\n            // Border path is offset by half the border width\n            let border_bounds = Rectangle {\n                x: quad.bounds.x + border_width / 2.0,\n                y: quad.bounds.y + border_width / 2.0,\n                width: quad.bounds.width - border_width,\n                height: quad.bounds.height - border_width,\n            };\n\n            // Make sure the border radius is correct\n            let mut border_radius = <[f32; 4]>::from(quad.border.radius);\n            let mut is_simple_border = true;\n\n            for radius in &mut border_radius {\n                *radius = if *radius == 0.0 {\n                    // Path should handle this fine\n                    0.0\n                } else if *radius > border_width / 2.0 {\n                    *radius - border_width / 2.0\n                } else {\n                    is_simple_border = false;\n                    0.0\n                }\n                .min(border_bounds.width / 2.0)\n                .min(border_bounds.height / 2.0);\n            }\n\n            // Stroking a path works well in this case\n            if is_simple_border {\n                let border_path = rounded_rectangle(border_bounds, border_radius);\n\n                pixels.stroke_path(\n                    &border_path,\n                    &tiny_skia::Paint {\n                        shader: tiny_skia::Shader::SolidColor(into_color(quad.border.color)),\n                        anti_alias: true,\n                        ..tiny_skia::Paint::default()\n                    },\n                    &tiny_skia::Stroke {\n                        width: border_width,\n                        ..tiny_skia::Stroke::default()\n                    },\n                    transform,\n                    clip_mask,\n                );\n            } else {\n                // Draw corners that have too small border radii as having no border radius,\n                // but mask them with the rounded rectangle with the correct border radius.\n                let mut temp_pixmap =\n                    tiny_skia::Pixmap::new(quad.bounds.width as u32, quad.bounds.height as u32)\n                        .unwrap();\n\n                let mut quad_mask =\n                    tiny_skia::Mask::new(quad.bounds.width as u32, quad.bounds.height as u32)\n                        .unwrap();\n\n                let zero_bounds = Rectangle {\n                    x: 0.0,\n                    y: 0.0,\n                    width: quad.bounds.width,\n                    height: quad.bounds.height,\n                };\n                let path = rounded_rectangle(zero_bounds, fill_border_radius);\n\n                quad_mask.fill_path(&path, tiny_skia::FillRule::EvenOdd, true, transform);\n                let path_bounds = Rectangle {\n                    x: border_width / 2.0,\n                    y: border_width / 2.0,\n                    width: quad.bounds.width - border_width,\n                    height: quad.bounds.height - border_width,\n                };\n\n                let border_radius_path = rounded_rectangle(path_bounds, border_radius);\n\n                temp_pixmap.stroke_path(\n                    &border_radius_path,\n                    &tiny_skia::Paint {\n                        shader: tiny_skia::Shader::SolidColor(into_color(quad.border.color)),\n                        anti_alias: true,\n                        ..tiny_skia::Paint::default()\n                    },\n                    &tiny_skia::Stroke {\n                        width: border_width,\n                        ..tiny_skia::Stroke::default()\n                    },\n                    transform,\n                    Some(&quad_mask),\n                );\n\n                pixels.draw_pixmap(\n                    quad.bounds.x as i32,\n                    quad.bounds.y as i32,\n                    temp_pixmap.as_ref(),\n                    &tiny_skia::PixmapPaint::default(),\n                    transform,\n                    clip_mask,\n                );\n            }\n        }\n    }\n\n    pub fn draw_text(\n        &mut self,\n        text: &Text,\n        transformation: Transformation,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        clip_mask: &mut tiny_skia::Mask,\n        clip_bounds: Rectangle,\n    ) {\n        match text {\n            Text::Paragraph {\n                paragraph,\n                position,\n                color,\n                clip_bounds: local_clip_bounds,\n                transformation: local_transformation,\n            } => {\n                let transformation = transformation * *local_transformation;\n                let Some(clip_bounds) =\n                    clip_bounds.intersection(&(*local_clip_bounds * transformation))\n                else {\n                    return;\n                };\n\n                let physical_bounds =\n                    Rectangle::new(*position, paragraph.min_bounds) * transformation;\n\n                if !clip_bounds.intersects(&physical_bounds) {\n                    return;\n                }\n\n                let clip_mask = match physical_bounds.is_within(&clip_bounds) {\n                    true => None,\n                    false => {\n                        adjust_clip_mask(clip_mask, clip_bounds);\n                        Some(clip_mask as &_)\n                    }\n                };\n\n                self.text_pipeline.draw_paragraph(\n                    paragraph,\n                    *position,\n                    *color,\n                    pixels,\n                    clip_mask,\n                    transformation,\n                );\n            }\n            Text::Editor {\n                editor,\n                position,\n                color,\n                clip_bounds: local_clip_bounds,\n                transformation: local_transformation,\n            } => {\n                let transformation = transformation * *local_transformation;\n\n                let Some(clip_bounds) =\n                    clip_bounds.intersection(&(*local_clip_bounds * transformation))\n                else {\n                    return;\n                };\n\n                adjust_clip_mask(clip_mask, clip_bounds);\n\n                self.text_pipeline.draw_editor(\n                    editor,\n                    *position,\n                    *color,\n                    pixels,\n                    Some(clip_mask),\n                    transformation,\n                );\n            }\n            Text::Cached {\n                content,\n                bounds,\n                color,\n                size,\n                line_height,\n                font,\n                align_x,\n                align_y,\n                shaping,\n                wrapping,\n                ellipsis,\n                clip_bounds: local_clip_bounds,\n            } => {\n                let physical_bounds = *local_clip_bounds * transformation;\n\n                if !clip_bounds.intersects(&physical_bounds) {\n                    return;\n                }\n\n                let clip_mask = match physical_bounds.is_within(&clip_bounds) {\n                    true => None,\n                    false => {\n                        adjust_clip_mask(clip_mask, clip_bounds);\n                        Some(clip_mask as &_)\n                    }\n                };\n\n                self.text_pipeline.draw_cached(\n                    content,\n                    *bounds,\n                    *color,\n                    *size,\n                    *line_height,\n                    *font,\n                    *align_x,\n                    *align_y,\n                    *shaping,\n                    *wrapping,\n                    *ellipsis,\n                    pixels,\n                    clip_mask,\n                    transformation,\n                );\n            }\n            Text::Raw {\n                raw,\n                transformation: local_transformation,\n            } => {\n                let Some(buffer) = raw.buffer.upgrade() else {\n                    return;\n                };\n\n                let transformation = transformation * *local_transformation;\n                let (width, height) = buffer.size();\n\n                let physical_bounds = Rectangle::new(\n                    raw.position,\n                    Size::new(\n                        width.unwrap_or(clip_bounds.width),\n                        height.unwrap_or(clip_bounds.height),\n                    ),\n                ) * transformation;\n\n                if !clip_bounds.intersects(&physical_bounds) {\n                    return;\n                }\n\n                let clip_mask =\n                    (!physical_bounds.is_within(&clip_bounds)).then_some(clip_mask as &_);\n\n                self.text_pipeline.draw_raw(\n                    &buffer,\n                    raw.position,\n                    raw.color,\n                    pixels,\n                    clip_mask,\n                    transformation,\n                );\n            }\n        }\n    }\n\n    pub fn draw_primitive(\n        &mut self,\n        primitive: &Primitive,\n        transformation: Transformation,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        clip_mask: &mut tiny_skia::Mask,\n        clip_bounds: Rectangle,\n    ) {\n        match primitive {\n            Primitive::Fill { path, paint, rule } => {\n                let physical_bounds = {\n                    let bounds = path.bounds();\n\n                    Rectangle {\n                        x: bounds.x(),\n                        y: bounds.y(),\n                        width: bounds.width(),\n                        height: bounds.height(),\n                    } * transformation\n                };\n\n                if !clip_bounds.intersects(&physical_bounds) {\n                    return;\n                }\n\n                let clip_mask =\n                    (!physical_bounds.is_within(&clip_bounds)).then_some(clip_mask as &_);\n\n                pixels.fill_path(\n                    path,\n                    paint,\n                    *rule,\n                    into_transform(transformation),\n                    clip_mask,\n                );\n            }\n            Primitive::Stroke {\n                path,\n                paint,\n                stroke,\n            } => {\n                let physical_bounds = {\n                    let bounds = path.bounds();\n\n                    Rectangle {\n                        x: bounds.x() - stroke.width / 2.0,\n                        y: bounds.y() - stroke.width / 2.0,\n                        width: bounds.width() + stroke.width,\n                        height: bounds.height() + stroke.width,\n                    } * transformation\n                };\n\n                if !clip_bounds.intersects(&physical_bounds) {\n                    return;\n                }\n\n                let clip_mask =\n                    (!physical_bounds.is_within(&clip_bounds)).then_some(clip_mask as &_);\n\n                pixels.stroke_path(\n                    path,\n                    paint,\n                    stroke,\n                    into_transform(transformation),\n                    clip_mask,\n                );\n            }\n        }\n    }\n\n    pub fn draw_image(\n        &mut self,\n        image: &Image,\n        _transformation: Transformation,\n        _pixels: &mut tiny_skia::PixmapMut<'_>,\n        _clip_mask: &mut tiny_skia::Mask,\n        _clip_bounds: Rectangle,\n    ) {\n        match image {\n            #[cfg(feature = \"image\")]\n            Image::Raster {\n                image,\n                bounds,\n                clip_bounds: local_clip_bounds,\n            } => {\n                let physical_bounds = *local_clip_bounds * _transformation;\n\n                let Some(clip_bounds) = physical_bounds.intersection(&_clip_bounds) else {\n                    return;\n                };\n\n                // TODO: Border radius\n                adjust_clip_mask(_clip_mask, clip_bounds);\n\n                let center = physical_bounds.center();\n                let radians = f32::from(image.rotation);\n\n                let transform = into_transform(_transformation).post_rotate_at(\n                    radians.to_degrees(),\n                    center.x,\n                    center.y,\n                );\n\n                self.raster_pipeline.draw(\n                    &image.handle,\n                    image.filter_method,\n                    *bounds,\n                    image.opacity,\n                    _pixels,\n                    transform,\n                    Some(_clip_mask),\n                );\n            }\n            #[cfg(feature = \"svg\")]\n            Image::Vector { svg, bounds, .. } => {\n                let physical_bounds = *bounds * _transformation;\n\n                if !_clip_bounds.intersects(&physical_bounds) {\n                    return;\n                }\n\n                let clip_mask =\n                    (!physical_bounds.is_within(&_clip_bounds)).then_some(_clip_mask as &_);\n\n                let center = physical_bounds.center();\n                let radians = f32::from(svg.rotation);\n\n                let transform = into_transform(_transformation).post_rotate_at(\n                    radians.to_degrees(),\n                    center.x,\n                    center.y,\n                );\n\n                self.vector_pipeline.draw(\n                    &svg.handle,\n                    svg.color,\n                    *bounds,\n                    svg.opacity,\n                    _pixels,\n                    transform,\n                    clip_mask,\n                );\n            }\n            #[cfg(not(feature = \"image\"))]\n            Image::Raster { .. } => {\n                log::warn!(\"Unsupported primitive in `iced_tiny_skia`: {image:?}\",);\n            }\n            #[cfg(not(feature = \"svg\"))]\n            Image::Vector { .. } => {\n                log::warn!(\"Unsupported primitive in `iced_tiny_skia`: {image:?}\",);\n            }\n        }\n    }\n\n    pub fn trim(&mut self) {\n        self.text_pipeline.trim_cache();\n\n        #[cfg(feature = \"image\")]\n        self.raster_pipeline.trim_cache();\n\n        #[cfg(feature = \"svg\")]\n        self.vector_pipeline.trim_cache();\n    }\n}\n\npub fn into_color(color: Color) -> tiny_skia::Color {\n    tiny_skia::Color::from_rgba(color.b, color.g, color.r, color.a)\n        .expect(\"Convert color from iced to tiny_skia\")\n}\n\nfn into_transform(transformation: Transformation) -> tiny_skia::Transform {\n    let translation = transformation.translation();\n\n    tiny_skia::Transform {\n        sx: transformation.scale_factor(),\n        kx: 0.0,\n        ky: 0.0,\n        sy: transformation.scale_factor(),\n        tx: translation.x,\n        ty: translation.y,\n    }\n}\n\nfn rounded_rectangle(bounds: Rectangle, border_radius: [f32; 4]) -> tiny_skia::Path {\n    let [top_left, top_right, bottom_right, bottom_left] = border_radius;\n\n    if top_left == 0.0 && top_right == 0.0 && bottom_right == 0.0 && bottom_left == 0.0 {\n        return tiny_skia::PathBuilder::from_rect(\n            tiny_skia::Rect::from_xywh(bounds.x, bounds.y, bounds.width, bounds.height)\n                .expect(\"Build quad rectangle\"),\n        );\n    }\n\n    if top_left == top_right\n        && top_left == bottom_right\n        && top_left == bottom_left\n        && top_left == bounds.width / 2.0\n        && top_left == bounds.height / 2.0\n    {\n        return tiny_skia::PathBuilder::from_circle(\n            bounds.x + bounds.width / 2.0,\n            bounds.y + bounds.height / 2.0,\n            top_left,\n        )\n        .expect(\"Build circle path\");\n    }\n\n    let mut builder = tiny_skia::PathBuilder::new();\n\n    builder.move_to(bounds.x + top_left, bounds.y);\n    builder.line_to(bounds.x + bounds.width - top_right, bounds.y);\n\n    if top_right > 0.0 {\n        arc_to(\n            &mut builder,\n            bounds.x + bounds.width - top_right,\n            bounds.y,\n            bounds.x + bounds.width,\n            bounds.y + top_right,\n            top_right,\n        );\n    }\n\n    maybe_line_to(\n        &mut builder,\n        bounds.x + bounds.width,\n        bounds.y + bounds.height - bottom_right,\n    );\n\n    if bottom_right > 0.0 {\n        arc_to(\n            &mut builder,\n            bounds.x + bounds.width,\n            bounds.y + bounds.height - bottom_right,\n            bounds.x + bounds.width - bottom_right,\n            bounds.y + bounds.height,\n            bottom_right,\n        );\n    }\n\n    maybe_line_to(\n        &mut builder,\n        bounds.x + bottom_left,\n        bounds.y + bounds.height,\n    );\n\n    if bottom_left > 0.0 {\n        arc_to(\n            &mut builder,\n            bounds.x + bottom_left,\n            bounds.y + bounds.height,\n            bounds.x,\n            bounds.y + bounds.height - bottom_left,\n            bottom_left,\n        );\n    }\n\n    maybe_line_to(&mut builder, bounds.x, bounds.y + top_left);\n\n    if top_left > 0.0 {\n        arc_to(\n            &mut builder,\n            bounds.x,\n            bounds.y + top_left,\n            bounds.x + top_left,\n            bounds.y,\n            top_left,\n        );\n    }\n\n    builder.finish().expect(\"Build rounded rectangle path\")\n}\n\nfn maybe_line_to(path: &mut tiny_skia::PathBuilder, x: f32, y: f32) {\n    if path.last_point() != Some(tiny_skia::Point { x, y }) {\n        path.line_to(x, y);\n    }\n}\n\nfn arc_to(\n    path: &mut tiny_skia::PathBuilder,\n    x_from: f32,\n    y_from: f32,\n    x_to: f32,\n    y_to: f32,\n    radius: f32,\n) {\n    let svg_arc = kurbo::SvgArc {\n        from: kurbo::Point::new(f64::from(x_from), f64::from(y_from)),\n        to: kurbo::Point::new(f64::from(x_to), f64::from(y_to)),\n        radii: kurbo::Vec2::new(f64::from(radius), f64::from(radius)),\n        x_rotation: 0.0,\n        large_arc: false,\n        sweep: true,\n    };\n\n    match kurbo::Arc::from_svg_arc(&svg_arc) {\n        Some(arc) => {\n            arc.to_cubic_beziers(0.1, |p1, p2, p| {\n                path.cubic_to(\n                    p1.x as f32,\n                    p1.y as f32,\n                    p2.x as f32,\n                    p2.y as f32,\n                    p.x as f32,\n                    p.y as f32,\n                );\n            });\n        }\n        None => {\n            path.line_to(x_to, y_to);\n        }\n    }\n}\n\nfn smoothstep(a: f32, b: f32, x: f32) -> f32 {\n    let x = ((x - a) / (b - a)).clamp(0.0, 1.0);\n\n    x * x * (3.0 - 2.0 * x)\n}\n\nfn rounded_box_sdf(to_center: Vector, size: tiny_skia::Size, radii: &[f32]) -> f32 {\n    let radius = match (to_center.x > 0.0, to_center.y > 0.0) {\n        (true, true) => radii[2],\n        (true, false) => radii[1],\n        (false, true) => radii[3],\n        (false, false) => radii[0],\n    };\n\n    let x = (to_center.x.abs() - size.width() + radius).max(0.0);\n    let y = (to_center.y.abs() - size.height() + radius).max(0.0);\n\n    (x.powf(2.0) + y.powf(2.0)).sqrt() - radius\n}\n\npub fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) {\n    clip_mask.clear();\n\n    let path = tiny_skia::PathBuilder::from_rect(\n        tiny_skia::Rect::from_xywh(bounds.x, bounds.y, bounds.width, bounds.height)\n            .expect(\"Create clip rectangle\"),\n    );\n\n    clip_mask.fill_path(\n        &path,\n        tiny_skia::FillRule::EvenOdd,\n        false,\n        tiny_skia::Transform::default(),\n    );\n}\n"
  },
  {
    "path": "tiny_skia/src/geometry.rs",
    "content": "use crate::Primitive;\nuse crate::core::text::LineHeight;\nuse crate::core::{self, Pixels, Point, Radians, Rectangle, Size, Svg, Vector};\nuse crate::graphics::cache::{self, Cached};\nuse crate::graphics::geometry::fill::{self, Fill};\nuse crate::graphics::geometry::stroke::{self, Stroke};\nuse crate::graphics::geometry::{self, Path, Style};\nuse crate::graphics::{self, Gradient, Image, Text};\n\nuse std::sync::Arc;\n\n#[derive(Debug)]\npub enum Geometry {\n    Live {\n        text: Vec<Text>,\n        images: Vec<graphics::Image>,\n        primitives: Vec<Primitive>,\n        clip_bounds: Rectangle,\n    },\n    Cache(Cache),\n}\n\n#[derive(Debug, Clone)]\npub struct Cache {\n    pub text: Arc<[Text]>,\n    pub images: Arc<[graphics::Image]>,\n    pub primitives: Arc<[Primitive]>,\n    pub clip_bounds: Rectangle,\n}\n\nimpl Cached for Geometry {\n    type Cache = Cache;\n\n    fn load(cache: &Cache) -> Self {\n        Self::Cache(cache.clone())\n    }\n\n    fn cache(self, _group: cache::Group, _previous: Option<Cache>) -> Cache {\n        match self {\n            Self::Live {\n                primitives,\n                images,\n                text,\n                clip_bounds,\n            } => Cache {\n                primitives: Arc::from(primitives),\n                images: Arc::from(images),\n                text: Arc::from(text),\n                clip_bounds,\n            },\n            Self::Cache(cache) => cache,\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct Frame {\n    clip_bounds: Rectangle,\n    transform: tiny_skia::Transform,\n    stack: Vec<tiny_skia::Transform>,\n    primitives: Vec<Primitive>,\n    images: Vec<graphics::Image>,\n    text: Vec<Text>,\n}\n\nimpl Frame {\n    pub fn new(bounds: Rectangle) -> Self {\n        Self {\n            clip_bounds: bounds,\n            stack: Vec::new(),\n            primitives: Vec::new(),\n            images: Vec::new(),\n            text: Vec::new(),\n            transform: tiny_skia::Transform::identity(),\n        }\n    }\n}\n\nimpl geometry::frame::Backend for Frame {\n    type Geometry = Geometry;\n\n    fn width(&self) -> f32 {\n        self.clip_bounds.width\n    }\n\n    fn height(&self) -> f32 {\n        self.clip_bounds.height\n    }\n\n    fn size(&self) -> Size {\n        self.clip_bounds.size()\n    }\n\n    fn center(&self) -> Point {\n        Point::new(self.clip_bounds.width / 2.0, self.clip_bounds.height / 2.0)\n    }\n\n    fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {\n        let Some(path) = convert_path(path).and_then(|path| path.transform(self.transform)) else {\n            return;\n        };\n\n        let fill = fill.into();\n\n        let mut paint = into_paint(fill.style);\n        paint.shader.transform(self.transform);\n\n        self.primitives.push(Primitive::Fill {\n            path,\n            paint,\n            rule: into_fill_rule(fill.rule),\n        });\n    }\n\n    fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>) {\n        let Some(path) = convert_path(&Path::rectangle(top_left, size))\n            .and_then(|path| path.transform(self.transform))\n        else {\n            return;\n        };\n\n        let fill = fill.into();\n\n        let mut paint = tiny_skia::Paint {\n            anti_alias: false,\n            ..into_paint(fill.style)\n        };\n        paint.shader.transform(self.transform);\n\n        self.primitives.push(Primitive::Fill {\n            path,\n            paint,\n            rule: into_fill_rule(fill.rule),\n        });\n    }\n\n    fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {\n        let Some(path) = convert_path(path).and_then(|path| path.transform(self.transform)) else {\n            return;\n        };\n\n        let stroke = stroke.into();\n        let skia_stroke = into_stroke(&stroke);\n\n        let mut paint = into_paint(stroke.style);\n        paint.shader.transform(self.transform);\n\n        self.primitives.push(Primitive::Stroke {\n            path,\n            paint,\n            stroke: skia_stroke,\n        });\n    }\n\n    fn stroke_rectangle<'a>(&mut self, top_left: Point, size: Size, stroke: impl Into<Stroke<'a>>) {\n        self.stroke(&Path::rectangle(top_left, size), stroke);\n    }\n\n    fn fill_text(&mut self, text: impl Into<geometry::Text>) {\n        let text = text.into();\n\n        let (scale_x, scale_y) = self.transform.get_scale();\n\n        if !self.transform.has_skew() && scale_x == scale_y && scale_x > 0.0 && scale_y > 0.0 {\n            let (bounds, size, line_height) = if self.transform.is_identity() {\n                (\n                    Rectangle::new(text.position, Size::new(text.max_width, f32::INFINITY)),\n                    text.size,\n                    text.line_height,\n                )\n            } else {\n                let mut position = [tiny_skia::Point {\n                    x: text.position.x,\n                    y: text.position.y,\n                }];\n\n                self.transform.map_points(&mut position);\n\n                let size = text.size.0 * scale_y;\n\n                let line_height = match text.line_height {\n                    LineHeight::Absolute(size) => LineHeight::Absolute(Pixels(size.0 * scale_y)),\n                    LineHeight::Relative(factor) => LineHeight::Relative(factor),\n                };\n\n                (\n                    Rectangle {\n                        x: position[0].x,\n                        y: position[0].y,\n                        width: text.max_width * scale_x,\n                        height: f32::INFINITY,\n                    },\n                    size.into(),\n                    line_height,\n                )\n            };\n\n            // TODO: Honor layering!\n            self.text.push(Text::Cached {\n                content: text.content,\n                bounds,\n                color: text.color,\n                size,\n                line_height: line_height.to_absolute(size),\n                font: text.font,\n                align_x: text.align_x,\n                align_y: text.align_y,\n                shaping: text.shaping,\n                wrapping: text.wrapping,\n                ellipsis: text.ellipsis,\n                clip_bounds: Rectangle::with_size(Size::INFINITE),\n            });\n        } else {\n            text.draw_with(|path, color| self.fill(&path, color));\n        }\n    }\n\n    fn stroke_text<'a>(&mut self, text: impl Into<geometry::Text>, stroke: impl Into<Stroke<'a>>) {\n        let text = text.into();\n        let stroke = stroke.into();\n\n        text.draw_with(|path, _color| self.stroke(&path, stroke));\n    }\n\n    fn push_transform(&mut self) {\n        self.stack.push(self.transform);\n    }\n\n    fn pop_transform(&mut self) {\n        self.transform = self.stack.pop().expect(\"Pop transform\");\n    }\n\n    fn draft(&mut self, clip_bounds: Rectangle) -> Self {\n        Self::new(clip_bounds)\n    }\n\n    fn paste(&mut self, frame: Self) {\n        self.primitives.extend(frame.primitives);\n        self.text.extend(frame.text);\n        self.images.extend(frame.images);\n    }\n\n    fn translate(&mut self, translation: Vector) {\n        self.transform = self.transform.pre_translate(translation.x, translation.y);\n    }\n\n    fn rotate(&mut self, angle: impl Into<Radians>) {\n        self.transform = self.transform.pre_concat(tiny_skia::Transform::from_rotate(\n            angle.into().0.to_degrees(),\n        ));\n    }\n\n    fn scale(&mut self, scale: impl Into<f32>) {\n        let scale = scale.into();\n\n        self.scale_nonuniform(Vector { x: scale, y: scale });\n    }\n\n    fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {\n        let scale = scale.into();\n\n        self.transform = self.transform.pre_scale(scale.x, scale.y);\n    }\n\n    fn into_geometry(self) -> Geometry {\n        Geometry::Live {\n            primitives: self.primitives,\n            images: self.images,\n            text: self.text,\n            clip_bounds: self.clip_bounds,\n        }\n    }\n\n    fn draw_image(&mut self, bounds: Rectangle, image: impl Into<core::Image>) {\n        let mut image = image.into();\n\n        let (bounds, external_rotation) = transform_rectangle(bounds, self.transform);\n\n        image.rotation += external_rotation;\n\n        self.images.push(graphics::Image::Raster {\n            image,\n            bounds,\n            clip_bounds: self.clip_bounds,\n        });\n    }\n\n    fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {\n        let mut svg = svg.into();\n\n        let (bounds, external_rotation) = transform_rectangle(bounds, self.transform);\n\n        svg.rotation += external_rotation;\n\n        self.images.push(Image::Vector {\n            svg,\n            bounds,\n            clip_bounds: self.clip_bounds,\n        });\n    }\n}\n\nfn transform_rectangle(\n    rectangle: Rectangle,\n    transform: tiny_skia::Transform,\n) -> (Rectangle, Radians) {\n    let mut top_left = tiny_skia::Point {\n        x: rectangle.x,\n        y: rectangle.y,\n    };\n\n    let mut top_right = tiny_skia::Point {\n        x: rectangle.x + rectangle.width,\n        y: rectangle.y,\n    };\n\n    let mut bottom_left = tiny_skia::Point {\n        x: rectangle.x,\n        y: rectangle.y + rectangle.height,\n    };\n\n    transform.map_point(&mut top_left);\n    transform.map_point(&mut top_right);\n    transform.map_point(&mut bottom_left);\n\n    Rectangle::with_vertices(\n        Point::new(top_left.x, top_left.y),\n        Point::new(top_right.x, top_right.y),\n        Point::new(bottom_left.x, bottom_left.y),\n    )\n}\n\nfn convert_path(path: &Path) -> Option<tiny_skia::Path> {\n    use iced_graphics::geometry::path::lyon_path;\n\n    let mut builder = tiny_skia::PathBuilder::new();\n    let mut last_point = lyon_path::math::Point::default();\n\n    for event in path.raw() {\n        match event {\n            lyon_path::Event::Begin { at } => {\n                builder.move_to(at.x, at.y);\n\n                last_point = at;\n            }\n            lyon_path::Event::Line { from, to } => {\n                if last_point != from {\n                    builder.move_to(from.x, from.y);\n                }\n\n                builder.line_to(to.x, to.y);\n\n                last_point = to;\n            }\n            lyon_path::Event::Quadratic { from, ctrl, to } => {\n                if last_point != from {\n                    builder.move_to(from.x, from.y);\n                }\n\n                builder.quad_to(ctrl.x, ctrl.y, to.x, to.y);\n\n                last_point = to;\n            }\n            lyon_path::Event::Cubic {\n                from,\n                ctrl1,\n                ctrl2,\n                to,\n            } => {\n                if last_point != from {\n                    builder.move_to(from.x, from.y);\n                }\n\n                builder.cubic_to(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, to.x, to.y);\n\n                last_point = to;\n            }\n            lyon_path::Event::End { close, .. } => {\n                if close {\n                    builder.close();\n                }\n            }\n        }\n    }\n\n    let result = builder.finish();\n\n    #[cfg(debug_assertions)]\n    if result.is_none() {\n        log::warn!(\"Invalid path: {:?}\", path.raw());\n    }\n\n    result\n}\n\npub fn into_paint(style: Style) -> tiny_skia::Paint<'static> {\n    tiny_skia::Paint {\n        shader: match style {\n            Style::Solid(color) => tiny_skia::Shader::SolidColor(\n                tiny_skia::Color::from_rgba(color.b, color.g, color.r, color.a)\n                    .expect(\"Create color\"),\n            ),\n            Style::Gradient(gradient) => match gradient {\n                Gradient::Linear(linear) => {\n                    let stops: Vec<tiny_skia::GradientStop> = linear\n                        .stops\n                        .into_iter()\n                        .flatten()\n                        .map(|stop| {\n                            tiny_skia::GradientStop::new(\n                                stop.offset,\n                                tiny_skia::Color::from_rgba(\n                                    stop.color.b,\n                                    stop.color.g,\n                                    stop.color.r,\n                                    stop.color.a,\n                                )\n                                .expect(\"Create color\"),\n                            )\n                        })\n                        .collect();\n\n                    tiny_skia::LinearGradient::new(\n                        tiny_skia::Point {\n                            x: linear.start.x,\n                            y: linear.start.y,\n                        },\n                        tiny_skia::Point {\n                            x: linear.end.x,\n                            y: linear.end.y,\n                        },\n                        if stops.is_empty() {\n                            vec![tiny_skia::GradientStop::new(0.0, tiny_skia::Color::BLACK)]\n                        } else {\n                            stops\n                        },\n                        tiny_skia::SpreadMode::Pad,\n                        tiny_skia::Transform::identity(),\n                    )\n                    .expect(\"Create linear gradient\")\n                }\n            },\n        },\n        anti_alias: true,\n        ..Default::default()\n    }\n}\n\npub fn into_fill_rule(rule: fill::Rule) -> tiny_skia::FillRule {\n    match rule {\n        fill::Rule::EvenOdd => tiny_skia::FillRule::EvenOdd,\n        fill::Rule::NonZero => tiny_skia::FillRule::Winding,\n    }\n}\n\npub fn into_stroke(stroke: &Stroke<'_>) -> tiny_skia::Stroke {\n    tiny_skia::Stroke {\n        width: stroke.width,\n        line_cap: match stroke.line_cap {\n            stroke::LineCap::Butt => tiny_skia::LineCap::Butt,\n            stroke::LineCap::Square => tiny_skia::LineCap::Square,\n            stroke::LineCap::Round => tiny_skia::LineCap::Round,\n        },\n        line_join: match stroke.line_join {\n            stroke::LineJoin::Miter => tiny_skia::LineJoin::Miter,\n            stroke::LineJoin::Round => tiny_skia::LineJoin::Round,\n            stroke::LineJoin::Bevel => tiny_skia::LineJoin::Bevel,\n        },\n        dash: if stroke.line_dash.segments.is_empty() {\n            None\n        } else {\n            tiny_skia::StrokeDash::new(\n                stroke.line_dash.segments.into(),\n                stroke.line_dash.offset as f32,\n            )\n        },\n        ..Default::default()\n    }\n}\n"
  },
  {
    "path": "tiny_skia/src/layer.rs",
    "content": "use crate::Primitive;\nuse crate::core::renderer::Quad;\nuse crate::core::{self, Background, Color, Point, Rectangle, Svg, Transformation};\nuse crate::graphics::damage;\nuse crate::graphics::layer;\nuse crate::graphics::text::{Editor, Paragraph, Text};\nuse crate::graphics::{self, Image};\n\nuse std::sync::Arc;\n\npub type Stack = layer::Stack<Layer>;\n\n#[derive(Debug, Clone)]\npub struct Layer {\n    pub bounds: Rectangle,\n    pub quads: Vec<(Quad, Background)>,\n    pub primitives: Vec<Item<Primitive>>,\n    pub images: Vec<Image>,\n    pub text: Vec<Item<Text>>,\n}\n\nimpl Layer {\n    pub fn draw_quad(\n        &mut self,\n        mut quad: Quad,\n        background: Background,\n        transformation: Transformation,\n    ) {\n        quad.bounds = quad.bounds * transformation;\n        self.quads.push((quad, background));\n    }\n\n    pub fn draw_paragraph(\n        &mut self,\n        paragraph: &Paragraph,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let paragraph = Text::Paragraph {\n            paragraph: paragraph.downgrade(),\n            position,\n            color,\n            clip_bounds,\n            transformation,\n        };\n\n        self.text.push(Item::Live(paragraph));\n    }\n\n    pub fn draw_editor(\n        &mut self,\n        editor: &Editor,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let editor = Text::Editor {\n            editor: editor.downgrade(),\n            position,\n            color,\n            clip_bounds,\n            transformation,\n        };\n\n        self.text.push(Item::Live(editor));\n    }\n\n    pub fn draw_text(\n        &mut self,\n        text: core::Text,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let text = Text::Cached {\n            content: text.content,\n            bounds: Rectangle::new(position, text.bounds) * transformation,\n            color,\n            size: text.size * transformation.scale_factor(),\n            line_height: text.line_height.to_absolute(text.size) * transformation.scale_factor(),\n            font: text.font,\n            align_x: text.align_x,\n            align_y: text.align_y,\n            shaping: text.shaping,\n            wrapping: text.wrapping,\n            ellipsis: text.ellipsis,\n            clip_bounds: clip_bounds * transformation,\n        };\n\n        self.text.push(Item::Live(text));\n    }\n\n    pub fn draw_text_raw(&mut self, raw: graphics::text::Raw, transformation: Transformation) {\n        let raw = Text::Raw {\n            raw,\n            transformation,\n        };\n\n        self.text.push(Item::Live(raw));\n    }\n\n    pub fn draw_text_group(\n        &mut self,\n        text: Vec<Text>,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        self.text\n            .push(Item::Group(text, clip_bounds, transformation));\n    }\n\n    pub fn draw_text_cache(\n        &mut self,\n        text: Arc<[Text]>,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        self.text\n            .push(Item::Cached(text, clip_bounds, transformation));\n    }\n\n    pub fn draw_image(&mut self, image: Image, transformation: Transformation) {\n        match image {\n            Image::Raster {\n                image,\n                bounds,\n                clip_bounds,\n            } => {\n                self.draw_raster(image, bounds, clip_bounds, transformation);\n            }\n            Image::Vector {\n                svg,\n                bounds,\n                clip_bounds,\n            } => {\n                self.draw_svg(svg, bounds, clip_bounds, transformation);\n            }\n        }\n    }\n\n    pub fn draw_raster(\n        &mut self,\n        image: core::Image,\n        bounds: Rectangle,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let image = Image::Raster {\n            image: core::Image {\n                border_radius: image.border_radius * transformation.scale_factor(),\n                ..image\n            },\n            bounds: bounds * transformation,\n            clip_bounds: clip_bounds * transformation,\n        };\n\n        self.images.push(image);\n    }\n\n    pub fn draw_svg(\n        &mut self,\n        svg: Svg,\n        bounds: Rectangle,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let svg = Image::Vector {\n            svg,\n            bounds: bounds * transformation,\n            clip_bounds: clip_bounds * transformation,\n        };\n\n        self.images.push(svg);\n    }\n\n    pub fn draw_primitive_group(\n        &mut self,\n        primitives: Vec<Primitive>,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        self.primitives.push(Item::Group(\n            primitives,\n            clip_bounds * transformation,\n            transformation,\n        ));\n    }\n\n    pub fn draw_primitive_cache(\n        &mut self,\n        primitives: Arc<[Primitive]>,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        self.primitives.push(Item::Cached(\n            primitives,\n            clip_bounds * transformation,\n            transformation,\n        ));\n    }\n\n    pub fn damage(previous: &Self, current: &Self) -> Vec<Rectangle> {\n        if previous.bounds != current.bounds {\n            return vec![previous.bounds, current.bounds];\n        }\n\n        let layer_bounds = current.bounds.expand(1.0);\n\n        let mut damage = damage::list(\n            &previous.quads,\n            &current.quads,\n            |(quad, _)| {\n                let Some(bounds) = quad.bounds.expand(1.0).intersection(&layer_bounds) else {\n                    return vec![];\n                };\n\n                vec![if quad.shadow.color.a > 0.0 {\n                    bounds.expand(\n                        quad.shadow.offset.x.abs().max(quad.shadow.offset.y.abs())\n                            + quad.shadow.blur_radius,\n                    )\n                } else {\n                    bounds\n                }]\n            },\n            |(quad_a, background_a), (quad_b, background_b)| {\n                quad_a == quad_b && background_a == background_b\n            },\n        );\n\n        let text = damage::diff(\n            &previous.text,\n            &current.text,\n            |item| {\n                item.as_slice()\n                    .iter()\n                    .filter_map(Text::visible_bounds)\n                    .map(|bounds| bounds * item.transformation())\n                    .collect()\n            },\n            |text_a, text_b| {\n                damage::list(\n                    text_a.as_slice(),\n                    text_b.as_slice(),\n                    |text| {\n                        text.visible_bounds()\n                            .into_iter()\n                            .map(|bounds| bounds * text_a.transformation())\n                            .collect()\n                    },\n                    |text_a, text_b| text_a == text_b,\n                )\n            },\n        );\n\n        let primitives = damage::list(\n            &previous.primitives,\n            &current.primitives,\n            |item| match item {\n                Item::Live(primitive) => vec![primitive.visible_bounds()],\n                Item::Group(primitives, group_bounds, transformation) => primitives\n                    .as_slice()\n                    .iter()\n                    .map(Primitive::visible_bounds)\n                    .map(|bounds| bounds * *transformation)\n                    .filter_map(|bounds| bounds.intersection(group_bounds))\n                    .collect(),\n                Item::Cached(_primitives, bounds, _transformation) => {\n                    vec![*bounds]\n                }\n            },\n            |primitive_a, primitive_b| match (primitive_a, primitive_b) {\n                (\n                    Item::Cached(cache_a, bounds_a, transformation_a),\n                    Item::Cached(cache_b, bounds_b, transformation_b),\n                ) => {\n                    Arc::ptr_eq(cache_a, cache_b)\n                        && bounds_a == bounds_b\n                        && transformation_a == transformation_b\n                }\n                _ => false,\n            },\n        );\n\n        let images = damage::list(\n            &previous.images,\n            &current.images,\n            |image| vec![image.bounds().expand(1.0)],\n            Image::eq,\n        );\n\n        damage.extend(text);\n        damage.extend(primitives);\n        damage.extend(images);\n        damage\n    }\n}\n\nimpl Default for Layer {\n    fn default() -> Self {\n        Self {\n            bounds: Rectangle::INFINITE,\n            quads: Vec::new(),\n            primitives: Vec::new(),\n            text: Vec::new(),\n            images: Vec::new(),\n        }\n    }\n}\n\nimpl graphics::Layer for Layer {\n    fn with_bounds(bounds: Rectangle) -> Self {\n        Self {\n            bounds,\n            ..Self::default()\n        }\n    }\n\n    fn bounds(&self) -> Rectangle {\n        self.bounds\n    }\n\n    fn flush(&mut self) {}\n\n    fn resize(&mut self, bounds: Rectangle) {\n        self.bounds = bounds;\n    }\n\n    fn reset(&mut self) {\n        self.bounds = Rectangle::INFINITE;\n\n        self.quads.clear();\n        self.primitives.clear();\n        self.text.clear();\n        self.images.clear();\n    }\n\n    fn start(&self) -> usize {\n        if !self.quads.is_empty() {\n            return 1;\n        }\n\n        if !self.primitives.is_empty() {\n            return 2;\n        }\n\n        if !self.images.is_empty() {\n            return 3;\n        }\n\n        if !self.text.is_empty() {\n            return 4;\n        }\n\n        usize::MAX\n    }\n\n    fn end(&self) -> usize {\n        if !self.text.is_empty() {\n            return 4;\n        }\n\n        if !self.images.is_empty() {\n            return 3;\n        }\n\n        if !self.primitives.is_empty() {\n            return 2;\n        }\n\n        if !self.quads.is_empty() {\n            return 1;\n        }\n\n        0\n    }\n\n    fn merge(&mut self, layer: &mut Self) {\n        self.quads.append(&mut layer.quads);\n        self.primitives.append(&mut layer.primitives);\n        self.text.append(&mut layer.text);\n        self.images.append(&mut layer.images);\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum Item<T> {\n    Live(T),\n    Group(Vec<T>, Rectangle, Transformation),\n    Cached(Arc<[T]>, Rectangle, Transformation),\n}\n\nimpl<T> Item<T> {\n    pub fn transformation(&self) -> Transformation {\n        match self {\n            Item::Live(_) => Transformation::IDENTITY,\n            Item::Group(_, _, transformation) | Item::Cached(_, _, transformation) => {\n                *transformation\n            }\n        }\n    }\n\n    pub fn clip_bounds(&self) -> Rectangle {\n        match self {\n            Item::Live(_) => Rectangle::INFINITE,\n            Item::Group(_, clip_bounds, _) | Item::Cached(_, clip_bounds, _) => *clip_bounds,\n        }\n    }\n\n    pub fn as_slice(&self) -> &[T] {\n        match self {\n            Item::Live(item) => std::slice::from_ref(item),\n            Item::Group(group, _, _) => group.as_slice(),\n            Item::Cached(cache, _, _) => cache,\n        }\n    }\n}\n"
  },
  {
    "path": "tiny_skia/src/lib.rs",
    "content": "#![allow(missing_docs)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\npub mod window;\n\nmod engine;\nmod layer;\nmod primitive;\nmod text;\n\n#[cfg(feature = \"image\")]\nmod raster;\n\n#[cfg(feature = \"svg\")]\nmod vector;\n\n#[cfg(feature = \"geometry\")]\npub mod geometry;\n\nuse iced_debug as debug;\npub use iced_graphics as graphics;\npub use iced_graphics::core;\n\npub use layer::Layer;\npub use primitive::Primitive;\n\n#[cfg(feature = \"geometry\")]\npub use geometry::Geometry;\n\nuse crate::core::renderer;\nuse crate::core::{Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation};\nuse crate::engine::Engine;\nuse crate::graphics::Viewport;\nuse crate::graphics::compositor;\nuse crate::graphics::text::{Editor, Paragraph};\n\n/// A [`tiny-skia`] graphics renderer for [`iced`].\n///\n/// [`tiny-skia`]: https://github.com/RazrFalcon/tiny-skia\n/// [`iced`]: https://github.com/iced-rs/iced\n#[derive(Debug)]\npub struct Renderer {\n    settings: renderer::Settings,\n    layers: layer::Stack,\n    engine: Engine, // TODO: Shared engine\n}\n\nimpl Renderer {\n    pub fn new(settings: renderer::Settings) -> Self {\n        Self {\n            settings,\n            layers: layer::Stack::new(),\n            engine: Engine::new(),\n        }\n    }\n\n    pub fn layers(&mut self) -> &[Layer] {\n        self.layers.flush();\n        self.layers.as_slice()\n    }\n\n    pub fn draw(\n        &mut self,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        clip_mask: &mut tiny_skia::Mask,\n        viewport: &Viewport,\n        damage: &[Rectangle],\n        background_color: Color,\n    ) {\n        let scale_factor = viewport.scale_factor();\n        self.layers.flush();\n\n        for &damage_bounds in damage {\n            let damage_bounds = damage_bounds * scale_factor;\n\n            let path = tiny_skia::PathBuilder::from_rect(\n                tiny_skia::Rect::from_xywh(\n                    damage_bounds.x,\n                    damage_bounds.y,\n                    damage_bounds.width,\n                    damage_bounds.height,\n                )\n                .expect(\"Create damage rectangle\"),\n            );\n\n            pixels.fill_path(\n                &path,\n                &tiny_skia::Paint {\n                    shader: tiny_skia::Shader::SolidColor(engine::into_color(background_color)),\n                    anti_alias: false,\n                    blend_mode: tiny_skia::BlendMode::Source,\n                    ..Default::default()\n                },\n                tiny_skia::FillRule::default(),\n                tiny_skia::Transform::identity(),\n                None,\n            );\n\n            for layer in self.layers.iter() {\n                let Some(layer_bounds) = damage_bounds.intersection(&(layer.bounds * scale_factor))\n                else {\n                    continue;\n                };\n\n                engine::adjust_clip_mask(clip_mask, layer_bounds);\n\n                if !layer.quads.is_empty() {\n                    let render_span = debug::render(debug::Primitive::Quad);\n                    for (quad, background) in &layer.quads {\n                        self.engine.draw_quad(\n                            quad,\n                            background,\n                            Transformation::scale(scale_factor),\n                            pixels,\n                            clip_mask,\n                            layer_bounds,\n                        );\n                    }\n                    render_span.finish();\n                }\n\n                if !layer.primitives.is_empty() {\n                    let render_span = debug::render(debug::Primitive::Triangle);\n\n                    for group in &layer.primitives {\n                        let Some(group_bounds) =\n                            (group.clip_bounds() * scale_factor).intersection(&layer_bounds)\n                        else {\n                            continue;\n                        };\n\n                        engine::adjust_clip_mask(clip_mask, group_bounds);\n\n                        for primitive in group.as_slice() {\n                            self.engine.draw_primitive(\n                                primitive,\n                                Transformation::scale(scale_factor) * group.transformation(),\n                                pixels,\n                                clip_mask,\n                                group_bounds,\n                            );\n                        }\n\n                        engine::adjust_clip_mask(clip_mask, layer_bounds);\n                    }\n\n                    render_span.finish();\n                }\n\n                if !layer.images.is_empty() {\n                    let render_span = debug::render(debug::Primitive::Image);\n\n                    for image in &layer.images {\n                        self.engine.draw_image(\n                            image,\n                            Transformation::scale(scale_factor),\n                            pixels,\n                            clip_mask,\n                            layer_bounds,\n                        );\n                    }\n\n                    render_span.finish();\n                }\n\n                if !layer.text.is_empty() {\n                    let render_span = debug::render(debug::Primitive::Image);\n\n                    for group in &layer.text {\n                        for text in group.as_slice() {\n                            self.engine.draw_text(\n                                text,\n                                Transformation::scale(scale_factor) * group.transformation(),\n                                pixels,\n                                clip_mask,\n                                layer_bounds,\n                            );\n                        }\n                    }\n\n                    render_span.finish();\n                }\n            }\n        }\n\n        self.engine.trim();\n    }\n}\n\nimpl core::Renderer for Renderer {\n    fn start_layer(&mut self, bounds: Rectangle) {\n        self.layers.push_clip(bounds);\n    }\n\n    fn end_layer(&mut self) {\n        self.layers.pop_clip();\n    }\n\n    fn start_transformation(&mut self, transformation: Transformation) {\n        self.layers.push_transformation(transformation);\n    }\n\n    fn end_transformation(&mut self) {\n        self.layers.pop_transformation();\n    }\n\n    fn fill_quad(&mut self, quad: renderer::Quad, background: impl Into<Background>) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_quad(quad, background.into(), transformation);\n    }\n\n    fn allocate_image(\n        &mut self,\n        _handle: &core::image::Handle,\n        callback: impl FnOnce(Result<core::image::Allocation, core::image::Error>) + Send + 'static,\n    ) {\n        #[cfg(feature = \"image\")]\n        #[allow(unsafe_code)]\n        // TODO: Concurrency\n        callback(self.engine.raster_pipeline.load(_handle));\n\n        #[cfg(not(feature = \"image\"))]\n        callback(Err(core::image::Error::Unsupported));\n    }\n\n    fn hint(&mut self, _scale_factor: f32) {\n        // TODO: No hinting supported\n        // We'll replace `tiny-skia` with `vello_cpu` soon\n    }\n\n    fn scale_factor(&self) -> Option<f32> {\n        None\n    }\n\n    fn reset(&mut self, new_bounds: Rectangle) {\n        self.layers.reset(new_bounds);\n    }\n}\n\nimpl core::text::Renderer for Renderer {\n    type Font = Font;\n    type Paragraph = Paragraph;\n    type Editor = Editor;\n\n    const ICON_FONT: Font = Font::new(\"Iced-Icons\");\n    const CHECKMARK_ICON: char = '\\u{f00c}';\n    const ARROW_DOWN_ICON: char = '\\u{e800}';\n    const ICED_LOGO: char = '\\u{e801}';\n    const SCROLL_UP_ICON: char = '\\u{e802}';\n    const SCROLL_DOWN_ICON: char = '\\u{e803}';\n    const SCROLL_LEFT_ICON: char = '\\u{e804}';\n    const SCROLL_RIGHT_ICON: char = '\\u{e805}';\n\n    fn default_font(&self) -> Self::Font {\n        self.settings.default_font\n    }\n\n    fn default_size(&self) -> Pixels {\n        self.settings.default_text_size\n    }\n\n    fn fill_paragraph(\n        &mut self,\n        text: &Self::Paragraph,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        let (layer, transformation) = self.layers.current_mut();\n\n        layer.draw_paragraph(text, position, color, clip_bounds, transformation);\n    }\n\n    fn fill_editor(\n        &mut self,\n        editor: &Self::Editor,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_editor(editor, position, color, clip_bounds, transformation);\n    }\n\n    fn fill_text(\n        &mut self,\n        text: core::Text,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_text(text, position, color, clip_bounds, transformation);\n    }\n}\n\nimpl graphics::text::Renderer for Renderer {\n    fn fill_raw(&mut self, raw: graphics::text::Raw) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_text_raw(raw, transformation);\n    }\n}\n\n#[cfg(feature = \"geometry\")]\nimpl graphics::geometry::Renderer for Renderer {\n    type Geometry = Geometry;\n    type Frame = geometry::Frame;\n\n    fn new_frame(&self, bounds: Rectangle) -> Self::Frame {\n        geometry::Frame::new(bounds)\n    }\n\n    fn draw_geometry(&mut self, geometry: Self::Geometry) {\n        let (layer, transformation) = self.layers.current_mut();\n\n        match geometry {\n            Geometry::Live {\n                primitives,\n                images,\n                text,\n                clip_bounds,\n            } => {\n                layer.draw_primitive_group(primitives, clip_bounds, transformation);\n\n                for image in images {\n                    layer.draw_image(image, transformation);\n                }\n\n                layer.draw_text_group(text, clip_bounds, transformation);\n            }\n            Geometry::Cache(cache) => {\n                layer.draw_primitive_cache(cache.primitives, cache.clip_bounds, transformation);\n\n                for image in cache.images.iter() {\n                    layer.draw_image(image.clone(), transformation);\n                }\n\n                layer.draw_text_cache(cache.text, cache.clip_bounds, transformation);\n            }\n        }\n    }\n}\n\nimpl graphics::mesh::Renderer for Renderer {\n    fn draw_mesh(&mut self, _mesh: graphics::Mesh) {\n        log::warn!(\"iced_tiny_skia does not support drawing meshes\");\n    }\n\n    fn draw_mesh_cache(&mut self, _cache: iced_graphics::mesh::Cache) {\n        log::warn!(\"iced_tiny_skia does not support drawing meshes\");\n    }\n}\n\n#[cfg(feature = \"image\")]\nimpl core::image::Renderer for Renderer {\n    type Handle = core::image::Handle;\n\n    fn load_image(\n        &self,\n        handle: &Self::Handle,\n    ) -> Result<core::image::Allocation, core::image::Error> {\n        self.engine.raster_pipeline.load(handle)\n    }\n\n    fn measure_image(&self, handle: &Self::Handle) -> Option<crate::core::Size<u32>> {\n        self.engine.raster_pipeline.dimensions(handle)\n    }\n\n    fn draw_image(&mut self, image: core::Image, bounds: Rectangle, clip_bounds: Rectangle) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_raster(image, bounds, clip_bounds, transformation);\n    }\n}\n\n#[cfg(feature = \"svg\")]\nimpl core::svg::Renderer for Renderer {\n    fn measure_svg(&self, handle: &core::svg::Handle) -> crate::core::Size<u32> {\n        self.engine.vector_pipeline.viewport_dimensions(handle)\n    }\n\n    fn draw_svg(&mut self, svg: core::Svg, bounds: Rectangle, clip_bounds: Rectangle) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_svg(svg, bounds, clip_bounds, transformation);\n    }\n}\n\nimpl compositor::Default for Renderer {\n    type Compositor = window::Compositor;\n}\n\nimpl renderer::Headless for Renderer {\n    async fn new(settings: renderer::Settings, backend: Option<&str>) -> Option<Self> {\n        if backend.is_some_and(|backend| ![\"tiny-skia\", \"tiny_skia\"].contains(&backend)) {\n            return None;\n        }\n\n        Some(Self::new(settings))\n    }\n\n    fn name(&self) -> String {\n        \"tiny-skia\".to_owned()\n    }\n\n    fn screenshot(\n        &mut self,\n        size: Size<u32>,\n        scale_factor: f32,\n        background_color: Color,\n    ) -> Vec<u8> {\n        let viewport = Viewport::with_physical_size(size, scale_factor);\n\n        window::compositor::screenshot(self, &viewport, background_color)\n    }\n}\n"
  },
  {
    "path": "tiny_skia/src/primitive.rs",
    "content": "use crate::core::Rectangle;\n\n#[derive(Debug, Clone, PartialEq)]\npub enum Primitive {\n    /// A path filled with some paint.\n    Fill {\n        /// The path to fill.\n        path: tiny_skia::Path,\n        /// The paint to use.\n        paint: tiny_skia::Paint<'static>,\n        /// The fill rule to follow.\n        rule: tiny_skia::FillRule,\n    },\n    /// A path stroked with some paint.\n    Stroke {\n        /// The path to stroke.\n        path: tiny_skia::Path,\n        /// The paint to use.\n        paint: tiny_skia::Paint<'static>,\n        /// The stroke settings.\n        stroke: tiny_skia::Stroke,\n    },\n}\n\nimpl Primitive {\n    /// Returns the visible bounds of the [`Primitive`].\n    pub fn visible_bounds(&self) -> Rectangle {\n        let bounds = match self {\n            Primitive::Fill { path, .. } => path.bounds(),\n            Primitive::Stroke { path, .. } => path.bounds(),\n        };\n\n        Rectangle {\n            x: bounds.x(),\n            y: bounds.y(),\n            width: bounds.width(),\n            height: bounds.height(),\n        }\n    }\n}\n"
  },
  {
    "path": "tiny_skia/src/raster.rs",
    "content": "use crate::core::image as raster;\nuse crate::core::{Rectangle, Size};\nuse crate::graphics;\n\nuse rustc_hash::{FxHashMap, FxHashSet};\nuse std::cell::RefCell;\nuse std::collections::hash_map;\n\n#[derive(Debug)]\npub struct Pipeline {\n    cache: RefCell<Cache>,\n}\n\nimpl Pipeline {\n    pub fn new() -> Self {\n        Self {\n            cache: RefCell::new(Cache::default()),\n        }\n    }\n\n    pub fn load(&self, handle: &raster::Handle) -> Result<raster::Allocation, raster::Error> {\n        let mut cache = self.cache.borrow_mut();\n        let image = cache.allocate(handle)?;\n\n        #[allow(unsafe_code)]\n        Ok(unsafe { raster::allocate(handle, Size::new(image.width(), image.height())) })\n    }\n\n    pub fn dimensions(&self, handle: &raster::Handle) -> Option<Size<u32>> {\n        let mut cache = self.cache.borrow_mut();\n        let image = cache.allocate(handle).ok()?;\n\n        Some(Size::new(image.width(), image.height()))\n    }\n\n    pub fn draw(\n        &mut self,\n        handle: &raster::Handle,\n        filter_method: raster::FilterMethod,\n        bounds: Rectangle,\n        opacity: f32,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        transform: tiny_skia::Transform,\n        clip_mask: Option<&tiny_skia::Mask>,\n    ) {\n        let mut cache = self.cache.borrow_mut();\n\n        let Ok(image) = cache.allocate(handle) else {\n            return;\n        };\n\n        let width_scale = bounds.width / image.width() as f32;\n        let height_scale = bounds.height / image.height() as f32;\n\n        let transform = transform.pre_scale(width_scale, height_scale);\n\n        let quality = match filter_method {\n            raster::FilterMethod::Linear => tiny_skia::FilterQuality::Bilinear,\n            raster::FilterMethod::Nearest => tiny_skia::FilterQuality::Nearest,\n        };\n\n        pixels.draw_pixmap(\n            (bounds.x / width_scale) as i32,\n            (bounds.y / height_scale) as i32,\n            image,\n            &tiny_skia::PixmapPaint {\n                quality,\n                opacity,\n                ..Default::default()\n            },\n            transform,\n            clip_mask,\n        );\n    }\n\n    pub fn trim_cache(&mut self) {\n        self.cache.borrow_mut().trim();\n    }\n}\n\n#[derive(Debug, Default)]\nstruct Cache {\n    entries: FxHashMap<raster::Id, Option<Entry>>,\n    hits: FxHashSet<raster::Id>,\n}\n\nimpl Cache {\n    pub fn allocate(\n        &mut self,\n        handle: &raster::Handle,\n    ) -> Result<tiny_skia::PixmapRef<'_>, raster::Error> {\n        let id = handle.id();\n\n        if let hash_map::Entry::Vacant(entry) = self.entries.entry(id) {\n            let image = match graphics::image::load(handle) {\n                Ok(image) => image,\n                Err(error) => {\n                    let _ = entry.insert(None);\n\n                    return Err(error);\n                }\n            };\n\n            if image.width() == 0 || image.height() == 0 {\n                return Err(raster::Error::Empty);\n            }\n\n            let mut buffer = vec![0u32; image.width() as usize * image.height() as usize];\n\n            for (i, pixel) in image.pixels().enumerate() {\n                let [r, g, b, a] = pixel.0;\n\n                buffer[i] = bytemuck::cast(tiny_skia::ColorU8::from_rgba(b, g, r, a).premultiply());\n            }\n\n            let _ = entry.insert(Some(Entry {\n                width: image.width(),\n                height: image.height(),\n                pixels: buffer,\n            }));\n        }\n\n        let _ = self.hits.insert(id);\n\n        Ok(self\n            .entries\n            .get(&id)\n            .unwrap()\n            .as_ref()\n            .map(|entry| {\n                tiny_skia::PixmapRef::from_bytes(\n                    bytemuck::cast_slice(&entry.pixels),\n                    entry.width,\n                    entry.height,\n                )\n                .expect(\"Build pixmap from image bytes\")\n            })\n            .expect(\"Image should be allocated\"))\n    }\n\n    fn trim(&mut self) {\n        self.entries.retain(|key, _| self.hits.contains(key));\n        self.hits.clear();\n    }\n}\n\n#[derive(Debug)]\nstruct Entry {\n    width: u32,\n    height: u32,\n    pixels: Vec<u32>,\n}\n"
  },
  {
    "path": "tiny_skia/src/text.rs",
    "content": "use crate::core::alignment;\nuse crate::core::text::{Alignment, Ellipsis, Shaping, Wrapping};\nuse crate::core::{Color, Font, Pixels, Point, Rectangle, Transformation};\nuse crate::graphics::text::cache::{self, Cache};\nuse crate::graphics::text::editor;\nuse crate::graphics::text::font_system;\nuse crate::graphics::text::paragraph;\n\nuse rustc_hash::{FxHashMap, FxHashSet};\nuse std::borrow::Cow;\nuse std::cell::RefCell;\nuse std::collections::hash_map;\n\n#[derive(Debug)]\npub struct Pipeline {\n    glyph_cache: GlyphCache,\n    cache: RefCell<Cache>,\n}\n\nimpl Pipeline {\n    pub fn new() -> Self {\n        Pipeline {\n            glyph_cache: GlyphCache::new(),\n            cache: RefCell::new(Cache::new()),\n        }\n    }\n\n    // TODO: Shared engine\n    #[allow(dead_code)]\n    pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) {\n        font_system()\n            .write()\n            .expect(\"Write font system\")\n            .load_font(bytes);\n\n        self.cache = RefCell::new(Cache::new());\n    }\n\n    pub fn draw_paragraph(\n        &mut self,\n        paragraph: &paragraph::Weak,\n        position: Point,\n        color: Color,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        clip_mask: Option<&tiny_skia::Mask>,\n        transformation: Transformation,\n    ) {\n        let Some(paragraph) = paragraph.upgrade() else {\n            return;\n        };\n\n        let mut font_system = font_system().write().expect(\"Write font system\");\n\n        draw(\n            font_system.raw(),\n            &mut self.glyph_cache,\n            paragraph.buffer(),\n            position,\n            color,\n            pixels,\n            clip_mask,\n            transformation,\n        );\n    }\n\n    pub fn draw_editor(\n        &mut self,\n        editor: &editor::Weak,\n        position: Point,\n        color: Color,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        clip_mask: Option<&tiny_skia::Mask>,\n        transformation: Transformation,\n    ) {\n        let Some(editor) = editor.upgrade() else {\n            return;\n        };\n\n        let mut font_system = font_system().write().expect(\"Write font system\");\n\n        draw(\n            font_system.raw(),\n            &mut self.glyph_cache,\n            editor.buffer(),\n            position,\n            color,\n            pixels,\n            clip_mask,\n            transformation,\n        );\n    }\n\n    pub fn draw_cached(\n        &mut self,\n        content: &str,\n        bounds: Rectangle,\n        color: Color,\n        size: Pixels,\n        line_height: Pixels,\n        font: Font,\n        align_x: Alignment,\n        align_y: alignment::Vertical,\n        shaping: Shaping,\n        wrapping: Wrapping,\n        ellipsis: Ellipsis,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        clip_mask: Option<&tiny_skia::Mask>,\n        transformation: Transformation,\n    ) {\n        let line_height = f32::from(line_height);\n\n        let mut font_system = font_system().write().expect(\"Write font system\");\n        let font_system = font_system.raw();\n\n        let key = cache::Key {\n            bounds: bounds.size(),\n            content,\n            font,\n            size: size.into(),\n            line_height,\n            shaping,\n            wrapping,\n            ellipsis,\n            align_x,\n        };\n\n        let (_, entry) = self.cache.get_mut().allocate(font_system, key);\n\n        let width = entry.min_bounds.width;\n        let height = entry.min_bounds.height;\n\n        let x = match align_x {\n            Alignment::Default | Alignment::Left | Alignment::Justified => bounds.x,\n            Alignment::Center => bounds.x - width / 2.0,\n            Alignment::Right => bounds.x - width,\n        };\n\n        let y = match align_y {\n            alignment::Vertical::Top => bounds.y,\n            alignment::Vertical::Center => bounds.y - height / 2.0,\n            alignment::Vertical::Bottom => bounds.y - height,\n        };\n\n        draw(\n            font_system,\n            &mut self.glyph_cache,\n            &entry.buffer,\n            Point::new(x, y),\n            color,\n            pixels,\n            clip_mask,\n            transformation,\n        );\n    }\n\n    pub fn draw_raw(\n        &mut self,\n        buffer: &cosmic_text::Buffer,\n        position: Point,\n        color: Color,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        clip_mask: Option<&tiny_skia::Mask>,\n        transformation: Transformation,\n    ) {\n        let mut font_system = font_system().write().expect(\"Write font system\");\n\n        draw(\n            font_system.raw(),\n            &mut self.glyph_cache,\n            buffer,\n            position,\n            color,\n            pixels,\n            clip_mask,\n            transformation,\n        );\n    }\n\n    pub fn trim_cache(&mut self) {\n        self.cache.get_mut().trim();\n        self.glyph_cache.trim();\n    }\n}\n\nfn draw(\n    font_system: &mut cosmic_text::FontSystem,\n    glyph_cache: &mut GlyphCache,\n    buffer: &cosmic_text::Buffer,\n    position: Point,\n    color: Color,\n    pixels: &mut tiny_skia::PixmapMut<'_>,\n    clip_mask: Option<&tiny_skia::Mask>,\n    transformation: Transformation,\n) {\n    let position = position * transformation;\n\n    let mut swash = cosmic_text::SwashCache::new();\n\n    for run in buffer.layout_runs() {\n        for glyph in run.glyphs {\n            let physical_glyph =\n                glyph.physical((position.x, position.y), transformation.scale_factor());\n\n            if let Some((buffer, placement)) = glyph_cache.allocate(\n                physical_glyph.cache_key,\n                glyph.color_opt.map(from_color).unwrap_or(color),\n                font_system,\n                &mut swash,\n            ) {\n                let pixmap =\n                    tiny_skia::PixmapRef::from_bytes(buffer, placement.width, placement.height)\n                        .expect(\"Create glyph pixel map\");\n\n                let opacity =\n                    color.a * glyph.color_opt.map(|c| c.a() as f32 / 255.0).unwrap_or(1.0);\n\n                pixels.draw_pixmap(\n                    physical_glyph.x + placement.left,\n                    physical_glyph.y - placement.top\n                        + (run.line_y * transformation.scale_factor()).round() as i32,\n                    pixmap,\n                    &tiny_skia::PixmapPaint {\n                        opacity,\n                        ..tiny_skia::PixmapPaint::default()\n                    },\n                    tiny_skia::Transform::identity(),\n                    clip_mask,\n                );\n            }\n        }\n    }\n}\n\nfn from_color(color: cosmic_text::Color) -> Color {\n    let [r, g, b, a] = color.as_rgba();\n\n    Color::from_rgba8(r, g, b, a as f32 / 255.0)\n}\n\n#[derive(Debug, Clone, Default)]\nstruct GlyphCache {\n    entries: FxHashMap<(cosmic_text::CacheKey, [u8; 3]), (Vec<u32>, cosmic_text::Placement)>,\n    recently_used: FxHashSet<(cosmic_text::CacheKey, [u8; 3])>,\n    trim_count: usize,\n}\n\nimpl GlyphCache {\n    const TRIM_INTERVAL: usize = 300;\n    const CAPACITY_LIMIT: usize = 16 * 1024;\n\n    fn new() -> Self {\n        GlyphCache::default()\n    }\n\n    fn allocate(\n        &mut self,\n        cache_key: cosmic_text::CacheKey,\n        color: Color,\n        font_system: &mut cosmic_text::FontSystem,\n        swash: &mut cosmic_text::SwashCache,\n    ) -> Option<(&[u8], cosmic_text::Placement)> {\n        let [r, g, b, _a] = color.into_rgba8();\n        let key = (cache_key, [r, g, b]);\n\n        if let hash_map::Entry::Vacant(entry) = self.entries.entry(key) {\n            // TODO: Outline support\n            let image = swash.get_image_uncached(font_system, cache_key)?;\n\n            let glyph_size = image.placement.width as usize * image.placement.height as usize;\n\n            if glyph_size == 0 {\n                return None;\n            }\n\n            let mut buffer = vec![0u32; glyph_size];\n\n            match image.content {\n                cosmic_text::SwashContent::Mask => {\n                    let mut i = 0;\n\n                    // TODO: Blend alpha\n\n                    for _y in 0..image.placement.height {\n                        for _x in 0..image.placement.width {\n                            buffer[i] = bytemuck::cast(\n                                tiny_skia::ColorU8::from_rgba(b, g, r, image.data[i]).premultiply(),\n                            );\n\n                            i += 1;\n                        }\n                    }\n                }\n                cosmic_text::SwashContent::Color => {\n                    let mut i = 0;\n\n                    for _y in 0..image.placement.height {\n                        for _x in 0..image.placement.width {\n                            // TODO: Blend alpha\n                            buffer[i >> 2] = bytemuck::cast(\n                                tiny_skia::ColorU8::from_rgba(\n                                    image.data[i + 2],\n                                    image.data[i + 1],\n                                    image.data[i],\n                                    image.data[i + 3],\n                                )\n                                .premultiply(),\n                            );\n\n                            i += 4;\n                        }\n                    }\n                }\n                cosmic_text::SwashContent::SubpixelMask => {\n                    // TODO\n                }\n            }\n\n            let _ = entry.insert((buffer, image.placement));\n        }\n\n        let _ = self.recently_used.insert(key);\n\n        self.entries\n            .get(&key)\n            .map(|(buffer, placement)| (bytemuck::cast_slice(buffer.as_slice()), *placement))\n    }\n\n    pub fn trim(&mut self) {\n        if self.trim_count > Self::TRIM_INTERVAL || self.recently_used.len() >= Self::CAPACITY_LIMIT\n        {\n            self.entries\n                .retain(|key, _| self.recently_used.contains(key));\n\n            self.recently_used.clear();\n\n            self.entries.shrink_to(Self::CAPACITY_LIMIT);\n            self.recently_used.shrink_to(Self::CAPACITY_LIMIT);\n\n            self.trim_count = 0;\n        } else {\n            self.trim_count += 1;\n        }\n    }\n}\n"
  },
  {
    "path": "tiny_skia/src/vector.rs",
    "content": "use crate::core::svg::{Data, Handle};\nuse crate::core::{Color, Rectangle, Size};\n\nuse resvg::usvg;\nuse rustc_hash::{FxHashMap, FxHashSet};\nuse tiny_skia::Transform;\n\nuse std::cell::RefCell;\nuse std::collections::hash_map;\nuse std::fs;\nuse std::panic;\nuse std::sync::Arc;\n\n#[derive(Debug)]\npub struct Pipeline {\n    cache: RefCell<Cache>,\n}\n\nimpl Pipeline {\n    pub fn new() -> Self {\n        Self {\n            cache: RefCell::new(Cache::default()),\n        }\n    }\n\n    pub fn viewport_dimensions(&self, handle: &Handle) -> Size<u32> {\n        self.cache\n            .borrow_mut()\n            .viewport_dimensions(handle)\n            .unwrap_or(Size::new(0, 0))\n    }\n\n    pub fn draw(\n        &mut self,\n        handle: &Handle,\n        color: Option<Color>,\n        bounds: Rectangle,\n        opacity: f32,\n        pixels: &mut tiny_skia::PixmapMut<'_>,\n        transform: Transform,\n        clip_mask: Option<&tiny_skia::Mask>,\n    ) {\n        if let Some(image) = self.cache.borrow_mut().draw(\n            handle,\n            color,\n            Size::new(\n                (bounds.width * transform.sx) as u32,\n                (bounds.height * transform.sy) as u32,\n            ),\n        ) {\n            pixels.draw_pixmap(\n                (bounds.x * transform.sx) as i32,\n                (bounds.y * transform.sy) as i32,\n                image,\n                &tiny_skia::PixmapPaint {\n                    opacity,\n                    ..tiny_skia::PixmapPaint::default()\n                },\n                Transform::default(),\n                clip_mask,\n            );\n        }\n    }\n\n    pub fn trim_cache(&mut self) {\n        self.cache.borrow_mut().trim();\n    }\n}\n\n#[derive(Default)]\nstruct Cache {\n    trees: FxHashMap<u64, Option<resvg::usvg::Tree>>,\n    tree_hits: FxHashSet<u64>,\n    rasters: FxHashMap<RasterKey, tiny_skia::Pixmap>,\n    raster_hits: FxHashSet<RasterKey>,\n    fontdb: Option<Arc<usvg::fontdb::Database>>,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\nstruct RasterKey {\n    id: u64,\n    color: Option<[u8; 4]>,\n    size: Size<u32>,\n}\n\nimpl Cache {\n    fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> {\n        let id = handle.id();\n\n        // TODO: Reuse `cosmic-text` font database\n        if self.fontdb.is_none() {\n            let mut fontdb = usvg::fontdb::Database::new();\n            fontdb.load_system_fonts();\n\n            self.fontdb = Some(Arc::new(fontdb));\n        }\n\n        let options = usvg::Options {\n            fontdb: self\n                .fontdb\n                .as_ref()\n                .expect(\"fontdb must be initialized\")\n                .clone(),\n            ..usvg::Options::default()\n        };\n\n        if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) {\n            let svg = match handle.data() {\n                Data::Path(path) => fs::read_to_string(path)\n                    .ok()\n                    .and_then(|contents| usvg::Tree::from_str(&contents, &options).ok()),\n                Data::Bytes(bytes) => usvg::Tree::from_data(bytes, &options).ok(),\n            };\n\n            let _ = entry.insert(svg);\n        }\n\n        let _ = self.tree_hits.insert(id);\n        self.trees.get(&id).unwrap().as_ref()\n    }\n\n    fn viewport_dimensions(&mut self, handle: &Handle) -> Option<Size<u32>> {\n        let tree = self.load(handle)?;\n        let size = tree.size();\n\n        Some(Size::new(size.width() as u32, size.height() as u32))\n    }\n\n    fn draw(\n        &mut self,\n        handle: &Handle,\n        color: Option<Color>,\n        size: Size<u32>,\n    ) -> Option<tiny_skia::PixmapRef<'_>> {\n        if size.width == 0 || size.height == 0 {\n            return None;\n        }\n\n        let key = RasterKey {\n            id: handle.id(),\n            color: color.map(Color::into_rgba8),\n            size,\n        };\n\n        #[allow(clippy::map_entry)]\n        if !self.rasters.contains_key(&key) {\n            let tree = self.load(handle)?;\n\n            let mut image = tiny_skia::Pixmap::new(size.width, size.height)?;\n\n            let tree_size = tree.size().to_int_size();\n\n            let target_size = if size.width > size.height {\n                tree_size.scale_to_width(size.width)\n            } else {\n                tree_size.scale_to_height(size.height)\n            };\n\n            let transform = if let Some(target_size) = target_size {\n                let tree_size = tree_size.to_size();\n                let target_size = target_size.to_size();\n\n                tiny_skia::Transform::from_scale(\n                    target_size.width() / tree_size.width(),\n                    target_size.height() / tree_size.height(),\n                )\n            } else {\n                tiny_skia::Transform::default()\n            };\n\n            // SVG rendering can panic on malformed or complex vectors.\n            // We catch panics to prevent crashes and continue gracefully.\n            let render = panic::catch_unwind(panic::AssertUnwindSafe(|| {\n                resvg::render(tree, transform, &mut image.as_mut());\n            }));\n\n            if let Err(error) = render {\n                log::warn!(\"SVG rendering for {handle:?} panicked: {error:?}\");\n            }\n\n            if let Some([r, g, b, _]) = key.color {\n                // Apply color filter\n                for pixel in bytemuck::cast_slice_mut::<u8, u32>(image.data_mut()) {\n                    *pixel = bytemuck::cast(\n                        tiny_skia::ColorU8::from_rgba(b, g, r, (*pixel >> 24) as u8).premultiply(),\n                    );\n                }\n            } else {\n                // Swap R and B channels for `softbuffer` presentation\n                for pixel in bytemuck::cast_slice_mut::<u8, u32>(image.data_mut()) {\n                    *pixel = *pixel & 0xFF00_FF00\n                        | ((0x0000_00FF & *pixel) << 16)\n                        | ((0x00FF_0000 & *pixel) >> 16);\n                }\n            }\n\n            let _ = self.rasters.insert(key, image);\n        }\n\n        let _ = self.raster_hits.insert(key);\n        self.rasters.get(&key).map(tiny_skia::Pixmap::as_ref)\n    }\n\n    fn trim(&mut self) {\n        self.trees.retain(|key, _| self.tree_hits.contains(key));\n        self.rasters.retain(|key, _| self.raster_hits.contains(key));\n\n        self.tree_hits.clear();\n        self.raster_hits.clear();\n    }\n}\n\nimpl std::fmt::Debug for Cache {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Cache\")\n            .field(\"tree_hits\", &self.tree_hits)\n            .field(\"rasters\", &self.rasters)\n            .field(\"raster_hits\", &self.raster_hits)\n            .finish_non_exhaustive()\n    }\n}\n"
  },
  {
    "path": "tiny_skia/src/window/compositor.rs",
    "content": "use crate::core::renderer;\nuse crate::core::{Color, Rectangle, Size};\nuse crate::graphics::compositor::{self, Information};\nuse crate::graphics::damage;\nuse crate::graphics::error::{self, Error};\nuse crate::graphics::{Shell, Viewport};\nuse crate::{Layer, Renderer};\n\nuse std::collections::VecDeque;\nuse std::num::NonZeroU32;\n\npub struct Compositor {\n    context: softbuffer::Context<Box<dyn compositor::Display>>,\n}\n\npub struct Surface {\n    window: softbuffer::Surface<Box<dyn compositor::Display>, Box<dyn compositor::Window>>,\n    clip_mask: tiny_skia::Mask,\n    frames: VecDeque<Frame>,\n    max_age: u8,\n}\n\n#[derive(Clone)]\nstruct Frame {\n    background: Color,\n    layers: Vec<Layer>,\n}\n\nimpl crate::graphics::Compositor for Compositor {\n    type Renderer = Renderer;\n    type Surface = Surface;\n\n    async fn with_backend(\n        _settings: compositor::Settings,\n        display: impl compositor::Display,\n        _compatible_window: impl compositor::Window,\n        _shell: Shell,\n        backend: Option<&str>,\n    ) -> Result<Self, Error> {\n        match backend {\n            None | Some(\"tiny-skia\") | Some(\"tiny_skia\") => Ok(new(display)),\n            Some(backend) => Err(Error::GraphicsAdapterNotFound {\n                backend: \"tiny-skia\",\n                reason: error::Reason::DidNotMatch {\n                    preferred_backend: backend.to_owned(),\n                },\n            }),\n        }\n    }\n\n    fn create_renderer(&self, settings: renderer::Settings) -> Self::Renderer {\n        Renderer::new(settings)\n    }\n\n    fn create_surface<W: compositor::Window + Clone>(\n        &mut self,\n        window: W,\n        width: u32,\n        height: u32,\n    ) -> Self::Surface {\n        let window = softbuffer::Surface::new(&self.context, Box::new(window.clone()) as _)\n            .expect(\"Create softbuffer surface for window\");\n\n        let mut surface = Surface {\n            window,\n            clip_mask: tiny_skia::Mask::new(1, 1).expect(\"Create clip mask\"),\n            frames: VecDeque::new(),\n            max_age: 0,\n        };\n\n        if width > 0 && height > 0 {\n            self.configure_surface(&mut surface, width, height);\n        }\n\n        surface\n    }\n\n    fn configure_surface(&mut self, surface: &mut Self::Surface, width: u32, height: u32) {\n        surface\n            .window\n            .resize(\n                NonZeroU32::new(width).expect(\"Non-zero width\"),\n                NonZeroU32::new(height).expect(\"Non-zero height\"),\n            )\n            .expect(\"Resize surface\");\n\n        surface.clip_mask = tiny_skia::Mask::new(width, height).expect(\"Create clip mask\");\n        surface.frames.clear();\n    }\n\n    fn information(&self) -> Information {\n        Information {\n            adapter: String::from(\"CPU\"),\n            backend: String::from(\"tiny-skia\"),\n        }\n    }\n\n    fn present(\n        &mut self,\n        renderer: &mut Self::Renderer,\n        surface: &mut Self::Surface,\n        viewport: &Viewport,\n        background_color: Color,\n        on_pre_present: impl FnOnce(),\n    ) -> Result<(), compositor::SurfaceError> {\n        present(\n            renderer,\n            surface,\n            viewport,\n            background_color,\n            on_pre_present,\n        )\n    }\n\n    fn screenshot(\n        &mut self,\n        renderer: &mut Self::Renderer,\n        viewport: &Viewport,\n        background_color: Color,\n    ) -> Vec<u8> {\n        screenshot(renderer, viewport, background_color)\n    }\n}\n\npub fn new(display: impl compositor::Display) -> Compositor {\n    #[allow(unsafe_code)]\n    let context =\n        softbuffer::Context::new(Box::new(display) as _).expect(\"Create softbuffer context\");\n\n    Compositor { context }\n}\n\npub fn present(\n    renderer: &mut Renderer,\n    surface: &mut Surface,\n    viewport: &Viewport,\n    background: Color,\n    on_pre_present: impl FnOnce(),\n) -> Result<(), compositor::SurfaceError> {\n    let physical_size = viewport.physical_size();\n\n    let mut buffer = surface\n        .window\n        .buffer_mut()\n        .map_err(|_| compositor::SurfaceError::Lost)?;\n\n    let last_frame = {\n        let age = buffer.age();\n\n        surface.max_age = surface.max_age.max(age);\n        surface.frames.truncate(surface.max_age as usize);\n\n        if age > 0 {\n            surface.frames.get(age as usize - 1)\n        } else {\n            None\n        }\n    };\n\n    let damage = last_frame\n        .and_then(|last_frame| {\n            (last_frame.background == background).then(|| {\n                damage::diff(\n                    &last_frame.layers,\n                    renderer.layers(),\n                    |layer| vec![layer.bounds],\n                    Layer::damage,\n                )\n            })\n        })\n        .unwrap_or_else(|| vec![Rectangle::with_size(viewport.logical_size())]);\n\n    if damage.is_empty() {\n        if let Some(last_frame) = last_frame {\n            surface.frames.push_front(last_frame.clone());\n        }\n    } else {\n        surface.frames.push_front(Frame {\n            background,\n            layers: renderer.layers().to_vec(),\n        });\n\n        let damage = damage::group(damage, Rectangle::with_size(viewport.logical_size()));\n\n        let mut pixels = tiny_skia::PixmapMut::from_bytes(\n            bytemuck::cast_slice_mut(&mut buffer),\n            physical_size.width,\n            physical_size.height,\n        )\n        .expect(\"Create pixel map\");\n\n        renderer.draw(\n            &mut pixels,\n            &mut surface.clip_mask,\n            viewport,\n            &damage,\n            background,\n        );\n    }\n\n    on_pre_present();\n    buffer.present().map_err(|_| compositor::SurfaceError::Lost)\n}\n\npub fn screenshot(\n    renderer: &mut Renderer,\n    viewport: &Viewport,\n    background_color: Color,\n) -> Vec<u8> {\n    let size = viewport.physical_size();\n\n    let mut offscreen_buffer: Vec<u32> = vec![0; size.width as usize * size.height as usize];\n\n    let mut clip_mask = tiny_skia::Mask::new(size.width, size.height).expect(\"Create clip mask\");\n\n    renderer.draw(\n        &mut tiny_skia::PixmapMut::from_bytes(\n            bytemuck::cast_slice_mut(&mut offscreen_buffer),\n            size.width,\n            size.height,\n        )\n        .expect(\"Create offscreen pixel map\"),\n        &mut clip_mask,\n        viewport,\n        &[Rectangle::with_size(Size::new(\n            size.width as f32,\n            size.height as f32,\n        ))],\n        background_color,\n    );\n\n    offscreen_buffer.iter().fold(\n        Vec::with_capacity(offscreen_buffer.len() * 4),\n        |mut acc, pixel| {\n            const A_MASK: u32 = 0xFF_00_00_00;\n            const R_MASK: u32 = 0x00_FF_00_00;\n            const G_MASK: u32 = 0x00_00_FF_00;\n            const B_MASK: u32 = 0x00_00_00_FF;\n\n            let a = ((A_MASK & pixel) >> 24) as u8;\n            let r = ((R_MASK & pixel) >> 16) as u8;\n            let g = ((G_MASK & pixel) >> 8) as u8;\n            let b = (B_MASK & pixel) as u8;\n\n            acc.extend([r, g, b, a]);\n            acc\n        },\n    )\n}\n"
  },
  {
    "path": "tiny_skia/src/window.rs",
    "content": "pub mod compositor;\n\npub use compositor::{Compositor, Surface};\n"
  },
  {
    "path": "wgpu/Cargo.toml",
    "content": "[package]\nname = \"iced_wgpu\"\ndescription = \"A renderer for iced on top of wgpu\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--cfg\", \"docsrs\"]\nall-features = true\n\n[features]\ndefault = [\"wgpu/default\"]\ngeometry = [\"iced_graphics/geometry\", \"lyon\"]\nimage = [\"iced_graphics/image\"]\nsvg = [\"iced_graphics/svg\", \"resvg/text\"]\nweb-colors = [\"iced_graphics/web-colors\"]\nwebgl = [\"wgpu/webgl\"]\nstrict-assertions = []\n\n[dependencies]\niced_debug.workspace = true\niced_graphics.workspace = true\n\nbitflags.workspace = true\nbytemuck.workspace = true\nfutures.workspace = true\nglam.workspace = true\ncryoglyph.workspace = true\nguillotiere.workspace = true\nlog.workspace = true\nrustc-hash.workspace = true\nthiserror.workspace = true\nwgpu.workspace = true\n\nlyon.workspace = true\nlyon.optional = true\n\nresvg.workspace = true\nresvg.optional = true\n"
  },
  {
    "path": "wgpu/README.md",
    "content": "# `iced_wgpu`\n[![Documentation](https://docs.rs/iced_wgpu/badge.svg)][documentation]\n[![Crates.io](https://img.shields.io/crates/v/iced_wgpu.svg)](https://crates.io/crates/iced_wgpu)\n[![License](https://img.shields.io/crates/l/iced_wgpu.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)\n[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)\n\n`iced_wgpu` is a [`wgpu`] renderer for [`iced_runtime`]. For now, it is the default renderer of Iced on [native platforms].\n\n[`wgpu`] supports most modern graphics backends: Vulkan, Metal, DX12, OpenGL, and WebGPU.\n\n<p align=\"center\">\n  <img alt=\"The native target\" src=\"../docs/graphs/native.png\" width=\"80%\">\n</p>\n\n[documentation]: https://docs.rs/iced_wgpu\n[`iced_runtime`]: ../runtime\n[`wgpu`]: https://github.com/gfx-rs/wgpu\n[native platforms]: https://github.com/gfx-rs/wgpu#supported-platforms\n[WebGPU API]: https://gpuweb.github.io/gpuweb/\n[`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph\n"
  },
  {
    "path": "wgpu/src/buffer.rs",
    "content": "use std::marker::PhantomData;\nuse std::num::NonZeroU64;\nuse std::ops::RangeBounds;\n\npub const MAX_WRITE_SIZE: usize = 100 * 1024;\n\nconst MAX_WRITE_SIZE_U64: NonZeroU64 =\n    NonZeroU64::new(MAX_WRITE_SIZE as u64).expect(\"MAX_WRITE_SIZE must be non-zero\");\n\n#[derive(Debug)]\npub struct Buffer<T> {\n    label: &'static str,\n    size: u64,\n    usage: wgpu::BufferUsages,\n    pub(crate) raw: wgpu::Buffer,\n    type_: PhantomData<T>,\n}\n\nimpl<T: bytemuck::Pod> Buffer<T> {\n    pub fn new(\n        device: &wgpu::Device,\n        label: &'static str,\n        amount: usize,\n        usage: wgpu::BufferUsages,\n    ) -> Self {\n        let size = next_copy_size::<T>(amount);\n\n        let raw = device.create_buffer(&wgpu::BufferDescriptor {\n            label: Some(label),\n            size,\n            usage,\n            mapped_at_creation: false,\n        });\n\n        Self {\n            label,\n            size,\n            usage,\n            raw,\n            type_: PhantomData,\n        }\n    }\n\n    pub fn resize(&mut self, device: &wgpu::Device, new_count: usize) -> bool {\n        let new_size = next_copy_size::<T>(new_count);\n\n        if self.size < new_size {\n            self.raw = device.create_buffer(&wgpu::BufferDescriptor {\n                label: Some(self.label),\n                size: new_size,\n                usage: self.usage,\n                mapped_at_creation: false,\n            });\n\n            self.size = new_size;\n\n            true\n        } else {\n            false\n        }\n    }\n\n    /// Returns the size of the written bytes.\n    pub fn write(\n        &mut self,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        offset: usize,\n        contents: &[T],\n    ) -> usize {\n        let bytes: &[u8] = bytemuck::cast_slice(contents);\n        let mut bytes_written = 0;\n\n        // Split write into multiple chunks if necessary\n        while bytes_written + MAX_WRITE_SIZE < bytes.len() {\n            belt.write_buffer(\n                encoder,\n                &self.raw,\n                (offset + bytes_written) as u64,\n                MAX_WRITE_SIZE_U64,\n            )\n            .copy_from_slice(&bytes[bytes_written..bytes_written + MAX_WRITE_SIZE]);\n\n            bytes_written += MAX_WRITE_SIZE;\n        }\n\n        // There will always be some bytes left, since the previous\n        // loop guarantees `bytes_written < bytes.len()`\n        let bytes_left = ((bytes.len() - bytes_written) as u64)\n            .try_into()\n            .expect(\"non-empty write\");\n\n        // Write them\n        belt.write_buffer(\n            encoder,\n            &self.raw,\n            (offset + bytes_written) as u64,\n            bytes_left,\n        )\n        .copy_from_slice(&bytes[bytes_written..]);\n\n        bytes.len()\n    }\n\n    pub fn slice(&self, bounds: impl RangeBounds<wgpu::BufferAddress>) -> wgpu::BufferSlice<'_> {\n        self.raw.slice(bounds)\n    }\n\n    pub fn range(&self, start: usize, end: usize) -> wgpu::BufferSlice<'_> {\n        self.slice(\n            start as u64 * std::mem::size_of::<T>() as u64\n                ..end as u64 * std::mem::size_of::<T>() as u64,\n        )\n    }\n}\n\nfn next_copy_size<T>(amount: usize) -> u64 {\n    let align_mask = wgpu::COPY_BUFFER_ALIGNMENT - 1;\n\n    (((std::mem::size_of::<T>() * amount).next_power_of_two() as u64 + align_mask) & !align_mask)\n        .max(wgpu::COPY_BUFFER_ALIGNMENT)\n}\n"
  },
  {
    "path": "wgpu/src/color.rs",
    "content": "use std::borrow::Cow;\n\nuse wgpu::util::DeviceExt;\n\npub fn convert(\n    device: &wgpu::Device,\n    encoder: &mut wgpu::CommandEncoder,\n    source: wgpu::Texture,\n    format: wgpu::TextureFormat,\n) -> wgpu::Texture {\n    if source.format() == format {\n        return source;\n    }\n\n    let sampler = device.create_sampler(&wgpu::SamplerDescriptor {\n        label: Some(\"iced_wgpu.offscreen.sampler\"),\n        ..wgpu::SamplerDescriptor::default()\n    });\n\n    #[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]\n    #[repr(C)]\n    struct Ratio {\n        u: f32,\n        v: f32,\n        // Padding field for 16-byte alignment.\n        // See https://docs.rs/wgpu/latest/wgpu/struct.DownlevelFlags.html#associatedconstant.BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED\n        _padding: [f32; 2],\n    }\n\n    let ratio = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {\n        label: Some(\"iced-wgpu::triangle::msaa ratio\"),\n        contents: bytemuck::bytes_of(&Ratio {\n            u: 1.0,\n            v: 1.0,\n            _padding: [0.0; 2],\n        }),\n        usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,\n    });\n\n    let constant_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n        label: Some(\"iced_wgpu.offscreen.blit.sampler_layout\"),\n        entries: &[\n            wgpu::BindGroupLayoutEntry {\n                binding: 0,\n                visibility: wgpu::ShaderStages::FRAGMENT,\n                ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),\n                count: None,\n            },\n            wgpu::BindGroupLayoutEntry {\n                binding: 1,\n                visibility: wgpu::ShaderStages::VERTEX,\n                ty: wgpu::BindingType::Buffer {\n                    ty: wgpu::BufferBindingType::Uniform,\n                    has_dynamic_offset: false,\n                    min_binding_size: None,\n                },\n                count: None,\n            },\n        ],\n    });\n\n    let constant_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n        label: Some(\"iced_wgpu.offscreen.sampler.bind_group\"),\n        layout: &constant_layout,\n        entries: &[\n            wgpu::BindGroupEntry {\n                binding: 0,\n                resource: wgpu::BindingResource::Sampler(&sampler),\n            },\n            wgpu::BindGroupEntry {\n                binding: 1,\n                resource: ratio.as_entire_binding(),\n            },\n        ],\n    });\n\n    let texture_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n        label: Some(\"iced_wgpu.offscreen.blit.texture_layout\"),\n        entries: &[wgpu::BindGroupLayoutEntry {\n            binding: 0,\n            visibility: wgpu::ShaderStages::FRAGMENT,\n            ty: wgpu::BindingType::Texture {\n                sample_type: wgpu::TextureSampleType::Float { filterable: false },\n                view_dimension: wgpu::TextureViewDimension::D2,\n                multisampled: false,\n            },\n            count: None,\n        }],\n    });\n\n    let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n        label: Some(\"iced_wgpu.offscreen.blit.pipeline_layout\"),\n        bind_group_layouts: &[&constant_layout, &texture_layout],\n        immediate_size: 0,\n    });\n\n    let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n        label: Some(\"iced_wgpu.offscreen.blit.shader\"),\n        source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!(\"shader/blit.wgsl\"))),\n    });\n\n    let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n        label: Some(\"iced_wgpu.offscreen.blit.pipeline\"),\n        layout: Some(&pipeline_layout),\n        vertex: wgpu::VertexState {\n            module: &shader,\n            entry_point: Some(\"vs_main\"),\n            buffers: &[],\n            compilation_options: wgpu::PipelineCompilationOptions::default(),\n        },\n        fragment: Some(wgpu::FragmentState {\n            module: &shader,\n            entry_point: Some(\"fs_main\"),\n            targets: &[Some(wgpu::ColorTargetState {\n                format,\n                blend: Some(wgpu::BlendState {\n                    color: wgpu::BlendComponent {\n                        src_factor: wgpu::BlendFactor::SrcAlpha,\n                        dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,\n                        operation: wgpu::BlendOperation::Add,\n                    },\n                    alpha: wgpu::BlendComponent {\n                        src_factor: wgpu::BlendFactor::One,\n                        dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,\n                        operation: wgpu::BlendOperation::Add,\n                    },\n                }),\n                write_mask: wgpu::ColorWrites::ALL,\n            })],\n            compilation_options: wgpu::PipelineCompilationOptions::default(),\n        }),\n        primitive: wgpu::PrimitiveState {\n            topology: wgpu::PrimitiveTopology::TriangleList,\n            front_face: wgpu::FrontFace::Cw,\n            ..wgpu::PrimitiveState::default()\n        },\n        depth_stencil: None,\n        multisample: wgpu::MultisampleState::default(),\n        multiview_mask: None,\n        cache: None,\n    });\n\n    let texture = device.create_texture(&wgpu::TextureDescriptor {\n        label: Some(\"iced_wgpu.offscreen.conversion.source_texture\"),\n        size: source.size(),\n        mip_level_count: 1,\n        sample_count: 1,\n        dimension: wgpu::TextureDimension::D2,\n        format,\n        usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,\n        view_formats: &[],\n    });\n\n    let view = &texture.create_view(&wgpu::TextureViewDescriptor::default());\n\n    let texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n        label: Some(\"iced_wgpu.offscreen.blit.texture_bind_group\"),\n        layout: &texture_layout,\n        entries: &[wgpu::BindGroupEntry {\n            binding: 0,\n            resource: wgpu::BindingResource::TextureView(\n                &source.create_view(&wgpu::TextureViewDescriptor::default()),\n            ),\n        }],\n    });\n\n    let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n        label: Some(\"iced_wgpu.offscreen.blit.render_pass\"),\n        color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n            view,\n            depth_slice: None,\n            resolve_target: None,\n            ops: wgpu::Operations {\n                load: wgpu::LoadOp::Load,\n                store: wgpu::StoreOp::Store,\n            },\n        })],\n        depth_stencil_attachment: None,\n        timestamp_writes: None,\n        occlusion_query_set: None,\n        multiview_mask: None,\n    });\n\n    pass.set_pipeline(&pipeline);\n    pass.set_bind_group(0, &constant_bind_group, &[]);\n    pass.set_bind_group(1, &texture_bind_group, &[]);\n    pass.draw(0..6, 0..1);\n\n    texture\n}\n"
  },
  {
    "path": "wgpu/src/engine.rs",
    "content": "use crate::graphics::{Antialiasing, Shell};\nuse crate::primitive;\nuse crate::quad;\nuse crate::text;\nuse crate::triangle;\n\nuse std::sync::{Arc, RwLock};\n\n#[derive(Clone)]\npub struct Engine {\n    pub(crate) device: wgpu::Device,\n    pub(crate) queue: wgpu::Queue,\n    pub(crate) format: wgpu::TextureFormat,\n\n    pub(crate) quad_pipeline: quad::Pipeline,\n    pub(crate) text_pipeline: text::Pipeline,\n    pub(crate) triangle_pipeline: triangle::Pipeline,\n    #[cfg(any(feature = \"image\", feature = \"svg\"))]\n    pub(crate) image_pipeline: crate::image::Pipeline,\n    pub(crate) primitive_storage: Arc<RwLock<primitive::Storage>>,\n    _shell: Shell,\n}\n\nimpl Engine {\n    pub fn new(\n        _adapter: &wgpu::Adapter,\n        device: wgpu::Device,\n        queue: wgpu::Queue,\n        format: wgpu::TextureFormat,\n        antialiasing: Option<Antialiasing>, // TODO: Initialize AA pipelines lazily\n        shell: Shell,\n    ) -> Self {\n        Self {\n            format,\n\n            quad_pipeline: quad::Pipeline::new(&device, format),\n            text_pipeline: text::Pipeline::new(&device, &queue, format),\n            triangle_pipeline: triangle::Pipeline::new(&device, format, antialiasing),\n\n            #[cfg(any(feature = \"image\", feature = \"svg\"))]\n            image_pipeline: {\n                let backend = _adapter.get_info().backend;\n\n                crate::image::Pipeline::new(&device, format, backend)\n            },\n\n            primitive_storage: Arc::new(RwLock::new(primitive::Storage::default())),\n\n            device,\n            queue,\n            _shell: shell,\n        }\n    }\n\n    #[cfg(any(feature = \"image\", feature = \"svg\"))]\n    pub fn create_image_cache(&self) -> crate::image::Cache {\n        self.image_pipeline\n            .create_cache(&self.device, &self.queue, &self._shell)\n    }\n\n    pub fn trim(&mut self) {\n        self.text_pipeline.trim();\n\n        self.primitive_storage\n            .write()\n            .expect(\"primitive storage should be writable\")\n            .trim();\n    }\n}\n"
  },
  {
    "path": "wgpu/src/geometry.rs",
    "content": "//! Build and draw geometry.\nuse crate::core::text::LineHeight;\nuse crate::core::{self, Pixels, Point, Radians, Rectangle, Size, Svg, Transformation, Vector};\nuse crate::graphics::cache::{self, Cached};\nuse crate::graphics::color;\nuse crate::graphics::geometry::fill::{self, Fill};\nuse crate::graphics::geometry::{self, LineCap, LineDash, LineJoin, Path, Stroke, Style};\nuse crate::graphics::gradient::{self, Gradient};\nuse crate::graphics::mesh::{self, Mesh};\nuse crate::graphics::{Image, Text};\nuse crate::text;\n\nuse lyon::geom::euclid;\nuse lyon::tessellation;\n\nuse std::borrow::Cow;\nuse std::sync::Arc;\n\n#[derive(Debug)]\npub enum Geometry {\n    Live {\n        meshes: Vec<Mesh>,\n        images: Vec<Image>,\n        text: Vec<Text>,\n    },\n    Cached(Cache),\n}\n\n#[derive(Debug, Clone, Default)]\npub struct Cache {\n    pub meshes: Option<mesh::Cache>,\n    pub images: Option<Arc<[Image]>>,\n    pub text: Option<text::Cache>,\n}\n\nimpl Cached for Geometry {\n    type Cache = Cache;\n\n    fn load(cache: &Self::Cache) -> Self {\n        Geometry::Cached(cache.clone())\n    }\n\n    fn cache(self, group: cache::Group, previous: Option<Self::Cache>) -> Self::Cache {\n        match self {\n            Self::Live {\n                meshes,\n                images,\n                text,\n            } => {\n                let images = if images.is_empty() {\n                    None\n                } else {\n                    Some(Arc::from(images))\n                };\n\n                let meshes = Arc::from(meshes);\n\n                if let Some(mut previous) = previous {\n                    if let Some(cache) = &mut previous.meshes {\n                        cache.update(meshes);\n                    } else {\n                        previous.meshes = if meshes.is_empty() {\n                            None\n                        } else {\n                            Some(mesh::Cache::new(meshes))\n                        };\n                    }\n\n                    if let Some(cache) = &mut previous.text {\n                        cache.update(text);\n                    } else {\n                        previous.text = text::Cache::new(group, text);\n                    }\n\n                    previous.images = images;\n\n                    previous\n                } else {\n                    Cache {\n                        meshes: if meshes.is_empty() {\n                            None\n                        } else {\n                            Some(mesh::Cache::new(meshes))\n                        },\n                        images,\n                        text: text::Cache::new(group, text),\n                    }\n                }\n            }\n            Self::Cached(cache) => cache,\n        }\n    }\n}\n\n/// A frame for drawing some geometry.\npub struct Frame {\n    clip_bounds: Rectangle,\n    buffers: BufferStack,\n    meshes: Vec<Mesh>,\n    images: Vec<Image>,\n    text: Vec<Text>,\n    transforms: Transforms,\n    fill_tessellator: tessellation::FillTessellator,\n    stroke_tessellator: tessellation::StrokeTessellator,\n}\n\nimpl Frame {\n    /// Creates a new [`Frame`] with the given clip bounds.\n    pub fn new(bounds: Rectangle) -> Frame {\n        Frame {\n            clip_bounds: bounds,\n            buffers: BufferStack::new(),\n            meshes: Vec::new(),\n            images: Vec::new(),\n            text: Vec::new(),\n            transforms: Transforms {\n                previous: Vec::new(),\n                current: Transform(lyon::math::Transform::identity()),\n            },\n            fill_tessellator: tessellation::FillTessellator::new(),\n            stroke_tessellator: tessellation::StrokeTessellator::new(),\n        }\n    }\n}\n\nimpl geometry::frame::Backend for Frame {\n    type Geometry = Geometry;\n\n    #[inline]\n    fn width(&self) -> f32 {\n        self.clip_bounds.width\n    }\n\n    #[inline]\n    fn height(&self) -> f32 {\n        self.clip_bounds.height\n    }\n\n    #[inline]\n    fn size(&self) -> Size {\n        self.clip_bounds.size()\n    }\n\n    #[inline]\n    fn center(&self) -> Point {\n        Point::new(self.clip_bounds.width / 2.0, self.clip_bounds.height / 2.0)\n    }\n\n    fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {\n        let Fill { style, rule } = fill.into();\n\n        let mut buffer = self\n            .buffers\n            .get_fill(&self.transforms.current.transform_style(style));\n\n        let options = tessellation::FillOptions::default().with_fill_rule(into_fill_rule(rule));\n\n        if self.transforms.current.is_identity() {\n            self.fill_tessellator\n                .tessellate_path(path.raw(), &options, buffer.as_mut())\n        } else {\n            let path = path.transform(&self.transforms.current.0);\n\n            self.fill_tessellator\n                .tessellate_path(path.raw(), &options, buffer.as_mut())\n        }\n        .expect(\"Tessellate path.\");\n    }\n\n    fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>) {\n        let Fill { style, rule } = fill.into();\n\n        let mut buffer = self\n            .buffers\n            .get_fill(&self.transforms.current.transform_style(style));\n\n        let top_left = self\n            .transforms\n            .current\n            .0\n            .transform_point(lyon::math::Point::new(top_left.x, top_left.y));\n\n        let size = self\n            .transforms\n            .current\n            .0\n            .transform_vector(lyon::math::Vector::new(size.width, size.height));\n\n        let options = tessellation::FillOptions::default().with_fill_rule(into_fill_rule(rule));\n\n        self.fill_tessellator\n            .tessellate_rectangle(\n                &lyon::math::Box2D::new(top_left, top_left + size),\n                &options,\n                buffer.as_mut(),\n            )\n            .expect(\"Fill rectangle\");\n    }\n\n    fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {\n        let stroke = stroke.into();\n\n        let mut buffer = self\n            .buffers\n            .get_stroke(&self.transforms.current.transform_style(stroke.style));\n\n        let mut options = tessellation::StrokeOptions::default();\n        options.line_width = stroke.width;\n        options.start_cap = into_line_cap(stroke.line_cap);\n        options.end_cap = into_line_cap(stroke.line_cap);\n        options.line_join = into_line_join(stroke.line_join);\n\n        let path = if stroke.line_dash.segments.is_empty() {\n            Cow::Borrowed(path)\n        } else {\n            Cow::Owned(dashed(path, stroke.line_dash))\n        };\n\n        if self.transforms.current.is_identity() {\n            self.stroke_tessellator\n                .tessellate_path(path.raw(), &options, buffer.as_mut())\n        } else {\n            let path = path.transform(&self.transforms.current.0);\n\n            self.stroke_tessellator\n                .tessellate_path(path.raw(), &options, buffer.as_mut())\n        }\n        .expect(\"Stroke path\");\n    }\n\n    fn stroke_rectangle<'a>(&mut self, top_left: Point, size: Size, stroke: impl Into<Stroke<'a>>) {\n        let stroke = stroke.into();\n\n        let mut buffer = self\n            .buffers\n            .get_stroke(&self.transforms.current.transform_style(stroke.style));\n\n        let top_left = self\n            .transforms\n            .current\n            .0\n            .transform_point(lyon::math::Point::new(top_left.x, top_left.y));\n\n        let size = self\n            .transforms\n            .current\n            .0\n            .transform_vector(lyon::math::Vector::new(size.width, size.height));\n\n        let mut options = tessellation::StrokeOptions::default();\n        options.line_width = stroke.width;\n        options.start_cap = into_line_cap(stroke.line_cap);\n        options.end_cap = into_line_cap(stroke.line_cap);\n        options.line_join = into_line_join(stroke.line_join);\n\n        self.stroke_tessellator\n            .tessellate_rectangle(\n                &lyon::math::Box2D::new(top_left, top_left + size),\n                &options,\n                buffer.as_mut(),\n            )\n            .expect(\"Stroke rectangle\");\n    }\n\n    fn stroke_text<'a>(&mut self, text: impl Into<geometry::Text>, stroke: impl Into<Stroke<'a>>) {\n        let text = text.into();\n        let stroke = stroke.into();\n\n        text.draw_with(|glyph, _color| self.stroke(&glyph, stroke));\n    }\n\n    fn fill_text(&mut self, text: impl Into<geometry::Text>) {\n        let text = text.into();\n\n        let (scale_x, scale_y) = self.transforms.current.scale();\n\n        if self.transforms.current.is_scale_translation()\n            && scale_x == scale_y\n            && scale_x > 0.0\n            && scale_y > 0.0\n        {\n            let (bounds, size, line_height) = if self.transforms.current.is_identity() {\n                (\n                    Rectangle::new(text.position, Size::new(text.max_width, f32::INFINITY)),\n                    text.size,\n                    text.line_height,\n                )\n            } else {\n                let position = self.transforms.current.transform_point(text.position);\n\n                let size = Pixels(text.size.0 * scale_y);\n\n                let line_height = match text.line_height {\n                    LineHeight::Absolute(size) => LineHeight::Absolute(Pixels(size.0 * scale_y)),\n                    LineHeight::Relative(factor) => LineHeight::Relative(factor),\n                };\n\n                (\n                    Rectangle::new(position, Size::new(text.max_width, f32::INFINITY)),\n                    size,\n                    line_height,\n                )\n            };\n\n            self.text.push(Text::Cached {\n                content: text.content,\n                bounds,\n                color: text.color,\n                size,\n                line_height: line_height.to_absolute(size),\n                font: text.font,\n                align_x: text.align_x,\n                align_y: text.align_y,\n                shaping: text.shaping,\n                wrapping: text.wrapping,\n                ellipsis: text.ellipsis,\n                clip_bounds: self.clip_bounds,\n            });\n        } else {\n            text.draw_with(|path, color| self.fill(&path, color));\n        }\n    }\n\n    #[inline]\n    fn translate(&mut self, translation: Vector) {\n        self.transforms.current.0 = self\n            .transforms\n            .current\n            .0\n            .pre_translate(lyon::math::Vector::new(translation.x, translation.y));\n    }\n\n    #[inline]\n    fn rotate(&mut self, angle: impl Into<Radians>) {\n        self.transforms.current.0 = self\n            .transforms\n            .current\n            .0\n            .pre_rotate(lyon::math::Angle::radians(angle.into().0));\n    }\n\n    #[inline]\n    fn scale(&mut self, scale: impl Into<f32>) {\n        let scale = scale.into();\n\n        self.scale_nonuniform(Vector { x: scale, y: scale });\n    }\n\n    #[inline]\n    fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {\n        let scale = scale.into();\n\n        self.transforms.current.0 = self.transforms.current.0.pre_scale(scale.x, scale.y);\n    }\n\n    fn push_transform(&mut self) {\n        self.transforms.previous.push(self.transforms.current);\n    }\n\n    fn pop_transform(&mut self) {\n        self.transforms.current = self.transforms.previous.pop().unwrap();\n    }\n\n    fn draft(&mut self, clip_bounds: Rectangle) -> Frame {\n        Frame::new(clip_bounds)\n    }\n\n    fn paste(&mut self, frame: Frame) {\n        self.meshes.extend(frame.meshes);\n        self.meshes\n            .extend(frame.buffers.into_meshes(frame.clip_bounds));\n\n        self.images.extend(frame.images);\n        self.text.extend(frame.text);\n    }\n\n    fn into_geometry(mut self) -> Self::Geometry {\n        self.meshes\n            .extend(self.buffers.into_meshes(self.clip_bounds));\n\n        Geometry::Live {\n            meshes: self.meshes,\n            images: self.images,\n            text: self.text,\n        }\n    }\n\n    fn draw_image(&mut self, bounds: Rectangle, image: impl Into<core::Image>) {\n        let mut image = image.into();\n\n        let (bounds, external_rotation) = self.transforms.current.transform_rectangle(bounds);\n\n        image.rotation += external_rotation;\n        image.border_radius = image.border_radius * self.transforms.current.scale().0;\n\n        self.images.push(Image::Raster {\n            image,\n            bounds,\n            clip_bounds: self.clip_bounds,\n        });\n    }\n\n    fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {\n        let mut svg = svg.into();\n\n        let (bounds, external_rotation) = self.transforms.current.transform_rectangle(bounds);\n\n        svg.rotation += external_rotation;\n\n        self.images.push(Image::Vector {\n            svg,\n            bounds,\n            clip_bounds: self.clip_bounds,\n        });\n    }\n}\n\nenum Buffer {\n    Solid(tessellation::VertexBuffers<mesh::SolidVertex2D, u32>),\n    Gradient(tessellation::VertexBuffers<mesh::GradientVertex2D, u32>),\n}\n\nstruct BufferStack {\n    stack: Vec<Buffer>,\n}\n\nimpl BufferStack {\n    fn new() -> Self {\n        Self { stack: Vec::new() }\n    }\n\n    fn get_mut(&mut self, style: &Style) -> &mut Buffer {\n        match style {\n            Style::Solid(_) => match self.stack.last() {\n                Some(Buffer::Solid(_)) => {}\n                _ => {\n                    self.stack\n                        .push(Buffer::Solid(tessellation::VertexBuffers::new()));\n                }\n            },\n            Style::Gradient(_) => match self.stack.last() {\n                Some(Buffer::Gradient(_)) => {}\n                _ => {\n                    self.stack\n                        .push(Buffer::Gradient(tessellation::VertexBuffers::new()));\n                }\n            },\n        }\n\n        self.stack.last_mut().unwrap()\n    }\n\n    fn get_fill<'a>(\n        &'a mut self,\n        style: &Style,\n    ) -> Box<dyn tessellation::FillGeometryBuilder + 'a> {\n        match (style, self.get_mut(style)) {\n            (Style::Solid(color), Buffer::Solid(buffer)) => {\n                Box::new(tessellation::BuffersBuilder::new(\n                    buffer,\n                    TriangleVertex2DBuilder(color::pack(*color)),\n                ))\n            }\n            (Style::Gradient(gradient), Buffer::Gradient(buffer)) => {\n                Box::new(tessellation::BuffersBuilder::new(\n                    buffer,\n                    GradientVertex2DBuilder {\n                        gradient: gradient.pack(),\n                    },\n                ))\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    fn get_stroke<'a>(\n        &'a mut self,\n        style: &Style,\n    ) -> Box<dyn tessellation::StrokeGeometryBuilder + 'a> {\n        match (style, self.get_mut(style)) {\n            (Style::Solid(color), Buffer::Solid(buffer)) => {\n                Box::new(tessellation::BuffersBuilder::new(\n                    buffer,\n                    TriangleVertex2DBuilder(color::pack(*color)),\n                ))\n            }\n            (Style::Gradient(gradient), Buffer::Gradient(buffer)) => {\n                Box::new(tessellation::BuffersBuilder::new(\n                    buffer,\n                    GradientVertex2DBuilder {\n                        gradient: gradient.pack(),\n                    },\n                ))\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    fn into_meshes(self, clip_bounds: Rectangle) -> impl Iterator<Item = Mesh> {\n        self.stack\n            .into_iter()\n            .filter_map(move |buffer| match buffer {\n                Buffer::Solid(buffer) if !buffer.indices.is_empty() => Some(Mesh::Solid {\n                    buffers: mesh::Indexed {\n                        vertices: buffer.vertices,\n                        indices: buffer.indices,\n                    },\n                    clip_bounds,\n                    transformation: Transformation::IDENTITY,\n                }),\n                Buffer::Gradient(buffer) if !buffer.indices.is_empty() => Some(Mesh::Gradient {\n                    buffers: mesh::Indexed {\n                        vertices: buffer.vertices,\n                        indices: buffer.indices,\n                    },\n                    clip_bounds,\n                    transformation: Transformation::IDENTITY,\n                }),\n                _ => None,\n            })\n    }\n}\n\n#[derive(Debug)]\nstruct Transforms {\n    previous: Vec<Transform>,\n    current: Transform,\n}\n\n#[derive(Debug, Clone, Copy)]\nstruct Transform(lyon::math::Transform);\n\nimpl Transform {\n    fn is_identity(&self) -> bool {\n        self.0 == lyon::math::Transform::identity()\n    }\n\n    fn is_scale_translation(&self) -> bool {\n        self.0.m12.abs() < 2.0 * f32::EPSILON && self.0.m21.abs() < 2.0 * f32::EPSILON\n    }\n\n    fn scale(&self) -> (f32, f32) {\n        (self.0.m11, self.0.m22)\n    }\n\n    fn transform_point(&self, point: Point) -> Point {\n        let transformed = self\n            .0\n            .transform_point(euclid::Point2D::new(point.x, point.y));\n\n        Point {\n            x: transformed.x,\n            y: transformed.y,\n        }\n    }\n\n    fn transform_style(&self, style: Style) -> Style {\n        match style {\n            Style::Solid(color) => Style::Solid(color),\n            Style::Gradient(gradient) => Style::Gradient(self.transform_gradient(gradient)),\n        }\n    }\n\n    fn transform_gradient(&self, mut gradient: Gradient) -> Gradient {\n        match &mut gradient {\n            Gradient::Linear(linear) => {\n                linear.start = self.transform_point(linear.start);\n                linear.end = self.transform_point(linear.end);\n            }\n        }\n\n        gradient\n    }\n\n    fn transform_rectangle(&self, rectangle: Rectangle) -> (Rectangle, Radians) {\n        let top_left = self.transform_point(rectangle.position());\n        let top_right =\n            self.transform_point(rectangle.position() + Vector::new(rectangle.width, 0.0));\n        let bottom_left =\n            self.transform_point(rectangle.position() + Vector::new(0.0, rectangle.height));\n\n        Rectangle::with_vertices(top_left, top_right, bottom_left)\n    }\n}\nstruct GradientVertex2DBuilder {\n    gradient: gradient::Packed,\n}\n\nimpl tessellation::FillVertexConstructor<mesh::GradientVertex2D> for GradientVertex2DBuilder {\n    fn new_vertex(&mut self, vertex: tessellation::FillVertex<'_>) -> mesh::GradientVertex2D {\n        let position = vertex.position();\n\n        mesh::GradientVertex2D {\n            position: [position.x, position.y],\n            gradient: self.gradient,\n        }\n    }\n}\n\nimpl tessellation::StrokeVertexConstructor<mesh::GradientVertex2D> for GradientVertex2DBuilder {\n    fn new_vertex(&mut self, vertex: tessellation::StrokeVertex<'_, '_>) -> mesh::GradientVertex2D {\n        let position = vertex.position();\n\n        mesh::GradientVertex2D {\n            position: [position.x, position.y],\n            gradient: self.gradient,\n        }\n    }\n}\n\nstruct TriangleVertex2DBuilder(color::Packed);\n\nimpl tessellation::FillVertexConstructor<mesh::SolidVertex2D> for TriangleVertex2DBuilder {\n    fn new_vertex(&mut self, vertex: tessellation::FillVertex<'_>) -> mesh::SolidVertex2D {\n        let position = vertex.position();\n\n        mesh::SolidVertex2D {\n            position: [position.x, position.y],\n            color: self.0,\n        }\n    }\n}\n\nimpl tessellation::StrokeVertexConstructor<mesh::SolidVertex2D> for TriangleVertex2DBuilder {\n    fn new_vertex(&mut self, vertex: tessellation::StrokeVertex<'_, '_>) -> mesh::SolidVertex2D {\n        let position = vertex.position();\n\n        mesh::SolidVertex2D {\n            position: [position.x, position.y],\n            color: self.0,\n        }\n    }\n}\n\nfn into_line_join(line_join: LineJoin) -> lyon::tessellation::LineJoin {\n    match line_join {\n        LineJoin::Miter => lyon::tessellation::LineJoin::Miter,\n        LineJoin::Round => lyon::tessellation::LineJoin::Round,\n        LineJoin::Bevel => lyon::tessellation::LineJoin::Bevel,\n    }\n}\n\nfn into_line_cap(line_cap: LineCap) -> lyon::tessellation::LineCap {\n    match line_cap {\n        LineCap::Butt => lyon::tessellation::LineCap::Butt,\n        LineCap::Square => lyon::tessellation::LineCap::Square,\n        LineCap::Round => lyon::tessellation::LineCap::Round,\n    }\n}\n\nfn into_fill_rule(rule: fill::Rule) -> lyon::tessellation::FillRule {\n    match rule {\n        fill::Rule::NonZero => lyon::tessellation::FillRule::NonZero,\n        fill::Rule::EvenOdd => lyon::tessellation::FillRule::EvenOdd,\n    }\n}\n\npub(super) fn dashed(path: &Path, line_dash: LineDash<'_>) -> Path {\n    use lyon::algorithms::walk::{RepeatedPattern, WalkerEvent, walk_along_path};\n    use lyon::path::iterator::PathIterator;\n\n    Path::new(|builder| {\n        let segments_odd = (line_dash.segments.len() % 2 == 1)\n            .then(|| [line_dash.segments, line_dash.segments].concat());\n\n        let mut draw_line = false;\n\n        walk_along_path(\n            path.raw()\n                .iter()\n                .flattened(lyon::tessellation::StrokeOptions::DEFAULT_TOLERANCE),\n            0.0,\n            lyon::tessellation::StrokeOptions::DEFAULT_TOLERANCE,\n            &mut RepeatedPattern {\n                callback: |event: WalkerEvent<'_>| {\n                    let point = Point {\n                        x: event.position.x,\n                        y: event.position.y,\n                    };\n\n                    if draw_line {\n                        builder.line_to(point);\n                    } else {\n                        builder.move_to(point);\n                    }\n\n                    draw_line = !draw_line;\n\n                    true\n                },\n                index: line_dash.offset,\n                intervals: segments_odd.as_deref().unwrap_or(line_dash.segments),\n            },\n        );\n    })\n}\n"
  },
  {
    "path": "wgpu/src/image/atlas/allocation.rs",
    "content": "use crate::core::Size;\nuse crate::image::atlas::allocator;\n\n#[derive(Debug)]\npub enum Allocation {\n    Partial {\n        layer: usize,\n        region: allocator::Region,\n        atlas_size: u32,\n    },\n    Full {\n        layer: usize,\n        size: u32,\n    },\n}\n\nimpl Allocation {\n    pub fn position(&self) -> (u32, u32) {\n        match self {\n            Allocation::Partial { region, .. } => region.position(),\n            Allocation::Full { .. } => (0, 0),\n        }\n    }\n\n    pub fn size(&self) -> Size<u32> {\n        match self {\n            Allocation::Partial { region, .. } => region.size(),\n            Allocation::Full { size, .. } => Size::new(*size, *size),\n        }\n    }\n\n    pub fn padding(&self) -> Size<u32> {\n        match self {\n            Allocation::Partial { region, .. } => region.padding(),\n            Allocation::Full { .. } => Size::new(0, 0),\n        }\n    }\n\n    pub fn layer(&self) -> usize {\n        match self {\n            Allocation::Partial { layer, .. } => *layer,\n            Allocation::Full { layer, .. } => *layer,\n        }\n    }\n\n    pub fn atlas_size(&self) -> u32 {\n        match self {\n            Allocation::Partial { atlas_size, .. } => *atlas_size,\n            Allocation::Full { size, .. } => *size,\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/image/atlas/allocator.rs",
    "content": "use crate::core;\n\nuse guillotiere::{AtlasAllocator, Size};\n\npub struct Allocator {\n    raw: AtlasAllocator,\n    allocations: usize,\n}\n\nimpl Allocator {\n    const PADDING: u32 = 1;\n\n    pub fn new(size: u32) -> Allocator {\n        let raw = AtlasAllocator::new(Size::new(size as i32, size as i32));\n\n        Allocator {\n            raw,\n            allocations: 0,\n        }\n    }\n\n    pub fn allocate(&mut self, width: u32, height: u32) -> Option<Region> {\n        let size = self.raw.size();\n\n        let padded_width = width + Self::PADDING * 2;\n        let padded_height = height + Self::PADDING * 2;\n\n        let pad_width = padded_width as i32 <= size.width;\n        let pad_height = padded_height as i32 <= size.height;\n\n        let mut allocation = self.raw.allocate(Size::new(\n            if pad_width { padded_width } else { width } as i32,\n            if pad_height { padded_height } else { height } as i32,\n        ))?;\n\n        if pad_width {\n            allocation.rectangle.min.x += Self::PADDING as i32;\n            allocation.rectangle.max.x -= Self::PADDING as i32;\n        }\n\n        if pad_height {\n            allocation.rectangle.min.y += Self::PADDING as i32;\n            allocation.rectangle.max.y -= Self::PADDING as i32;\n        }\n\n        self.allocations += 1;\n\n        Some(Region {\n            allocation,\n            padding: core::Size::new(\n                if pad_width { Self::PADDING } else { 0 },\n                if pad_height { Self::PADDING } else { 0 },\n            ),\n        })\n    }\n\n    pub fn deallocate(&mut self, region: &Region) {\n        self.raw.deallocate(region.allocation.id);\n\n        self.allocations = self.allocations.saturating_sub(1);\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.allocations == 0\n    }\n\n    pub fn allocations(&self) -> usize {\n        self.allocations\n    }\n}\n\npub struct Region {\n    allocation: guillotiere::Allocation,\n    padding: core::Size<u32>,\n}\n\nimpl Region {\n    pub fn position(&self) -> (u32, u32) {\n        let rectangle = &self.allocation.rectangle;\n\n        (rectangle.min.x as u32, rectangle.min.y as u32)\n    }\n\n    pub fn size(&self) -> core::Size<u32> {\n        let size = self.allocation.rectangle.size();\n\n        core::Size::new(size.width as u32, size.height as u32)\n    }\n\n    pub fn padding(&self) -> crate::core::Size<u32> {\n        self.padding\n    }\n}\n\nimpl std::fmt::Debug for Allocator {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"Allocator\")\n    }\n}\n\nimpl std::fmt::Debug for Region {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Region\")\n            .field(\"id\", &self.allocation.id)\n            .field(\"rectangle\", &self.allocation.rectangle)\n            .finish()\n    }\n}\n"
  },
  {
    "path": "wgpu/src/image/atlas/entry.rs",
    "content": "use crate::core::Size;\nuse crate::image::atlas;\n\n#[derive(Debug)]\npub enum Entry {\n    Contiguous(atlas::Allocation),\n    Fragmented {\n        size: Size<u32>,\n        fragments: Vec<Fragment>,\n    },\n}\n\nimpl Entry {\n    #[cfg(feature = \"image\")]\n    pub fn size(&self) -> Size<u32> {\n        match self {\n            Entry::Contiguous(allocation) => allocation.size(),\n            Entry::Fragmented { size, .. } => *size,\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct Fragment {\n    pub position: (u32, u32),\n    pub allocation: atlas::Allocation,\n}\n"
  },
  {
    "path": "wgpu/src/image/atlas/layer.rs",
    "content": "use crate::image::atlas::Allocator;\n\n#[derive(Debug)]\npub enum Layer {\n    Empty,\n    Busy(Allocator),\n    Full,\n}\n\nimpl Layer {\n    pub fn is_empty(&self) -> bool {\n        matches!(self, Layer::Empty)\n    }\n\n    pub fn allocations(&self) -> usize {\n        match self {\n            Layer::Empty => 0,\n            Layer::Busy(allocator) => allocator.allocations(),\n            Layer::Full => 1,\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/image/atlas.rs",
    "content": "pub mod entry;\n\nmod allocation;\nmod allocator;\nmod layer;\n\npub use allocation::Allocation;\npub use entry::Entry;\npub use layer::Layer;\n\nuse allocator::Allocator;\n\npub const DEFAULT_SIZE: u32 = 2048;\npub const MAX_SIZE: u32 = 2048;\n\nuse crate::core::Size;\nuse crate::graphics::color;\n\nuse std::sync::Arc;\n\n#[derive(Debug)]\npub struct Atlas {\n    size: u32,\n    backend: wgpu::Backend,\n    texture: wgpu::Texture,\n    texture_view: wgpu::TextureView,\n    texture_bind_group: Arc<wgpu::BindGroup>,\n    texture_layout: wgpu::BindGroupLayout,\n    layers: Vec<Layer>,\n}\n\nimpl Atlas {\n    pub fn new(\n        device: &wgpu::Device,\n        backend: wgpu::Backend,\n        texture_layout: wgpu::BindGroupLayout,\n    ) -> Self {\n        Self::with_size(device, backend, texture_layout, DEFAULT_SIZE)\n    }\n\n    pub fn with_size(\n        device: &wgpu::Device,\n        backend: wgpu::Backend,\n        texture_layout: wgpu::BindGroupLayout,\n        size: u32,\n    ) -> Self {\n        let size = size.min(MAX_SIZE);\n\n        let layers = match backend {\n            // On the GL backend we start with 2 layers, to help wgpu figure\n            // out that this texture is `GL_TEXTURE_2D_ARRAY` rather than `GL_TEXTURE_2D`\n            // https://github.com/gfx-rs/wgpu/blob/004e3efe84a320d9331371ed31fa50baa2414911/wgpu-hal/src/gles/mod.rs#L371\n            wgpu::Backend::Gl => vec![Layer::Empty, Layer::Empty],\n            _ => vec![Layer::Empty],\n        };\n\n        let extent = wgpu::Extent3d {\n            width: size,\n            height: size,\n            depth_or_array_layers: layers.len() as u32,\n        };\n\n        let texture = device.create_texture(&wgpu::TextureDescriptor {\n            label: Some(\"iced_wgpu::image texture atlas\"),\n            size: extent,\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format: if color::GAMMA_CORRECTION {\n                wgpu::TextureFormat::Rgba8UnormSrgb\n            } else {\n                wgpu::TextureFormat::Rgba8Unorm\n            },\n            usage: wgpu::TextureUsages::COPY_DST\n                | wgpu::TextureUsages::COPY_SRC\n                | wgpu::TextureUsages::TEXTURE_BINDING,\n            view_formats: &[],\n        });\n\n        let texture_view = texture.create_view(&wgpu::TextureViewDescriptor {\n            dimension: Some(wgpu::TextureViewDimension::D2Array),\n            ..Default::default()\n        });\n\n        let texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"iced_wgpu::image texture atlas bind group\"),\n            layout: &texture_layout,\n            entries: &[wgpu::BindGroupEntry {\n                binding: 0,\n                resource: wgpu::BindingResource::TextureView(&texture_view),\n            }],\n        });\n\n        Atlas {\n            size,\n            backend,\n            texture,\n            texture_view,\n            texture_bind_group: Arc::new(texture_bind_group),\n            texture_layout,\n            layers,\n        }\n    }\n\n    pub fn bind_group(&self) -> &Arc<wgpu::BindGroup> {\n        &self.texture_bind_group\n    }\n\n    pub fn upload(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        width: u32,\n        height: u32,\n        pixels: &[u8],\n    ) -> Option<Entry> {\n        let entry = {\n            let current_size = self.layers.len();\n            let entry = self.allocate(width, height)?;\n\n            // We grow the internal texture after allocating if necessary\n            let new_layers = self.layers.len() - current_size;\n            self.grow(new_layers, device, encoder, self.backend);\n\n            entry\n        };\n\n        log::debug!(\"Allocated atlas entry: {entry:?}\");\n\n        match &entry {\n            Entry::Contiguous(allocation) => {\n                self.upload_allocation(pixels, width, 0, allocation, encoder, belt);\n            }\n            Entry::Fragmented { fragments, .. } => {\n                for fragment in fragments {\n                    let (x, y) = fragment.position;\n                    let offset = 4 * (y * width + x) as usize;\n\n                    self.upload_allocation(\n                        pixels,\n                        width,\n                        offset,\n                        &fragment.allocation,\n                        encoder,\n                        belt,\n                    );\n                }\n            }\n        }\n\n        if log::log_enabled!(log::Level::Debug) {\n            log::debug!(\n                \"Atlas layers: {} (busy: {}, allocations: {})\",\n                self.layers.len(),\n                self.layers.iter().filter(|layer| !layer.is_empty()).count(),\n                self.layers.iter().map(Layer::allocations).sum::<usize>(),\n            );\n        }\n\n        Some(entry)\n    }\n\n    pub fn remove(&mut self, entry: &Entry) {\n        log::debug!(\"Removing atlas entry: {entry:?}\");\n\n        match entry {\n            Entry::Contiguous(allocation) => {\n                self.deallocate(allocation);\n            }\n            Entry::Fragmented { fragments, .. } => {\n                for fragment in fragments {\n                    self.deallocate(&fragment.allocation);\n                }\n            }\n        }\n    }\n\n    fn allocate(&mut self, width: u32, height: u32) -> Option<Entry> {\n        // Allocate one layer if texture fits perfectly\n        if width == self.size && height == self.size {\n            let mut empty_layers = self\n                .layers\n                .iter_mut()\n                .enumerate()\n                .filter(|(_, layer)| layer.is_empty());\n\n            if let Some((i, layer)) = empty_layers.next() {\n                *layer = Layer::Full;\n\n                return Some(Entry::Contiguous(Allocation::Full {\n                    layer: i,\n                    size: self.size,\n                }));\n            }\n\n            self.layers.push(Layer::Full);\n\n            return Some(Entry::Contiguous(Allocation::Full {\n                layer: self.layers.len() - 1,\n                size: self.size,\n            }));\n        }\n\n        // Split big textures across multiple layers\n        if width > self.size || height > self.size {\n            let mut fragments = Vec::new();\n            let mut y = 0;\n\n            while y < height {\n                let height = std::cmp::min(height - y, self.size);\n                let mut x = 0;\n\n                while x < width {\n                    let width = std::cmp::min(width - x, self.size);\n\n                    let allocation = self.allocate(width, height)?;\n\n                    if let Entry::Contiguous(allocation) = allocation {\n                        fragments.push(entry::Fragment {\n                            position: (x, y),\n                            allocation,\n                        });\n                    }\n\n                    x += width;\n                }\n\n                y += height;\n            }\n\n            return Some(Entry::Fragmented {\n                size: Size::new(width, height),\n                fragments,\n            });\n        }\n\n        // Try allocating on an existing layer\n        for (i, layer) in self.layers.iter_mut().enumerate() {\n            match layer {\n                Layer::Empty => {\n                    let mut allocator = Allocator::new(self.size);\n\n                    if let Some(region) = allocator.allocate(width, height) {\n                        *layer = Layer::Busy(allocator);\n\n                        return Some(Entry::Contiguous(Allocation::Partial {\n                            region,\n                            layer: i,\n                            atlas_size: self.size,\n                        }));\n                    }\n                }\n                Layer::Busy(allocator) => {\n                    if let Some(region) = allocator.allocate(width, height) {\n                        return Some(Entry::Contiguous(Allocation::Partial {\n                            region,\n                            layer: i,\n                            atlas_size: self.size,\n                        }));\n                    }\n                }\n                Layer::Full => {}\n            }\n        }\n\n        // Create new layer with atlas allocator\n        let mut allocator = Allocator::new(self.size);\n\n        if let Some(region) = allocator.allocate(width, height) {\n            self.layers.push(Layer::Busy(allocator));\n\n            return Some(Entry::Contiguous(Allocation::Partial {\n                region,\n                layer: self.layers.len() - 1,\n                atlas_size: self.size,\n            }));\n        }\n\n        // We ran out of memory (?)\n        None\n    }\n\n    fn deallocate(&mut self, allocation: &Allocation) {\n        log::debug!(\"Deallocating atlas: {allocation:?}\");\n\n        match allocation {\n            Allocation::Full { layer, .. } => {\n                self.layers[*layer] = Layer::Empty;\n            }\n            Allocation::Partial { layer, region, .. } => {\n                let layer = &mut self.layers[*layer];\n\n                if let Layer::Busy(allocator) = layer {\n                    allocator.deallocate(region);\n\n                    if allocator.is_empty() {\n                        *layer = Layer::Empty;\n                    }\n                }\n            }\n        }\n    }\n\n    fn upload_allocation(\n        &self,\n        pixels: &[u8],\n        image_width: u32,\n        offset: usize,\n        allocation: &Allocation,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n    ) {\n        let (x, y) = allocation.position();\n        let Size { width, height } = allocation.size();\n        let layer = allocation.layer();\n        let padding = allocation.padding();\n\n        // It is a webgpu requirement that:\n        //   BufferCopyView.layout.bytes_per_row % wgpu::COPY_BYTES_PER_ROW_ALIGNMENT == 0\n        // So we calculate bytes_per_row by rounding width up to the next\n        // multiple of wgpu::COPY_BYTES_PER_ROW_ALIGNMENT.\n        let bytes_per_row = (4 * (width + padding.width * 2))\n            .next_multiple_of(wgpu::COPY_BYTES_PER_ROW_ALIGNMENT)\n            as usize;\n        let total_bytes = bytes_per_row * (height + padding.height * 2) as usize;\n\n        let buffer_slice = belt.allocate(\n            wgpu::BufferSize::new(total_bytes as u64).unwrap(),\n            wgpu::BufferSize::new(8 * 4).unwrap(),\n        );\n\n        const PIXEL: usize = 4;\n\n        let mut fragment = buffer_slice.get_mapped_range_mut();\n        let w = width as usize;\n        let h = height as usize;\n        let pad_w = padding.width as usize;\n        let pad_h = padding.height as usize;\n        let stride = PIXEL * w;\n\n        // Copy image rows\n        for row in 0..h {\n            let src = offset + row * PIXEL * image_width as usize;\n            let dst = (row + pad_h) * bytes_per_row;\n\n            fragment[dst + PIXEL * pad_w..dst + PIXEL * pad_w + stride]\n                .copy_from_slice(&pixels[src..src + stride]);\n\n            // Add padding to the sides, if needed\n            for i in 0..pad_w {\n                fragment[dst + PIXEL * i..dst + PIXEL * (i + 1)]\n                    .copy_from_slice(&pixels[src..src + PIXEL]);\n\n                fragment\n                    [dst + stride + PIXEL * (pad_w + i)..dst + stride + PIXEL * (pad_w + i + 1)]\n                    .copy_from_slice(&pixels[src + stride - PIXEL..src + stride]);\n            }\n        }\n\n        // Add padding on top and bottom\n        for row in 0..pad_h {\n            let dst_top = row * bytes_per_row;\n            let dst_bottom = (pad_h + h + row) * bytes_per_row;\n            let src_top = offset;\n            let src_bottom = offset + (h - 1) * PIXEL * image_width as usize;\n\n            // Top\n            fragment[dst_top + PIXEL * pad_w..dst_top + PIXEL * (pad_w + w)]\n                .copy_from_slice(&pixels[src_top..src_top + PIXEL * w]);\n\n            // Bottom\n            fragment[dst_bottom + PIXEL * pad_w..dst_bottom + PIXEL * (pad_w + w)]\n                .copy_from_slice(&pixels[src_bottom..src_bottom + PIXEL * w]);\n\n            // Corners\n            for i in 0..pad_w {\n                // Top left\n                fragment[dst_top + PIXEL * i..dst_top + PIXEL * (i + 1)]\n                    .copy_from_slice(&pixels[offset..offset + PIXEL]);\n\n                // Top right\n                fragment[dst_top + PIXEL * (w + pad_w + i)..dst_top + PIXEL * (w + pad_w + i + 1)]\n                    .copy_from_slice(&pixels[offset + PIXEL * (w - 1)..offset + PIXEL * w]);\n\n                // Bottom left\n                fragment[dst_bottom + PIXEL * i..dst_bottom + PIXEL * (i + 1)]\n                    .copy_from_slice(&pixels[src_bottom..src_bottom + PIXEL]);\n\n                // Bottom right\n                fragment[dst_bottom + PIXEL * (w + pad_w + i)\n                    ..dst_bottom + PIXEL * (w + pad_w + i + 1)]\n                    .copy_from_slice(&pixels[src_bottom + PIXEL * (w - 1)..src_bottom + PIXEL * w]);\n            }\n        }\n\n        // Copy actual image\n        encoder.copy_buffer_to_texture(\n            wgpu::TexelCopyBufferInfo {\n                buffer: buffer_slice.buffer(),\n                layout: wgpu::TexelCopyBufferLayout {\n                    offset: buffer_slice.offset(),\n                    bytes_per_row: Some(bytes_per_row as u32),\n                    rows_per_image: Some(height + padding.height * 2),\n                },\n            },\n            wgpu::TexelCopyTextureInfo {\n                texture: &self.texture,\n                mip_level: 0,\n                origin: wgpu::Origin3d {\n                    x: x - padding.width,\n                    y: y - padding.height,\n                    z: layer as u32,\n                },\n                aspect: wgpu::TextureAspect::default(),\n            },\n            wgpu::Extent3d {\n                width: width + padding.width * 2,\n                height: height + padding.height * 2,\n                depth_or_array_layers: 1,\n            },\n        );\n    }\n\n    fn grow(\n        &mut self,\n        amount: usize,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        backend: wgpu::Backend,\n    ) {\n        if amount == 0 {\n            return;\n        }\n\n        // On the GL backend if layers.len() is a multiple of 6 we need to help wgpu figure out that this texture\n        // is still a `GL_TEXTURE_2D_ARRAY` rather than `GL_TEXTURE_CUBE_MAP` or `GL_TEXTURE_CUBE_ARRAY`.\n        // This will over-allocate some unused memory on GL, but it's better than not being able to\n        // grow the atlas past multiples of 6!\n        // https://github.com/gfx-rs/wgpu/blob/004e3efe84a320d9331371ed31fa50baa2414911/wgpu-hal/src/gles/mod.rs#L371\n        let depth_or_array_layers = match backend {\n            wgpu::Backend::Gl if self.layers.len().is_multiple_of(6) => {\n                self.layers.len() as u32 + 1\n            }\n            _ => self.layers.len() as u32,\n        };\n\n        let new_texture = device.create_texture(&wgpu::TextureDescriptor {\n            label: Some(\"iced_wgpu::image texture atlas\"),\n            size: wgpu::Extent3d {\n                width: self.size,\n                height: self.size,\n                depth_or_array_layers,\n            },\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format: if color::GAMMA_CORRECTION {\n                wgpu::TextureFormat::Rgba8UnormSrgb\n            } else {\n                wgpu::TextureFormat::Rgba8Unorm\n            },\n            usage: wgpu::TextureUsages::COPY_DST\n                | wgpu::TextureUsages::COPY_SRC\n                | wgpu::TextureUsages::TEXTURE_BINDING,\n            view_formats: &[],\n        });\n\n        let amount_to_copy = self.layers.len() - amount;\n\n        for (i, layer) in self.layers.iter_mut().take(amount_to_copy).enumerate() {\n            if layer.is_empty() {\n                continue;\n            }\n\n            encoder.copy_texture_to_texture(\n                wgpu::TexelCopyTextureInfo {\n                    texture: &self.texture,\n                    mip_level: 0,\n                    origin: wgpu::Origin3d {\n                        x: 0,\n                        y: 0,\n                        z: i as u32,\n                    },\n                    aspect: wgpu::TextureAspect::default(),\n                },\n                wgpu::TexelCopyTextureInfo {\n                    texture: &new_texture,\n                    mip_level: 0,\n                    origin: wgpu::Origin3d {\n                        x: 0,\n                        y: 0,\n                        z: i as u32,\n                    },\n                    aspect: wgpu::TextureAspect::default(),\n                },\n                wgpu::Extent3d {\n                    width: self.size,\n                    height: self.size,\n                    depth_or_array_layers: 1,\n                },\n            );\n        }\n\n        self.texture = new_texture;\n        self.texture_view = self.texture.create_view(&wgpu::TextureViewDescriptor {\n            dimension: Some(wgpu::TextureViewDimension::D2Array),\n            ..Default::default()\n        });\n\n        self.texture_bind_group = Arc::new(device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"iced_wgpu::image texture atlas bind group\"),\n            layout: &self.texture_layout,\n            entries: &[wgpu::BindGroupEntry {\n                binding: 0,\n                resource: wgpu::BindingResource::TextureView(&self.texture_view),\n            }],\n        }));\n    }\n}\n"
  },
  {
    "path": "wgpu/src/image/cache.rs",
    "content": "use crate::core::{self, Size};\nuse crate::graphics::Shell;\nuse crate::image::atlas::{self, Atlas};\n\n#[cfg(all(feature = \"image\", not(target_arch = \"wasm32\")))]\nuse worker::Worker;\n\n#[cfg(feature = \"image\")]\nuse std::collections::HashMap;\n\nuse std::sync::Arc;\n\npub struct Cache {\n    atlas: Atlas,\n    #[cfg(feature = \"image\")]\n    raster: Raster,\n    #[cfg(feature = \"svg\")]\n    vector: crate::image::vector::Cache,\n    #[cfg(all(feature = \"image\", not(target_arch = \"wasm32\")))]\n    worker: Worker,\n}\n\nimpl Cache {\n    pub fn new(\n        device: &wgpu::Device,\n        _queue: &wgpu::Queue,\n        backend: wgpu::Backend,\n        layout: wgpu::BindGroupLayout,\n        _shell: &Shell,\n    ) -> Self {\n        #[cfg(all(feature = \"image\", not(target_arch = \"wasm32\")))]\n        let worker = Worker::new(device, _queue, backend, layout.clone(), _shell);\n\n        Self {\n            atlas: Atlas::new(device, backend, layout),\n            #[cfg(feature = \"image\")]\n            raster: Raster {\n                cache: crate::image::raster::Cache::default(),\n                pending: HashMap::new(),\n                belt: wgpu::util::StagingBelt::new(device.clone(), 2 * 1024 * 1024),\n            },\n            #[cfg(feature = \"svg\")]\n            vector: crate::image::vector::Cache::default(),\n            #[cfg(all(feature = \"image\", not(target_arch = \"wasm32\")))]\n            worker,\n        }\n    }\n\n    #[cfg(feature = \"image\")]\n    pub fn allocate_image(\n        &mut self,\n        handle: &core::image::Handle,\n        callback: impl FnOnce(Result<core::image::Allocation, core::image::Error>) + Send + 'static,\n    ) {\n        use crate::image::raster::Memory;\n\n        let callback = Box::new(callback);\n\n        if let Some(callbacks) = self.raster.pending.get_mut(&handle.id()) {\n            callbacks.push(callback);\n            return;\n        }\n\n        if let Some(Memory::Device {\n            allocation, entry, ..\n        }) = self.raster.cache.get_mut(handle)\n        {\n            if let Some(allocation) = allocation\n                .as_ref()\n                .and_then(core::image::Allocation::upgrade)\n            {\n                callback(Ok(allocation));\n                return;\n            }\n\n            #[allow(unsafe_code)]\n            let new = unsafe { core::image::allocate(handle, entry.size()) };\n            *allocation = Some(new.downgrade());\n            callback(Ok(new));\n\n            return;\n        }\n\n        let _ = self.raster.pending.insert(handle.id(), vec![callback]);\n\n        #[cfg(not(target_arch = \"wasm32\"))]\n        self.worker.load(handle, true);\n    }\n\n    #[cfg(feature = \"image\")]\n    pub fn load_image(\n        &mut self,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n        handle: &core::image::Handle,\n    ) -> Result<core::image::Allocation, core::image::Error> {\n        use crate::image::raster::Memory;\n\n        if !self.raster.cache.contains(handle) {\n            self.raster.cache.insert(handle, Memory::load(handle));\n        }\n\n        match self.raster.cache.get_mut(handle).unwrap() {\n            Memory::Host(image) => {\n                let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {\n                    label: Some(\"raster image upload\"),\n                });\n\n                let entry = self.atlas.upload(\n                    device,\n                    &mut encoder,\n                    &mut self.raster.belt,\n                    image.width(),\n                    image.height(),\n                    image,\n                );\n\n                self.raster.belt.finish();\n                let submission = queue.submit([encoder.finish()]);\n                self.raster.belt.recall();\n\n                let Some(entry) = entry else {\n                    return Err(core::image::Error::OutOfMemory);\n                };\n\n                let _ = device.poll(wgpu::PollType::Wait {\n                    submission_index: Some(submission),\n                    timeout: None,\n                });\n\n                #[allow(unsafe_code)]\n                let allocation = unsafe {\n                    core::image::allocate(handle, Size::new(image.width(), image.height()))\n                };\n\n                self.raster.cache.insert(\n                    handle,\n                    Memory::Device {\n                        entry,\n                        bind_group: None,\n                        allocation: Some(allocation.downgrade()),\n                    },\n                );\n\n                Ok(allocation)\n            }\n            Memory::Device {\n                entry, allocation, ..\n            } => {\n                if let Some(allocation) = allocation\n                    .as_ref()\n                    .and_then(core::image::Allocation::upgrade)\n                {\n                    return Ok(allocation);\n                }\n\n                #[allow(unsafe_code)]\n                let new = unsafe { core::image::allocate(handle, entry.size()) };\n\n                *allocation = Some(new.downgrade());\n\n                Ok(new)\n            }\n            Memory::Error(error) => Err(error.clone()),\n        }\n    }\n\n    #[cfg(feature = \"image\")]\n    pub fn measure_image(&mut self, handle: &core::image::Handle) -> Option<Size<u32>> {\n        self.receive();\n\n        let image = load_image(\n            &mut self.raster.cache,\n            &mut self.raster.pending,\n            #[cfg(not(target_arch = \"wasm32\"))]\n            &self.worker,\n            handle,\n            None,\n        )?;\n\n        Some(image.dimensions())\n    }\n\n    #[cfg(feature = \"svg\")]\n    pub fn measure_svg(&mut self, handle: &core::svg::Handle) -> Size<u32> {\n        // TODO: Concurrency\n        self.vector.load(handle).viewport_dimensions()\n    }\n\n    #[cfg(feature = \"image\")]\n    pub fn upload_raster(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        handle: &core::image::Handle,\n    ) -> Option<(&atlas::Entry, &Arc<wgpu::BindGroup>)> {\n        use crate::image::raster::Memory;\n\n        self.receive();\n\n        let memory = load_image(\n            &mut self.raster.cache,\n            &mut self.raster.pending,\n            #[cfg(not(target_arch = \"wasm32\"))]\n            &self.worker,\n            handle,\n            None,\n        )?;\n\n        if let Memory::Device {\n            entry, bind_group, ..\n        } = memory\n        {\n            return Some((\n                entry,\n                bind_group.as_ref().unwrap_or(self.atlas.bind_group()),\n            ));\n        }\n\n        let image = memory.host()?;\n\n        const MAX_SYNC_SIZE: usize = 2 * 1024 * 1024;\n\n        // TODO: Concurrent Wasm support\n        if image.len() < MAX_SYNC_SIZE || cfg!(target_arch = \"wasm32\") {\n            let entry =\n                self.atlas\n                    .upload(device, encoder, belt, image.width(), image.height(), &image)?;\n\n            *memory = Memory::Device {\n                entry,\n                bind_group: None,\n                allocation: None,\n            };\n\n            if let Memory::Device { entry, .. } = memory {\n                return Some((entry, self.atlas.bind_group()));\n            }\n        }\n\n        if !self.raster.pending.contains_key(&handle.id()) {\n            let _ = self.raster.pending.insert(handle.id(), Vec::new());\n\n            #[cfg(not(target_arch = \"wasm32\"))]\n            self.worker.upload(handle, image);\n        }\n\n        None\n    }\n\n    #[cfg(feature = \"svg\")]\n    pub fn upload_vector(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        handle: &core::svg::Handle,\n        color: Option<core::Color>,\n        size: Size<u32>,\n    ) -> Option<(&atlas::Entry, &Arc<wgpu::BindGroup>)> {\n        // TODO: Concurrency\n        self.vector\n            .upload(device, encoder, belt, handle, color, size, &mut self.atlas)\n            .map(|entry| (entry, self.atlas.bind_group()))\n    }\n\n    pub fn trim(&mut self) {\n        #[cfg(feature = \"image\")]\n        {\n            self.receive();\n            self.raster.cache.trim(&mut self.atlas, |_bind_group| {\n                #[cfg(not(target_arch = \"wasm32\"))]\n                self.worker.drop(_bind_group);\n            });\n        }\n\n        #[cfg(feature = \"svg\")]\n        self.vector.trim(&mut self.atlas); // TODO: Concurrency\n    }\n\n    #[cfg(feature = \"image\")]\n    pub fn receive(&mut self) {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        while let Ok(work) = self.worker.try_recv() {\n            use crate::image::raster::Memory;\n\n            match work {\n                worker::Work::Upload {\n                    handle,\n                    entry,\n                    bind_group,\n                } => {\n                    let callbacks = self.raster.pending.remove(&handle.id());\n\n                    let allocation = if let Some(callbacks) = callbacks {\n                        #[allow(unsafe_code)]\n                        let allocation = unsafe { core::image::allocate(&handle, entry.size()) };\n\n                        let reference = allocation.downgrade();\n\n                        for callback in callbacks {\n                            callback(Ok(allocation.clone()));\n                        }\n\n                        Some(reference)\n                    } else {\n                        None\n                    };\n\n                    self.raster.cache.insert(\n                        &handle,\n                        Memory::Device {\n                            entry,\n                            bind_group: Some(bind_group),\n                            allocation,\n                        },\n                    );\n                }\n                worker::Work::Error { handle, error } => {\n                    let callbacks = self.raster.pending.remove(&handle.id());\n\n                    if let Some(callbacks) = callbacks {\n                        for callback in callbacks {\n                            callback(Err(error.clone()));\n                        }\n                    }\n\n                    self.raster.cache.insert(&handle, Memory::Error(error));\n                }\n            }\n        }\n    }\n}\n\n#[cfg(all(feature = \"image\", not(target_arch = \"wasm32\")))]\nimpl Drop for Cache {\n    fn drop(&mut self) {\n        self.worker.quit();\n    }\n}\n\n#[cfg(feature = \"image\")]\nstruct Raster {\n    cache: crate::image::raster::Cache,\n    pending: HashMap<core::image::Id, Vec<Callback>>,\n    belt: wgpu::util::StagingBelt,\n}\n\n#[cfg(feature = \"image\")]\ntype Callback = Box<dyn FnOnce(Result<core::image::Allocation, core::image::Error>) + Send>;\n\n#[cfg(feature = \"image\")]\nfn load_image<'a>(\n    cache: &'a mut crate::image::raster::Cache,\n    pending: &mut HashMap<core::image::Id, Vec<Callback>>,\n    #[cfg(not(target_arch = \"wasm32\"))] worker: &Worker,\n    handle: &core::image::Handle,\n    callback: Option<Callback>,\n) -> Option<&'a mut crate::image::raster::Memory> {\n    use crate::image::raster::Memory;\n\n    if !cache.contains(handle) {\n        if cfg!(target_arch = \"wasm32\") {\n            // TODO: Concurrent support for Wasm\n            cache.insert(handle, Memory::load(handle));\n        } else if let core::image::Handle::Rgba { .. } = handle {\n            // Load RGBA handles synchronously, since it's very cheap\n            cache.insert(handle, Memory::load(handle));\n        } else if !pending.contains_key(&handle.id()) {\n            let _ = pending.insert(handle.id(), Vec::from_iter(callback));\n\n            #[cfg(not(target_arch = \"wasm32\"))]\n            worker.load(handle, false);\n        }\n    }\n\n    cache.get_mut(handle)\n}\n\n#[cfg(all(feature = \"image\", not(target_arch = \"wasm32\")))]\nmod worker {\n    use crate::core::Bytes;\n    use crate::core::image;\n    use crate::graphics::Shell;\n    use crate::image::atlas::{self, Atlas};\n    use crate::image::raster;\n\n    use std::sync::Arc;\n    use std::sync::mpsc;\n    use std::thread;\n\n    pub struct Worker {\n        jobs: mpsc::SyncSender<Job>,\n        quit: mpsc::SyncSender<()>,\n        work: mpsc::Receiver<Work>,\n        handle: Option<std::thread::JoinHandle<()>>,\n    }\n\n    impl Worker {\n        pub fn new(\n            device: &wgpu::Device,\n            queue: &wgpu::Queue,\n            backend: wgpu::Backend,\n            texture_layout: wgpu::BindGroupLayout,\n            shell: &Shell,\n        ) -> Self {\n            let (jobs_sender, jobs_receiver) = mpsc::sync_channel(1_000);\n            let (quit_sender, quit_receiver) = mpsc::sync_channel(1);\n            let (work_sender, work_receiver) = mpsc::sync_channel(1_000);\n\n            let instance = Instance {\n                device: device.clone(),\n                queue: queue.clone(),\n                backend,\n                texture_layout,\n                shell: shell.clone(),\n                belt: wgpu::util::StagingBelt::new(device.clone(), 4 * 1024 * 1024),\n                jobs: jobs_receiver,\n                output: work_sender,\n                quit: quit_receiver,\n            };\n\n            let handle = thread::spawn(move || instance.run());\n\n            Self {\n                jobs: jobs_sender,\n                quit: quit_sender,\n                work: work_receiver,\n                handle: Some(handle),\n            }\n        }\n\n        pub fn load(&self, handle: &image::Handle, is_allocation: bool) {\n            let _ = self.jobs.send(Job::Load {\n                handle: handle.clone(),\n                is_allocation,\n            });\n        }\n\n        pub fn upload(&self, handle: &image::Handle, image: raster::Image) {\n            let _ = self.jobs.send(Job::Upload {\n                handle: handle.clone(),\n                width: image.width(),\n                height: image.height(),\n                rgba: image.into_raw(),\n            });\n        }\n\n        pub fn drop(&self, bind_group: Arc<wgpu::BindGroup>) {\n            let _ = self.jobs.send(Job::Drop(bind_group));\n        }\n\n        pub fn try_recv(&self) -> Result<Work, mpsc::TryRecvError> {\n            self.work.try_recv()\n        }\n\n        pub fn quit(&mut self) {\n            let _ = self.quit.try_send(());\n            let _ = self.jobs.send(Job::Quit);\n            let _ = self.handle.take().map(thread::JoinHandle::join);\n        }\n    }\n\n    pub struct Instance {\n        device: wgpu::Device,\n        queue: wgpu::Queue,\n        backend: wgpu::Backend,\n        texture_layout: wgpu::BindGroupLayout,\n        shell: Shell,\n        belt: wgpu::util::StagingBelt,\n        jobs: mpsc::Receiver<Job>,\n        output: mpsc::SyncSender<Work>,\n        quit: mpsc::Receiver<()>,\n    }\n\n    #[derive(Debug)]\n    enum Job {\n        Load {\n            handle: image::Handle,\n            is_allocation: bool,\n        },\n        Upload {\n            handle: image::Handle,\n            rgba: Bytes,\n            width: u32,\n            height: u32,\n        },\n        Drop(Arc<wgpu::BindGroup>),\n        Quit,\n    }\n\n    pub enum Work {\n        Upload {\n            handle: image::Handle,\n            entry: atlas::Entry,\n            bind_group: Arc<wgpu::BindGroup>,\n        },\n        Error {\n            handle: image::Handle,\n            error: image::Error,\n        },\n    }\n\n    impl Instance {\n        fn run(mut self) {\n            loop {\n                if self.quit.try_recv().is_ok() {\n                    return;\n                }\n\n                let Ok(job) = self.jobs.recv() else {\n                    return;\n                };\n\n                match job {\n                    Job::Load {\n                        handle,\n                        is_allocation,\n                    } => match crate::graphics::image::load(&handle) {\n                        Ok(image) => self.upload(\n                            handle,\n                            image.width(),\n                            image.height(),\n                            image.into_raw(),\n                            if is_allocation {\n                                Shell::tick\n                            } else {\n                                Shell::invalidate_layout\n                            },\n                        ),\n                        Err(error) => {\n                            let _ = self.output.send(Work::Error { handle, error });\n                        }\n                    },\n                    Job::Upload {\n                        handle,\n                        rgba,\n                        width,\n                        height,\n                    } => {\n                        self.upload(handle, width, height, rgba, Shell::request_redraw);\n                    }\n                    Job::Drop(bind_group) => {\n                        drop(bind_group);\n                    }\n                    Job::Quit => return,\n                }\n            }\n        }\n\n        fn upload(\n            &mut self,\n            handle: image::Handle,\n            width: u32,\n            height: u32,\n            rgba: Bytes,\n            callback: fn(&Shell),\n        ) {\n            let mut encoder = self\n                .device\n                .create_command_encoder(&wgpu::CommandEncoderDescriptor {\n                    label: Some(\"raster image upload\"),\n                });\n\n            let mut atlas = Atlas::with_size(\n                &self.device,\n                self.backend,\n                self.texture_layout.clone(),\n                width.max(height),\n            );\n\n            let Some(entry) = atlas.upload(\n                &self.device,\n                &mut encoder,\n                &mut self.belt,\n                width,\n                height,\n                &rgba,\n            ) else {\n                return;\n            };\n\n            let output = self.output.clone();\n            let shell = self.shell.clone();\n\n            self.belt.finish();\n            let submission = self.queue.submit([encoder.finish()]);\n            self.belt.recall();\n\n            let bind_group = atlas.bind_group().clone();\n\n            self.queue.on_submitted_work_done(move || {\n                let _ = output.send(Work::Upload {\n                    handle,\n                    entry,\n                    bind_group,\n                });\n\n                callback(&shell);\n            });\n\n            let _ = self.device.poll(wgpu::PollType::Wait {\n                submission_index: Some(submission),\n                timeout: None,\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/image/mod.rs",
    "content": "pub(crate) mod cache;\npub(crate) use cache::Cache;\n\nmod atlas;\n\n#[cfg(feature = \"image\")]\nmod raster;\n\n#[cfg(feature = \"svg\")]\nmod vector;\n\nuse crate::Buffer;\nuse crate::core::border;\nuse crate::core::{Rectangle, Size, Transformation};\nuse crate::graphics::Shell;\n\nuse bytemuck::{Pod, Zeroable};\n\nuse std::mem;\nuse std::sync::Arc;\n\npub use crate::graphics::Image;\n\npub type Batch = Vec<Image>;\n\n#[derive(Debug, Clone)]\npub struct Pipeline {\n    raw: wgpu::RenderPipeline,\n    backend: wgpu::Backend,\n    nearest_sampler: wgpu::Sampler,\n    linear_sampler: wgpu::Sampler,\n    texture_layout: wgpu::BindGroupLayout,\n    constant_layout: wgpu::BindGroupLayout,\n}\n\nimpl Pipeline {\n    pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat, backend: wgpu::Backend) -> Self {\n        let nearest_sampler = device.create_sampler(&wgpu::SamplerDescriptor {\n            address_mode_u: wgpu::AddressMode::ClampToEdge,\n            address_mode_v: wgpu::AddressMode::ClampToEdge,\n            address_mode_w: wgpu::AddressMode::ClampToEdge,\n            min_filter: wgpu::FilterMode::Nearest,\n            mag_filter: wgpu::FilterMode::Nearest,\n            mipmap_filter: wgpu::MipmapFilterMode::Nearest,\n            ..Default::default()\n        });\n\n        let linear_sampler = device.create_sampler(&wgpu::SamplerDescriptor {\n            address_mode_u: wgpu::AddressMode::ClampToEdge,\n            address_mode_v: wgpu::AddressMode::ClampToEdge,\n            address_mode_w: wgpu::AddressMode::ClampToEdge,\n            min_filter: wgpu::FilterMode::Linear,\n            mag_filter: wgpu::FilterMode::Linear,\n            mipmap_filter: wgpu::MipmapFilterMode::Linear,\n            ..Default::default()\n        });\n\n        let constant_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n            label: Some(\"iced_wgpu::image constants layout\"),\n            entries: &[\n                wgpu::BindGroupLayoutEntry {\n                    binding: 0,\n                    visibility: wgpu::ShaderStages::VERTEX,\n                    ty: wgpu::BindingType::Buffer {\n                        ty: wgpu::BufferBindingType::Uniform,\n                        has_dynamic_offset: false,\n                        min_binding_size: wgpu::BufferSize::new(mem::size_of::<Uniforms>() as u64),\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 texture_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n            label: Some(\"iced_wgpu::image texture atlas layout\"),\n            entries: &[wgpu::BindGroupLayoutEntry {\n                binding: 0,\n                visibility: wgpu::ShaderStages::FRAGMENT,\n                ty: wgpu::BindingType::Texture {\n                    sample_type: wgpu::TextureSampleType::Float { filterable: true },\n                    view_dimension: wgpu::TextureViewDimension::D2Array,\n                    multisampled: false,\n                },\n                count: None,\n            }],\n        });\n\n        let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: Some(\"iced_wgpu::image pipeline layout\"),\n            bind_group_layouts: &[&constant_layout, &texture_layout],\n            immediate_size: 0,\n        });\n\n        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: Some(\"iced_wgpu image shader\"),\n            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(concat!(\n                include_str!(\"../shader/vertex.wgsl\"),\n                \"\\n\",\n                include_str!(\"../shader/color.wgsl\"),\n                \"\\n\",\n                include_str!(\"../shader/image.wgsl\"),\n            ))),\n        });\n\n        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: Some(\"iced_wgpu::image pipeline\"),\n            layout: Some(&layout),\n            vertex: wgpu::VertexState {\n                module: &shader,\n                entry_point: Some(\"vs_main\"),\n                buffers: &[wgpu::VertexBufferLayout {\n                    array_stride: mem::size_of::<Instance>() as u64,\n                    step_mode: wgpu::VertexStepMode::Instance,\n                    attributes: &wgpu::vertex_attr_array!(\n                        // Center\n                        0 => Float32x2,\n                        // Clip bounds\n                        1 => Float32x4,\n                        // Border radius\n                        2 => Float32x4,\n                        // Tile\n                        3 => Float32x4,\n                        // Rotation\n                        4 => Float32,\n                        // Opacity\n                        5 => Float32,\n                        // Atlas position\n                        6 => Float32x2,\n                        // Atlas scale\n                        7 => Float32x2,\n                        // Layer\n                        8 => Sint32,\n                    ),\n                }],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            },\n            fragment: Some(wgpu::FragmentState {\n                module: &shader,\n                entry_point: Some(\"fs_main\"),\n                targets: &[Some(wgpu::ColorTargetState {\n                    format,\n                    blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),\n                    write_mask: wgpu::ColorWrites::ALL,\n                })],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            }),\n            primitive: wgpu::PrimitiveState {\n                topology: wgpu::PrimitiveTopology::TriangleList,\n                front_face: wgpu::FrontFace::Cw,\n                ..Default::default()\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        Pipeline {\n            raw: pipeline,\n            backend,\n            nearest_sampler,\n            linear_sampler,\n            texture_layout,\n            constant_layout,\n        }\n    }\n\n    pub fn create_cache(&self, device: &wgpu::Device, queue: &wgpu::Queue, shell: &Shell) -> Cache {\n        Cache::new(\n            device,\n            queue,\n            self.backend,\n            self.texture_layout.clone(),\n            shell,\n        )\n    }\n}\n\n#[derive(Default)]\npub struct State {\n    layers: Vec<Layer>,\n    prepare_layer: usize,\n    nearest_instances: Vec<Instance>,\n    linear_instances: Vec<Instance>,\n}\n\nimpl State {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn prepare(\n        &mut self,\n        pipeline: &Pipeline,\n        device: &wgpu::Device,\n        belt: &mut wgpu::util::StagingBelt,\n        encoder: &mut wgpu::CommandEncoder,\n        cache: &mut Cache,\n        images: &Batch,\n        transformation: Transformation,\n        scale: f32,\n    ) {\n        if self.layers.len() <= self.prepare_layer {\n            self.layers.push(Layer::new(\n                device,\n                &pipeline.constant_layout,\n                &pipeline.nearest_sampler,\n                &pipeline.linear_sampler,\n            ));\n        }\n\n        let layer = &mut self.layers[self.prepare_layer];\n\n        let mut atlas: Option<Arc<wgpu::BindGroup>> = None;\n\n        for image in images {\n            match &image {\n                #[cfg(feature = \"image\")]\n                Image::Raster {\n                    image,\n                    bounds,\n                    clip_bounds,\n                } => {\n                    let bounds = (*bounds * scale).round();\n                    let clip_bounds = (*clip_bounds * scale).round();\n\n                    if bounds.width < 1.0 || bounds.height < 1.0 {\n                        return;\n                    }\n\n                    if let Some((atlas_entry, bind_group)) =\n                        cache.upload_raster(device, encoder, belt, &image.handle)\n                    {\n                        match atlas.as_mut() {\n                            None => {\n                                atlas = Some(bind_group.clone());\n                            }\n                            Some(atlas) if atlas != bind_group => {\n                                layer.push(atlas, &self.nearest_instances, &self.linear_instances);\n\n                                *atlas = Arc::clone(bind_group);\n                            }\n                            _ => {}\n                        }\n\n                        add_instances(\n                            bounds,\n                            clip_bounds,\n                            image.border_radius * scale,\n                            f32::from(image.rotation),\n                            image.opacity,\n                            atlas_entry,\n                            match image.filter_method {\n                                crate::core::image::FilterMethod::Nearest => {\n                                    &mut self.nearest_instances\n                                }\n                                crate::core::image::FilterMethod::Linear => {\n                                    &mut self.linear_instances\n                                }\n                            },\n                        );\n                    }\n                }\n                #[cfg(not(feature = \"image\"))]\n                Image::Raster { .. } => continue,\n\n                #[cfg(feature = \"svg\")]\n                Image::Vector {\n                    svg,\n                    bounds,\n                    clip_bounds,\n                } => {\n                    let bounds = (*bounds * scale).round();\n                    let clip_bounds = (*clip_bounds * scale).round();\n\n                    if bounds.width < 1.0 || bounds.height < 1.0 {\n                        return;\n                    }\n\n                    if let Some((atlas_entry, bind_group)) = cache.upload_vector(\n                        device,\n                        encoder,\n                        belt,\n                        &svg.handle,\n                        svg.color,\n                        Size::new(bounds.width as u32, bounds.height as u32),\n                    ) {\n                        match atlas.as_mut() {\n                            None => {\n                                atlas = Some(bind_group.clone());\n                            }\n                            Some(atlas) if atlas != bind_group => {\n                                layer.push(atlas, &self.nearest_instances, &self.linear_instances);\n\n                                *atlas = bind_group.clone();\n                            }\n                            _ => {}\n                        }\n\n                        add_instances(\n                            bounds,\n                            clip_bounds,\n                            border::radius(0),\n                            f32::from(svg.rotation),\n                            svg.opacity,\n                            atlas_entry,\n                            &mut self.nearest_instances,\n                        );\n                    }\n                }\n                #[cfg(not(feature = \"svg\"))]\n                Image::Vector { .. } => continue,\n            }\n        }\n\n        if let Some(atlas) = &atlas {\n            layer.push(atlas, &self.nearest_instances, &self.linear_instances);\n        }\n\n        layer.prepare(\n            device,\n            encoder,\n            belt,\n            transformation,\n            &self.nearest_instances,\n            &self.linear_instances,\n        );\n\n        self.prepare_layer += 1;\n        self.nearest_instances.clear();\n        self.linear_instances.clear();\n    }\n\n    pub fn render<'a>(\n        &'a self,\n        pipeline: &'a Pipeline,\n        layer: usize,\n        bounds: Rectangle<u32>,\n        render_pass: &mut wgpu::RenderPass<'a>,\n    ) {\n        if let Some(layer) = self.layers.get(layer) {\n            render_pass.set_pipeline(&pipeline.raw);\n\n            render_pass.set_scissor_rect(bounds.x, bounds.y, bounds.width, bounds.height);\n\n            layer.render(render_pass);\n        }\n    }\n\n    pub fn trim(&mut self) {\n        for layer in &mut self.layers[..self.prepare_layer] {\n            layer.clear();\n        }\n\n        self.prepare_layer = 0;\n    }\n}\n\n#[derive(Debug)]\nstruct Layer {\n    uniforms: wgpu::Buffer,\n    instances: Buffer<Instance>,\n    nearest: Vec<Group>,\n    nearest_layout: wgpu::BindGroup,\n    nearest_total: usize,\n    linear: Vec<Group>,\n    linear_layout: wgpu::BindGroup,\n    linear_total: usize,\n}\n\n#[derive(Debug)]\nstruct Group {\n    atlas: Arc<wgpu::BindGroup>,\n    instance_count: usize,\n}\n\nimpl Layer {\n    fn new(\n        device: &wgpu::Device,\n        constant_layout: &wgpu::BindGroupLayout,\n        nearest_sampler: &wgpu::Sampler,\n        linear_sampler: &wgpu::Sampler,\n    ) -> Self {\n        let uniforms = device.create_buffer(&wgpu::BufferDescriptor {\n            label: Some(\"iced_wgpu::image uniforms buffer\"),\n            size: mem::size_of::<Uniforms>() as u64,\n            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,\n            mapped_at_creation: false,\n        });\n\n        let instances = Buffer::new(\n            device,\n            \"iced_wgpu::image instance buffer\",\n            Instance::INITIAL,\n            wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,\n        );\n\n        let nearest_layout = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"iced_wgpu::image constants bind group\"),\n            layout: constant_layout,\n            entries: &[\n                wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {\n                        buffer: &uniforms,\n                        offset: 0,\n                        size: None,\n                    }),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 1,\n                    resource: wgpu::BindingResource::Sampler(nearest_sampler),\n                },\n            ],\n        });\n\n        let linear_layout = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"iced_wgpu::image constants bind group\"),\n            layout: constant_layout,\n            entries: &[\n                wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {\n                        buffer: &uniforms,\n                        offset: 0,\n                        size: None,\n                    }),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 1,\n                    resource: wgpu::BindingResource::Sampler(linear_sampler),\n                },\n            ],\n        });\n\n        Self {\n            uniforms,\n            instances,\n            nearest: Vec::new(),\n            nearest_layout,\n            nearest_total: 0,\n            linear: Vec::new(),\n            linear_layout,\n            linear_total: 0,\n        }\n    }\n\n    fn prepare(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        transformation: Transformation,\n        nearest: &[Instance],\n        linear: &[Instance],\n    ) {\n        let uniforms = Uniforms {\n            transform: transformation.into(),\n        };\n\n        let bytes = bytemuck::bytes_of(&uniforms);\n\n        belt.write_buffer(\n            encoder,\n            &self.uniforms,\n            0,\n            (bytes.len() as u64).try_into().expect(\"Sized uniforms\"),\n        )\n        .copy_from_slice(bytes);\n\n        let _ = self\n            .instances\n            .resize(device, self.nearest_total + self.linear_total);\n\n        let mut offset = 0;\n\n        if !nearest.is_empty() {\n            offset += self.instances.write(encoder, belt, 0, nearest);\n        }\n\n        if !linear.is_empty() {\n            let _ = self.instances.write(encoder, belt, offset, linear);\n        }\n    }\n\n    fn push(&mut self, atlas: &Arc<wgpu::BindGroup>, nearest: &[Instance], linear: &[Instance]) {\n        let new_nearest = nearest.len() - self.nearest_total;\n\n        if new_nearest > 0 {\n            self.nearest.push(Group {\n                atlas: atlas.clone(),\n                instance_count: new_nearest,\n            });\n\n            self.nearest_total = nearest.len();\n        }\n\n        let new_linear = linear.len() - self.linear_total;\n\n        if new_linear > 0 {\n            self.linear.push(Group {\n                atlas: atlas.clone(),\n                instance_count: new_linear,\n            });\n\n            self.linear_total = linear.len();\n        }\n    }\n\n    fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {\n        render_pass.set_vertex_buffer(0, self.instances.slice(..));\n\n        let mut offset = 0;\n\n        if !self.nearest.is_empty() {\n            render_pass.set_bind_group(0, &self.nearest_layout, &[]);\n\n            for group in &self.nearest {\n                render_pass.set_bind_group(1, group.atlas.as_ref(), &[]);\n                render_pass.draw(0..6, offset..offset + group.instance_count as u32);\n\n                offset += group.instance_count as u32;\n            }\n        }\n\n        if !self.linear.is_empty() {\n            render_pass.set_bind_group(0, &self.linear_layout, &[]);\n\n            for group in &self.linear {\n                render_pass.set_bind_group(1, group.atlas.as_ref(), &[]);\n                render_pass.draw(0..6, offset..offset + group.instance_count as u32);\n\n                offset += group.instance_count as u32;\n            }\n        }\n    }\n\n    fn clear(&mut self) {\n        self.nearest.clear();\n        self.nearest_total = 0;\n\n        self.linear.clear();\n        self.linear_total = 0;\n    }\n}\n\n#[repr(C)]\n#[derive(Debug, Clone, Copy, Zeroable, Pod)]\nstruct Instance {\n    _center: [f32; 2],\n    _clip_bounds: [f32; 4],\n    _border_radius: [f32; 4],\n    _tile: [f32; 4],\n    _rotation: f32,\n    _opacity: f32,\n    _position_in_atlas: [f32; 2],\n    _size_in_atlas: [f32; 2],\n    _layer: u32,\n}\n\nimpl Instance {\n    pub const INITIAL: usize = 20;\n}\n\n#[repr(C)]\n#[derive(Debug, Clone, Copy, Zeroable, Pod)]\nstruct Uniforms {\n    transform: [f32; 16],\n}\n\nfn add_instances(\n    bounds: Rectangle,\n    clip_bounds: Rectangle,\n    border_radius: border::Radius,\n    rotation: f32,\n    opacity: f32,\n    entry: &atlas::Entry,\n    instances: &mut Vec<Instance>,\n) {\n    let center = [\n        bounds.x + bounds.width / 2.0,\n        bounds.y + bounds.height / 2.0,\n    ];\n\n    let clip_bounds = [\n        clip_bounds.x,\n        clip_bounds.y,\n        clip_bounds.width,\n        clip_bounds.height,\n    ];\n\n    let border_radius = border_radius.into();\n\n    match entry {\n        atlas::Entry::Contiguous(allocation) => {\n            add_instance(\n                center,\n                clip_bounds,\n                border_radius,\n                [bounds.x, bounds.y, bounds.width, bounds.height],\n                rotation,\n                opacity,\n                allocation,\n                instances,\n            );\n        }\n        atlas::Entry::Fragmented { fragments, size } => {\n            let scaling_x = bounds.width / size.width as f32;\n            let scaling_y = bounds.height / size.height as f32;\n\n            for fragment in fragments {\n                let allocation = &fragment.allocation;\n                let (fragment_x, fragment_y) = fragment.position;\n\n                let Size {\n                    width: fragment_width,\n                    height: fragment_height,\n                } = allocation.size();\n\n                let tile = [\n                    bounds.x + fragment_x as f32 * scaling_x,\n                    bounds.y + fragment_y as f32 * scaling_y,\n                    fragment_width as f32 * scaling_x,\n                    fragment_height as f32 * scaling_y,\n                ];\n\n                add_instance(\n                    center,\n                    clip_bounds,\n                    border_radius,\n                    tile,\n                    rotation,\n                    opacity,\n                    allocation,\n                    instances,\n                );\n            }\n        }\n    }\n}\n\n#[inline]\nfn add_instance(\n    center: [f32; 2],\n    clip_bounds: [f32; 4],\n    border_radius: [f32; 4],\n    tile: [f32; 4],\n    rotation: f32,\n    opacity: f32,\n    allocation: &atlas::Allocation,\n    instances: &mut Vec<Instance>,\n) {\n    let (x, y) = allocation.position();\n    let Size { width, height } = allocation.size();\n    let layer = allocation.layer();\n    let atlas_size = allocation.atlas_size();\n\n    let instance = Instance {\n        _center: center,\n        _clip_bounds: clip_bounds,\n        _border_radius: border_radius,\n        _tile: tile,\n        _rotation: rotation,\n        _opacity: opacity,\n        _position_in_atlas: [x as f32 / atlas_size as f32, y as f32 / atlas_size as f32],\n        _size_in_atlas: [\n            width as f32 / atlas_size as f32,\n            height as f32 / atlas_size as f32,\n        ],\n        _layer: layer as u32,\n    };\n\n    instances.push(instance);\n}\n"
  },
  {
    "path": "wgpu/src/image/null.rs",
    "content": "pub use crate::graphics::Image;\n\n#[derive(Debug, Default)]\npub struct Batch;\n\nimpl Batch {\n    pub fn push(&mut self, _image: Image) {}\n\n    pub fn clear(&mut self) {}\n\n    pub fn is_empty(&self) -> bool {\n        true\n    }\n\n    pub fn append(&mut self, _batch: &mut Self) {}\n}\n"
  },
  {
    "path": "wgpu/src/image/raster.rs",
    "content": "use crate::core::Size;\nuse crate::core::image;\nuse crate::graphics;\nuse crate::image::atlas::{self, Atlas};\n\nuse rustc_hash::{FxHashMap, FxHashSet};\nuse std::sync::{Arc, Weak};\n\npub type Image = graphics::image::Buffer;\n\n/// Entry in cache corresponding to an image handle\n#[derive(Debug)]\npub enum Memory {\n    /// Image data on host\n    Host(Image),\n    /// Storage entry\n    Device {\n        entry: atlas::Entry,\n        bind_group: Option<Arc<wgpu::BindGroup>>,\n        allocation: Option<Weak<image::Memory>>,\n    },\n    Error(image::Error),\n}\n\nimpl Memory {\n    pub fn load(handle: &image::Handle) -> Self {\n        match graphics::image::load(handle) {\n            Ok(image) => Self::Host(image),\n            Err(error) => Self::Error(error),\n        }\n    }\n\n    pub fn dimensions(&self) -> Size<u32> {\n        match self {\n            Memory::Host(image) => {\n                let (width, height) = image.dimensions();\n\n                Size::new(width, height)\n            }\n            Memory::Device { entry, .. } => entry.size(),\n            Memory::Error(_) => Size::new(1, 1),\n        }\n    }\n\n    pub fn host(&self) -> Option<Image> {\n        match self {\n            Memory::Host(image) => Some(image.clone()),\n            Memory::Device { .. } | Memory::Error(_) => None,\n        }\n    }\n}\n\n#[derive(Debug, Default)]\npub struct Cache {\n    map: FxHashMap<image::Id, Memory>,\n    hits: FxHashSet<image::Id>,\n    should_trim: bool,\n}\n\nimpl Cache {\n    pub fn get_mut(&mut self, handle: &image::Handle) -> Option<&mut Memory> {\n        let _ = self.hits.insert(handle.id());\n\n        self.map.get_mut(&handle.id())\n    }\n\n    pub fn insert(&mut self, handle: &image::Handle, memory: Memory) {\n        let _ = self.map.insert(handle.id(), memory);\n        let _ = self.hits.insert(handle.id());\n\n        self.should_trim = true;\n    }\n\n    pub fn contains(&self, handle: &image::Handle) -> bool {\n        self.map.contains_key(&handle.id())\n    }\n\n    pub fn trim(&mut self, atlas: &mut Atlas, on_drop: impl Fn(Arc<wgpu::BindGroup>)) {\n        // Only trim if new entries have landed in the `Cache`\n        if !self.should_trim {\n            return;\n        }\n\n        let hits = &self.hits;\n\n        self.map.retain(|id, memory| {\n            // Retain active allocations\n            if let Memory::Device { allocation, .. } = memory\n                && allocation\n                    .as_ref()\n                    .is_some_and(|allocation| allocation.strong_count() > 0)\n            {\n                return true;\n            }\n\n            let retain = hits.contains(id);\n\n            if !retain {\n                log::debug!(\"Dropping image allocation: {id:?}\");\n\n                if let Memory::Device {\n                    entry, bind_group, ..\n                } = memory\n                {\n                    if let Some(bind_group) = bind_group.take() {\n                        on_drop(bind_group);\n                    } else {\n                        atlas.remove(entry);\n                    }\n                }\n            }\n\n            retain\n        });\n\n        self.hits.clear();\n        self.should_trim = false;\n    }\n}\n"
  },
  {
    "path": "wgpu/src/image/vector.rs",
    "content": "use crate::core::svg;\nuse crate::core::{Color, Size};\nuse crate::image::atlas::{self, Atlas};\n\nuse resvg::tiny_skia;\nuse resvg::usvg;\nuse rustc_hash::{FxHashMap, FxHashSet};\nuse std::fs;\nuse std::panic;\nuse std::sync::Arc;\n\n/// Entry in cache corresponding to an svg handle\npub enum Svg {\n    /// Parsed svg\n    Loaded(usvg::Tree),\n    /// Svg not found or failed to parse\n    NotFound,\n}\n\nimpl Svg {\n    /// Viewport width and height\n    pub fn viewport_dimensions(&self) -> Size<u32> {\n        match self {\n            Svg::Loaded(tree) => {\n                let size = tree.size();\n\n                Size::new(size.width() as u32, size.height() as u32)\n            }\n            Svg::NotFound => Size::new(1, 1),\n        }\n    }\n}\n\n/// Caches svg vector and raster data\n#[derive(Debug, Default)]\npub struct Cache {\n    svgs: FxHashMap<u64, Svg>,\n    rasterized: FxHashMap<(u64, u32, u32, ColorFilter), atlas::Entry>,\n    svg_hits: FxHashSet<u64>,\n    rasterized_hits: FxHashSet<(u64, u32, u32, ColorFilter)>,\n    should_trim: bool,\n    fontdb: Option<Arc<usvg::fontdb::Database>>,\n}\n\ntype ColorFilter = Option<[u8; 4]>;\n\nimpl Cache {\n    /// Load svg\n    pub fn load(&mut self, handle: &svg::Handle) -> &Svg {\n        if self.svgs.contains_key(&handle.id()) {\n            return self.svgs.get(&handle.id()).unwrap();\n        }\n\n        // TODO: Reuse `cosmic-text` font database\n        if self.fontdb.is_none() {\n            let mut fontdb = usvg::fontdb::Database::new();\n            fontdb.load_system_fonts();\n\n            self.fontdb = Some(Arc::new(fontdb));\n        }\n\n        let options = usvg::Options {\n            fontdb: self\n                .fontdb\n                .as_ref()\n                .expect(\"fontdb must be initialized\")\n                .clone(),\n            ..usvg::Options::default()\n        };\n\n        let svg = match handle.data() {\n            svg::Data::Path(path) => fs::read_to_string(path)\n                .ok()\n                .and_then(|contents| usvg::Tree::from_str(&contents, &options).ok())\n                .map(Svg::Loaded)\n                .unwrap_or(Svg::NotFound),\n            svg::Data::Bytes(bytes) => match usvg::Tree::from_data(bytes, &options) {\n                Ok(tree) => Svg::Loaded(tree),\n                Err(_) => Svg::NotFound,\n            },\n        };\n\n        self.should_trim = true;\n\n        let _ = self.svgs.insert(handle.id(), svg);\n        self.svgs.get(&handle.id()).unwrap()\n    }\n\n    /// Load svg and upload raster data\n    pub fn upload(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        handle: &svg::Handle,\n        color: Option<Color>,\n        size: Size<u32>,\n        atlas: &mut Atlas,\n    ) -> Option<&atlas::Entry> {\n        let id = handle.id();\n\n        let color = color.map(Color::into_rgba8);\n        let key = (id, size.width, size.height, color);\n\n        // TODO: Optimize!\n        // We currently rerasterize the SVG when its size changes. This is slow\n        // as heck. A GPU rasterizer like `pathfinder` may perform better.\n        // It would be cool to be able to smooth resize the `svg` example.\n        if self.rasterized.contains_key(&key) {\n            let _ = self.svg_hits.insert(id);\n            let _ = self.rasterized_hits.insert(key);\n\n            return self.rasterized.get(&key);\n        }\n\n        match self.load(handle) {\n            Svg::Loaded(tree) => {\n                // TODO: Optimize!\n                // We currently rerasterize the SVG when its size changes. This is slow\n                // as heck. A GPU rasterizer like `pathfinder` may perform better.\n                // It would be cool to be able to smooth resize the `svg` example.\n                let mut img = tiny_skia::Pixmap::new(size.width, size.height)?;\n\n                let tree_size = tree.size().to_int_size();\n\n                let target_size = if size.width > size.height {\n                    tree_size.scale_to_height(size.height)\n                } else {\n                    tree_size.scale_to_width(size.width)\n                };\n\n                let transform = if let Some(target_size) = target_size {\n                    let tree_size = tree_size.to_size();\n                    let target_size = target_size.to_size();\n\n                    tiny_skia::Transform::from_scale(\n                        target_size.width() / tree_size.width(),\n                        target_size.height() / tree_size.height(),\n                    )\n                } else {\n                    tiny_skia::Transform::default()\n                };\n\n                // SVG rendering can panic on malformed or complex vectors.\n                // We catch panics to prevent crashes and continue gracefully.\n                let render = panic::catch_unwind(panic::AssertUnwindSafe(|| {\n                    resvg::render(tree, transform, &mut img.as_mut());\n                }));\n\n                if let Err(error) = render {\n                    log::warn!(\"SVG rendering for {handle:?} panicked: {error:?}\");\n                }\n\n                let mut rgba = img.take();\n\n                if let Some(color) = color {\n                    rgba.chunks_exact_mut(4).for_each(|rgba| {\n                        if rgba[3] > 0 {\n                            rgba[0] = color[0];\n                            rgba[1] = color[1];\n                            rgba[2] = color[2];\n                        }\n                    });\n                }\n\n                let allocation =\n                    atlas.upload(device, encoder, belt, size.width, size.height, &rgba)?;\n\n                log::debug!(\"allocating {id} {}x{}\", size.width, size.height);\n\n                let _ = self.svg_hits.insert(id);\n                let _ = self.rasterized_hits.insert(key);\n                let _ = self.rasterized.insert(key, allocation);\n                self.should_trim = true;\n\n                self.rasterized.get(&key)\n            }\n            Svg::NotFound => None,\n        }\n    }\n\n    /// Load svg and upload raster data\n    pub fn trim(&mut self, atlas: &mut Atlas) {\n        if !self.should_trim {\n            return;\n        }\n\n        let svg_hits = &self.svg_hits;\n        let rasterized_hits = &self.rasterized_hits;\n\n        self.svgs.retain(|k, _| svg_hits.contains(k));\n        self.rasterized.retain(|k, entry| {\n            let retain = rasterized_hits.contains(k);\n\n            if !retain {\n                atlas.remove(entry);\n            }\n\n            retain\n        });\n        self.svg_hits.clear();\n        self.rasterized_hits.clear();\n        self.should_trim = false;\n    }\n}\n\nimpl std::fmt::Debug for Svg {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Svg::Loaded(_) => write!(f, \"Svg::Loaded\"),\n            Svg::NotFound => write!(f, \"Svg::NotFound\"),\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/layer.rs",
    "content": "use crate::core::{self, Background, Color, Point, Rectangle, Svg, Transformation, renderer};\nuse crate::graphics;\nuse crate::graphics::Mesh;\nuse crate::graphics::color;\nuse crate::graphics::layer;\nuse crate::graphics::mesh;\nuse crate::graphics::text::{Editor, Paragraph};\nuse crate::image::{self, Image};\nuse crate::primitive::{self, Primitive};\nuse crate::quad::{self, Quad};\nuse crate::text::{self, Text};\nuse crate::triangle;\n\npub type Stack = layer::Stack<Layer>;\n\n#[derive(Debug)]\npub struct Layer {\n    pub bounds: Rectangle,\n    pub quads: quad::Batch,\n    pub triangles: triangle::Batch,\n    pub primitives: primitive::Batch,\n    pub images: image::Batch,\n    pub text: text::Batch,\n    pending_meshes: Vec<Mesh>,\n    pending_text: Vec<Text>,\n}\n\nimpl Layer {\n    pub fn is_empty(&self) -> bool {\n        self.quads.is_empty()\n            && self.triangles.is_empty()\n            && self.primitives.is_empty()\n            && self.images.is_empty()\n            && self.text.is_empty()\n            && self.pending_meshes.is_empty()\n            && self.pending_text.is_empty()\n    }\n\n    pub fn draw_quad(\n        &mut self,\n        quad: renderer::Quad,\n        background: Background,\n        transformation: Transformation,\n    ) {\n        let bounds = quad.bounds * transformation;\n\n        let quad = Quad {\n            position: [bounds.x, bounds.y],\n            size: [bounds.width, bounds.height],\n            border_color: color::pack(quad.border.color),\n            border_radius: (quad.border.radius * transformation.scale_factor()).into(),\n            border_width: quad.border.width * transformation.scale_factor(),\n            shadow_color: color::pack(quad.shadow.color),\n            shadow_offset: (quad.shadow.offset * transformation.scale_factor()).into(),\n            shadow_blur_radius: quad.shadow.blur_radius * transformation.scale_factor(),\n            snap: quad.snap as u32,\n        };\n\n        self.quads.add(quad, &background);\n    }\n\n    pub fn draw_paragraph(\n        &mut self,\n        paragraph: &Paragraph,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let paragraph = Text::Paragraph {\n            paragraph: paragraph.downgrade(),\n            position,\n            color,\n            clip_bounds,\n            transformation,\n        };\n\n        self.pending_text.push(paragraph);\n    }\n\n    pub fn draw_editor(\n        &mut self,\n        editor: &Editor,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let editor = Text::Editor {\n            editor: editor.downgrade(),\n            position,\n            color,\n            clip_bounds,\n            transformation,\n        };\n\n        self.pending_text.push(editor);\n    }\n\n    pub fn draw_text(\n        &mut self,\n        text: crate::core::Text,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let text = Text::Cached {\n            content: text.content,\n            bounds: Rectangle::new(position, text.bounds) * transformation,\n            color,\n            size: text.size * transformation.scale_factor(),\n            line_height: text.line_height.to_absolute(text.size) * transformation.scale_factor(),\n            font: text.font,\n            align_x: text.align_x,\n            align_y: text.align_y,\n            shaping: text.shaping,\n            wrapping: text.wrapping,\n            ellipsis: text.ellipsis,\n            clip_bounds: clip_bounds * transformation,\n        };\n\n        self.pending_text.push(text);\n    }\n\n    pub fn draw_text_raw(&mut self, raw: graphics::text::Raw, transformation: Transformation) {\n        let raw = Text::Raw {\n            raw,\n            transformation,\n        };\n\n        self.pending_text.push(raw);\n    }\n\n    pub fn draw_image(&mut self, image: Image, transformation: Transformation) {\n        match image {\n            Image::Raster {\n                image,\n                bounds,\n                clip_bounds,\n            } => {\n                self.draw_raster(image, bounds, clip_bounds, transformation);\n            }\n            Image::Vector {\n                svg,\n                bounds,\n                clip_bounds,\n            } => {\n                self.draw_svg(svg, bounds, clip_bounds, transformation);\n            }\n        }\n    }\n\n    pub fn draw_raster(\n        &mut self,\n        image: core::Image,\n        bounds: Rectangle,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let image = Image::Raster {\n            image: core::Image {\n                border_radius: image.border_radius * transformation.scale_factor(),\n                ..image\n            },\n            bounds: bounds * transformation,\n            clip_bounds: clip_bounds * transformation,\n        };\n\n        self.images.push(image);\n    }\n\n    pub fn draw_svg(\n        &mut self,\n        svg: Svg,\n        bounds: Rectangle,\n        clip_bounds: Rectangle,\n        transformation: Transformation,\n    ) {\n        let svg = Image::Vector {\n            svg,\n            bounds: bounds * transformation,\n            clip_bounds: clip_bounds * transformation,\n        };\n\n        self.images.push(svg);\n    }\n\n    pub fn draw_mesh(&mut self, mut mesh: Mesh, transformation: Transformation) {\n        match &mut mesh {\n            Mesh::Solid {\n                transformation: local_transformation,\n                ..\n            }\n            | Mesh::Gradient {\n                transformation: local_transformation,\n                ..\n            } => {\n                *local_transformation = *local_transformation * transformation;\n            }\n        }\n\n        self.pending_meshes.push(mesh);\n    }\n\n    pub fn draw_mesh_group(&mut self, meshes: Vec<Mesh>, transformation: Transformation) {\n        self.flush_meshes();\n\n        self.triangles.push(triangle::Item::Group {\n            meshes,\n            transformation,\n        });\n    }\n\n    pub fn draw_mesh_cache(&mut self, cache: mesh::Cache, transformation: Transformation) {\n        self.flush_meshes();\n\n        self.triangles.push(triangle::Item::Cached {\n            cache,\n            transformation,\n        });\n    }\n\n    pub fn draw_text_group(&mut self, text: Vec<Text>, transformation: Transformation) {\n        self.flush_text();\n\n        self.text.push(text::Item::Group {\n            text,\n            transformation,\n        });\n    }\n\n    pub fn draw_text_cache(&mut self, cache: text::Cache, transformation: Transformation) {\n        self.flush_text();\n\n        self.text.push(text::Item::Cached {\n            cache,\n            transformation,\n        });\n    }\n\n    pub fn draw_primitive(\n        &mut self,\n        bounds: Rectangle,\n        primitive: impl Primitive,\n        transformation: Transformation,\n    ) {\n        let bounds = bounds * transformation;\n\n        self.primitives\n            .push(primitive::Instance::new(bounds, primitive));\n    }\n\n    fn flush_meshes(&mut self) {\n        if !self.pending_meshes.is_empty() {\n            self.triangles.push(triangle::Item::Group {\n                transformation: Transformation::IDENTITY,\n                meshes: self.pending_meshes.drain(..).collect(),\n            });\n        }\n    }\n\n    fn flush_text(&mut self) {\n        if !self.pending_text.is_empty() {\n            self.text.push(text::Item::Group {\n                transformation: Transformation::IDENTITY,\n                text: self.pending_text.drain(..).collect(),\n            });\n        }\n    }\n}\n\nimpl graphics::Layer for Layer {\n    fn with_bounds(bounds: Rectangle) -> Self {\n        Self {\n            bounds,\n            ..Self::default()\n        }\n    }\n\n    fn bounds(&self) -> Rectangle {\n        self.bounds\n    }\n\n    fn flush(&mut self) {\n        self.flush_meshes();\n        self.flush_text();\n    }\n\n    fn resize(&mut self, bounds: Rectangle) {\n        self.bounds = bounds;\n    }\n\n    fn reset(&mut self) {\n        self.bounds = Rectangle::INFINITE;\n\n        self.quads.clear();\n        self.triangles.clear();\n        self.primitives.clear();\n        self.text.clear();\n        self.images.clear();\n        self.pending_meshes.clear();\n        self.pending_text.clear();\n    }\n\n    fn start(&self) -> usize {\n        if !self.quads.is_empty() {\n            return 1;\n        }\n\n        if !self.triangles.is_empty() {\n            return 2;\n        }\n\n        if !self.primitives.is_empty() {\n            return 3;\n        }\n\n        if !self.images.is_empty() {\n            return 4;\n        }\n\n        if !self.text.is_empty() {\n            return 5;\n        }\n\n        usize::MAX\n    }\n\n    fn end(&self) -> usize {\n        if !self.text.is_empty() {\n            return 5;\n        }\n\n        if !self.images.is_empty() {\n            return 4;\n        }\n\n        if !self.primitives.is_empty() {\n            return 3;\n        }\n\n        if !self.triangles.is_empty() {\n            return 2;\n        }\n\n        if !self.quads.is_empty() {\n            return 1;\n        }\n\n        0\n    }\n\n    fn merge(&mut self, layer: &mut Self) {\n        self.quads.append(&mut layer.quads);\n        self.triangles.append(&mut layer.triangles);\n        self.primitives.append(&mut layer.primitives);\n        self.images.append(&mut layer.images);\n        self.text.append(&mut layer.text);\n    }\n}\n\nimpl Default for Layer {\n    fn default() -> Self {\n        Self {\n            bounds: Rectangle::INFINITE,\n            quads: quad::Batch::default(),\n            triangles: triangle::Batch::default(),\n            primitives: primitive::Batch::default(),\n            text: text::Batch::default(),\n            images: image::Batch::default(),\n            pending_meshes: Vec::new(),\n            pending_text: Vec::new(),\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/lib.rs",
    "content": "//! A [`wgpu`] renderer for [Iced].\n//!\n//! ![The native path of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)\n//!\n//! [`wgpu`] supports most modern graphics backends: Vulkan, Metal, DX11, and\n//! DX12 (OpenGL and WebGL are still WIP). Additionally, it will support the\n//! incoming [WebGPU API].\n//!\n//! Currently, `iced_wgpu` supports the following primitives:\n//! - Text, which is rendered using [`glyphon`].\n//! - Quads or rectangles, with rounded borders and a solid background color.\n//! - Clip areas, useful to implement scrollables or hide overflowing content.\n//! - Images and SVG, loaded from memory or the file system.\n//! - Meshes of triangles, useful to draw geometry freely.\n//!\n//! [Iced]: https://github.com/iced-rs/iced\n//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs\n//! [WebGPU API]: https://gpuweb.github.io/gpuweb/\n//! [`glyphon`]: https://github.com/grovesNL/glyphon\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg\"\n)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n#![allow(missing_docs)]\npub mod layer;\npub mod primitive;\npub mod window;\n\n#[cfg(feature = \"geometry\")]\npub mod geometry;\n\nmod buffer;\nmod color;\nmod engine;\nmod quad;\nmod text;\nmod triangle;\n\n#[cfg(any(feature = \"image\", feature = \"svg\"))]\n#[path = \"image/mod.rs\"]\nmod image;\n\n#[cfg(not(any(feature = \"image\", feature = \"svg\")))]\n#[path = \"image/null.rs\"]\nmod image;\n\nuse buffer::Buffer;\n\nuse iced_debug as debug;\npub use iced_graphics as graphics;\npub use iced_graphics::core;\n\npub use wgpu;\n\npub use engine::Engine;\npub use layer::Layer;\npub use primitive::Primitive;\n\n#[cfg(feature = \"geometry\")]\npub use geometry::Geometry;\n\nuse crate::core::renderer;\nuse crate::core::{Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation};\nuse crate::graphics::mesh;\nuse crate::graphics::text::{Editor, Paragraph};\nuse crate::graphics::{Shell, Viewport};\n\n/// A [`wgpu`] graphics renderer for [`iced`].\n///\n/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs\n/// [`iced`]: https://github.com/iced-rs/iced\npub struct Renderer {\n    engine: Engine,\n    settings: renderer::Settings,\n\n    layers: layer::Stack,\n    scale_factor: Option<f32>,\n\n    quad: quad::State,\n    triangle: triangle::State,\n    text: text::State,\n    text_viewport: text::Viewport,\n\n    #[cfg(any(feature = \"svg\", feature = \"image\"))]\n    image: image::State,\n\n    // TODO: Centralize all the image feature handling\n    #[cfg(any(feature = \"svg\", feature = \"image\"))]\n    image_cache: std::cell::RefCell<image::Cache>,\n\n    staging_belt: wgpu::util::StagingBelt,\n}\n\nimpl Renderer {\n    pub fn new(engine: Engine, settings: renderer::Settings) -> Self {\n        Self {\n            settings,\n            layers: layer::Stack::new(),\n            scale_factor: None,\n\n            quad: quad::State::new(),\n            triangle: triangle::State::new(&engine.device, &engine.triangle_pipeline),\n            text: text::State::new(),\n            text_viewport: engine.text_pipeline.create_viewport(&engine.device),\n\n            #[cfg(any(feature = \"svg\", feature = \"image\"))]\n            image: image::State::new(),\n\n            #[cfg(any(feature = \"svg\", feature = \"image\"))]\n            image_cache: std::cell::RefCell::new(engine.create_image_cache()),\n\n            // TODO: Resize belt smartly (?)\n            // It would be great if the `StagingBelt` API exposed methods\n            // for introspection to detect when a resize may be worth it.\n            staging_belt: wgpu::util::StagingBelt::new(\n                engine.device.clone(),\n                buffer::MAX_WRITE_SIZE as u64,\n            ),\n\n            engine,\n        }\n    }\n\n    fn draw(\n        &mut self,\n        clear_color: Option<Color>,\n        target: &wgpu::TextureView,\n        viewport: &Viewport,\n    ) -> wgpu::CommandEncoder {\n        let mut encoder =\n            self.engine\n                .device\n                .create_command_encoder(&wgpu::CommandEncoderDescriptor {\n                    label: Some(\"iced_wgpu encoder\"),\n                });\n\n        self.prepare(&mut encoder, viewport);\n        self.render(&mut encoder, target, clear_color, viewport);\n\n        self.quad.trim();\n        self.triangle.trim();\n        self.text.trim();\n\n        // TODO: Provide window id (?)\n        self.engine.trim();\n\n        #[cfg(any(feature = \"svg\", feature = \"image\"))]\n        {\n            self.image.trim();\n            self.image_cache.borrow_mut().trim();\n        }\n\n        encoder\n    }\n\n    pub fn present(\n        &mut self,\n        clear_color: Option<Color>,\n        _format: wgpu::TextureFormat,\n        frame: &wgpu::TextureView,\n        viewport: &Viewport,\n    ) -> wgpu::SubmissionIndex {\n        let encoder = self.draw(clear_color, frame, viewport);\n\n        self.staging_belt.finish();\n        let submission = self.engine.queue.submit([encoder.finish()]);\n        self.staging_belt.recall();\n        submission\n    }\n\n    /// Renders the current surface to an offscreen buffer.\n    ///\n    /// Returns RGBA bytes of the texture data.\n    pub fn screenshot(&mut self, viewport: &Viewport, background_color: Color) -> Vec<u8> {\n        #[derive(Clone, Copy, Debug)]\n        struct BufferDimensions {\n            width: u32,\n            height: u32,\n            unpadded_bytes_per_row: usize,\n            padded_bytes_per_row: usize,\n        }\n\n        impl BufferDimensions {\n            fn new(size: Size<u32>) -> Self {\n                let unpadded_bytes_per_row = size.width as usize * 4; //slice of buffer per row; always RGBA\n                let alignment = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize; //256\n                let padded_bytes_per_row_padding =\n                    (alignment - unpadded_bytes_per_row % alignment) % alignment;\n                let padded_bytes_per_row = unpadded_bytes_per_row + padded_bytes_per_row_padding;\n\n                Self {\n                    width: size.width,\n                    height: size.height,\n                    unpadded_bytes_per_row,\n                    padded_bytes_per_row,\n                }\n            }\n        }\n\n        let dimensions = BufferDimensions::new(viewport.physical_size());\n\n        let texture_extent = wgpu::Extent3d {\n            width: dimensions.width,\n            height: dimensions.height,\n            depth_or_array_layers: 1,\n        };\n\n        let texture = self.engine.device.create_texture(&wgpu::TextureDescriptor {\n            label: Some(\"iced_wgpu.offscreen.source_texture\"),\n            size: texture_extent,\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format: self.engine.format,\n            usage: wgpu::TextureUsages::RENDER_ATTACHMENT\n                | wgpu::TextureUsages::COPY_SRC\n                | wgpu::TextureUsages::TEXTURE_BINDING,\n            view_formats: &[],\n        });\n\n        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());\n\n        let mut encoder = self.draw(Some(background_color), &view, viewport);\n\n        let texture = crate::color::convert(\n            &self.engine.device,\n            &mut encoder,\n            texture,\n            if graphics::color::GAMMA_CORRECTION {\n                wgpu::TextureFormat::Rgba8UnormSrgb\n            } else {\n                wgpu::TextureFormat::Rgba8Unorm\n            },\n        );\n\n        let output_buffer = self.engine.device.create_buffer(&wgpu::BufferDescriptor {\n            label: Some(\"iced_wgpu.offscreen.output_texture_buffer\"),\n            size: (dimensions.padded_bytes_per_row * dimensions.height as usize) as u64,\n            usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,\n            mapped_at_creation: false,\n        });\n\n        encoder.copy_texture_to_buffer(\n            texture.as_image_copy(),\n            wgpu::TexelCopyBufferInfo {\n                buffer: &output_buffer,\n                layout: wgpu::TexelCopyBufferLayout {\n                    offset: 0,\n                    bytes_per_row: Some(dimensions.padded_bytes_per_row as u32),\n                    rows_per_image: None,\n                },\n            },\n            texture_extent,\n        );\n\n        self.staging_belt.finish();\n        let index = self.engine.queue.submit([encoder.finish()]);\n        self.staging_belt.recall();\n\n        let slice = output_buffer.slice(..);\n        slice.map_async(wgpu::MapMode::Read, |_| {});\n\n        let _ = self.engine.device.poll(wgpu::PollType::Wait {\n            submission_index: Some(index),\n            timeout: None,\n        });\n\n        let mapped_buffer = slice.get_mapped_range();\n\n        mapped_buffer\n            .chunks(dimensions.padded_bytes_per_row)\n            .fold(vec![], |mut acc, row| {\n                acc.extend(&row[..dimensions.unpadded_bytes_per_row]);\n                acc\n            })\n    }\n\n    fn prepare(&mut self, encoder: &mut wgpu::CommandEncoder, viewport: &Viewport) {\n        let scale_factor = viewport.scale_factor();\n\n        self.text_viewport\n            .update(&self.engine.queue, viewport.physical_size());\n\n        let physical_bounds =\n            Rectangle::<f32>::from(Rectangle::with_size(viewport.physical_size()));\n\n        self.layers.merge();\n\n        for layer in self.layers.iter() {\n            let clip_bounds = layer.bounds * scale_factor;\n\n            if physical_bounds\n                .intersection(&clip_bounds)\n                .and_then(Rectangle::snap)\n                .is_none()\n            {\n                continue;\n            }\n\n            if !layer.quads.is_empty() {\n                let prepare_span = debug::prepare(debug::Primitive::Quad);\n\n                self.quad.prepare(\n                    &self.engine.quad_pipeline,\n                    &self.engine.device,\n                    &mut self.staging_belt,\n                    encoder,\n                    &layer.quads,\n                    viewport.projection(),\n                    scale_factor,\n                );\n\n                prepare_span.finish();\n            }\n\n            if !layer.triangles.is_empty() {\n                let prepare_span = debug::prepare(debug::Primitive::Triangle);\n\n                self.triangle.prepare(\n                    &self.engine.triangle_pipeline,\n                    &self.engine.device,\n                    &mut self.staging_belt,\n                    encoder,\n                    &layer.triangles,\n                    Transformation::scale(scale_factor),\n                    viewport.physical_size(),\n                );\n\n                prepare_span.finish();\n            }\n\n            if !layer.primitives.is_empty() {\n                let prepare_span = debug::prepare(debug::Primitive::Shader);\n\n                let mut primitive_storage = self\n                    .engine\n                    .primitive_storage\n                    .write()\n                    .expect(\"Write primitive storage\");\n\n                for instance in &layer.primitives {\n                    instance.primitive.prepare(\n                        &mut primitive_storage,\n                        &self.engine.device,\n                        &self.engine.queue,\n                        self.engine.format,\n                        &instance.bounds,\n                        viewport,\n                    );\n                }\n\n                prepare_span.finish();\n            }\n\n            #[cfg(any(feature = \"svg\", feature = \"image\"))]\n            if !layer.images.is_empty() {\n                let prepare_span = debug::prepare(debug::Primitive::Image);\n\n                self.image.prepare(\n                    &self.engine.image_pipeline,\n                    &self.engine.device,\n                    &mut self.staging_belt,\n                    encoder,\n                    &mut self.image_cache.borrow_mut(),\n                    &layer.images,\n                    viewport.projection(),\n                    scale_factor,\n                );\n\n                prepare_span.finish();\n            }\n\n            if !layer.text.is_empty() {\n                let prepare_span = debug::prepare(debug::Primitive::Text);\n\n                self.text.prepare(\n                    &self.engine.text_pipeline,\n                    &self.engine.device,\n                    &self.engine.queue,\n                    &self.text_viewport,\n                    encoder,\n                    &layer.text,\n                    layer.bounds,\n                    Transformation::scale(scale_factor),\n                );\n\n                prepare_span.finish();\n            }\n        }\n    }\n\n    fn render(\n        &mut self,\n        encoder: &mut wgpu::CommandEncoder,\n        frame: &wgpu::TextureView,\n        clear_color: Option<Color>,\n        viewport: &Viewport,\n    ) {\n        use std::mem::ManuallyDrop;\n\n        let mut render_pass =\n            ManuallyDrop::new(encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n                label: Some(\"iced_wgpu render pass\"),\n                color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                    view: frame,\n                    depth_slice: None,\n                    resolve_target: None,\n                    ops: wgpu::Operations {\n                        load: match clear_color {\n                            Some(background_color) => wgpu::LoadOp::Clear({\n                                let [r, g, b, a] =\n                                    graphics::color::pack(background_color).components();\n\n                                wgpu::Color {\n                                    r: f64::from(r * a),\n                                    g: f64::from(g * a),\n                                    b: f64::from(b * a),\n                                    a: f64::from(a),\n                                }\n                            }),\n                            None => wgpu::LoadOp::Load,\n                        },\n                        store: wgpu::StoreOp::Store,\n                    },\n                })],\n                depth_stencil_attachment: None,\n                timestamp_writes: None,\n                occlusion_query_set: None,\n                multiview_mask: None,\n            }));\n\n        let mut quad_layer = 0;\n        let mut mesh_layer = 0;\n        let mut text_layer = 0;\n\n        #[cfg(any(feature = \"svg\", feature = \"image\"))]\n        let mut image_layer = 0;\n\n        let scale_factor = viewport.scale_factor();\n        let physical_bounds =\n            Rectangle::<f32>::from(Rectangle::with_size(viewport.physical_size()));\n\n        let scale = Transformation::scale(scale_factor);\n\n        for layer in self.layers.iter() {\n            let Some(physical_bounds) =\n                physical_bounds.intersection(&(layer.bounds * scale_factor))\n            else {\n                continue;\n            };\n\n            let Some(scissor_rect) = physical_bounds.snap() else {\n                continue;\n            };\n\n            if !layer.quads.is_empty() {\n                let render_span = debug::render(debug::Primitive::Quad);\n                self.quad.render(\n                    &self.engine.quad_pipeline,\n                    quad_layer,\n                    scissor_rect,\n                    &layer.quads,\n                    &mut render_pass,\n                );\n                render_span.finish();\n\n                quad_layer += 1;\n            }\n\n            if !layer.triangles.is_empty() {\n                let _ = ManuallyDrop::into_inner(render_pass);\n\n                let render_span = debug::render(debug::Primitive::Triangle);\n                mesh_layer += self.triangle.render(\n                    &self.engine.triangle_pipeline,\n                    encoder,\n                    frame,\n                    mesh_layer,\n                    &layer.triangles,\n                    physical_bounds,\n                    scale,\n                );\n                render_span.finish();\n\n                render_pass =\n                    ManuallyDrop::new(encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n                        label: Some(\"iced_wgpu render pass\"),\n                        color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                            view: frame,\n                            depth_slice: None,\n                            resolve_target: None,\n                            ops: wgpu::Operations {\n                                load: wgpu::LoadOp::Load,\n                                store: wgpu::StoreOp::Store,\n                            },\n                        })],\n                        depth_stencil_attachment: None,\n                        timestamp_writes: None,\n                        occlusion_query_set: None,\n                        multiview_mask: None,\n                    }));\n            }\n\n            if !layer.primitives.is_empty() {\n                let render_span = debug::render(debug::Primitive::Shader);\n\n                let primitive_storage = self\n                    .engine\n                    .primitive_storage\n                    .read()\n                    .expect(\"Read primitive storage\");\n\n                let mut need_render = Vec::new();\n\n                for instance in &layer.primitives {\n                    let bounds = instance.bounds * scale;\n\n                    if let Some(clip_bounds) = (instance.bounds * scale)\n                        .intersection(&physical_bounds)\n                        .and_then(Rectangle::snap)\n                    {\n                        render_pass.set_viewport(\n                            bounds.x,\n                            bounds.y,\n                            bounds.width,\n                            bounds.height,\n                            0.0,\n                            1.0,\n                        );\n\n                        render_pass.set_scissor_rect(\n                            clip_bounds.x,\n                            clip_bounds.y,\n                            clip_bounds.width,\n                            clip_bounds.height,\n                        );\n\n                        let drawn = instance\n                            .primitive\n                            .draw(&primitive_storage, &mut render_pass);\n\n                        if !drawn {\n                            need_render.push((instance, clip_bounds));\n                        }\n                    }\n                }\n\n                render_pass.set_viewport(\n                    0.0,\n                    0.0,\n                    viewport.physical_width() as f32,\n                    viewport.physical_height() as f32,\n                    0.0,\n                    1.0,\n                );\n\n                render_pass.set_scissor_rect(\n                    0,\n                    0,\n                    viewport.physical_width(),\n                    viewport.physical_height(),\n                );\n\n                if !need_render.is_empty() {\n                    let _ = ManuallyDrop::into_inner(render_pass);\n\n                    for (instance, clip_bounds) in need_render {\n                        instance\n                            .primitive\n                            .render(&primitive_storage, encoder, frame, &clip_bounds);\n                    }\n\n                    render_pass =\n                        ManuallyDrop::new(encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n                            label: Some(\"iced_wgpu render pass\"),\n                            color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                                view: frame,\n                                depth_slice: None,\n                                resolve_target: None,\n                                ops: wgpu::Operations {\n                                    load: wgpu::LoadOp::Load,\n                                    store: wgpu::StoreOp::Store,\n                                },\n                            })],\n                            depth_stencil_attachment: None,\n                            timestamp_writes: None,\n                            occlusion_query_set: None,\n                            multiview_mask: None,\n                        }));\n                }\n\n                render_span.finish();\n            }\n\n            #[cfg(any(feature = \"svg\", feature = \"image\"))]\n            if !layer.images.is_empty() {\n                let render_span = debug::render(debug::Primitive::Image);\n                self.image.render(\n                    &self.engine.image_pipeline,\n                    image_layer,\n                    scissor_rect,\n                    &mut render_pass,\n                );\n                render_span.finish();\n\n                image_layer += 1;\n            }\n\n            if !layer.text.is_empty() {\n                let render_span = debug::render(debug::Primitive::Text);\n                text_layer += self.text.render(\n                    &self.engine.text_pipeline,\n                    &self.text_viewport,\n                    text_layer,\n                    &layer.text,\n                    scissor_rect,\n                    &mut render_pass,\n                );\n                render_span.finish();\n            }\n        }\n\n        let _ = ManuallyDrop::into_inner(render_pass);\n\n        debug::layers_rendered(|| {\n            self.layers\n                .iter()\n                .filter(|layer| {\n                    !layer.is_empty()\n                        && physical_bounds\n                            .intersection(&(layer.bounds * scale_factor))\n                            .is_some_and(|viewport| viewport.snap().is_some())\n                })\n                .count()\n        });\n    }\n}\n\nimpl core::Renderer for Renderer {\n    fn start_layer(&mut self, bounds: Rectangle) {\n        self.layers.push_clip(bounds);\n    }\n\n    fn end_layer(&mut self) {\n        self.layers.pop_clip();\n    }\n\n    fn start_transformation(&mut self, transformation: Transformation) {\n        self.layers.push_transformation(transformation);\n    }\n\n    fn end_transformation(&mut self) {\n        self.layers.pop_transformation();\n    }\n\n    fn fill_quad(&mut self, quad: core::renderer::Quad, background: impl Into<Background>) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_quad(quad, background.into(), transformation);\n    }\n\n    fn allocate_image(\n        &mut self,\n        _handle: &core::image::Handle,\n        _callback: impl FnOnce(Result<core::image::Allocation, core::image::Error>) + Send + 'static,\n    ) {\n        #[cfg(feature = \"image\")]\n        self.image_cache\n            .get_mut()\n            .allocate_image(_handle, _callback);\n    }\n\n    fn hint(&mut self, scale_factor: f32) {\n        self.scale_factor = Some(scale_factor);\n    }\n\n    fn scale_factor(&self) -> Option<f32> {\n        Some(self.scale_factor? * self.layers.transformation().scale_factor())\n    }\n\n    fn tick(&mut self) {\n        #[cfg(feature = \"image\")]\n        self.image_cache.get_mut().receive();\n    }\n\n    fn reset(&mut self, new_bounds: Rectangle) {\n        self.layers.reset(new_bounds);\n    }\n}\n\nimpl core::text::Renderer for Renderer {\n    type Font = Font;\n    type Paragraph = Paragraph;\n    type Editor = Editor;\n\n    const ICON_FONT: Font = Font::new(\"Iced-Icons\");\n    const CHECKMARK_ICON: char = '\\u{f00c}';\n    const ARROW_DOWN_ICON: char = '\\u{e800}';\n    const ICED_LOGO: char = '\\u{e801}';\n    const SCROLL_UP_ICON: char = '\\u{e802}';\n    const SCROLL_DOWN_ICON: char = '\\u{e803}';\n    const SCROLL_LEFT_ICON: char = '\\u{e804}';\n    const SCROLL_RIGHT_ICON: char = '\\u{e805}';\n\n    fn default_font(&self) -> Self::Font {\n        self.settings.default_font\n    }\n\n    fn default_size(&self) -> Pixels {\n        self.settings.default_text_size\n    }\n\n    fn fill_paragraph(\n        &mut self,\n        text: &Self::Paragraph,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        let (layer, transformation) = self.layers.current_mut();\n\n        layer.draw_paragraph(text, position, color, clip_bounds, transformation);\n    }\n\n    fn fill_editor(\n        &mut self,\n        editor: &Self::Editor,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_editor(editor, position, color, clip_bounds, transformation);\n    }\n\n    fn fill_text(\n        &mut self,\n        text: core::Text,\n        position: Point,\n        color: Color,\n        clip_bounds: Rectangle,\n    ) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_text(text, position, color, clip_bounds, transformation);\n    }\n}\n\nimpl graphics::text::Renderer for Renderer {\n    fn fill_raw(&mut self, raw: graphics::text::Raw) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_text_raw(raw, transformation);\n    }\n}\n\n#[cfg(feature = \"image\")]\nimpl core::image::Renderer for Renderer {\n    type Handle = core::image::Handle;\n\n    fn load_image(\n        &self,\n        handle: &Self::Handle,\n    ) -> Result<core::image::Allocation, core::image::Error> {\n        self.image_cache\n            .borrow_mut()\n            .load_image(&self.engine.device, &self.engine.queue, handle)\n    }\n\n    fn measure_image(&self, handle: &Self::Handle) -> Option<core::Size<u32>> {\n        self.image_cache.borrow_mut().measure_image(handle)\n    }\n\n    fn draw_image(&mut self, image: core::Image, bounds: Rectangle, clip_bounds: Rectangle) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_raster(image, bounds, clip_bounds, transformation);\n    }\n}\n\n#[cfg(feature = \"svg\")]\nimpl core::svg::Renderer for Renderer {\n    fn measure_svg(&self, handle: &core::svg::Handle) -> core::Size<u32> {\n        self.image_cache.borrow_mut().measure_svg(handle)\n    }\n\n    fn draw_svg(&mut self, svg: core::Svg, bounds: Rectangle, clip_bounds: Rectangle) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_svg(svg, bounds, clip_bounds, transformation);\n    }\n}\n\nimpl graphics::mesh::Renderer for Renderer {\n    fn draw_mesh(&mut self, mesh: graphics::Mesh) {\n        debug_assert!(\n            !mesh.indices().is_empty(),\n            \"Mesh must not have empty indices\"\n        );\n\n        debug_assert!(\n            mesh.indices().len().is_multiple_of(3),\n            \"Mesh indices length must be a multiple of 3\"\n        );\n\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_mesh(mesh, transformation);\n    }\n\n    fn draw_mesh_cache(&mut self, cache: mesh::Cache) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_mesh_cache(cache, transformation);\n    }\n}\n\n#[cfg(feature = \"geometry\")]\nimpl graphics::geometry::Renderer for Renderer {\n    type Geometry = Geometry;\n    type Frame = geometry::Frame;\n\n    fn new_frame(&self, bounds: Rectangle) -> Self::Frame {\n        geometry::Frame::new(bounds)\n    }\n\n    fn draw_geometry(&mut self, geometry: Self::Geometry) {\n        let (layer, transformation) = self.layers.current_mut();\n\n        match geometry {\n            Geometry::Live {\n                meshes,\n                images,\n                text,\n            } => {\n                layer.draw_mesh_group(meshes, transformation);\n\n                for image in images {\n                    layer.draw_image(image, transformation);\n                }\n\n                layer.draw_text_group(text, transformation);\n            }\n            Geometry::Cached(cache) => {\n                if let Some(meshes) = cache.meshes {\n                    layer.draw_mesh_cache(meshes, transformation);\n                }\n\n                if let Some(images) = cache.images {\n                    for image in images.iter().cloned() {\n                        layer.draw_image(image, transformation);\n                    }\n                }\n\n                if let Some(text) = cache.text {\n                    layer.draw_text_cache(text, transformation);\n                }\n            }\n        }\n    }\n}\n\nimpl primitive::Renderer for Renderer {\n    fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl Primitive) {\n        let (layer, transformation) = self.layers.current_mut();\n        layer.draw_primitive(bounds, primitive, transformation);\n    }\n}\n\nimpl graphics::compositor::Default for crate::Renderer {\n    type Compositor = window::Compositor;\n}\n\nimpl renderer::Headless for Renderer {\n    async fn new(settings: renderer::Settings, backend: Option<&str>) -> Option<Self> {\n        if backend.is_some_and(|backend| backend != \"wgpu\") {\n            return None;\n        }\n\n        let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {\n            backends: wgpu::Backends::from_env().unwrap_or(wgpu::Backends::PRIMARY),\n            flags: wgpu::InstanceFlags::empty(),\n            ..wgpu::InstanceDescriptor::default()\n        });\n\n        let adapter = instance\n            .request_adapter(&wgpu::RequestAdapterOptions {\n                power_preference: wgpu::PowerPreference::HighPerformance,\n                force_fallback_adapter: false,\n                compatible_surface: None,\n            })\n            .await\n            .ok()?;\n\n        let (device, queue) = adapter\n            .request_device(&wgpu::DeviceDescriptor {\n                label: Some(\"iced_wgpu [headless]\"),\n                required_features: wgpu::Features::empty(),\n                required_limits: wgpu::Limits {\n                    max_bind_groups: 2,\n                    ..wgpu::Limits::default()\n                },\n                memory_hints: wgpu::MemoryHints::MemoryUsage,\n                trace: wgpu::Trace::Off,\n                experimental_features: wgpu::ExperimentalFeatures::disabled(),\n            })\n            .await\n            .ok()?;\n\n        let engine = Engine::new(\n            &adapter,\n            device,\n            queue,\n            if graphics::color::GAMMA_CORRECTION {\n                wgpu::TextureFormat::Rgba8UnormSrgb\n            } else {\n                wgpu::TextureFormat::Rgba8Unorm\n            },\n            Some(graphics::Antialiasing::MSAAx4),\n            Shell::headless(),\n        );\n\n        Some(Self::new(engine, settings))\n    }\n\n    fn name(&self) -> String {\n        \"wgpu\".to_owned()\n    }\n\n    fn screenshot(\n        &mut self,\n        size: Size<u32>,\n        scale_factor: f32,\n        background_color: Color,\n    ) -> Vec<u8> {\n        self.screenshot(\n            &Viewport::with_physical_size(size, scale_factor),\n            background_color,\n        )\n    }\n}\n"
  },
  {
    "path": "wgpu/src/primitive.rs",
    "content": "//! Draw custom primitives.\nuse crate::core::{self, Rectangle};\nuse crate::graphics::Viewport;\nuse crate::graphics::futures::{MaybeSend, MaybeSync};\n\nuse rustc_hash::FxHashMap;\nuse std::any::{Any, TypeId};\nuse std::fmt::Debug;\n\n/// A batch of primitives.\npub type Batch = Vec<Instance>;\n\n/// A set of methods which allows a [`Primitive`] to be rendered.\npub trait Primitive: Debug + MaybeSend + MaybeSync + 'static {\n    /// The shared renderer of this [`Primitive`].\n    ///\n    /// Normally, this will contain a bunch of [`wgpu`] state; like\n    /// a rendering pipeline, buffers, and textures.\n    ///\n    /// All instances of this [`Primitive`] type will share the same\n    /// [`Renderer`].\n    type Pipeline: Pipeline + MaybeSend + MaybeSync;\n\n    /// Processes the [`Primitive`], allowing for GPU buffer allocation.\n    fn prepare(\n        &self,\n        pipeline: &mut Self::Pipeline,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n        bounds: &Rectangle,\n        viewport: &Viewport,\n    );\n\n    /// Draws the [`Primitive`] in the given [`wgpu::RenderPass`].\n    ///\n    /// When possible, this should be implemented over [`render`](Self::render)\n    /// since reusing the existing render pass should be considerably more\n    /// efficient than issuing a new one.\n    ///\n    /// The viewport and scissor rect of the render pass provided is set\n    /// to the bounds and clip bounds of the [`Primitive`], respectively.\n    ///\n    /// If you have complex composition needs, then you can leverage\n    /// [`render`](Self::render) by returning `false` here.\n    ///\n    /// By default, it does nothing and returns `false`.\n    fn draw(&self, _pipeline: &Self::Pipeline, _render_pass: &mut wgpu::RenderPass<'_>) -> bool {\n        false\n    }\n\n    /// Renders the [`Primitive`], using the given [`wgpu::CommandEncoder`].\n    ///\n    /// This will only be called if [`draw`](Self::draw) returns `false`.\n    ///\n    /// By default, it does nothing.\n    fn render(\n        &self,\n        _pipeline: &Self::Pipeline,\n        _encoder: &mut wgpu::CommandEncoder,\n        _target: &wgpu::TextureView,\n        _clip_bounds: &Rectangle<u32>,\n    ) {\n    }\n}\n\n/// The pipeline of a graphics [`Primitive`].\npub trait Pipeline: Any + MaybeSend + MaybeSync {\n    /// Creates the [`Pipeline`] of a [`Primitive`].\n    ///\n    /// This will only be called once, when the first [`Primitive`] with this kind\n    /// of [`Pipeline`] is encountered.\n    fn new(device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat) -> Self\n    where\n        Self: Sized;\n\n    /// Trims any cached data in the [`Pipeline`].\n    ///\n    /// This will normally be called at the end of a frame.\n    fn trim(&mut self) {}\n}\n\npub(crate) trait Stored: Debug + MaybeSend + MaybeSync + 'static {\n    fn prepare(\n        &self,\n        storage: &mut Storage,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n        format: wgpu::TextureFormat,\n        bounds: &Rectangle,\n        viewport: &Viewport,\n    );\n\n    fn draw(&self, storage: &Storage, render_pass: &mut wgpu::RenderPass<'_>) -> bool;\n\n    fn render(\n        &self,\n        storage: &Storage,\n        encoder: &mut wgpu::CommandEncoder,\n        target: &wgpu::TextureView,\n        clip_bounds: &Rectangle<u32>,\n    );\n}\n\n#[derive(Debug)]\nstruct BlackBox<P: Primitive> {\n    primitive: P,\n}\n\nimpl<P: Primitive> Stored for BlackBox<P> {\n    fn prepare(\n        &self,\n        storage: &mut Storage,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n        format: wgpu::TextureFormat,\n        bounds: &Rectangle,\n        viewport: &Viewport,\n    ) {\n        if !storage.has::<P>() {\n            storage.store::<P, _>(P::Pipeline::new(device, queue, format));\n        }\n\n        let renderer = storage\n            .get_mut::<P>()\n            .expect(\"renderer should be initialized\")\n            .downcast_mut::<P::Pipeline>()\n            .expect(\"renderer should have the proper type\");\n\n        self.primitive\n            .prepare(renderer, device, queue, bounds, viewport);\n    }\n\n    fn draw(&self, storage: &Storage, render_pass: &mut wgpu::RenderPass<'_>) -> bool {\n        let renderer = storage\n            .get::<P>()\n            .expect(\"renderer should be initialized\")\n            .downcast_ref::<P::Pipeline>()\n            .expect(\"renderer should have the proper type\");\n\n        self.primitive.draw(renderer, render_pass)\n    }\n\n    fn render(\n        &self,\n        storage: &Storage,\n        encoder: &mut wgpu::CommandEncoder,\n        target: &wgpu::TextureView,\n        clip_bounds: &Rectangle<u32>,\n    ) {\n        let renderer = storage\n            .get::<P>()\n            .expect(\"renderer should be initialized\")\n            .downcast_ref::<P::Pipeline>()\n            .expect(\"renderer should have the proper type\");\n\n        self.primitive\n            .render(renderer, encoder, target, clip_bounds);\n    }\n}\n\n#[derive(Debug)]\n/// An instance of a specific [`Primitive`].\npub struct Instance {\n    /// The bounds of the [`Instance`].\n    pub(crate) bounds: Rectangle,\n\n    /// The [`Primitive`] to render.\n    pub(crate) primitive: Box<dyn Stored>,\n}\n\nimpl Instance {\n    /// Creates a new [`Instance`] with the given [`Primitive`].\n    pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self {\n        Instance {\n            bounds,\n            primitive: Box::new(BlackBox { primitive }),\n        }\n    }\n}\n\n/// A renderer than can draw custom primitives.\npub trait Renderer: core::Renderer {\n    /// Draws a custom primitive.\n    fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl Primitive);\n}\n\n/// Stores custom, user-provided types.\n#[derive(Default)]\npub struct Storage {\n    pipelines: FxHashMap<TypeId, Box<dyn Pipeline>>,\n}\n\nimpl Storage {\n    /// Returns `true` if `Storage` contains a type `T`.\n    pub fn has<T: 'static>(&self) -> bool {\n        self.pipelines.contains_key(&TypeId::of::<T>())\n    }\n\n    /// Inserts the data `T` in to [`Storage`].\n    pub fn store<T: 'static, P: Pipeline>(&mut self, pipeline: P) {\n        let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));\n    }\n\n    /// Returns a reference to the data with type `T` if it exists in [`Storage`].\n    pub fn get<T: 'static>(&self) -> Option<&dyn Any> {\n        self.pipelines\n            .get(&TypeId::of::<T>())\n            .map(|pipeline| pipeline.as_ref() as &dyn Any)\n    }\n\n    /// Returns a mutable reference to the data with type `T` if it exists in [`Storage`].\n    pub fn get_mut<T: 'static>(&mut self) -> Option<&mut dyn Any> {\n        self.pipelines\n            .get_mut(&TypeId::of::<T>())\n            .map(|pipeline| pipeline.as_mut() as &mut dyn Any)\n    }\n\n    /// Trims the cache of all the pipelines in the [`Storage`].\n    pub fn trim(&mut self) {\n        for pipeline in self.pipelines.values_mut() {\n            pipeline.trim();\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/quad/gradient.rs",
    "content": "use crate::Buffer;\nuse crate::graphics::gradient;\nuse crate::quad::{self, Quad};\n\nuse bytemuck::{Pod, Zeroable};\nuse std::ops::Range;\n\n/// A quad filled with interpolated colors.\n#[derive(Clone, Copy, Debug)]\n#[repr(C)]\npub struct Gradient {\n    /// The background gradient data of the quad.\n    pub gradient: gradient::Packed,\n\n    /// The [`Quad`] data of the [`Gradient`].\n    pub quad: Quad,\n}\n\n#[allow(unsafe_code)]\nunsafe impl Pod for Gradient {}\n\n#[allow(unsafe_code)]\nunsafe impl Zeroable for Gradient {}\n\n#[derive(Debug)]\npub struct Layer {\n    instances: Buffer<Gradient>,\n    instance_count: usize,\n}\n\nimpl Layer {\n    pub fn new(device: &wgpu::Device) -> Self {\n        let instances = Buffer::new(\n            device,\n            \"iced_wgpu.quad.gradient.buffer\",\n            quad::INITIAL_INSTANCES,\n            wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,\n        );\n\n        Self {\n            instances,\n            instance_count: 0,\n        }\n    }\n\n    pub fn prepare(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        instances: &[Gradient],\n    ) {\n        let _ = self.instances.resize(device, instances.len());\n        let _ = self.instances.write(encoder, belt, 0, instances);\n\n        self.instance_count = instances.len();\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct Pipeline {\n    #[cfg(not(target_arch = \"wasm32\"))]\n    pipeline: wgpu::RenderPipeline,\n}\n\nimpl Pipeline {\n    #[allow(unused_variables)]\n    pub fn new(\n        device: &wgpu::Device,\n        format: wgpu::TextureFormat,\n        constants_layout: &wgpu::BindGroupLayout,\n    ) -> Self {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        {\n            let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n                label: Some(\"iced_wgpu.quad.gradient.pipeline\"),\n                bind_group_layouts: &[constants_layout],\n                immediate_size: 0,\n            });\n\n            let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n                label: Some(\"iced_wgpu.quad.gradient.shader\"),\n                source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(concat!(\n                    include_str!(\"../shader/quad.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"../shader/vertex.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"../shader/quad/gradient.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"../shader/color.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"../shader/color/linear_rgb.wgsl\")\n                ))),\n            });\n\n            let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n                label: Some(\"iced_wgpu.quad.gradient.pipeline\"),\n                layout: Some(&layout),\n                vertex: wgpu::VertexState {\n                    module: &shader,\n                    entry_point: Some(\"gradient_vs_main\"),\n                    buffers: &[wgpu::VertexBufferLayout {\n                        array_stride: std::mem::size_of::<Gradient>() as u64,\n                        step_mode: wgpu::VertexStepMode::Instance,\n                        attributes: &wgpu::vertex_attr_array!(\n                            // Colors 1-2\n                            0 => Uint32x4,\n                            // Colors 3-4\n                            1 => Uint32x4,\n                            // Colors 5-6\n                            2 => Uint32x4,\n                            // Colors 7-8\n                            3 => Uint32x4,\n                            // Offsets 1-8\n                            4 => Uint32x4,\n                            // Direction\n                            5 => Float32x4,\n                            // Position & Scale\n                            6 => Float32x4,\n                            // Border color\n                            7 => Float32x4,\n                            // Border radius\n                            8 => Float32x4,\n                            // Border width\n                            9 => Float32,\n                            // Snap\n                            10 => Uint32,\n                        ),\n                    }],\n                    compilation_options: wgpu::PipelineCompilationOptions::default(),\n                },\n                fragment: Some(wgpu::FragmentState {\n                    module: &shader,\n                    entry_point: Some(\"gradient_fs_main\"),\n                    targets: &quad::color_target_state(format),\n                    compilation_options: wgpu::PipelineCompilationOptions::default(),\n                }),\n                primitive: wgpu::PrimitiveState {\n                    topology: wgpu::PrimitiveTopology::TriangleList,\n                    front_face: wgpu::FrontFace::Cw,\n                    ..Default::default()\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 { pipeline }\n        }\n\n        #[cfg(target_arch = \"wasm32\")]\n        Self {}\n    }\n\n    #[allow(unused_variables)]\n    pub fn render<'a>(\n        &'a self,\n        render_pass: &mut wgpu::RenderPass<'a>,\n        constants: &'a wgpu::BindGroup,\n        layer: &'a Layer,\n        range: Range<usize>,\n    ) {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        {\n            render_pass.set_pipeline(&self.pipeline);\n            render_pass.set_bind_group(0, constants, &[]);\n            render_pass.set_vertex_buffer(0, layer.instances.slice(..));\n\n            render_pass.draw(0..6, range.start as u32..range.end as u32);\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/quad/solid.rs",
    "content": "use crate::Buffer;\nuse crate::graphics::color;\nuse crate::quad::{self, Quad};\n\nuse bytemuck::{Pod, Zeroable};\nuse std::ops::Range;\n\n/// A quad filled with a solid color.\n#[derive(Clone, Copy, Debug, Pod, Zeroable)]\n#[repr(C)]\npub struct Solid {\n    /// The background color data of the quad.\n    pub color: color::Packed,\n\n    /// The [`Quad`] data of the [`Solid`].\n    pub quad: Quad,\n}\n\n#[derive(Debug)]\npub struct Layer {\n    instances: Buffer<Solid>,\n    instance_count: usize,\n}\n\nimpl Layer {\n    pub fn new(device: &wgpu::Device) -> Self {\n        let instances = Buffer::new(\n            device,\n            \"iced_wgpu.quad.solid.buffer\",\n            quad::INITIAL_INSTANCES,\n            wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,\n        );\n\n        Self {\n            instances,\n            instance_count: 0,\n        }\n    }\n\n    pub fn prepare(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        instances: &[Solid],\n    ) {\n        let _ = self.instances.resize(device, instances.len());\n        let _ = self.instances.write(encoder, belt, 0, instances);\n\n        self.instance_count = instances.len();\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct Pipeline {\n    pipeline: wgpu::RenderPipeline,\n}\n\nimpl Pipeline {\n    pub fn new(\n        device: &wgpu::Device,\n        format: wgpu::TextureFormat,\n        constants_layout: &wgpu::BindGroupLayout,\n    ) -> Self {\n        let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: Some(\"iced_wgpu.quad.solid.pipeline\"),\n            bind_group_layouts: &[constants_layout],\n            immediate_size: 0,\n        });\n\n        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: Some(\"iced_wgpu.quad.solid.shader\"),\n            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(concat!(\n                include_str!(\"../shader/color.wgsl\"),\n                \"\\n\",\n                include_str!(\"../shader/quad.wgsl\"),\n                \"\\n\",\n                include_str!(\"../shader/vertex.wgsl\"),\n                \"\\n\",\n                include_str!(\"../shader/quad/solid.wgsl\"),\n            ))),\n        });\n\n        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: Some(\"iced_wgpu.quad.solid.pipeline\"),\n            layout: Some(&layout),\n            vertex: wgpu::VertexState {\n                module: &shader,\n                entry_point: Some(\"solid_vs_main\"),\n                buffers: &[wgpu::VertexBufferLayout {\n                    array_stride: std::mem::size_of::<Solid>() as u64,\n                    step_mode: wgpu::VertexStepMode::Instance,\n                    attributes: &wgpu::vertex_attr_array!(\n                        // Color\n                        0 => Float32x4,\n                        // Position\n                        1 => Float32x2,\n                        // Size\n                        2 => Float32x2,\n                        // Border color\n                        3 => Float32x4,\n                        // Border radius\n                        4 => Float32x4,\n                        // Border width\n                        5 => Float32,\n                        // Shadow color\n                        6 => Float32x4,\n                        // Shadow offset\n                        7 => Float32x2,\n                        // Shadow blur radius\n                        8 => Float32,\n                        // Snap\n                        9 => Uint32,\n                    ),\n                }],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            },\n            fragment: Some(wgpu::FragmentState {\n                module: &shader,\n                entry_point: Some(\"solid_fs_main\"),\n                targets: &quad::color_target_state(format),\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            }),\n            primitive: wgpu::PrimitiveState {\n                topology: wgpu::PrimitiveTopology::TriangleList,\n                front_face: wgpu::FrontFace::Cw,\n                ..Default::default()\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 { pipeline }\n    }\n\n    pub fn render<'a>(\n        &'a self,\n        render_pass: &mut wgpu::RenderPass<'a>,\n        constants: &'a wgpu::BindGroup,\n        layer: &'a Layer,\n        range: Range<usize>,\n    ) {\n        render_pass.set_pipeline(&self.pipeline);\n        render_pass.set_bind_group(0, constants, &[]);\n        render_pass.set_vertex_buffer(0, layer.instances.slice(..));\n\n        render_pass.draw(0..6, range.start as u32..range.end as u32);\n    }\n}\n"
  },
  {
    "path": "wgpu/src/quad.rs",
    "content": "mod gradient;\nmod solid;\n\nuse gradient::Gradient;\nuse solid::Solid;\n\nuse crate::core::{Background, Rectangle, Transformation};\nuse crate::graphics;\nuse crate::graphics::color;\n\nuse bytemuck::{Pod, Zeroable};\n\nuse std::mem;\n\nconst INITIAL_INSTANCES: usize = 2_000;\n\n/// The properties of a quad.\n#[derive(Clone, Copy, Debug, Pod, Zeroable)]\n#[repr(C)]\npub struct Quad {\n    /// The position of the [`Quad`].\n    pub position: [f32; 2],\n\n    /// The size of the [`Quad`].\n    pub size: [f32; 2],\n\n    /// The border color of the [`Quad`], in __linear RGB__.\n    pub border_color: color::Packed,\n\n    /// The border radii of the [`Quad`].\n    pub border_radius: [f32; 4],\n\n    /// The border width of the [`Quad`].\n    pub border_width: f32,\n\n    /// The shadow color of the [`Quad`].\n    pub shadow_color: color::Packed,\n\n    /// The shadow offset of the [`Quad`].\n    pub shadow_offset: [f32; 2],\n\n    /// The shadow blur radius of the [`Quad`].\n    pub shadow_blur_radius: f32,\n\n    /// Whether the [`Quad`] should be snapped to the pixel grid.\n    pub snap: u32,\n}\n\n#[derive(Debug, Clone)]\npub struct Pipeline {\n    solid: solid::Pipeline,\n    gradient: gradient::Pipeline,\n    constant_layout: wgpu::BindGroupLayout,\n}\n\n#[derive(Default)]\npub struct State {\n    layers: Vec<Layer>,\n    prepare_layer: usize,\n}\n\nimpl State {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn prepare(\n        &mut self,\n        pipeline: &Pipeline,\n        device: &wgpu::Device,\n        belt: &mut wgpu::util::StagingBelt,\n        encoder: &mut wgpu::CommandEncoder,\n        quads: &Batch,\n        transformation: Transformation,\n        scale: f32,\n    ) {\n        if self.layers.len() <= self.prepare_layer {\n            self.layers\n                .push(Layer::new(device, &pipeline.constant_layout));\n        }\n\n        let layer = &mut self.layers[self.prepare_layer];\n        layer.prepare(device, encoder, belt, quads, transformation, scale);\n\n        self.prepare_layer += 1;\n    }\n\n    pub fn render<'a>(\n        &'a self,\n        pipeline: &'a Pipeline,\n        layer: usize,\n        bounds: Rectangle<u32>,\n        quads: &Batch,\n        render_pass: &mut wgpu::RenderPass<'a>,\n    ) {\n        if let Some(layer) = self.layers.get(layer) {\n            render_pass.set_scissor_rect(bounds.x, bounds.y, bounds.width, bounds.height);\n\n            let mut solid_offset = 0;\n            let mut gradient_offset = 0;\n\n            for (kind, count) in &quads.order {\n                match kind {\n                    Kind::Solid => {\n                        pipeline.solid.render(\n                            render_pass,\n                            &layer.constants,\n                            &layer.solid,\n                            solid_offset..(solid_offset + count),\n                        );\n\n                        solid_offset += count;\n                    }\n                    Kind::Gradient => {\n                        pipeline.gradient.render(\n                            render_pass,\n                            &layer.constants,\n                            &layer.gradient,\n                            gradient_offset..(gradient_offset + count),\n                        );\n\n                        gradient_offset += count;\n                    }\n                }\n            }\n        }\n    }\n\n    pub fn trim(&mut self) {\n        self.prepare_layer = 0;\n    }\n}\n\nimpl Pipeline {\n    pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Pipeline {\n        let constant_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n            label: Some(\"iced_wgpu::quad uniforms layout\"),\n            entries: &[wgpu::BindGroupLayoutEntry {\n                binding: 0,\n                visibility: wgpu::ShaderStages::VERTEX,\n                ty: wgpu::BindingType::Buffer {\n                    ty: wgpu::BufferBindingType::Uniform,\n                    has_dynamic_offset: false,\n                    min_binding_size: wgpu::BufferSize::new(\n                        mem::size_of::<Uniforms>() as wgpu::BufferAddress\n                    ),\n                },\n                count: None,\n            }],\n        });\n\n        Self {\n            solid: solid::Pipeline::new(device, format, &constant_layout),\n            gradient: gradient::Pipeline::new(device, format, &constant_layout),\n            constant_layout,\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct Layer {\n    constants: wgpu::BindGroup,\n    constants_buffer: wgpu::Buffer,\n    solid: solid::Layer,\n    gradient: gradient::Layer,\n}\n\nimpl Layer {\n    pub fn new(device: &wgpu::Device, constant_layout: &wgpu::BindGroupLayout) -> Self {\n        let constants_buffer = device.create_buffer(&wgpu::BufferDescriptor {\n            label: Some(\"iced_wgpu::quad uniforms buffer\"),\n            size: mem::size_of::<Uniforms>() as wgpu::BufferAddress,\n            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,\n            mapped_at_creation: false,\n        });\n\n        let constants = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"iced_wgpu::quad uniforms bind group\"),\n            layout: constant_layout,\n            entries: &[wgpu::BindGroupEntry {\n                binding: 0,\n                resource: constants_buffer.as_entire_binding(),\n            }],\n        });\n\n        Self {\n            constants,\n            constants_buffer,\n            solid: solid::Layer::new(device),\n            gradient: gradient::Layer::new(device),\n        }\n    }\n\n    pub fn prepare(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        quads: &Batch,\n        transformation: Transformation,\n        scale: f32,\n    ) {\n        self.update(encoder, belt, transformation, scale);\n\n        if !quads.solids.is_empty() {\n            self.solid.prepare(device, encoder, belt, &quads.solids);\n        }\n\n        if !quads.gradients.is_empty() {\n            self.gradient\n                .prepare(device, encoder, belt, &quads.gradients);\n        }\n    }\n\n    pub fn update(\n        &mut self,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        transformation: Transformation,\n        scale: f32,\n    ) {\n        let uniforms = Uniforms::new(transformation, scale);\n        let bytes = bytemuck::bytes_of(&uniforms);\n\n        belt.write_buffer(\n            encoder,\n            &self.constants_buffer,\n            0,\n            (bytes.len() as u64).try_into().expect(\"Sized uniforms\"),\n        )\n        .copy_from_slice(bytes);\n    }\n}\n\n/// A group of [`Quad`]s rendered together.\n#[derive(Default, Debug)]\npub struct Batch {\n    /// The solid quads of the [`Layer`].\n    solids: Vec<Solid>,\n\n    /// The gradient quads of the [`Layer`].\n    gradients: Vec<Gradient>,\n\n    /// The quad order of the [`Layer`].\n    order: Order,\n}\n\n/// The quad order of a [`Layer`]; stored as a tuple of the quad type & its count.\ntype Order = Vec<(Kind, usize)>;\n\nimpl Batch {\n    /// Returns true if there are no quads of any type in [`Quads`].\n    pub fn is_empty(&self) -> bool {\n        self.solids.is_empty() && self.gradients.is_empty()\n    }\n\n    /// Adds a [`Quad`] with the provided `Background` type to the quad [`Layer`].\n    pub fn add(&mut self, quad: Quad, background: &Background) {\n        let kind = match background {\n            Background::Color(color) => {\n                self.solids.push(Solid {\n                    color: color::pack(*color),\n                    quad,\n                });\n\n                Kind::Solid\n            }\n            Background::Gradient(gradient) => {\n                self.gradients.push(Gradient {\n                    gradient: graphics::gradient::pack(\n                        gradient,\n                        Rectangle::new(quad.position.into(), quad.size.into()),\n                    ),\n                    quad,\n                });\n\n                Kind::Gradient\n            }\n        };\n\n        match self.order.last_mut() {\n            Some((last_kind, count)) if kind == *last_kind => {\n                *count += 1;\n            }\n            _ => {\n                self.order.push((kind, 1));\n            }\n        }\n    }\n\n    pub fn clear(&mut self) {\n        self.solids.clear();\n        self.gradients.clear();\n        self.order.clear();\n    }\n\n    pub fn append(&mut self, batch: &mut Batch) {\n        self.solids.append(&mut batch.solids);\n        self.gradients.append(&mut batch.gradients);\n        self.order.append(&mut batch.order);\n    }\n}\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\n/// The kind of a quad.\nenum Kind {\n    /// A solid quad\n    Solid,\n    /// A gradient quad\n    Gradient,\n}\n\nfn color_target_state(format: wgpu::TextureFormat) -> [Option<wgpu::ColorTargetState>; 1] {\n    [Some(wgpu::ColorTargetState {\n        format,\n        blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),\n        write_mask: wgpu::ColorWrites::ALL,\n    })]\n}\n\n#[repr(C)]\n#[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]\nstruct Uniforms {\n    transform: [f32; 16],\n    scale: f32,\n    // Uniforms must be aligned to their largest member,\n    // this uses a mat4x4<f32> which aligns to 16, so align to that\n    _padding: [f32; 3],\n}\n\nimpl Uniforms {\n    fn new(transformation: Transformation, scale: f32) -> Uniforms {\n        Self {\n            transform: *transformation.as_ref(),\n            scale,\n            _padding: [0.0; 3],\n        }\n    }\n}\n\nimpl Default for Uniforms {\n    fn default() -> Self {\n        Self {\n            transform: *Transformation::IDENTITY.as_ref(),\n            scale: 1.0,\n            _padding: [0.0; 3],\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/shader/blit.wgsl",
    "content": "var<private> uvs: array<vec2<f32>, 6> = array<vec2<f32>, 6>(\n    vec2<f32>(0.0, 0.0),\n    vec2<f32>(1.0, 0.0),\n    vec2<f32>(1.0, 1.0),\n    vec2<f32>(0.0, 0.0),\n    vec2<f32>(0.0, 1.0),\n    vec2<f32>(1.0, 1.0)\n);\n\n@group(0) @binding(0) var u_sampler: sampler;\n@group(0) @binding(1) var<uniform> u_ratio: vec4<f32>;\n@group(1) @binding(0) var u_texture: texture_2d<f32>;\n\nstruct VertexInput {\n    @builtin(vertex_index) vertex_index: u32,\n}\n\nstruct VertexOutput {\n    @builtin(position) position: vec4<f32>,\n    @location(0) uv: vec2<f32>,\n}\n\n@vertex\nfn vs_main(input: VertexInput) -> VertexOutput {\n    let uv = uvs[input.vertex_index];\n\n    var out: VertexOutput;\n    out.uv = uv * u_ratio.xy;\n    out.position = vec4<f32>(uv * vec2(2.0, -2.0) + vec2(-1.0, 1.0), 0.0, 1.0);\n\n    return out;\n}\n\n@fragment\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\n    return textureSample(u_texture, u_sampler, input.uv);\n}\n"
  },
  {
    "path": "wgpu/src/shader/color/linear_rgb.wgsl",
    "content": "fn interpolate_color(from_: vec4<f32>, to_: vec4<f32>, factor: f32) -> vec4<f32> {\n    return mix(from_, to_, factor);\n}\n"
  },
  {
    "path": "wgpu/src/shader/color.wgsl",
    "content": "fn premultiply(color: vec4<f32>) -> vec4<f32> {\n    return vec4(color.xyz * color.a, color.a);\n}\n\nfn unpack_color(data: vec2<u32>) -> vec4<f32> {\n    return premultiply(unpack_u32(data));\n}\n\nfn unpack_u32(data: vec2<u32>) -> vec4<f32> {\n    let rg: vec2<f32> = unpack2x16float(data.x);\n    let ba: vec2<f32> = unpack2x16float(data.y);\n\n    return vec4<f32>(rg.y, rg.x, ba.y, ba.x);\n}\n"
  },
  {
    "path": "wgpu/src/shader/image.wgsl",
    "content": "struct Globals {\n    transform: mat4x4<f32>,\n}\n\n@group(0) @binding(0) var<uniform> globals: Globals;\n@group(0) @binding(1) var u_sampler: sampler;\n@group(1) @binding(0) var u_texture: texture_2d_array<f32>;\n\nstruct VertexInput {\n    @builtin(vertex_index) vertex_index: u32,\n    @location(0) center: vec2<f32>,\n    @location(1) clip_bounds: vec4<f32>,\n    @location(2) border_radius: vec4<f32>,\n    @location(3) tile: vec4<f32>,\n    @location(4) rotation: f32,\n    @location(5) opacity: f32,\n    @location(6) atlas_pos: vec2<f32>,\n    @location(7) atlas_scale: vec2<f32>,\n    @location(8) layer: i32,\n}\n\nstruct VertexOutput {\n    @builtin(position) position: vec4<f32>,\n    @location(0) @interpolate(flat) clip_bounds: vec4<f32>,\n    @location(1) @interpolate(flat) border_radius: vec4<f32>,\n    @location(2) @interpolate(flat) atlas: vec4<f32>,\n    @location(3) @interpolate(flat) layer: i32,\n    @location(4) @interpolate(flat) opacity: f32,\n    @location(5) uv: vec2<f32>,\n}\n\n@vertex\nfn vs_main(input: VertexInput) -> VertexOutput {\n    var out: VertexOutput;\n\n    // Generate a vertex position in the range [0, 1] from the vertex index\n    let corner = vertex_position(input.vertex_index);\n\n    let tile = input.tile;\n    let center = input.center;\n\n    // List the unrotated tile corners\n    let corners = array<vec2<f32>, 4>(\n        tile.xy,                              // Top left\n        tile.xy + vec2<f32>(tile.z, 0.0),     // Top right\n        tile.xy + vec2<f32>(0.0, tile.w),     // Bottom left\n        tile.xy + tile.zw                     // Bottom right\n    );\n\n    // Rotate tile corners around center\n    let cos_r = cos(-input.rotation); // Clockwise\n    let sin_r = sin(-input.rotation);\n    var rotated = array<vec2<f32>, 4>();\n\n    for (var i = 0u; i < 4u; i++) {\n        let c = corners[i] - input.center;\n        rotated[i] = vec2<f32>(c.x * cos_r - c.y * sin_r, c.x * sin_r + c.y * cos_r) + input.center;\n    }\n\n    // Find bounding box of rotated tile\n    var min_xy = rotated[0];\n    var max_xy = rotated[0];\n    for (var i = 1u; i < 4u; i++) {\n        min_xy = min(min_xy, rotated[i]);\n        max_xy = max(max_xy, rotated[i]);\n    }\n    let rotated_bounds = vec4<f32>(min_xy, max_xy - min_xy);\n\n    // Intersect with clip bounds\n    let clip_min = max(rotated_bounds.xy, input.clip_bounds.xy);\n    let clip_max = min(rotated_bounds.xy + rotated_bounds.zw, input.clip_bounds.xy + input.clip_bounds.zw);\n    let clipped_tile = vec4<f32>(clip_min, max(vec2<f32>(0.0), clip_max - clip_min));\n\n    // Calculate the vertex position\n    let v_pos = clipped_tile.xy + corner * clipped_tile.zw;\n    out.position = vec4<f32>(v_pos, 0.0, 1.0);\n    out.clip_bounds = input.clip_bounds;\n\n    // Calculate rotated UV\n    let uv = input.atlas_pos + (v_pos - tile.xy) / tile.zw * input.atlas_scale;\n    let uv_center = input.atlas_pos + input.atlas_scale / 2.0;\n\n    let d = uv - uv_center;\n    out.uv = vec2<f32>(d.x * cos_r - d.y * sin_r, d.x * sin_r + d.y * cos_r) + uv_center;\n\n    out.position = globals.transform * out.position;\n    out.border_radius = min(input.border_radius, vec4(min(input.clip_bounds.z, input.clip_bounds.w) / 2.0));\n    out.atlas = vec4(input.atlas_pos, input.atlas_pos + input.atlas_scale);\n    out.layer = input.layer;\n    out.opacity = input.opacity;\n\n    return out;\n}\n\n@fragment\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\n    let fragment = input.position.xy;\n    let position = input.clip_bounds.xy;\n    let scale = input.clip_bounds.zw;\n\n    let d = rounded_box_sdf(\n        2.0 * (fragment - position - scale / 2.0),\n        scale,\n        input.border_radius * 2.0,\n    ) / 2.0;\n\n    let antialias: f32 = clamp(1.0 - d, 0.0, 1.0);\n    let inside = all(input.uv >= input.atlas.xy) && all(input.uv <= input.atlas.zw);\n\n    let sample = textureSample(u_texture, u_sampler, input.uv, input.layer) * vec4<f32>(1.0, 1.0, 1.0, antialias * input.opacity * f32(inside));\n    return premultiply(sample);\n}\n\nfn rounded_box_sdf(p: vec2<f32>, size: vec2<f32>, corners: vec4<f32>) -> f32 {\n    let box_half = select(corners.yz, corners.xw, p.x > 0.0);\n    let corner = select(box_half.y, box_half.x, p.y > 0.0);\n    let q = abs(p) - size + corner;\n    return min(max(q.x, q.y), 0.0) + length(max(q, vec2(0.0))) - corner;\n}\n"
  },
  {
    "path": "wgpu/src/shader/quad/gradient.wgsl",
    "content": "struct GradientVertexInput {\n    @builtin(vertex_index) vertex_index: u32,\n    @location(0) @interpolate(flat) colors_1: vec4<u32>,\n    @location(1) @interpolate(flat) colors_2: vec4<u32>,\n    @location(2) @interpolate(flat) colors_3: vec4<u32>,\n    @location(3) @interpolate(flat) colors_4: vec4<u32>,\n    @location(4) @interpolate(flat) offsets: vec4<u32>,\n    @location(5) direction: vec4<f32>,\n    @location(6) position_and_scale: vec4<f32>,\n    @location(7) border_color: vec4<f32>,\n    @location(8) border_radius: vec4<f32>,\n    @location(9) border_width: f32,\n    @location(10) snap: u32,\n}\n\nstruct GradientVertexOutput {\n    @builtin(position) position: vec4<f32>,\n    @location(1) @interpolate(flat) colors_1: vec4<u32>,\n    @location(2) @interpolate(flat) colors_2: vec4<u32>,\n    @location(3) @interpolate(flat) colors_3: vec4<u32>,\n    @location(4) @interpolate(flat) colors_4: vec4<u32>,\n    @location(5) @interpolate(flat) offsets: vec4<u32>,\n    @location(6) direction: vec4<f32>,\n    @location(7) position_and_scale: vec4<f32>,\n    @location(8) border_color: vec4<f32>,\n    @location(9) border_radius: vec4<f32>,\n    @location(10) border_width: f32,\n}\n\n@vertex\nfn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput {\n    var out: GradientVertexOutput;\n\n    var pos: vec2<f32> = input.position_and_scale.xy * globals.scale;\n    var scale: vec2<f32> = input.position_and_scale.zw * globals.scale;\n\n    var pos_snap = vec2<f32>(0.0, 0.0);\n    var scale_snap = vec2<f32>(0.0, 0.0);\n\n    if bool(input.snap) {\n        pos_snap = round(pos + vec2(0.001, 0.001)) - pos;\n        scale_snap = round(pos + scale + vec2(0.001, 0.001)) - pos - pos_snap - scale;\n    }\n\n    var min_border_radius = min(input.position_and_scale.z, input.position_and_scale.w) * 0.5;\n    var border_radius: vec4<f32> = vec4<f32>(\n        min(input.border_radius.x, min_border_radius),\n        min(input.border_radius.y, min_border_radius),\n        min(input.border_radius.z, min_border_radius),\n        min(input.border_radius.w, min_border_radius)\n    );\n\n    var transform: mat4x4<f32> = mat4x4<f32>(\n        vec4<f32>(scale.x + scale_snap.x + 1.0, 0.0, 0.0, 0.0),\n        vec4<f32>(0.0, scale.y + scale_snap.y + 1.0, 0.0, 0.0),\n        vec4<f32>(0.0, 0.0, 1.0, 0.0),\n        vec4<f32>(pos + pos_snap - vec2<f32>(0.5, 0.5), 0.0, 1.0)\n    );\n\n    out.position = globals.transform * transform * vec4<f32>(vertex_position(input.vertex_index), 0.0, 1.0);\n    out.colors_1 = input.colors_1;\n    out.colors_2 = input.colors_2;\n    out.colors_3 = input.colors_3;\n    out.colors_4 = input.colors_4;\n    out.offsets = input.offsets;\n    out.direction = input.direction * globals.scale;\n    out.position_and_scale = vec4<f32>(pos + pos_snap, scale + scale_snap);\n    out.border_color = premultiply(input.border_color);\n    out.border_radius = border_radius * globals.scale;\n    out.border_width = input.border_width * globals.scale;\n\n    return out;\n}\n\nfn random(coords: vec2<f32>) -> f32 {\n    return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453);\n}\n\n/// Returns the current interpolated color with a max 8-stop gradient\nfn gradient(\n    raw_position: vec2<f32>,\n    direction: vec4<f32>,\n    colors: array<vec4<f32>, 8>,\n    offsets: array<f32, 8>,\n    last_index: i32\n) -> vec4<f32> {\n    let start = direction.xy;\n    let end = direction.zw;\n\n    let v1 = end - start;\n    let v2 = raw_position - start;\n    let unit = normalize(v1);\n    let coord_offset = dot(unit, v2) / length(v1);\n\n    //need to store these as a var to use dynamic indexing in a loop\n    //this is already added to wgsl spec but not in wgpu yet\n    var colors_arr = colors;\n    var offsets_arr = offsets;\n\n    var color: vec4<f32>;\n\n    let noise_granularity: f32 = 0.3/255.0;\n\n    for (var i: i32 = 0; i < last_index; i++) {\n        let curr_offset = offsets_arr[i];\n        let next_offset = offsets_arr[i+1];\n\n        if (coord_offset <= offsets_arr[0]) {\n            color = colors_arr[0];\n        }\n\n        if (curr_offset <= coord_offset && coord_offset <= next_offset) {\n            let from_ = colors_arr[i];\n            let to_ = colors_arr[i+1];\n            let factor = smoothstep(curr_offset, next_offset, coord_offset);\n\n            color = interpolate_color(from_, to_, factor);\n        }\n\n        if (coord_offset >= offsets_arr[last_index]) {\n            color = colors_arr[last_index];\n        }\n    }\n\n    return color + mix(-noise_granularity, noise_granularity, random(raw_position));\n}\n\n@fragment\nfn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> {\n    let colors = array<vec4<f32>, 8>(\n        unpack_color(input.colors_1.xy),\n        unpack_color(input.colors_1.zw),\n        unpack_color(input.colors_2.xy),\n        unpack_color(input.colors_2.zw),\n        unpack_color(input.colors_3.xy),\n        unpack_color(input.colors_3.zw),\n        unpack_color(input.colors_4.xy),\n        unpack_color(input.colors_4.zw),\n    );\n\n    let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy);\n    let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw);\n\n    var offsets = array<f32, 8>(\n        offsets_1.x,\n        offsets_1.y,\n        offsets_1.z,\n        offsets_1.w,\n        offsets_2.x,\n        offsets_2.y,\n        offsets_2.z,\n        offsets_2.w,\n    );\n\n    //TODO could just pass this in to the shader but is probably more performant to just check it here\n    var last_index = 7;\n    for (var i: i32 = 0; i <= 7; i++) {\n        if (offsets[i] > 1.0) {\n            last_index = i - 1;\n            break;\n        }\n    }\n\n    var mixed_color: vec4<f32> = gradient(input.position.xy, input.direction, colors, offsets, last_index);\n\n    let pos = input.position_and_scale.xy;\n    let scale = input.position_and_scale.zw;\n\n    var dist: f32 = rounded_box_sdf(\n        -(input.position.xy - pos - scale / 2.0) * 2.0,\n        scale,\n        input.border_radius * 2.0\n    ) / 2.0;\n\n    if (input.border_width > 0.0) {\n        mixed_color = mix(\n            mixed_color,\n            input.border_color,\n            clamp(0.5 + dist + input.border_width, 0.0, 1.0)\n        );\n    }\n\n    return mixed_color * clamp(0.5-dist, 0.0, 1.0);\n}\n"
  },
  {
    "path": "wgpu/src/shader/quad/solid.wgsl",
    "content": "struct SolidVertexInput {\n    @builtin(vertex_index) vertex_index: u32,\n    @location(0) color: vec4<f32>,\n    @location(1) pos: vec2<f32>,\n    @location(2) scale: vec2<f32>,\n    @location(3) border_color: vec4<f32>,\n    @location(4) border_radius: vec4<f32>,\n    @location(5) border_width: f32,\n    @location(6) shadow_color: vec4<f32>,\n    @location(7) shadow_offset: vec2<f32>,\n    @location(8) shadow_blur_radius: f32,\n    @location(9) snap: u32,\n}\n\nstruct SolidVertexOutput {\n    @builtin(position) position: vec4<f32>,\n    @location(0) color: vec4<f32>,\n    @location(1) border_color: vec4<f32>,\n    @location(2) pos: vec2<f32>,\n    @location(3) scale: vec2<f32>,\n    @location(4) border_radius: vec4<f32>,\n    @location(5) border_width: f32,\n    @location(6) shadow_color: vec4<f32>,\n    @location(7) shadow_offset: vec2<f32>,\n    @location(8) shadow_blur_radius: f32,\n}\n\n@vertex\nfn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput {\n    var out: SolidVertexOutput;\n\n    var pos: vec2<f32> = (input.pos + min(input.shadow_offset, vec2<f32>(0.0, 0.0)) - input.shadow_blur_radius) * globals.scale;\n    var scale: vec2<f32> = (input.scale + vec2<f32>(abs(input.shadow_offset.x), abs(input.shadow_offset.y)) + input.shadow_blur_radius * 2.0) * globals.scale;\n\n    var pos_snap = vec2<f32>(0.0, 0.0);\n    var scale_snap = vec2<f32>(0.0, 0.0);\n\n    if bool(input.snap) {\n        pos_snap = round(pos + vec2(0.001, 0.001)) - pos;\n        scale_snap = round(pos + scale + vec2(0.001, 0.001)) - pos - pos_snap - scale;\n    }\n\n    let border_radius = min(input.border_radius, vec4(min(input.scale.x, input.scale.y) / 2.0));\n\n    var transform: mat4x4<f32> = mat4x4<f32>(\n        vec4<f32>(scale.x + scale_snap.x + 1.0, 0.0, 0.0, 0.0),\n        vec4<f32>(0.0, scale.y + scale_snap.y + 1.0, 0.0, 0.0),\n        vec4<f32>(0.0, 0.0, 1.0, 0.0),\n        vec4<f32>(pos + pos_snap - vec2<f32>(0.5, 0.5), 0.0, 1.0)\n    );\n\n    out.position = globals.transform * transform * vec4<f32>(vertex_position(input.vertex_index), 0.0, 1.0);\n    out.color = premultiply(input.color);\n    out.border_color = premultiply(input.border_color);\n    out.pos = input.pos * globals.scale + pos_snap;\n    out.scale = input.scale * globals.scale + scale_snap;\n    out.border_radius = border_radius * globals.scale;\n    out.border_width = input.border_width * globals.scale;\n    out.shadow_color = premultiply(input.shadow_color);\n    out.shadow_offset = input.shadow_offset * globals.scale;\n    out.shadow_blur_radius = input.shadow_blur_radius * globals.scale;\n\n    return out;\n}\n\n@fragment\nfn solid_fs_main(\n    input: SolidVertexOutput\n) -> @location(0) vec4<f32> {\n    var mixed_color: vec4<f32> = input.color;\n\n    var dist = rounded_box_sdf(\n        -(input.position.xy - input.pos - input.scale * 0.5) * 2.0,\n        input.scale,\n        input.border_radius * 2.0\n    ) / 2.0;\n\n    if (input.border_width > 0.0) {\n        mixed_color = mix(\n            input.color,\n            input.border_color,\n            clamp(0.5 + dist + input.border_width, 0.0, 1.0)\n        );\n    }\n\n    var quad_alpha: f32 = clamp(0.5-dist, 0.0, 1.0);\n\n    let quad_color = mixed_color * quad_alpha;\n\n    if input.shadow_color.a > 0.0 {\n        var shadow_dist: f32 = rounded_box_sdf(\n            -(input.position.xy - input.pos - input.shadow_offset - input.scale/2.0) * 2.0,\n            input.scale,\n            input.border_radius * 2.0\n        ) / 2.0;\n        let shadow_alpha = 1.0 - smoothstep(-input.shadow_blur_radius, input.shadow_blur_radius, max(shadow_dist, 0.0));\n\n        return mix(quad_color, input.shadow_color, (1.0 - quad_alpha) * shadow_alpha);\n    } else {\n        return quad_color;\n    }\n}\n"
  },
  {
    "path": "wgpu/src/shader/quad.wgsl",
    "content": "struct Globals {\n    transform: mat4x4<f32>,\n    scale: f32,\n}\n\n@group(0) @binding(0) var<uniform> globals: Globals;\n\nfn rounded_box_sdf(p: vec2<f32>, size: vec2<f32>, corners: vec4<f32>) -> f32 {\n    var box_half = select(corners.yz, corners.xw, p.x > 0.0);\n    var corner = select(box_half.y, box_half.x, p.y > 0.0);\n    var q = abs(p) - size + corner;\n    return min(max(q.x, q.y), 0.0) + length(max(q, vec2(0.0))) - corner;\n}\n"
  },
  {
    "path": "wgpu/src/shader/triangle/gradient.wgsl",
    "content": "struct GradientVertexInput {\n    @location(0) v_pos: vec2<f32>,\n    @location(1) @interpolate(flat) colors_1: vec4<u32>,\n    @location(2) @interpolate(flat) colors_2: vec4<u32>,\n    @location(3) @interpolate(flat) colors_3: vec4<u32>,\n    @location(4) @interpolate(flat) colors_4: vec4<u32>,\n    @location(5) @interpolate(flat) offsets: vec4<u32>,\n    @location(6) direction: vec4<f32>,\n}\n\nstruct GradientVertexOutput {\n    @builtin(position) position: vec4<f32>,\n    @location(0) raw_position: vec2<f32>,\n    @location(1) @interpolate(flat) colors_1: vec4<u32>,\n    @location(2) @interpolate(flat) colors_2: vec4<u32>,\n    @location(3) @interpolate(flat) colors_3: vec4<u32>,\n    @location(4) @interpolate(flat) colors_4: vec4<u32>,\n    @location(5) @interpolate(flat) offsets: vec4<u32>,\n    @location(6) direction: vec4<f32>,\n}\n\n@vertex\nfn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput {\n    var output: GradientVertexOutput;\n\n    output.position = globals.transform * vec4<f32>(input.v_pos, 0.0, 1.0);\n    output.raw_position = input.v_pos;\n    output.colors_1 = input.colors_1;\n    output.colors_2 = input.colors_2;\n    output.colors_3 = input.colors_3;\n    output.colors_4 = input.colors_4;\n    output.offsets = input.offsets;\n    output.direction = input.direction;\n\n    return output;\n}\n\n/// Returns the current interpolated color with a max 8-stop gradient\nfn gradient(\n    raw_position: vec2<f32>,\n    direction: vec4<f32>,\n    colors: array<vec4<f32>, 8>,\n    offsets: array<f32, 8>,\n    last_index: i32\n) -> vec4<f32> {\n    let start = direction.xy;\n    let end = direction.zw;\n\n    let v1 = end - start;\n    let v2 = raw_position - start;\n    let unit = normalize(v1);\n    let coord_offset = dot(unit, v2) / length(v1);\n\n    //need to store these as a var to use dynamic indexing in a loop\n    //this is already added to wgsl spec but not in wgpu yet\n    var colors_arr = colors;\n    var offsets_arr = offsets;\n\n    var color: vec4<f32>;\n\n    let noise_granularity: f32 = 0.3/255.0;\n\n    for (var i: i32 = 0; i < last_index; i++) {\n        let curr_offset = offsets_arr[i];\n        let next_offset = offsets_arr[i+1];\n\n        if (coord_offset <= offsets_arr[0]) {\n            color = colors_arr[0];\n        }\n\n        if (curr_offset <= coord_offset && coord_offset <= next_offset) {\n            let from_ = colors_arr[i];\n            let to_ = colors_arr[i+1];\n            let factor = smoothstep(curr_offset, next_offset, coord_offset);\n\n            color = interpolate_color(from_, to_, factor);\n        }\n\n        if (coord_offset >= offsets_arr[last_index]) {\n            color = colors_arr[last_index];\n        }\n    }\n\n    return color + mix(-noise_granularity, noise_granularity, random(raw_position));\n}\n\n@fragment\nfn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> {\n    let colors = array<vec4<f32>, 8>(\n        unpack_color(input.colors_1.xy),\n        unpack_color(input.colors_1.zw),\n        unpack_color(input.colors_2.xy),\n        unpack_color(input.colors_2.zw),\n        unpack_color(input.colors_3.xy),\n        unpack_color(input.colors_3.zw),\n        unpack_color(input.colors_4.xy),\n        unpack_color(input.colors_4.zw),\n    );\n\n    let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy);\n    let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw);\n\n    var offsets = array<f32, 8>(\n        offsets_1.x,\n        offsets_1.y,\n        offsets_1.z,\n        offsets_1.w,\n        offsets_2.x,\n        offsets_2.y,\n        offsets_2.z,\n        offsets_2.w,\n    );\n\n    var last_index = 7;\n    for (var i: i32 = 0; i <= 7; i++) {\n        if (offsets[i] >= 1.0) {\n            last_index = i;\n            break;\n        }\n    }\n\n    return gradient(input.raw_position, input.direction, colors, offsets, last_index);\n}\n\nfn random(coords: vec2<f32>) -> f32 {\n    return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453);\n}\n"
  },
  {
    "path": "wgpu/src/shader/triangle/solid.wgsl",
    "content": "struct SolidVertexInput {\n    @location(0) position: vec2<f32>,\n    @location(1) color: vec4<f32>,\n}\n\nstruct SolidVertexOutput {\n    @builtin(position) position: vec4<f32>,\n    @location(0) color: vec4<f32>,\n}\n\n@vertex\nfn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput {\n    var out: SolidVertexOutput;\n\n    out.color = premultiply(input.color);\n    out.position = globals.transform * vec4<f32>(input.position, 0.0, 1.0);\n\n    return out;\n}\n\n@fragment\nfn solid_fs_main(input: SolidVertexOutput) -> @location(0) vec4<f32> {\n    return input.color;\n}\n"
  },
  {
    "path": "wgpu/src/shader/triangle.wgsl",
    "content": "struct Globals {\n    transform: mat4x4<f32>,\n}\n\n@group(0) @binding(0) var<uniform> globals: Globals;\n"
  },
  {
    "path": "wgpu/src/shader/vertex.wgsl",
    "content": "// Compute the normalized quad coordinates based on the vertex index.\nfn vertex_position(vertex_index: u32) -> vec2<f32> {\n    // #: 0 1 2 3 4 5\n    // x: 1 1 0 0 0 1\n    // y: 1 0 0 0 1 1\n    return vec2<f32>((vec2(1u, 2u) + vertex_index) % vec2(6u) < vec2(3u));\n}\n"
  },
  {
    "path": "wgpu/src/text.rs",
    "content": "use crate::core::alignment;\nuse crate::core::text::Alignment;\nuse crate::core::{Rectangle, Size, Transformation};\nuse crate::graphics::cache;\nuse crate::graphics::color;\nuse crate::graphics::text::cache::{self as text_cache, Cache as BufferCache};\nuse crate::graphics::text::{Editor, Paragraph, font_system, to_color};\n\nuse rustc_hash::FxHashMap;\nuse std::collections::hash_map;\nuse std::sync::atomic::{self, AtomicU64};\nuse std::sync::{self, Arc, RwLock};\n\npub use crate::graphics::Text;\n\nconst COLOR_MODE: cryoglyph::ColorMode = if color::GAMMA_CORRECTION {\n    cryoglyph::ColorMode::Accurate\n} else {\n    cryoglyph::ColorMode::Web\n};\n\npub type Batch = Vec<Item>;\n\n#[derive(Debug)]\npub enum Item {\n    Group {\n        transformation: Transformation,\n        text: Vec<Text>,\n    },\n    Cached {\n        transformation: Transformation,\n        cache: Cache,\n    },\n}\n\n#[derive(Debug, Clone)]\npub struct Cache {\n    id: Id,\n    group: cache::Group,\n    text: Arc<[Text]>,\n    version: usize,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct Id(u64);\n\nimpl Cache {\n    pub fn new(group: cache::Group, text: Vec<Text>) -> Option<Self> {\n        static NEXT_ID: AtomicU64 = AtomicU64::new(0);\n\n        if text.is_empty() {\n            return None;\n        }\n\n        Some(Self {\n            id: Id(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)),\n            group,\n            text: Arc::from(text),\n            version: 0,\n        })\n    }\n\n    pub fn update(&mut self, text: Vec<Text>) {\n        if self.text.is_empty() && text.is_empty() {\n            return;\n        }\n\n        self.text = Arc::from(text);\n        self.version += 1;\n    }\n}\n\nstruct Upload {\n    renderer: cryoglyph::TextRenderer,\n    buffer_cache: BufferCache,\n    transformation: Transformation,\n    version: usize,\n    group_version: usize,\n    text: sync::Weak<[Text]>,\n    _atlas: sync::Weak<()>,\n}\n\n#[derive(Default)]\npub struct Storage {\n    groups: FxHashMap<cache::Group, Group>,\n    uploads: FxHashMap<Id, Upload>,\n}\n\nstruct Group {\n    atlas: cryoglyph::TextAtlas,\n    version: usize,\n    should_trim: bool,\n    handle: Arc<()>, // Keeps track of active uploads\n}\n\nimpl Storage {\n    fn get(&self, cache: &Cache) -> Option<(&cryoglyph::TextAtlas, &Upload)> {\n        if cache.text.is_empty() {\n            return None;\n        }\n\n        self.groups\n            .get(&cache.group)\n            .map(|group| &group.atlas)\n            .zip(self.uploads.get(&cache.id))\n    }\n\n    fn prepare(\n        &mut self,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n        viewport: &cryoglyph::Viewport,\n        encoder: &mut wgpu::CommandEncoder,\n        format: wgpu::TextureFormat,\n        state: &cryoglyph::Cache,\n        cache: &Cache,\n        new_transformation: Transformation,\n        bounds: Rectangle,\n    ) {\n        let group_count = self.groups.len();\n\n        let group = self.groups.entry(cache.group).or_insert_with(|| {\n            log::debug!(\n                \"New text atlas: {:?} (total: {})\",\n                cache.group,\n                group_count + 1\n            );\n\n            Group {\n                atlas: cryoglyph::TextAtlas::with_color_mode(\n                    device, queue, state, format, COLOR_MODE,\n                ),\n                version: 0,\n                should_trim: false,\n                handle: Arc::new(()),\n            }\n        });\n\n        match self.uploads.entry(cache.id) {\n            hash_map::Entry::Occupied(entry) => {\n                let upload = entry.into_mut();\n\n                if upload.version != cache.version\n                    || upload.group_version != group.version\n                    || upload.transformation != new_transformation\n                {\n                    if !cache.text.is_empty() {\n                        let _ = prepare(\n                            device,\n                            queue,\n                            viewport,\n                            encoder,\n                            &mut upload.renderer,\n                            &mut group.atlas,\n                            &mut upload.buffer_cache,\n                            &cache.text,\n                            bounds,\n                            new_transformation,\n                        );\n                    }\n\n                    // Only trim if glyphs have changed\n                    group.should_trim = group.should_trim || upload.version != cache.version;\n\n                    upload.text = Arc::downgrade(&cache.text);\n                    upload.version = cache.version;\n                    upload.group_version = group.version;\n                    upload.transformation = new_transformation;\n\n                    upload.buffer_cache.trim();\n                }\n            }\n            hash_map::Entry::Vacant(entry) => {\n                let mut renderer = cryoglyph::TextRenderer::new(\n                    &mut group.atlas,\n                    device,\n                    wgpu::MultisampleState::default(),\n                    None,\n                );\n\n                let mut buffer_cache = BufferCache::new();\n\n                if !cache.text.is_empty() {\n                    let _ = prepare(\n                        device,\n                        queue,\n                        viewport,\n                        encoder,\n                        &mut renderer,\n                        &mut group.atlas,\n                        &mut buffer_cache,\n                        &cache.text,\n                        bounds,\n                        new_transformation,\n                    );\n                }\n\n                let _ = entry.insert(Upload {\n                    renderer,\n                    buffer_cache,\n                    transformation: new_transformation,\n                    version: 0,\n                    group_version: group.version,\n                    text: Arc::downgrade(&cache.text),\n                    _atlas: Arc::downgrade(&group.handle),\n                });\n\n                group.should_trim = cache.group.is_singleton();\n\n                log::debug!(\n                    \"New text upload: {} (total: {})\",\n                    cache.id.0,\n                    self.uploads.len()\n                );\n            }\n        }\n    }\n\n    pub fn trim(&mut self) {\n        self.uploads\n            .retain(|_id, upload| upload.text.strong_count() > 0);\n\n        self.groups.retain(|id, group| {\n            let active_uploads = Arc::weak_count(&group.handle);\n\n            if active_uploads == 0 {\n                log::debug!(\"Dropping text atlas: {id:?}\");\n\n                return false;\n            }\n\n            if group.should_trim {\n                log::trace!(\"Trimming text atlas: {id:?}\");\n\n                group.atlas.trim();\n                group.should_trim = false;\n\n                // We only need to worry about glyph fighting\n                // when the atlas may be shared by multiple\n                // uploads.\n                if !id.is_singleton() {\n                    log::debug!(\n                        \"Invalidating text atlas: {id:?} \\\n                        (uploads: {active_uploads})\"\n                    );\n\n                    group.version += 1;\n                }\n            }\n\n            true\n        });\n    }\n}\n\npub struct Viewport(cryoglyph::Viewport);\n\nimpl Viewport {\n    pub fn update(&mut self, queue: &wgpu::Queue, resolution: Size<u32>) {\n        self.0.update(\n            queue,\n            cryoglyph::Resolution {\n                width: resolution.width,\n                height: resolution.height,\n            },\n        );\n    }\n}\n\n#[derive(Clone)]\npub struct Pipeline {\n    format: wgpu::TextureFormat,\n    cache: cryoglyph::Cache,\n    atlas: Arc<RwLock<cryoglyph::TextAtlas>>,\n}\n\nimpl Pipeline {\n    pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat) -> Self {\n        let cache = cryoglyph::Cache::new(device);\n        let atlas =\n            cryoglyph::TextAtlas::with_color_mode(device, queue, &cache, format, COLOR_MODE);\n\n        Pipeline {\n            format,\n            cache,\n            atlas: Arc::new(RwLock::new(atlas)),\n        }\n    }\n\n    pub fn create_viewport(&self, device: &wgpu::Device) -> Viewport {\n        Viewport(cryoglyph::Viewport::new(device, &self.cache))\n    }\n\n    pub fn trim(&self) {\n        self.atlas.write().expect(\"Write text atlas\").trim();\n    }\n}\n\n#[derive(Default)]\npub struct State {\n    renderers: Vec<cryoglyph::TextRenderer>,\n    prepare_layer: usize,\n    cache: BufferCache,\n    storage: Storage,\n}\n\nimpl State {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn prepare(\n        &mut self,\n        pipeline: &Pipeline,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n        viewport: &Viewport,\n        encoder: &mut wgpu::CommandEncoder,\n        batch: &Batch,\n        layer_bounds: Rectangle,\n        layer_transformation: Transformation,\n    ) {\n        let mut atlas = pipeline.atlas.write().expect(\"Write to text atlas\");\n\n        for item in batch {\n            match item {\n                Item::Group {\n                    transformation,\n                    text,\n                } => {\n                    if self.renderers.len() <= self.prepare_layer {\n                        self.renderers.push(cryoglyph::TextRenderer::new(\n                            &mut atlas,\n                            device,\n                            wgpu::MultisampleState::default(),\n                            None,\n                        ));\n                    }\n\n                    let renderer = &mut self.renderers[self.prepare_layer];\n                    let result = prepare(\n                        device,\n                        queue,\n                        &viewport.0,\n                        encoder,\n                        renderer,\n                        &mut atlas,\n                        &mut self.cache,\n                        text,\n                        layer_bounds * layer_transformation,\n                        layer_transformation * *transformation,\n                    );\n\n                    match result {\n                        Ok(()) => {\n                            self.prepare_layer += 1;\n                        }\n                        Err(cryoglyph::PrepareError::AtlasFull) => {\n                            // If the atlas cannot grow, then all bets are off.\n                            // Instead of panicking, we will just pray that the result\n                            // will be somewhat readable...\n                        }\n                    }\n                }\n                Item::Cached {\n                    transformation,\n                    cache,\n                } => {\n                    self.storage.prepare(\n                        device,\n                        queue,\n                        &viewport.0,\n                        encoder,\n                        pipeline.format,\n                        &pipeline.cache,\n                        cache,\n                        layer_transformation * *transformation,\n                        layer_bounds * layer_transformation,\n                    );\n                }\n            }\n        }\n    }\n\n    pub fn render<'a>(\n        &'a self,\n        pipeline: &'a Pipeline,\n        viewport: &'a Viewport,\n        start: usize,\n        batch: &'a Batch,\n        bounds: Rectangle<u32>,\n        render_pass: &mut wgpu::RenderPass<'a>,\n    ) -> usize {\n        let atlas = pipeline.atlas.read().expect(\"Read text atlas\");\n        let mut layer_count = 0;\n\n        render_pass.set_scissor_rect(bounds.x, bounds.y, bounds.width, bounds.height);\n\n        for item in batch {\n            match item {\n                Item::Group { .. } => {\n                    let renderer = &self.renderers[start + layer_count];\n\n                    renderer\n                        .render(&atlas, &viewport.0, render_pass)\n                        .expect(\"Render text\");\n\n                    layer_count += 1;\n                }\n                Item::Cached { cache, .. } => {\n                    if let Some((atlas, upload)) = self.storage.get(cache) {\n                        upload\n                            .renderer\n                            .render(atlas, &viewport.0, render_pass)\n                            .expect(\"Render cached text\");\n                    }\n                }\n            }\n        }\n\n        layer_count\n    }\n\n    pub fn trim(&mut self) {\n        self.cache.trim();\n        self.storage.trim();\n\n        self.prepare_layer = 0;\n    }\n}\n\nfn prepare(\n    device: &wgpu::Device,\n    queue: &wgpu::Queue,\n    viewport: &cryoglyph::Viewport,\n    encoder: &mut wgpu::CommandEncoder,\n    renderer: &mut cryoglyph::TextRenderer,\n    atlas: &mut cryoglyph::TextAtlas,\n    buffer_cache: &mut BufferCache,\n    sections: &[Text],\n    layer_bounds: Rectangle,\n    layer_transformation: Transformation,\n) -> Result<(), cryoglyph::PrepareError> {\n    let mut font_system = font_system().write().expect(\"Write font system\");\n    let font_system = font_system.raw();\n\n    enum Allocation {\n        Paragraph(Paragraph),\n        Editor(Editor),\n        Cache(text_cache::KeyHash),\n        Raw(Arc<cryoglyph::Buffer>),\n    }\n\n    let allocations: Vec<_> = sections\n        .iter()\n        .map(|section| match section {\n            Text::Paragraph { paragraph, .. } => paragraph.upgrade().map(Allocation::Paragraph),\n            Text::Editor { editor, .. } => editor.upgrade().map(Allocation::Editor),\n            Text::Cached {\n                content,\n                bounds,\n                size,\n                line_height,\n                font,\n                shaping,\n                wrapping,\n                ellipsis,\n                align_x,\n                ..\n            } => {\n                let (key, _) = buffer_cache.allocate(\n                    font_system,\n                    text_cache::Key {\n                        content,\n                        size: f32::from(*size),\n                        line_height: f32::from(*line_height),\n                        font: *font,\n                        align_x: *align_x,\n                        bounds: Size {\n                            width: bounds.width,\n                            height: bounds.height,\n                        },\n                        shaping: *shaping,\n                        wrapping: *wrapping,\n                        ellipsis: *ellipsis,\n                    },\n                );\n\n                Some(Allocation::Cache(key))\n            }\n            Text::Raw { raw, .. } => raw.buffer.upgrade().map(Allocation::Raw),\n        })\n        .collect();\n\n    let text_areas = sections\n        .iter()\n        .zip(allocations.iter())\n        .filter_map(|(section, allocation)| {\n            let (buffer, hint_factor, position, color, clip_bounds, transformation) = match section\n            {\n                Text::Paragraph {\n                    position,\n                    color,\n                    clip_bounds,\n                    transformation,\n                    ..\n                } => {\n                    use crate::core::text::Paragraph as _;\n\n                    let Some(Allocation::Paragraph(paragraph)) = allocation else {\n                        return None;\n                    };\n\n                    (\n                        paragraph.buffer(),\n                        paragraph.hint_factor(),\n                        *position,\n                        *color,\n                        *clip_bounds,\n                        *transformation,\n                    )\n                }\n                Text::Editor {\n                    position,\n                    color,\n                    clip_bounds,\n                    transformation,\n                    ..\n                } => {\n                    use crate::core::text::Editor as _;\n\n                    let Some(Allocation::Editor(editor)) = allocation else {\n                        return None;\n                    };\n\n                    (\n                        editor.buffer(),\n                        editor.hint_factor(),\n                        *position,\n                        *color,\n                        *clip_bounds,\n                        *transformation,\n                    )\n                }\n                Text::Cached {\n                    bounds,\n                    align_x,\n                    align_y,\n                    color,\n                    clip_bounds,\n                    ..\n                } => {\n                    let Some(Allocation::Cache(key)) = allocation else {\n                        return None;\n                    };\n\n                    let entry = buffer_cache.get(key).expect(\"Get cached buffer\");\n\n                    let mut position = bounds.position();\n\n                    position.x = match align_x {\n                        Alignment::Default | Alignment::Left | Alignment::Justified => position.x,\n                        Alignment::Center => position.x - entry.min_bounds.width / 2.0,\n                        Alignment::Right => position.x - entry.min_bounds.width,\n                    };\n\n                    position.y = match align_y {\n                        alignment::Vertical::Top => position.y,\n                        alignment::Vertical::Center => position.y - entry.min_bounds.height / 2.0,\n                        alignment::Vertical::Bottom => position.y - entry.min_bounds.height,\n                    };\n\n                    (\n                        &entry.buffer,\n                        None,\n                        position,\n                        *color,\n                        *clip_bounds,\n                        Transformation::IDENTITY,\n                    )\n                }\n                Text::Raw {\n                    raw,\n                    transformation,\n                } => {\n                    let Some(Allocation::Raw(buffer)) = allocation else {\n                        return None;\n                    };\n\n                    (\n                        buffer.as_ref(),\n                        None,\n                        raw.position,\n                        raw.color,\n                        raw.clip_bounds,\n                        *transformation,\n                    )\n                }\n            };\n\n            let clip_bounds = layer_bounds\n                .intersection(&(clip_bounds * transformation * layer_transformation))?;\n\n            let mut position = position * transformation * layer_transformation;\n            let mut scale = transformation.scale_factor() * layer_transformation.scale_factor();\n\n            if let Some(hint_factor) = hint_factor {\n                let font_size = (buffer.metrics().font_size / hint_factor).round() as u32;\n\n                position.x = position.x.round()\n                    // This is a hack! Empirically and cluelessly derived\n                    // It tries to nudge hinted text to improve rasterization\n                    + if font_size.is_multiple_of(2) {\n                        0.25\n                    } else if font_size.is_multiple_of(5) {\n                        -0.45 // Deliberately avoid 0.5 to circumvent erratic rounding due to floating precision errors\n                    } else {\n                        -0.25\n                    };\n\n                scale /= hint_factor;\n            }\n\n            Some(cryoglyph::TextArea {\n                buffer,\n                left: position.x,\n                top: position.y,\n                scale,\n                bounds: cryoglyph::TextBounds {\n                    left: clip_bounds.x.round() as i32,\n                    top: clip_bounds.y.round() as i32,\n                    right: (clip_bounds.x + clip_bounds.width).round() as i32,\n                    bottom: (clip_bounds.y + clip_bounds.height).round() as i32,\n                },\n                default_color: to_color(color),\n            })\n        });\n\n    renderer.prepare(\n        device,\n        queue,\n        encoder,\n        font_system,\n        atlas,\n        viewport,\n        text_areas,\n        &mut cryoglyph::SwashCache::new(),\n    )\n}\n"
  },
  {
    "path": "wgpu/src/triangle/msaa.rs",
    "content": "use crate::core::{Size, Transformation};\nuse crate::graphics;\n\nuse std::num::NonZeroU64;\nuse std::sync::{Arc, RwLock};\n\n#[derive(Debug, Clone)]\npub struct Pipeline {\n    format: wgpu::TextureFormat,\n    sampler: wgpu::Sampler,\n    raw: wgpu::RenderPipeline,\n    constant_layout: wgpu::BindGroupLayout,\n    texture_layout: wgpu::BindGroupLayout,\n    sample_count: u32,\n    targets: Arc<RwLock<Option<Targets>>>,\n}\n\nimpl Pipeline {\n    pub fn new(\n        device: &wgpu::Device,\n        format: wgpu::TextureFormat,\n        antialiasing: graphics::Antialiasing,\n    ) -> Pipeline {\n        let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());\n\n        let constant_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n            label: Some(\"iced_wgpu::triangle:msaa uniforms layout\"),\n            entries: &[\n                wgpu::BindGroupLayoutEntry {\n                    binding: 0,\n                    visibility: wgpu::ShaderStages::FRAGMENT,\n                    ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),\n                    count: None,\n                },\n                wgpu::BindGroupLayoutEntry {\n                    binding: 1,\n                    visibility: wgpu::ShaderStages::VERTEX,\n                    ty: wgpu::BindingType::Buffer {\n                        ty: wgpu::BufferBindingType::Uniform,\n                        has_dynamic_offset: false,\n                        min_binding_size: None,\n                    },\n                    count: None,\n                },\n            ],\n        });\n\n        let texture_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa texture layout\"),\n            entries: &[wgpu::BindGroupLayoutEntry {\n                binding: 0,\n                visibility: wgpu::ShaderStages::FRAGMENT,\n                ty: wgpu::BindingType::Texture {\n                    sample_type: wgpu::TextureSampleType::Float { filterable: false },\n                    view_dimension: wgpu::TextureViewDimension::D2,\n                    multisampled: false,\n                },\n                count: None,\n            }],\n        });\n\n        let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa pipeline layout\"),\n            bind_group_layouts: &[&constant_layout, &texture_layout],\n            immediate_size: 0,\n        });\n\n        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: Some(\"iced_wgpu triangle blit_shader\"),\n            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!(\n                \"../shader/blit.wgsl\"\n            ))),\n        });\n\n        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa pipeline\"),\n            layout: Some(&layout),\n            vertex: wgpu::VertexState {\n                module: &shader,\n                entry_point: Some(\"vs_main\"),\n                buffers: &[],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            },\n            fragment: Some(wgpu::FragmentState {\n                module: &shader,\n                entry_point: Some(\"fs_main\"),\n                targets: &[Some(wgpu::ColorTargetState {\n                    format,\n                    blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),\n                    write_mask: wgpu::ColorWrites::ALL,\n                })],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            }),\n            primitive: wgpu::PrimitiveState {\n                topology: wgpu::PrimitiveTopology::TriangleList,\n                front_face: wgpu::FrontFace::Cw,\n                ..Default::default()\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 {\n            format,\n            sampler,\n            raw: pipeline,\n            constant_layout,\n            texture_layout,\n            sample_count: antialiasing.sample_count(),\n            targets: Arc::new(RwLock::new(None)),\n        }\n    }\n\n    fn targets(&self, device: &wgpu::Device, region_size: Size<u32>) -> Targets {\n        let mut targets = self.targets.write().expect(\"Write MSAA targets\");\n\n        match targets.as_mut() {\n            Some(targets)\n                if region_size.width <= targets.size.width\n                    && region_size.height <= targets.size.height => {}\n            _ => {\n                *targets = Some(Targets::new(\n                    device,\n                    self.format,\n                    &self.texture_layout,\n                    self.sample_count,\n                    region_size,\n                ));\n            }\n        }\n\n        targets.as_ref().unwrap().clone()\n    }\n\n    pub fn render_pass<'a>(&self, encoder: &'a mut wgpu::CommandEncoder) -> wgpu::RenderPass<'a> {\n        let targets = self.targets.read().expect(\"Read MSAA targets\");\n        let targets = targets.as_ref().unwrap();\n\n        encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n            label: Some(\"iced_wgpu.triangle.render_pass\"),\n            color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                view: &targets.attachment,\n                depth_slice: None,\n                resolve_target: Some(&targets.resolve),\n                ops: wgpu::Operations {\n                    load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),\n                    store: wgpu::StoreOp::Store,\n                },\n            })],\n            depth_stencil_attachment: None,\n            timestamp_writes: None,\n            occlusion_query_set: None,\n            multiview_mask: None,\n        })\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct Targets {\n    attachment: wgpu::TextureView,\n    resolve: wgpu::TextureView,\n    bind_group: wgpu::BindGroup,\n    size: Size<u32>,\n}\n\nimpl Targets {\n    pub fn new(\n        device: &wgpu::Device,\n        format: wgpu::TextureFormat,\n        texture_layout: &wgpu::BindGroupLayout,\n        sample_count: u32,\n        size: Size<u32>,\n    ) -> Targets {\n        let extent = wgpu::Extent3d {\n            width: size.width,\n            height: size.height,\n            depth_or_array_layers: 1,\n        };\n\n        let attachment = device.create_texture(&wgpu::TextureDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa attachment\"),\n            size: extent,\n            mip_level_count: 1,\n            sample_count,\n            dimension: wgpu::TextureDimension::D2,\n            format,\n            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,\n            view_formats: &[],\n        });\n\n        let resolve = device.create_texture(&wgpu::TextureDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa resolve target\"),\n            size: extent,\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format,\n            usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,\n            view_formats: &[],\n        });\n\n        let attachment = attachment.create_view(&wgpu::TextureViewDescriptor::default());\n\n        let resolve = resolve.create_view(&wgpu::TextureViewDescriptor::default());\n\n        let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa texture bind group\"),\n            layout: texture_layout,\n            entries: &[wgpu::BindGroupEntry {\n                binding: 0,\n                resource: wgpu::BindingResource::TextureView(&resolve),\n            }],\n        });\n\n        Targets {\n            attachment,\n            resolve,\n            bind_group,\n            size,\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]\n#[repr(C)]\nstruct Ratio {\n    u: f32,\n    v: f32,\n    // Padding field for 16-byte alignment.\n    // See https://docs.rs/wgpu/latest/wgpu/struct.DownlevelFlags.html#associatedconstant.BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED\n    _padding: [f32; 2],\n}\n\npub struct State {\n    ratio: wgpu::Buffer,\n    constants: wgpu::BindGroup,\n    last_ratio: Option<Ratio>,\n}\n\nimpl State {\n    pub fn new(device: &wgpu::Device, pipeline: &Pipeline) -> Self {\n        let ratio = device.create_buffer(&wgpu::BufferDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa ratio\"),\n            size: std::mem::size_of::<Ratio>() as u64,\n            usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,\n            mapped_at_creation: false,\n        });\n\n        let constants = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa uniforms bind group\"),\n            layout: &pipeline.constant_layout,\n            entries: &[\n                wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::Sampler(&pipeline.sampler),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 1,\n                    resource: ratio.as_entire_binding(),\n                },\n            ],\n        });\n\n        Self {\n            ratio,\n            constants,\n            last_ratio: None,\n        }\n    }\n\n    pub fn prepare(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        pipeline: &Pipeline,\n        region_size: Size<u32>,\n    ) -> Transformation {\n        let targets = pipeline.targets(device, region_size);\n\n        let ratio = Ratio {\n            u: region_size.width as f32 / targets.size.width as f32,\n            v: region_size.height as f32 / targets.size.height as f32,\n            _padding: [0.0; 2],\n        };\n\n        if Some(ratio) != self.last_ratio {\n            belt.write_buffer(\n                encoder,\n                &self.ratio,\n                0,\n                NonZeroU64::new(std::mem::size_of::<Ratio>() as u64).expect(\"non-empty ratio\"),\n            )\n            .copy_from_slice(bytemuck::bytes_of(&ratio));\n\n            self.last_ratio = Some(ratio);\n        }\n\n        Transformation::orthographic(targets.size.width, targets.size.height)\n    }\n\n    pub fn render(\n        &self,\n        pipeline: &Pipeline,\n        encoder: &mut wgpu::CommandEncoder,\n        target: &wgpu::TextureView,\n    ) {\n        let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n            label: Some(\"iced_wgpu::triangle::msaa render pass\"),\n            color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                view: target,\n                depth_slice: None,\n                resolve_target: None,\n                ops: wgpu::Operations {\n                    load: wgpu::LoadOp::Load,\n                    store: wgpu::StoreOp::Store,\n                },\n            })],\n            depth_stencil_attachment: None,\n            timestamp_writes: None,\n            occlusion_query_set: None,\n            multiview_mask: None,\n        });\n\n        render_pass.set_pipeline(&pipeline.raw);\n        render_pass.set_bind_group(0, &self.constants, &[]);\n        render_pass.set_bind_group(\n            1,\n            &pipeline\n                .targets\n                .read()\n                .expect(\"Read MSAA targets\")\n                .as_ref()\n                .unwrap()\n                .bind_group,\n            &[],\n        );\n        render_pass.draw(0..6, 0..1);\n    }\n}\n"
  },
  {
    "path": "wgpu/src/triangle.rs",
    "content": "//! Draw meshes of triangles.\nmod msaa;\n\nuse crate::Buffer;\nuse crate::core::{Point, Rectangle, Size, Transformation, Vector};\nuse crate::graphics::Antialiasing;\nuse crate::graphics::mesh::{self, Mesh};\n\nuse rustc_hash::FxHashMap;\nuse std::collections::hash_map;\nuse std::sync::Arc;\n\nconst INITIAL_INDEX_COUNT: usize = 1_000;\nconst INITIAL_VERTEX_COUNT: usize = 1_000;\n\npub type Batch = Vec<Item>;\n\n#[derive(Debug)]\npub enum Item {\n    Group {\n        transformation: Transformation,\n        meshes: Vec<Mesh>,\n    },\n    Cached {\n        transformation: Transformation,\n        cache: mesh::Cache,\n    },\n}\n\n#[derive(Debug)]\nstruct Upload {\n    layer: Layer,\n    transformation: Transformation,\n    version: usize,\n    batch: Arc<[Mesh]>,\n}\n\n#[derive(Debug, Default)]\npub struct Storage {\n    uploads: FxHashMap<mesh::Id, Upload>,\n}\n\nimpl Storage {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    fn get(&self, cache: &mesh::Cache) -> Option<&Upload> {\n        if cache.is_empty() {\n            return None;\n        }\n\n        self.uploads.get(&cache.id())\n    }\n\n    fn prepare(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        solid: &solid::Pipeline,\n        gradient: &gradient::Pipeline,\n        cache: &mesh::Cache,\n        new_transformation: Transformation,\n    ) {\n        match self.uploads.entry(cache.id()) {\n            hash_map::Entry::Occupied(entry) => {\n                let upload = entry.into_mut();\n\n                if upload.version != cache.version() || upload.transformation != new_transformation\n                {\n                    if !cache.is_empty() {\n                        upload.layer.prepare(\n                            device,\n                            encoder,\n                            belt,\n                            solid,\n                            gradient,\n                            cache.batch(),\n                            new_transformation,\n                        );\n                    }\n\n                    upload.batch = cache.batch().clone();\n                    upload.version = cache.version();\n                    upload.transformation = new_transformation;\n                }\n            }\n            hash_map::Entry::Vacant(entry) => {\n                let mut layer = Layer::new(device, solid, gradient);\n\n                layer.prepare(\n                    device,\n                    encoder,\n                    belt,\n                    solid,\n                    gradient,\n                    cache.batch(),\n                    new_transformation,\n                );\n\n                let _ = entry.insert(Upload {\n                    layer,\n                    transformation: new_transformation,\n                    version: 0,\n                    batch: cache.batch().clone(),\n                });\n\n                log::debug!(\n                    \"New mesh upload: {:?} (total: {})\",\n                    cache.id(),\n                    self.uploads.len()\n                );\n            }\n        }\n    }\n\n    pub fn trim(&mut self) {\n        self.uploads\n            .retain(|_id, upload| Arc::strong_count(&upload.batch) > 1);\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct Pipeline {\n    msaa: Option<msaa::Pipeline>,\n    solid: solid::Pipeline,\n    gradient: gradient::Pipeline,\n}\n\npub struct State {\n    msaa: Option<msaa::State>,\n    layers: Vec<Layer>,\n    prepare_layer: usize,\n    storage: Storage,\n}\n\nimpl State {\n    pub fn new(device: &wgpu::Device, pipeline: &Pipeline) -> Self {\n        Self {\n            msaa: pipeline\n                .msaa\n                .as_ref()\n                .map(|pipeline| msaa::State::new(device, pipeline)),\n            layers: Vec::new(),\n            prepare_layer: 0,\n            storage: Storage::new(),\n        }\n    }\n\n    pub fn prepare(\n        &mut self,\n        pipeline: &Pipeline,\n        device: &wgpu::Device,\n        belt: &mut wgpu::util::StagingBelt,\n        encoder: &mut wgpu::CommandEncoder,\n        items: &[Item],\n        scale: Transformation,\n        target_size: Size<u32>,\n    ) {\n        let projection =\n            if let Some((state, pipeline)) = self.msaa.as_mut().zip(pipeline.msaa.as_ref()) {\n                state.prepare(device, encoder, belt, pipeline, target_size) * scale\n            } else {\n                Transformation::orthographic(target_size.width, target_size.height) * scale\n            };\n\n        for item in items {\n            match item {\n                Item::Group {\n                    transformation,\n                    meshes,\n                } => {\n                    if self.layers.len() <= self.prepare_layer {\n                        self.layers\n                            .push(Layer::new(device, &pipeline.solid, &pipeline.gradient));\n                    }\n\n                    let layer = &mut self.layers[self.prepare_layer];\n                    layer.prepare(\n                        device,\n                        encoder,\n                        belt,\n                        &pipeline.solid,\n                        &pipeline.gradient,\n                        meshes,\n                        projection * *transformation,\n                    );\n\n                    self.prepare_layer += 1;\n                }\n                Item::Cached {\n                    transformation,\n                    cache,\n                } => {\n                    self.storage.prepare(\n                        device,\n                        encoder,\n                        belt,\n                        &pipeline.solid,\n                        &pipeline.gradient,\n                        cache,\n                        projection * *transformation,\n                    );\n                }\n            }\n        }\n    }\n\n    pub fn render(\n        &mut self,\n        pipeline: &Pipeline,\n        encoder: &mut wgpu::CommandEncoder,\n        target: &wgpu::TextureView,\n        start: usize,\n        batch: &Batch,\n        bounds: Rectangle,\n        screen_transformation: Transformation,\n    ) -> usize {\n        let mut layer_count = 0;\n\n        let items = batch.iter().filter_map(|item| match item {\n            Item::Group {\n                transformation,\n                meshes,\n            } => {\n                let layer = &self.layers[start + layer_count];\n                layer_count += 1;\n\n                Some((\n                    layer,\n                    meshes.as_slice(),\n                    screen_transformation * *transformation,\n                ))\n            }\n            Item::Cached {\n                transformation,\n                cache,\n            } => {\n                let upload = self.storage.get(cache)?;\n\n                Some((\n                    &upload.layer,\n                    &upload.batch,\n                    screen_transformation * *transformation,\n                ))\n            }\n        });\n\n        render(\n            encoder,\n            target,\n            self.msaa.as_ref().zip(pipeline.msaa.as_ref()),\n            &pipeline.solid,\n            &pipeline.gradient,\n            bounds,\n            items,\n        );\n\n        layer_count\n    }\n\n    pub fn trim(&mut self) {\n        self.storage.trim();\n\n        self.prepare_layer = 0;\n    }\n}\n\nimpl Pipeline {\n    pub fn new(\n        device: &wgpu::Device,\n        format: wgpu::TextureFormat,\n        antialiasing: Option<Antialiasing>,\n    ) -> Pipeline {\n        Pipeline {\n            msaa: antialiasing.map(|a| msaa::Pipeline::new(device, format, a)),\n            solid: solid::Pipeline::new(device, format, antialiasing),\n            gradient: gradient::Pipeline::new(device, format, antialiasing),\n        }\n    }\n}\n\nfn render<'a>(\n    encoder: &mut wgpu::CommandEncoder,\n    target: &wgpu::TextureView,\n    mut msaa: Option<(&msaa::State, &msaa::Pipeline)>,\n    solid: &solid::Pipeline,\n    gradient: &gradient::Pipeline,\n    bounds: Rectangle,\n    group: impl Iterator<Item = (&'a Layer, &'a [Mesh], Transformation)>,\n) {\n    {\n        let mut render_pass = if let Some((_state, pipeline)) = &mut msaa {\n            pipeline.render_pass(encoder)\n        } else {\n            encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n                label: Some(\"iced_wgpu.triangle.render_pass\"),\n                color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                    view: target,\n                    depth_slice: None,\n                    resolve_target: None,\n                    ops: wgpu::Operations {\n                        load: wgpu::LoadOp::Load,\n                        store: wgpu::StoreOp::Store,\n                    },\n                })],\n                depth_stencil_attachment: None,\n                timestamp_writes: None,\n                occlusion_query_set: None,\n                multiview_mask: None,\n            })\n        };\n\n        for (layer, meshes, transformation) in group {\n            layer.render(\n                solid,\n                gradient,\n                meshes,\n                bounds,\n                transformation,\n                &mut render_pass,\n            );\n        }\n    }\n\n    if let Some((state, pipeline)) = msaa {\n        state.render(pipeline, encoder, target);\n    }\n}\n\n#[derive(Debug)]\npub struct Layer {\n    index_buffer: Buffer<u32>,\n    solid: solid::Layer,\n    gradient: gradient::Layer,\n}\n\nimpl Layer {\n    fn new(device: &wgpu::Device, solid: &solid::Pipeline, gradient: &gradient::Pipeline) -> Self {\n        Self {\n            index_buffer: Buffer::new(\n                device,\n                \"iced_wgpu.triangle.index_buffer\",\n                INITIAL_INDEX_COUNT,\n                wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,\n            ),\n            solid: solid::Layer::new(device, &solid.constants_layout),\n            gradient: gradient::Layer::new(device, &gradient.constants_layout),\n        }\n    }\n\n    fn prepare(\n        &mut self,\n        device: &wgpu::Device,\n        encoder: &mut wgpu::CommandEncoder,\n        belt: &mut wgpu::util::StagingBelt,\n        solid: &solid::Pipeline,\n        gradient: &gradient::Pipeline,\n        meshes: &[Mesh],\n        transformation: Transformation,\n    ) {\n        // Count the total amount of vertices & indices we need to handle\n        let count = mesh::attribute_count_of(meshes);\n\n        // Then we ensure the current attribute buffers are big enough, resizing if necessary.\n        // We are not currently using the return value of these functions as we have no system in\n        // place to calculate mesh diff, or to know whether or not that would be more performant for\n        // the majority of use cases. Therefore we will write GPU data every frame (for now).\n        let _ = self.index_buffer.resize(device, count.indices);\n        let _ = self.solid.vertices.resize(device, count.solid_vertices);\n        let _ = self\n            .gradient\n            .vertices\n            .resize(device, count.gradient_vertices);\n\n        if self.solid.uniforms.resize(device, count.solids) {\n            self.solid.constants =\n                solid::Layer::bind_group(device, &self.solid.uniforms.raw, &solid.constants_layout);\n        }\n\n        if self.gradient.uniforms.resize(device, count.gradients) {\n            self.gradient.constants = gradient::Layer::bind_group(\n                device,\n                &self.gradient.uniforms.raw,\n                &gradient.constants_layout,\n            );\n        }\n\n        let mut solid_vertex_offset = 0;\n        let mut solid_uniform_offset = 0;\n        let mut gradient_vertex_offset = 0;\n        let mut gradient_uniform_offset = 0;\n        let mut index_offset = 0;\n\n        for mesh in meshes {\n            let clip_bounds = mesh.clip_bounds() * transformation;\n            let snap_distance = clip_bounds\n                .snap()\n                .map(|snapped_bounds| {\n                    Point::new(snapped_bounds.x as f32, snapped_bounds.y as f32)\n                        - clip_bounds.position()\n                })\n                .unwrap_or(Vector::ZERO);\n\n            let uniforms = Uniforms::new(\n                transformation\n                    * mesh.transformation()\n                    * Transformation::translate(snap_distance.x, snap_distance.y),\n            );\n\n            let indices = mesh.indices();\n\n            index_offset += self\n                .index_buffer\n                .write(encoder, belt, index_offset, indices);\n\n            match mesh {\n                Mesh::Solid { buffers, .. } => {\n                    solid_vertex_offset += self.solid.vertices.write(\n                        encoder,\n                        belt,\n                        solid_vertex_offset,\n                        &buffers.vertices,\n                    );\n\n                    solid_uniform_offset +=\n                        self.solid\n                            .uniforms\n                            .write(encoder, belt, solid_uniform_offset, &[uniforms]);\n                }\n                Mesh::Gradient { buffers, .. } => {\n                    gradient_vertex_offset += self.gradient.vertices.write(\n                        encoder,\n                        belt,\n                        gradient_vertex_offset,\n                        &buffers.vertices,\n                    );\n\n                    gradient_uniform_offset += self.gradient.uniforms.write(\n                        encoder,\n                        belt,\n                        gradient_uniform_offset,\n                        &[uniforms],\n                    );\n                }\n            }\n        }\n    }\n\n    fn render<'a>(\n        &'a self,\n        solid: &'a solid::Pipeline,\n        gradient: &'a gradient::Pipeline,\n        meshes: &[Mesh],\n        bounds: Rectangle,\n        transformation: Transformation,\n        render_pass: &mut wgpu::RenderPass<'a>,\n    ) {\n        let mut num_solids = 0;\n        let mut num_gradients = 0;\n        let mut solid_offset = 0;\n        let mut gradient_offset = 0;\n        let mut index_offset = 0;\n        let mut last_is_solid = None;\n\n        for mesh in meshes {\n            let Some(clip_bounds) = bounds\n                .intersection(&(mesh.clip_bounds() * transformation))\n                .and_then(Rectangle::snap)\n            else {\n                match mesh {\n                    Mesh::Solid { buffers, .. } => {\n                        solid_offset += buffers.vertices.len();\n                        num_solids += 1;\n                    }\n                    Mesh::Gradient { buffers, .. } => {\n                        gradient_offset += buffers.vertices.len();\n                        num_gradients += 1;\n                    }\n                }\n                continue;\n            };\n\n            render_pass.set_scissor_rect(\n                clip_bounds.x,\n                clip_bounds.y,\n                clip_bounds.width,\n                clip_bounds.height,\n            );\n\n            match mesh {\n                Mesh::Solid { buffers, .. } => {\n                    if !last_is_solid.unwrap_or(false) {\n                        render_pass.set_pipeline(&solid.pipeline);\n\n                        last_is_solid = Some(true);\n                    }\n\n                    render_pass.set_bind_group(\n                        0,\n                        &self.solid.constants,\n                        &[(num_solids * std::mem::size_of::<Uniforms>()) as u32],\n                    );\n\n                    render_pass.set_vertex_buffer(\n                        0,\n                        self.solid\n                            .vertices\n                            .range(solid_offset, solid_offset + buffers.vertices.len()),\n                    );\n\n                    num_solids += 1;\n                    solid_offset += buffers.vertices.len();\n                }\n                Mesh::Gradient { buffers, .. } => {\n                    if last_is_solid.unwrap_or(true) {\n                        render_pass.set_pipeline(&gradient.pipeline);\n\n                        last_is_solid = Some(false);\n                    }\n\n                    render_pass.set_bind_group(\n                        0,\n                        &self.gradient.constants,\n                        &[(num_gradients * std::mem::size_of::<Uniforms>()) as u32],\n                    );\n\n                    render_pass.set_vertex_buffer(\n                        0,\n                        self.gradient\n                            .vertices\n                            .range(gradient_offset, gradient_offset + buffers.vertices.len()),\n                    );\n\n                    num_gradients += 1;\n                    gradient_offset += buffers.vertices.len();\n                }\n            };\n\n            render_pass.set_index_buffer(\n                self.index_buffer\n                    .range(index_offset, index_offset + mesh.indices().len()),\n                wgpu::IndexFormat::Uint32,\n            );\n\n            render_pass.draw_indexed(0..mesh.indices().len() as u32, 0, 0..1);\n\n            index_offset += mesh.indices().len();\n        }\n    }\n}\n\nfn fragment_target(texture_format: wgpu::TextureFormat) -> wgpu::ColorTargetState {\n    wgpu::ColorTargetState {\n        format: texture_format,\n        blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),\n        write_mask: wgpu::ColorWrites::ALL,\n    }\n}\n\nfn primitive_state() -> wgpu::PrimitiveState {\n    wgpu::PrimitiveState {\n        topology: wgpu::PrimitiveTopology::TriangleList,\n        front_face: wgpu::FrontFace::Cw,\n        ..Default::default()\n    }\n}\n\nfn multisample_state(antialiasing: Option<Antialiasing>) -> wgpu::MultisampleState {\n    wgpu::MultisampleState {\n        count: antialiasing.map(Antialiasing::sample_count).unwrap_or(1),\n        mask: !0,\n        alpha_to_coverage_enabled: false,\n    }\n}\n\n#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]\n#[repr(C)]\npub struct Uniforms {\n    transform: [f32; 16],\n    /// Uniform values must be 256-aligned;\n    /// see: [`wgpu::Limits`] `min_uniform_buffer_offset_alignment`.\n    _padding: [f32; 48],\n}\n\nimpl Uniforms {\n    pub fn new(transform: Transformation) -> Self {\n        Self {\n            transform: transform.into(),\n            _padding: [0.0; 48],\n        }\n    }\n\n    pub fn entry() -> wgpu::BindGroupLayoutEntry {\n        wgpu::BindGroupLayoutEntry {\n            binding: 0,\n            visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,\n            ty: wgpu::BindingType::Buffer {\n                ty: wgpu::BufferBindingType::Uniform,\n                has_dynamic_offset: true,\n                min_binding_size: wgpu::BufferSize::new(std::mem::size_of::<Self>() as u64),\n            },\n            count: None,\n        }\n    }\n\n    pub fn min_size() -> Option<wgpu::BufferSize> {\n        wgpu::BufferSize::new(std::mem::size_of::<Self>() as u64)\n    }\n}\n\nmod solid {\n    use crate::Buffer;\n    use crate::graphics::Antialiasing;\n    use crate::graphics::mesh;\n    use crate::triangle;\n\n    #[derive(Debug, Clone)]\n    pub struct Pipeline {\n        pub pipeline: wgpu::RenderPipeline,\n        pub constants_layout: wgpu::BindGroupLayout,\n    }\n\n    #[derive(Debug)]\n    pub struct Layer {\n        pub vertices: Buffer<mesh::SolidVertex2D>,\n        pub uniforms: Buffer<triangle::Uniforms>,\n        pub constants: wgpu::BindGroup,\n    }\n\n    impl Layer {\n        pub fn new(device: &wgpu::Device, constants_layout: &wgpu::BindGroupLayout) -> Self {\n            let vertices = Buffer::new(\n                device,\n                \"iced_wgpu.triangle.solid.vertex_buffer\",\n                triangle::INITIAL_VERTEX_COUNT,\n                wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,\n            );\n\n            let uniforms = Buffer::new(\n                device,\n                \"iced_wgpu.triangle.solid.uniforms\",\n                1,\n                wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,\n            );\n\n            let constants = Self::bind_group(device, &uniforms.raw, constants_layout);\n\n            Self {\n                vertices,\n                uniforms,\n                constants,\n            }\n        }\n\n        pub fn bind_group(\n            device: &wgpu::Device,\n            buffer: &wgpu::Buffer,\n            layout: &wgpu::BindGroupLayout,\n        ) -> wgpu::BindGroup {\n            device.create_bind_group(&wgpu::BindGroupDescriptor {\n                label: Some(\"iced_wgpu.triangle.solid.bind_group\"),\n                layout,\n                entries: &[wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {\n                        buffer,\n                        offset: 0,\n                        size: triangle::Uniforms::min_size(),\n                    }),\n                }],\n            })\n        }\n    }\n\n    impl Pipeline {\n        pub fn new(\n            device: &wgpu::Device,\n            format: wgpu::TextureFormat,\n            antialiasing: Option<Antialiasing>,\n        ) -> Self {\n            let constants_layout =\n                device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n                    label: Some(\"iced_wgpu.triangle.solid.bind_group_layout\"),\n                    entries: &[triangle::Uniforms::entry()],\n                });\n\n            let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n                label: Some(\"iced_wgpu.triangle.solid.pipeline_layout\"),\n                bind_group_layouts: &[&constants_layout],\n                immediate_size: 0,\n            });\n\n            let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n                label: Some(\"iced_wgpu.triangle.solid.shader\"),\n                source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(concat!(\n                    include_str!(\"shader/triangle.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"shader/triangle/solid.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"shader/color.wgsl\"),\n                ))),\n            });\n\n            let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n                label: Some(\"iced_wgpu::triangle::solid pipeline\"),\n                layout: Some(&layout),\n                vertex: wgpu::VertexState {\n                    module: &shader,\n                    entry_point: Some(\"solid_vs_main\"),\n                    buffers: &[wgpu::VertexBufferLayout {\n                        array_stride: std::mem::size_of::<mesh::SolidVertex2D>() as u64,\n                        step_mode: wgpu::VertexStepMode::Vertex,\n                        attributes: &wgpu::vertex_attr_array!(\n                            // Position\n                            0 => Float32x2,\n                            // Color\n                            1 => Float32x4,\n                        ),\n                    }],\n                    compilation_options: wgpu::PipelineCompilationOptions::default(),\n                },\n                fragment: Some(wgpu::FragmentState {\n                    module: &shader,\n                    entry_point: Some(\"solid_fs_main\"),\n                    targets: &[Some(triangle::fragment_target(format))],\n                    compilation_options: wgpu::PipelineCompilationOptions::default(),\n                }),\n                primitive: triangle::primitive_state(),\n                depth_stencil: None,\n                multisample: triangle::multisample_state(antialiasing),\n                multiview_mask: None,\n                cache: None,\n            });\n\n            Self {\n                pipeline,\n                constants_layout,\n            }\n        }\n    }\n}\n\nmod gradient {\n    use crate::Buffer;\n    use crate::graphics::Antialiasing;\n    use crate::graphics::mesh;\n    use crate::triangle;\n\n    #[derive(Debug, Clone)]\n    pub struct Pipeline {\n        pub pipeline: wgpu::RenderPipeline,\n        pub constants_layout: wgpu::BindGroupLayout,\n    }\n\n    #[derive(Debug)]\n    pub struct Layer {\n        pub vertices: Buffer<mesh::GradientVertex2D>,\n        pub uniforms: Buffer<triangle::Uniforms>,\n        pub constants: wgpu::BindGroup,\n    }\n\n    impl Layer {\n        pub fn new(device: &wgpu::Device, constants_layout: &wgpu::BindGroupLayout) -> Self {\n            let vertices = Buffer::new(\n                device,\n                \"iced_wgpu.triangle.gradient.vertex_buffer\",\n                triangle::INITIAL_VERTEX_COUNT,\n                wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,\n            );\n\n            let uniforms = Buffer::new(\n                device,\n                \"iced_wgpu.triangle.gradient.uniforms\",\n                1,\n                wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,\n            );\n\n            let constants = Self::bind_group(device, &uniforms.raw, constants_layout);\n\n            Self {\n                vertices,\n                uniforms,\n                constants,\n            }\n        }\n\n        pub fn bind_group(\n            device: &wgpu::Device,\n            uniform_buffer: &wgpu::Buffer,\n            layout: &wgpu::BindGroupLayout,\n        ) -> wgpu::BindGroup {\n            device.create_bind_group(&wgpu::BindGroupDescriptor {\n                label: Some(\"iced_wgpu.triangle.gradient.bind_group\"),\n                layout,\n                entries: &[wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {\n                        buffer: uniform_buffer,\n                        offset: 0,\n                        size: triangle::Uniforms::min_size(),\n                    }),\n                }],\n            })\n        }\n    }\n\n    impl Pipeline {\n        pub fn new(\n            device: &wgpu::Device,\n            format: wgpu::TextureFormat,\n            antialiasing: Option<Antialiasing>,\n        ) -> Self {\n            let constants_layout =\n                device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n                    label: Some(\"iced_wgpu.triangle.gradient.bind_group_layout\"),\n                    entries: &[triangle::Uniforms::entry()],\n                });\n\n            let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n                label: Some(\"iced_wgpu.triangle.gradient.pipeline_layout\"),\n                bind_group_layouts: &[&constants_layout],\n                immediate_size: 0,\n            });\n\n            let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n                label: Some(\"iced_wgpu.triangle.gradient.shader\"),\n                source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(concat!(\n                    include_str!(\"shader/triangle.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"shader/triangle/gradient.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"shader/color.wgsl\"),\n                    \"\\n\",\n                    include_str!(\"shader/color/linear_rgb.wgsl\")\n                ))),\n            });\n\n            let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n                label: Some(\"iced_wgpu.triangle.gradient.pipeline\"),\n                layout: Some(&layout),\n                vertex: wgpu::VertexState {\n                    module: &shader,\n                    entry_point: Some(\"gradient_vs_main\"),\n                    buffers: &[wgpu::VertexBufferLayout {\n                        array_stride: std::mem::size_of::<mesh::GradientVertex2D>() as u64,\n                        step_mode: wgpu::VertexStepMode::Vertex,\n                        attributes: &wgpu::vertex_attr_array!(\n                            // Position\n                            0 => Float32x2,\n                            // Colors 1-2\n                            1 => Uint32x4,\n                            // Colors 3-4\n                            2 => Uint32x4,\n                            // Colors 5-6\n                            3 => Uint32x4,\n                            // Colors 7-8\n                            4 => Uint32x4,\n                            // Offsets\n                            5 => Uint32x4,\n                            // Direction\n                            6 => Float32x4\n                        ),\n                    }],\n                    compilation_options: wgpu::PipelineCompilationOptions::default(),\n                },\n                fragment: Some(wgpu::FragmentState {\n                    module: &shader,\n                    entry_point: Some(\"gradient_fs_main\"),\n                    targets: &[Some(triangle::fragment_target(format))],\n                    compilation_options: wgpu::PipelineCompilationOptions::default(),\n                }),\n                primitive: triangle::primitive_state(),\n                depth_stencil: None,\n                multisample: triangle::multisample_state(antialiasing),\n                multiview_mask: None,\n                cache: None,\n            });\n\n            Self {\n                pipeline,\n                constants_layout,\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "wgpu/src/window/compositor.rs",
    "content": "//! Connect a window with a renderer.\nuse crate::core::Color;\nuse crate::core::renderer;\nuse crate::graphics::color;\nuse crate::graphics::compositor;\nuse crate::graphics::error;\nuse crate::graphics::{self, Antialiasing, Shell, Viewport};\nuse crate::{Engine, Renderer};\n\n/// A window graphics backend for iced powered by `wgpu`.\npub struct Compositor {\n    instance: wgpu::Instance,\n    adapter: wgpu::Adapter,\n    format: wgpu::TextureFormat,\n    alpha_mode: wgpu::CompositeAlphaMode,\n    engine: Engine,\n    settings: Settings,\n}\n\n/// A compositor error.\n#[derive(Debug, Clone, thiserror::Error)]\npub enum Error {\n    /// The surface creation failed.\n    #[error(\"the surface creation failed: {0}\")]\n    SurfaceCreationFailed(#[from] wgpu::CreateSurfaceError),\n    /// The surface is not compatible.\n    #[error(\"the surface is not compatible\")]\n    IncompatibleSurface,\n    /// No adapter was found for the options requested.\n    #[error(\"no adapter was found for the options requested: {0:?}\")]\n    NoAdapterFound(String),\n    /// No device request succeeded.\n    #[error(\"no device request succeeded: {0:?}\")]\n    RequestDeviceFailed(Vec<(wgpu::Limits, wgpu::RequestDeviceError)>),\n}\n\nimpl From<Error> for graphics::Error {\n    fn from(error: Error) -> Self {\n        Self::GraphicsAdapterNotFound {\n            backend: \"wgpu\",\n            reason: error::Reason::RequestFailed(error.to_string()),\n        }\n    }\n}\n\nimpl Compositor {\n    /// Requests a new [`Compositor`] with the given [`Settings`].\n    ///\n    /// Returns `None` if no compatible graphics adapter could be found.\n    pub async fn request<W: compositor::Window>(\n        settings: Settings,\n        compatible_window: Option<W>,\n        shell: Shell,\n    ) -> Result<Self, Error> {\n        let instance = wgpu::util::new_instance_with_webgpu_detection(&wgpu::InstanceDescriptor {\n            backends: settings.backends,\n            flags: if cfg!(feature = \"strict-assertions\") {\n                wgpu::InstanceFlags::debugging()\n            } else {\n                wgpu::InstanceFlags::empty()\n            },\n            ..Default::default()\n        })\n        .await;\n\n        log::info!(\"{settings:#?}\");\n\n        #[cfg(not(target_arch = \"wasm32\"))]\n        if log::max_level() >= log::LevelFilter::Info {\n            let available_adapters: Vec<_> = instance\n                .enumerate_adapters(settings.backends)\n                .await\n                .iter()\n                .map(wgpu::Adapter::get_info)\n                .collect();\n            log::info!(\"Available adapters: {available_adapters:#?}\");\n        }\n\n        #[allow(unsafe_code)]\n        let compatible_surface =\n            compatible_window.and_then(|window| instance.create_surface(window).ok());\n\n        let adapter_options = wgpu::RequestAdapterOptions {\n            power_preference: wgpu::PowerPreference::from_env()\n                .unwrap_or(wgpu::PowerPreference::HighPerformance),\n            compatible_surface: compatible_surface.as_ref(),\n            force_fallback_adapter: false,\n        };\n\n        let adapter = instance\n            .request_adapter(&adapter_options)\n            .await\n            .map_err(|_error| Error::NoAdapterFound(format!(\"{adapter_options:?}\")))?;\n\n        log::info!(\"Selected: {:#?}\", adapter.get_info());\n\n        let (format, alpha_mode) = compatible_surface\n            .as_ref()\n            .and_then(|surface| {\n                let capabilities = surface.get_capabilities(&adapter);\n\n                let formats = capabilities.formats.iter().copied();\n\n                log::info!(\"Available formats: {formats:#?}\");\n\n                const BLACKLIST: &[wgpu::TextureFormat] = &[\n                    wgpu::TextureFormat::Rgb10a2Unorm,\n                    wgpu::TextureFormat::Rgb10a2Uint,\n                ];\n\n                let mut formats = formats.filter(|format| {\n                    format.required_features() == wgpu::Features::empty()\n                        && !BLACKLIST.contains(format)\n                });\n\n                let format = if color::GAMMA_CORRECTION {\n                    formats.find(wgpu::TextureFormat::is_srgb)\n                } else {\n                    formats.find(|format| !wgpu::TextureFormat::is_srgb(format))\n                };\n\n                let format = format.or_else(|| {\n                    log::warn!(\"No format found!\");\n\n                    capabilities.formats.first().copied()\n                });\n\n                let alpha_modes = capabilities.alpha_modes;\n\n                log::info!(\"Available alpha modes: {alpha_modes:#?}\");\n\n                let preferred_alpha =\n                    if alpha_modes.contains(&wgpu::CompositeAlphaMode::PreMultiplied) {\n                        wgpu::CompositeAlphaMode::PreMultiplied\n                    } else {\n                        wgpu::CompositeAlphaMode::Auto\n                    };\n\n                format.zip(Some(preferred_alpha))\n            })\n            .ok_or(Error::IncompatibleSurface)?;\n\n        log::info!(\"Selected format: {format:?} with alpha mode: {alpha_mode:?}\");\n\n        #[cfg(target_arch = \"wasm32\")]\n        let limits = [wgpu::Limits::downlevel_webgl2_defaults().using_resolution(adapter.limits())];\n\n        #[cfg(not(target_arch = \"wasm32\"))]\n        let limits = [wgpu::Limits::default(), wgpu::Limits::downlevel_defaults()];\n\n        let limits = limits.into_iter().map(|limits| wgpu::Limits {\n            max_bind_groups: 2,\n            max_non_sampler_bindings: 2048,\n            ..limits\n        });\n\n        // Request SHADER_F16 only if the adapter supports it (e.g., not available in WebGL2)\n        let required_features = if adapter.features().contains(wgpu::Features::SHADER_F16) {\n            wgpu::Features::SHADER_F16\n        } else {\n            wgpu::Features::empty()\n        };\n\n        let mut errors = Vec::new();\n\n        for required_limits in limits {\n            let result = adapter\n                .request_device(&wgpu::DeviceDescriptor {\n                    label: Some(\"iced_wgpu::window::compositor device descriptor\"),\n                    required_features,\n                    required_limits: required_limits.clone(),\n                    memory_hints: wgpu::MemoryHints::MemoryUsage,\n                    trace: wgpu::Trace::Off,\n                    experimental_features: wgpu::ExperimentalFeatures::disabled(),\n                })\n                .await;\n\n            match result {\n                Ok((device, queue)) => {\n                    let engine = Engine::new(\n                        &adapter,\n                        device,\n                        queue,\n                        format,\n                        settings.antialiasing,\n                        shell,\n                    );\n\n                    return Ok(Compositor {\n                        instance,\n                        adapter,\n                        format,\n                        alpha_mode,\n                        engine,\n                        settings,\n                    });\n                }\n                Err(error) => {\n                    errors.push((required_limits, error));\n                }\n            }\n        }\n\n        Err(Error::RequestDeviceFailed(errors))\n    }\n}\n\n/// Creates a [`Compositor`] with the given [`Settings`] and window.\npub async fn new<W: compositor::Window>(\n    settings: Settings,\n    compatible_window: W,\n    shell: Shell,\n) -> Result<Compositor, Error> {\n    Compositor::request(settings, Some(compatible_window), shell).await\n}\n\n/// Presents the given primitives with the given [`Compositor`].\npub fn present(\n    renderer: &mut Renderer,\n    surface: &mut wgpu::Surface<'static>,\n    viewport: &Viewport,\n    background_color: Color,\n    on_pre_present: impl FnOnce(),\n) -> Result<(), compositor::SurfaceError> {\n    match surface.get_current_texture() {\n        Ok(frame) => {\n            let view = &frame\n                .texture\n                .create_view(&wgpu::TextureViewDescriptor::default());\n\n            let _submission = renderer.present(\n                Some(background_color),\n                frame.texture.format(),\n                view,\n                viewport,\n            );\n\n            // Present the frame\n            on_pre_present();\n            frame.present();\n\n            Ok(())\n        }\n        Err(error) => match error {\n            wgpu::SurfaceError::Timeout => Err(compositor::SurfaceError::Timeout),\n            wgpu::SurfaceError::Outdated => Err(compositor::SurfaceError::Outdated),\n            wgpu::SurfaceError::Lost => Err(compositor::SurfaceError::Lost),\n            wgpu::SurfaceError::OutOfMemory => Err(compositor::SurfaceError::OutOfMemory),\n            wgpu::SurfaceError::Other => Err(compositor::SurfaceError::Other),\n        },\n    }\n}\n\nimpl graphics::Compositor for Compositor {\n    type Renderer = Renderer;\n    type Surface = wgpu::Surface<'static>;\n\n    async fn with_backend(\n        settings: compositor::Settings,\n        _display: impl compositor::Display,\n        compatible_window: impl compositor::Window,\n        shell: Shell,\n        backend: Option<&str>,\n    ) -> Result<Self, graphics::Error> {\n        match backend {\n            None | Some(\"wgpu\") => {\n                let mut settings = Settings::from(settings);\n\n                if let Some(backends) = wgpu::Backends::from_env() {\n                    settings.backends = backends;\n                }\n\n                if let Some(present_mode) = present_mode_from_env() {\n                    settings.present_mode = present_mode;\n                }\n\n                Ok(new(settings, compatible_window, shell).await?)\n            }\n            Some(backend) => Err(graphics::Error::GraphicsAdapterNotFound {\n                backend: \"wgpu\",\n                reason: error::Reason::DidNotMatch {\n                    preferred_backend: backend.to_owned(),\n                },\n            }),\n        }\n    }\n\n    fn create_renderer(&self, settings: renderer::Settings) -> Self::Renderer {\n        Renderer::new(self.engine.clone(), settings)\n    }\n\n    fn create_surface<W: compositor::Window>(\n        &mut self,\n        window: W,\n        width: u32,\n        height: u32,\n    ) -> Self::Surface {\n        let mut surface = self\n            .instance\n            .create_surface(window)\n            .expect(\"Create surface\");\n\n        if width > 0 && height > 0 {\n            self.configure_surface(&mut surface, width, height);\n        }\n\n        surface\n    }\n\n    fn configure_surface(&mut self, surface: &mut Self::Surface, width: u32, height: u32) {\n        surface.configure(\n            &self.engine.device,\n            &wgpu::SurfaceConfiguration {\n                usage: wgpu::TextureUsages::RENDER_ATTACHMENT,\n                format: self.format,\n                present_mode: self.settings.present_mode,\n                width,\n                height,\n                alpha_mode: self.alpha_mode,\n                view_formats: vec![],\n                desired_maximum_frame_latency: 1,\n            },\n        );\n    }\n\n    fn information(&self) -> compositor::Information {\n        let information = self.adapter.get_info();\n\n        compositor::Information {\n            adapter: information.name,\n            backend: format!(\"{:?}\", information.backend),\n        }\n    }\n\n    fn present(\n        &mut self,\n        renderer: &mut Self::Renderer,\n        surface: &mut Self::Surface,\n        viewport: &Viewport,\n        background_color: Color,\n        on_pre_present: impl FnOnce(),\n    ) -> Result<(), compositor::SurfaceError> {\n        present(\n            renderer,\n            surface,\n            viewport,\n            background_color,\n            on_pre_present,\n        )\n    }\n\n    fn screenshot(\n        &mut self,\n        renderer: &mut Self::Renderer,\n        viewport: &Viewport,\n        background_color: Color,\n    ) -> Vec<u8> {\n        renderer.screenshot(viewport, background_color)\n    }\n}\n\n/// The settings of a [`Compositor`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Settings {\n    /// The present mode of the [`Renderer`].\n    ///\n    /// [`Renderer`]: crate::Renderer\n    pub present_mode: wgpu::PresentMode,\n\n    /// The graphics backends to use.\n    pub backends: wgpu::Backends,\n\n    /// The antialiasing strategy that will be used for triangle primitives.\n    ///\n    /// By default, it is `None`.\n    pub antialiasing: Option<Antialiasing>,\n}\n\nimpl Default for Settings {\n    fn default() -> Settings {\n        Settings {\n            present_mode: wgpu::PresentMode::AutoVsync,\n            backends: wgpu::Backends::all(),\n            antialiasing: None,\n        }\n    }\n}\n\nimpl From<compositor::Settings> for Settings {\n    fn from(settings: compositor::Settings) -> Self {\n        Self {\n            present_mode: if settings.vsync {\n                wgpu::PresentMode::AutoVsync\n            } else {\n                wgpu::PresentMode::AutoNoVsync\n            },\n            antialiasing: settings.antialiasing,\n            ..Settings::default()\n        }\n    }\n}\n\n/// Obtains a [`wgpu::PresentMode`] from the current environment\n/// configuration, if set.\n///\n/// The value returned by this function can be changed by setting\n/// the `ICED_PRESENT_MODE` env variable. The possible values are:\n///\n/// - `vsync` → [`wgpu::PresentMode::AutoVsync`]\n/// - `no_vsync` → [`wgpu::PresentMode::AutoNoVsync`]\n/// - `immediate` → [`wgpu::PresentMode::Immediate`]\n/// - `fifo` → [`wgpu::PresentMode::Fifo`]\n/// - `fifo_relaxed` → [`wgpu::PresentMode::FifoRelaxed`]\n/// - `mailbox` → [`wgpu::PresentMode::Mailbox`]\npub fn present_mode_from_env() -> Option<wgpu::PresentMode> {\n    let present_mode = std::env::var(\"ICED_PRESENT_MODE\").ok()?;\n\n    match present_mode.to_lowercase().as_str() {\n        \"vsync\" => Some(wgpu::PresentMode::AutoVsync),\n        \"no_vsync\" => Some(wgpu::PresentMode::AutoNoVsync),\n        \"immediate\" => Some(wgpu::PresentMode::Immediate),\n        \"fifo\" => Some(wgpu::PresentMode::Fifo),\n        \"fifo_relaxed\" => Some(wgpu::PresentMode::FifoRelaxed),\n        \"mailbox\" => Some(wgpu::PresentMode::Mailbox),\n        _ => None,\n    }\n}\n"
  },
  {
    "path": "wgpu/src/window.rs",
    "content": "//! Display rendering results on windows.\npub mod compositor;\n\npub use compositor::Compositor;\npub use wgpu::Surface;\n"
  },
  {
    "path": "widget/Cargo.toml",
    "content": "[package]\nname = \"iced_widget\"\ndescription = \"The built-in widgets for iced\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--cfg\", \"docsrs\"]\nall-features = true\n\n[features]\nlazy = [\"ouroboros\"]\nimage = [\"iced_renderer/image\"]\nsvg = [\"iced_renderer/svg\"]\ncanvas = [\"iced_renderer/geometry\"]\nqr_code = [\"canvas\", \"dep:qrcode\"]\nwgpu = [\"iced_renderer/wgpu-bare\"]\nmarkdown = [\"dep:pulldown-cmark\"]\nhighlighter = [\"dep:iced_highlighter\"]\nadvanced = []\n\n[dependencies]\niced_renderer.workspace = true\n\nnum-traits.workspace = true\nlog.workspace = true\nrustc-hash.workspace = true\nthiserror.workspace = true\nunicode-segmentation.workspace = true\n\nouroboros.workspace = true\nouroboros.optional = true\n\nqrcode.workspace = true\nqrcode.optional = true\n\npulldown-cmark.workspace = true\npulldown-cmark.optional = true\n\niced_highlighter.workspace = true\niced_highlighter.optional = true\n"
  },
  {
    "path": "widget/src/action.rs",
    "content": "use crate::core::event;\nuse crate::core::time::Instant;\nuse crate::core::window;\n\n/// A runtime action that can be performed by some widgets.\n#[derive(Debug, Clone)]\npub struct Action<Message> {\n    message_to_publish: Option<Message>,\n    redraw_request: window::RedrawRequest,\n    event_status: event::Status,\n}\n\nimpl<Message> Action<Message> {\n    fn new() -> Self {\n        Self {\n            message_to_publish: None,\n            redraw_request: window::RedrawRequest::Wait,\n            event_status: event::Status::Ignored,\n        }\n    }\n\n    /// Creates a new \"capturing\" [`Action`]. A capturing [`Action`]\n    /// will make other widgets consider it final and prevent further\n    /// processing.\n    ///\n    /// Prevents \"event bubbling\".\n    pub fn capture() -> Self {\n        Self {\n            event_status: event::Status::Captured,\n            ..Self::new()\n        }\n    }\n\n    /// Creates a new [`Action`] that publishes the given `Message` for\n    /// the application to handle.\n    ///\n    /// Publishing a `Message` always produces a redraw.\n    pub fn publish(message: Message) -> Self {\n        Self {\n            message_to_publish: Some(message),\n            ..Self::new()\n        }\n    }\n\n    /// Creates a new [`Action`] that requests a redraw to happen as\n    /// soon as possible; without publishing any `Message`.\n    pub fn request_redraw() -> Self {\n        Self {\n            redraw_request: window::RedrawRequest::NextFrame,\n            ..Self::new()\n        }\n    }\n\n    /// Creates a new [`Action`] that requests a redraw to happen at\n    /// the given [`Instant`]; without publishing any `Message`.\n    ///\n    /// This can be useful to efficiently animate content, like a\n    /// blinking caret on a text input.\n    pub fn request_redraw_at(at: Instant) -> Self {\n        Self {\n            redraw_request: window::RedrawRequest::At(at),\n            ..Self::new()\n        }\n    }\n\n    /// Marks the [`Action`] as \"capturing\". See [`Self::capture`].\n    pub fn and_capture(mut self) -> Self {\n        self.event_status = event::Status::Captured;\n        self\n    }\n\n    /// Converts the [`Action`] into its internal parts.\n    ///\n    /// This method is meant to be used by runtimes, libraries, or internal\n    /// widget implementations.\n    pub fn into_inner(self) -> (Option<Message>, window::RedrawRequest, event::Status) {\n        (\n            self.message_to_publish,\n            self.redraw_request,\n            self.event_status,\n        )\n    }\n}\n"
  },
  {
    "path": "widget/src/button.rs",
    "content": "//! Buttons allow your users to perform actions by pressing them.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! use iced::widget::button;\n//!\n//! #[derive(Clone)]\n//! enum Message {\n//!     ButtonPressed,\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     button(\"Press me!\").on_press(Message::ButtonPressed).into()\n//! }\n//! ```\nuse crate::core::border::{self, Border};\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::theme::palette;\nuse crate::core::touch;\nuse crate::core::widget::Operation;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    Background, Color, Element, Event, Layout, Length, Padding, Rectangle, Shadow, Shell, Size,\n    Theme, Vector, Widget,\n};\n\n/// A generic widget that produces a message when pressed.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::button;\n///\n/// #[derive(Clone)]\n/// enum Message {\n///     ButtonPressed,\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     button(\"Press me!\").on_press(Message::ButtonPressed).into()\n/// }\n/// ```\n///\n/// If a [`Button::on_press`] handler is not set, the resulting [`Button`] will\n/// be disabled:\n///\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::button;\n///\n/// #[derive(Clone)]\n/// enum Message {\n///     ButtonPressed,\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     button(\"I am disabled!\").into()\n/// }\n/// ```\npub struct Button<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n    Theme: Catalog,\n{\n    content: Element<'a, Message, Theme, Renderer>,\n    on_press: Option<OnPress<'a, Message>>,\n    width: Length,\n    height: Length,\n    padding: Padding,\n    clip: bool,\n    class: Theme::Class<'a>,\n    status: Option<Status>,\n}\n\nenum OnPress<'a, Message> {\n    Direct(Message),\n    Closure(Box<dyn Fn() -> Message + 'a>),\n}\n\nimpl<Message: Clone> OnPress<'_, Message> {\n    fn get(&self) -> Message {\n        match self {\n            OnPress::Direct(message) => message.clone(),\n            OnPress::Closure(f) => f(),\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> Button<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n    Theme: Catalog,\n{\n    /// Creates a new [`Button`] with the given content.\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        let content = content.into();\n        let size = content.as_widget().size_hint();\n\n        Button {\n            content,\n            on_press: None,\n            width: size.width.fluid(),\n            height: size.height.fluid(),\n            padding: DEFAULT_PADDING,\n            clip: false,\n            class: Theme::default(),\n            status: None,\n        }\n    }\n\n    /// Sets the width of the [`Button`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Button`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`Button`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the message that will be produced when the [`Button`] is pressed.\n    ///\n    /// Unless `on_press` is called, the [`Button`] will be disabled.\n    pub fn on_press(mut self, on_press: Message) -> Self {\n        self.on_press = Some(OnPress::Direct(on_press));\n        self\n    }\n\n    /// Sets the message that will be produced when the [`Button`] is pressed.\n    ///\n    /// This is analogous to [`Button::on_press`], but using a closure to produce\n    /// the message.\n    ///\n    /// This closure will only be called when the [`Button`] is actually pressed and,\n    /// therefore, this method is useful to reduce overhead if creating the resulting\n    /// message is slow.\n    pub fn on_press_with(mut self, on_press: impl Fn() -> Message + 'a) -> Self {\n        self.on_press = Some(OnPress::Closure(Box::new(on_press)));\n        self\n    }\n\n    /// Sets the message that will be produced when the [`Button`] is pressed,\n    /// if `Some`.\n    ///\n    /// If `None`, the [`Button`] will be disabled.\n    pub fn on_press_maybe(mut self, on_press: Option<Message>) -> Self {\n        self.on_press = on_press.map(OnPress::Direct);\n        self\n    }\n\n    /// Sets whether the contents of the [`Button`] should be clipped on\n    /// overflow.\n    pub fn clip(mut self, clip: bool) -> Self {\n        self.clip = clip;\n        self\n    }\n\n    /// Sets the style of the [`Button`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Button`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\nstruct State {\n    is_pressed: bool,\n}\n\nimpl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Button<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a + Clone,\n    Renderer: 'a + crate::core::Renderer,\n    Theme: Catalog,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::default())\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        vec![Tree::new(&self.content)]\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        tree.diff_children(std::slice::from_ref(&self.content));\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::padded(limits, self.width, self.height, self.padding, |limits| {\n            self.content\n                .as_widget_mut()\n                .layout(&mut tree.children[0], renderer, limits)\n        })\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        operation.container(None, layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.content.as_widget_mut().operate(\n                &mut tree.children[0],\n                layout.children().next().unwrap(),\n                renderer,\n                operation,\n            );\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget_mut().update(\n            &mut tree.children[0],\n            event,\n            layout.children().next().unwrap(),\n            cursor,\n            renderer,\n            shell,\n            viewport,\n        );\n\n        if shell.is_event_captured() {\n            return;\n        }\n\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                if self.on_press.is_some() {\n                    let bounds = layout.bounds();\n\n                    if cursor.is_over(bounds) {\n                        let state = tree.state.downcast_mut::<State>();\n\n                        state.is_pressed = true;\n\n                        shell.capture_event();\n                    }\n                }\n            }\n            Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerLifted { .. }) => {\n                if let Some(on_press) = &self.on_press {\n                    let state = tree.state.downcast_mut::<State>();\n\n                    if state.is_pressed {\n                        state.is_pressed = false;\n\n                        let bounds = layout.bounds();\n\n                        if cursor.is_over(bounds) {\n                            shell.publish(on_press.get());\n                        }\n\n                        shell.capture_event();\n                    }\n                }\n            }\n            Event::Touch(touch::Event::FingerLost { .. }) => {\n                let state = tree.state.downcast_mut::<State>();\n\n                state.is_pressed = false;\n            }\n            _ => {}\n        }\n\n        let current_status = if self.on_press.is_none() {\n            Status::Disabled\n        } else if cursor.is_over(layout.bounds()) {\n            let state = tree.state.downcast_ref::<State>();\n\n            if state.is_pressed {\n                Status::Pressed\n            } else {\n                Status::Hovered\n            }\n        } else {\n            Status::Active\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.status = Some(current_status);\n        } else if self.status.is_some_and(|status| status != current_status) {\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n        let content_layout = layout.children().next().unwrap();\n        let style = theme.style(&self.class, self.status.unwrap_or(Status::Disabled));\n\n        if style.background.is_some() || style.border.width > 0.0 || style.shadow.color.a > 0.0 {\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds,\n                    border: style.border,\n                    shadow: style.shadow,\n                    snap: style.snap,\n                },\n                style\n                    .background\n                    .unwrap_or(Background::Color(Color::TRANSPARENT)),\n            );\n        }\n\n        let viewport = if self.clip {\n            bounds.intersection(viewport).unwrap_or(*viewport)\n        } else {\n            *viewport\n        };\n\n        self.content.as_widget().draw(\n            &tree.children[0],\n            renderer,\n            theme,\n            &renderer::Style {\n                text_color: style.text_color,\n            },\n            content_layout,\n            cursor,\n            &viewport,\n        );\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let is_mouse_over = cursor.is_over(layout.bounds());\n\n        if is_mouse_over && self.on_press.is_some() {\n            mouse::Interaction::Pointer\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.content.as_widget_mut().overlay(\n            &mut tree.children[0],\n            layout.children().next().unwrap(),\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Button<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone + 'a,\n    Theme: Catalog + 'a,\n    Renderer: crate::core::Renderer + 'a,\n{\n    fn from(button: Button<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(button)\n    }\n}\n\n/// The default [`Padding`] of a [`Button`].\npub const DEFAULT_PADDING: Padding = Padding {\n    top: 5.0,\n    bottom: 5.0,\n    right: 10.0,\n    left: 10.0,\n};\n\n/// The possible status of a [`Button`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`Button`] can be pressed.\n    Active,\n    /// The [`Button`] can be pressed and it is being hovered.\n    Hovered,\n    /// The [`Button`] is being pressed.\n    Pressed,\n    /// The [`Button`] cannot be pressed.\n    Disabled,\n}\n\n/// The style of a button.\n///\n/// If not specified with [`Button::style`]\n/// the theme will provide the style.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`Background`] of the button.\n    pub background: Option<Background>,\n    /// The text [`Color`] of the button.\n    pub text_color: Color,\n    /// The [`Border`] of the button.\n    pub border: Border,\n    /// The [`Shadow`] of the button.\n    pub shadow: Shadow,\n    /// Whether the button should be snapped to the pixel grid.\n    pub snap: bool,\n}\n\nimpl Style {\n    /// Updates the [`Style`] with the given [`Background`].\n    pub fn with_background(self, background: impl Into<Background>) -> Self {\n        Self {\n            background: Some(background.into()),\n            ..self\n        }\n    }\n}\n\nimpl Default for Style {\n    fn default() -> Self {\n        Self {\n            background: None,\n            text_color: Color::BLACK,\n            border: Border::default(),\n            shadow: Shadow::default(),\n            snap: renderer::CRISP,\n        }\n    }\n}\n\n/// The theme catalog of a [`Button`].\n///\n/// All themes that can be used with [`Button`]\n/// must implement this trait.\n///\n/// # Example\n/// ```no_run\n/// # use iced_widget::core::{Color, Background};\n/// # use iced_widget::button::{Catalog, Status, Style};\n/// # struct MyTheme;\n/// #[derive(Debug, Default)]\n/// pub enum ButtonClass {\n///     #[default]\n///     Primary,\n///     Secondary,\n///     Danger\n/// }\n///\n/// impl Catalog for MyTheme {\n///     type Class<'a> = ButtonClass;\n///     \n///     fn default<'a>() -> Self::Class<'a> {\n///         ButtonClass::default()\n///     }\n///     \n///\n///     fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n///         let mut style = Style::default();\n///\n///         match class {\n///             ButtonClass::Primary => {\n///                 style.background = Some(Background::Color(Color::from_rgb(0.529, 0.808, 0.921)));\n///             },\n///             ButtonClass::Secondary => {\n///                 style.background = Some(Background::Color(Color::WHITE));\n///             },\n///             ButtonClass::Danger => {\n///                 style.background = Some(Background::Color(Color::from_rgb(0.941, 0.502, 0.502)));\n///             },\n///         }\n///\n///         style\n///     }\n/// }\n/// ```\n///\n/// Although, in order to use [`Button::style`]\n/// with `MyTheme`, [`Catalog::Class`] must implement\n/// `From<StyleFn<'_, MyTheme>>`.\npub trait Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`Button`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(primary)\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// A primary button; denoting a main action.\npub fn primary(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n    let base = styled(palette.primary.base);\n\n    match status {\n        Status::Active | Status::Pressed => base,\n        Status::Hovered => Style {\n            background: Some(Background::Color(palette.primary.strong.color)),\n            ..base\n        },\n        Status::Disabled => disabled(base),\n    }\n}\n\n/// A secondary button; denoting a complementary action.\npub fn secondary(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n    let base = styled(palette.secondary.base);\n\n    match status {\n        Status::Active | Status::Pressed => base,\n        Status::Hovered => Style {\n            background: Some(Background::Color(palette.secondary.strong.color)),\n            ..base\n        },\n        Status::Disabled => disabled(base),\n    }\n}\n\n/// A success button; denoting a good outcome.\npub fn success(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n    let base = styled(palette.success.base);\n\n    match status {\n        Status::Active | Status::Pressed => base,\n        Status::Hovered => Style {\n            background: Some(Background::Color(palette.success.strong.color)),\n            ..base\n        },\n        Status::Disabled => disabled(base),\n    }\n}\n\n/// A warning button; denoting a risky action.\npub fn warning(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n    let base = styled(palette.warning.base);\n\n    match status {\n        Status::Active | Status::Pressed => base,\n        Status::Hovered => Style {\n            background: Some(Background::Color(palette.warning.strong.color)),\n            ..base\n        },\n        Status::Disabled => disabled(base),\n    }\n}\n\n/// A danger button; denoting a destructive action.\npub fn danger(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n    let base = styled(palette.danger.base);\n\n    match status {\n        Status::Active | Status::Pressed => base,\n        Status::Hovered => Style {\n            background: Some(Background::Color(palette.danger.strong.color)),\n            ..base\n        },\n        Status::Disabled => disabled(base),\n    }\n}\n\n/// A text button; useful for links.\npub fn text(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    let base = Style {\n        text_color: palette.background.base.text,\n        ..Style::default()\n    };\n\n    match status {\n        Status::Active | Status::Pressed => base,\n        Status::Hovered => Style {\n            text_color: palette.background.base.text.scale_alpha(0.8),\n            ..base\n        },\n        Status::Disabled => disabled(base),\n    }\n}\n\n/// A button using background shades.\npub fn background(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n    let base = styled(palette.background.base);\n\n    match status {\n        Status::Active => base,\n        Status::Pressed => Style {\n            background: Some(Background::Color(palette.background.strong.color)),\n            ..base\n        },\n        Status::Hovered => Style {\n            background: Some(Background::Color(palette.background.weak.color)),\n            ..base\n        },\n        Status::Disabled => disabled(base),\n    }\n}\n\n/// A subtle button using weak background shades.\npub fn subtle(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n    let base = styled(palette.background.weakest);\n\n    match status {\n        Status::Active => base,\n        Status::Pressed => Style {\n            background: Some(Background::Color(palette.background.strong.color)),\n            ..base\n        },\n        Status::Hovered => Style {\n            background: Some(Background::Color(palette.background.weaker.color)),\n            ..base\n        },\n        Status::Disabled => disabled(base),\n    }\n}\n\nfn styled(pair: palette::Pair) -> Style {\n    Style {\n        background: Some(Background::Color(pair.color)),\n        text_color: pair.text,\n        border: border::rounded(2),\n        ..Style::default()\n    }\n}\n\nfn disabled(style: Style) -> Style {\n    Style {\n        background: style\n            .background\n            .map(|background| background.scale_alpha(0.5)),\n        text_color: style.text_color.scale_alpha(0.5),\n        ..style\n    }\n}\n"
  },
  {
    "path": "widget/src/canvas/program.rs",
    "content": "use crate::Action;\nuse crate::canvas::mouse;\nuse crate::canvas::{Event, Geometry};\nuse crate::core::Rectangle;\nuse crate::graphics::geometry;\n\n/// The state and logic of a [`Canvas`].\n///\n/// A [`Program`] can mutate internal state and produce messages for an\n/// application.\n///\n/// [`Canvas`]: crate::Canvas\npub trait Program<Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Renderer: geometry::Renderer,\n{\n    /// The internal state mutated by the [`Program`].\n    type State: Default + 'static;\n\n    /// Updates the [`State`](Self::State) of the [`Program`].\n    ///\n    /// When a [`Program`] is used in a [`Canvas`], the runtime will call this\n    /// method for each [`Event`].\n    ///\n    /// This method can optionally return an [`Action`] to either notify an\n    /// application of any meaningful interactions, capture the event, or\n    /// request a redraw.\n    ///\n    /// By default, this method does and returns nothing.\n    ///\n    /// [`Canvas`]: crate::Canvas\n    fn update(\n        &self,\n        _state: &mut Self::State,\n        _event: &Event,\n        _bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Option<Action<Message>> {\n        None\n    }\n\n    /// Draws the state of the [`Program`], producing a bunch of [`Geometry`].\n    ///\n    /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a\n    /// [`Cache`].\n    ///\n    /// [`Geometry`]: crate::canvas::Geometry\n    /// [`Frame`]: crate::canvas::Frame\n    /// [`Cache`]: crate::canvas::Cache\n    fn draw(\n        &self,\n        state: &Self::State,\n        renderer: &Renderer,\n        theme: &Theme,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> Vec<Geometry<Renderer>>;\n\n    /// Returns the current mouse interaction of the [`Program`].\n    ///\n    /// The interaction returned will be in effect even if the cursor position\n    /// is out of bounds of the program's [`Canvas`].\n    ///\n    /// [`Canvas`]: crate::Canvas\n    fn mouse_interaction(\n        &self,\n        _state: &Self::State,\n        _bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> mouse::Interaction {\n        mouse::Interaction::default()\n    }\n}\n\nimpl<Message, Theme, Renderer, T> Program<Message, Theme, Renderer> for &T\nwhere\n    Renderer: geometry::Renderer,\n    T: Program<Message, Theme, Renderer>,\n{\n    type State = T::State;\n\n    fn update(\n        &self,\n        state: &mut Self::State,\n        event: &Event,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> Option<Action<Message>> {\n        T::update(self, state, event, bounds, cursor)\n    }\n\n    fn draw(\n        &self,\n        state: &Self::State,\n        renderer: &Renderer,\n        theme: &Theme,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> Vec<Geometry<Renderer>> {\n        T::draw(self, state, renderer, theme, bounds, cursor)\n    }\n\n    fn mouse_interaction(\n        &self,\n        state: &Self::State,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> mouse::Interaction {\n        T::mouse_interaction(self, state, bounds, cursor)\n    }\n}\n"
  },
  {
    "path": "widget/src/canvas.rs",
    "content": "//! Canvases can be leveraged to draw interactive 2D graphics.\n//!\n//! # Example: Drawing a Simple Circle\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::mouse;\n//! use iced::widget::canvas;\n//! use iced::{Color, Rectangle, Renderer, Theme};\n//!\n//! // First, we define the data we need for drawing\n//! #[derive(Debug)]\n//! struct Circle {\n//!     radius: f32,\n//! }\n//!\n//! // Then, we implement the `Program` trait\n//! impl<Message> canvas::Program<Message> for Circle {\n//!     // No internal state\n//!     type State = ();\n//!\n//!     fn draw(\n//!         &self,\n//!         _state: &(),\n//!         renderer: &Renderer,\n//!         _theme: &Theme,\n//!         bounds: Rectangle,\n//!         _cursor: mouse::Cursor\n//!     ) -> Vec<canvas::Geometry> {\n//!         // We prepare a new `Frame`\n//!         let mut frame = canvas::Frame::new(renderer, bounds.size());\n//!\n//!         // We create a `Path` representing a simple circle\n//!         let circle = canvas::Path::circle(frame.center(), self.radius);\n//!\n//!         // And fill it with some color\n//!         frame.fill(&circle, Color::BLACK);\n//!\n//!         // Then, we produce the geometry\n//!         vec![frame.into_geometry()]\n//!     }\n//! }\n//!\n//! // Finally, we simply use our `Circle` to create the `Canvas`!\n//! fn view<'a, Message: 'a>(_state: &'a State) -> Element<'a, Message> {\n//!     canvas(Circle { radius: 50.0 }).into()\n//! }\n//! ```\nmod program;\n\npub use program::Program;\n\npub use crate::Action;\npub use crate::core::event::Event;\npub use crate::graphics::cache::Group;\npub use crate::graphics::geometry::{\n    Fill, Gradient, Image, LineCap, LineDash, LineJoin, Path, Stroke, Style, Text, fill, gradient,\n    path, stroke,\n};\n\nuse crate::core::event;\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{Element, Length, Rectangle, Shell, Size, Vector, Widget};\nuse crate::graphics::geometry;\n\nuse std::marker::PhantomData;\n\n/// A simple cache that stores generated [`Geometry`] to avoid recomputation.\n///\n/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer\n/// change or it is explicitly cleared.\npub type Cache<Renderer = crate::Renderer> = geometry::Cache<Renderer>;\n\n/// The geometry supported by a renderer.\npub type Geometry<Renderer = crate::Renderer> = <Renderer as geometry::Renderer>::Geometry;\n\n/// The frame supported by a renderer.\npub type Frame<Renderer = crate::Renderer> = geometry::Frame<Renderer>;\n\n/// A widget capable of drawing 2D graphics.\n///\n/// # Example: Drawing a Simple Circle\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::mouse;\n/// use iced::widget::canvas;\n/// use iced::{Color, Rectangle, Renderer, Theme};\n///\n/// // First, we define the data we need for drawing\n/// #[derive(Debug)]\n/// struct Circle {\n///     radius: f32,\n/// }\n///\n/// // Then, we implement the `Program` trait\n/// impl<Message> canvas::Program<Message> for Circle {\n///     // No internal state\n///     type State = ();\n///\n///     fn draw(\n///         &self,\n///         _state: &(),\n///         renderer: &Renderer,\n///         _theme: &Theme,\n///         bounds: Rectangle,\n///         _cursor: mouse::Cursor\n///     ) -> Vec<canvas::Geometry> {\n///         // We prepare a new `Frame`\n///         let mut frame = canvas::Frame::new(renderer, bounds.size());\n///\n///         // We create a `Path` representing a simple circle\n///         let circle = canvas::Path::circle(frame.center(), self.radius);\n///\n///         // And fill it with some color\n///         frame.fill(&circle, Color::BLACK);\n///\n///         // Then, we produce the geometry\n///         vec![frame.into_geometry()]\n///     }\n/// }\n///\n/// // Finally, we simply use our `Circle` to create the `Canvas`!\n/// fn view<'a, Message: 'a>(_state: &'a State) -> Element<'a, Message> {\n///     canvas(Circle { radius: 50.0 }).into()\n/// }\n/// ```\n#[derive(Debug)]\npub struct Canvas<P, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Renderer: geometry::Renderer,\n    P: Program<Message, Theme, Renderer>,\n{\n    width: Length,\n    height: Length,\n    program: P,\n    message_: PhantomData<Message>,\n    theme_: PhantomData<Theme>,\n    renderer_: PhantomData<Renderer>,\n    last_mouse_interaction: Option<mouse::Interaction>,\n}\n\nimpl<P, Message, Theme, Renderer> Canvas<P, Message, Theme, Renderer>\nwhere\n    P: Program<Message, Theme, Renderer>,\n    Renderer: geometry::Renderer,\n{\n    const DEFAULT_SIZE: f32 = 100.0;\n\n    /// Creates a new [`Canvas`].\n    pub fn new(program: P) -> Self {\n        Canvas {\n            width: Length::Fixed(Self::DEFAULT_SIZE),\n            height: Length::Fixed(Self::DEFAULT_SIZE),\n            program,\n            message_: PhantomData,\n            theme_: PhantomData,\n            renderer_: PhantomData,\n            last_mouse_interaction: None,\n        }\n    }\n\n    /// Sets the width of the [`Canvas`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Canvas`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n}\n\nimpl<P, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Canvas<P, Message, Theme, Renderer>\nwhere\n    Renderer: geometry::Renderer,\n    P: Program<Message, Theme, Renderer>,\n{\n    fn tag(&self) -> tree::Tag {\n        struct Tag<T>(T);\n        tree::Tag::of::<Tag<P::State>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(P::State::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::atomic(limits, self.width, self.height)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        let state = tree.state.downcast_mut::<P::State>();\n        let is_redraw_request =\n            matches!(event, Event::Window(window::Event::RedrawRequested(_now)),);\n\n        if let Some(action) = self.program.update(state, event, bounds, cursor) {\n            let (message, redraw_request, event_status) = action.into_inner();\n\n            shell.request_redraw_at(redraw_request);\n\n            if let Some(message) = message {\n                shell.publish(message);\n            }\n\n            if event_status == event::Status::Captured {\n                shell.capture_event();\n            }\n        }\n\n        if shell.redraw_request() != window::RedrawRequest::NextFrame {\n            let mouse_interaction =\n                self.mouse_interaction(tree, layout, cursor, viewport, renderer);\n\n            if is_redraw_request {\n                self.last_mouse_interaction = Some(mouse_interaction);\n            } else if self\n                .last_mouse_interaction\n                .is_some_and(|last_mouse_interaction| last_mouse_interaction != mouse_interaction)\n            {\n                shell.request_redraw();\n            }\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let bounds = layout.bounds();\n        let state = tree.state.downcast_ref::<P::State>();\n\n        self.program.mouse_interaction(state, bounds, cursor)\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        if bounds.width < 1.0 || bounds.height < 1.0 {\n            return;\n        }\n\n        let state = tree.state.downcast_ref::<P::State>();\n\n        renderer.with_translation(Vector::new(bounds.x, bounds.y), |renderer| {\n            let layers = self.program.draw(state, renderer, theme, bounds, cursor);\n\n            for layer in layers {\n                renderer.draw_geometry(layer);\n            }\n        });\n    }\n}\n\nimpl<'a, P, Message, Theme, Renderer> From<Canvas<P, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: 'a + geometry::Renderer,\n    P: 'a + Program<Message, Theme, Renderer>,\n{\n    fn from(canvas: Canvas<P, Message, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(canvas)\n    }\n}\n"
  },
  {
    "path": "widget/src/checkbox.rs",
    "content": "//! Checkboxes can be used to let users make binary choices.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::checkbox;\n//!\n//! struct State {\n//!    is_checked: bool,\n//! }\n//!\n//! enum Message {\n//!     CheckboxToggled(bool),\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     checkbox(state.is_checked)\n//!         .label(\"Toggle me!\")\n//!         .on_toggle(Message::CheckboxToggled)\n//!         .into()\n//! }\n//!\n//! fn update(state: &mut State, message: Message) {\n//!     match message {\n//!         Message::CheckboxToggled(is_checked) => {\n//!             state.is_checked = is_checked;\n//!         }\n//!     }\n//! }\n//! ```\n//! ![Checkbox drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true)\nuse crate::core::alignment;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::text;\nuse crate::core::theme::palette;\nuse crate::core::touch;\nuse crate::core::widget;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    Background, Border, Color, Element, Event, Layout, Length, Pixels, Rectangle, Shell, Size,\n    Theme, Widget,\n};\n\n/// A box that can be checked.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::checkbox;\n///\n/// struct State {\n///    is_checked: bool,\n/// }\n///\n/// enum Message {\n///     CheckboxToggled(bool),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     checkbox(state.is_checked)\n///         .label(\"Toggle me!\")\n///         .on_toggle(Message::CheckboxToggled)\n///         .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::CheckboxToggled(is_checked) => {\n///             state.is_checked = is_checked;\n///         }\n///     }\n/// }\n/// ```\n/// ![Checkbox drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true)\npub struct Checkbox<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Renderer: text::Renderer,\n    Theme: Catalog,\n{\n    is_checked: bool,\n    on_toggle: Option<Box<dyn Fn(bool) -> Message + 'a>>,\n    label: Option<text::Fragment<'a>>,\n    width: Length,\n    size: f32,\n    spacing: f32,\n    text_size: Option<Pixels>,\n    line_height: text::LineHeight,\n    shaping: text::Shaping,\n    wrapping: text::Wrapping,\n    font: Option<Renderer::Font>,\n    icon: Icon<Renderer::Font>,\n    class: Theme::Class<'a>,\n    last_status: Option<Status>,\n}\n\nimpl<'a, Message, Theme, Renderer> Checkbox<'a, Message, Theme, Renderer>\nwhere\n    Renderer: text::Renderer,\n    Theme: Catalog,\n{\n    /// The default size of a [`Checkbox`].\n    const DEFAULT_SIZE: f32 = 16.0;\n\n    /// Creates a new [`Checkbox`].\n    ///\n    /// It expects:\n    ///   * a boolean describing whether the [`Checkbox`] is checked or not\n    pub fn new(is_checked: bool) -> Self {\n        Checkbox {\n            is_checked,\n            on_toggle: None,\n            label: None,\n            width: Length::Shrink,\n            size: Self::DEFAULT_SIZE,\n            spacing: Self::DEFAULT_SIZE / 2.0,\n            text_size: None,\n            line_height: text::LineHeight::default(),\n            shaping: text::Shaping::default(),\n            wrapping: text::Wrapping::default(),\n            font: None,\n            icon: Icon {\n                font: Renderer::ICON_FONT,\n                code_point: Renderer::CHECKMARK_ICON,\n                size: None,\n                line_height: text::LineHeight::default(),\n                shaping: text::Shaping::Basic,\n            },\n            class: Theme::default(),\n            last_status: None,\n        }\n    }\n\n    /// Sets the label of the [`Checkbox`].\n    pub fn label(mut self, label: impl text::IntoFragment<'a>) -> Self {\n        self.label = Some(label.into_fragment());\n        self\n    }\n\n    /// Sets the function that will be called when the [`Checkbox`] is toggled.\n    /// It will receive the new state of the [`Checkbox`] and must produce a\n    /// `Message`.\n    ///\n    /// Unless `on_toggle` is called, the [`Checkbox`] will be disabled.\n    pub fn on_toggle<F>(mut self, f: F) -> Self\n    where\n        F: 'a + Fn(bool) -> Message,\n    {\n        self.on_toggle = Some(Box::new(f));\n        self\n    }\n\n    /// Sets the function that will be called when the [`Checkbox`] is toggled,\n    /// if `Some`.\n    ///\n    /// If `None`, the checkbox will be disabled.\n    pub fn on_toggle_maybe<F>(mut self, f: Option<F>) -> Self\n    where\n        F: Fn(bool) -> Message + 'a,\n    {\n        self.on_toggle = f.map(|f| Box::new(f) as _);\n        self\n    }\n\n    /// Sets the size of the [`Checkbox`].\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        self.size = size.into().0;\n        self\n    }\n\n    /// Sets the width of the [`Checkbox`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the spacing between the [`Checkbox`] and the text.\n    pub fn spacing(mut self, spacing: impl Into<Pixels>) -> Self {\n        self.spacing = spacing.into().0;\n        self\n    }\n\n    /// Sets the text size of the [`Checkbox`].\n    pub fn text_size(mut self, text_size: impl Into<Pixels>) -> Self {\n        self.text_size = Some(text_size.into());\n        self\n    }\n\n    /// Sets the text [`text::LineHeight`] of the [`Checkbox`].\n    pub fn line_height(mut self, line_height: impl Into<text::LineHeight>) -> Self {\n        self.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the [`text::Shaping`] strategy of the [`Checkbox`].\n    pub fn shaping(mut self, shaping: text::Shaping) -> Self {\n        self.shaping = shaping;\n        self\n    }\n\n    /// Sets the [`text::Wrapping`] strategy of the [`Checkbox`].\n    pub fn wrapping(mut self, wrapping: text::Wrapping) -> Self {\n        self.wrapping = wrapping;\n        self\n    }\n\n    /// Sets the [`Renderer::Font`] of the text of the [`Checkbox`].\n    ///\n    /// [`Renderer::Font`]: crate::core::text::Renderer\n    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {\n        self.font = Some(font.into());\n        self\n    }\n\n    /// Sets the [`Icon`] of the [`Checkbox`].\n    pub fn icon(mut self, icon: Icon<Renderer::Font>) -> Self {\n        self.icon = icon;\n        self\n    }\n\n    /// Sets the style of the [`Checkbox`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Checkbox`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Checkbox<'_, Message, Theme, Renderer>\nwhere\n    Renderer: text::Renderer,\n    Theme: Catalog,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<widget::text::State<Renderer::Paragraph>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(widget::text::State::<Renderer::Paragraph>::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::next_to_each_other(\n            &limits.width(self.width),\n            if self.label.is_some() {\n                self.spacing\n            } else {\n                0.0\n            },\n            |_| layout::Node::new(Size::new(self.size, self.size)),\n            |limits| {\n                if let Some(label) = self.label.as_deref() {\n                    let state = tree\n                        .state\n                        .downcast_mut::<widget::text::State<Renderer::Paragraph>>();\n\n                    widget::text::layout(\n                        state,\n                        renderer,\n                        limits,\n                        label,\n                        widget::text::Format {\n                            width: self.width,\n                            height: Length::Shrink,\n                            line_height: self.line_height,\n                            size: self.text_size,\n                            font: self.font,\n                            align_x: text::Alignment::Default,\n                            align_y: alignment::Vertical::Top,\n                            shaping: self.shaping,\n                            wrapping: self.wrapping,\n                            ellipsis: text::Ellipsis::None,\n                        },\n                    )\n                } else {\n                    layout::Node::new(Size::ZERO)\n                }\n            },\n        )\n    }\n\n    fn update(\n        &mut self,\n        _tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                let mouse_over = cursor.is_over(layout.bounds());\n\n                if mouse_over && let Some(on_toggle) = &self.on_toggle {\n                    shell.publish((on_toggle)(!self.is_checked));\n                    shell.capture_event();\n                }\n            }\n            _ => {}\n        }\n\n        let current_status = {\n            let is_mouse_over = cursor.is_over(layout.bounds());\n            let is_disabled = self.on_toggle.is_none();\n            let is_checked = self.is_checked;\n\n            if is_disabled {\n                Status::Disabled { is_checked }\n            } else if is_mouse_over {\n                Status::Hovered { is_checked }\n            } else {\n                Status::Active { is_checked }\n            }\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.last_status = Some(current_status);\n        } else if self\n            .last_status\n            .is_some_and(|status| status != current_status)\n        {\n            shell.request_redraw();\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        if cursor.is_over(layout.bounds()) && self.on_toggle.is_some() {\n            mouse::Interaction::Pointer\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        defaults: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let mut children = layout.children();\n\n        let style = theme.style(\n            &self.class,\n            self.last_status.unwrap_or(Status::Disabled {\n                is_checked: self.is_checked,\n            }),\n        );\n\n        {\n            let layout = children.next().unwrap();\n            let bounds = layout.bounds();\n\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds,\n                    border: style.border,\n                    ..renderer::Quad::default()\n                },\n                style.background,\n            );\n\n            let Icon {\n                font,\n                code_point,\n                size,\n                line_height,\n                shaping,\n            } = &self.icon;\n            let size = size.unwrap_or(Pixels(bounds.height * 0.7));\n\n            if self.is_checked {\n                renderer.fill_text(\n                    text::Text {\n                        content: code_point.to_string(),\n                        font: *font,\n                        size,\n                        line_height: *line_height,\n                        bounds: bounds.size(),\n                        align_x: text::Alignment::Center,\n                        align_y: alignment::Vertical::Center,\n                        shaping: *shaping,\n                        wrapping: text::Wrapping::default(),\n                        ellipsis: text::Ellipsis::default(),\n                        hint_factor: None,\n                    },\n                    bounds.center(),\n                    style.icon_color,\n                    *viewport,\n                );\n            }\n        }\n\n        if self.label.is_none() {\n            return;\n        }\n\n        {\n            let label_layout = children.next().unwrap();\n            let state: &widget::text::State<Renderer::Paragraph> = tree.state.downcast_ref();\n\n            crate::text::draw(\n                renderer,\n                defaults,\n                label_layout.bounds(),\n                state.raw(),\n                crate::text::Style {\n                    color: style.text_color,\n                },\n                viewport,\n            );\n        }\n    }\n\n    fn operate(\n        &mut self,\n        _tree: &mut Tree,\n        layout: Layout<'_>,\n        _renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        if let Some(label) = self.label.as_deref() {\n            operation.text(None, layout.bounds(), label);\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Checkbox<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a + Catalog,\n    Renderer: 'a + text::Renderer,\n{\n    fn from(\n        checkbox: Checkbox<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(checkbox)\n    }\n}\n\n/// The icon in a [`Checkbox`].\n#[derive(Debug, Clone, PartialEq)]\npub struct Icon<Font> {\n    /// Font that will be used to display the `code_point`,\n    pub font: Font,\n    /// The unicode code point that will be used as the icon.\n    pub code_point: char,\n    /// Font size of the content.\n    pub size: Option<Pixels>,\n    /// The line height of the icon.\n    pub line_height: text::LineHeight,\n    /// The shaping strategy of the icon.\n    pub shaping: text::Shaping,\n}\n\n/// The possible status of a [`Checkbox`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`Checkbox`] can be interacted with.\n    Active {\n        /// Indicates if the [`Checkbox`] is currently checked.\n        is_checked: bool,\n    },\n    /// The [`Checkbox`] can be interacted with and it is being hovered.\n    Hovered {\n        /// Indicates if the [`Checkbox`] is currently checked.\n        is_checked: bool,\n    },\n    /// The [`Checkbox`] cannot be interacted with.\n    Disabled {\n        /// Indicates if the [`Checkbox`] is currently checked.\n        is_checked: bool,\n    },\n}\n\n/// The style of a checkbox.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`Background`] of the checkbox.\n    pub background: Background,\n    /// The icon [`Color`] of the checkbox.\n    pub icon_color: Color,\n    /// The [`Border`] of the checkbox.\n    pub border: Border,\n    /// The text [`Color`] of the checkbox.\n    pub text_color: Option<Color>,\n}\n\n/// The theme catalog of a [`Checkbox`].\npub trait Catalog: Sized {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`Checkbox`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(primary)\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// A primary checkbox; denoting a main toggle.\npub fn primary(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    match status {\n        Status::Active { is_checked } => styled(\n            palette.background.strong.color,\n            palette.background.base,\n            palette.primary.base.text,\n            palette.primary.base,\n            is_checked,\n        ),\n        Status::Hovered { is_checked } => styled(\n            palette.background.strong.color,\n            palette.background.weak,\n            palette.primary.base.text,\n            palette.primary.strong,\n            is_checked,\n        ),\n        Status::Disabled { is_checked } => styled(\n            palette.background.weak.color,\n            palette.background.weaker,\n            palette.primary.base.text,\n            palette.background.strong,\n            is_checked,\n        ),\n    }\n}\n\n/// A secondary checkbox; denoting a complementary toggle.\npub fn secondary(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    match status {\n        Status::Active { is_checked } => styled(\n            palette.background.strong.color,\n            palette.background.base,\n            palette.background.base.text,\n            palette.background.strong,\n            is_checked,\n        ),\n        Status::Hovered { is_checked } => styled(\n            palette.background.strong.color,\n            palette.background.weak,\n            palette.background.base.text,\n            palette.background.strong,\n            is_checked,\n        ),\n        Status::Disabled { is_checked } => styled(\n            palette.background.weak.color,\n            palette.background.weak,\n            palette.background.base.text,\n            palette.background.weak,\n            is_checked,\n        ),\n    }\n}\n\n/// A success checkbox; denoting a positive toggle.\npub fn success(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    match status {\n        Status::Active { is_checked } => styled(\n            palette.background.weak.color,\n            palette.background.base,\n            palette.success.base.text,\n            palette.success.base,\n            is_checked,\n        ),\n        Status::Hovered { is_checked } => styled(\n            palette.background.strong.color,\n            palette.background.weak,\n            palette.success.base.text,\n            palette.success.strong,\n            is_checked,\n        ),\n        Status::Disabled { is_checked } => styled(\n            palette.background.weak.color,\n            palette.background.weak,\n            palette.success.base.text,\n            palette.success.weak,\n            is_checked,\n        ),\n    }\n}\n\n/// A danger checkbox; denoting a negative toggle.\npub fn danger(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    match status {\n        Status::Active { is_checked } => styled(\n            palette.background.strong.color,\n            palette.background.base,\n            palette.danger.base.text,\n            palette.danger.base,\n            is_checked,\n        ),\n        Status::Hovered { is_checked } => styled(\n            palette.background.strong.color,\n            palette.background.weak,\n            palette.danger.base.text,\n            palette.danger.strong,\n            is_checked,\n        ),\n        Status::Disabled { is_checked } => styled(\n            palette.background.weak.color,\n            palette.background.weak,\n            palette.danger.base.text,\n            palette.danger.weak,\n            is_checked,\n        ),\n    }\n}\n\nfn styled(\n    border_color: Color,\n    base: palette::Pair,\n    icon_color: Color,\n    accent: palette::Pair,\n    is_checked: bool,\n) -> Style {\n    let (background, border) = if is_checked {\n        (accent, accent.color)\n    } else {\n        (base, border_color)\n    };\n\n    Style {\n        background: Background::Color(background.color),\n        icon_color,\n        border: Border {\n            radius: 2.0.into(),\n            width: 1.0,\n            color: border,\n        },\n        text_color: None,\n    }\n}\n"
  },
  {
    "path": "widget/src/column.rs",
    "content": "//! Distribute content vertically.\nuse crate::core::alignment::{self, Alignment};\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget::{Operation, Tree};\nuse crate::core::{\n    Element, Event, Layout, Length, Padding, Pixels, Rectangle, Shell, Size, Vector, Widget,\n};\n\n/// A container that distributes its contents vertically.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{button, column};\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     column![\n///         \"I am on top!\",\n///         button(\"I am in the center!\"),\n///         \"I am below.\",\n///     ].into()\n/// }\n/// ```\npub struct Column<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    spacing: f32,\n    padding: Padding,\n    width: Length,\n    height: Length,\n    max_width: f32,\n    align: Alignment,\n    clip: bool,\n    children: Vec<Element<'a, Message, Theme, Renderer>>,\n}\n\nimpl<'a, Message, Theme, Renderer> Column<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    /// Creates an empty [`Column`].\n    pub fn new() -> Self {\n        Self::from_vec(Vec::new())\n    }\n\n    /// Creates a [`Column`] with the given capacity.\n    pub fn with_capacity(capacity: usize) -> Self {\n        Self::from_vec(Vec::with_capacity(capacity))\n    }\n\n    /// Creates a [`Column`] with the given elements.\n    pub fn with_children(\n        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        let iterator = children.into_iter();\n\n        Self::with_capacity(iterator.size_hint().0).extend(iterator)\n    }\n\n    /// Creates a [`Column`] from an already allocated [`Vec`].\n    ///\n    /// Keep in mind that the [`Column`] will not inspect the [`Vec`], which means\n    /// it won't automatically adapt to the sizing strategy of its contents.\n    ///\n    /// If any of the children have a [`Length::Fill`] strategy, you will need to\n    /// call [`Column::width`] or [`Column::height`] accordingly.\n    pub fn from_vec(children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            spacing: 0.0,\n            padding: Padding::ZERO,\n            width: Length::Shrink,\n            height: Length::Shrink,\n            max_width: f32::INFINITY,\n            align: Alignment::Start,\n            clip: false,\n            children,\n        }\n    }\n\n    /// Sets the vertical spacing _between_ elements.\n    ///\n    /// Custom margins per element do not exist in iced. You should use this\n    /// method instead! While less flexible, it helps you keep spacing between\n    /// elements consistent.\n    pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {\n        self.spacing = amount.into().0;\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`Column`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the width of the [`Column`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Column`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the maximum width of the [`Column`].\n    pub fn max_width(mut self, max_width: impl Into<Pixels>) -> Self {\n        self.max_width = max_width.into().0;\n        self\n    }\n\n    /// Sets the horizontal alignment of the contents of the [`Column`] .\n    pub fn align_x(mut self, align: impl Into<alignment::Horizontal>) -> Self {\n        self.align = Alignment::from(align.into());\n        self\n    }\n\n    /// Sets whether the contents of the [`Column`] should be clipped on\n    /// overflow.\n    pub fn clip(mut self, clip: bool) -> Self {\n        self.clip = clip;\n        self\n    }\n\n    /// Adds an element to the [`Column`].\n    pub fn push(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        let child = child.into();\n        let child_size = child.as_widget().size_hint();\n\n        if !child_size.is_void() {\n            self.width = self.width.enclose(child_size.width);\n            self.height = self.height.enclose(child_size.height);\n            self.children.push(child);\n        }\n\n        self\n    }\n\n    /// Extends the [`Column`] with the given children.\n    pub fn extend(\n        self,\n        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        children.into_iter().fold(self, Self::push)\n    }\n\n    /// Turns the [`Column`] into a [`Wrapping`] column.\n    ///\n    /// The original alignment of the [`Column`] is preserved per column wrapped.\n    pub fn wrap(self) -> Wrapping<'a, Message, Theme, Renderer> {\n        Wrapping {\n            column: self,\n            horizontal_spacing: None,\n            align_y: alignment::Vertical::Top,\n        }\n    }\n}\n\nimpl<Message, Renderer> Default for Column<'_, Message, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<'a, Message, Theme, Renderer: crate::core::Renderer>\n    FromIterator<Element<'a, Message, Theme, Renderer>> for Column<'a, Message, Theme, Renderer>\n{\n    fn from_iter<T: IntoIterator<Item = Element<'a, Message, Theme, Renderer>>>(iter: T) -> Self {\n        Self::with_children(iter)\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Column<'_, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn children(&self) -> Vec<Tree> {\n        self.children.iter().map(Tree::new).collect()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        tree.diff_children(&self.children);\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits.max_width(self.max_width);\n\n        layout::flex::resolve(\n            layout::flex::Axis::Vertical,\n            renderer,\n            &limits,\n            self.width,\n            self.height,\n            self.padding,\n            self.spacing,\n            self.align,\n            &mut self.children,\n            &mut tree.children,\n        )\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        operation.container(None, layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.children\n                .iter_mut()\n                .zip(&mut tree.children)\n                .zip(layout.children())\n                .for_each(|((child, state), layout)| {\n                    child\n                        .as_widget_mut()\n                        .operate(state, layout, renderer, operation);\n                });\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        for ((child, tree), layout) in self\n            .children\n            .iter_mut()\n            .zip(&mut tree.children)\n            .zip(layout.children())\n        {\n            child\n                .as_widget_mut()\n                .update(tree, event, layout, cursor, renderer, shell, viewport);\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.children\n            .iter()\n            .zip(&tree.children)\n            .zip(layout.children())\n            .map(|((child, tree), layout)| {\n                child\n                    .as_widget()\n                    .mouse_interaction(tree, layout, cursor, viewport, renderer)\n            })\n            .max()\n            .unwrap_or_default()\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {\n            let viewport = if self.clip {\n                &clipped_viewport\n            } else {\n                viewport\n            };\n\n            for ((child, tree), layout) in self\n                .children\n                .iter()\n                .zip(&tree.children)\n                .zip(layout.children())\n                .filter(|(_, layout)| layout.bounds().intersects(viewport))\n            {\n                child\n                    .as_widget()\n                    .draw(tree, renderer, theme, style, layout, cursor, viewport);\n            }\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        overlay::from_children(\n            &mut self.children,\n            tree,\n            layout,\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Column<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: crate::core::Renderer + 'a,\n{\n    fn from(column: Column<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(column)\n    }\n}\n\n/// A [`Column`] that wraps its contents.\n///\n/// Create a [`Column`] first, and then call [`Column::wrap`] to\n/// obtain a [`Column`] that wraps its contents.\n///\n/// The original alignment of the [`Column`] is preserved per column wrapped.\n#[allow(missing_debug_implementations)]\npub struct Wrapping<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    column: Column<'a, Message, Theme, Renderer>,\n    horizontal_spacing: Option<f32>,\n    align_y: alignment::Vertical,\n}\n\nimpl<Message, Theme, Renderer> Wrapping<'_, Message, Theme, Renderer> {\n    /// Sets the horizontal spacing _between_ columns.\n    pub fn horizontal_spacing(mut self, amount: impl Into<Pixels>) -> Self {\n        self.horizontal_spacing = Some(amount.into().0);\n        self\n    }\n\n    /// Sets the vertical alignment of the wrapping [`Column`].\n    pub fn align_x(mut self, align_y: impl Into<alignment::Vertical>) -> Self {\n        self.align_y = align_y.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Wrapping<'_, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn children(&self) -> Vec<Tree> {\n        self.column.children()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        self.column.diff(tree);\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.column.size()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits\n            .width(self.column.width)\n            .height(self.column.height)\n            .shrink(self.column.padding);\n\n        let child_limits = limits.loose();\n        let spacing = self.column.spacing;\n        let horizontal_spacing = self.horizontal_spacing.unwrap_or(spacing);\n        let max_height = limits.max().height;\n\n        let mut children: Vec<layout::Node> = Vec::new();\n        let mut intrinsic_size = Size::ZERO;\n        let mut column_start = 0;\n        let mut column_width = 0.0;\n        let mut x = 0.0;\n        let mut y = 0.0;\n\n        let align_factor = match self.column.align {\n            Alignment::Start => 0.0,\n            Alignment::Center => 2.0,\n            Alignment::End => 1.0,\n        };\n\n        let align_x = |column_start: std::ops::Range<usize>,\n                       column_width: f32,\n                       children: &mut Vec<layout::Node>| {\n            if align_factor != 0.0 {\n                for node in &mut children[column_start] {\n                    let width = node.size().width;\n\n                    node.translate_mut(Vector::new((column_width - width) / align_factor, 0.0));\n                }\n            }\n        };\n\n        for (i, child) in self.column.children.iter_mut().enumerate() {\n            let node = child\n                .as_widget_mut()\n                .layout(&mut tree.children[i], renderer, &child_limits);\n\n            let child_size = node.size();\n\n            if y != 0.0 && y + child_size.height > max_height {\n                intrinsic_size.height = intrinsic_size.height.max(y - spacing);\n\n                align_x(column_start..i, column_width, &mut children);\n\n                x += column_width + horizontal_spacing;\n                y = 0.0;\n                column_start = i;\n                column_width = 0.0;\n            }\n\n            column_width = column_width.max(child_size.width);\n\n            children\n                .push(node.move_to((x + self.column.padding.left, y + self.column.padding.top)));\n\n            y += child_size.height + spacing;\n        }\n\n        if y != 0.0 {\n            intrinsic_size.height = intrinsic_size.height.max(y - spacing);\n        }\n\n        intrinsic_size.width = x + column_width;\n        align_x(column_start..children.len(), column_width, &mut children);\n\n        let align_factor = match self.align_y {\n            alignment::Vertical::Top => 0.0,\n            alignment::Vertical::Center => 2.0,\n            alignment::Vertical::Bottom => 1.0,\n        };\n\n        if align_factor != 0.0 {\n            let total_height = intrinsic_size.height;\n\n            let mut column_start = 0;\n\n            for i in 0..children.len() {\n                let bounds = children[i].bounds();\n                let column_height = bounds.y + bounds.height;\n\n                let next_y = children\n                    .get(i + 1)\n                    .map(|node| node.bounds().y)\n                    .unwrap_or_default();\n\n                if next_y == 0.0 {\n                    let translation =\n                        Vector::new(0.0, (total_height - column_height) / align_factor);\n\n                    for node in &mut children[column_start..=i] {\n                        node.translate_mut(translation);\n                    }\n\n                    column_start = i + 1;\n                }\n            }\n        }\n\n        let size = limits.resolve(self.column.width, self.column.height, intrinsic_size);\n\n        layout::Node::with_children(size.expand(self.column.padding), children)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        self.column.operate(tree, layout, renderer, operation);\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.column\n            .update(tree, event, layout, cursor, renderer, shell, viewport);\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.column\n            .mouse_interaction(tree, layout, cursor, viewport, renderer)\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.column\n            .draw(tree, renderer, theme, style, layout, cursor, viewport);\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.column\n            .overlay(tree, layout, renderer, viewport, translation)\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Wrapping<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: crate::core::Renderer + 'a,\n{\n    fn from(column: Wrapping<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(column)\n    }\n}\n"
  },
  {
    "path": "widget/src/combo_box.rs",
    "content": "//! Combo boxes display a dropdown list of searchable and selectable options.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::combo_box;\n//!\n//! struct State {\n//!    fruits: combo_box::State<Fruit>,\n//!    favorite: Option<Fruit>,\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Fruit {\n//!     Apple,\n//!     Orange,\n//!     Strawberry,\n//!     Tomato,\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     FruitSelected(Fruit),\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     combo_box(\n//!         &state.fruits,\n//!         \"Select your favorite fruit...\",\n//!         state.favorite.as_ref(),\n//!         Message::FruitSelected\n//!     )\n//!     .into()\n//! }\n//!\n//! fn update(state: &mut State, message: Message) {\n//!     match message {\n//!         Message::FruitSelected(fruit) => {\n//!             state.favorite = Some(fruit);\n//!         }\n//!     }\n//! }\n//!\n//! impl std::fmt::Display for Fruit {\n//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n//!         f.write_str(match self {\n//!             Self::Apple => \"Apple\",\n//!             Self::Orange => \"Orange\",\n//!             Self::Strawberry => \"Strawberry\",\n//!             Self::Tomato => \"Tomato\",\n//!         })\n//!     }\n//! }\n//! ```\nuse crate::core::keyboard;\nuse crate::core::keyboard::key;\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::text;\nuse crate::core::time::Instant;\nuse crate::core::widget::{self, Widget};\nuse crate::core::{Element, Event, Length, Padding, Pixels, Rectangle, Shell, Size, Theme, Vector};\nuse crate::overlay::menu;\nuse crate::text::LineHeight;\nuse crate::text_input::{self, TextInput};\n\nuse std::cell::RefCell;\nuse std::fmt::Display;\n\n/// A widget for searching and selecting a single value from a list of options.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::combo_box;\n///\n/// struct State {\n///    fruits: combo_box::State<Fruit>,\n///    favorite: Option<Fruit>,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Fruit {\n///     Apple,\n///     Orange,\n///     Strawberry,\n///     Tomato,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     FruitSelected(Fruit),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     combo_box(\n///         &state.fruits,\n///         \"Select your favorite fruit...\",\n///         state.favorite.as_ref(),\n///         Message::FruitSelected\n///     )\n///     .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::FruitSelected(fruit) => {\n///             state.favorite = Some(fruit);\n///         }\n///     }\n/// }\n///\n/// impl std::fmt::Display for Fruit {\n///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n///         f.write_str(match self {\n///             Self::Apple => \"Apple\",\n///             Self::Orange => \"Orange\",\n///             Self::Strawberry => \"Strawberry\",\n///             Self::Tomato => \"Tomato\",\n///         })\n///     }\n/// }\n/// ```\npub struct ComboBox<'a, T, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    state: &'a State<T>,\n    text_input: TextInput<'a, TextInputEvent, Theme, Renderer>,\n    font: Option<Renderer::Font>,\n    selection: text_input::Value,\n    on_selected: Box<dyn Fn(T) -> Message + 'a>,\n    on_option_hovered: Option<Box<dyn Fn(T) -> Message + 'a>>,\n    on_open: Option<Message>,\n    on_close: Option<Message>,\n    on_input: Option<Box<dyn Fn(String) -> Message + 'a>>,\n    padding: Padding,\n    size: Option<f32>,\n    shaping: text::Shaping,\n    ellipsis: text::Ellipsis,\n    menu_class: <Theme as menu::Catalog>::Class<'a>,\n    menu_height: Length,\n}\n\nimpl<'a, T, Message, Theme, Renderer> ComboBox<'a, T, Message, Theme, Renderer>\nwhere\n    T: std::fmt::Display + Clone,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// Creates a new [`ComboBox`] with the given list of options, a placeholder,\n    /// the current selected value, and the message to produce when an option is\n    /// selected.\n    pub fn new(\n        state: &'a State<T>,\n        placeholder: &str,\n        selection: Option<&T>,\n        on_selected: impl Fn(T) -> Message + 'a,\n    ) -> Self {\n        let text_input = TextInput::new(placeholder, &state.value())\n            .on_input(TextInputEvent::TextChanged)\n            .class(Theme::default_input());\n\n        let selection = selection.map(T::to_string).unwrap_or_default();\n\n        Self {\n            state,\n            text_input,\n            font: None,\n            selection: text_input::Value::new(&selection),\n            on_selected: Box::new(on_selected),\n            on_option_hovered: None,\n            on_input: None,\n            on_open: None,\n            on_close: None,\n            padding: text_input::DEFAULT_PADDING,\n            size: None,\n            shaping: text::Shaping::default(),\n            ellipsis: text::Ellipsis::End,\n            menu_class: <Theme as Catalog>::default_menu(),\n            menu_height: Length::Shrink,\n        }\n    }\n\n    /// Sets the message that should be produced when some text is typed into\n    /// the [`TextInput`] of the [`ComboBox`].\n    pub fn on_input(mut self, on_input: impl Fn(String) -> Message + 'a) -> Self {\n        self.on_input = Some(Box::new(on_input));\n        self\n    }\n\n    /// Sets the message that will be produced when an option of the\n    /// [`ComboBox`] is hovered using the arrow keys.\n    pub fn on_option_hovered(mut self, on_option_hovered: impl Fn(T) -> Message + 'a) -> Self {\n        self.on_option_hovered = Some(Box::new(on_option_hovered));\n        self\n    }\n\n    /// Sets the message that will be produced when the  [`ComboBox`] is\n    /// opened.\n    pub fn on_open(mut self, message: Message) -> Self {\n        self.on_open = Some(message);\n        self\n    }\n\n    /// Sets the message that will be produced when the outside area\n    /// of the [`ComboBox`] is pressed.\n    pub fn on_close(mut self, message: Message) -> Self {\n        self.on_close = Some(message);\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`ComboBox`].\n    pub fn padding(mut self, padding: impl Into<Padding>) -> Self {\n        self.padding = padding.into();\n        self.text_input = self.text_input.padding(self.padding);\n        self\n    }\n\n    /// Sets the [`Renderer::Font`] of the [`ComboBox`].\n    ///\n    /// [`Renderer::Font`]: text::Renderer\n    pub fn font(mut self, font: Renderer::Font) -> Self {\n        self.text_input = self.text_input.font(font);\n        self.font = Some(font);\n        self\n    }\n\n    /// Sets the [`text_input::Icon`] of the [`ComboBox`].\n    pub fn icon(mut self, icon: text_input::Icon<Renderer::Font>) -> Self {\n        self.text_input = self.text_input.icon(icon);\n        self\n    }\n\n    /// Sets the text sixe of the [`ComboBox`].\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        let size = size.into();\n\n        self.text_input = self.text_input.size(size);\n        self.size = Some(size.0);\n\n        self\n    }\n\n    /// Sets the [`LineHeight`] of the [`ComboBox`].\n    pub fn line_height(self, line_height: impl Into<LineHeight>) -> Self {\n        Self {\n            text_input: self.text_input.line_height(line_height),\n            ..self\n        }\n    }\n\n    /// Sets the width of the [`ComboBox`].\n    pub fn width(self, width: impl Into<Length>) -> Self {\n        Self {\n            text_input: self.text_input.width(width),\n            ..self\n        }\n    }\n\n    /// Sets the height of the menu of the [`ComboBox`].\n    pub fn menu_height(mut self, menu_height: impl Into<Length>) -> Self {\n        self.menu_height = menu_height.into();\n        self\n    }\n\n    /// Sets the [`text::Shaping`] strategy of the [`ComboBox`].\n    pub fn shaping(mut self, shaping: text::Shaping) -> Self {\n        self.shaping = shaping;\n        self\n    }\n\n    /// Sets the [`text::Ellipsis`] strategy of the [`ComboBox`].\n    pub fn ellipsis(mut self, ellipsis: text::Ellipsis) -> Self {\n        self.ellipsis = ellipsis;\n        self\n    }\n\n    /// Sets the style of the input of the [`ComboBox`].\n    #[must_use]\n    pub fn input_style(\n        mut self,\n        style: impl Fn(&Theme, text_input::Status) -> text_input::Style + 'a,\n    ) -> Self\n    where\n        <Theme as text_input::Catalog>::Class<'a>: From<text_input::StyleFn<'a, Theme>>,\n    {\n        self.text_input = self.text_input.style(style);\n        self\n    }\n\n    /// Sets the style of the menu of the [`ComboBox`].\n    #[must_use]\n    pub fn menu_style(mut self, style: impl Fn(&Theme) -> menu::Style + 'a) -> Self\n    where\n        <Theme as menu::Catalog>::Class<'a>: From<menu::StyleFn<'a, Theme>>,\n    {\n        self.menu_class = (Box::new(style) as menu::StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the input of the [`ComboBox`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn input_class(\n        mut self,\n        class: impl Into<<Theme as text_input::Catalog>::Class<'a>>,\n    ) -> Self {\n        self.text_input = self.text_input.class(class);\n        self\n    }\n\n    /// Sets the style class of the menu of the [`ComboBox`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn menu_class(mut self, class: impl Into<<Theme as menu::Catalog>::Class<'a>>) -> Self {\n        self.menu_class = class.into();\n        self\n    }\n}\n\n/// The local state of a [`ComboBox`].\n#[derive(Debug, Clone)]\npub struct State<T> {\n    options: Vec<T>,\n    inner: RefCell<Inner<T>>,\n}\n\n#[derive(Debug, Clone)]\nstruct Inner<T> {\n    value: String,\n    option_matchers: Vec<String>,\n    filtered_options: Filtered<T>,\n}\n\n#[derive(Debug, Clone)]\nstruct Filtered<T> {\n    options: Vec<T>,\n    updated: Instant,\n}\n\nimpl<T> State<T>\nwhere\n    T: Display + Clone,\n{\n    /// Creates a new [`State`] for a [`ComboBox`] with the given list of options.\n    pub fn new(options: Vec<T>) -> Self {\n        Self::with_selection(options, None)\n    }\n\n    /// Creates a new [`State`] for a [`ComboBox`] with the given list of options\n    /// and selected value.\n    pub fn with_selection(options: Vec<T>, selection: Option<&T>) -> Self {\n        let value = selection.map(T::to_string).unwrap_or_default();\n\n        // Pre-build \"matcher\" strings ahead of time so that search is fast\n        let option_matchers = build_matchers(&options);\n\n        let filtered_options = Filtered::new(\n            search(&options, &option_matchers, &value)\n                .cloned()\n                .collect(),\n        );\n\n        Self {\n            options,\n            inner: RefCell::new(Inner {\n                value,\n                option_matchers,\n                filtered_options,\n            }),\n        }\n    }\n\n    /// Returns the options of the [`State`].\n    ///\n    /// These are the options provided when the [`State`]\n    /// was constructed with [`State::new`].\n    pub fn options(&self) -> &[T] {\n        &self.options\n    }\n\n    /// Pushes a new option to the [`State`].\n    pub fn push(&mut self, new_option: T) {\n        let mut inner = self.inner.borrow_mut();\n\n        inner.option_matchers.push(build_matcher(&new_option));\n        self.options.push(new_option);\n\n        inner.filtered_options = Filtered::new(\n            search(&self.options, &inner.option_matchers, &inner.value)\n                .cloned()\n                .collect(),\n        );\n    }\n\n    /// Returns ownership of the options of the [`State`].\n    pub fn into_options(self) -> Vec<T> {\n        self.options\n    }\n\n    fn value(&self) -> String {\n        let inner = self.inner.borrow();\n\n        inner.value.clone()\n    }\n\n    fn with_inner<O>(&self, f: impl FnOnce(&Inner<T>) -> O) -> O {\n        let inner = self.inner.borrow();\n\n        f(&inner)\n    }\n\n    fn with_inner_mut(&self, f: impl FnOnce(&mut Inner<T>)) {\n        let mut inner = self.inner.borrow_mut();\n\n        f(&mut inner);\n    }\n\n    fn sync_filtered_options(&self, options: &mut Filtered<T>) {\n        let inner = self.inner.borrow();\n\n        inner.filtered_options.sync(options);\n    }\n}\n\nimpl<T> Default for State<T>\nwhere\n    T: Display + Clone,\n{\n    fn default() -> Self {\n        Self::new(Vec::new())\n    }\n}\n\nimpl<T> Filtered<T>\nwhere\n    T: Clone,\n{\n    fn new(options: Vec<T>) -> Self {\n        Self {\n            options,\n            updated: Instant::now(),\n        }\n    }\n\n    fn empty() -> Self {\n        Self {\n            options: vec![],\n            updated: Instant::now(),\n        }\n    }\n\n    fn update(&mut self, options: Vec<T>) {\n        self.options = options;\n        self.updated = Instant::now();\n    }\n\n    fn sync(&self, other: &mut Filtered<T>) {\n        if other.updated != self.updated {\n            *other = self.clone();\n        }\n    }\n}\n\nstruct Menu<T> {\n    menu: menu::State,\n    hovered_option: Option<usize>,\n    new_selection: Option<T>,\n    filtered_options: Filtered<T>,\n}\n\n#[derive(Debug, Clone)]\nenum TextInputEvent {\n    TextChanged(String),\n}\n\nimpl<T, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for ComboBox<'_, T, Message, Theme, Renderer>\nwhere\n    T: Display + Clone + 'static,\n    Message: Clone,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn size(&self) -> Size<Length> {\n        Widget::<TextInputEvent, Theme, Renderer>::size(&self.text_input)\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut widget::Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let is_focused = {\n            let text_input_state = tree.children[0]\n                .state\n                .downcast_ref::<text_input::State<Renderer::Paragraph>>();\n\n            text_input_state.is_focused()\n        };\n\n        self.text_input.layout(\n            &mut tree.children[0],\n            renderer,\n            limits,\n            (!is_focused).then_some(&self.selection),\n        )\n    }\n\n    fn tag(&self) -> widget::tree::Tag {\n        widget::tree::Tag::of::<Menu<T>>()\n    }\n\n    fn state(&self) -> widget::tree::State {\n        widget::tree::State::new(Menu::<T> {\n            menu: menu::State::new(),\n            filtered_options: Filtered::empty(),\n            hovered_option: Some(0),\n            new_selection: None,\n        })\n    }\n\n    fn children(&self) -> Vec<widget::Tree> {\n        vec![widget::Tree::new(&self.text_input as &dyn Widget<_, _, _>)]\n    }\n\n    fn diff(&self, _tree: &mut widget::Tree) {\n        // do nothing so the children don't get cleared\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut widget::Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        let menu = tree.state.downcast_mut::<Menu<T>>();\n\n        let started_focused = {\n            let text_input_state = tree.children[0]\n                .state\n                .downcast_ref::<text_input::State<Renderer::Paragraph>>();\n\n            text_input_state.is_focused()\n        };\n        // This is intended to check whether or not the message buffer was empty,\n        // since `Shell` does not expose such functionality.\n        let mut published_message_to_shell = false;\n\n        // Create a new list of local messages\n        let mut local_messages = Vec::new();\n        let mut local_shell = Shell::new(&mut local_messages);\n\n        // Provide it to the widget\n        self.text_input.update(\n            &mut tree.children[0],\n            event,\n            layout,\n            cursor,\n            renderer,\n            &mut local_shell,\n            viewport,\n        );\n\n        if local_shell.is_event_captured() {\n            shell.capture_event();\n        }\n\n        shell.request_redraw_at(local_shell.redraw_request());\n        shell.request_input_method(local_shell.input_method());\n        shell.clipboard_mut().merge(local_shell.clipboard_mut());\n\n        // Then finally react to them here\n        for message in local_messages {\n            let TextInputEvent::TextChanged(new_value) = message;\n\n            if let Some(on_input) = &self.on_input {\n                shell.publish((on_input)(new_value.clone()));\n            }\n\n            // Couple the filtered options with the `ComboBox`\n            // value and only recompute them when the value changes,\n            // instead of doing it in every `view` call\n            self.state.with_inner_mut(|state| {\n                menu.hovered_option = Some(0);\n                state.value = new_value;\n\n                state.filtered_options.update(\n                    search(&self.state.options, &state.option_matchers, &state.value)\n                        .cloned()\n                        .collect(),\n                );\n            });\n            shell.invalidate_layout();\n            shell.request_redraw();\n        }\n\n        let is_focused = {\n            let text_input_state = tree.children[0]\n                .state\n                .downcast_ref::<text_input::State<Renderer::Paragraph>>();\n\n            text_input_state.is_focused()\n        };\n\n        if is_focused {\n            self.state.with_inner(|state| {\n                if !started_focused && let Some(on_option_hovered) = &mut self.on_option_hovered {\n                    let hovered_option = menu.hovered_option.unwrap_or(0);\n\n                    if let Some(option) = state.filtered_options.options.get(hovered_option) {\n                        shell.publish(on_option_hovered(option.clone()));\n                        published_message_to_shell = true;\n                    }\n                }\n\n                if let Event::Keyboard(keyboard::Event::KeyPressed {\n                    key: keyboard::Key::Named(named_key),\n                    modifiers,\n                    ..\n                }) = event\n                {\n                    let shift_modifier = modifiers.shift();\n                    match (named_key, shift_modifier) {\n                        (key::Named::Enter, _) => {\n                            if let Some(index) = &menu.hovered_option\n                                && let Some(option) = state.filtered_options.options.get(*index)\n                            {\n                                menu.new_selection = Some(option.clone());\n                            }\n\n                            shell.capture_event();\n                            shell.request_redraw();\n                        }\n                        (key::Named::ArrowUp, _) | (key::Named::Tab, true) => {\n                            if let Some(index) = &mut menu.hovered_option {\n                                if *index == 0 {\n                                    *index = state.filtered_options.options.len().saturating_sub(1);\n                                } else {\n                                    *index = index.saturating_sub(1);\n                                }\n                            } else {\n                                menu.hovered_option = Some(0);\n                            }\n\n                            if let Some(on_option_hovered) = &mut self.on_option_hovered\n                                && let Some(option) = menu\n                                    .hovered_option\n                                    .and_then(|index| state.filtered_options.options.get(index))\n                            {\n                                // Notify the selection\n                                shell.publish((on_option_hovered)(option.clone()));\n                                published_message_to_shell = true;\n                            }\n\n                            shell.capture_event();\n                            shell.request_redraw();\n                        }\n                        (key::Named::ArrowDown, _) | (key::Named::Tab, false)\n                            if !modifiers.shift() =>\n                        {\n                            if let Some(index) = &mut menu.hovered_option {\n                                if *index >= state.filtered_options.options.len().saturating_sub(1)\n                                {\n                                    *index = 0;\n                                } else {\n                                    *index = index.saturating_add(1).min(\n                                        state.filtered_options.options.len().saturating_sub(1),\n                                    );\n                                }\n                            } else {\n                                menu.hovered_option = Some(0);\n                            }\n\n                            if let Some(on_option_hovered) = &mut self.on_option_hovered\n                                && let Some(option) = menu\n                                    .hovered_option\n                                    .and_then(|index| state.filtered_options.options.get(index))\n                            {\n                                // Notify the selection\n                                shell.publish((on_option_hovered)(option.clone()));\n                                published_message_to_shell = true;\n                            }\n\n                            shell.capture_event();\n                            shell.request_redraw();\n                        }\n                        _ => {}\n                    }\n                }\n            });\n        }\n\n        // If the overlay menu has selected something\n        self.state.with_inner_mut(|state| {\n            if let Some(selection) = menu.new_selection.take() {\n                // Clear the value and reset the options and menu\n                state.value = String::new();\n                state.filtered_options.update(self.state.options.clone());\n                menu.menu = menu::State::default();\n\n                // Notify the selection\n                shell.publish((self.on_selected)(selection));\n                published_message_to_shell = true;\n\n                // Unfocus the input\n                let mut local_messages = Vec::new();\n                let mut local_shell = Shell::new(&mut local_messages);\n                self.text_input.update(\n                    &mut tree.children[0],\n                    &Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),\n                    layout,\n                    mouse::Cursor::Unavailable,\n                    renderer,\n                    &mut local_shell,\n                    viewport,\n                );\n                shell.request_input_method(local_shell.input_method());\n            }\n        });\n\n        let is_focused = {\n            let text_input_state = tree.children[0]\n                .state\n                .downcast_ref::<text_input::State<Renderer::Paragraph>>();\n\n            text_input_state.is_focused()\n        };\n\n        if started_focused != is_focused {\n            // Focus changed, invalidate widget tree to force a fresh `view`\n            shell.invalidate_widgets();\n\n            if !published_message_to_shell {\n                if is_focused {\n                    if let Some(on_open) = self.on_open.take() {\n                        shell.publish(on_open);\n                    }\n                } else if let Some(on_close) = self.on_close.take() {\n                    shell.publish(on_close);\n                }\n            }\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &widget::Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.text_input\n            .mouse_interaction(&tree.children[0], layout, cursor, viewport, renderer)\n    }\n\n    fn draw(\n        &self,\n        tree: &widget::Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let is_focused = {\n            let text_input_state = tree.children[0]\n                .state\n                .downcast_ref::<text_input::State<Renderer::Paragraph>>();\n\n            text_input_state.is_focused()\n        };\n\n        let selection = if is_focused || self.selection.is_empty() {\n            None\n        } else {\n            Some(&self.selection)\n        };\n\n        self.text_input.draw(\n            &tree.children[0],\n            renderer,\n            theme,\n            layout,\n            cursor,\n            selection,\n            viewport,\n        );\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut widget::Tree,\n        layout: Layout<'_>,\n        _renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        let is_focused = {\n            let text_input_state = tree.children[0]\n                .state\n                .downcast_ref::<text_input::State<Renderer::Paragraph>>();\n\n            text_input_state.is_focused()\n        };\n\n        if is_focused {\n            let Menu {\n                menu,\n                filtered_options,\n                hovered_option,\n                ..\n            } = tree.state.downcast_mut::<Menu<T>>();\n\n            self.state.sync_filtered_options(filtered_options);\n\n            if filtered_options.options.is_empty() {\n                None\n            } else {\n                let bounds = layout.bounds();\n\n                let mut menu = menu::Menu::new(\n                    menu,\n                    &filtered_options.options,\n                    hovered_option,\n                    &T::to_string,\n                    |selection| {\n                        self.state.with_inner_mut(|state| {\n                            state.value = String::new();\n                            state.filtered_options.update(self.state.options.clone());\n                        });\n\n                        tree.children[0]\n                            .state\n                            .downcast_mut::<text_input::State<Renderer::Paragraph>>()\n                            .unfocus();\n\n                        (self.on_selected)(selection)\n                    },\n                    self.on_option_hovered.as_deref(),\n                    &self.menu_class,\n                )\n                .width(bounds.width)\n                .padding(self.padding)\n                .shaping(self.shaping)\n                .ellipsis(self.ellipsis);\n\n                if let Some(font) = self.font {\n                    menu = menu.font(font);\n                }\n\n                if let Some(size) = self.size {\n                    menu = menu.text_size(size);\n                }\n\n                Some(menu.overlay(\n                    layout.position() + translation,\n                    *viewport,\n                    bounds.height,\n                    self.menu_height,\n                ))\n            }\n        } else {\n            None\n        }\n    }\n}\n\nimpl<'a, T, Message, Theme, Renderer> From<ComboBox<'a, T, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    T: Display + Clone + 'static,\n    Message: Clone + 'a,\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n{\n    fn from(combo_box: ComboBox<'a, T, Message, Theme, Renderer>) -> Self {\n        Self::new(combo_box)\n    }\n}\n\n/// The theme catalog of a [`ComboBox`].\npub trait Catalog: text_input::Catalog + menu::Catalog {\n    /// The default class for the text input of the [`ComboBox`].\n    fn default_input<'a>() -> <Self as text_input::Catalog>::Class<'a> {\n        <Self as text_input::Catalog>::default()\n    }\n\n    /// The default class for the menu of the [`ComboBox`].\n    fn default_menu<'a>() -> <Self as menu::Catalog>::Class<'a> {\n        <Self as menu::Catalog>::default()\n    }\n}\n\nimpl Catalog for Theme {}\n\nfn search<'a, T, A>(\n    options: impl IntoIterator<Item = T> + 'a,\n    option_matchers: impl IntoIterator<Item = &'a A> + 'a,\n    query: &'a str,\n) -> impl Iterator<Item = T> + 'a\nwhere\n    A: AsRef<str> + 'a,\n{\n    let query: Vec<String> = query\n        .to_lowercase()\n        .split(|c: char| !c.is_ascii_alphanumeric())\n        .map(String::from)\n        .collect();\n\n    options\n        .into_iter()\n        .zip(option_matchers)\n        // Make sure each part of the query is found in the option\n        .filter_map(move |(option, matcher)| {\n            if query.iter().all(|part| matcher.as_ref().contains(part)) {\n                Some(option)\n            } else {\n                None\n            }\n        })\n}\n\nfn build_matchers<'a, T>(options: impl IntoIterator<Item = T> + 'a) -> Vec<String>\nwhere\n    T: Display + 'a,\n{\n    options.into_iter().map(build_matcher).collect()\n}\n\nfn build_matcher<T>(option: T) -> String\nwhere\n    T: Display,\n{\n    let mut matcher = option.to_string();\n    matcher.retain(|c| c.is_ascii_alphanumeric());\n    matcher.to_lowercase()\n}\n"
  },
  {
    "path": "widget/src/container.rs",
    "content": "//! Containers let you align a widget inside their boundaries.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! use iced::widget::container;\n//!\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     container(\"This text is centered inside a rounded box!\")\n//!         .padding(10)\n//!         .center(800)\n//!         .style(container::rounded_box)\n//!         .into()\n//! }\n//! ```\nuse crate::core::alignment::{self, Alignment};\nuse crate::core::border::{self, Border};\nuse crate::core::gradient::{self, Gradient};\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::theme;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::widget::{self, Operation};\nuse crate::core::{\n    self, Background, Color, Element, Event, Layout, Length, Padding, Pixels, Rectangle, Shadow,\n    Shell, Size, Theme, Vector, Widget, color,\n};\n\n/// A widget that aligns its contents inside of its boundaries.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::container;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     container(\"This text is centered inside a rounded box!\")\n///         .padding(10)\n///         .center(800)\n///         .style(container::rounded_box)\n///         .into()\n/// }\n/// ```\npub struct Container<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    id: Option<widget::Id>,\n    padding: Padding,\n    width: Length,\n    height: Length,\n    max_width: f32,\n    max_height: f32,\n    horizontal_alignment: alignment::Horizontal,\n    vertical_alignment: alignment::Vertical,\n    clip: bool,\n    content: Element<'a, Message, Theme, Renderer>,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Message, Theme, Renderer> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    /// Creates a [`Container`] with the given content.\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        let content = content.into();\n        let size = content.as_widget().size_hint();\n\n        Container {\n            id: None,\n            padding: Padding::ZERO,\n            width: size.width.fluid(),\n            height: size.height.fluid(),\n            max_width: f32::INFINITY,\n            max_height: f32::INFINITY,\n            horizontal_alignment: alignment::Horizontal::Left,\n            vertical_alignment: alignment::Vertical::Top,\n            clip: false,\n            class: Theme::default(),\n            content,\n        }\n    }\n\n    /// Sets the [`widget::Id`] of the [`Container`].\n    pub fn id(mut self, id: impl Into<widget::Id>) -> Self {\n        self.id = Some(id.into());\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`Container`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the width of the [`Container`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Container`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the maximum width of the [`Container`].\n    pub fn max_width(mut self, max_width: impl Into<Pixels>) -> Self {\n        self.max_width = max_width.into().0;\n        self\n    }\n\n    /// Sets the maximum height of the [`Container`].\n    pub fn max_height(mut self, max_height: impl Into<Pixels>) -> Self {\n        self.max_height = max_height.into().0;\n        self\n    }\n\n    /// Sets the width of the [`Container`] and centers its contents horizontally.\n    pub fn center_x(self, width: impl Into<Length>) -> Self {\n        self.width(width).align_x(alignment::Horizontal::Center)\n    }\n\n    /// Sets the height of the [`Container`] and centers its contents vertically.\n    pub fn center_y(self, height: impl Into<Length>) -> Self {\n        self.height(height).align_y(alignment::Vertical::Center)\n    }\n\n    /// Sets the width and height of the [`Container`] and centers its contents in\n    /// both the horizontal and vertical axes.\n    ///\n    /// This is equivalent to chaining [`center_x`] and [`center_y`].\n    ///\n    /// [`center_x`]: Self::center_x\n    /// [`center_y`]: Self::center_y\n    pub fn center(self, length: impl Into<Length>) -> Self {\n        let length = length.into();\n\n        self.center_x(length).center_y(length)\n    }\n\n    /// Sets the width of the [`Container`] and aligns its contents to the left.\n    pub fn align_left(self, width: impl Into<Length>) -> Self {\n        self.width(width).align_x(alignment::Horizontal::Left)\n    }\n\n    /// Sets the width of the [`Container`] and aligns its contents to the right.\n    pub fn align_right(self, width: impl Into<Length>) -> Self {\n        self.width(width).align_x(alignment::Horizontal::Right)\n    }\n\n    /// Sets the height of the [`Container`] and aligns its contents to the top.\n    pub fn align_top(self, height: impl Into<Length>) -> Self {\n        self.height(height).align_y(alignment::Vertical::Top)\n    }\n\n    /// Sets the height of the [`Container`] and aligns its contents to the bottom.\n    pub fn align_bottom(self, height: impl Into<Length>) -> Self {\n        self.height(height).align_y(alignment::Vertical::Bottom)\n    }\n\n    /// Sets the content alignment for the horizontal axis of the [`Container`].\n    pub fn align_x(mut self, alignment: impl Into<alignment::Horizontal>) -> Self {\n        self.horizontal_alignment = alignment.into();\n        self\n    }\n\n    /// Sets the content alignment for the vertical axis of the [`Container`].\n    pub fn align_y(mut self, alignment: impl Into<alignment::Vertical>) -> Self {\n        self.vertical_alignment = alignment.into();\n        self\n    }\n\n    /// Sets whether the contents of the [`Container`] should be clipped on\n    /// overflow.\n    pub fn clip(mut self, clip: bool) -> Self {\n        self.clip = clip;\n        self\n    }\n\n    /// Sets the style of the [`Container`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Container`].\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Container<'_, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        self.content.as_widget().tag()\n    }\n\n    fn state(&self) -> tree::State {\n        self.content.as_widget().state()\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        self.content.as_widget().children()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        self.content.as_widget().diff(tree);\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout(\n            limits,\n            self.width,\n            self.height,\n            self.max_width,\n            self.max_height,\n            self.padding,\n            self.horizontal_alignment,\n            self.vertical_alignment,\n            |limits| self.content.as_widget_mut().layout(tree, renderer, limits),\n        )\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        operation.container(self.id.as_ref(), layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.content.as_widget_mut().operate(\n                tree,\n                layout.children().next().unwrap(),\n                renderer,\n                operation,\n            );\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget_mut().update(\n            tree,\n            event,\n            layout.children().next().unwrap(),\n            cursor,\n            renderer,\n            shell,\n            viewport,\n        );\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.content.as_widget().mouse_interaction(\n            tree,\n            layout.children().next().unwrap(),\n            cursor,\n            viewport,\n            renderer,\n        )\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        renderer_style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n        let style = theme.style(&self.class);\n\n        if let Some(clipped_viewport) = bounds.intersection(viewport) {\n            draw_background(renderer, &style, bounds);\n\n            self.content.as_widget().draw(\n                tree,\n                renderer,\n                theme,\n                &renderer::Style {\n                    text_color: style.text_color.unwrap_or(renderer_style.text_color),\n                },\n                layout.children().next().unwrap(),\n                cursor,\n                if self.clip {\n                    &clipped_viewport\n                } else {\n                    viewport\n                },\n            );\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.content.as_widget_mut().overlay(\n            tree,\n            layout.children().next().unwrap(),\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Container<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(\n        container: Container<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(container)\n    }\n}\n\n/// Computes the layout of a [`Container`].\npub fn layout(\n    limits: &layout::Limits,\n    width: Length,\n    height: Length,\n    max_width: f32,\n    max_height: f32,\n    padding: Padding,\n    horizontal_alignment: alignment::Horizontal,\n    vertical_alignment: alignment::Vertical,\n    layout_content: impl FnOnce(&layout::Limits) -> layout::Node,\n) -> layout::Node {\n    layout::positioned(\n        &limits.max_width(max_width).max_height(max_height),\n        width,\n        height,\n        padding,\n        |limits| layout_content(&limits.loose()),\n        |content, size| {\n            content.align(\n                Alignment::from(horizontal_alignment),\n                Alignment::from(vertical_alignment),\n                size,\n            )\n        },\n    )\n}\n\n/// Draws the background of a [`Container`] given its [`Style`] and its `bounds`.\npub fn draw_background<Renderer>(renderer: &mut Renderer, style: &Style, bounds: Rectangle)\nwhere\n    Renderer: core::Renderer,\n{\n    if style.background.is_some() || style.border.width > 0.0 || style.shadow.color.a > 0.0 {\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds,\n                border: style.border,\n                shadow: style.shadow,\n                snap: style.snap,\n            },\n            style\n                .background\n                .unwrap_or(Background::Color(Color::TRANSPARENT)),\n        );\n    }\n}\n\n/// The appearance of a container.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The text [`Color`] of the container.\n    pub text_color: Option<Color>,\n    /// The [`Background`] of the container.\n    pub background: Option<Background>,\n    /// The [`Border`] of the container.\n    pub border: Border,\n    /// The [`Shadow`] of the container.\n    pub shadow: Shadow,\n    /// Whether the container should be snapped to the pixel grid.\n    pub snap: bool,\n}\n\nimpl Default for Style {\n    fn default() -> Self {\n        Self {\n            text_color: None,\n            background: None,\n            border: Border::default(),\n            shadow: Shadow::default(),\n            snap: renderer::CRISP,\n        }\n    }\n}\n\nimpl Style {\n    /// Updates the text color of the [`Style`].\n    pub fn color(self, color: impl Into<Color>) -> Self {\n        Self {\n            text_color: Some(color.into()),\n            ..self\n        }\n    }\n\n    /// Updates the border of the [`Style`].\n    pub fn border(self, border: impl Into<Border>) -> Self {\n        Self {\n            border: border.into(),\n            ..self\n        }\n    }\n\n    /// Updates the background of the [`Style`].\n    pub fn background(self, background: impl Into<Background>) -> Self {\n        Self {\n            background: Some(background.into()),\n            ..self\n        }\n    }\n\n    /// Updates the shadow of the [`Style`].\n    pub fn shadow(self, shadow: impl Into<Shadow>) -> Self {\n        Self {\n            shadow: shadow.into(),\n            ..self\n        }\n    }\n}\n\nimpl From<Color> for Style {\n    fn from(color: Color) -> Self {\n        Self::default().background(color)\n    }\n}\n\nimpl From<Gradient> for Style {\n    fn from(gradient: Gradient) -> Self {\n        Self::default().background(gradient)\n    }\n}\n\nimpl From<gradient::Linear> for Style {\n    fn from(gradient: gradient::Linear) -> Self {\n        Self::default().background(gradient)\n    }\n}\n\n/// The theme catalog of a [`Container`].\npub trait Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`Container`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl<Theme> From<Style> for StyleFn<'_, Theme> {\n    fn from(style: Style) -> Self {\n        Box::new(move |_theme| style)\n    }\n}\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(transparent)\n    }\n\n    fn style(&self, class: &Self::Class<'_>) -> Style {\n        class(self)\n    }\n}\n\n/// A transparent [`Container`].\npub fn transparent<Theme>(_theme: &Theme) -> Style {\n    Style::default()\n}\n\n/// A [`Container`] with the given [`Background`].\npub fn background(background: impl Into<Background>) -> Style {\n    Style::default().background(background)\n}\n\n/// A rounded [`Container`] with a background.\npub fn rounded_box(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    Style {\n        background: Some(palette.background.weak.color.into()),\n        text_color: Some(palette.background.weak.text),\n        border: border::rounded(2),\n        ..Style::default()\n    }\n}\n\n/// A bordered [`Container`] with a background.\npub fn bordered_box(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    Style {\n        background: Some(palette.background.weakest.color.into()),\n        text_color: Some(palette.background.weakest.text),\n        border: Border {\n            width: 1.0,\n            radius: 5.0.into(),\n            color: palette.background.weak.color,\n        },\n        ..Style::default()\n    }\n}\n\n/// A [`Container`] with a dark background and white text.\npub fn dark(_theme: &Theme) -> Style {\n    style(theme::palette::Pair {\n        color: color!(0x111111),\n        text: Color::WHITE,\n    })\n}\n\n/// A [`Container`] with a primary background color.\npub fn primary(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    style(palette.primary.base)\n}\n\n/// A [`Container`] with a secondary background color.\npub fn secondary(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    style(palette.secondary.base)\n}\n\n/// A [`Container`] with a success background color.\npub fn success(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    style(palette.success.base)\n}\n\n/// A [`Container`] with a warning background color.\npub fn warning(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    style(palette.warning.base)\n}\n\n/// A [`Container`] with a danger background color.\npub fn danger(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    style(palette.danger.base)\n}\n\nfn style(pair: theme::palette::Pair) -> Style {\n    Style {\n        background: Some(pair.color.into()),\n        text_color: Some(pair.text),\n        border: border::rounded(2),\n        ..Style::default()\n    }\n}\n"
  },
  {
    "path": "widget/src/float.rs",
    "content": "//! Make elements float!\nuse crate::core;\nuse crate::core::border;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget;\nuse crate::core::widget::tree;\nuse crate::core::{\n    Element, Event, Layout, Length, Rectangle, Shadow, Shell, Size, Transformation, Vector, Widget,\n};\n\n/// A widget that can make its contents float over other widgets.\npub struct Float<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n{\n    content: Element<'a, Message, Theme, Renderer>,\n    scale: f32,\n    translate: Option<Box<dyn Fn(Rectangle, Rectangle) -> Vector + 'a>>,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Message, Theme, Renderer> Float<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n{\n    /// Creates a new [`Float`] widget with the given content.\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            content: content.into(),\n            scale: 1.0,\n            translate: None,\n            class: Theme::default(),\n        }\n    }\n\n    /// Sets the scale to be applied to the contents of the [`Float`].\n    pub fn scale(mut self, scale: f32) -> Self {\n        self.scale = scale;\n        self\n    }\n\n    /// Sets the translation logic to be applied to the contents of the [`Float`].\n    ///\n    /// The logic takes the original (non-scaled) bounds of the contents and the\n    /// viewport bounds. These bounds can be useful to ensure the floating elements\n    /// always stay on screen.\n    pub fn translate(mut self, translate: impl Fn(Rectangle, Rectangle) -> Vector + 'a) -> Self {\n        self.translate = Some(Box::new(translate));\n        self\n    }\n\n    /// Sets the style of the [`Float`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Float`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n\n    fn is_floating(&self, bounds: Rectangle, viewport: Rectangle) -> bool {\n        self.scale > 1.0\n            || self\n                .translate\n                .as_ref()\n                .is_some_and(|translate| translate(bounds, viewport) != Vector::ZERO)\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Float<'_, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        self.content.as_widget().tag()\n    }\n\n    fn state(&self) -> tree::State {\n        self.content.as_widget().state()\n    }\n\n    fn children(&self) -> Vec<tree::Tree> {\n        self.content.as_widget().children()\n    }\n\n    fn diff(&self, tree: &mut widget::Tree) {\n        self.content.as_widget().diff(tree);\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.content.as_widget().size()\n    }\n\n    fn size_hint(&self) -> Size<Length> {\n        self.content.as_widget().size_hint()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut widget::Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.content.as_widget_mut().layout(tree, renderer, limits)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut widget::Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        if self.is_floating(layout.bounds(), *viewport) {\n            return;\n        }\n\n        self.content\n            .as_widget_mut()\n            .update(tree, event, layout, cursor, renderer, shell, viewport);\n    }\n\n    fn draw(\n        &self,\n        tree: &widget::Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        if self.is_floating(layout.bounds(), *viewport) {\n            return;\n        }\n\n        {\n            let style = theme.style(&self.class);\n\n            if style.shadow.color.a > 0.0 {\n                renderer.fill_quad(\n                    renderer::Quad {\n                        bounds: layout.bounds().shrink(1.0),\n                        shadow: style.shadow,\n                        border: border::rounded(style.shadow_border_radius),\n                        snap: false,\n                    },\n                    style.shadow.color,\n                );\n            }\n        }\n\n        self.content\n            .as_widget()\n            .draw(tree, renderer, theme, style, layout, cursor, viewport);\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &widget::Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        if self.is_floating(layout.bounds(), *viewport) {\n            return mouse::Interaction::None;\n        }\n\n        self.content\n            .as_widget()\n            .mouse_interaction(tree, layout, cursor, viewport, renderer)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut widget::Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.content\n            .as_widget_mut()\n            .operate(tree, layout, renderer, operation);\n    }\n\n    fn overlay<'a>(\n        &'a mut self,\n        state: &'a mut widget::Tree,\n        layout: Layout<'a>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        offset: Vector,\n    ) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {\n        let bounds = layout.bounds();\n\n        let translation = self\n            .translate\n            .as_ref()\n            .map(|translate| translate(bounds + offset, *viewport))\n            .unwrap_or(Vector::ZERO);\n\n        if self.scale > 1.0 || translation != Vector::ZERO {\n            let translation = translation + offset;\n\n            let transformation = Transformation::translate(\n                bounds.x + bounds.width / 2.0 + translation.x,\n                bounds.y + bounds.height / 2.0 + translation.y,\n            ) * Transformation::scale(self.scale)\n                * Transformation::translate(\n                    -bounds.x - bounds.width / 2.0,\n                    -bounds.y - bounds.height / 2.0,\n                );\n\n            Some(overlay::Element::new(Box::new(Overlay {\n                float: self,\n                state,\n                layout,\n                viewport: *viewport,\n                transformation,\n            })))\n        } else {\n            self.content\n                .as_widget_mut()\n                .overlay(state, layout, renderer, viewport, offset)\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Float<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(float: Float<'a, Message, Theme, Renderer>) -> Self {\n        Element::new(float)\n    }\n}\n\nstruct Overlay<'a, 'b, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n{\n    float: &'a mut Float<'b, Message, Theme, Renderer>,\n    state: &'a mut widget::Tree,\n    layout: Layout<'a>,\n    viewport: Rectangle,\n    transformation: Transformation,\n}\n\nimpl<Message, Theme, Renderer> core::Overlay<Message, Theme, Renderer>\n    for Overlay<'_, '_, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    fn layout(&mut self, _renderer: &Renderer, _bounds: Size) -> layout::Node {\n        let bounds = self.layout.bounds() * self.transformation;\n\n        layout::Node::new(bounds.size()).move_to(bounds.position())\n    }\n\n    fn update(\n        &mut self,\n        event: &Event,\n        _layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n    ) {\n        let inverse = self.transformation.inverse();\n\n        self.float.content.as_widget_mut().update(\n            self.state,\n            event,\n            self.layout,\n            cursor * inverse,\n            renderer,\n            shell,\n            &(self.viewport * inverse),\n        );\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        _layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) {\n        let bounds = self.layout.bounds();\n        let inverse = self.transformation.inverse();\n\n        renderer.with_layer(self.viewport, |renderer| {\n            renderer.with_transformation(self.transformation, |renderer| {\n                {\n                    let style = theme.style(&self.float.class);\n\n                    if style.shadow.color.a > 0.0 {\n                        renderer.fill_quad(\n                            renderer::Quad {\n                                bounds: bounds.shrink(1.0),\n                                shadow: style.shadow,\n                                border: border::rounded(style.shadow_border_radius),\n                                snap: false,\n                            },\n                            style.shadow.color,\n                        );\n                    }\n                }\n\n                self.float.content.as_widget().draw(\n                    self.state,\n                    renderer,\n                    theme,\n                    style,\n                    self.layout,\n                    cursor * inverse,\n                    &(self.viewport * inverse),\n                );\n            });\n        });\n    }\n\n    fn mouse_interaction(\n        &self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        if !cursor.is_over(layout.bounds()) {\n            return mouse::Interaction::None;\n        }\n\n        let inverse = self.transformation.inverse();\n\n        self.float.content.as_widget().mouse_interaction(\n            self.state,\n            self.layout,\n            cursor * inverse,\n            &(self.viewport * inverse),\n            renderer,\n        )\n    }\n\n    fn index(&self) -> f32 {\n        self.float.scale * 0.5\n    }\n\n    fn overlay<'a>(\n        &'a mut self,\n        _layout: Layout<'_>,\n        renderer: &Renderer,\n    ) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {\n        self.float.content.as_widget_mut().overlay(\n            self.state,\n            self.layout,\n            renderer,\n            &(self.viewport * self.transformation.inverse()),\n            self.transformation.translation(),\n        )\n    }\n}\n\n/// The theme catalog of a [`Float`].\n///\n/// All themes that can be used with [`Float`]\n/// must implement this trait.\npub trait Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`Float`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl Catalog for crate::Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(|_| Style::default())\n    }\n\n    fn style(&self, class: &Self::Class<'_>) -> Style {\n        class(self)\n    }\n}\n\n/// The style of a [`Float`].\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub struct Style {\n    /// The [`Shadow`] of the [`Float`].\n    pub shadow: Shadow,\n    /// The border radius of the shadow.\n    pub shadow_border_radius: border::Radius,\n}\n"
  },
  {
    "path": "widget/src/grid.rs",
    "content": "//! Distribute content on a grid.\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget::{Operation, Tree};\nuse crate::core::{Element, Event, Length, Pixels, Rectangle, Shell, Size, Vector, Widget};\n\n/// A container that distributes its contents on a responsive grid.\npub struct Grid<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    spacing: f32,\n    columns: Constraint,\n    width: Option<Pixels>,\n    height: Sizing,\n    children: Vec<Element<'a, Message, Theme, Renderer>>,\n}\n\nenum Constraint {\n    MaxWidth(Pixels),\n    Amount(usize),\n}\n\nimpl<'a, Message, Theme, Renderer> Grid<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    /// Creates an empty [`Grid`].\n    pub fn new() -> Self {\n        Self::from_vec(Vec::new())\n    }\n\n    /// Creates a [`Grid`] with the given capacity.\n    pub fn with_capacity(capacity: usize) -> Self {\n        Self::from_vec(Vec::with_capacity(capacity))\n    }\n\n    /// Creates a [`Grid`] with the given elements.\n    pub fn with_children(\n        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        let iterator = children.into_iter();\n\n        Self::with_capacity(iterator.size_hint().0).extend(iterator)\n    }\n\n    /// Creates a [`Grid`] from an already allocated [`Vec`].\n    pub fn from_vec(children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            spacing: 0.0,\n            columns: Constraint::Amount(3),\n            width: None,\n            height: Sizing::AspectRatio(1.0),\n            children,\n        }\n    }\n\n    /// Sets the spacing _between_ cells in the [`Grid`].\n    pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {\n        self.spacing = amount.into().0;\n        self\n    }\n\n    /// Sets the width of the [`Grid`] in [`Pixels`].\n    ///\n    /// By default, a [`Grid`] will [`Fill`] its parent.\n    ///\n    /// [`Fill`]: Length::Fill\n    pub fn width(mut self, width: impl Into<Pixels>) -> Self {\n        self.width = Some(width.into());\n        self\n    }\n\n    /// Sets the height of the [`Grid`].\n    ///\n    /// By default, a [`Grid`] uses a cell aspect ratio of `1.0` (i.e. squares).\n    pub fn height(mut self, height: impl Into<Sizing>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the amount of columns in the [`Grid`].\n    pub fn columns(mut self, column: usize) -> Self {\n        self.columns = Constraint::Amount(column);\n        self\n    }\n\n    /// Makes the amount of columns dynamic in the [`Grid`], never\n    /// exceeding the provided `max_width`.\n    pub fn fluid(mut self, max_width: impl Into<Pixels>) -> Self {\n        self.columns = Constraint::MaxWidth(max_width.into());\n        self\n    }\n\n    /// Adds an [`Element`] to the [`Grid`].\n    pub fn push(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        self.children.push(child.into());\n        self\n    }\n\n    /// Adds an element to the [`Grid`], if `Some`.\n    pub fn push_maybe(\n        self,\n        child: Option<impl Into<Element<'a, Message, Theme, Renderer>>>,\n    ) -> Self {\n        if let Some(child) = child {\n            self.push(child)\n        } else {\n            self\n        }\n    }\n\n    /// Extends the [`Grid`] with the given children.\n    pub fn extend(\n        self,\n        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        children.into_iter().fold(self, Self::push)\n    }\n}\n\nimpl<Message, Renderer> Default for Grid<'_, Message, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<'a, Message, Theme, Renderer: crate::core::Renderer>\n    FromIterator<Element<'a, Message, Theme, Renderer>> for Grid<'a, Message, Theme, Renderer>\n{\n    fn from_iter<T: IntoIterator<Item = Element<'a, Message, Theme, Renderer>>>(iter: T) -> Self {\n        Self::with_children(iter)\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Grid<'_, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn children(&self) -> Vec<Tree> {\n        self.children.iter().map(Tree::new).collect()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        tree.diff_children(&self.children);\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self\n                .width\n                .map(|pixels| Length::Fixed(pixels.0))\n                .unwrap_or(Length::Fill),\n            height: match self.height {\n                Sizing::AspectRatio(_) => Length::Shrink,\n                Sizing::EvenlyDistribute(length) => length,\n            },\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let size = self.size();\n        let limits = limits.width(size.width).height(size.height);\n        let available = limits.max();\n\n        if limits.compression().width && self.width.is_none() {\n            return layout::Node::new(Size::ZERO);\n        }\n\n        let cells_per_row = match self.columns {\n            // width = n * (cell + spacing) - spacing, given n > 0\n            Constraint::MaxWidth(pixels) => {\n                ((available.width + self.spacing) / (pixels.0 + self.spacing)).ceil() as usize\n            }\n            Constraint::Amount(amount) => amount,\n        };\n\n        if self.children.is_empty() || cells_per_row == 0 {\n            return layout::Node::new(limits.resolve(size.width, size.height, Size::ZERO));\n        }\n\n        let cell_width =\n            (available.width - self.spacing * (cells_per_row - 1) as f32) / cells_per_row as f32;\n\n        let cell_height = match self.height {\n            Sizing::AspectRatio(ratio) => Some(cell_width / ratio),\n            Sizing::EvenlyDistribute(Length::Shrink) => None,\n            Sizing::EvenlyDistribute(_) => {\n                let total_rows = self.children.len().div_ceil(cells_per_row);\n                Some(\n                    (available.height - self.spacing * (total_rows - 1) as f32) / total_rows as f32,\n                )\n            }\n        };\n\n        let cell_limits = layout::Limits::new(\n            Size::new(cell_width, cell_height.unwrap_or(0.0)),\n            Size::new(cell_width, cell_height.unwrap_or(available.height)),\n        );\n\n        let mut nodes = Vec::with_capacity(self.children.len());\n        let mut x = 0.0;\n        let mut y = 0.0;\n        let mut row_height = 0.0f32;\n\n        for (i, (child, tree)) in self.children.iter_mut().zip(&mut tree.children).enumerate() {\n            let node = child\n                .as_widget_mut()\n                .layout(tree, renderer, &cell_limits)\n                .move_to((x, y));\n\n            let size = node.size();\n\n            x += size.width + self.spacing;\n            row_height = row_height.max(size.height);\n\n            if (i + 1) % cells_per_row == 0 {\n                y += cell_height.unwrap_or(row_height) + self.spacing;\n                x = 0.0;\n                row_height = 0.0;\n            }\n\n            nodes.push(node);\n        }\n\n        if x == 0.0 {\n            y -= self.spacing;\n        } else {\n            y += cell_height.unwrap_or(row_height);\n        }\n\n        layout::Node::with_children(Size::new(available.width, y), nodes)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        operation.container(None, layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.children\n                .iter_mut()\n                .zip(&mut tree.children)\n                .zip(layout.children())\n                .for_each(|((child, state), layout)| {\n                    child\n                        .as_widget_mut()\n                        .operate(state, layout, renderer, operation);\n                });\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        for ((child, tree), layout) in self\n            .children\n            .iter_mut()\n            .zip(&mut tree.children)\n            .zip(layout.children())\n        {\n            child\n                .as_widget_mut()\n                .update(tree, event, layout, cursor, renderer, shell, viewport);\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.children\n            .iter()\n            .zip(&tree.children)\n            .zip(layout.children())\n            .map(|((child, tree), layout)| {\n                child\n                    .as_widget()\n                    .mouse_interaction(tree, layout, cursor, viewport, renderer)\n            })\n            .max()\n            .unwrap_or_default()\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        if let Some(viewport) = layout.bounds().intersection(viewport) {\n            for ((child, tree), layout) in self\n                .children\n                .iter()\n                .zip(&tree.children)\n                .zip(layout.children())\n                .filter(|(_, layout)| layout.bounds().intersects(&viewport))\n            {\n                child\n                    .as_widget()\n                    .draw(tree, renderer, theme, style, layout, cursor, &viewport);\n            }\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        overlay::from_children(\n            &mut self.children,\n            tree,\n            layout,\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Grid<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: crate::core::Renderer + 'a,\n{\n    fn from(row: Grid<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(row)\n    }\n}\n\n/// The sizing strategy of a [`Grid`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Sizing {\n    /// The [`Grid`] will ensure each cell follows the given aspect ratio and the\n    /// total size will be the sum of the cells and the spacing between them.\n    ///\n    /// The ratio is the amount of horizontal pixels per each vertical pixel of a cell\n    /// in the [`Grid`].\n    AspectRatio(f32),\n\n    /// The [`Grid`] will evenly distribute the space available in the given [`Length`]\n    /// for each cell.\n    EvenlyDistribute(Length),\n}\n\nimpl From<f32> for Sizing {\n    fn from(height: f32) -> Self {\n        Self::EvenlyDistribute(Length::from(height))\n    }\n}\n\nimpl From<Length> for Sizing {\n    fn from(height: Length) -> Self {\n        Self::EvenlyDistribute(height)\n    }\n}\n\n/// Creates a new [`Sizing`] strategy that maintains the given aspect ratio.\npub fn aspect_ratio(width: impl Into<Pixels>, height: impl Into<Pixels>) -> Sizing {\n    Sizing::AspectRatio(width.into().0 / height.into().0)\n}\n"
  },
  {
    "path": "widget/src/helpers.rs",
    "content": "//! Helper functions to create pure widgets.\nuse crate::button::{self, Button};\nuse crate::checkbox::{self, Checkbox};\nuse crate::combo_box::{self, ComboBox};\nuse crate::container::{self, Container};\nuse crate::core;\nuse crate::core::theme;\nuse crate::core::widget::operation::{self, Operation};\nuse crate::core::window;\nuse crate::core::{Element, Length, Size, Widget};\nuse crate::float::{self, Float};\nuse crate::keyed;\nuse crate::overlay;\nuse crate::pane_grid::{self, PaneGrid};\nuse crate::pick_list::{self, PickList};\nuse crate::progress_bar::{self, ProgressBar};\nuse crate::radio::{self, Radio};\nuse crate::scrollable::{self, Scrollable};\nuse crate::slider::{self, Slider};\nuse crate::text::{self, Text};\nuse crate::text_editor::{self, TextEditor};\nuse crate::text_input::{self, TextInput};\nuse crate::toggler::{self, Toggler};\nuse crate::tooltip::{self, Tooltip};\nuse crate::vertical_slider::{self, VerticalSlider};\nuse crate::{Column, Grid, MouseArea, Pin, Responsive, Row, Sensor, Space, Stack, Themer};\n\nuse std::borrow::Borrow;\nuse std::ops::RangeInclusive;\n\npub use crate::table::table;\n\n/// Creates a [`Column`] with the given children.\n///\n/// Columns distribute their children vertically.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{button, column};\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     column![\n///         \"I am on top!\",\n///         button(\"I am in the center!\"),\n///         \"I am below.\",\n///     ].into()\n/// }\n/// ```\n#[macro_export]\nmacro_rules! column {\n    () => (\n        $crate::Column::new()\n    );\n    ($($x:expr),+ $(,)?) => (\n        $crate::Column::with_children([$($crate::core::Element::from($x)),+])\n    );\n}\n\n/// Creates a [`Row`] with the given children.\n///\n/// Rows distribute their children horizontally.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{button, row};\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     row![\n///         \"I am to the left!\",\n///         button(\"I am in the middle!\"),\n///         \"I am to the right!\",\n///     ].into()\n/// }\n/// ```\n#[macro_export]\nmacro_rules! row {\n    () => (\n        $crate::Row::new()\n    );\n    ($($x:expr),+ $(,)?) => (\n        $crate::Row::with_children([$($crate::core::Element::from($x)),+])\n    );\n}\n\n/// Creates a [`Stack`] with the given children.\n///\n/// [`Stack`]: crate::Stack\n#[macro_export]\nmacro_rules! stack {\n    () => (\n        $crate::Stack::new()\n    );\n    ($($x:expr),+ $(,)?) => (\n        $crate::Stack::with_children([$($crate::core::Element::from($x)),+])\n    );\n}\n\n/// Creates a [`Grid`] with the given children.\n///\n/// [`Grid`]: crate::Grid\n#[macro_export]\nmacro_rules! grid {\n    () => (\n        $crate::Grid::new()\n    );\n    ($($x:expr),+ $(,)?) => (\n        $crate::Grid::with_children([$($crate::core::Element::from($x)),+])\n    );\n}\n\n/// Creates a new [`Text`] widget with the provided content.\n///\n/// [`Text`]: core::widget::Text\n///\n/// This macro uses the same syntax as [`format!`], but creates a new [`Text`] widget instead.\n///\n/// See [the formatting documentation in `std::fmt`](std::fmt)\n/// for details of the macro argument syntax.\n///\n/// # Examples\n///\n/// ```no_run\n/// # mod iced {\n/// #     pub mod widget {\n/// #         macro_rules! text {\n/// #           ($($arg:tt)*) => {unimplemented!()}\n/// #         }\n/// #         pub(crate) use text;\n/// #     }\n/// # }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>;\n/// use iced::widget::text;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(_state: &State) -> Element<Message> {\n///     let simple = text!(\"Hello, world!\");\n///\n///     let keyword = text!(\"Hello, {}\", \"world!\");\n///\n///     let planet = \"Earth\";\n///     let local_variable = text!(\"Hello, {planet}!\");\n///     // ...\n///     # unimplemented!()\n/// }\n/// ```\n#[macro_export]\nmacro_rules! text {\n    ($($arg:tt)*) => {\n        $crate::Text::new(format!($($arg)*))\n    };\n}\n\n/// Creates some [`Rich`] text with the given spans.\n///\n/// [`Rich`]: text::Rich\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::font;\n/// use iced::widget::{rich_text, span};\n/// use iced::{color, never, Font};\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     rich_text![\n///         span(\"I am red!\").color(color!(0xff0000)),\n///         span(\" \"),\n///         span(\"And I am bold!\").font(Font { weight: font::Weight::Bold, ..Font::default() }),\n///     ]\n///     .on_link_click(never)\n///     .size(20)\n///     .into()\n/// }\n/// ```\n#[macro_export]\nmacro_rules! rich_text {\n    () => (\n        $crate::text::Rich::new()\n    );\n    ($($x:expr),+ $(,)?) => (\n        $crate::text::Rich::from_iter([$($crate::text::Span::from($x)),+])\n    );\n}\n\n/// Creates a new [`Container`] with the provided content.\n///\n/// Containers let you align a widget inside their boundaries.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::container;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     container(\"This text is centered inside a rounded box!\")\n///         .padding(10)\n///         .center(800)\n///         .style(container::rounded_box)\n///         .into()\n/// }\n/// ```\npub fn container<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    Container::new(content)\n}\n\n/// Creates a new [`Container`] that fills all the available space\n/// and centers its contents inside.\n///\n/// This is equivalent to:\n/// ```rust,no_run\n/// # use iced_widget::core::Length::Fill;\n/// # use iced_widget::Container;\n/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }\n/// let center = container(\"Center!\").center(Fill);\n/// ```\n///\n/// [`Container`]: crate::Container\npub fn center<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    container(content).center(Length::Fill)\n}\n\n/// Creates a new [`Container`] that fills all the available space\n/// horizontally and centers its contents inside.\n///\n/// This is equivalent to:\n/// ```rust,no_run\n/// # use iced_widget::core::Length::Fill;\n/// # use iced_widget::Container;\n/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }\n/// let center_x = container(\"Horizontal Center!\").center_x(Fill);\n/// ```\n///\n/// [`Container`]: crate::Container\npub fn center_x<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    container(content).center_x(Length::Fill)\n}\n\n/// Creates a new [`Container`] that fills all the available space\n/// vertically and centers its contents inside.\n///\n/// This is equivalent to:\n/// ```rust,no_run\n/// # use iced_widget::core::Length::Fill;\n/// # use iced_widget::Container;\n/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }\n/// let center_y = container(\"Vertical Center!\").center_y(Fill);\n/// ```\n///\n/// [`Container`]: crate::Container\npub fn center_y<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    container(content).center_y(Length::Fill)\n}\n\n/// Creates a new [`Container`] that fills all the available space\n/// horizontally and right-aligns its contents inside.\n///\n/// This is equivalent to:\n/// ```rust,no_run\n/// # use iced_widget::core::Length::Fill;\n/// # use iced_widget::Container;\n/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }\n/// let right = container(\"Right!\").align_right(Fill);\n/// ```\n///\n/// [`Container`]: crate::Container\npub fn right<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    container(content).align_right(Length::Fill)\n}\n\n/// Creates a new [`Container`] that fills all the available space\n/// and aligns its contents inside to the right center.\n///\n/// This is equivalent to:\n/// ```rust,no_run\n/// # use iced_widget::core::Length::Fill;\n/// # use iced_widget::Container;\n/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }\n/// let right_center = container(\"Bottom Center!\").align_right(Fill).center_y(Fill);\n/// ```\n///\n/// [`Container`]: crate::Container\npub fn right_center<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    container(content)\n        .align_right(Length::Fill)\n        .center_y(Length::Fill)\n}\n\n/// Creates a new [`Container`] that fills all the available space\n/// vertically and bottom-aligns its contents inside.\n///\n/// This is equivalent to:\n/// ```rust,no_run\n/// # use iced_widget::core::Length::Fill;\n/// # use iced_widget::Container;\n/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }\n/// let bottom = container(\"Bottom!\").align_bottom(Fill);\n/// ```\n///\n/// [`Container`]: crate::Container\npub fn bottom<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    container(content).align_bottom(Length::Fill)\n}\n\n/// Creates a new [`Container`] that fills all the available space\n/// and aligns its contents inside to the bottom center.\n///\n/// This is equivalent to:\n/// ```rust,no_run\n/// # use iced_widget::core::Length::Fill;\n/// # use iced_widget::Container;\n/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }\n/// let bottom_center = container(\"Bottom Center!\").center_x(Fill).align_bottom(Fill);\n/// ```\n///\n/// [`Container`]: crate::Container\npub fn bottom_center<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    container(content)\n        .center_x(Length::Fill)\n        .align_bottom(Length::Fill)\n}\n\n/// Creates a new [`Container`] that fills all the available space\n/// and aligns its contents inside to the bottom right corner.\n///\n/// This is equivalent to:\n/// ```rust,no_run\n/// # use iced_widget::core::Length::Fill;\n/// # use iced_widget::Container;\n/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }\n/// let bottom_right = container(\"Bottom!\").align_right(Fill).align_bottom(Fill);\n/// ```\n///\n/// [`Container`]: crate::Container\npub fn bottom_right<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Container<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    container(content)\n        .align_right(Length::Fill)\n        .align_bottom(Length::Fill)\n}\n\n/// Creates a new [`Pin`] widget with the given content.\n///\n/// A [`Pin`] widget positions its contents at some fixed coordinates inside of its boundaries.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::Length::Fill; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::pin;\n/// use iced::Fill;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     pin(\"This text is displayed at coordinates (50, 50)!\")\n///         .x(50)\n///         .y(50)\n///         .into()\n/// }\n/// ```\npub fn pin<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Pin<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    Pin::new(content)\n}\n\n/// Creates a new [`Column`] with the given children.\n///\n/// Columns distribute their children vertically.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{column, text};\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     column((0..5).map(|i| text!(\"Item {i}\").into())).into()\n/// }\n/// ```\npub fn column<'a, Message, Theme, Renderer>(\n    children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n) -> Column<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    Column::with_children(children)\n}\n\n/// Creates a new [`keyed::Column`] from an iterator of elements.\n///\n/// Keyed columns distribute content vertically while keeping continuity.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{keyed_column, text};\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     keyed_column((0..=100).map(|i| {\n///         (i, text!(\"Item {i}\").into())\n///     })).into()\n/// }\n/// ```\npub fn keyed_column<'a, Key, Message, Theme, Renderer>(\n    children: impl IntoIterator<Item = (Key, Element<'a, Message, Theme, Renderer>)>,\n) -> keyed::Column<'a, Key, Message, Theme, Renderer>\nwhere\n    Key: Copy + PartialEq,\n    Renderer: core::Renderer,\n{\n    keyed::Column::with_children(children)\n}\n\n/// Creates a new [`Row`] from an iterator.\n///\n/// Rows distribute their children horizontally.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{row, text};\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     row((0..5).map(|i| text!(\"Item {i}\").into())).into()\n/// }\n/// ```\npub fn row<'a, Message, Theme, Renderer>(\n    children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n) -> Row<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    Row::with_children(children)\n}\n\n/// Creates a new [`Grid`] from an iterator.\npub fn grid<'a, Message, Theme, Renderer>(\n    children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n) -> Grid<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    Grid::with_children(children)\n}\n\n/// Creates a new [`Stack`] with the given children.\n///\n/// [`Stack`]: crate::Stack\npub fn stack<'a, Message, Theme, Renderer>(\n    children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n) -> Stack<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    Stack::with_children(children)\n}\n\n/// Wraps the given widget and captures any mouse button presses inside the bounds of\n/// the widget—effectively making it _opaque_.\n///\n/// This helper is meant to be used to mark elements in a [`Stack`] to avoid mouse\n/// events from passing through layers.\n///\n/// [`Stack`]: crate::Stack\npub fn opaque<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: core::Renderer + 'a,\n{\n    use crate::core::layout::{self, Layout};\n    use crate::core::mouse;\n    use crate::core::renderer;\n    use crate::core::widget::tree::{self, Tree};\n    use crate::core::{Event, Rectangle, Shell, Size};\n\n    struct Opaque<'a, Message, Theme, Renderer> {\n        content: Element<'a, Message, Theme, Renderer>,\n    }\n\n    impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n        for Opaque<'_, Message, Theme, Renderer>\n    where\n        Renderer: core::Renderer,\n    {\n        fn tag(&self) -> tree::Tag {\n            self.content.as_widget().tag()\n        }\n\n        fn state(&self) -> tree::State {\n            self.content.as_widget().state()\n        }\n\n        fn children(&self) -> Vec<Tree> {\n            self.content.as_widget().children()\n        }\n\n        fn diff(&self, tree: &mut Tree) {\n            self.content.as_widget().diff(tree);\n        }\n\n        fn size(&self) -> Size<Length> {\n            self.content.as_widget().size()\n        }\n\n        fn size_hint(&self) -> Size<Length> {\n            self.content.as_widget().size_hint()\n        }\n\n        fn layout(\n            &mut self,\n            tree: &mut Tree,\n            renderer: &Renderer,\n            limits: &layout::Limits,\n        ) -> layout::Node {\n            self.content.as_widget_mut().layout(tree, renderer, limits)\n        }\n\n        fn draw(\n            &self,\n            tree: &Tree,\n            renderer: &mut Renderer,\n            theme: &Theme,\n            style: &renderer::Style,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            viewport: &Rectangle,\n        ) {\n            self.content\n                .as_widget()\n                .draw(tree, renderer, theme, style, layout, cursor, viewport);\n        }\n\n        fn operate(\n            &mut self,\n            tree: &mut Tree,\n            layout: Layout<'_>,\n            renderer: &Renderer,\n            operation: &mut dyn operation::Operation,\n        ) {\n            self.content\n                .as_widget_mut()\n                .operate(tree, layout, renderer, operation);\n        }\n\n        fn update(\n            &mut self,\n            tree: &mut Tree,\n            event: &Event,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            renderer: &Renderer,\n            shell: &mut Shell<'_, Message>,\n            viewport: &Rectangle,\n        ) {\n            let is_mouse_press =\n                matches!(event, core::Event::Mouse(mouse::Event::ButtonPressed(_)));\n\n            self.content\n                .as_widget_mut()\n                .update(tree, event, layout, cursor, renderer, shell, viewport);\n\n            if is_mouse_press && cursor.is_over(layout.bounds()) {\n                shell.capture_event();\n            }\n        }\n\n        fn mouse_interaction(\n            &self,\n            state: &core::widget::Tree,\n            layout: core::Layout<'_>,\n            cursor: core::mouse::Cursor,\n            viewport: &core::Rectangle,\n            renderer: &Renderer,\n        ) -> core::mouse::Interaction {\n            let interaction = self\n                .content\n                .as_widget()\n                .mouse_interaction(state, layout, cursor, viewport, renderer);\n\n            if interaction == mouse::Interaction::None && cursor.is_over(layout.bounds()) {\n                mouse::Interaction::Idle\n            } else {\n                interaction\n            }\n        }\n\n        fn overlay<'b>(\n            &'b mut self,\n            state: &'b mut core::widget::Tree,\n            layout: core::Layout<'b>,\n            renderer: &Renderer,\n            viewport: &Rectangle,\n            translation: core::Vector,\n        ) -> Option<core::overlay::Element<'b, Message, Theme, Renderer>> {\n            self.content\n                .as_widget_mut()\n                .overlay(state, layout, renderer, viewport, translation)\n        }\n    }\n\n    Element::new(Opaque {\n        content: content.into(),\n    })\n}\n\n/// Displays a widget on top of another one, only when the base widget is hovered.\n///\n/// This works analogously to a [`stack`], but it will only display the layer on top\n/// when the cursor is over the base. It can be useful for removing visual clutter.\n///\n/// [`stack`]: stack()\npub fn hover<'a, Message, Theme, Renderer>(\n    base: impl Into<Element<'a, Message, Theme, Renderer>>,\n    top: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: core::Renderer + 'a,\n{\n    use crate::core::layout::{self, Layout};\n    use crate::core::mouse;\n    use crate::core::renderer;\n    use crate::core::widget::tree::{self, Tree};\n    use crate::core::{Event, Rectangle, Shell, Size};\n\n    struct Hover<'a, Message, Theme, Renderer> {\n        base: Element<'a, Message, Theme, Renderer>,\n        top: Element<'a, Message, Theme, Renderer>,\n        is_top_focused: bool,\n        is_top_overlay_active: bool,\n        is_hovered: bool,\n    }\n\n    impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n        for Hover<'_, Message, Theme, Renderer>\n    where\n        Renderer: core::Renderer,\n    {\n        fn tag(&self) -> tree::Tag {\n            struct Tag;\n            tree::Tag::of::<Tag>()\n        }\n\n        fn children(&self) -> Vec<Tree> {\n            vec![Tree::new(&self.base), Tree::new(&self.top)]\n        }\n\n        fn diff(&self, tree: &mut Tree) {\n            tree.diff_children(&[&self.base, &self.top]);\n        }\n\n        fn size(&self) -> Size<Length> {\n            self.base.as_widget().size()\n        }\n\n        fn size_hint(&self) -> Size<Length> {\n            self.base.as_widget().size_hint()\n        }\n\n        fn layout(\n            &mut self,\n            tree: &mut Tree,\n            renderer: &Renderer,\n            limits: &layout::Limits,\n        ) -> layout::Node {\n            let base = self\n                .base\n                .as_widget_mut()\n                .layout(&mut tree.children[0], renderer, limits);\n\n            let top = self.top.as_widget_mut().layout(\n                &mut tree.children[1],\n                renderer,\n                &layout::Limits::new(Size::ZERO, base.size()),\n            );\n\n            layout::Node::with_children(base.size(), vec![base, top])\n        }\n\n        fn draw(\n            &self,\n            tree: &Tree,\n            renderer: &mut Renderer,\n            theme: &Theme,\n            style: &renderer::Style,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            viewport: &Rectangle,\n        ) {\n            if let Some(bounds) = layout.bounds().intersection(viewport) {\n                let mut children = layout.children().zip(&tree.children);\n\n                let (base_layout, base_tree) = children.next().unwrap();\n\n                self.base.as_widget().draw(\n                    base_tree,\n                    renderer,\n                    theme,\n                    style,\n                    base_layout,\n                    cursor,\n                    viewport,\n                );\n\n                if cursor.is_over(layout.bounds())\n                    || self.is_top_focused\n                    || self.is_top_overlay_active\n                {\n                    let (top_layout, top_tree) = children.next().unwrap();\n\n                    renderer.with_layer(bounds, |renderer| {\n                        self.top.as_widget().draw(\n                            top_tree, renderer, theme, style, top_layout, cursor, viewport,\n                        );\n                    });\n                }\n            }\n        }\n\n        fn operate(\n            &mut self,\n            tree: &mut Tree,\n            layout: Layout<'_>,\n            renderer: &Renderer,\n            operation: &mut dyn operation::Operation,\n        ) {\n            let children = [&mut self.base, &mut self.top]\n                .into_iter()\n                .zip(layout.children().zip(&mut tree.children));\n\n            for (child, (layout, tree)) in children {\n                child\n                    .as_widget_mut()\n                    .operate(tree, layout, renderer, operation);\n            }\n        }\n\n        fn update(\n            &mut self,\n            tree: &mut Tree,\n            event: &Event,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            renderer: &Renderer,\n            shell: &mut Shell<'_, Message>,\n            viewport: &Rectangle,\n        ) {\n            let mut children = layout.children().zip(&mut tree.children);\n            let (base_layout, base_tree) = children.next().unwrap();\n            let (top_layout, top_tree) = children.next().unwrap();\n\n            let is_hovered = cursor.is_over(layout.bounds());\n\n            if matches!(event, Event::Window(window::Event::RedrawRequested(_))) {\n                let mut count_focused = operation::focusable::count();\n\n                self.top.as_widget_mut().operate(\n                    top_tree,\n                    top_layout,\n                    renderer,\n                    &mut operation::black_box(&mut count_focused),\n                );\n\n                self.is_top_focused = match count_focused.finish() {\n                    operation::Outcome::Some(count) => count.focused.is_some(),\n                    _ => false,\n                };\n\n                self.is_hovered = is_hovered;\n            } else if is_hovered != self.is_hovered {\n                shell.request_redraw();\n            }\n\n            let is_visible = is_hovered || self.is_top_focused || self.is_top_overlay_active;\n\n            if matches!(\n                event,\n                Event::Mouse(mouse::Event::CursorMoved { .. } | mouse::Event::ButtonReleased(_))\n            ) || is_visible\n            {\n                let redraw_request = shell.redraw_request();\n\n                self.top.as_widget_mut().update(\n                    top_tree, event, top_layout, cursor, renderer, shell, viewport,\n                );\n\n                // Ignore redraw requests of invisible content\n                if !is_visible {\n                    Shell::replace_redraw_request(shell, redraw_request);\n                }\n\n                if shell.is_event_captured() {\n                    return;\n                }\n            };\n\n            self.base.as_widget_mut().update(\n                base_tree,\n                event,\n                base_layout,\n                cursor,\n                renderer,\n                shell,\n                viewport,\n            );\n        }\n\n        fn mouse_interaction(\n            &self,\n            tree: &Tree,\n            layout: Layout<'_>,\n            cursor: mouse::Cursor,\n            viewport: &Rectangle,\n            renderer: &Renderer,\n        ) -> mouse::Interaction {\n            [&self.base, &self.top]\n                .into_iter()\n                .rev()\n                .zip(layout.children().rev().zip(tree.children.iter().rev()))\n                .map(|(child, (layout, tree))| {\n                    child\n                        .as_widget()\n                        .mouse_interaction(tree, layout, cursor, viewport, renderer)\n                })\n                .find(|&interaction| interaction != mouse::Interaction::None)\n                .unwrap_or_default()\n        }\n\n        fn overlay<'b>(\n            &'b mut self,\n            tree: &'b mut core::widget::Tree,\n            layout: core::Layout<'b>,\n            renderer: &Renderer,\n            viewport: &Rectangle,\n            translation: core::Vector,\n        ) -> Option<core::overlay::Element<'b, Message, Theme, Renderer>> {\n            let mut overlays = [&mut self.base, &mut self.top]\n                .into_iter()\n                .zip(layout.children().zip(tree.children.iter_mut()))\n                .map(|(child, (layout, tree))| {\n                    child\n                        .as_widget_mut()\n                        .overlay(tree, layout, renderer, viewport, translation)\n                });\n\n            if let Some(base_overlay) = overlays.next()? {\n                return Some(base_overlay);\n            }\n\n            let top_overlay = overlays.next()?;\n            self.is_top_overlay_active = top_overlay.is_some();\n\n            top_overlay\n        }\n    }\n\n    Element::new(Hover {\n        base: base.into(),\n        top: top.into(),\n        is_top_focused: false,\n        is_top_overlay_active: false,\n        is_hovered: false,\n    })\n}\n\n/// Creates a new [`Sensor`] widget.\n///\n/// A [`Sensor`] widget can generate messages when its contents are shown,\n/// hidden, or resized.\n///\n/// It can even notify you with anticipation at a given distance!\npub fn sensor<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Sensor<'a, (), Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    Sensor::new(content)\n}\n\n/// Creates a new [`Scrollable`] with the provided content.\n///\n/// Scrollables let users navigate an endless amount of content with a scrollbar.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{column, scrollable, space};\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     scrollable(column![\n///         \"Scroll me!\",\n///         space().height(3000),\n///         \"You did it!\",\n///     ]).into()\n/// }\n/// ```\npub fn scrollable<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Scrollable<'a, Message, Theme, Renderer>\nwhere\n    Theme: scrollable::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    Scrollable::new(content)\n}\n\n/// Creates a new [`Button`] with the provided content.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::button;\n///\n/// #[derive(Clone)]\n/// enum Message {\n///     ButtonPressed,\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     button(\"Press me!\").on_press(Message::ButtonPressed).into()\n/// }\n/// ```\npub fn button<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Button<'a, Message, Theme, Renderer>\nwhere\n    Theme: button::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    Button::new(content)\n}\n\n/// Creates a new [`Tooltip`] for the provided content with the given\n/// [`Element`] and [`tooltip::Position`].\n///\n/// Tooltips display a hint of information over some element when hovered.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{container, tooltip};\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(_state: &State) -> Element<'_, Message> {\n///     tooltip(\n///         \"Hover me to display the tooltip!\",\n///         container(\"This is the tooltip contents!\")\n///             .padding(10)\n///             .style(container::rounded_box),\n///         tooltip::Position::Bottom,\n///     ).into()\n/// }\n/// ```\npub fn tooltip<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n    tooltip: impl Into<Element<'a, Message, Theme, Renderer>>,\n    position: tooltip::Position,\n) -> crate::Tooltip<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    Tooltip::new(content, tooltip, position)\n}\n\n/// Creates a new [`Text`] widget with the provided content.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>;\n/// use iced::widget::text;\n/// use iced::color;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     text(\"Hello, this is iced!\")\n///         .size(20)\n///         .color(color!(0x0000ff))\n///         .into()\n/// }\n/// ```\npub fn text<'a, Theme, Renderer>(text: impl text::IntoFragment<'a>) -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    Text::new(text)\n}\n\n/// Creates a new [`Text`] widget that displays the provided value.\npub fn value<'a, Theme, Renderer>(value: impl ToString) -> Text<'a, Theme, Renderer>\nwhere\n    Theme: text::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    Text::new(value.to_string())\n}\n\n/// Creates a new [`Rich`] text widget with the provided spans.\n///\n/// [`Rich`]: text::Rich\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::font;\n/// use iced::widget::{rich_text, span};\n/// use iced::{color, never, Font};\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     LinkClicked(&'static str),\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     rich_text([\n///         span(\"I am red!\").color(color!(0xff0000)),\n///         span(\" \"),\n///         span(\"And I am bold!\").font(Font { weight: font::Weight::Bold, ..Font::default() }),\n///     ])\n///     .on_link_click(never)\n///     .size(20)\n///     .into()\n/// }\n/// ```\npub fn rich_text<'a, Link, Message, Theme, Renderer>(\n    spans: impl AsRef<[text::Span<'a, Link, Renderer::Font>]> + 'a,\n) -> text::Rich<'a, Link, Message, Theme, Renderer>\nwhere\n    Link: Clone + 'static,\n    Theme: text::Catalog + 'a,\n    Renderer: core::text::Renderer,\n    Renderer::Font: 'a,\n{\n    text::Rich::with_spans(spans)\n}\n\n/// Creates a new [`Span`] of text with the provided content.\n///\n/// A [`Span`] is a fragment of some [`Rich`] text.\n///\n/// [`Span`]: text::Span\n/// [`Rich`]: text::Rich\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::font;\n/// use iced::widget::{rich_text, span};\n/// use iced::{color, never, Font};\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     rich_text![\n///         span(\"I am red!\").color(color!(0xff0000)),\n///         \" \",\n///         span(\"And I am bold!\").font(Font { weight: font::Weight::Bold, ..Font::default() }),\n///     ]\n///     .on_link_click(never)\n///     .size(20)\n///     .into()\n/// }\n/// ```\npub fn span<'a, Link, Font>(text: impl text::IntoFragment<'a>) -> text::Span<'a, Link, Font> {\n    text::Span::new(text)\n}\n\n#[cfg(feature = \"markdown\")]\n#[doc(inline)]\npub use crate::markdown::view as markdown;\n\n/// Creates a new [`Checkbox`].\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::checkbox;\n///\n/// struct State {\n///    is_checked: bool,\n/// }\n///\n/// enum Message {\n///     CheckboxToggled(bool),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     checkbox(state.is_checked)\n///         .label(\"Toggle me!\")\n///         .on_toggle(Message::CheckboxToggled)\n///         .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::CheckboxToggled(is_checked) => {\n///             state.is_checked = is_checked;\n///         }\n///     }\n/// }\n/// ```\n/// ![Checkbox drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true)\npub fn checkbox<'a, Message, Theme, Renderer>(\n    is_checked: bool,\n) -> Checkbox<'a, Message, Theme, Renderer>\nwhere\n    Theme: checkbox::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    Checkbox::new(is_checked)\n}\n\n/// Creates a new [`Radio`].\n///\n/// Radio buttons let users choose a single option from a bunch of options.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::{column, radio};\n///\n/// struct State {\n///    selection: Option<Choice>,\n/// }\n///\n/// #[derive(Debug, Clone, Copy)]\n/// enum Message {\n///     RadioSelected(Choice),\n/// }\n///\n/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n/// enum Choice {\n///     A,\n///     B,\n///     C,\n///     All,\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     let a = radio(\n///         \"A\",\n///         Choice::A,\n///         state.selection,\n///         Message::RadioSelected,\n///     );\n///\n///     let b = radio(\n///         \"B\",\n///         Choice::B,\n///         state.selection,\n///         Message::RadioSelected,\n///     );\n///\n///     let c = radio(\n///         \"C\",\n///         Choice::C,\n///         state.selection,\n///         Message::RadioSelected,\n///     );\n///\n///     let all = radio(\n///         \"All of the above\",\n///         Choice::All,\n///         state.selection,\n///         Message::RadioSelected\n///     );\n///\n///     column![a, b, c, all].into()\n/// }\n/// ```\npub fn radio<'a, Message, Theme, Renderer, V>(\n    label: impl Into<String>,\n    value: V,\n    selected: Option<V>,\n    on_click: impl FnOnce(V) -> Message,\n) -> Radio<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone,\n    Theme: radio::Catalog + 'a,\n    Renderer: core::text::Renderer,\n    V: Copy + Eq,\n{\n    Radio::new(label, value, selected, on_click)\n}\n\n/// Creates a new [`Toggler`].\n///\n/// Togglers let users make binary choices by toggling a switch.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::toggler;\n///\n/// struct State {\n///    is_checked: bool,\n/// }\n///\n/// enum Message {\n///     TogglerToggled(bool),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     toggler(state.is_checked)\n///         .label(\"Toggle me!\")\n///         .on_toggle(Message::TogglerToggled)\n///         .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::TogglerToggled(is_checked) => {\n///             state.is_checked = is_checked;\n///         }\n///     }\n/// }\n/// ```\npub fn toggler<'a, Message, Theme, Renderer>(\n    is_checked: bool,\n) -> Toggler<'a, Message, Theme, Renderer>\nwhere\n    Theme: toggler::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    Toggler::new(is_checked)\n}\n\n/// Creates a new [`TextInput`].\n///\n/// Text inputs display fields that can be filled with text.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::text_input;\n///\n/// struct State {\n///    content: String,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     ContentChanged(String)\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     text_input(\"Type something here...\", &state.content)\n///         .on_input(Message::ContentChanged)\n///         .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::ContentChanged(content) => {\n///             state.content = content;\n///         }\n///     }\n/// }\n/// ```\npub fn text_input<'a, Message, Theme, Renderer>(\n    placeholder: &str,\n    value: &str,\n) -> TextInput<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone,\n    Theme: text_input::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    TextInput::new(placeholder, value)\n}\n\n/// Creates a new [`TextEditor`].\n///\n/// Text editors display a multi-line text input for text editing.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::text_editor;\n///\n/// struct State {\n///    content: text_editor::Content,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     Edit(text_editor::Action)\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     text_editor(&state.content)\n///         .placeholder(\"Type something here...\")\n///         .on_action(Message::Edit)\n///         .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::Edit(action) => {\n///             state.content.perform(action);\n///         }\n///     }\n/// }\n/// ```\npub fn text_editor<'a, Message, Theme, Renderer>(\n    content: &'a text_editor::Content<Renderer>,\n) -> TextEditor<'a, core::text::highlighter::PlainText, Message, Theme, Renderer>\nwhere\n    Message: Clone,\n    Theme: text_editor::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    TextEditor::new(content)\n}\n\n/// Creates a new [`Slider`].\n///\n/// Sliders let users set a value by moving an indicator.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::slider;\n///\n/// struct State {\n///    value: f32,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     ValueChanged(f32),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     slider(0.0..=100.0, state.value, Message::ValueChanged).into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::ValueChanged(value) => {\n///             state.value = value;\n///         }\n///     }\n/// }\n/// ```\npub fn slider<'a, T, Message, Theme>(\n    range: std::ops::RangeInclusive<T>,\n    value: T,\n    on_change: impl Fn(T) -> Message + 'a,\n) -> Slider<'a, T, Message, Theme>\nwhere\n    T: Copy + From<u8> + std::cmp::PartialOrd,\n    Message: Clone,\n    Theme: slider::Catalog + 'a,\n{\n    Slider::new(range, value, on_change)\n}\n\n/// Creates a new [`VerticalSlider`].\n///\n/// Sliders let users set a value by moving an indicator.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::vertical_slider;\n///\n/// struct State {\n///    value: f32,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     ValueChanged(f32),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     vertical_slider(0.0..=100.0, state.value, Message::ValueChanged).into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::ValueChanged(value) => {\n///             state.value = value;\n///         }\n///     }\n/// }\n/// ```\npub fn vertical_slider<'a, T, Message, Theme>(\n    range: std::ops::RangeInclusive<T>,\n    value: T,\n    on_change: impl Fn(T) -> Message + 'a,\n) -> VerticalSlider<'a, T, Message, Theme>\nwhere\n    T: Copy + From<u8> + std::cmp::PartialOrd,\n    Message: Clone,\n    Theme: vertical_slider::Catalog + 'a,\n{\n    VerticalSlider::new(range, value, on_change)\n}\n\n/// Creates a new [`PickList`].\n///\n/// Pick lists display a dropdown list of selectable options.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::pick_list;\n///\n/// struct State {\n///    favorite: Option<Fruit>,\n/// }\n///\n/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n/// enum Fruit {\n///     Apple,\n///     Orange,\n///     Strawberry,\n///     Tomato,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     FruitSelected(Fruit),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     let fruits = [\n///         Fruit::Apple,\n///         Fruit::Orange,\n///         Fruit::Strawberry,\n///         Fruit::Tomato,\n///     ];\n///\n///     pick_list(\n///         state.favorite,\n///         fruits,\n///         Fruit::to_string,\n///     )\n///     .on_select(Message::FruitSelected)\n///     .placeholder(\"Select your favorite fruit...\")\n///     .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::FruitSelected(fruit) => {\n///             state.favorite = Some(fruit);\n///         }\n///     }\n/// }\n///\n/// impl std::fmt::Display for Fruit {\n///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n///         f.write_str(match self {\n///             Self::Apple => \"Apple\",\n///             Self::Orange => \"Orange\",\n///             Self::Strawberry => \"Strawberry\",\n///             Self::Tomato => \"Tomato\",\n///         })\n///     }\n/// }\n/// ```\npub fn pick_list<'a, T, L, V, Message, Theme, Renderer>(\n    selected: Option<V>,\n    options: L,\n    to_string: impl Fn(&T) -> String + 'a,\n) -> PickList<'a, T, L, V, Message, Theme, Renderer>\nwhere\n    T: PartialEq + Clone + 'a,\n    L: Borrow<[T]> + 'a,\n    V: Borrow<T> + 'a,\n    Message: Clone,\n    Theme: pick_list::Catalog + overlay::menu::Catalog,\n    Renderer: core::text::Renderer,\n{\n    PickList::new(selected, options, to_string)\n}\n\n/// Creates a new [`ComboBox`].\n///\n/// Combo boxes display a dropdown list of searchable and selectable options.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::combo_box;\n///\n/// struct State {\n///    fruits: combo_box::State<Fruit>,\n///    favorite: Option<Fruit>,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Fruit {\n///     Apple,\n///     Orange,\n///     Strawberry,\n///     Tomato,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     FruitSelected(Fruit),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     combo_box(\n///         &state.fruits,\n///         \"Select your favorite fruit...\",\n///         state.favorite.as_ref(),\n///         Message::FruitSelected\n///     )\n///     .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::FruitSelected(fruit) => {\n///             state.favorite = Some(fruit);\n///         }\n///     }\n/// }\n///\n/// impl std::fmt::Display for Fruit {\n///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n///         f.write_str(match self {\n///             Self::Apple => \"Apple\",\n///             Self::Orange => \"Orange\",\n///             Self::Strawberry => \"Strawberry\",\n///             Self::Tomato => \"Tomato\",\n///         })\n///     }\n/// }\n/// ```\npub fn combo_box<'a, T, Message, Theme, Renderer>(\n    state: &'a combo_box::State<T>,\n    placeholder: &str,\n    selection: Option<&T>,\n    on_selected: impl Fn(T) -> Message + 'a,\n) -> ComboBox<'a, T, Message, Theme, Renderer>\nwhere\n    T: std::fmt::Display + Clone,\n    Theme: combo_box::Catalog + 'a,\n    Renderer: core::text::Renderer,\n{\n    ComboBox::new(state, placeholder, selection, on_selected)\n}\n\n/// Creates some empty [`Space`] with no size.\n///\n/// This is considered the \"identity\" widget. It will take\n/// no space and do nothing.\npub fn space() -> Space {\n    Space::new()\n}\n\n/// Creates a new [`ProgressBar`].\n///\n/// Progress bars visualize the progression of an extended computer operation, such as a download, file transfer, or installation.\n///\n/// It expects:\n///   * an inclusive range of possible values, and\n///   * the current value of the [`ProgressBar`].\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::progress_bar;\n///\n/// struct State {\n///    progress: f32,\n/// }\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     progress_bar(0.0..=100.0, state.progress).into()\n/// }\n/// ```\npub fn progress_bar<'a, Theme>(range: RangeInclusive<f32>, value: f32) -> ProgressBar<'a, Theme>\nwhere\n    Theme: progress_bar::Catalog + 'a,\n{\n    ProgressBar::new(range, value)\n}\n\n/// Creates a new [`Image`].\n///\n/// Images display raster graphics in different formats (PNG, JPG, etc.).\n///\n/// [`Image`]: crate::Image\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::image;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     image(\"ferris.png\").into()\n/// }\n/// ```\n/// <img src=\"https://github.com/iced-rs/iced/blob/9712b319bb7a32848001b96bd84977430f14b623/examples/resources/ferris.png?raw=true\" width=\"300\">\n#[cfg(feature = \"image\")]\npub fn image<Handle>(handle: impl Into<Handle>) -> crate::Image<Handle> {\n    crate::Image::new(handle.into())\n}\n\n/// Creates a new [`Svg`] widget from the given [`Handle`].\n///\n/// Svg widgets display vector graphics in your application.\n///\n/// [`Svg`]: crate::Svg\n/// [`Handle`]: crate::svg::Handle\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::svg;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     svg(\"tiger.svg\").into()\n/// }\n/// ```\n#[cfg(feature = \"svg\")]\npub fn svg<'a, Theme>(handle: impl Into<core::svg::Handle>) -> crate::Svg<'a, Theme>\nwhere\n    Theme: crate::svg::Catalog,\n{\n    crate::Svg::new(handle)\n}\n\n/// Creates an [`Element`] that displays the iced logo with the given `text_size`.\n///\n/// Useful for showing some love to your favorite GUI library in your \"About\" screen,\n/// for instance.\npub fn iced<'a, Message, Theme, Renderer>(\n    text_size: impl Into<core::Pixels>,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Renderer: core::Renderer + core::text::Renderer<Font = core::Font> + 'a,\n    Theme: text::Catalog + container::Catalog + 'a,\n    <Theme as container::Catalog>::Class<'a>: From<container::StyleFn<'a, Theme>>,\n    <Theme as text::Catalog>::Class<'a>: From<text::StyleFn<'a, Theme>>,\n{\n    use crate::core::border;\n    use crate::core::color;\n    use crate::core::gradient;\n    use crate::core::{Alignment, Color, Font, Radians};\n\n    let text_size = text_size.into();\n\n    row![\n        container(\n            text(Renderer::ICED_LOGO)\n                .line_height(1.0)\n                .size(text_size)\n                .font(Renderer::ICON_FONT)\n                .color(Color::WHITE)\n        )\n        .padding(text_size * 0.15)\n        .style(move |_| container::Style {\n            background: Some(\n                gradient::Linear::new(Radians::PI / 4.0)\n                    .add_stop(0.0, color!(0x0033ff))\n                    .add_stop(1.0, color!(0x1177ff))\n                    .into()\n            ),\n            border: border::rounded(border::radius(text_size * 0.4)),\n            ..container::Style::default()\n        }),\n        text(\"iced\").size(text_size).font(Font::MONOSPACE)\n    ]\n    .spacing(text_size.0 / 3.0)\n    .align_y(Alignment::Center)\n    .into()\n}\n\n/// Creates a new [`Canvas`].\n///\n/// Canvases can be leveraged to draw interactive 2D graphics.\n///\n/// [`Canvas`]: crate::Canvas\n///\n/// # Example: Drawing a Simple Circle\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::mouse;\n/// use iced::widget::canvas;\n/// use iced::{Color, Rectangle, Renderer, Theme};\n///\n/// // First, we define the data we need for drawing\n/// #[derive(Debug)]\n/// struct Circle {\n///     radius: f32,\n/// }\n///\n/// // Then, we implement the `Program` trait\n/// impl<Message> canvas::Program<Message> for Circle {\n///     // No internal state\n///     type State = ();\n///\n///     fn draw(\n///         &self,\n///         _state: &(),\n///         renderer: &Renderer,\n///         _theme: &Theme,\n///         bounds: Rectangle,\n///         _cursor: mouse::Cursor\n///     ) -> Vec<canvas::Geometry> {\n///         // We prepare a new `Frame`\n///         let mut frame = canvas::Frame::new(renderer, bounds.size());\n///\n///         // We create a `Path` representing a simple circle\n///         let circle = canvas::Path::circle(frame.center(), self.radius);\n///\n///         // And fill it with some color\n///         frame.fill(&circle, Color::BLACK);\n///\n///         // Then, we produce the geometry\n///         vec![frame.into_geometry()]\n///     }\n/// }\n///\n/// // Finally, we simply use our `Circle` to create the `Canvas`!\n/// fn view<'a, Message: 'a>(_state: &'a State) -> Element<'a, Message> {\n///     canvas(Circle { radius: 50.0 }).into()\n/// }\n/// ```\n#[cfg(feature = \"canvas\")]\npub fn canvas<P, Message, Theme, Renderer>(program: P) -> crate::Canvas<P, Message, Theme, Renderer>\nwhere\n    Renderer: crate::graphics::geometry::Renderer,\n    P: crate::canvas::Program<Message, Theme, Renderer>,\n{\n    crate::Canvas::new(program)\n}\n\n/// Creates a new [`QRCode`] widget from the given [`Data`].\n///\n/// QR codes display information in a type of two-dimensional matrix barcode.\n///\n/// [`QRCode`]: crate::QRCode\n/// [`Data`]: crate::qr_code::Data\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::qr_code;\n///\n/// struct State {\n///    data: qr_code::Data,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     qr_code(&state.data).into()\n/// }\n/// ```\n#[cfg(feature = \"qr_code\")]\npub fn qr_code<'a, Theme>(data: &'a crate::qr_code::Data) -> crate::QRCode<'a, Theme>\nwhere\n    Theme: crate::qr_code::Catalog + 'a,\n{\n    crate::QRCode::new(data)\n}\n\n/// Creates a new [`Shader`].\n///\n/// [`Shader`]: crate::Shader\n#[cfg(feature = \"wgpu\")]\npub fn shader<Message, P>(program: P) -> crate::Shader<Message, P>\nwhere\n    P: crate::shader::Program<Message>,\n{\n    crate::Shader::new(program)\n}\n\n/// Creates a new [`MouseArea`].\npub fn mouse_area<'a, Message, Theme, Renderer>(\n    widget: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> MouseArea<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    MouseArea::new(widget)\n}\n\n/// A widget that applies any `Theme` to its contents.\npub fn themer<'a, Message, Theme, Renderer>(\n    theme: Option<Theme>,\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Themer<'a, Message, Theme, Renderer>\nwhere\n    Theme: theme::Base,\n    Renderer: core::Renderer,\n{\n    Themer::new(theme, content)\n}\n\n/// Creates a [`PaneGrid`] with the given [`pane_grid::State`] and view function.\n///\n/// Pane grids let your users split regions of your application and organize layout dynamically.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::{pane_grid, text};\n///\n/// struct State {\n///     panes: pane_grid::State<Pane>,\n/// }\n///\n/// enum Pane {\n///     SomePane,\n///     AnotherKindOfPane,\n/// }\n///\n/// enum Message {\n///     PaneDragged(pane_grid::DragEvent),\n///     PaneResized(pane_grid::ResizeEvent),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     pane_grid(&state.panes, |pane, state, is_maximized| {\n///         pane_grid::Content::new(match state {\n///             Pane::SomePane => text(\"This is some pane\"),\n///             Pane::AnotherKindOfPane => text(\"This is another kind of pane\"),\n///         })\n///     })\n///     .on_drag(Message::PaneDragged)\n///     .on_resize(10, Message::PaneResized)\n///     .into()\n/// }\n/// ```\npub fn pane_grid<'a, T, Message, Theme, Renderer>(\n    state: &'a pane_grid::State<T>,\n    view: impl Fn(pane_grid::Pane, &'a T, bool) -> pane_grid::Content<'a, Message, Theme, Renderer>,\n) -> PaneGrid<'a, Message, Theme, Renderer>\nwhere\n    Theme: pane_grid::Catalog,\n    Renderer: core::Renderer,\n{\n    PaneGrid::new(state, view)\n}\n\n/// Creates a new [`Float`] widget with the given content.\npub fn float<'a, Message, Theme, Renderer>(\n    content: impl Into<Element<'a, Message, Theme, Renderer>>,\n) -> Float<'a, Message, Theme, Renderer>\nwhere\n    Theme: float::Catalog,\n    Renderer: core::Renderer,\n{\n    Float::new(content)\n}\n\n/// Creates a new [`Responsive`] widget with a closure that produces its\n/// contents.\n///\n/// The `view` closure will receive the maximum available space for\n/// the [`Responsive`] during layout. You can use this [`Size`] to\n/// conditionally build the contents.\npub fn responsive<'a, Message, Theme, Renderer>(\n    f: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a,\n) -> Responsive<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    Responsive::new(f)\n}\n"
  },
  {
    "path": "widget/src/image/viewer.rs",
    "content": "//! Zoom and pan on an image.\nuse crate::core::border;\nuse crate::core::image::{self, FilterMethod};\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::{\n    ContentFit, Element, Event, Image, Layout, Length, Pixels, Point, Radians, Rectangle, Shell,\n    Size, Vector, Widget,\n};\n\n/// A frame that displays an image with the ability to zoom in/out and pan.\npub struct Viewer<Handle> {\n    padding: f32,\n    width: Length,\n    height: Length,\n    min_scale: f32,\n    max_scale: f32,\n    scale_step: f32,\n    handle: Handle,\n    filter_method: FilterMethod,\n    content_fit: ContentFit,\n}\n\nimpl<Handle> Viewer<Handle> {\n    /// Creates a new [`Viewer`] with the given [`State`].\n    pub fn new<T: Into<Handle>>(handle: T) -> Self {\n        Viewer {\n            handle: handle.into(),\n            padding: 0.0,\n            width: Length::Shrink,\n            height: Length::Shrink,\n            min_scale: 0.25,\n            max_scale: 10.0,\n            scale_step: 0.10,\n            filter_method: FilterMethod::default(),\n            content_fit: ContentFit::default(),\n        }\n    }\n\n    /// Sets the [`FilterMethod`] of the [`Viewer`].\n    pub fn filter_method(mut self, filter_method: image::FilterMethod) -> Self {\n        self.filter_method = filter_method;\n        self\n    }\n\n    /// Sets the [`ContentFit`] of the [`Viewer`].\n    pub fn content_fit(mut self, content_fit: ContentFit) -> Self {\n        self.content_fit = content_fit;\n        self\n    }\n\n    /// Sets the padding of the [`Viewer`].\n    pub fn padding(mut self, padding: impl Into<Pixels>) -> Self {\n        self.padding = padding.into().0;\n        self\n    }\n\n    /// Sets the width of the [`Viewer`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Viewer`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the max scale applied to the image of the [`Viewer`].\n    ///\n    /// Default is `10.0`\n    pub fn max_scale(mut self, max_scale: f32) -> Self {\n        self.max_scale = max_scale;\n        self\n    }\n\n    /// Sets the min scale applied to the image of the [`Viewer`].\n    ///\n    /// Default is `0.25`\n    pub fn min_scale(mut self, min_scale: f32) -> Self {\n        self.min_scale = min_scale;\n        self\n    }\n\n    /// Sets the percentage the image of the [`Viewer`] will be scaled by\n    /// when zoomed in / out.\n    ///\n    /// Default is `0.10`\n    pub fn scale_step(mut self, scale_step: f32) -> Self {\n        self.scale_step = scale_step;\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer, Handle> Widget<Message, Theme, Renderer> for Viewer<Handle>\nwhere\n    Renderer: image::Renderer<Handle = Handle>,\n    Handle: Clone,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::new())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        // The raw w/h of the underlying image\n        let image_size = renderer.measure_image(&self.handle).unwrap_or_default();\n\n        let image_size = Size::new(image_size.width as f32, image_size.height as f32);\n\n        // The size to be available to the widget prior to `Shrink`ing\n        let raw_size = limits.resolve(self.width, self.height, image_size);\n\n        // The uncropped size of the image when fit to the bounds above\n        let full_size = self.content_fit.fit(image_size, raw_size);\n\n        // Shrink the widget to fit the resized image, if requested\n        let final_size = Size {\n            width: match self.width {\n                Length::Shrink => f32::min(raw_size.width, full_size.width),\n                _ => raw_size.width,\n            },\n            height: match self.height {\n                Length::Shrink => f32::min(raw_size.height, full_size.height),\n                _ => raw_size.height,\n            },\n        };\n\n        layout::Node::new(final_size)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        match event {\n            Event::Mouse(mouse::Event::WheelScrolled { delta }) => {\n                let Some(cursor_position) = cursor.position_over(bounds) else {\n                    return;\n                };\n\n                match *delta {\n                    mouse::ScrollDelta::Lines { y, .. } | mouse::ScrollDelta::Pixels { y, .. } => {\n                        let state = tree.state.downcast_mut::<State>();\n                        let previous_scale = state.scale;\n\n                        if y < 0.0 && previous_scale > self.min_scale\n                            || y > 0.0 && previous_scale < self.max_scale\n                        {\n                            state.scale = (if y > 0.0 {\n                                state.scale * (1.0 + self.scale_step)\n                            } else {\n                                state.scale / (1.0 + self.scale_step)\n                            })\n                            .clamp(self.min_scale, self.max_scale);\n\n                            let scaled_size = scaled_image_size(\n                                renderer,\n                                &self.handle,\n                                state,\n                                bounds.size(),\n                                self.content_fit,\n                            );\n\n                            let factor = state.scale / previous_scale - 1.0;\n\n                            let cursor_to_center = cursor_position - bounds.center();\n\n                            let adjustment =\n                                cursor_to_center * factor + state.current_offset * factor;\n\n                            state.current_offset = Vector::new(\n                                if scaled_size.width > bounds.width {\n                                    state.current_offset.x + adjustment.x\n                                } else {\n                                    0.0\n                                },\n                                if scaled_size.height > bounds.height {\n                                    state.current_offset.y + adjustment.y\n                                } else {\n                                    0.0\n                                },\n                            );\n                        }\n                    }\n                }\n\n                shell.request_redraw();\n                shell.capture_event();\n            }\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {\n                let Some(cursor_position) = cursor.position_over(bounds) else {\n                    return;\n                };\n\n                let state = tree.state.downcast_mut::<State>();\n\n                state.cursor_grabbed_at = Some(cursor_position);\n                state.starting_offset = state.current_offset;\n\n                shell.capture_event();\n            }\n            Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {\n                let state = tree.state.downcast_mut::<State>();\n\n                state.cursor_grabbed_at = None;\n            }\n            Event::Mouse(mouse::Event::CursorMoved { position }) => {\n                let state = tree.state.downcast_mut::<State>();\n\n                if let Some(origin) = state.cursor_grabbed_at {\n                    let scaled_size = scaled_image_size(\n                        renderer,\n                        &self.handle,\n                        state,\n                        bounds.size(),\n                        self.content_fit,\n                    );\n                    let hidden_width = (scaled_size.width - bounds.width / 2.0).max(0.0).round();\n\n                    let hidden_height = (scaled_size.height - bounds.height / 2.0).max(0.0).round();\n\n                    let delta = *position - origin;\n\n                    let x = if bounds.width < scaled_size.width {\n                        (state.starting_offset.x - delta.x).clamp(-hidden_width, hidden_width)\n                    } else {\n                        0.0\n                    };\n\n                    let y = if bounds.height < scaled_size.height {\n                        (state.starting_offset.y - delta.y).clamp(-hidden_height, hidden_height)\n                    } else {\n                        0.0\n                    };\n\n                    state.current_offset = Vector::new(x, y);\n                    shell.request_redraw();\n                    shell.capture_event();\n                }\n            }\n            _ => {}\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let state = tree.state.downcast_ref::<State>();\n        let bounds = layout.bounds();\n        let is_mouse_over = cursor.is_over(bounds);\n\n        if state.is_cursor_grabbed() {\n            mouse::Interaction::Grabbing\n        } else if is_mouse_over {\n            mouse::Interaction::Grab\n        } else {\n            mouse::Interaction::None\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        _theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_ref::<State>();\n        let bounds = layout.bounds();\n\n        let final_size = scaled_image_size(\n            renderer,\n            &self.handle,\n            state,\n            bounds.size(),\n            self.content_fit,\n        );\n\n        let translation = {\n            let diff_w = bounds.width - final_size.width;\n            let diff_h = bounds.height - final_size.height;\n\n            let image_top_left = match self.content_fit {\n                ContentFit::None => Vector::new(diff_w.max(0.0) / 2.0, diff_h.max(0.0) / 2.0),\n                _ => Vector::new(diff_w / 2.0, diff_h / 2.0),\n            };\n\n            image_top_left - state.offset(bounds, final_size)\n        };\n\n        let drawing_bounds = Rectangle::new(bounds.position(), final_size);\n\n        let render = |renderer: &mut Renderer| {\n            renderer.with_translation(translation, |renderer| {\n                renderer.draw_image(\n                    Image {\n                        handle: self.handle.clone(),\n                        border_radius: border::Radius::default(),\n                        filter_method: self.filter_method,\n                        rotation: Radians(0.0),\n                        opacity: 1.0,\n                    },\n                    drawing_bounds,\n                    *viewport - translation,\n                );\n            });\n        };\n\n        renderer.with_layer(bounds, render);\n    }\n}\n\n/// The local state of a [`Viewer`].\n#[derive(Debug, Clone, Copy)]\npub struct State {\n    scale: f32,\n    starting_offset: Vector,\n    current_offset: Vector,\n    cursor_grabbed_at: Option<Point>,\n}\n\nimpl Default for State {\n    fn default() -> Self {\n        Self {\n            scale: 1.0,\n            starting_offset: Vector::default(),\n            current_offset: Vector::default(),\n            cursor_grabbed_at: None,\n        }\n    }\n}\n\nimpl State {\n    /// Creates a new [`State`].\n    pub fn new() -> Self {\n        State::default()\n    }\n\n    /// Returns the current offset of the [`State`], given the bounds\n    /// of the [`Viewer`] and its image.\n    fn offset(&self, bounds: Rectangle, image_size: Size) -> Vector {\n        let hidden_width = (image_size.width - bounds.width / 2.0).max(0.0).round();\n\n        let hidden_height = (image_size.height - bounds.height / 2.0).max(0.0).round();\n\n        Vector::new(\n            self.current_offset.x.clamp(-hidden_width, hidden_width),\n            self.current_offset.y.clamp(-hidden_height, hidden_height),\n        )\n    }\n\n    /// Returns if the cursor is currently grabbed by the [`Viewer`].\n    pub fn is_cursor_grabbed(&self) -> bool {\n        self.cursor_grabbed_at.is_some()\n    }\n}\n\nimpl<'a, Message, Theme, Renderer, Handle> From<Viewer<Handle>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Renderer: 'a + image::Renderer<Handle = Handle>,\n    Message: 'a,\n    Handle: Clone + 'a,\n{\n    fn from(viewer: Viewer<Handle>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(viewer)\n    }\n}\n\n/// Returns the bounds of the underlying image, given the bounds of\n/// the [`Viewer`]. Scaling will be applied and original aspect ratio\n/// will be respected.\npub fn scaled_image_size<Renderer>(\n    renderer: &Renderer,\n    handle: &<Renderer as image::Renderer>::Handle,\n    state: &State,\n    bounds: Size,\n    content_fit: ContentFit,\n) -> Size\nwhere\n    Renderer: image::Renderer,\n{\n    let Size { width, height } = renderer.measure_image(handle).unwrap_or_default();\n\n    let image_size = Size::new(width as f32, height as f32);\n\n    let adjusted_fit = content_fit.fit(image_size, bounds);\n\n    Size::new(\n        adjusted_fit.width * state.scale,\n        adjusted_fit.height * state.scale,\n    )\n}\n"
  },
  {
    "path": "widget/src/image.rs",
    "content": "//! Images display raster graphics in different formats (PNG, JPG, etc.).\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! use iced::widget::image;\n//!\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     image(\"ferris.png\").into()\n//! }\n//! ```\n//! <img src=\"https://github.com/iced-rs/iced/blob/9712b319bb7a32848001b96bd84977430f14b623/examples/resources/ferris.png?raw=true\" width=\"300\">\npub mod viewer;\npub use viewer::Viewer;\n\nuse crate::core::border;\nuse crate::core::image;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::widget::Tree;\nuse crate::core::{\n    ContentFit, Element, Layout, Length, Point, Rectangle, Rotation, Size, Vector, Widget,\n};\n\npub use image::{FilterMethod, Handle};\n\n/// Creates a new [`Viewer`] with the given image `Handle`.\npub fn viewer<Handle>(handle: Handle) -> Viewer<Handle> {\n    Viewer::new(handle)\n}\n\n/// A frame that displays an image while keeping aspect ratio.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::image;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     image(\"ferris.png\").into()\n/// }\n/// ```\n/// <img src=\"https://github.com/iced-rs/iced/blob/9712b319bb7a32848001b96bd84977430f14b623/examples/resources/ferris.png?raw=true\" width=\"300\">\npub struct Image<Handle = image::Handle> {\n    handle: Handle,\n    width: Length,\n    height: Length,\n    crop: Option<Rectangle<u32>>,\n    border_radius: border::Radius,\n    content_fit: ContentFit,\n    filter_method: FilterMethod,\n    rotation: Rotation,\n    opacity: f32,\n    scale: f32,\n    expand: bool,\n}\n\nimpl<Handle> Image<Handle> {\n    /// Creates a new [`Image`] with the given path.\n    pub fn new(handle: impl Into<Handle>) -> Self {\n        Image {\n            handle: handle.into(),\n            width: Length::Shrink,\n            height: Length::Shrink,\n            crop: None,\n            border_radius: border::Radius::default(),\n            content_fit: ContentFit::default(),\n            filter_method: FilterMethod::default(),\n            rotation: Rotation::default(),\n            opacity: 1.0,\n            scale: 1.0,\n            expand: false,\n        }\n    }\n\n    /// Sets the width of the [`Image`] boundaries.\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Image`] boundaries.\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets whether the [`Image`] should try to fill as much space\n    /// available as possible while keeping aspect ratio and without\n    /// allocating extra space in any axis with a [`Length::Shrink`]\n    /// sizing strategy.\n    ///\n    /// This is similar to using [`Length::Fill`] for both the\n    /// [`width`](Self::width) and the [`height`](Self::height),\n    /// but without the downside of blank space.\n    pub fn expand(mut self, expand: bool) -> Self {\n        self.expand = expand;\n        self\n    }\n\n    /// Sets the [`ContentFit`] of the [`Image`].\n    ///\n    /// Defaults to [`ContentFit::Contain`]\n    pub fn content_fit(mut self, content_fit: ContentFit) -> Self {\n        self.content_fit = content_fit;\n        self\n    }\n\n    /// Sets the [`FilterMethod`] of the [`Image`].\n    pub fn filter_method(mut self, filter_method: FilterMethod) -> Self {\n        self.filter_method = filter_method;\n        self\n    }\n\n    /// Applies the given [`Rotation`] to the [`Image`].\n    pub fn rotation(mut self, rotation: impl Into<Rotation>) -> Self {\n        self.rotation = rotation.into();\n        self\n    }\n\n    /// Sets the opacity of the [`Image`].\n    ///\n    /// It should be in the [0.0, 1.0] range—`0.0` meaning completely transparent,\n    /// and `1.0` meaning completely opaque.\n    pub fn opacity(mut self, opacity: impl Into<f32>) -> Self {\n        self.opacity = opacity.into();\n        self\n    }\n\n    /// Sets the scale of the [`Image`].\n    ///\n    /// The region of the [`Image`] drawn will be scaled from the center by the given scale factor.\n    /// This can be useful to create certain effects and animations, like smooth zoom in / out.\n    pub fn scale(mut self, scale: impl Into<f32>) -> Self {\n        self.scale = scale.into();\n        self\n    }\n\n    /// Crops the [`Image`] to the given region described by the [`Rectangle`] in absolute\n    /// coordinates.\n    ///\n    /// Cropping is done before applying any transformation or [`ContentFit`]. In practice,\n    /// this means that cropping an [`Image`] with this method should produce the same result\n    /// as cropping it externally (e.g. with an image editor) and creating a new [`Handle`]\n    /// for the cropped version.\n    ///\n    /// However, this method is much more efficient; since it just leverages scissoring during\n    /// rendering and no image cropping actually takes place. Instead, it reuses the existing\n    /// image allocations and should be as efficient as not cropping at all!\n    ///\n    /// The `region` coordinates will be clamped to the image dimensions, if necessary.\n    pub fn crop(mut self, region: Rectangle<u32>) -> Self {\n        self.crop = Some(region);\n        self\n    }\n\n    /// Sets the [`border::Radius`] of the [`Image`].\n    ///\n    /// Currently, it will only be applied around the rectangular bounding box\n    /// of the [`Image`].\n    pub fn border_radius(mut self, border_radius: impl Into<border::Radius>) -> Self {\n        self.border_radius = border_radius.into();\n        self\n    }\n}\n\n/// Computes the layout of an [`Image`].\npub fn layout<Renderer, Handle>(\n    renderer: &Renderer,\n    limits: &layout::Limits,\n    handle: &Handle,\n    width: Length,\n    height: Length,\n    region: Option<Rectangle<u32>>,\n    content_fit: ContentFit,\n    rotation: Rotation,\n    expand: bool,\n) -> layout::Node\nwhere\n    Renderer: image::Renderer<Handle = Handle>,\n{\n    // The raw w/h of the underlying image\n    let image_size = crop(renderer.measure_image(handle).unwrap_or_default(), region);\n\n    // The rotated size of the image\n    let rotated_size = rotation.apply(image_size);\n\n    // The size to be available to the widget prior to `Shrink`ing\n    let bounds = if expand {\n        limits.width(width).height(height).max()\n    } else {\n        limits.resolve(width, height, rotated_size)\n    };\n\n    // The uncropped size of the image when fit to the bounds above\n    let full_size = content_fit.fit(rotated_size, bounds);\n\n    // Shrink the widget to fit the resized image, if requested\n    let final_size = Size {\n        width: match width {\n            Length::Shrink => f32::min(bounds.width, full_size.width),\n            _ => bounds.width,\n        },\n        height: match height {\n            Length::Shrink => f32::min(bounds.height, full_size.height),\n            _ => bounds.height,\n        },\n    };\n\n    layout::Node::new(final_size)\n}\n\nfn drawing_bounds<Renderer, Handle>(\n    renderer: &Renderer,\n    bounds: Rectangle,\n    handle: &Handle,\n    region: Option<Rectangle<u32>>,\n    content_fit: ContentFit,\n    rotation: Rotation,\n    scale: f32,\n) -> Rectangle\nwhere\n    Renderer: image::Renderer<Handle = Handle>,\n{\n    let original_size = renderer.measure_image(handle).unwrap_or_default();\n    let image_size = crop(original_size, region);\n    let rotated_size = rotation.apply(image_size);\n    let adjusted_fit = content_fit.fit(rotated_size, bounds.size());\n\n    let fit_scale = Vector::new(\n        adjusted_fit.width / rotated_size.width,\n        adjusted_fit.height / rotated_size.height,\n    );\n\n    let final_size = image_size * fit_scale * scale;\n\n    let (crop_offset, final_size) = if let Some(region) = region {\n        let x = region.x.min(original_size.width) as f32;\n        let y = region.y.min(original_size.height) as f32;\n        let width = image_size.width;\n        let height = image_size.height;\n\n        let ratio = Vector::new(\n            original_size.width as f32 / width,\n            original_size.height as f32 / height,\n        );\n\n        let final_size = final_size * ratio;\n\n        let scale = Vector::new(\n            final_size.width / original_size.width as f32,\n            final_size.height / original_size.height as f32,\n        );\n\n        let offset = match content_fit {\n            ContentFit::None => Vector::new(x * scale.x, y * scale.y),\n            _ => Vector::new(\n                ((original_size.width as f32 - width) / 2.0 - x) * scale.x,\n                ((original_size.height as f32 - height) / 2.0 - y) * scale.y,\n            ),\n        };\n\n        (offset, final_size)\n    } else {\n        (Vector::ZERO, final_size)\n    };\n\n    let position = match content_fit {\n        ContentFit::None => Point::new(\n            bounds.x + (rotated_size.width - adjusted_fit.width) / 2.0,\n            bounds.y + (rotated_size.height - adjusted_fit.height) / 2.0,\n        ),\n        _ => Point::new(\n            bounds.center_x() - final_size.width / 2.0,\n            bounds.center_y() - final_size.height / 2.0,\n        ),\n    };\n\n    Rectangle::new(position + crop_offset, final_size)\n}\n\nfn crop(size: Size<u32>, region: Option<Rectangle<u32>>) -> Size<f32> {\n    if let Some(region) = region {\n        Size::new(\n            region.width.min(size.width) as f32,\n            region.height.min(size.height) as f32,\n        )\n    } else {\n        Size::new(size.width as f32, size.height as f32)\n    }\n}\n\n/// Draws an [`Image`]\npub fn draw<Renderer, Handle>(\n    renderer: &mut Renderer,\n    layout: Layout<'_>,\n    handle: &Handle,\n    crop: Option<Rectangle<u32>>,\n    border_radius: border::Radius,\n    content_fit: ContentFit,\n    filter_method: FilterMethod,\n    rotation: Rotation,\n    opacity: f32,\n    scale: f32,\n) where\n    Renderer: image::Renderer<Handle = Handle>,\n    Handle: Clone,\n{\n    let bounds = layout.bounds();\n    let drawing_bounds =\n        drawing_bounds(renderer, bounds, handle, crop, content_fit, rotation, scale);\n\n    renderer.draw_image(\n        image::Image {\n            handle: handle.clone(),\n            border_radius,\n            filter_method,\n            rotation: rotation.radians(),\n            opacity,\n        },\n        drawing_bounds,\n        bounds,\n    );\n}\n\nimpl<Message, Theme, Renderer, Handle> Widget<Message, Theme, Renderer> for Image<Handle>\nwhere\n    Renderer: image::Renderer<Handle = Handle>,\n    Handle: Clone,\n{\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout(\n            renderer,\n            limits,\n            &self.handle,\n            self.width,\n            self.height,\n            self.crop,\n            self.content_fit,\n            self.rotation,\n            self.expand,\n        )\n    }\n\n    fn draw(\n        &self,\n        _tree: &Tree,\n        renderer: &mut Renderer,\n        _theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        draw(\n            renderer,\n            layout,\n            &self.handle,\n            self.crop,\n            self.border_radius,\n            self.content_fit,\n            self.filter_method,\n            self.rotation,\n            self.opacity,\n            self.scale,\n        );\n    }\n}\n\nimpl<'a, Message, Theme, Renderer, Handle> From<Image<Handle>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Renderer: image::Renderer<Handle = Handle>,\n    Handle: Clone + 'a,\n{\n    fn from(image: Image<Handle>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(image)\n    }\n}\n"
  },
  {
    "path": "widget/src/keyed/column.rs",
    "content": "//! Keyed columns distribute content vertically while keeping continuity.\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget::Operation;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::{\n    Alignment, Element, Event, Layout, Length, Padding, Pixels, Rectangle, Shell, Size, Vector,\n    Widget,\n};\n\n/// A container that distributes its contents vertically while keeping continuity.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{keyed_column, text};\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     keyed_column((0..=100).map(|i| {\n///         (i, text!(\"Item {i}\").into())\n///     })).into()\n/// }\n/// ```\npub struct Column<'a, Key, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Key: Copy + PartialEq,\n{\n    spacing: f32,\n    padding: Padding,\n    width: Length,\n    height: Length,\n    max_width: f32,\n    align_items: Alignment,\n    keys: Vec<Key>,\n    children: Vec<Element<'a, Message, Theme, Renderer>>,\n}\n\nimpl<'a, Key, Message, Theme, Renderer> Column<'a, Key, Message, Theme, Renderer>\nwhere\n    Key: Copy + PartialEq,\n    Renderer: crate::core::Renderer,\n{\n    /// Creates an empty [`Column`].\n    pub fn new() -> Self {\n        Self::from_vecs(Vec::new(), Vec::new())\n    }\n\n    /// Creates a [`Column`] from already allocated [`Vec`]s.\n    ///\n    /// Keep in mind that the [`Column`] will not inspect the [`Vec`]s, which means\n    /// it won't automatically adapt to the sizing strategy of its contents.\n    ///\n    /// If any of the children have a [`Length::Fill`] strategy, you will need to\n    /// call [`Column::width`] or [`Column::height`] accordingly.\n    pub fn from_vecs(keys: Vec<Key>, children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            spacing: 0.0,\n            padding: Padding::ZERO,\n            width: Length::Shrink,\n            height: Length::Shrink,\n            max_width: f32::INFINITY,\n            align_items: Alignment::Start,\n            keys,\n            children,\n        }\n    }\n\n    /// Creates a [`Column`] with the given capacity.\n    pub fn with_capacity(capacity: usize) -> Self {\n        Self::from_vecs(Vec::with_capacity(capacity), Vec::with_capacity(capacity))\n    }\n\n    /// Creates a [`Column`] with the given elements.\n    pub fn with_children(\n        children: impl IntoIterator<Item = (Key, Element<'a, Message, Theme, Renderer>)>,\n    ) -> Self {\n        let iterator = children.into_iter();\n\n        Self::with_capacity(iterator.size_hint().0).extend(iterator)\n    }\n\n    /// Sets the vertical spacing _between_ elements.\n    ///\n    /// Custom margins per element do not exist in iced. You should use this\n    /// method instead! While less flexible, it helps you keep spacing between\n    /// elements consistent.\n    pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {\n        self.spacing = amount.into().0;\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`Column`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the width of the [`Column`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Column`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the maximum width of the [`Column`].\n    pub fn max_width(mut self, max_width: impl Into<Pixels>) -> Self {\n        self.max_width = max_width.into().0;\n        self\n    }\n\n    /// Sets the horizontal alignment of the contents of the [`Column`] .\n    pub fn align_items(mut self, align: Alignment) -> Self {\n        self.align_items = align;\n        self\n    }\n\n    /// Adds an element to the [`Column`].\n    pub fn push(\n        mut self,\n        key: Key,\n        child: impl Into<Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        let child = child.into();\n        let child_size = child.as_widget().size_hint();\n\n        self.width = self.width.enclose(child_size.width);\n        self.height = self.height.enclose(child_size.height);\n\n        self.keys.push(key);\n        self.children.push(child);\n        self\n    }\n\n    /// Adds an element to the [`Column`], if `Some`.\n    pub fn push_maybe(\n        self,\n        key: Key,\n        child: Option<impl Into<Element<'a, Message, Theme, Renderer>>>,\n    ) -> Self {\n        if let Some(child) = child {\n            self.push(key, child)\n        } else {\n            self\n        }\n    }\n\n    /// Extends the [`Column`] with the given children.\n    pub fn extend(\n        self,\n        children: impl IntoIterator<Item = (Key, Element<'a, Message, Theme, Renderer>)>,\n    ) -> Self {\n        children\n            .into_iter()\n            .fold(self, |column, (key, child)| column.push(key, child))\n    }\n}\n\nimpl<Key, Message, Renderer> Default for Column<'_, Key, Message, Renderer>\nwhere\n    Key: Copy + PartialEq,\n    Renderer: crate::core::Renderer,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nstruct State<Key>\nwhere\n    Key: Copy + PartialEq,\n{\n    keys: Vec<Key>,\n}\n\nimpl<Key, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Column<'_, Key, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n    Key: Copy + PartialEq + 'static,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State<Key>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State {\n            keys: self.keys.clone(),\n        })\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        self.children.iter().map(Tree::new).collect()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        let Tree {\n            state, children, ..\n        } = tree;\n\n        let state = state.downcast_mut::<State<Key>>();\n\n        tree::diff_children_custom_with_search(\n            children,\n            &self.children,\n            |tree, child| child.as_widget().diff(tree),\n            |index| {\n                self.keys.get(index).or_else(|| self.keys.last()).copied()\n                    != Some(state.keys[index])\n            },\n            |child| Tree::new(child.as_widget()),\n        );\n\n        if state.keys != self.keys {\n            state.keys.clone_from(&self.keys);\n        }\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits\n            .max_width(self.max_width)\n            .width(self.width)\n            .height(self.height);\n\n        layout::flex::resolve(\n            layout::flex::Axis::Vertical,\n            renderer,\n            &limits,\n            self.width,\n            self.height,\n            self.padding,\n            self.spacing,\n            self.align_items,\n            &mut self.children,\n            &mut tree.children,\n        )\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        operation.container(None, layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.children\n                .iter_mut()\n                .zip(&mut tree.children)\n                .zip(layout.children())\n                .for_each(|((child, state), layout)| {\n                    child\n                        .as_widget_mut()\n                        .operate(state, layout, renderer, operation);\n                });\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        for ((child, tree), layout) in self\n            .children\n            .iter_mut()\n            .zip(&mut tree.children)\n            .zip(layout.children())\n        {\n            child\n                .as_widget_mut()\n                .update(tree, event, layout, cursor, renderer, shell, viewport);\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.children\n            .iter()\n            .zip(&tree.children)\n            .zip(layout.children())\n            .map(|((child, tree), layout)| {\n                child\n                    .as_widget()\n                    .mouse_interaction(tree, layout, cursor, viewport, renderer)\n            })\n            .max()\n            .unwrap_or_default()\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        for ((child, state), layout) in self\n            .children\n            .iter()\n            .zip(&tree.children)\n            .zip(layout.children())\n        {\n            child\n                .as_widget()\n                .draw(state, renderer, theme, style, layout, cursor, viewport);\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        overlay::from_children(\n            &mut self.children,\n            tree,\n            layout,\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Key, Message, Theme, Renderer> From<Column<'a, Key, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Key: Copy + PartialEq + 'static,\n    Message: 'a,\n    Theme: 'a,\n    Renderer: crate::core::Renderer + 'a,\n{\n    fn from(column: Column<'a, Key, Message, Theme, Renderer>) -> Self {\n        Self::new(column)\n    }\n}\n"
  },
  {
    "path": "widget/src/keyed.rs",
    "content": "//! Keyed widgets can provide hints to ensure continuity.\n//!\n//! # What is continuity?\n//! Continuity is the feeling of persistence of state.\n//!\n//! In a graphical user interface, users expect widgets to have a\n//! certain degree of continuous state. For instance, a text input\n//! that is focused should stay focused even if the widget tree\n//! changes slightly.\n//!\n//! Continuity is tricky in `iced` and the Elm Architecture because\n//! the whole widget tree is rebuilt during every `view` call. This is\n//! very convenient from a developer perspective because you can build\n//! extremely dynamic interfaces without worrying about changing state.\n//!\n//! However, the tradeoff is that determining what changed becomes hard\n//! for `iced`. If you have a list of things, adding an element at the\n//! top may cause a loss of continuity on every element on the list!\n//!\n//! # How can we keep continuity?\n//! The good news is that user interfaces generally have a static widget\n//! structure. This structure can be relied on to ensure some degree of\n//! continuity. `iced` already does this.\n//!\n//! However, sometimes you have a certain part of your interface that is\n//! quite dynamic. For instance, a list of things where items may be added\n//! or removed at any place.\n//!\n//! There are different ways to mitigate this during the reconciliation\n//! stage, but they involve comparing trees at certain depths and\n//! backtracking... Quite computationally expensive.\n//!\n//! One approach that is cheaper consists in letting the user provide some hints\n//! about the identities of the different widgets so that they can be compared\n//! directly without going deeper.\n//!\n//! The widgets in this module will all ask for a \"hint\" of some sort. In order\n//! to help them keep continuity, you need to make sure the hint stays the same\n//! for the same items in your user interface between `view` calls.\npub mod column;\n\npub use column::Column;\n\n/// Creates a keyed [`Column`] with the given children.\n///\n/// Keyed columns distribute content vertically while keeping continuity.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::keyed_column;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     keyed_column![\n///         (0, \"Item 0\"),\n///         (1, \"Item 1\"),\n///         (2, \"Item 2\"),\n///     ].into()\n/// }\n/// ```\n#[macro_export]\nmacro_rules! keyed_column {\n    () => (\n        $crate::keyed::Column::new()\n    );\n    ($(($key:expr, $x:expr)),+ $(,)?) => (\n        $crate::keyed::Column::with_children(vec![$(($key, $crate::core::Element::from($x))),+])\n    );\n}\n"
  },
  {
    "path": "widget/src/lazy/cache.rs",
    "content": "#![allow(dead_code)]\nuse crate::core::Element;\nuse crate::core::overlay;\n\nuse ouroboros::self_referencing;\n\n#[self_referencing(pub_extras)]\npub struct Cache<'a, Message: 'a, Theme: 'a, Renderer: 'a> {\n    pub element: Element<'a, Message, Theme, Renderer>,\n\n    #[borrows(mut element)]\n    #[covariant]\n    overlay: Option<overlay::Element<'this, Message, Theme, Renderer>>,\n}\n"
  },
  {
    "path": "widget/src/lazy/component.rs",
    "content": "//! Build and reuse custom widgets using The Elm Architecture.\n#![allow(deprecated)]\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::{self, Element, Length, Rectangle, Shell, Size, Vector, Widget};\n\nuse ouroboros::self_referencing;\nuse std::cell::RefCell;\nuse std::marker::PhantomData;\nuse std::rc::Rc;\n\n/// A reusable, custom widget that uses The Elm Architecture.\n///\n/// A [`Component`] allows you to implement custom widgets as if they were\n/// `iced` applications with encapsulated state.\n///\n/// In other words, a [`Component`] allows you to turn `iced` applications into\n/// custom widgets and embed them without cumbersome wiring.\n///\n/// A [`Component`] produces widgets that may fire an [`Event`](Component::Event)\n/// and update the internal state of the [`Component`].\n///\n/// Additionally, a [`Component`] is capable of producing a `Message` to notify\n/// the parent application of any relevant interactions.\n///\n/// # State\n/// A component can store its state in one of two ways: either as data within the\n/// implementor of the trait, or in a type [`State`][Component::State] that is managed\n/// by the runtime and provided to the trait methods. These two approaches are not\n/// mutually exclusive and have opposite pros and cons.\n///\n/// For instance, if a piece of state is needed by multiple components that reside\n/// in different branches of the tree, then it's more convenient to let a common\n/// ancestor store it and pass it down.\n///\n/// On the other hand, if a piece of state is only needed by the component itself,\n/// you can store it as part of its internal [`State`][Component::State].\n#[cfg(feature = \"lazy\")]\n#[deprecated(\n    since = \"0.13.0\",\n    note = \"components introduce encapsulated state and hamper the use of a single source of truth. \\\n    Instead, leverage the Elm Architecture directly, or implement a custom widget\"\n)]\npub trait Component<Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    /// The internal state of this [`Component`].\n    type State: Default;\n\n    /// The type of event this [`Component`] handles internally.\n    type Event;\n\n    /// Processes an [`Event`](Component::Event) and updates the [`Component`] state accordingly.\n    ///\n    /// It can produce a `Message` for the parent application.\n    fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<Message>;\n\n    /// Produces the widgets of the [`Component`], which may trigger an [`Event`](Component::Event)\n    /// on user interaction.\n    fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Theme, Renderer>;\n\n    /// Update the [`Component`] state based on the provided [`Operation`](widget::Operation)\n    ///\n    /// By default, it does nothing.\n    fn operate(\n        &self,\n        _bounds: Rectangle,\n        _state: &mut Self::State,\n        _operation: &mut dyn widget::Operation,\n    ) {\n    }\n\n    /// Returns a [`Size`] hint for laying out the [`Component`].\n    ///\n    /// This hint may be used by some widget containers to adjust their sizing strategy\n    /// during construction.\n    fn size_hint(&self) -> Size<Length> {\n        Size {\n            width: Length::Shrink,\n            height: Length::Shrink,\n        }\n    }\n}\n\nstruct Tag<T>(T);\n\n/// Turns an implementor of [`Component`] into an [`Element`] that can be\n/// embedded in any application.\npub fn view<'a, C, Message, Theme, Renderer>(component: C) -> Element<'a, Message, Theme, Renderer>\nwhere\n    C: Component<Message, Theme, Renderer> + 'a,\n    C::State: 'static,\n    Message: 'a,\n    Theme: 'a,\n    Renderer: core::Renderer + 'a,\n{\n    Element::new(Instance {\n        state: RefCell::new(Some(\n            StateBuilder {\n                component: Box::new(component),\n                message: PhantomData,\n                state: PhantomData,\n                element_builder: |_| None,\n            }\n            .build(),\n        )),\n        tree: RefCell::new(Rc::new(RefCell::new(None))),\n    })\n}\n\nstruct Instance<'a, Message, Theme, Renderer, Event, S> {\n    state: RefCell<Option<State<'a, Message, Theme, Renderer, Event, S>>>,\n    tree: RefCell<Rc<RefCell<Option<Tree>>>>,\n}\n\n#[self_referencing]\nstruct State<'a, Message: 'a, Theme: 'a, Renderer: 'a, Event: 'a, S: 'a> {\n    component: Box<dyn Component<Message, Theme, Renderer, Event = Event, State = S> + 'a>,\n    message: PhantomData<Message>,\n    state: PhantomData<S>,\n\n    #[borrows(component)]\n    #[covariant]\n    element: Option<Element<'this, Event, Theme, Renderer>>,\n}\n\nimpl<Message, Theme, Renderer, Event, S> Instance<'_, Message, Theme, Renderer, Event, S>\nwhere\n    S: Default + 'static,\n    Renderer: renderer::Renderer,\n{\n    fn diff_self(&self) {\n        self.with_element(|element| {\n            self.tree\n                .borrow_mut()\n                .borrow_mut()\n                .as_mut()\n                .unwrap()\n                .diff_children(std::slice::from_ref(&element));\n        });\n    }\n\n    fn rebuild_element_if_necessary(&self) {\n        let inner = self.state.borrow_mut().take().unwrap();\n        if inner.borrow_element().is_none() {\n            let heads = inner.into_heads();\n\n            *self.state.borrow_mut() = Some(\n                StateBuilder {\n                    component: heads.component,\n                    message: PhantomData,\n                    state: PhantomData,\n                    element_builder: |component| {\n                        Some(\n                            component.view(\n                                self.tree\n                                    .borrow()\n                                    .borrow()\n                                    .as_ref()\n                                    .unwrap()\n                                    .state\n                                    .downcast_ref::<S>(),\n                            ),\n                        )\n                    },\n                }\n                .build(),\n            );\n            self.diff_self();\n        } else {\n            *self.state.borrow_mut() = Some(inner);\n        }\n    }\n\n    fn rebuild_element_with_operation(\n        &self,\n        layout: Layout<'_>,\n        operation: &mut dyn widget::Operation,\n    ) {\n        let heads = self.state.borrow_mut().take().unwrap().into_heads();\n\n        heads.component.operate(\n            layout.bounds(),\n            self.tree\n                .borrow_mut()\n                .borrow_mut()\n                .as_mut()\n                .unwrap()\n                .state\n                .downcast_mut(),\n            operation,\n        );\n\n        *self.state.borrow_mut() = Some(\n            StateBuilder {\n                component: heads.component,\n                message: PhantomData,\n                state: PhantomData,\n                element_builder: |component| {\n                    Some(\n                        component.view(\n                            self.tree\n                                .borrow()\n                                .borrow()\n                                .as_ref()\n                                .unwrap()\n                                .state\n                                .downcast_ref(),\n                        ),\n                    )\n                },\n            }\n            .build(),\n        );\n        self.diff_self();\n    }\n\n    fn with_element<T>(&self, f: impl FnOnce(&Element<'_, Event, Theme, Renderer>) -> T) -> T {\n        self.with_element_mut(|element| f(element))\n    }\n\n    fn with_element_mut<T>(\n        &self,\n        f: impl FnOnce(&mut Element<'_, Event, Theme, Renderer>) -> T,\n    ) -> T {\n        self.rebuild_element_if_necessary();\n        self.state\n            .borrow_mut()\n            .as_mut()\n            .unwrap()\n            .with_element_mut(|element| f(element.as_mut().unwrap()))\n    }\n}\n\nimpl<Message, Theme, Renderer, Event, S> Widget<Message, Theme, Renderer>\n    for Instance<'_, Message, Theme, Renderer, Event, S>\nwhere\n    S: 'static + Default,\n    Renderer: core::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<Tag<S>>()\n    }\n\n    fn state(&self) -> tree::State {\n        let state = Rc::new(RefCell::new(Some(Tree {\n            tag: tree::Tag::of::<Tag<S>>(),\n            state: tree::State::new(S::default()),\n            children: vec![Tree::empty()],\n        })));\n\n        *self.tree.borrow_mut() = state.clone();\n        self.diff_self();\n\n        tree::State::new(state)\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        vec![]\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();\n        *self.tree.borrow_mut() = tree.clone();\n        self.rebuild_element_if_necessary();\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.with_element(|element| element.as_widget().size())\n    }\n\n    fn size_hint(&self) -> Size<Length> {\n        self.state\n            .borrow()\n            .as_ref()\n            .expect(\"Borrow instance state\")\n            .borrow_component()\n            .size_hint()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let t = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();\n\n        self.with_element_mut(|element| {\n            element.as_widget_mut().layout(\n                &mut t.borrow_mut().as_mut().unwrap().children[0],\n                renderer,\n                limits,\n            )\n        })\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &core::Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        let mut local_messages = Vec::new();\n        let mut local_shell = Shell::new(&mut local_messages);\n\n        let t = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();\n        self.with_element_mut(|element| {\n            element.as_widget_mut().update(\n                &mut t.borrow_mut().as_mut().unwrap().children[0],\n                event,\n                layout,\n                cursor,\n                renderer,\n                &mut local_shell,\n                viewport,\n            );\n        });\n\n        if local_shell.is_event_captured() {\n            shell.capture_event();\n        }\n\n        local_shell.revalidate_layout(|| shell.invalidate_layout());\n        shell.request_redraw_at(local_shell.redraw_request());\n        shell.request_input_method(local_shell.input_method());\n        shell.clipboard_mut().merge(local_shell.clipboard_mut());\n\n        if !local_messages.is_empty() {\n            let mut heads = self.state.take().unwrap().into_heads();\n\n            for message in local_messages.into_iter().filter_map(|message| {\n                heads.component.update(\n                    t.borrow_mut().as_mut().unwrap().state.downcast_mut(),\n                    message,\n                )\n            }) {\n                shell.publish(message);\n            }\n\n            self.state = RefCell::new(Some(\n                StateBuilder {\n                    component: heads.component,\n                    message: PhantomData,\n                    state: PhantomData,\n                    element_builder: |_| None,\n                }\n                .build(),\n            ));\n\n            shell.invalidate_layout();\n            shell.request_redraw();\n        }\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.rebuild_element_with_operation(layout, operation);\n\n        let tree = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();\n        self.with_element_mut(|element| {\n            element.as_widget_mut().operate(\n                &mut tree.borrow_mut().as_mut().unwrap().children[0],\n                layout,\n                renderer,\n                operation,\n            );\n        });\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();\n        self.with_element(|element| {\n            element.as_widget().draw(\n                &tree.borrow().as_ref().unwrap().children[0],\n                renderer,\n                theme,\n                style,\n                layout,\n                cursor,\n                viewport,\n            );\n        });\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();\n        self.with_element(|element| {\n            element.as_widget().mouse_interaction(\n                &tree.borrow().as_ref().unwrap().children[0],\n                layout,\n                cursor,\n                viewport,\n                renderer,\n            )\n        })\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.rebuild_element_if_necessary();\n\n        let state = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();\n        let tree = state.borrow_mut().take().unwrap();\n\n        let overlay = InnerBuilder {\n            instance: self,\n            tree,\n            types: PhantomData,\n            overlay_builder: |instance, tree| {\n                instance\n                    .state\n                    .get_mut()\n                    .as_mut()\n                    .unwrap()\n                    .with_element_mut(move |element| {\n                        element\n                            .as_mut()\n                            .unwrap()\n                            .as_widget_mut()\n                            .overlay(\n                                &mut tree.children[0],\n                                layout,\n                                renderer,\n                                viewport,\n                                translation,\n                            )\n                            .map(|overlay| RefCell::new(overlay::Nested::new(overlay)))\n                    })\n            },\n        }\n        .build();\n\n        #[allow(clippy::redundant_closure_for_method_calls)]\n        if overlay.with_overlay(|overlay| overlay.is_some()) {\n            Some(overlay::Element::new(Box::new(OverlayInstance {\n                overlay: Some(Overlay(Some(overlay))), // Beautiful, I know\n            })))\n        } else {\n            let heads = overlay.into_heads();\n\n            // - You may not like it, but this is what peak performance looks like\n            // - TODO: Get rid of ouroboros, for good\n            // - What?!\n            *state.borrow_mut() = Some(heads.tree);\n\n            None\n        }\n    }\n}\n\nstruct Overlay<'a, 'b, Message, Theme, Renderer, Event, S>(\n    Option<Inner<'a, 'b, Message, Theme, Renderer, Event, S>>,\n);\n\nimpl<Message, Theme, Renderer, Event, S> Drop\n    for Overlay<'_, '_, Message, Theme, Renderer, Event, S>\n{\n    fn drop(&mut self) {\n        if let Some(heads) = self.0.take().map(Inner::into_heads) {\n            *heads.instance.tree.borrow_mut().borrow_mut() = Some(heads.tree);\n        }\n    }\n}\n\n#[self_referencing]\nstruct Inner<'a, 'b, Message, Theme, Renderer, Event, S> {\n    instance: &'a mut Instance<'b, Message, Theme, Renderer, Event, S>,\n    tree: Tree,\n    types: PhantomData<(Message, Event, S)>,\n\n    #[borrows(mut instance, mut tree)]\n    #[not_covariant]\n    overlay: Option<RefCell<overlay::Nested<'this, Event, Theme, Renderer>>>,\n}\n\nstruct OverlayInstance<'a, 'b, Message, Theme, Renderer, Event, S> {\n    overlay: Option<Overlay<'a, 'b, Message, Theme, Renderer, Event, S>>,\n}\n\nimpl<Message, Theme, Renderer, Event, S>\n    OverlayInstance<'_, '_, Message, Theme, Renderer, Event, S>\n{\n    fn with_overlay_maybe<T>(\n        &self,\n        f: impl FnOnce(&mut overlay::Nested<'_, Event, Theme, Renderer>) -> T,\n    ) -> Option<T> {\n        self.overlay\n            .as_ref()\n            .unwrap()\n            .0\n            .as_ref()\n            .unwrap()\n            .with_overlay(|overlay| overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut())))\n    }\n\n    fn with_overlay_mut_maybe<T>(\n        &mut self,\n        f: impl FnOnce(&mut overlay::Nested<'_, Event, Theme, Renderer>) -> T,\n    ) -> Option<T> {\n        self.overlay\n            .as_mut()\n            .unwrap()\n            .0\n            .as_mut()\n            .unwrap()\n            .with_overlay_mut(|overlay| overlay.as_mut().map(|nested| (f)(nested.get_mut())))\n    }\n}\n\nimpl<Message, Theme, Renderer, Event, S> overlay::Overlay<Message, Theme, Renderer>\n    for OverlayInstance<'_, '_, Message, Theme, Renderer, Event, S>\nwhere\n    Renderer: core::Renderer,\n    S: 'static + Default,\n{\n    fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n        self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))\n            .unwrap_or_default()\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) {\n        let _ = self.with_overlay_maybe(|overlay| {\n            overlay.draw(renderer, theme, style, layout, cursor);\n        });\n    }\n\n    fn mouse_interaction(\n        &self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.with_overlay_maybe(|overlay| overlay.mouse_interaction(layout, cursor, renderer))\n            .unwrap_or_default()\n    }\n\n    fn update(\n        &mut self,\n        event: &core::Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n    ) {\n        let mut local_messages = Vec::new();\n        let mut local_shell = Shell::new(&mut local_messages);\n\n        let _ = self.with_overlay_mut_maybe(|overlay| {\n            overlay.update(event, layout, cursor, renderer, &mut local_shell);\n        });\n\n        if local_shell.is_event_captured() {\n            shell.capture_event();\n        }\n\n        local_shell.revalidate_layout(|| shell.invalidate_layout());\n        shell.request_redraw_at(local_shell.redraw_request());\n        shell.request_input_method(local_shell.input_method());\n        shell.clipboard_mut().merge(local_shell.clipboard_mut());\n\n        if !local_messages.is_empty() {\n            let mut inner = self.overlay.take().unwrap().0.take().unwrap().into_heads();\n            let mut heads = inner.instance.state.take().unwrap().into_heads();\n\n            for message in local_messages.into_iter().filter_map(|message| {\n                heads\n                    .component\n                    .update(inner.tree.state.downcast_mut(), message)\n            }) {\n                shell.publish(message);\n            }\n\n            *inner.instance.state.borrow_mut() = Some(\n                StateBuilder {\n                    component: heads.component,\n                    message: PhantomData,\n                    state: PhantomData,\n                    element_builder: |_| None,\n                }\n                .build(),\n            );\n\n            self.overlay = Some(Overlay(Some(\n                InnerBuilder {\n                    instance: inner.instance,\n                    tree: inner.tree,\n                    types: PhantomData,\n                    overlay_builder: |_, _| None,\n                }\n                .build(),\n            )));\n\n            shell.invalidate_layout();\n        }\n    }\n}\n"
  },
  {
    "path": "widget/src/lazy/helpers.rs",
    "content": "use crate::core::{self, Element};\nuse crate::lazy::component;\n\nuse std::hash::Hash;\n\n#[allow(deprecated)]\npub use crate::lazy::{Component, Lazy};\n\n/// Creates a new [`Lazy`] widget with the given data `Dependency` and a\n/// closure that can turn this data into a widget tree.\n#[cfg(feature = \"lazy\")]\npub fn lazy<'a, Message, Theme, Renderer, Dependency, View>(\n    dependency: Dependency,\n    view: impl Fn(&Dependency) -> View + 'a,\n) -> Lazy<'a, Message, Theme, Renderer, Dependency, View>\nwhere\n    Dependency: Hash + 'a,\n    View: Into<Element<'static, Message, Theme, Renderer>>,\n{\n    Lazy::new(dependency, view)\n}\n\n/// Turns an implementor of [`Component`] into an [`Element`] that can be\n/// embedded in any application.\n#[cfg(feature = \"lazy\")]\n#[deprecated(\n    since = \"0.13.0\",\n    note = \"components introduce encapsulated state and hamper the use of a single source of truth. \\\n    Instead, leverage the Elm Architecture directly, or implement a custom widget\"\n)]\n#[allow(deprecated)]\npub fn component<'a, C, Message, Theme, Renderer>(\n    component: C,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    C: Component<Message, Theme, Renderer> + 'a,\n    C::State: 'static,\n    Message: 'a,\n    Theme: 'a,\n    Renderer: core::Renderer + 'a,\n{\n    component::view(component)\n}\n"
  },
  {
    "path": "widget/src/lazy.rs",
    "content": "#![allow(clippy::await_holding_refcell_ref, clippy::type_complexity)]\npub(crate) mod helpers;\n\npub mod component;\n\n#[allow(deprecated)]\npub use component::Component;\n\nmod cache;\n\nuse crate::core::Element;\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::widget::{self, Widget};\nuse crate::core::{self, Event, Length, Rectangle, Shell, Size, Vector};\n\nuse ouroboros::self_referencing;\nuse rustc_hash::FxHasher;\nuse std::cell::RefCell;\nuse std::hash::{Hash, Hasher as H};\nuse std::rc::Rc;\n\n/// A widget that only rebuilds its contents when necessary.\n#[cfg(feature = \"lazy\")]\npub struct Lazy<'a, Message, Theme, Renderer, Dependency, View> {\n    dependency: Dependency,\n    view: Box<dyn Fn(&Dependency) -> View + 'a>,\n    element: RefCell<Option<Rc<RefCell<Option<Element<'static, Message, Theme, Renderer>>>>>>,\n}\n\nimpl<'a, Message, Theme, Renderer, Dependency, View>\n    Lazy<'a, Message, Theme, Renderer, Dependency, View>\nwhere\n    Dependency: Hash + 'a,\n    View: Into<Element<'static, Message, Theme, Renderer>>,\n{\n    /// Creates a new [`Lazy`] widget with the given data `Dependency` and a\n    /// closure that can turn this data into a widget tree.\n    pub fn new(dependency: Dependency, view: impl Fn(&Dependency) -> View + 'a) -> Self {\n        Self {\n            dependency,\n            view: Box::new(view),\n            element: RefCell::new(None),\n        }\n    }\n\n    fn with_element<T>(&self, f: impl FnOnce(&Element<'_, Message, Theme, Renderer>) -> T) -> T {\n        f(self\n            .element\n            .borrow()\n            .as_ref()\n            .unwrap()\n            .borrow()\n            .as_ref()\n            .unwrap())\n    }\n\n    fn with_element_mut<T>(\n        &self,\n        f: impl FnOnce(&mut Element<'_, Message, Theme, Renderer>) -> T,\n    ) -> T {\n        f(self\n            .element\n            .borrow()\n            .as_ref()\n            .unwrap()\n            .borrow_mut()\n            .as_mut()\n            .unwrap())\n    }\n}\n\nstruct Internal<Message, Theme, Renderer> {\n    element: Rc<RefCell<Option<Element<'static, Message, Theme, Renderer>>>>,\n    hash: u64,\n}\n\nimpl<'a, Message, Theme, Renderer, Dependency, View> Widget<Message, Theme, Renderer>\n    for Lazy<'a, Message, Theme, Renderer, Dependency, View>\nwhere\n    View: Into<Element<'static, Message, Theme, Renderer>> + 'static,\n    Dependency: Hash + 'a,\n    Message: 'static,\n    Theme: 'static,\n    Renderer: core::Renderer + 'static,\n{\n    fn tag(&self) -> tree::Tag {\n        struct Tag<T>(T);\n        tree::Tag::of::<Tag<View>>()\n    }\n\n    fn state(&self) -> tree::State {\n        let hash = {\n            let mut hasher = FxHasher::default();\n            self.dependency.hash(&mut hasher);\n\n            hasher.finish()\n        };\n\n        let element = Rc::new(RefCell::new(Some((self.view)(&self.dependency).into())));\n\n        (*self.element.borrow_mut()) = Some(element.clone());\n\n        tree::State::new(Internal { element, hash })\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        self.with_element(|element| vec![Tree::new(element.as_widget())])\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        let current = tree\n            .state\n            .downcast_mut::<Internal<Message, Theme, Renderer>>();\n\n        let new_hash = {\n            let mut hasher = FxHasher::default();\n            self.dependency.hash(&mut hasher);\n\n            hasher.finish()\n        };\n\n        if current.hash != new_hash {\n            current.hash = new_hash;\n\n            let element = (self.view)(&self.dependency).into();\n            current.element = Rc::new(RefCell::new(Some(element)));\n\n            (*self.element.borrow_mut()) = Some(current.element.clone());\n            self.with_element(|element| {\n                tree.diff_children(std::slice::from_ref(&element.as_widget()));\n            });\n        } else {\n            (*self.element.borrow_mut()) = Some(current.element.clone());\n        }\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.with_element(|element| element.as_widget().size())\n    }\n\n    fn size_hint(&self) -> Size<Length> {\n        Size {\n            width: Length::Shrink,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.with_element_mut(|element| {\n            element\n                .as_widget_mut()\n                .layout(&mut tree.children[0], renderer, limits)\n        })\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.with_element_mut(|element| {\n            element\n                .as_widget_mut()\n                .operate(&mut tree.children[0], layout, renderer, operation);\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.with_element_mut(|element| {\n            element.as_widget_mut().update(\n                &mut tree.children[0],\n                event,\n                layout,\n                cursor,\n                renderer,\n                shell,\n                viewport,\n            );\n        });\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.with_element(|element| {\n            element.as_widget().mouse_interaction(\n                &tree.children[0],\n                layout,\n                cursor,\n                viewport,\n                renderer,\n            )\n        })\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.with_element(|element| {\n            element.as_widget().draw(\n                &tree.children[0],\n                renderer,\n                theme,\n                style,\n                layout,\n                cursor,\n                viewport,\n            );\n        });\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        let overlay = InnerBuilder {\n            cell: self.element.borrow().as_ref().unwrap().clone(),\n            element: self\n                .element\n                .borrow()\n                .as_ref()\n                .unwrap()\n                .borrow_mut()\n                .take()\n                .unwrap(),\n            tree: &mut tree.children[0],\n            layout,\n            overlay_builder: |element, tree, layout| {\n                element\n                    .as_widget_mut()\n                    .overlay(tree, *layout, renderer, viewport, translation)\n                    .map(|overlay| RefCell::new(overlay::Nested::new(overlay)))\n            },\n        }\n        .build();\n\n        #[allow(clippy::redundant_closure_for_method_calls)]\n        if overlay.with_overlay(|overlay| overlay.is_some()) {\n            Some(overlay::Element::new(Box::new(Overlay(Some(overlay)))))\n        } else {\n            let heads = overlay.into_heads();\n\n            // - You may not like it, but this is what peak performance looks like\n            // - TODO: Get rid of ouroboros, for good\n            // - What?!\n            *self.element.borrow().as_ref().unwrap().borrow_mut() = Some(heads.element);\n\n            None\n        }\n    }\n}\n\n#[self_referencing]\nstruct Inner<'a, Message: 'a, Theme: 'a, Renderer: 'a> {\n    cell: Rc<RefCell<Option<Element<'static, Message, Theme, Renderer>>>>,\n    element: Element<'static, Message, Theme, Renderer>,\n    tree: &'a mut Tree,\n    layout: Layout<'a>,\n\n    #[borrows(mut element, mut tree, layout)]\n    #[not_covariant]\n    overlay: Option<RefCell<overlay::Nested<'this, Message, Theme, Renderer>>>,\n}\n\nstruct Overlay<'a, Message, Theme, Renderer>(Option<Inner<'a, Message, Theme, Renderer>>);\n\nimpl<Message, Theme, Renderer> Drop for Overlay<'_, Message, Theme, Renderer> {\n    fn drop(&mut self) {\n        let heads = self.0.take().unwrap().into_heads();\n        (*heads.cell.borrow_mut()) = Some(heads.element);\n    }\n}\n\nimpl<Message, Theme, Renderer> Overlay<'_, Message, Theme, Renderer> {\n    fn with_overlay_maybe<T>(\n        &self,\n        f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,\n    ) -> Option<T> {\n        self.0\n            .as_ref()\n            .unwrap()\n            .with_overlay(|overlay| overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut())))\n    }\n\n    fn with_overlay_mut_maybe<T>(\n        &mut self,\n        f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,\n    ) -> Option<T> {\n        self.0\n            .as_mut()\n            .unwrap()\n            .with_overlay_mut(|overlay| overlay.as_mut().map(|nested| (f)(nested.get_mut())))\n    }\n}\n\nimpl<Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>\n    for Overlay<'_, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n        self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))\n            .unwrap_or_default()\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) {\n        let _ = self.with_overlay_maybe(|overlay| {\n            overlay.draw(renderer, theme, style, layout, cursor);\n        });\n    }\n\n    fn mouse_interaction(\n        &self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.with_overlay_maybe(|overlay| overlay.mouse_interaction(layout, cursor, renderer))\n            .unwrap_or_default()\n    }\n\n    fn update(\n        &mut self,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n    ) {\n        let _ = self.with_overlay_mut_maybe(|overlay| {\n            overlay.update(event, layout, cursor, renderer, shell);\n        });\n    }\n}\n\nimpl<'a, Message, Theme, Renderer, Dependency, View>\n    From<Lazy<'a, Message, Theme, Renderer, Dependency, View>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    View: Into<Element<'static, Message, Theme, Renderer>> + 'static,\n    Renderer: core::Renderer + 'static,\n    Message: 'static,\n    Theme: 'static,\n    Dependency: Hash + 'a,\n{\n    fn from(lazy: Lazy<'a, Message, Theme, Renderer, Dependency, View>) -> Self {\n        Self::new(lazy)\n    }\n}\n"
  },
  {
    "path": "widget/src/lib.rs",
    "content": "//! Use the built-in widgets or create your own.\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg\"\n)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\npub use iced_renderer as renderer;\npub use iced_renderer::core;\npub use iced_renderer::graphics;\n\npub use core::widget::Id;\n\nmod action;\nmod column;\nmod mouse_area;\nmod pin;\nmod responsive;\nmod stack;\nmod themer;\n\npub mod button;\npub mod checkbox;\npub mod combo_box;\npub mod container;\npub mod float;\npub mod grid;\npub mod keyed;\npub mod overlay;\npub mod pane_grid;\npub mod pick_list;\npub mod progress_bar;\npub mod radio;\npub mod row;\npub mod rule;\npub mod scrollable;\npub mod sensor;\npub mod slider;\npub mod space;\npub mod table;\npub mod text;\npub mod text_editor;\npub mod text_input;\npub mod toggler;\npub mod tooltip;\npub mod vertical_slider;\n\nmod helpers;\n\npub use helpers::*;\n\n#[cfg(feature = \"lazy\")]\nmod lazy;\n\n#[cfg(feature = \"lazy\")]\npub use crate::lazy::helpers::*;\n\n#[doc(no_inline)]\npub use button::Button;\n#[doc(no_inline)]\npub use checkbox::Checkbox;\n#[doc(no_inline)]\npub use column::Column;\n#[doc(no_inline)]\npub use combo_box::ComboBox;\n#[doc(no_inline)]\npub use container::Container;\n#[doc(no_inline)]\npub use float::Float;\n#[doc(no_inline)]\npub use grid::Grid;\n#[doc(no_inline)]\npub use mouse_area::MouseArea;\n#[doc(no_inline)]\npub use pane_grid::PaneGrid;\n#[doc(no_inline)]\npub use pick_list::PickList;\n#[doc(no_inline)]\npub use pin::Pin;\n#[doc(no_inline)]\npub use progress_bar::ProgressBar;\n#[doc(no_inline)]\npub use radio::Radio;\n#[doc(no_inline)]\npub use responsive::Responsive;\n#[doc(no_inline)]\npub use row::Row;\n#[doc(no_inline)]\npub use rule::Rule;\n#[doc(no_inline)]\npub use scrollable::Scrollable;\n#[doc(no_inline)]\npub use sensor::Sensor;\n#[doc(no_inline)]\npub use slider::Slider;\n#[doc(no_inline)]\npub use space::Space;\n#[doc(no_inline)]\npub use stack::Stack;\n#[doc(no_inline)]\npub use text::Text;\n#[doc(no_inline)]\npub use text_editor::TextEditor;\n#[doc(no_inline)]\npub use text_input::TextInput;\n#[doc(no_inline)]\npub use themer::Themer;\n#[doc(no_inline)]\npub use toggler::Toggler;\n#[doc(no_inline)]\npub use tooltip::Tooltip;\n#[doc(no_inline)]\npub use vertical_slider::VerticalSlider;\n\n#[cfg(feature = \"wgpu\")]\npub mod shader;\n\n#[cfg(feature = \"wgpu\")]\n#[doc(no_inline)]\npub use shader::Shader;\n\n#[cfg(feature = \"svg\")]\npub mod svg;\n\n#[cfg(feature = \"svg\")]\n#[doc(no_inline)]\npub use svg::Svg;\n\n#[cfg(feature = \"image\")]\npub mod image;\n\n#[cfg(feature = \"image\")]\n#[doc(no_inline)]\npub use image::Image;\n\n#[cfg(feature = \"canvas\")]\npub mod canvas;\n\n#[cfg(feature = \"canvas\")]\n#[doc(no_inline)]\npub use canvas::Canvas;\n\n#[cfg(feature = \"qr_code\")]\npub mod qr_code;\n\n#[cfg(feature = \"qr_code\")]\n#[doc(no_inline)]\npub use qr_code::QRCode;\n\n#[cfg(feature = \"markdown\")]\npub mod markdown;\n\npub use crate::core::theme::{self, Theme};\npub use action::Action;\npub use renderer::Renderer;\n"
  },
  {
    "path": "widget/src/markdown.rs",
    "content": "//! Markdown widgets can parse and display Markdown.\n//!\n//! You can enable the `highlighter` feature for syntax highlighting\n//! in code blocks.\n//!\n//! Only the variants of [`Item`] are currently supported.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::markdown;\n//! use iced::Theme;\n//!\n//! struct State {\n//!    markdown: Vec<markdown::Item>,\n//! }\n//!\n//! enum Message {\n//!     LinkClicked(markdown::Uri),\n//! }\n//!\n//! impl State {\n//!     pub fn new() -> Self {\n//!         Self {\n//!             markdown: markdown::parse(\"This is some **Markdown**!\").collect(),\n//!         }\n//!     }\n//!\n//!     fn view(&self) -> Element<'_, Message> {\n//!         markdown::view(&self.markdown, Theme::TokyoNight)\n//!             .map(Message::LinkClicked)\n//!             .into()\n//!     }\n//!\n//!     fn update(state: &mut State, message: Message) {\n//!         match message {\n//!             Message::LinkClicked(url) => {\n//!                 println!(\"The following url was clicked: {url}\");\n//!             }\n//!         }\n//!     }\n//! }\n//! ```\nuse crate::core::alignment;\nuse crate::core::border;\nuse crate::core::font::{self, Font};\nuse crate::core::padding;\nuse crate::core::theme::palette;\nuse crate::core::{self, Color, Element, Length, Padding, Pixels, Theme, color};\nuse crate::{checkbox, column, container, rich_text, row, rule, scrollable, span, text};\n\nuse std::borrow::BorrowMut;\nuse std::cell::{Cell, RefCell};\nuse std::collections::{HashMap, HashSet};\nuse std::mem;\nuse std::ops::Range;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\npub use core::text::Highlight;\npub use pulldown_cmark::HeadingLevel;\n\n/// A [`String`] representing a [URI] in a Markdown document\n///\n/// [URI]: https://en.wikipedia.org/wiki/Uniform_Resource_Identifier\npub type Uri = String;\n\n/// A bunch of Markdown that has been parsed.\n#[derive(Debug, Default)]\npub struct Content {\n    items: Vec<Item>,\n    incomplete: HashMap<usize, Section>,\n    state: State,\n}\n\n#[derive(Debug)]\nstruct Section {\n    content: String,\n    broken_links: HashSet<String>,\n}\n\nimpl Content {\n    /// Creates a new empty [`Content`].\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Creates some new [`Content`] by parsing the given Markdown.\n    pub fn parse(markdown: &str) -> Self {\n        let mut content = Self::new();\n        content.push_str(markdown);\n        content\n    }\n\n    /// Pushes more Markdown into the [`Content`]; parsing incrementally!\n    ///\n    /// This is specially useful when you have long streams of Markdown; like\n    /// big files or potentially long replies.\n    pub fn push_str(&mut self, markdown: &str) {\n        if markdown.is_empty() {\n            return;\n        }\n\n        // Append to last leftover text\n        let mut leftover = std::mem::take(&mut self.state.leftover);\n        leftover.push_str(markdown);\n\n        let input = if leftover.trim_end().ends_with('|') {\n            leftover.trim_end().trim_end_matches('|')\n        } else {\n            leftover.as_str()\n        };\n\n        // Pop the last item\n        let _ = self.items.pop();\n\n        // Re-parse last item and new text\n        for (item, source, broken_links) in parse_with(&mut self.state, input) {\n            if !broken_links.is_empty() {\n                let _ = self.incomplete.insert(\n                    self.items.len(),\n                    Section {\n                        content: source.to_owned(),\n                        broken_links,\n                    },\n                );\n            }\n\n            self.items.push(item);\n        }\n\n        self.state.leftover.push_str(&leftover[input.len()..]);\n\n        // Re-parse incomplete sections if new references are available\n        if !self.incomplete.is_empty() {\n            self.incomplete.retain(|index, section| {\n                if self.items.len() <= *index {\n                    return false;\n                }\n\n                let broken_links_before = section.broken_links.len();\n\n                section\n                    .broken_links\n                    .retain(|link| !self.state.references.contains_key(link));\n\n                if broken_links_before != section.broken_links.len() {\n                    let mut state = State {\n                        leftover: String::new(),\n                        references: self.state.references.clone(),\n                        images: HashSet::new(),\n                        #[cfg(feature = \"highlighter\")]\n                        highlighter: None,\n                    };\n\n                    if let Some((item, _source, _broken_links)) =\n                        parse_with(&mut state, &section.content).next()\n                    {\n                        self.items[*index] = item;\n                    }\n\n                    self.state.images.extend(state.images.drain());\n                    drop(state);\n                }\n\n                !section.broken_links.is_empty()\n            });\n        }\n    }\n\n    /// Returns the Markdown items, ready to be rendered.\n    ///\n    /// You can use [`view`] to turn them into an [`Element`].\n    pub fn items(&self) -> &[Item] {\n        &self.items\n    }\n\n    /// Returns the URLs of the Markdown images present in the [`Content`].\n    pub fn images(&self) -> &HashSet<Uri> {\n        &self.state.images\n    }\n}\n\n/// A Markdown item.\n#[derive(Debug, Clone)]\npub enum Item {\n    /// A heading.\n    Heading(pulldown_cmark::HeadingLevel, Text),\n    /// A paragraph.\n    Paragraph(Text),\n    /// A code block.\n    ///\n    /// You can enable the `highlighter` feature for syntax highlighting.\n    CodeBlock {\n        /// The language of the code block, if any.\n        language: Option<String>,\n        /// The raw code of the code block.\n        code: String,\n        /// The styled lines of text in the code block.\n        lines: Vec<Text>,\n    },\n    /// A list.\n    List {\n        /// The first number of the list, if it is ordered.\n        start: Option<u64>,\n        /// The items of the list.\n        bullets: Vec<Bullet>,\n    },\n    /// An image.\n    Image {\n        /// The destination URL of the image.\n        url: Uri,\n        /// The title of the image.\n        title: String,\n        /// The alternative text of the image.\n        alt: Text,\n    },\n    /// A quote.\n    Quote(Vec<Item>),\n    /// A horizontal separator.\n    Rule,\n    /// A table.\n    Table {\n        /// The columns of the table.\n        columns: Vec<Column>,\n        /// The rows of the table.\n        rows: Vec<Row>,\n    },\n}\n\n/// The column of a table.\n#[derive(Debug, Clone)]\npub struct Column {\n    /// The header of the column.\n    pub header: Vec<Item>,\n    /// The alignment of the column.\n    pub alignment: pulldown_cmark::Alignment,\n}\n\n/// The row of a table.\n#[derive(Debug, Clone)]\npub struct Row {\n    /// The cells of the row.\n    cells: Vec<Vec<Item>>,\n}\n\n/// A bunch of parsed Markdown text.\n#[derive(Debug, Clone)]\npub struct Text {\n    spans: Vec<Span>,\n    last_style: Cell<Option<Style>>,\n    last_styled_spans: RefCell<Arc<[text::Span<'static, Uri>]>>,\n}\n\nimpl Text {\n    fn new(spans: Vec<Span>) -> Self {\n        Self {\n            spans,\n            last_style: Cell::default(),\n            last_styled_spans: RefCell::default(),\n        }\n    }\n\n    /// Returns the [`rich_text()`] spans ready to be used for the given style.\n    ///\n    /// This method performs caching for you. It will only reallocate if the [`Style`]\n    /// provided changes.\n    pub fn spans(&self, style: Style) -> Arc<[text::Span<'static, Uri>]> {\n        if Some(style) != self.last_style.get() {\n            *self.last_styled_spans.borrow_mut() =\n                self.spans.iter().map(|span| span.view(&style)).collect();\n\n            self.last_style.set(Some(style));\n        }\n\n        self.last_styled_spans.borrow().clone()\n    }\n}\n\n#[derive(Debug, Clone)]\nenum Span {\n    Standard {\n        text: String,\n        strikethrough: bool,\n        link: Option<Uri>,\n        strong: bool,\n        emphasis: bool,\n        code: bool,\n    },\n    #[cfg(feature = \"highlighter\")]\n    Highlight {\n        text: String,\n        color: Option<Color>,\n        font: Option<Font>,\n    },\n}\n\nimpl Span {\n    fn view(&self, style: &Style) -> text::Span<'static, Uri> {\n        match self {\n            Span::Standard {\n                text,\n                strikethrough,\n                link,\n                strong,\n                emphasis,\n                code,\n            } => {\n                let span = span(text.clone()).strikethrough(*strikethrough);\n\n                let span = if *code {\n                    span.font(style.inline_code_font)\n                        .color(style.inline_code_color)\n                        .background(style.inline_code_highlight.background)\n                        .border(style.inline_code_highlight.border)\n                        .padding(style.inline_code_padding)\n                } else if *strong || *emphasis {\n                    span.font(Font {\n                        weight: if *strong {\n                            font::Weight::Bold\n                        } else {\n                            font::Weight::Normal\n                        },\n                        style: if *emphasis {\n                            font::Style::Italic\n                        } else {\n                            font::Style::Normal\n                        },\n                        ..style.font\n                    })\n                } else {\n                    span.font(style.font)\n                };\n\n                if let Some(link) = link.as_ref() {\n                    span.color(style.link_color).link(link.clone())\n                } else {\n                    span\n                }\n            }\n            #[cfg(feature = \"highlighter\")]\n            Span::Highlight { text, color, font } => {\n                span(text.clone()).color_maybe(*color).font_maybe(*font)\n            }\n        }\n    }\n}\n\n/// The item of a list.\n#[derive(Debug, Clone)]\npub enum Bullet {\n    /// A simple bullet point.\n    Point {\n        /// The contents of the bullet point.\n        items: Vec<Item>,\n    },\n    /// A task.\n    Task {\n        /// The contents of the task.\n        items: Vec<Item>,\n        /// Whether the task is done or not.\n        done: bool,\n    },\n}\n\nimpl Bullet {\n    fn items(&self) -> &[Item] {\n        match self {\n            Bullet::Point { items } | Bullet::Task { items, .. } => items,\n        }\n    }\n\n    fn push(&mut self, item: Item) {\n        let (Bullet::Point { items } | Bullet::Task { items, .. }) = self;\n\n        items.push(item);\n    }\n}\n\n/// Parse the given Markdown content.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::markdown;\n/// use iced::Theme;\n///\n/// struct State {\n///    markdown: Vec<markdown::Item>,\n/// }\n///\n/// enum Message {\n///     LinkClicked(markdown::Uri),\n/// }\n///\n/// impl State {\n///     pub fn new() -> Self {\n///         Self {\n///             markdown: markdown::parse(\"This is some **Markdown**!\").collect(),\n///         }\n///     }\n///\n///     fn view(&self) -> Element<'_, Message> {\n///         markdown::view(&self.markdown, Theme::TokyoNight)\n///             .map(Message::LinkClicked)\n///             .into()\n///     }\n///\n///     fn update(state: &mut State, message: Message) {\n///         match message {\n///             Message::LinkClicked(url) => {\n///                 println!(\"The following url was clicked: {url}\");\n///             }\n///         }\n///     }\n/// }\n/// ```\npub fn parse(markdown: &str) -> impl Iterator<Item = Item> + '_ {\n    parse_with(State::default(), markdown).map(|(item, _source, _broken_links)| item)\n}\n\n#[derive(Debug, Default)]\nstruct State {\n    leftover: String,\n    references: HashMap<String, String>,\n    images: HashSet<Uri>,\n    #[cfg(feature = \"highlighter\")]\n    highlighter: Option<Highlighter>,\n}\n\n#[cfg(feature = \"highlighter\")]\n#[derive(Debug)]\nstruct Highlighter {\n    lines: Vec<(String, Vec<Span>)>,\n    language: String,\n    parser: iced_highlighter::Stream,\n    current: usize,\n}\n\n#[cfg(feature = \"highlighter\")]\nimpl Highlighter {\n    pub fn new(language: &str) -> Self {\n        Self {\n            lines: Vec::new(),\n            parser: iced_highlighter::Stream::new(&iced_highlighter::Settings {\n                theme: iced_highlighter::Theme::Base16Ocean,\n                token: language.to_owned(),\n            }),\n            language: language.to_owned(),\n            current: 0,\n        }\n    }\n\n    pub fn prepare(&mut self) {\n        self.current = 0;\n    }\n\n    pub fn highlight_line(&mut self, text: &str) -> &[Span] {\n        match self.lines.get(self.current) {\n            Some(line) if line.0 == text => {}\n            _ => {\n                if self.current + 1 < self.lines.len() {\n                    log::debug!(\"Resetting highlighter...\");\n                    self.parser.reset();\n                    self.lines.truncate(self.current);\n\n                    for line in &self.lines {\n                        log::debug!(\"Refeeding {n} lines\", n = self.lines.len());\n\n                        let _ = self.parser.highlight_line(&line.0);\n                    }\n                }\n\n                log::trace!(\"Parsing: {text}\", text = text.trim_end());\n\n                if self.current + 1 < self.lines.len() {\n                    self.parser.commit();\n                }\n\n                let mut spans = Vec::new();\n\n                for (range, highlight) in self.parser.highlight_line(text) {\n                    spans.push(Span::Highlight {\n                        text: text[range].to_owned(),\n                        color: highlight.color(),\n                        font: highlight.font(),\n                    });\n                }\n\n                if self.current + 1 == self.lines.len() {\n                    let _ = self.lines.pop();\n                }\n\n                self.lines.push((text.to_owned(), spans));\n            }\n        }\n\n        self.current += 1;\n\n        &self\n            .lines\n            .get(self.current - 1)\n            .expect(\"Line must be parsed\")\n            .1\n    }\n}\n\nfn parse_with<'a>(\n    mut state: impl BorrowMut<State> + 'a,\n    markdown: &'a str,\n) -> impl Iterator<Item = (Item, &'a str, HashSet<String>)> + 'a {\n    enum Scope {\n        List(List),\n        Quote(Vec<Item>),\n        Table {\n            alignment: Vec<pulldown_cmark::Alignment>,\n            columns: Vec<Column>,\n            rows: Vec<Row>,\n            current: Vec<Item>,\n        },\n    }\n\n    struct List {\n        start: Option<u64>,\n        bullets: Vec<Bullet>,\n    }\n\n    let broken_links = Rc::new(RefCell::new(HashSet::new()));\n\n    let mut spans = Vec::new();\n    let mut code = String::new();\n    let mut code_language = None;\n    let mut code_lines = Vec::new();\n    let mut strong = false;\n    let mut emphasis = false;\n    let mut strikethrough = false;\n    let mut metadata = false;\n    let mut code_block = false;\n    let mut link = None;\n    let mut image = None;\n    let mut stack = Vec::new();\n\n    #[cfg(feature = \"highlighter\")]\n    let mut highlighter = None;\n\n    let parser = pulldown_cmark::Parser::new_with_broken_link_callback(\n        markdown,\n        pulldown_cmark::Options::ENABLE_YAML_STYLE_METADATA_BLOCKS\n            | pulldown_cmark::Options::ENABLE_PLUSES_DELIMITED_METADATA_BLOCKS\n            | pulldown_cmark::Options::ENABLE_TABLES\n            | pulldown_cmark::Options::ENABLE_STRIKETHROUGH\n            | pulldown_cmark::Options::ENABLE_TASKLISTS,\n        {\n            let references = state.borrow().references.clone();\n            let broken_links = broken_links.clone();\n\n            Some(move |broken_link: pulldown_cmark::BrokenLink<'_>| {\n                if let Some(reference) = references.get(broken_link.reference.as_ref()) {\n                    Some((\n                        pulldown_cmark::CowStr::from(reference.to_owned()),\n                        broken_link.reference.into_static(),\n                    ))\n                } else {\n                    let _ = RefCell::borrow_mut(&broken_links)\n                        .insert(broken_link.reference.into_string());\n\n                    None\n                }\n            })\n        },\n    );\n\n    let references = &mut state.borrow_mut().references;\n\n    for reference in parser.reference_definitions().iter() {\n        let _ = references.insert(reference.0.to_owned(), reference.1.dest.to_string());\n    }\n\n    let produce = move |state: &mut State, stack: &mut Vec<Scope>, item, source: Range<usize>| {\n        if let Some(scope) = stack.last_mut() {\n            match scope {\n                Scope::List(list) => {\n                    list.bullets.last_mut().expect(\"item context\").push(item);\n                }\n                Scope::Quote(items) => {\n                    items.push(item);\n                }\n                Scope::Table { current, .. } => {\n                    current.push(item);\n                }\n            }\n\n            None\n        } else {\n            state.leftover = markdown[source.start..].to_owned();\n\n            Some((\n                item,\n                &markdown[source.start..source.end],\n                broken_links.take(),\n            ))\n        }\n    };\n\n    let parser = parser.into_offset_iter();\n\n    // We want to keep the `spans` capacity\n    #[allow(clippy::drain_collect)]\n    parser.filter_map(move |(event, source)| match event {\n        pulldown_cmark::Event::Start(tag) => match tag {\n            pulldown_cmark::Tag::Strong if !metadata => {\n                strong = true;\n                None\n            }\n            pulldown_cmark::Tag::Emphasis if !metadata => {\n                emphasis = true;\n                None\n            }\n            pulldown_cmark::Tag::Strikethrough if !metadata => {\n                strikethrough = true;\n                None\n            }\n            pulldown_cmark::Tag::Link { dest_url, .. } if !metadata => {\n                link = Some(dest_url.into_string());\n                None\n            }\n            pulldown_cmark::Tag::Image {\n                dest_url, title, ..\n            } if !metadata => {\n                image = Some((dest_url.into_string(), title.into_string()));\n                None\n            }\n            pulldown_cmark::Tag::List(first_item) if !metadata => {\n                let prev = if spans.is_empty() {\n                    None\n                } else {\n                    produce(\n                        state.borrow_mut(),\n                        &mut stack,\n                        Item::Paragraph(Text::new(spans.drain(..).collect())),\n                        source,\n                    )\n                };\n\n                stack.push(Scope::List(List {\n                    start: first_item,\n                    bullets: Vec::new(),\n                }));\n\n                prev\n            }\n            pulldown_cmark::Tag::Item => {\n                if let Some(Scope::List(list)) = stack.last_mut() {\n                    list.bullets.push(Bullet::Point { items: Vec::new() });\n                }\n\n                None\n            }\n            pulldown_cmark::Tag::BlockQuote(_kind) if !metadata => {\n                let prev = if spans.is_empty() {\n                    None\n                } else {\n                    produce(\n                        state.borrow_mut(),\n                        &mut stack,\n                        Item::Paragraph(Text::new(spans.drain(..).collect())),\n                        source,\n                    )\n                };\n\n                stack.push(Scope::Quote(Vec::new()));\n\n                prev\n            }\n            pulldown_cmark::Tag::CodeBlock(pulldown_cmark::CodeBlockKind::Fenced(language))\n                if !metadata =>\n            {\n                #[cfg(feature = \"highlighter\")]\n                {\n                    highlighter = Some({\n                        let mut highlighter = state\n                            .borrow_mut()\n                            .highlighter\n                            .take()\n                            .filter(|highlighter| highlighter.language == language.as_ref())\n                            .unwrap_or_else(|| {\n                                Highlighter::new(language.split(',').next().unwrap_or_default())\n                            });\n\n                        highlighter.prepare();\n\n                        highlighter\n                    });\n                }\n\n                code_block = true;\n                code_language = (!language.is_empty()).then(|| language.into_string());\n\n                if spans.is_empty() {\n                    None\n                } else {\n                    produce(\n                        state.borrow_mut(),\n                        &mut stack,\n                        Item::Paragraph(Text::new(spans.drain(..).collect())),\n                        source,\n                    )\n                }\n            }\n            pulldown_cmark::Tag::MetadataBlock(_) => {\n                metadata = true;\n                None\n            }\n            pulldown_cmark::Tag::Table(alignment) => {\n                stack.push(Scope::Table {\n                    columns: Vec::with_capacity(alignment.len()),\n                    alignment,\n                    current: Vec::new(),\n                    rows: Vec::new(),\n                });\n\n                None\n            }\n            pulldown_cmark::Tag::TableHead => {\n                strong = true;\n                None\n            }\n            pulldown_cmark::Tag::TableRow => {\n                let Scope::Table { rows, .. } = stack.last_mut()? else {\n                    return None;\n                };\n\n                rows.push(Row { cells: Vec::new() });\n                None\n            }\n            _ => None,\n        },\n        pulldown_cmark::Event::End(tag) => match tag {\n            pulldown_cmark::TagEnd::Heading(level) if !metadata => produce(\n                state.borrow_mut(),\n                &mut stack,\n                Item::Heading(level, Text::new(spans.drain(..).collect())),\n                source,\n            ),\n            pulldown_cmark::TagEnd::Strong if !metadata => {\n                strong = false;\n                None\n            }\n            pulldown_cmark::TagEnd::Emphasis if !metadata => {\n                emphasis = false;\n                None\n            }\n            pulldown_cmark::TagEnd::Strikethrough if !metadata => {\n                strikethrough = false;\n                None\n            }\n            pulldown_cmark::TagEnd::Link if !metadata => {\n                link = None;\n                None\n            }\n            pulldown_cmark::TagEnd::Paragraph if !metadata => {\n                if spans.is_empty() {\n                    None\n                } else {\n                    produce(\n                        state.borrow_mut(),\n                        &mut stack,\n                        Item::Paragraph(Text::new(spans.drain(..).collect())),\n                        source,\n                    )\n                }\n            }\n            pulldown_cmark::TagEnd::Item if !metadata => {\n                if spans.is_empty() {\n                    None\n                } else {\n                    produce(\n                        state.borrow_mut(),\n                        &mut stack,\n                        Item::Paragraph(Text::new(spans.drain(..).collect())),\n                        source,\n                    )\n                }\n            }\n            pulldown_cmark::TagEnd::List(_) if !metadata => {\n                let scope = stack.pop()?;\n\n                let Scope::List(list) = scope else {\n                    return None;\n                };\n\n                produce(\n                    state.borrow_mut(),\n                    &mut stack,\n                    Item::List {\n                        start: list.start,\n                        bullets: list.bullets,\n                    },\n                    source,\n                )\n            }\n            pulldown_cmark::TagEnd::BlockQuote(_kind) if !metadata => {\n                let scope = stack.pop()?;\n\n                let Scope::Quote(quote) = scope else {\n                    return None;\n                };\n\n                produce(state.borrow_mut(), &mut stack, Item::Quote(quote), source)\n            }\n            pulldown_cmark::TagEnd::Image if !metadata => {\n                let (url, title) = image.take()?;\n                let alt = Text::new(spans.drain(..).collect());\n\n                let state = state.borrow_mut();\n                let _ = state.images.insert(url.clone());\n\n                produce(state, &mut stack, Item::Image { url, title, alt }, source)\n            }\n            pulldown_cmark::TagEnd::CodeBlock if !metadata => {\n                code_block = false;\n\n                #[cfg(feature = \"highlighter\")]\n                {\n                    state.borrow_mut().highlighter = highlighter.take();\n                }\n\n                produce(\n                    state.borrow_mut(),\n                    &mut stack,\n                    Item::CodeBlock {\n                        language: code_language.take(),\n                        code: mem::take(&mut code),\n                        lines: code_lines.drain(..).collect(),\n                    },\n                    source,\n                )\n            }\n            pulldown_cmark::TagEnd::MetadataBlock(_) => {\n                metadata = false;\n                None\n            }\n            pulldown_cmark::TagEnd::Table => {\n                let scope = stack.pop()?;\n\n                let Scope::Table { columns, rows, .. } = scope else {\n                    return None;\n                };\n\n                produce(\n                    state.borrow_mut(),\n                    &mut stack,\n                    Item::Table { columns, rows },\n                    source,\n                )\n            }\n            pulldown_cmark::TagEnd::TableHead => {\n                strong = false;\n                None\n            }\n            pulldown_cmark::TagEnd::TableCell => {\n                if !spans.is_empty() {\n                    let _ = produce(\n                        state.borrow_mut(),\n                        &mut stack,\n                        Item::Paragraph(Text::new(spans.drain(..).collect())),\n                        source,\n                    );\n                }\n\n                let Scope::Table {\n                    alignment,\n                    columns,\n                    rows,\n                    current,\n                } = stack.last_mut()?\n                else {\n                    return None;\n                };\n\n                if columns.len() < alignment.len() {\n                    columns.push(Column {\n                        header: std::mem::take(current),\n                        alignment: alignment[columns.len()],\n                    });\n                } else {\n                    rows.last_mut()\n                        .expect(\"table row\")\n                        .cells\n                        .push(std::mem::take(current));\n                }\n\n                None\n            }\n            _ => None,\n        },\n        pulldown_cmark::Event::Text(text) if !metadata => {\n            if code_block {\n                code.push_str(&text);\n\n                #[cfg(feature = \"highlighter\")]\n                if let Some(highlighter) = &mut highlighter {\n                    for line in text.lines() {\n                        code_lines.push(Text::new(highlighter.highlight_line(line).to_vec()));\n                    }\n                }\n\n                #[cfg(not(feature = \"highlighter\"))]\n                for line in text.lines() {\n                    code_lines.push(Text::new(vec![Span::Standard {\n                        text: line.to_owned(),\n                        strong,\n                        emphasis,\n                        strikethrough,\n                        link: link.clone(),\n                        code: false,\n                    }]));\n                }\n\n                return None;\n            }\n\n            let span = Span::Standard {\n                text: text.into_string(),\n                strong,\n                emphasis,\n                strikethrough,\n                link: link.clone(),\n                code: false,\n            };\n\n            spans.push(span);\n\n            None\n        }\n        pulldown_cmark::Event::Code(code) if !metadata => {\n            let span = Span::Standard {\n                text: code.into_string(),\n                strong,\n                emphasis,\n                strikethrough,\n                link: link.clone(),\n                code: true,\n            };\n\n            spans.push(span);\n            None\n        }\n        pulldown_cmark::Event::SoftBreak if !metadata => {\n            spans.push(Span::Standard {\n                text: String::from(\" \"),\n                strikethrough,\n                strong,\n                emphasis,\n                link: link.clone(),\n                code: false,\n            });\n            None\n        }\n        pulldown_cmark::Event::HardBreak if !metadata => {\n            spans.push(Span::Standard {\n                text: String::from(\"\\n\"),\n                strikethrough,\n                strong,\n                emphasis,\n                link: link.clone(),\n                code: false,\n            });\n            None\n        }\n        pulldown_cmark::Event::Rule => produce(state.borrow_mut(), &mut stack, Item::Rule, source),\n        pulldown_cmark::Event::TaskListMarker(done) => {\n            if let Some(Scope::List(list)) = stack.last_mut()\n                && let Some(item) = list.bullets.last_mut()\n                && let Bullet::Point { items } = item\n            {\n                *item = Bullet::Task {\n                    items: std::mem::take(items),\n                    done,\n                };\n            }\n\n            None\n        }\n        _ => None,\n    })\n}\n\n/// Configuration controlling Markdown rendering in [`view`].\n#[derive(Debug, Clone, Copy)]\npub struct Settings {\n    /// The base text size.\n    pub text_size: Pixels,\n    /// The text size of level 1 heading.\n    pub h1_size: Pixels,\n    /// The text size of level 2 heading.\n    pub h2_size: Pixels,\n    /// The text size of level 3 heading.\n    pub h3_size: Pixels,\n    /// The text size of level 4 heading.\n    pub h4_size: Pixels,\n    /// The text size of level 5 heading.\n    pub h5_size: Pixels,\n    /// The text size of level 6 heading.\n    pub h6_size: Pixels,\n    /// The text size used in code blocks.\n    pub code_size: Pixels,\n    /// The spacing to be used between elements.\n    pub spacing: Pixels,\n    /// The styling of the Markdown.\n    pub style: Style,\n}\n\nimpl Settings {\n    /// Creates new [`Settings`] with default text size and the given [`Style`].\n    pub fn with_style(style: impl Into<Style>) -> Self {\n        Self::with_text_size(16, style)\n    }\n\n    /// Creates new [`Settings`] with the given base text size in [`Pixels`].\n    ///\n    /// Heading levels will be adjusted automatically. Specifically,\n    /// the first level will be twice the base size, and then every level\n    /// after that will be 25% smaller.\n    pub fn with_text_size(text_size: impl Into<Pixels>, style: impl Into<Style>) -> Self {\n        let text_size = text_size.into();\n\n        Self {\n            text_size,\n            h1_size: text_size * 2.0,\n            h2_size: text_size * 1.75,\n            h3_size: text_size * 1.5,\n            h4_size: text_size * 1.25,\n            h5_size: text_size,\n            h6_size: text_size,\n            code_size: text_size * 0.75,\n            spacing: text_size * 0.875,\n            style: style.into(),\n        }\n    }\n}\n\nimpl From<&Theme> for Settings {\n    fn from(theme: &Theme) -> Self {\n        Self::with_style(Style::from(theme))\n    }\n}\n\nimpl From<Theme> for Settings {\n    fn from(theme: Theme) -> Self {\n        Self::with_style(Style::from(theme))\n    }\n}\n\n/// The text styling of some Markdown rendering in [`view`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`Font`] to be applied to basic text.\n    pub font: Font,\n    /// The [`Highlight`] to be applied to the background of inline code.\n    pub inline_code_highlight: Highlight,\n    /// The [`Padding`] to be applied to the background of inline code.\n    pub inline_code_padding: Padding,\n    /// The [`Color`] to be applied to inline code.\n    pub inline_code_color: Color,\n    /// The [`Font`] to be applied to inline code.\n    pub inline_code_font: Font,\n    /// The [`Font`] to be applied to code blocks.\n    pub code_block_font: Font,\n    /// The [`Color`] to be applied to links.\n    pub link_color: Color,\n}\n\nimpl Style {\n    /// Creates a new [`Style`] from the given [`palette::Seed`].\n    pub fn from_palette(seed: palette::Seed) -> Self {\n        Self {\n            font: Font::default(),\n            inline_code_padding: padding::left(1).right(1),\n            inline_code_highlight: Highlight {\n                background: color!(0x111111).into(),\n                border: border::rounded(4),\n            },\n            inline_code_color: Color::WHITE,\n            inline_code_font: Font::MONOSPACE,\n            code_block_font: Font::MONOSPACE,\n            link_color: seed.primary,\n        }\n    }\n}\n\nimpl From<palette::Seed> for Style {\n    fn from(seed: palette::Seed) -> Self {\n        Self::from_palette(seed)\n    }\n}\n\nimpl From<&Theme> for Style {\n    fn from(theme: &Theme) -> Self {\n        Self::from_palette(theme.seed())\n    }\n}\n\nimpl From<Theme> for Style {\n    fn from(theme: Theme) -> Self {\n        Self::from_palette(theme.seed())\n    }\n}\n\n/// Display a bunch of Markdown items.\n///\n/// You can obtain the items with [`parse`].\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::markdown;\n/// use iced::Theme;\n///\n/// struct State {\n///    markdown: Vec<markdown::Item>,\n/// }\n///\n/// enum Message {\n///     LinkClicked(markdown::Uri),\n/// }\n///\n/// impl State {\n///     pub fn new() -> Self {\n///         Self {\n///             markdown: markdown::parse(\"This is some **Markdown**!\").collect(),\n///         }\n///     }\n///\n///     fn view(&self) -> Element<'_, Message> {\n///         markdown::view(&self.markdown, Theme::TokyoNight)\n///             .map(Message::LinkClicked)\n///             .into()\n///     }\n///\n///     fn update(state: &mut State, message: Message) {\n///         match message {\n///             Message::LinkClicked(url) => {\n///                 println!(\"The following url was clicked: {url}\");\n///             }\n///         }\n///     }\n/// }\n/// ```\npub fn view<'a, Theme, Renderer>(\n    items: impl IntoIterator<Item = &'a Item>,\n    settings: impl Into<Settings>,\n) -> Element<'a, Uri, Theme, Renderer>\nwhere\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    view_with(items, settings, &DefaultViewer)\n}\n\n/// Runs [`view`] but with a custom [`Viewer`] to turn an [`Item`] into\n/// an [`Element`].\n///\n/// This is useful if you want to customize the look of certain Markdown\n/// elements.\npub fn view_with<'a, Message, Theme, Renderer>(\n    items: impl IntoIterator<Item = &'a Item>,\n    settings: impl Into<Settings>,\n    viewer: &impl Viewer<'a, Message, Theme, Renderer>,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    let settings = settings.into();\n\n    let blocks = items\n        .into_iter()\n        .enumerate()\n        .map(|(i, item_)| item(viewer, settings, item_, i));\n\n    Element::new(column(blocks).spacing(settings.spacing))\n}\n\n/// Displays an [`Item`] using the given [`Viewer`].\npub fn item<'a, Message, Theme, Renderer>(\n    viewer: &impl Viewer<'a, Message, Theme, Renderer>,\n    settings: Settings,\n    item: &'a Item,\n    index: usize,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    match item {\n        Item::Image { url, title, alt } => viewer.image(settings, url, title, alt),\n        Item::Heading(level, text) => viewer.heading(settings, level, text, index),\n        Item::Paragraph(text) => viewer.paragraph(settings, text),\n        Item::CodeBlock {\n            language,\n            code,\n            lines,\n        } => viewer.code_block(settings, language.as_deref(), code, lines),\n        Item::List {\n            start: None,\n            bullets,\n        } => viewer.unordered_list(settings, bullets),\n        Item::List {\n            start: Some(start),\n            bullets,\n        } => viewer.ordered_list(settings, *start, bullets),\n        Item::Quote(quote) => viewer.quote(settings, quote),\n        Item::Rule => viewer.rule(settings),\n        Item::Table { columns, rows } => viewer.table(settings, columns, rows),\n    }\n}\n\n/// Displays a heading using the default look.\npub fn heading<'a, Message, Theme, Renderer>(\n    settings: Settings,\n    level: &'a HeadingLevel,\n    text: &'a Text,\n    index: usize,\n    on_link_click: impl Fn(Uri) -> Message + 'a,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    let Settings {\n        h1_size,\n        h2_size,\n        h3_size,\n        h4_size,\n        h5_size,\n        h6_size,\n        text_size,\n        ..\n    } = settings;\n\n    container(\n        rich_text(text.spans(settings.style))\n            .on_link_click(on_link_click)\n            .size(match level {\n                pulldown_cmark::HeadingLevel::H1 => h1_size,\n                pulldown_cmark::HeadingLevel::H2 => h2_size,\n                pulldown_cmark::HeadingLevel::H3 => h3_size,\n                pulldown_cmark::HeadingLevel::H4 => h4_size,\n                pulldown_cmark::HeadingLevel::H5 => h5_size,\n                pulldown_cmark::HeadingLevel::H6 => h6_size,\n            }),\n    )\n    .padding(padding::top(if index > 0 {\n        text_size / 2.0\n    } else {\n        Pixels::ZERO\n    }))\n    .into()\n}\n\n/// Displays a paragraph using the default look.\npub fn paragraph<'a, Message, Theme, Renderer>(\n    settings: Settings,\n    text: &Text,\n    on_link_click: impl Fn(Uri) -> Message + 'a,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    rich_text(text.spans(settings.style))\n        .size(settings.text_size)\n        .on_link_click(on_link_click)\n        .into()\n}\n\n/// Displays an unordered list using the default look and\n/// calling the [`Viewer`] for each bullet point item.\npub fn unordered_list<'a, Message, Theme, Renderer>(\n    viewer: &impl Viewer<'a, Message, Theme, Renderer>,\n    settings: Settings,\n    bullets: &'a [Bullet],\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    column(bullets.iter().map(|bullet| {\n        row![\n            match bullet {\n                Bullet::Point { .. } => {\n                    text(\"•\").size(settings.text_size).into()\n                }\n                Bullet::Task { done, .. } => {\n                    Element::from(\n                        container(checkbox(*done).size(settings.text_size))\n                            .center_y(text::LineHeight::default().to_absolute(settings.text_size)),\n                    )\n                }\n            },\n            view_with(\n                bullet.items(),\n                Settings {\n                    spacing: settings.spacing * 0.6,\n                    ..settings\n                },\n                viewer,\n            )\n        ]\n        .spacing(settings.spacing)\n        .into()\n    }))\n    .spacing(settings.spacing * 0.75)\n    .padding([0.0, settings.spacing.0])\n    .into()\n}\n\n/// Displays an ordered list using the default look and\n/// calling the [`Viewer`] for each numbered item.\npub fn ordered_list<'a, Message, Theme, Renderer>(\n    viewer: &impl Viewer<'a, Message, Theme, Renderer>,\n    settings: Settings,\n    start: u64,\n    bullets: &'a [Bullet],\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    let digits = (start + bullets.len() as u64).max(1).ilog10() + 1;\n\n    column(bullets.iter().enumerate().map(|(i, bullet)| {\n        row![\n            text!(\"{}.\", i as u64 + start)\n                .size(settings.text_size)\n                .align_x(alignment::Horizontal::Right)\n                .width(settings.text_size * ((digits as f32 / 2.0).ceil() + 1.0)),\n            view_with(\n                bullet.items(),\n                Settings {\n                    spacing: settings.spacing * 0.6,\n                    ..settings\n                },\n                viewer,\n            )\n        ]\n        .spacing(settings.spacing)\n        .into()\n    }))\n    .spacing(settings.spacing * 0.75)\n    .into()\n}\n\n/// Displays a code block using the default look.\npub fn code_block<'a, Message, Theme, Renderer>(\n    settings: Settings,\n    lines: &'a [Text],\n    on_link_click: impl Fn(Uri) -> Message + Clone + 'a,\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    container(\n        scrollable(\n            container(column(lines.iter().map(|line| {\n                rich_text(line.spans(settings.style))\n                    .on_link_click(on_link_click.clone())\n                    .font(settings.style.code_block_font)\n                    .size(settings.code_size)\n                    .into()\n            })))\n            .padding(settings.code_size),\n        )\n        .direction(scrollable::Direction::Horizontal(\n            scrollable::Scrollbar::default()\n                .width(settings.code_size / 2)\n                .scroller_width(settings.code_size / 2),\n        )),\n    )\n    .width(Length::Fill)\n    .padding(settings.code_size / 4)\n    .class(Theme::code_block())\n    .into()\n}\n\n/// Displays a quote using the default look.\npub fn quote<'a, Message, Theme, Renderer>(\n    viewer: &impl Viewer<'a, Message, Theme, Renderer>,\n    settings: Settings,\n    contents: &'a [Item],\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    row![\n        rule::vertical(4),\n        column(\n            contents\n                .iter()\n                .enumerate()\n                .map(|(i, content)| item(viewer, settings, content, i)),\n        )\n        .spacing(settings.spacing.0),\n    ]\n    .height(Length::Shrink)\n    .spacing(settings.spacing.0)\n    .into()\n}\n\n/// Displays a rule using the default look.\npub fn rule<'a, Message, Theme, Renderer>() -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    rule::horizontal(2).into()\n}\n\n/// Displays a table using the default look.\npub fn table<'a, Message, Theme, Renderer>(\n    viewer: &impl Viewer<'a, Message, Theme, Renderer>,\n    settings: Settings,\n    columns: &'a [Column],\n    rows: &'a [Row],\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    use crate::table;\n\n    let table = table(\n        columns.iter().enumerate().map(move |(i, column)| {\n            table::column(items(viewer, settings, &column.header), move |row: &Row| {\n                if let Some(cells) = row.cells.get(i) {\n                    items(viewer, settings, cells)\n                } else {\n                    text(\"\").into()\n                }\n            })\n            .align_x(match column.alignment {\n                pulldown_cmark::Alignment::None | pulldown_cmark::Alignment::Left => {\n                    alignment::Horizontal::Left\n                }\n                pulldown_cmark::Alignment::Center => alignment::Horizontal::Center,\n                pulldown_cmark::Alignment::Right => alignment::Horizontal::Right,\n            })\n        }),\n        rows,\n    )\n    .padding_x(settings.spacing.0)\n    .padding_y(settings.spacing.0 / 2.0)\n    .separator_x(0);\n\n    scrollable(table)\n        .direction(scrollable::Direction::Horizontal(\n            scrollable::Scrollbar::default(),\n        ))\n        .spacing(settings.spacing.0 / 2.0)\n        .into()\n}\n\n/// Displays a column of items with the default look.\npub fn items<'a, Message, Theme, Renderer>(\n    viewer: &impl Viewer<'a, Message, Theme, Renderer>,\n    settings: Settings,\n    items: &'a [Item],\n) -> Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    column(\n        items\n            .iter()\n            .enumerate()\n            .map(|(i, content)| item(viewer, settings, content, i)),\n    )\n    .spacing(settings.spacing.0)\n    .into()\n}\n\n/// A view strategy to display a Markdown [`Item`].\npub trait Viewer<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Self: Sized + 'a,\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    /// Produces a message when a link is clicked with the given [`Uri`].\n    fn on_link_click(url: Uri) -> Message;\n\n    /// Displays an image.\n    ///\n    /// By default, it will show a container with the image title.\n    fn image(\n        &self,\n        settings: Settings,\n        url: &'a Uri,\n        title: &'a str,\n        alt: &Text,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        let _url = url;\n        let _title = title;\n\n        container(rich_text(alt.spans(settings.style)).on_link_click(Self::on_link_click))\n            .padding(settings.spacing.0)\n            .class(Theme::code_block())\n            .into()\n    }\n\n    /// Displays a heading.\n    ///\n    /// By default, it calls [`heading`].\n    fn heading(\n        &self,\n        settings: Settings,\n        level: &'a HeadingLevel,\n        text: &'a Text,\n        index: usize,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        heading(settings, level, text, index, Self::on_link_click)\n    }\n\n    /// Displays a paragraph.\n    ///\n    /// By default, it calls [`paragraph`].\n    fn paragraph(&self, settings: Settings, text: &Text) -> Element<'a, Message, Theme, Renderer> {\n        paragraph(settings, text, Self::on_link_click)\n    }\n\n    /// Displays a code block.\n    ///\n    /// By default, it calls [`code_block`].\n    fn code_block(\n        &self,\n        settings: Settings,\n        language: Option<&'a str>,\n        code: &'a str,\n        lines: &'a [Text],\n    ) -> Element<'a, Message, Theme, Renderer> {\n        let _language = language;\n        let _code = code;\n\n        code_block(settings, lines, Self::on_link_click)\n    }\n\n    /// Displays an unordered list.\n    ///\n    /// By default, it calls [`unordered_list`].\n    fn unordered_list(\n        &self,\n        settings: Settings,\n        bullets: &'a [Bullet],\n    ) -> Element<'a, Message, Theme, Renderer> {\n        unordered_list(self, settings, bullets)\n    }\n\n    /// Displays an ordered list.\n    ///\n    /// By default, it calls [`ordered_list`].\n    fn ordered_list(\n        &self,\n        settings: Settings,\n        start: u64,\n        bullets: &'a [Bullet],\n    ) -> Element<'a, Message, Theme, Renderer> {\n        ordered_list(self, settings, start, bullets)\n    }\n\n    /// Displays a quote.\n    ///\n    /// By default, it calls [`quote`].\n    fn quote(\n        &self,\n        settings: Settings,\n        contents: &'a [Item],\n    ) -> Element<'a, Message, Theme, Renderer> {\n        quote(self, settings, contents)\n    }\n\n    /// Displays a rule.\n    ///\n    /// By default, it calls [`rule`](self::rule()).\n    fn rule(&self, _settings: Settings) -> Element<'a, Message, Theme, Renderer> {\n        rule()\n    }\n\n    /// Displays a table.\n    ///\n    /// By default, it calls [`table`].\n    fn table(\n        &self,\n        settings: Settings,\n        columns: &'a [Column],\n        rows: &'a [Row],\n    ) -> Element<'a, Message, Theme, Renderer> {\n        table(self, settings, columns, rows)\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\nstruct DefaultViewer;\n\nimpl<'a, Theme, Renderer> Viewer<'a, Uri, Theme, Renderer> for DefaultViewer\nwhere\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer<Font = Font> + 'a,\n{\n    fn on_link_click(url: Uri) -> Uri {\n        url\n    }\n}\n\n/// The theme catalog of Markdown items.\npub trait Catalog:\n    container::Catalog\n    + scrollable::Catalog\n    + text::Catalog\n    + crate::rule::Catalog\n    + checkbox::Catalog\n    + crate::table::Catalog\n{\n    /// The styling class of a Markdown code block.\n    fn code_block<'a>() -> <Self as container::Catalog>::Class<'a>;\n}\n\nimpl Catalog for Theme {\n    fn code_block<'a>() -> <Self as container::Catalog>::Class<'a> {\n        Box::new(container::dark)\n    }\n}\n"
  },
  {
    "path": "widget/src/mouse_area.rs",
    "content": "//! A container for capturing mouse events.\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::touch;\nuse crate::core::widget::{Operation, Tree, tree};\nuse crate::core::{Element, Event, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget};\n\n/// Emit messages on mouse events.\npub struct MouseArea<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    content: Element<'a, Message, Theme, Renderer>,\n    on_press: Option<Message>,\n    on_release: Option<Message>,\n    on_double_click: Option<Message>,\n    on_right_press: Option<Message>,\n    on_right_release: Option<Message>,\n    on_middle_press: Option<Message>,\n    on_middle_release: Option<Message>,\n    on_scroll: Option<Box<dyn Fn(mouse::ScrollDelta) -> Message + 'a>>,\n    on_enter: Option<Message>,\n    on_move: Option<Box<dyn Fn(Point) -> Message + 'a>>,\n    on_exit: Option<Message>,\n    interaction: Option<mouse::Interaction>,\n}\n\nimpl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {\n    /// The message to emit on a left button press.\n    #[must_use]\n    pub fn on_press(mut self, message: Message) -> Self {\n        self.on_press = Some(message);\n        self\n    }\n\n    /// The message to emit on a left button release.\n    #[must_use]\n    pub fn on_release(mut self, message: Message) -> Self {\n        self.on_release = Some(message);\n        self\n    }\n\n    /// The message to emit on a double click.\n    ///\n    /// If you use this with [`on_press`]/[`on_release`], those\n    /// event will be emit as normal.\n    ///\n    /// The events stream will be: on_press -> on_release -> on_press\n    /// -> on_double_click -> on_release -> on_press ...\n    ///\n    /// [`on_press`]: Self::on_press\n    /// [`on_release`]: Self::on_release\n    #[must_use]\n    pub fn on_double_click(mut self, message: Message) -> Self {\n        self.on_double_click = Some(message);\n        self\n    }\n\n    /// The message to emit on a right button press.\n    #[must_use]\n    pub fn on_right_press(mut self, message: Message) -> Self {\n        self.on_right_press = Some(message);\n        self\n    }\n\n    /// The message to emit on a right button release.\n    #[must_use]\n    pub fn on_right_release(mut self, message: Message) -> Self {\n        self.on_right_release = Some(message);\n        self\n    }\n\n    /// The message to emit on a middle button press.\n    #[must_use]\n    pub fn on_middle_press(mut self, message: Message) -> Self {\n        self.on_middle_press = Some(message);\n        self\n    }\n\n    /// The message to emit on a middle button release.\n    #[must_use]\n    pub fn on_middle_release(mut self, message: Message) -> Self {\n        self.on_middle_release = Some(message);\n        self\n    }\n\n    /// The message to emit when scroll wheel is used\n    #[must_use]\n    pub fn on_scroll(mut self, on_scroll: impl Fn(mouse::ScrollDelta) -> Message + 'a) -> Self {\n        self.on_scroll = Some(Box::new(on_scroll));\n        self\n    }\n\n    /// The message to emit when the mouse enters the area.\n    #[must_use]\n    pub fn on_enter(mut self, message: Message) -> Self {\n        self.on_enter = Some(message);\n        self\n    }\n\n    /// The message to emit when the mouse moves in the area.\n    #[must_use]\n    pub fn on_move(mut self, on_move: impl Fn(Point) -> Message + 'a) -> Self {\n        self.on_move = Some(Box::new(on_move));\n        self\n    }\n\n    /// The message to emit when the mouse exits the area.\n    #[must_use]\n    pub fn on_exit(mut self, message: Message) -> Self {\n        self.on_exit = Some(message);\n        self\n    }\n\n    /// The [`mouse::Interaction`] to use when hovering the area.\n    #[must_use]\n    pub fn interaction(mut self, interaction: mouse::Interaction) -> Self {\n        self.interaction = Some(interaction);\n        self\n    }\n}\n\n/// Local state of the [`MouseArea`].\n#[derive(Default)]\nstruct State {\n    is_hovered: bool,\n    bounds: Rectangle,\n    cursor_position: Option<Point>,\n    previous_click: Option<mouse::Click>,\n}\n\nimpl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {\n    /// Creates a [`MouseArea`] with the given content.\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        MouseArea {\n            content: content.into(),\n            on_press: None,\n            on_release: None,\n            on_double_click: None,\n            on_right_press: None,\n            on_right_release: None,\n            on_middle_press: None,\n            on_middle_release: None,\n            on_scroll: None,\n            on_enter: None,\n            on_move: None,\n            on_exit: None,\n            interaction: None,\n        }\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for MouseArea<'_, Message, Theme, Renderer>\nwhere\n    Renderer: renderer::Renderer,\n    Message: Clone,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::default())\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        vec![Tree::new(&self.content)]\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        tree.diff_children(std::slice::from_ref(&self.content));\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.content.as_widget().size()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.content\n            .as_widget_mut()\n            .layout(&mut tree.children[0], renderer, limits)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        self.content\n            .as_widget_mut()\n            .operate(&mut tree.children[0], layout, renderer, operation);\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget_mut().update(\n            &mut tree.children[0],\n            event,\n            layout,\n            cursor,\n            renderer,\n            shell,\n            viewport,\n        );\n\n        if shell.is_event_captured() {\n            return;\n        }\n\n        update(self, tree, event, layout, cursor, shell);\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let content_interaction = self.content.as_widget().mouse_interaction(\n            &tree.children[0],\n            layout,\n            cursor,\n            viewport,\n            renderer,\n        );\n\n        match (self.interaction, content_interaction) {\n            (Some(interaction), mouse::Interaction::None) if cursor.is_over(layout.bounds()) => {\n                interaction\n            }\n            _ => content_interaction,\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        renderer_style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget().draw(\n            &tree.children[0],\n            renderer,\n            theme,\n            renderer_style,\n            layout,\n            cursor,\n            viewport,\n        );\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.content.as_widget_mut().overlay(\n            &mut tree.children[0],\n            layout,\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<MouseArea<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a + Clone,\n    Theme: 'a,\n    Renderer: 'a + renderer::Renderer,\n{\n    fn from(\n        area: MouseArea<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(area)\n    }\n}\n\n/// Processes the given [`Event`] and updates the [`State`] of an [`MouseArea`]\n/// accordingly.\nfn update<Message: Clone, Theme, Renderer>(\n    widget: &mut MouseArea<'_, Message, Theme, Renderer>,\n    tree: &mut Tree,\n    event: &Event,\n    layout: Layout<'_>,\n    cursor: mouse::Cursor,\n    shell: &mut Shell<'_, Message>,\n) {\n    let state: &mut State = tree.state.downcast_mut();\n\n    let cursor_position = cursor.position();\n    let bounds = layout.bounds();\n\n    if state.cursor_position != cursor_position || state.bounds != bounds {\n        let was_hovered = state.is_hovered;\n\n        state.is_hovered = cursor.is_over(layout.bounds());\n        state.cursor_position = cursor_position;\n        state.bounds = bounds;\n\n        match (\n            widget.on_enter.as_ref(),\n            widget.on_move.as_ref(),\n            widget.on_exit.as_ref(),\n        ) {\n            (Some(on_enter), _, _) if state.is_hovered && !was_hovered => {\n                shell.publish(on_enter.clone());\n            }\n            (_, Some(on_move), _) if state.is_hovered => {\n                if let Some(position) = cursor.position_in(layout.bounds()) {\n                    shell.publish(on_move(position));\n                }\n            }\n            (_, _, Some(on_exit)) if !state.is_hovered && was_hovered => {\n                shell.publish(on_exit.clone());\n            }\n            _ => {}\n        }\n    }\n\n    if !cursor.is_over(layout.bounds()) {\n        return;\n    }\n\n    match event {\n        Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n        | Event::Touch(touch::Event::FingerPressed { .. }) => {\n            if let Some(message) = widget.on_press.as_ref() {\n                shell.publish(message.clone());\n                shell.capture_event();\n            }\n\n            if let Some(position) = cursor_position\n                && let Some(message) = widget.on_double_click.as_ref()\n            {\n                let new_click =\n                    mouse::Click::new(position, mouse::Button::Left, state.previous_click);\n\n                if new_click.kind() == mouse::click::Kind::Double {\n                    shell.publish(message.clone());\n                }\n\n                state.previous_click = Some(new_click);\n\n                // Even if this is not a double click, but the press is nevertheless\n                // processed by us and should not be popup to parent widgets.\n                shell.capture_event();\n            }\n        }\n        Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))\n        | Event::Touch(touch::Event::FingerLifted { .. }) => {\n            if let Some(message) = widget.on_release.as_ref() {\n                shell.publish(message.clone());\n            }\n        }\n        Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) => {\n            if let Some(message) = widget.on_right_press.as_ref() {\n                shell.publish(message.clone());\n                shell.capture_event();\n            }\n        }\n        Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Right)) => {\n            if let Some(message) = widget.on_right_release.as_ref() {\n                shell.publish(message.clone());\n            }\n        }\n        Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Middle)) => {\n            if let Some(message) = widget.on_middle_press.as_ref() {\n                shell.publish(message.clone());\n                shell.capture_event();\n            }\n        }\n        Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Middle)) => {\n            if let Some(message) = widget.on_middle_release.as_ref() {\n                shell.publish(message.clone());\n            }\n        }\n        Event::Mouse(mouse::Event::WheelScrolled { delta }) => {\n            if let Some(on_scroll) = widget.on_scroll.as_ref() {\n                shell.publish(on_scroll(*delta));\n                shell.capture_event();\n            }\n        }\n        _ => {}\n    }\n}\n"
  },
  {
    "path": "widget/src/overlay/menu.rs",
    "content": "//! Build and show dropdown menus.\nuse crate::core::alignment;\nuse crate::core::border::{self, Border};\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::text::{self, Text};\nuse crate::core::touch;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    Background, Color, Event, Length, Padding, Pixels, Point, Rectangle, Shadow, Size, Theme,\n    Vector,\n};\nuse crate::core::{Element, Shell, Widget};\nuse crate::scrollable::{self, Scrollable};\n\n/// A list of selectable options.\npub struct Menu<'a, 'b, T, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n    'b: 'a,\n{\n    state: &'a mut State,\n    options: &'a [T],\n    hovered_option: &'a mut Option<usize>,\n    to_string: &'a dyn Fn(&T) -> String,\n    on_selected: Box<dyn FnMut(T) -> Message + 'a>,\n    on_option_hovered: Option<&'a dyn Fn(T) -> Message>,\n    width: f32,\n    padding: Padding,\n    text_size: Option<Pixels>,\n    line_height: text::LineHeight,\n    shaping: text::Shaping,\n    ellipsis: text::Ellipsis,\n    font: Option<Renderer::Font>,\n    class: &'a <Theme as Catalog>::Class<'b>,\n}\n\nimpl<'a, 'b, T, Message, Theme, Renderer> Menu<'a, 'b, T, Message, Theme, Renderer>\nwhere\n    T: Clone,\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n    'b: 'a,\n{\n    /// Creates a new [`Menu`] with the given [`State`], a list of options,\n    /// the message to produced when an option is selected, and its [`Style`].\n    pub fn new(\n        state: &'a mut State,\n        options: &'a [T],\n        hovered_option: &'a mut Option<usize>,\n        to_string: &'a dyn Fn(&T) -> String,\n        on_selected: impl FnMut(T) -> Message + 'a,\n        on_option_hovered: Option<&'a dyn Fn(T) -> Message>,\n        class: &'a <Theme as Catalog>::Class<'b>,\n    ) -> Self {\n        Menu {\n            state,\n            options,\n            hovered_option,\n            to_string,\n            on_selected: Box::new(on_selected),\n            on_option_hovered,\n            width: 0.0,\n            padding: Padding::ZERO,\n            text_size: None,\n            line_height: text::LineHeight::default(),\n            shaping: text::Shaping::default(),\n            ellipsis: text::Ellipsis::default(),\n            font: None,\n            class,\n        }\n    }\n\n    /// Sets the width of the [`Menu`].\n    pub fn width(mut self, width: f32) -> Self {\n        self.width = width;\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`Menu`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the text size of the [`Menu`].\n    pub fn text_size(mut self, text_size: impl Into<Pixels>) -> Self {\n        self.text_size = Some(text_size.into());\n        self\n    }\n\n    /// Sets the text [`text::LineHeight`] of the [`Menu`].\n    pub fn line_height(mut self, line_height: impl Into<text::LineHeight>) -> Self {\n        self.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the [`text::Shaping`] strategy of the [`Menu`].\n    pub fn shaping(mut self, shaping: text::Shaping) -> Self {\n        self.shaping = shaping;\n        self\n    }\n\n    /// Sets the [`text::Ellipsis`] strategy of the [`Menu`].\n    pub fn ellipsis(mut self, ellipsis: text::Ellipsis) -> Self {\n        self.ellipsis = ellipsis;\n        self\n    }\n\n    /// Sets the font of the [`Menu`].\n    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {\n        self.font = Some(font.into());\n        self\n    }\n\n    /// Turns the [`Menu`] into an overlay [`Element`] at the given target\n    /// position.\n    ///\n    /// The `target_height` will be used to display the menu either on top\n    /// of the target or under it, depending on the screen position and the\n    /// dimensions of the [`Menu`].\n    pub fn overlay(\n        self,\n        position: Point,\n        viewport: Rectangle,\n        target_height: f32,\n        menu_height: Length,\n    ) -> overlay::Element<'a, Message, Theme, Renderer> {\n        overlay::Element::new(Box::new(Overlay::new(\n            position,\n            viewport,\n            self,\n            target_height,\n            menu_height,\n        )))\n    }\n}\n\n/// The local state of a [`Menu`].\n#[derive(Debug)]\npub struct State {\n    tree: Tree,\n}\n\nimpl State {\n    /// Creates a new [`State`] for a [`Menu`].\n    pub fn new() -> Self {\n        Self {\n            tree: Tree::empty(),\n        }\n    }\n}\n\nimpl Default for State {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nstruct Overlay<'a, 'b, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    position: Point,\n    viewport: Rectangle,\n    tree: &'a mut Tree,\n    list: Scrollable<'a, Message, Theme, Renderer>,\n    width: f32,\n    target_height: f32,\n    class: &'a <Theme as Catalog>::Class<'b>,\n}\n\nimpl<'a, 'b, Message, Theme, Renderer> Overlay<'a, 'b, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + scrollable::Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n    'b: 'a,\n{\n    pub fn new<T>(\n        position: Point,\n        viewport: Rectangle,\n        menu: Menu<'a, 'b, T, Message, Theme, Renderer>,\n        target_height: f32,\n        menu_height: Length,\n    ) -> Self\n    where\n        T: Clone,\n    {\n        let Menu {\n            state,\n            options,\n            hovered_option,\n            to_string,\n            on_selected,\n            on_option_hovered,\n            width,\n            padding,\n            font,\n            text_size,\n            line_height,\n            shaping,\n            ellipsis,\n            class,\n        } = menu;\n\n        let list = Scrollable::new(List {\n            options,\n            hovered_option,\n            to_string,\n            on_selected,\n            on_option_hovered,\n            font,\n            text_size,\n            line_height,\n            shaping,\n            ellipsis,\n            padding,\n            class,\n        })\n        .height(menu_height);\n\n        state.tree.diff(&list as &dyn Widget<_, _, _>);\n\n        Self {\n            position,\n            viewport,\n            tree: &mut state.tree,\n            list,\n            width,\n            target_height,\n            class,\n        }\n    }\n}\n\nimpl<Message, Theme, Renderer> crate::core::Overlay<Message, Theme, Renderer>\n    for Overlay<'_, '_, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n        let space_below = bounds.height - (self.position.y + self.target_height);\n        let space_above = self.position.y;\n\n        let limits = layout::Limits::new(\n            Size::ZERO,\n            Size::new(\n                bounds.width - self.position.x,\n                if space_below > space_above {\n                    space_below\n                } else {\n                    space_above\n                },\n            ),\n        )\n        .width(self.width);\n\n        let node = self.list.layout(self.tree, renderer, &limits);\n        let size = node.size();\n\n        node.move_to(if space_below > space_above {\n            self.position + Vector::new(0.0, self.target_height)\n        } else {\n            self.position - Vector::new(0.0, size.height)\n        })\n    }\n\n    fn update(\n        &mut self,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n    ) {\n        let bounds = layout.bounds();\n\n        self.list\n            .update(self.tree, event, layout, cursor, renderer, shell, &bounds);\n    }\n\n    fn mouse_interaction(\n        &self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.list\n            .mouse_interaction(self.tree, layout, cursor, &self.viewport, renderer)\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        defaults: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) {\n        let bounds = layout.bounds();\n\n        let style = Catalog::style(theme, self.class);\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds,\n                border: style.border,\n                shadow: style.shadow,\n                ..renderer::Quad::default()\n            },\n            style.background,\n        );\n\n        self.list.draw(\n            self.tree, renderer, theme, defaults, layout, cursor, &bounds,\n        );\n    }\n}\n\nstruct List<'a, 'b, T, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    options: &'a [T],\n    hovered_option: &'a mut Option<usize>,\n    to_string: &'a dyn Fn(&T) -> String,\n    on_selected: Box<dyn FnMut(T) -> Message + 'a>,\n    on_option_hovered: Option<&'a dyn Fn(T) -> Message>,\n    padding: Padding,\n    text_size: Option<Pixels>,\n    line_height: text::LineHeight,\n    shaping: text::Shaping,\n    ellipsis: text::Ellipsis,\n    font: Option<Renderer::Font>,\n    class: &'a <Theme as Catalog>::Class<'b>,\n}\n\nstruct ListState {\n    is_hovered: Option<bool>,\n}\n\nimpl<T, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for List<'_, '_, T, Message, Theme, Renderer>\nwhere\n    T: Clone,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<Option<bool>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(ListState { is_hovered: None })\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: Length::Fill,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        use std::f32;\n\n        let text_size = self.text_size.unwrap_or_else(|| renderer.default_size());\n\n        let text_line_height = self.line_height.to_absolute(text_size);\n\n        let size = {\n            let intrinsic = Size::new(\n                0.0,\n                (f32::from(text_line_height) + self.padding.y()) * self.options.len() as f32,\n            );\n\n            limits.resolve(Length::Fill, Length::Shrink, intrinsic)\n        };\n\n        layout::Node::new(size)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {\n                if cursor.is_over(layout.bounds())\n                    && let Some(index) = *self.hovered_option\n                    && let Some(option) = self.options.get(index)\n                {\n                    shell.publish((self.on_selected)(option.clone()));\n                    shell.capture_event();\n                }\n            }\n            Event::Mouse(mouse::Event::CursorMoved { .. }) => {\n                if let Some(cursor_position) = cursor.position_in(layout.bounds()) {\n                    let text_size = self.text_size.unwrap_or_else(|| renderer.default_size());\n\n                    let option_height =\n                        f32::from(self.line_height.to_absolute(text_size)) + self.padding.y();\n\n                    let new_hovered_option = (cursor_position.y / option_height) as usize;\n\n                    if *self.hovered_option != Some(new_hovered_option)\n                        && let Some(option) = self.options.get(new_hovered_option)\n                    {\n                        if let Some(on_option_hovered) = self.on_option_hovered {\n                            shell.publish(on_option_hovered(option.clone()));\n                        }\n\n                        shell.request_redraw();\n                    }\n\n                    *self.hovered_option = Some(new_hovered_option);\n                }\n            }\n            Event::Touch(touch::Event::FingerPressed { .. }) => {\n                if let Some(cursor_position) = cursor.position_in(layout.bounds()) {\n                    let text_size = self.text_size.unwrap_or_else(|| renderer.default_size());\n\n                    let option_height =\n                        f32::from(self.line_height.to_absolute(text_size)) + self.padding.y();\n\n                    *self.hovered_option = Some((cursor_position.y / option_height) as usize);\n\n                    if let Some(index) = *self.hovered_option\n                        && let Some(option) = self.options.get(index)\n                    {\n                        shell.publish((self.on_selected)(option.clone()));\n                        shell.capture_event();\n                    }\n                }\n            }\n            _ => {}\n        }\n\n        let state = tree.state.downcast_mut::<ListState>();\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            state.is_hovered = Some(cursor.is_over(layout.bounds()));\n        } else if state\n            .is_hovered\n            .is_some_and(|is_hovered| is_hovered != cursor.is_over(layout.bounds()))\n        {\n            shell.request_redraw();\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let is_mouse_over = cursor.is_over(layout.bounds());\n\n        if is_mouse_over {\n            mouse::Interaction::Pointer\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n\n    fn draw(\n        &self,\n        _tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let style = Catalog::style(theme, self.class);\n        let bounds = layout.bounds();\n\n        let text_size = self.text_size.unwrap_or_else(|| renderer.default_size());\n        let option_height = f32::from(self.line_height.to_absolute(text_size)) + self.padding.y();\n\n        let offset = viewport.y - bounds.y;\n        let start = (offset / option_height) as usize;\n        let end = ((offset + viewport.height) / option_height).ceil() as usize;\n\n        let visible_options = &self.options[start..end.min(self.options.len())];\n\n        for (i, option) in visible_options.iter().enumerate() {\n            let i = start + i;\n            let is_selected = *self.hovered_option == Some(i);\n\n            let bounds = Rectangle {\n                x: bounds.x,\n                y: bounds.y + (option_height * i as f32),\n                width: bounds.width,\n                height: option_height,\n            };\n\n            if is_selected {\n                renderer.fill_quad(\n                    renderer::Quad {\n                        bounds: Rectangle {\n                            x: bounds.x + style.border.width,\n                            width: bounds.width - style.border.width * 2.0,\n                            ..bounds\n                        },\n                        border: border::rounded(style.border.radius),\n                        ..renderer::Quad::default()\n                    },\n                    style.selected_background,\n                );\n            }\n\n            renderer.fill_text(\n                Text {\n                    content: (self.to_string)(option),\n                    bounds: Size::new(bounds.width - self.padding.x(), bounds.height),\n                    size: text_size,\n                    line_height: self.line_height,\n                    font: self.font.unwrap_or_else(|| renderer.default_font()),\n                    align_x: text::Alignment::Default,\n                    align_y: alignment::Vertical::Center,\n                    shaping: self.shaping,\n                    wrapping: text::Wrapping::None,\n                    ellipsis: self.ellipsis,\n                    hint_factor: renderer.scale_factor(),\n                },\n                Point::new(bounds.x + self.padding.left, bounds.center_y()),\n                if is_selected {\n                    style.selected_text_color\n                } else {\n                    style.text_color\n                },\n                *viewport,\n            );\n        }\n    }\n}\n\nimpl<'a, 'b, T, Message, Theme, Renderer> From<List<'a, 'b, T, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    T: Clone,\n    Message: 'a,\n    Theme: 'a + Catalog,\n    Renderer: 'a + text::Renderer,\n    'b: 'a,\n{\n    fn from(list: List<'a, 'b, T, Message, Theme, Renderer>) -> Self {\n        Element::new(list)\n    }\n}\n\n/// The appearance of a [`Menu`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`Background`] of the menu.\n    pub background: Background,\n    /// The [`Border`] of the menu.\n    pub border: Border,\n    /// The text [`Color`] of the menu.\n    pub text_color: Color,\n    /// The text [`Color`] of a selected option in the menu.\n    pub selected_text_color: Color,\n    /// The background [`Color`] of a selected option in the menu.\n    pub selected_background: Background,\n    /// The [`Shadow`] of the menu.\n    pub shadow: Shadow,\n}\n\n/// The theme catalog of a [`Menu`].\npub trait Catalog: scrollable::Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> <Self as Catalog>::Class<'a>;\n\n    /// The default class for the scrollable of the [`Menu`].\n    fn default_scrollable<'a>() -> <Self as scrollable::Catalog>::Class<'a> {\n        <Self as scrollable::Catalog>::default()\n    }\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &<Self as Catalog>::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`Menu`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> StyleFn<'a, Self> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &StyleFn<'_, Self>) -> Style {\n        class(self)\n    }\n}\n\n/// The default style of the list of a [`Menu`].\npub fn default(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    Style {\n        background: palette.background.weak.color.into(),\n        border: Border {\n            width: 1.0,\n            radius: 0.0.into(),\n            color: palette.background.strong.color,\n        },\n        text_color: palette.background.weak.text,\n        selected_text_color: palette.primary.strong.text,\n        selected_background: palette.primary.strong.color.into(),\n        shadow: Shadow::default(),\n    }\n}\n"
  },
  {
    "path": "widget/src/overlay.rs",
    "content": "//! Display interactive elements on top of other widgets.\npub mod menu;\n"
  },
  {
    "path": "widget/src/pane_grid/axis.rs",
    "content": "use crate::core::Rectangle;\n\n/// A fixed reference line for the measurement of coordinates.\n#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]\npub enum Axis {\n    /// The horizontal axis: —\n    Horizontal,\n    /// The vertical axis: |\n    Vertical,\n}\n\nimpl Axis {\n    /// Splits the provided [`Rectangle`] on the current [`Axis`] with the\n    /// given `ratio` and `spacing`.\n    pub fn split(\n        &self,\n        rectangle: &Rectangle,\n        ratio: f32,\n        spacing: f32,\n        min_size_a: f32,\n        min_size_b: f32,\n    ) -> (Rectangle, Rectangle, f32) {\n        match self {\n            Axis::Horizontal => {\n                let height_top = (rectangle.height * ratio - spacing / 2.0)\n                    .round()\n                    .max(min_size_a)\n                    .min(rectangle.height - min_size_b - spacing);\n\n                let height_bottom = (rectangle.height - height_top - spacing).max(min_size_b);\n\n                let ratio = (height_top + spacing / 2.0) / rectangle.height;\n\n                (\n                    Rectangle {\n                        height: height_top,\n                        ..*rectangle\n                    },\n                    Rectangle {\n                        y: rectangle.y + height_top + spacing,\n                        height: height_bottom,\n                        ..*rectangle\n                    },\n                    ratio,\n                )\n            }\n            Axis::Vertical => {\n                let width_left = (rectangle.width * ratio - spacing / 2.0)\n                    .round()\n                    .max(min_size_a)\n                    .min(rectangle.width - min_size_b - spacing);\n\n                let width_right = (rectangle.width - width_left - spacing).max(min_size_b);\n\n                let ratio = (width_left + spacing / 2.0) / rectangle.width;\n\n                (\n                    Rectangle {\n                        width: width_left,\n                        ..*rectangle\n                    },\n                    Rectangle {\n                        x: rectangle.x + width_left + spacing,\n                        width: width_right,\n                        ..*rectangle\n                    },\n                    ratio,\n                )\n            }\n        }\n    }\n\n    /// Calculates the bounds of the split line in a [`Rectangle`] region.\n    pub fn split_line_bounds(&self, rectangle: Rectangle, ratio: f32, spacing: f32) -> Rectangle {\n        match self {\n            Axis::Horizontal => Rectangle {\n                x: rectangle.x,\n                y: (rectangle.y + rectangle.height * ratio - spacing / 2.0).round(),\n                width: rectangle.width,\n                height: spacing,\n            },\n            Axis::Vertical => Rectangle {\n                x: (rectangle.x + rectangle.width * ratio - spacing / 2.0).round(),\n                y: rectangle.y,\n                width: spacing,\n                height: rectangle.height,\n            },\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    enum Case {\n        Horizontal {\n            overall_height: f32,\n            spacing: f32,\n            top_height: f32,\n            bottom_y: f32,\n            bottom_height: f32,\n        },\n        Vertical {\n            overall_width: f32,\n            spacing: f32,\n            left_width: f32,\n            right_x: f32,\n            right_width: f32,\n        },\n    }\n\n    #[test]\n    fn split() {\n        let cases = vec![\n            // Even height, even spacing\n            Case::Horizontal {\n                overall_height: 10.0,\n                spacing: 2.0,\n                top_height: 4.0,\n                bottom_y: 6.0,\n                bottom_height: 4.0,\n            },\n            // Odd height, even spacing\n            Case::Horizontal {\n                overall_height: 9.0,\n                spacing: 2.0,\n                top_height: 4.0,\n                bottom_y: 6.0,\n                bottom_height: 3.0,\n            },\n            // Even height, odd spacing\n            Case::Horizontal {\n                overall_height: 10.0,\n                spacing: 1.0,\n                top_height: 5.0,\n                bottom_y: 6.0,\n                bottom_height: 4.0,\n            },\n            // Odd height, odd spacing\n            Case::Horizontal {\n                overall_height: 9.0,\n                spacing: 1.0,\n                top_height: 4.0,\n                bottom_y: 5.0,\n                bottom_height: 4.0,\n            },\n            // Even width, even spacing\n            Case::Vertical {\n                overall_width: 10.0,\n                spacing: 2.0,\n                left_width: 4.0,\n                right_x: 6.0,\n                right_width: 4.0,\n            },\n            // Odd width, even spacing\n            Case::Vertical {\n                overall_width: 9.0,\n                spacing: 2.0,\n                left_width: 4.0,\n                right_x: 6.0,\n                right_width: 3.0,\n            },\n            // Even width, odd spacing\n            Case::Vertical {\n                overall_width: 10.0,\n                spacing: 1.0,\n                left_width: 5.0,\n                right_x: 6.0,\n                right_width: 4.0,\n            },\n            // Odd width, odd spacing\n            Case::Vertical {\n                overall_width: 9.0,\n                spacing: 1.0,\n                left_width: 4.0,\n                right_x: 5.0,\n                right_width: 4.0,\n            },\n        ];\n        for case in cases {\n            match case {\n                Case::Horizontal {\n                    overall_height,\n                    spacing,\n                    top_height,\n                    bottom_y,\n                    bottom_height,\n                } => {\n                    let a = Axis::Horizontal;\n                    let r = Rectangle {\n                        x: 0.0,\n                        y: 0.0,\n                        width: 10.0,\n                        height: overall_height,\n                    };\n                    let (top, bottom, _ratio) = a.split(&r, 0.5, spacing, 0.0, 0.0);\n                    assert_eq!(\n                        top,\n                        Rectangle {\n                            height: top_height,\n                            ..r\n                        }\n                    );\n                    assert_eq!(\n                        bottom,\n                        Rectangle {\n                            y: bottom_y,\n                            height: bottom_height,\n                            ..r\n                        }\n                    );\n                }\n                Case::Vertical {\n                    overall_width,\n                    spacing,\n                    left_width,\n                    right_x,\n                    right_width,\n                } => {\n                    let a = Axis::Vertical;\n                    let r = Rectangle {\n                        x: 0.0,\n                        y: 0.0,\n                        width: overall_width,\n                        height: 10.0,\n                    };\n                    let (left, right, _ratio) = a.split(&r, 0.5, spacing, 0.0, 0.0);\n                    assert_eq!(\n                        left,\n                        Rectangle {\n                            width: left_width,\n                            ..r\n                        }\n                    );\n                    assert_eq!(\n                        right,\n                        Rectangle {\n                            x: right_x,\n                            width: right_width,\n                            ..r\n                        }\n                    );\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "widget/src/pane_grid/configuration.rs",
    "content": "use crate::pane_grid::Axis;\n\n/// The arrangement of a [`PaneGrid`].\n///\n/// [`PaneGrid`]: super::PaneGrid\n#[derive(Debug, Clone)]\npub enum Configuration<T> {\n    /// A split of the available space.\n    Split {\n        /// The direction of the split.\n        axis: Axis,\n\n        /// The ratio of the split in [0.0, 1.0].\n        ratio: f32,\n\n        /// The left/top [`Configuration`] of the split.\n        a: Box<Configuration<T>>,\n\n        /// The right/bottom [`Configuration`] of the split.\n        b: Box<Configuration<T>>,\n    },\n    /// A [`Pane`].\n    ///\n    /// [`Pane`]: super::Pane\n    Pane(T),\n}\n"
  },
  {
    "path": "widget/src/pane_grid/content.rs",
    "content": "use crate::container;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget::{self, Tree};\nuse crate::core::{self, Element, Event, Layout, Point, Rectangle, Shell, Size, Vector};\nuse crate::pane_grid::{Draggable, TitleBar};\n\n/// The content of a [`Pane`].\n///\n/// [`Pane`]: super::Pane\npub struct Content<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    title_bar: Option<TitleBar<'a, Message, Theme, Renderer>>,\n    body: Element<'a, Message, Theme, Renderer>,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Message, Theme, Renderer> Content<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    /// Creates a new [`Content`] with the provided body.\n    pub fn new(body: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            title_bar: None,\n            body: body.into(),\n            class: Theme::default(),\n        }\n    }\n\n    /// Sets the [`TitleBar`] of the [`Content`].\n    pub fn title_bar(mut self, title_bar: TitleBar<'a, Message, Theme, Renderer>) -> Self {\n        self.title_bar = Some(title_bar);\n        self\n    }\n\n    /// Sets the style of the [`Content`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> container::Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<container::StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as container::StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Content`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Content<'_, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    pub(super) fn state(&self) -> Tree {\n        let children = if let Some(title_bar) = self.title_bar.as_ref() {\n            vec![Tree::new(&self.body), title_bar.state()]\n        } else {\n            vec![Tree::new(&self.body), Tree::empty()]\n        };\n\n        Tree {\n            children,\n            ..Tree::empty()\n        }\n    }\n\n    pub(super) fn diff(&self, tree: &mut Tree) {\n        if tree.children.len() == 2 {\n            if let Some(title_bar) = self.title_bar.as_ref() {\n                title_bar.diff(&mut tree.children[1]);\n            }\n\n            tree.children[0].diff(&self.body);\n        } else {\n            *tree = self.state();\n        }\n    }\n\n    /// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`].\n    ///\n    /// [`Renderer`]: core::Renderer\n    pub fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        {\n            let style = theme.style(&self.class);\n\n            container::draw_background(renderer, &style, bounds);\n        }\n\n        if let Some(title_bar) = &self.title_bar {\n            let mut children = layout.children();\n            let title_bar_layout = children.next().unwrap();\n            let body_layout = children.next().unwrap();\n\n            let show_controls = cursor.is_over(bounds);\n\n            self.body.as_widget().draw(\n                &tree.children[0],\n                renderer,\n                theme,\n                style,\n                body_layout,\n                cursor,\n                viewport,\n            );\n\n            title_bar.draw(\n                &tree.children[1],\n                renderer,\n                theme,\n                style,\n                title_bar_layout,\n                cursor,\n                viewport,\n                show_controls,\n            );\n        } else {\n            self.body.as_widget().draw(\n                &tree.children[0],\n                renderer,\n                theme,\n                style,\n                layout,\n                cursor,\n                viewport,\n            );\n        }\n    }\n\n    pub(crate) fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        if let Some(title_bar) = &mut self.title_bar {\n            let max_size = limits.max();\n\n            let title_bar_layout = title_bar.layout(\n                &mut tree.children[1],\n                renderer,\n                &layout::Limits::new(Size::ZERO, max_size),\n            );\n\n            let title_bar_size = title_bar_layout.size();\n\n            let body_layout = self.body.as_widget_mut().layout(\n                &mut tree.children[0],\n                renderer,\n                &layout::Limits::new(\n                    Size::ZERO,\n                    Size::new(max_size.width, max_size.height - title_bar_size.height),\n                ),\n            );\n\n            layout::Node::with_children(\n                max_size,\n                vec![\n                    title_bar_layout,\n                    body_layout.move_to(Point::new(0.0, title_bar_size.height)),\n                ],\n            )\n        } else {\n            self.body\n                .as_widget_mut()\n                .layout(&mut tree.children[0], renderer, limits)\n        }\n    }\n\n    pub(crate) fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        let body_layout = if let Some(title_bar) = &mut self.title_bar {\n            let mut children = layout.children();\n\n            title_bar.operate(\n                &mut tree.children[1],\n                children.next().unwrap(),\n                renderer,\n                operation,\n            );\n\n            children.next().unwrap()\n        } else {\n            layout\n        };\n\n        self.body\n            .as_widget_mut()\n            .operate(&mut tree.children[0], body_layout, renderer, operation);\n    }\n\n    pub(crate) fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n        is_picked: bool,\n    ) {\n        let body_layout = if let Some(title_bar) = &mut self.title_bar {\n            let mut children = layout.children();\n\n            title_bar.update(\n                &mut tree.children[1],\n                event,\n                children.next().unwrap(),\n                cursor,\n                renderer,\n                shell,\n                viewport,\n            );\n\n            children.next().unwrap()\n        } else {\n            layout\n        };\n\n        if !is_picked {\n            self.body.as_widget_mut().update(\n                &mut tree.children[0],\n                event,\n                body_layout,\n                cursor,\n                renderer,\n                shell,\n                viewport,\n            );\n        }\n    }\n\n    pub(crate) fn grid_interaction(\n        &self,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        drag_enabled: bool,\n    ) -> Option<mouse::Interaction> {\n        let title_bar = self.title_bar.as_ref()?;\n\n        let mut children = layout.children();\n        let title_bar_layout = children.next().unwrap();\n\n        let is_over_pick_area = cursor\n            .position()\n            .map(|cursor_position| title_bar.is_over_pick_area(title_bar_layout, cursor_position))\n            .unwrap_or_default();\n\n        if is_over_pick_area && drag_enabled {\n            return Some(mouse::Interaction::Grab);\n        }\n\n        None\n    }\n\n    pub(crate) fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n        drag_enabled: bool,\n    ) -> mouse::Interaction {\n        let (body_layout, title_bar_interaction) = if let Some(title_bar) = &self.title_bar {\n            let mut children = layout.children();\n            let title_bar_layout = children.next().unwrap();\n\n            let is_over_pick_area = cursor\n                .position()\n                .map(|cursor_position| {\n                    title_bar.is_over_pick_area(title_bar_layout, cursor_position)\n                })\n                .unwrap_or_default();\n\n            if is_over_pick_area && drag_enabled {\n                return mouse::Interaction::Grab;\n            }\n\n            let mouse_interaction = title_bar.mouse_interaction(\n                &tree.children[1],\n                title_bar_layout,\n                cursor,\n                viewport,\n                renderer,\n            );\n\n            (children.next().unwrap(), mouse_interaction)\n        } else {\n            (layout, mouse::Interaction::default())\n        };\n\n        self.body\n            .as_widget()\n            .mouse_interaction(&tree.children[0], body_layout, cursor, viewport, renderer)\n            .max(title_bar_interaction)\n    }\n\n    pub(crate) fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        if let Some(title_bar) = self.title_bar.as_mut() {\n            let mut children = layout.children();\n            let title_bar_layout = children.next()?;\n\n            let mut states = tree.children.iter_mut();\n            let body_state = states.next().unwrap();\n            let title_bar_state = states.next().unwrap();\n\n            match title_bar.overlay(\n                title_bar_state,\n                title_bar_layout,\n                renderer,\n                viewport,\n                translation,\n            ) {\n                Some(overlay) => Some(overlay),\n                None => self.body.as_widget_mut().overlay(\n                    body_state,\n                    children.next()?,\n                    renderer,\n                    viewport,\n                    translation,\n                ),\n            }\n        } else {\n            self.body.as_widget_mut().overlay(\n                &mut tree.children[0],\n                layout,\n                renderer,\n                viewport,\n                translation,\n            )\n        }\n    }\n}\n\nimpl<Message, Theme, Renderer> Draggable for &Content<'_, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    fn can_be_dragged_at(&self, layout: Layout<'_>, cursor_position: Point) -> bool {\n        if let Some(title_bar) = &self.title_bar {\n            let mut children = layout.children();\n            let title_bar_layout = children.next().unwrap();\n\n            title_bar.is_over_pick_area(title_bar_layout, cursor_position)\n        } else {\n            false\n        }\n    }\n}\n\nimpl<'a, T, Message, Theme, Renderer> From<T> for Content<'a, Message, Theme, Renderer>\nwhere\n    T: Into<Element<'a, Message, Theme, Renderer>>,\n    Theme: container::Catalog + 'a,\n    Renderer: core::Renderer,\n{\n    fn from(element: T) -> Self {\n        Self::new(element)\n    }\n}\n"
  },
  {
    "path": "widget/src/pane_grid/controls.rs",
    "content": "use crate::container;\nuse crate::core::{self, Element};\n\n/// The controls of a [`Pane`].\n///\n/// [`Pane`]: super::Pane\npub struct Controls<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    pub(super) full: Element<'a, Message, Theme, Renderer>,\n    pub(super) compact: Option<Element<'a, Message, Theme, Renderer>>,\n}\n\nimpl<'a, Message, Theme, Renderer> Controls<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    /// Creates a new [`Controls`] with the given content.\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            full: content.into(),\n            compact: None,\n        }\n    }\n\n    /// Creates a new [`Controls`] with a full and compact variant.\n    /// If there is not enough room to show the full variant without overlap,\n    /// then the compact variant will be shown instead.\n    pub fn dynamic(\n        full: impl Into<Element<'a, Message, Theme, Renderer>>,\n        compact: impl Into<Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        Self {\n            full: full.into(),\n            compact: Some(compact.into()),\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Element<'a, Message, Theme, Renderer>>\n    for Controls<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    fn from(value: Element<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(value)\n    }\n}\n"
  },
  {
    "path": "widget/src/pane_grid/direction.rs",
    "content": "/// A four cardinal direction.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Direction {\n    /// ↑\n    Up,\n    /// ↓\n    Down,\n    /// ←\n    Left,\n    /// →\n    Right,\n}\n"
  },
  {
    "path": "widget/src/pane_grid/draggable.rs",
    "content": "use crate::core::{Layout, Point};\n\n/// A pane that can be dragged.\npub trait Draggable {\n    /// Returns whether the [`Draggable`] with the given [`Layout`] can be picked\n    /// at the provided cursor position.\n    fn can_be_dragged_at(&self, layout: Layout<'_>, cursor: Point) -> bool;\n}\n"
  },
  {
    "path": "widget/src/pane_grid/node.rs",
    "content": "use crate::core::{Rectangle, Size};\nuse crate::pane_grid::{Axis, Pane, Split};\n\nuse std::collections::BTreeMap;\n\n/// A layout node of a [`PaneGrid`].\n///\n/// [`PaneGrid`]: super::PaneGrid\n#[derive(Debug, Clone)]\npub enum Node {\n    /// The region of this [`Node`] is split into two.\n    Split {\n        /// The [`Split`] of this [`Node`].\n        id: Split,\n\n        /// The direction of the split.\n        axis: Axis,\n\n        /// The ratio of the split in [0.0, 1.0].\n        ratio: f32,\n\n        /// The left/top [`Node`] of the split.\n        a: Box<Node>,\n\n        /// The right/bottom [`Node`] of the split.\n        b: Box<Node>,\n    },\n    /// The region of this [`Node`] is taken by a [`Pane`].\n    Pane(Pane),\n}\n\n#[derive(Debug)]\nenum Count {\n    Split {\n        horizontal: usize,\n        vertical: usize,\n        a: Box<Count>,\n        b: Box<Count>,\n    },\n    Pane,\n}\n\nimpl Count {\n    fn horizontal(&self) -> usize {\n        match self {\n            Count::Split { horizontal, .. } => *horizontal,\n            Count::Pane => 0,\n        }\n    }\n\n    fn vertical(&self) -> usize {\n        match self {\n            Count::Split { vertical, .. } => *vertical,\n            Count::Pane => 0,\n        }\n    }\n}\n\nimpl Node {\n    /// Returns an iterator over each [`Split`] in this [`Node`].\n    pub fn splits(&self) -> impl Iterator<Item = &Split> {\n        let mut unvisited_nodes = vec![self];\n\n        std::iter::from_fn(move || {\n            while let Some(node) = unvisited_nodes.pop() {\n                if let Node::Split { id, a, b, .. } = node {\n                    unvisited_nodes.push(a);\n                    unvisited_nodes.push(b);\n\n                    return Some(id);\n                }\n            }\n\n            None\n        })\n    }\n\n    fn count(&self) -> Count {\n        match self {\n            Node::Split { a, b, axis, .. } => {\n                let a = a.count();\n                let b = b.count();\n\n                let (horizontal, vertical) = match axis {\n                    Axis::Horizontal => (\n                        1 + a.horizontal() + b.horizontal(),\n                        a.vertical().max(b.vertical()),\n                    ),\n                    Axis::Vertical => (\n                        a.horizontal().max(b.horizontal()),\n                        1 + a.vertical() + b.vertical(),\n                    ),\n                };\n\n                Count::Split {\n                    horizontal,\n                    vertical,\n                    a: Box::new(a),\n                    b: Box::new(b),\n                }\n            }\n            Node::Pane(_) => Count::Pane,\n        }\n    }\n\n    /// Returns the rectangular region for each [`Pane`] in the [`Node`] given\n    /// the spacing between panes and the total available space.\n    pub fn pane_regions(\n        &self,\n        spacing: f32,\n        min_size: f32,\n        bounds: Size,\n    ) -> BTreeMap<Pane, Rectangle> {\n        let mut regions = BTreeMap::new();\n        let count = self.count();\n\n        self.compute_regions(\n            spacing,\n            min_size,\n            &Rectangle {\n                x: 0.0,\n                y: 0.0,\n                width: bounds.width,\n                height: bounds.height,\n            },\n            &count,\n            &mut regions,\n        );\n\n        regions\n    }\n\n    /// Returns the axis, rectangular region, and ratio for each [`Split`] in\n    /// the [`Node`] given the spacing between panes and the total available\n    /// space.\n    pub fn split_regions(\n        &self,\n        spacing: f32,\n        min_size: f32,\n        bounds: Size,\n    ) -> BTreeMap<Split, (Axis, Rectangle, f32)> {\n        let mut splits = BTreeMap::new();\n        let count = self.count();\n\n        self.compute_splits(\n            spacing,\n            min_size,\n            &Rectangle {\n                x: 0.0,\n                y: 0.0,\n                width: bounds.width,\n                height: bounds.height,\n            },\n            &count,\n            &mut splits,\n        );\n\n        splits\n    }\n\n    pub(crate) fn find(&mut self, pane: Pane) -> Option<&mut Node> {\n        match self {\n            Node::Split { a, b, .. } => a.find(pane).or_else(move || b.find(pane)),\n            Node::Pane(p) => {\n                if *p == pane {\n                    Some(self)\n                } else {\n                    None\n                }\n            }\n        }\n    }\n\n    pub(crate) fn split(&mut self, id: Split, axis: Axis, new_pane: Pane) {\n        *self = Node::Split {\n            id,\n            axis,\n            ratio: 0.5,\n            a: Box::new(self.clone()),\n            b: Box::new(Node::Pane(new_pane)),\n        };\n    }\n\n    pub(crate) fn split_inverse(&mut self, id: Split, axis: Axis, pane: Pane) {\n        *self = Node::Split {\n            id,\n            axis,\n            ratio: 0.5,\n            a: Box::new(Node::Pane(pane)),\n            b: Box::new(self.clone()),\n        };\n    }\n\n    pub(crate) fn update(&mut self, f: &impl Fn(&mut Node)) {\n        if let Node::Split { a, b, .. } = self {\n            a.update(f);\n            b.update(f);\n        }\n\n        f(self);\n    }\n\n    pub(crate) fn resize(&mut self, split: Split, percentage: f32) -> bool {\n        match self {\n            Node::Split {\n                id, ratio, a, b, ..\n            } => {\n                if *id == split {\n                    *ratio = percentage;\n\n                    true\n                } else if a.resize(split, percentage) {\n                    true\n                } else {\n                    b.resize(split, percentage)\n                }\n            }\n            Node::Pane(_) => false,\n        }\n    }\n\n    pub(crate) fn remove(&mut self, pane: Pane) -> Option<Pane> {\n        match self {\n            Node::Split { a, b, .. } => {\n                if a.pane() == Some(pane) {\n                    *self = *b.clone();\n                    Some(self.first_pane())\n                } else if b.pane() == Some(pane) {\n                    *self = *a.clone();\n                    Some(self.first_pane())\n                } else {\n                    a.remove(pane).or_else(|| b.remove(pane))\n                }\n            }\n            Node::Pane(_) => None,\n        }\n    }\n\n    fn pane(&self) -> Option<Pane> {\n        match self {\n            Node::Split { .. } => None,\n            Node::Pane(pane) => Some(*pane),\n        }\n    }\n\n    fn first_pane(&self) -> Pane {\n        match self {\n            Node::Split { a, .. } => a.first_pane(),\n            Node::Pane(pane) => *pane,\n        }\n    }\n\n    fn compute_regions(\n        &self,\n        spacing: f32,\n        min_size: f32,\n        current: &Rectangle,\n        count: &Count,\n        regions: &mut BTreeMap<Pane, Rectangle>,\n    ) {\n        match (self, count) {\n            (\n                Node::Split {\n                    axis, ratio, a, b, ..\n                },\n                Count::Split {\n                    a: count_a,\n                    b: count_b,\n                    ..\n                },\n            ) => {\n                let (a_factor, b_factor) = match axis {\n                    Axis::Horizontal => (count_a.horizontal(), count_b.horizontal()),\n                    Axis::Vertical => (count_a.vertical(), count_b.vertical()),\n                };\n\n                let (region_a, region_b, _ratio) = axis.split(\n                    current,\n                    *ratio,\n                    spacing,\n                    min_size * (a_factor + 1) as f32 + spacing * a_factor as f32,\n                    min_size * (b_factor + 1) as f32 + spacing * b_factor as f32,\n                );\n\n                a.compute_regions(spacing, min_size, &region_a, count_a, regions);\n                b.compute_regions(spacing, min_size, &region_b, count_b, regions);\n            }\n            (Node::Pane(pane), Count::Pane) => {\n                let _ = regions.insert(*pane, *current);\n            }\n            _ => {\n                unreachable!(\"Node configuration and count do not match\")\n            }\n        }\n    }\n\n    fn compute_splits(\n        &self,\n        spacing: f32,\n        min_size: f32,\n        current: &Rectangle,\n        count: &Count,\n        splits: &mut BTreeMap<Split, (Axis, Rectangle, f32)>,\n    ) {\n        match (self, count) {\n            (\n                Node::Split {\n                    axis,\n                    ratio,\n                    a,\n                    b,\n                    id,\n                },\n                Count::Split {\n                    a: count_a,\n                    b: count_b,\n                    ..\n                },\n            ) => {\n                let (a_factor, b_factor) = match axis {\n                    Axis::Horizontal => (count_a.horizontal(), count_b.horizontal()),\n                    Axis::Vertical => (count_a.vertical(), count_b.vertical()),\n                };\n\n                let (region_a, region_b, ratio) = axis.split(\n                    current,\n                    *ratio,\n                    spacing,\n                    min_size * (a_factor + 1) as f32 + spacing * a_factor as f32,\n                    min_size * (b_factor + 1) as f32 + spacing * b_factor as f32,\n                );\n\n                let _ = splits.insert(*id, (*axis, *current, ratio));\n\n                a.compute_splits(spacing, min_size, &region_a, count_a, splits);\n                b.compute_splits(spacing, min_size, &region_b, count_b, splits);\n            }\n            (Node::Pane(_), Count::Pane) => {}\n            _ => {\n                unreachable!(\"Node configuration and split count do not match\")\n            }\n        }\n    }\n}\n\nimpl std::hash::Hash for Node {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        match self {\n            Node::Split {\n                id,\n                axis,\n                ratio,\n                a,\n                b,\n            } => {\n                id.hash(state);\n                axis.hash(state);\n                ((ratio * 100_000.0) as u32).hash(state);\n                a.hash(state);\n                b.hash(state);\n            }\n            Node::Pane(pane) => {\n                pane.hash(state);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "widget/src/pane_grid/pane.rs",
    "content": "/// A rectangular region in a [`PaneGrid`] used to display widgets.\n///\n/// [`PaneGrid`]: super::PaneGrid\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct Pane(pub(super) usize);\n"
  },
  {
    "path": "widget/src/pane_grid/split.rs",
    "content": "/// A divider that splits a region in a [`PaneGrid`] into two different panes.\n///\n/// [`PaneGrid`]: super::PaneGrid\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct Split(pub(super) usize);\n"
  },
  {
    "path": "widget/src/pane_grid/state.rs",
    "content": "//! The state of a [`PaneGrid`].\n//!\n//! [`PaneGrid`]: super::PaneGrid\nuse crate::core::{Point, Size};\nuse crate::pane_grid::{Axis, Configuration, Direction, Edge, Node, Pane, Region, Split, Target};\n\nuse std::borrow::Cow;\nuse std::collections::BTreeMap;\n\n/// The state of a [`PaneGrid`].\n///\n/// It keeps track of the state of each [`Pane`] and the position of each\n/// [`Split`].\n///\n/// The [`State`] needs to own any mutable contents a [`Pane`] may need. This is\n/// why this struct is generic over the type `T`. Values of this type are\n/// provided to the view function of [`PaneGrid::new`] for displaying each\n/// [`Pane`].\n///\n/// [`PaneGrid`]: super::PaneGrid\n/// [`PaneGrid::new`]: super::PaneGrid::new\n#[derive(Debug, Clone)]\npub struct State<T> {\n    /// The panes of the [`PaneGrid`].\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    pub panes: BTreeMap<Pane, T>,\n\n    /// The internal state of the [`PaneGrid`].\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    pub internal: Internal,\n}\n\nimpl<T> State<T> {\n    /// Creates a new [`State`], initializing the first pane with the provided\n    /// state.\n    ///\n    /// Alongside the [`State`], it returns the first [`Pane`] identifier.\n    pub fn new(first_pane_state: T) -> (Self, Pane) {\n        (\n            Self::with_configuration(Configuration::Pane(first_pane_state)),\n            Pane(0),\n        )\n    }\n\n    /// Creates a new [`State`] with the given [`Configuration`].\n    pub fn with_configuration(config: impl Into<Configuration<T>>) -> Self {\n        let mut panes = BTreeMap::default();\n\n        let internal = Internal::from_configuration(&mut panes, config.into(), 0);\n\n        State { panes, internal }\n    }\n\n    /// Returns the total amount of panes in the [`State`].\n    pub fn len(&self) -> usize {\n        self.panes.len()\n    }\n\n    /// Returns `true` if the amount of panes in the [`State`] is 0.\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    /// Returns the internal state of the given [`Pane`], if it exists.\n    pub fn get(&self, pane: Pane) -> Option<&T> {\n        self.panes.get(&pane)\n    }\n\n    /// Returns the internal state of the given [`Pane`] with mutability, if it\n    /// exists.\n    pub fn get_mut(&mut self, pane: Pane) -> Option<&mut T> {\n        self.panes.get_mut(&pane)\n    }\n\n    /// Returns an iterator over all the panes of the [`State`], alongside its\n    /// internal state.\n    pub fn iter(&self) -> impl Iterator<Item = (&Pane, &T)> {\n        self.panes.iter()\n    }\n\n    /// Returns a mutable iterator over all the panes of the [`State`],\n    /// alongside its internal state.\n    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Pane, &mut T)> {\n        self.panes.iter_mut()\n    }\n\n    /// Returns the layout of the [`State`].\n    pub fn layout(&self) -> &Node {\n        &self.internal.layout\n    }\n\n    /// Returns the adjacent [`Pane`] of another [`Pane`] in the given\n    /// direction, if there is one.\n    pub fn adjacent(&self, pane: Pane, direction: Direction) -> Option<Pane> {\n        let regions = self\n            .internal\n            .layout\n            .pane_regions(0.0, 0.0, Size::new(4096.0, 4096.0));\n\n        let current_region = regions.get(&pane)?;\n\n        let target = match direction {\n            Direction::Left => Point::new(current_region.x - 1.0, current_region.y + 1.0),\n            Direction::Right => Point::new(\n                current_region.x + current_region.width + 1.0,\n                current_region.y + 1.0,\n            ),\n            Direction::Up => Point::new(current_region.x + 1.0, current_region.y - 1.0),\n            Direction::Down => Point::new(\n                current_region.x + 1.0,\n                current_region.y + current_region.height + 1.0,\n            ),\n        };\n\n        let mut colliding_regions = regions.iter().filter(|(_, region)| region.contains(target));\n\n        let (pane, _) = colliding_regions.next()?;\n\n        Some(*pane)\n    }\n\n    /// Splits the given [`Pane`] into two in the given [`Axis`] and\n    /// initializing the new [`Pane`] with the provided internal state.\n    pub fn split(&mut self, axis: Axis, pane: Pane, state: T) -> Option<(Pane, Split)> {\n        self.split_node(axis, Some(pane), state, false)\n    }\n\n    /// Split a target [`Pane`] with a given [`Pane`] on a given [`Region`].\n    ///\n    /// Panes will be swapped by default for [`Region::Center`].\n    pub fn split_with(&mut self, target: Pane, pane: Pane, region: Region) {\n        match region {\n            Region::Center => self.swap(pane, target),\n            Region::Edge(edge) => match edge {\n                Edge::Top => {\n                    self.split_and_swap(Axis::Horizontal, target, pane, true);\n                }\n                Edge::Bottom => {\n                    self.split_and_swap(Axis::Horizontal, target, pane, false);\n                }\n                Edge::Left => {\n                    self.split_and_swap(Axis::Vertical, target, pane, true);\n                }\n                Edge::Right => {\n                    self.split_and_swap(Axis::Vertical, target, pane, false);\n                }\n            },\n        }\n    }\n\n    /// Drops the given [`Pane`] into the provided [`Target`].\n    pub fn drop(&mut self, pane: Pane, target: Target) {\n        match target {\n            Target::Edge(edge) => self.move_to_edge(pane, edge),\n            Target::Pane(target, region) => {\n                self.split_with(target, pane, region);\n            }\n        }\n    }\n\n    fn split_node(\n        &mut self,\n        axis: Axis,\n        pane: Option<Pane>,\n        state: T,\n        inverse: bool,\n    ) -> Option<(Pane, Split)> {\n        let node = if let Some(pane) = pane {\n            self.internal.layout.find(pane)?\n        } else {\n            // Major node\n            &mut self.internal.layout\n        };\n\n        let new_pane = {\n            self.internal.last_id = self.internal.last_id.checked_add(1)?;\n\n            Pane(self.internal.last_id)\n        };\n\n        let new_split = {\n            self.internal.last_id = self.internal.last_id.checked_add(1)?;\n\n            Split(self.internal.last_id)\n        };\n\n        if inverse {\n            node.split_inverse(new_split, axis, new_pane);\n        } else {\n            node.split(new_split, axis, new_pane);\n        }\n\n        let _ = self.panes.insert(new_pane, state);\n        let _ = self.internal.maximized.take();\n\n        Some((new_pane, new_split))\n    }\n\n    fn split_and_swap(&mut self, axis: Axis, target: Pane, pane: Pane, swap: bool) {\n        if let Some((state, _)) = self.close(pane)\n            && let Some((new_pane, _)) = self.split(axis, target, state)\n        {\n            // Ensure new node corresponds to original closed `Pane` for state continuity\n            self.relabel(new_pane, pane);\n\n            if swap {\n                self.swap(target, pane);\n            }\n        }\n    }\n\n    /// Move [`Pane`] to an [`Edge`] of the [`PaneGrid`].\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    pub fn move_to_edge(&mut self, pane: Pane, edge: Edge) {\n        match edge {\n            Edge::Top => {\n                self.split_major_node_and_swap(Axis::Horizontal, pane, true);\n            }\n            Edge::Bottom => {\n                self.split_major_node_and_swap(Axis::Horizontal, pane, false);\n            }\n            Edge::Left => {\n                self.split_major_node_and_swap(Axis::Vertical, pane, true);\n            }\n            Edge::Right => {\n                self.split_major_node_and_swap(Axis::Vertical, pane, false);\n            }\n        }\n    }\n\n    fn split_major_node_and_swap(&mut self, axis: Axis, pane: Pane, inverse: bool) {\n        if let Some((state, _)) = self.close(pane)\n            && let Some((new_pane, _)) = self.split_node(axis, None, state, inverse)\n        {\n            // Ensure new node corresponds to original closed `Pane` for state continuity\n            self.relabel(new_pane, pane);\n        }\n    }\n\n    fn relabel(&mut self, target: Pane, label: Pane) {\n        self.swap(target, label);\n\n        let _ = self\n            .panes\n            .remove(&target)\n            .and_then(|state| self.panes.insert(label, state));\n    }\n\n    /// Swaps the position of the provided panes in the [`State`].\n    ///\n    /// If you want to swap panes on drag and drop in your [`PaneGrid`], you\n    /// will need to call this method when handling a [`DragEvent`].\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    /// [`DragEvent`]: super::DragEvent\n    pub fn swap(&mut self, a: Pane, b: Pane) {\n        self.internal.layout.update(&|node| match node {\n            Node::Split { .. } => {}\n            Node::Pane(pane) => {\n                if *pane == a {\n                    *node = Node::Pane(b);\n                } else if *pane == b {\n                    *node = Node::Pane(a);\n                }\n            }\n        });\n    }\n\n    /// Resizes two panes by setting the position of the provided [`Split`].\n    ///\n    /// The ratio is a value in [0, 1], representing the exact position of a\n    /// [`Split`] between two panes.\n    ///\n    /// If you want to enable resize interactions in your [`PaneGrid`], you will\n    /// need to call this method when handling a [`ResizeEvent`].\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    /// [`ResizeEvent`]: super::ResizeEvent\n    pub fn resize(&mut self, split: Split, ratio: f32) {\n        let _ = self.internal.layout.resize(split, ratio);\n    }\n\n    /// Closes the given [`Pane`] and returns its internal state and its closest\n    /// sibling, if it exists.\n    pub fn close(&mut self, pane: Pane) -> Option<(T, Pane)> {\n        if self.internal.maximized == Some(pane) {\n            let _ = self.internal.maximized.take();\n        }\n\n        if let Some(sibling) = self.internal.layout.remove(pane) {\n            self.panes.remove(&pane).map(|state| (state, sibling))\n        } else {\n            None\n        }\n    }\n\n    /// Maximize the given [`Pane`]. Only this pane will be rendered by the\n    /// [`PaneGrid`] until [`Self::restore()`] is called.\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    pub fn maximize(&mut self, pane: Pane) {\n        self.internal.maximized = Some(pane);\n    }\n\n    /// Restore the currently maximized [`Pane`] to it's normal size. All panes\n    /// will be rendered by the [`PaneGrid`].\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    pub fn restore(&mut self) {\n        let _ = self.internal.maximized.take();\n    }\n\n    /// Returns the maximized [`Pane`] of the [`PaneGrid`].\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    pub fn maximized(&self) -> Option<Pane> {\n        self.internal.maximized\n    }\n}\n\n/// The internal state of a [`PaneGrid`].\n///\n/// [`PaneGrid`]: super::PaneGrid\n#[derive(Debug, Clone)]\npub struct Internal {\n    layout: Node,\n    last_id: usize,\n    maximized: Option<Pane>,\n}\n\nimpl Internal {\n    /// Initializes the [`Internal`] state of a [`PaneGrid`] from a\n    /// [`Configuration`].\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    pub fn from_configuration<T>(\n        panes: &mut BTreeMap<Pane, T>,\n        content: Configuration<T>,\n        next_id: usize,\n    ) -> Self {\n        let (layout, last_id) = match content {\n            Configuration::Split { axis, ratio, a, b } => {\n                let Internal {\n                    layout: a,\n                    last_id: next_id,\n                    ..\n                } = Self::from_configuration(panes, *a, next_id);\n\n                let Internal {\n                    layout: b,\n                    last_id: next_id,\n                    ..\n                } = Self::from_configuration(panes, *b, next_id);\n\n                (\n                    Node::Split {\n                        id: Split(next_id),\n                        axis,\n                        ratio,\n                        a: Box::new(a),\n                        b: Box::new(b),\n                    },\n                    next_id + 1,\n                )\n            }\n            Configuration::Pane(state) => {\n                let id = Pane(next_id);\n                let _ = panes.insert(id, state);\n\n                (Node::Pane(id), next_id + 1)\n            }\n        };\n\n        Self {\n            layout,\n            last_id,\n            maximized: None,\n        }\n    }\n\n    pub(super) fn layout(&self) -> Cow<'_, Node> {\n        match self.maximized {\n            Some(pane) => Cow::Owned(Node::Pane(pane)),\n            None => Cow::Borrowed(&self.layout),\n        }\n    }\n\n    pub(super) fn maximized(&self) -> Option<Pane> {\n        self.maximized\n    }\n}\n\n/// The current action of a [`PaneGrid`].\n///\n/// [`PaneGrid`]: super::PaneGrid\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub enum Action {\n    /// The [`PaneGrid`] is idle.\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    #[default]\n    Idle,\n    /// A [`Pane`] in the [`PaneGrid`] is being dragged.\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    Dragging {\n        /// The [`Pane`] being dragged.\n        pane: Pane,\n        /// The starting [`Point`] of the drag interaction.\n        origin: Point,\n    },\n    /// A [`Split`] in the [`PaneGrid`] is being dragged.\n    ///\n    /// [`PaneGrid`]: super::PaneGrid\n    Resizing {\n        /// The [`Split`] being dragged.\n        split: Split,\n        /// The [`Axis`] of the [`Split`].\n        axis: Axis,\n    },\n}\n\nimpl Action {\n    /// Returns the current [`Pane`] that is being dragged, if any.\n    pub fn picked_pane(&self) -> Option<(Pane, Point)> {\n        match *self {\n            Action::Dragging { pane, origin, .. } => Some((pane, origin)),\n            _ => None,\n        }\n    }\n\n    /// Returns the current [`Split`] that is being dragged, if any.\n    pub fn picked_split(&self) -> Option<(Split, Axis)> {\n        match *self {\n            Action::Resizing { split, axis, .. } => Some((split, axis)),\n            _ => None,\n        }\n    }\n}\n"
  },
  {
    "path": "widget/src/pane_grid/title_bar.rs",
    "content": "use crate::container;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget::{self, Tree};\nuse crate::core::{self, Element, Event, Layout, Padding, Point, Rectangle, Shell, Size, Vector};\nuse crate::pane_grid::controls::Controls;\n\n/// The title bar of a [`Pane`].\n///\n/// [`Pane`]: super::Pane\npub struct TitleBar<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    content: Element<'a, Message, Theme, Renderer>,\n    controls: Option<Controls<'a, Message, Theme, Renderer>>,\n    padding: Padding,\n    always_show_controls: bool,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Message, Theme, Renderer> TitleBar<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    /// Creates a new [`TitleBar`] with the given content.\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            content: content.into(),\n            controls: None,\n            padding: Padding::ZERO,\n            always_show_controls: false,\n            class: Theme::default(),\n        }\n    }\n\n    /// Sets the controls of the [`TitleBar`].\n    pub fn controls(mut self, controls: impl Into<Controls<'a, Message, Theme, Renderer>>) -> Self {\n        self.controls = Some(controls.into());\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`TitleBar`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets whether or not the [`controls`] attached to this [`TitleBar`] are\n    /// always visible.\n    ///\n    /// By default, the controls are only visible when the [`Pane`] of this\n    /// [`TitleBar`] is hovered.\n    ///\n    /// [`controls`]: Self::controls\n    /// [`Pane`]: super::Pane\n    pub fn always_show_controls(mut self) -> Self {\n        self.always_show_controls = true;\n        self\n    }\n\n    /// Sets the style of the [`TitleBar`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> container::Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<container::StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as container::StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`TitleBar`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> TitleBar<'_, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: core::Renderer,\n{\n    pub(super) fn state(&self) -> Tree {\n        let children = match self.controls.as_ref() {\n            Some(controls) => match controls.compact.as_ref() {\n                Some(compact) => vec![\n                    Tree::new(&self.content),\n                    Tree::new(&controls.full),\n                    Tree::new(compact),\n                ],\n                None => vec![\n                    Tree::new(&self.content),\n                    Tree::new(&controls.full),\n                    Tree::empty(),\n                ],\n            },\n            None => {\n                vec![Tree::new(&self.content), Tree::empty(), Tree::empty()]\n            }\n        };\n\n        Tree {\n            children,\n            ..Tree::empty()\n        }\n    }\n\n    pub(super) fn diff(&self, tree: &mut Tree) {\n        if tree.children.len() == 3 {\n            if let Some(controls) = self.controls.as_ref() {\n                if let Some(compact) = controls.compact.as_ref() {\n                    tree.children[2].diff(compact);\n                }\n\n                tree.children[1].diff(&controls.full);\n            }\n\n            tree.children[0].diff(&self.content);\n        } else {\n            *tree = self.state();\n        }\n    }\n\n    /// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`].\n    ///\n    /// [`Renderer`]: core::Renderer\n    pub fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        inherited_style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        show_controls: bool,\n    ) {\n        let bounds = layout.bounds();\n        let style = theme.style(&self.class);\n\n        let inherited_style = renderer::Style {\n            text_color: style.text_color.unwrap_or(inherited_style.text_color),\n        };\n\n        container::draw_background(renderer, &style, bounds);\n\n        let mut children = layout.children();\n        let padded = children.next().unwrap();\n\n        let mut children = padded.children();\n        let title_layout = children.next().unwrap();\n        let mut show_title = true;\n\n        if let Some(controls) = &self.controls\n            && (show_controls || self.always_show_controls)\n        {\n            let controls_layout = children.next().unwrap();\n            if title_layout.bounds().width + controls_layout.bounds().width > padded.bounds().width\n            {\n                if let Some(compact) = controls.compact.as_ref() {\n                    let compact_layout = children.next().unwrap();\n\n                    compact.as_widget().draw(\n                        &tree.children[2],\n                        renderer,\n                        theme,\n                        &inherited_style,\n                        compact_layout,\n                        cursor,\n                        viewport,\n                    );\n                } else {\n                    show_title = false;\n\n                    controls.full.as_widget().draw(\n                        &tree.children[1],\n                        renderer,\n                        theme,\n                        &inherited_style,\n                        controls_layout,\n                        cursor,\n                        viewport,\n                    );\n                }\n            } else {\n                controls.full.as_widget().draw(\n                    &tree.children[1],\n                    renderer,\n                    theme,\n                    &inherited_style,\n                    controls_layout,\n                    cursor,\n                    viewport,\n                );\n            }\n        }\n\n        if show_title {\n            self.content.as_widget().draw(\n                &tree.children[0],\n                renderer,\n                theme,\n                &inherited_style,\n                title_layout,\n                cursor,\n                viewport,\n            );\n        }\n    }\n\n    /// Returns whether the mouse cursor is over the pick area of the\n    /// [`TitleBar`] or not.\n    ///\n    /// The whole [`TitleBar`] is a pick area, except its controls.\n    pub fn is_over_pick_area(&self, layout: Layout<'_>, cursor_position: Point) -> bool {\n        if layout.bounds().contains(cursor_position) {\n            let mut children = layout.children();\n            let padded = children.next().unwrap();\n            let mut children = padded.children();\n            let title_layout = children.next().unwrap();\n\n            if let Some(controls) = self.controls.as_ref() {\n                let controls_layout = children.next().unwrap();\n\n                if title_layout.bounds().width + controls_layout.bounds().width\n                    > padded.bounds().width\n                {\n                    if controls.compact.is_some() {\n                        let compact_layout = children.next().unwrap();\n\n                        !compact_layout.bounds().contains(cursor_position)\n                            && !title_layout.bounds().contains(cursor_position)\n                    } else {\n                        !controls_layout.bounds().contains(cursor_position)\n                    }\n                } else {\n                    !controls_layout.bounds().contains(cursor_position)\n                        && !title_layout.bounds().contains(cursor_position)\n                }\n            } else {\n                !title_layout.bounds().contains(cursor_position)\n            }\n        } else {\n            false\n        }\n    }\n\n    pub(crate) fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits.shrink(self.padding);\n        let max_size = limits.max();\n\n        let title_layout = self.content.as_widget_mut().layout(\n            &mut tree.children[0],\n            renderer,\n            &layout::Limits::new(Size::ZERO, max_size),\n        );\n\n        let title_size = title_layout.size();\n\n        let node = if let Some(controls) = &mut self.controls {\n            let controls_layout = controls.full.as_widget_mut().layout(\n                &mut tree.children[1],\n                renderer,\n                &layout::Limits::new(Size::ZERO, max_size),\n            );\n\n            if title_layout.bounds().width + controls_layout.bounds().width > max_size.width {\n                if let Some(compact) = controls.compact.as_mut() {\n                    let compact_layout = compact.as_widget_mut().layout(\n                        &mut tree.children[2],\n                        renderer,\n                        &layout::Limits::new(Size::ZERO, max_size),\n                    );\n\n                    let compact_size = compact_layout.size();\n                    let space_before_controls = max_size.width - compact_size.width;\n\n                    let height = title_size.height.max(compact_size.height);\n\n                    layout::Node::with_children(\n                        Size::new(max_size.width, height),\n                        vec![\n                            title_layout,\n                            controls_layout,\n                            compact_layout.move_to(Point::new(space_before_controls, 0.0)),\n                        ],\n                    )\n                } else {\n                    let controls_size = controls_layout.size();\n                    let space_before_controls = max_size.width - controls_size.width;\n\n                    let height = title_size.height.max(controls_size.height);\n\n                    layout::Node::with_children(\n                        Size::new(max_size.width, height),\n                        vec![\n                            title_layout,\n                            controls_layout.move_to(Point::new(space_before_controls, 0.0)),\n                        ],\n                    )\n                }\n            } else {\n                let controls_size = controls_layout.size();\n                let space_before_controls = max_size.width - controls_size.width;\n\n                let height = title_size.height.max(controls_size.height);\n\n                layout::Node::with_children(\n                    Size::new(max_size.width, height),\n                    vec![\n                        title_layout,\n                        controls_layout.move_to(Point::new(space_before_controls, 0.0)),\n                    ],\n                )\n            }\n        } else {\n            layout::Node::with_children(\n                Size::new(max_size.width, title_size.height),\n                vec![title_layout],\n            )\n        };\n\n        layout::Node::container(node, self.padding)\n    }\n\n    pub(crate) fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        let mut children = layout.children();\n        let padded = children.next().unwrap();\n\n        let mut children = padded.children();\n        let title_layout = children.next().unwrap();\n        let mut show_title = true;\n\n        if let Some(controls) = &mut self.controls {\n            let controls_layout = children.next().unwrap();\n\n            if title_layout.bounds().width + controls_layout.bounds().width > padded.bounds().width\n            {\n                if let Some(compact) = controls.compact.as_mut() {\n                    let compact_layout = children.next().unwrap();\n\n                    compact.as_widget_mut().operate(\n                        &mut tree.children[2],\n                        compact_layout,\n                        renderer,\n                        operation,\n                    );\n                } else {\n                    show_title = false;\n\n                    controls.full.as_widget_mut().operate(\n                        &mut tree.children[1],\n                        controls_layout,\n                        renderer,\n                        operation,\n                    );\n                }\n            } else {\n                controls.full.as_widget_mut().operate(\n                    &mut tree.children[1],\n                    controls_layout,\n                    renderer,\n                    operation,\n                );\n            }\n        };\n\n        if show_title {\n            self.content.as_widget_mut().operate(\n                &mut tree.children[0],\n                title_layout,\n                renderer,\n                operation,\n            );\n        }\n    }\n\n    pub(crate) fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        let mut children = layout.children();\n        let padded = children.next().unwrap();\n\n        let mut children = padded.children();\n        let title_layout = children.next().unwrap();\n        let mut show_title = true;\n\n        if let Some(controls) = &mut self.controls {\n            let controls_layout = children.next().unwrap();\n\n            if title_layout.bounds().width + controls_layout.bounds().width > padded.bounds().width\n            {\n                if let Some(compact) = controls.compact.as_mut() {\n                    let compact_layout = children.next().unwrap();\n\n                    compact.as_widget_mut().update(\n                        &mut tree.children[2],\n                        event,\n                        compact_layout,\n                        cursor,\n                        renderer,\n                        shell,\n                        viewport,\n                    );\n                } else {\n                    show_title = false;\n\n                    controls.full.as_widget_mut().update(\n                        &mut tree.children[1],\n                        event,\n                        controls_layout,\n                        cursor,\n                        renderer,\n                        shell,\n                        viewport,\n                    );\n                }\n            } else {\n                controls.full.as_widget_mut().update(\n                    &mut tree.children[1],\n                    event,\n                    controls_layout,\n                    cursor,\n                    renderer,\n                    shell,\n                    viewport,\n                );\n            }\n        }\n\n        if show_title {\n            self.content.as_widget_mut().update(\n                &mut tree.children[0],\n                event,\n                title_layout,\n                cursor,\n                renderer,\n                shell,\n                viewport,\n            );\n        }\n    }\n\n    pub(crate) fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let mut children = layout.children();\n        let padded = children.next().unwrap();\n\n        let mut children = padded.children();\n        let title_layout = children.next().unwrap();\n\n        let title_interaction = self.content.as_widget().mouse_interaction(\n            &tree.children[0],\n            title_layout,\n            cursor,\n            viewport,\n            renderer,\n        );\n\n        if let Some(controls) = &self.controls {\n            let controls_layout = children.next().unwrap();\n            let controls_interaction = controls.full.as_widget().mouse_interaction(\n                &tree.children[1],\n                controls_layout,\n                cursor,\n                viewport,\n                renderer,\n            );\n\n            if title_layout.bounds().width + controls_layout.bounds().width > padded.bounds().width\n            {\n                if let Some(compact) = controls.compact.as_ref() {\n                    let compact_layout = children.next().unwrap();\n                    let compact_interaction = compact.as_widget().mouse_interaction(\n                        &tree.children[2],\n                        compact_layout,\n                        cursor,\n                        viewport,\n                        renderer,\n                    );\n\n                    compact_interaction.max(title_interaction)\n                } else {\n                    controls_interaction\n                }\n            } else {\n                controls_interaction.max(title_interaction)\n            }\n        } else {\n            title_interaction\n        }\n    }\n\n    pub(crate) fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        let mut children = layout.children();\n        let padded = children.next()?;\n\n        let mut children = padded.children();\n        let title_layout = children.next()?;\n\n        let Self {\n            content, controls, ..\n        } = self;\n\n        let mut states = tree.children.iter_mut();\n        let title_state = states.next().unwrap();\n        let controls_state = states.next().unwrap();\n\n        content\n            .as_widget_mut()\n            .overlay(title_state, title_layout, renderer, viewport, translation)\n            .or_else(move || {\n                controls.as_mut().and_then(|controls| {\n                    let controls_layout = children.next()?;\n\n                    if title_layout.bounds().width + controls_layout.bounds().width\n                        > padded.bounds().width\n                    {\n                        if let Some(compact) = controls.compact.as_mut() {\n                            let compact_state = states.next().unwrap();\n                            let compact_layout = children.next()?;\n\n                            compact.as_widget_mut().overlay(\n                                compact_state,\n                                compact_layout,\n                                renderer,\n                                viewport,\n                                translation,\n                            )\n                        } else {\n                            controls.full.as_widget_mut().overlay(\n                                controls_state,\n                                controls_layout,\n                                renderer,\n                                viewport,\n                                translation,\n                            )\n                        }\n                    } else {\n                        controls.full.as_widget_mut().overlay(\n                            controls_state,\n                            controls_layout,\n                            renderer,\n                            viewport,\n                            translation,\n                        )\n                    }\n                })\n            })\n    }\n}\n"
  },
  {
    "path": "widget/src/pane_grid.rs",
    "content": "//! Pane grids let your users split regions of your application and organize layout dynamically.\n//!\n//! ![Pane grid - Iced](https://iced.rs/examples/pane_grid.gif)\n//!\n//! This distribution of space is common in tiling window managers (like\n//! [`awesome`](https://awesomewm.org/), [`i3`](https://i3wm.org/), or even\n//! [`tmux`](https://github.com/tmux/tmux)).\n//!\n//! A [`PaneGrid`] supports:\n//!\n//! * Vertical and horizontal splits\n//! * Tracking of the last active pane\n//! * Mouse-based resizing\n//! * Drag and drop to reorganize panes\n//! * Hotkey support\n//! * Configurable modifier keys\n//! * [`State`] API to perform actions programmatically (`split`, `swap`, `resize`, etc.)\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::{pane_grid, text};\n//!\n//! struct State {\n//!     panes: pane_grid::State<Pane>,\n//! }\n//!\n//! enum Pane {\n//!     SomePane,\n//!     AnotherKindOfPane,\n//! }\n//!\n//! enum Message {\n//!     PaneDragged(pane_grid::DragEvent),\n//!     PaneResized(pane_grid::ResizeEvent),\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     pane_grid(&state.panes, |pane, state, is_maximized| {\n//!         pane_grid::Content::new(match state {\n//!             Pane::SomePane => text(\"This is some pane\"),\n//!             Pane::AnotherKindOfPane => text(\"This is another kind of pane\"),\n//!         })\n//!     })\n//!     .on_drag(Message::PaneDragged)\n//!     .on_resize(10, Message::PaneResized)\n//!     .into()\n//! }\n//! ```\n//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,\n//! drag and drop, and hotkey support.\n//!\n//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/master/examples/pane_grid\nmod axis;\nmod configuration;\nmod content;\nmod controls;\nmod direction;\nmod draggable;\nmod node;\nmod pane;\nmod split;\nmod title_bar;\n\npub mod state;\n\npub use axis::Axis;\npub use configuration::Configuration;\npub use content::Content;\npub use controls::Controls;\npub use direction::Direction;\npub use draggable::Draggable;\npub use node::Node;\npub use pane::Pane;\npub use split::Split;\npub use state::State;\npub use title_bar::TitleBar;\n\nuse crate::container;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay::{self, Group};\nuse crate::core::renderer;\nuse crate::core::touch;\nuse crate::core::widget;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    self, Background, Border, Color, Element, Event, Layout, Length, Pixels, Point, Rectangle,\n    Shell, Size, Theme, Vector, Widget,\n};\n\nconst DRAG_DEADBAND_DISTANCE: f32 = 10.0;\nconst THICKNESS_RATIO: f32 = 25.0;\n\n/// A collection of panes distributed using either vertical or horizontal splits\n/// to completely fill the space available.\n///\n/// ![Pane grid - Iced](https://iced.rs/examples/pane_grid.gif)\n///\n/// This distribution of space is common in tiling window managers (like\n/// [`awesome`](https://awesomewm.org/), [`i3`](https://i3wm.org/), or even\n/// [`tmux`](https://github.com/tmux/tmux)).\n///\n/// A [`PaneGrid`] supports:\n///\n/// * Vertical and horizontal splits\n/// * Tracking of the last active pane\n/// * Mouse-based resizing\n/// * Drag and drop to reorganize panes\n/// * Hotkey support\n/// * Configurable modifier keys\n/// * [`State`] API to perform actions programmatically (`split`, `swap`, `resize`, etc.)\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::{pane_grid, text};\n///\n/// struct State {\n///     panes: pane_grid::State<Pane>,\n/// }\n///\n/// enum Pane {\n///     SomePane,\n///     AnotherKindOfPane,\n/// }\n///\n/// enum Message {\n///     PaneDragged(pane_grid::DragEvent),\n///     PaneResized(pane_grid::ResizeEvent),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     pane_grid(&state.panes, |pane, state, is_maximized| {\n///         pane_grid::Content::new(match state {\n///             Pane::SomePane => text(\"This is some pane\"),\n///             Pane::AnotherKindOfPane => text(\"This is another kind of pane\"),\n///         })\n///     })\n///     .on_drag(Message::PaneDragged)\n///     .on_resize(10, Message::PaneResized)\n///     .into()\n/// }\n/// ```\npub struct PaneGrid<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    internal: &'a state::Internal,\n    panes: Vec<Pane>,\n    contents: Vec<Content<'a, Message, Theme, Renderer>>,\n    width: Length,\n    height: Length,\n    spacing: f32,\n    min_size: f32,\n    on_click: Option<Box<dyn Fn(Pane) -> Message + 'a>>,\n    on_drag: Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,\n    on_resize: Option<(f32, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>,\n    class: <Theme as Catalog>::Class<'a>,\n    last_mouse_interaction: Option<mouse::Interaction>,\n}\n\nimpl<'a, Message, Theme, Renderer> PaneGrid<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    /// Creates a [`PaneGrid`] with the given [`State`] and view function.\n    ///\n    /// The view function will be called to display each [`Pane`] present in the\n    /// [`State`]. [`bool`] is set if the pane is maximized.\n    pub fn new<T>(\n        state: &'a State<T>,\n        view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Theme, Renderer>,\n    ) -> Self {\n        let panes = state.panes.keys().copied().collect();\n        let contents = state\n            .panes\n            .iter()\n            .map(|(pane, pane_state)| match state.maximized() {\n                Some(p) if *pane == p => view(*pane, pane_state, true),\n                _ => view(*pane, pane_state, false),\n            })\n            .collect();\n\n        Self {\n            internal: &state.internal,\n            panes,\n            contents,\n            width: Length::Fill,\n            height: Length::Fill,\n            spacing: 0.0,\n            min_size: 50.0,\n            on_click: None,\n            on_drag: None,\n            on_resize: None,\n            class: <Theme as Catalog>::default(),\n            last_mouse_interaction: None,\n        }\n    }\n\n    /// Sets the width of the [`PaneGrid`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`PaneGrid`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the spacing _between_ the panes of the [`PaneGrid`].\n    pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {\n        self.spacing = amount.into().0;\n        self\n    }\n\n    /// Sets the minimum size of a [`Pane`] in the [`PaneGrid`] on both axes.\n    pub fn min_size(mut self, min_size: impl Into<Pixels>) -> Self {\n        self.min_size = min_size.into().0;\n        self\n    }\n\n    /// Sets the message that will be produced when a [`Pane`] of the\n    /// [`PaneGrid`] is clicked.\n    pub fn on_click<F>(mut self, f: F) -> Self\n    where\n        F: 'a + Fn(Pane) -> Message,\n    {\n        self.on_click = Some(Box::new(f));\n        self\n    }\n\n    /// Enables the drag and drop interactions of the [`PaneGrid`], which will\n    /// use the provided function to produce messages.\n    pub fn on_drag<F>(mut self, f: F) -> Self\n    where\n        F: 'a + Fn(DragEvent) -> Message,\n    {\n        if self.internal.maximized().is_none() {\n            self.on_drag = Some(Box::new(f));\n        }\n        self\n    }\n\n    /// Enables the resize interactions of the [`PaneGrid`], which will\n    /// use the provided function to produce messages.\n    ///\n    /// The `leeway` describes the amount of space around a split that can be\n    /// used to grab it.\n    ///\n    /// The grabbable area of a split will have a length of `spacing + leeway`,\n    /// properly centered. In other words, a length of\n    /// `(spacing + leeway) / 2.0` on either side of the split line.\n    pub fn on_resize<F>(mut self, leeway: impl Into<Pixels>, f: F) -> Self\n    where\n        F: 'a + Fn(ResizeEvent) -> Message,\n    {\n        if self.internal.maximized().is_none() {\n            self.on_resize = Some((leeway.into().0, Box::new(f)));\n        }\n        self\n    }\n\n    /// Sets the style of the [`PaneGrid`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self\n    where\n        <Theme as Catalog>::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`PaneGrid`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<<Theme as Catalog>::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n\n    fn drag_enabled(&self) -> bool {\n        if self.internal.maximized().is_none() {\n            self.on_drag.is_some()\n        } else {\n            Default::default()\n        }\n    }\n\n    fn grid_interaction(\n        &self,\n        action: &state::Action,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n    ) -> Option<mouse::Interaction> {\n        if action.picked_pane().is_some() {\n            return Some(mouse::Interaction::Grabbing);\n        }\n\n        let resize_leeway = self.on_resize.as_ref().map(|(leeway, _)| *leeway);\n        let node = self.internal.layout();\n\n        let resize_axis = action.picked_split().map(|(_, axis)| axis).or_else(|| {\n            resize_leeway.and_then(|leeway| {\n                let cursor_position = cursor.position()?;\n                let bounds = layout.bounds();\n\n                let splits = node.split_regions(self.spacing, self.min_size, bounds.size());\n\n                let relative_cursor =\n                    Point::new(cursor_position.x - bounds.x, cursor_position.y - bounds.y);\n\n                hovered_split(splits.iter(), self.spacing + leeway, relative_cursor)\n                    .map(|(_, axis, _)| axis)\n            })\n        });\n\n        if let Some(resize_axis) = resize_axis {\n            return Some(match resize_axis {\n                Axis::Horizontal => mouse::Interaction::ResizingVertically,\n                Axis::Vertical => mouse::Interaction::ResizingHorizontally,\n            });\n        }\n\n        None\n    }\n}\n\n#[derive(Default)]\nstruct Memory {\n    action: state::Action,\n    order: Vec<Pane>,\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for PaneGrid<'_, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<Memory>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(Memory::default())\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        self.contents.iter().map(Content::state).collect()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        let Memory { order, .. } = tree.state.downcast_ref();\n\n        // `Pane` always increments and is iterated by Ord so new\n        // states are always added at the end. We can simply remove\n        // states which no longer exist and `diff_children` will\n        // diff the remaining values in the correct order and\n        // add new states at the end\n\n        let mut i = 0;\n        let mut j = 0;\n        tree.children.retain(|_| {\n            let retain = self.panes.get(i) == order.get(j);\n\n            if retain {\n                i += 1;\n            }\n            j += 1;\n\n            retain\n        });\n\n        tree.diff_children_custom(\n            &self.contents,\n            |state, content| content.diff(state),\n            Content::state,\n        );\n\n        let Memory { order, .. } = tree.state.downcast_mut();\n        order.clone_from(&self.panes);\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let bounds = limits.resolve(self.width, self.height, Size::ZERO);\n        let regions = self\n            .internal\n            .layout()\n            .pane_regions(self.spacing, self.min_size, bounds);\n\n        let children = self\n            .panes\n            .iter_mut()\n            .zip(&mut self.contents)\n            .zip(tree.children.iter_mut())\n            .filter_map(|((pane, content), tree)| {\n                if self\n                    .internal\n                    .maximized()\n                    .is_some_and(|maximized| maximized != *pane)\n                {\n                    return Some(layout::Node::new(Size::ZERO));\n                }\n\n                let region = regions.get(pane)?;\n                let size = Size::new(region.width, region.height);\n\n                let node = content.layout(tree, renderer, &layout::Limits::new(size, size));\n\n                Some(node.move_to(Point::new(region.x, region.y)))\n            })\n            .collect();\n\n        layout::Node::with_children(bounds, children)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        operation.container(None, layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.panes\n                .iter_mut()\n                .zip(&mut self.contents)\n                .zip(&mut tree.children)\n                .zip(layout.children())\n                .filter(|(((pane, _), _), _)| {\n                    self.internal\n                        .maximized()\n                        .is_none_or(|maximized| **pane == maximized)\n                })\n                .for_each(|(((_, content), state), layout)| {\n                    content.operate(state, layout, renderer, operation);\n                });\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        let Memory { action, .. } = tree.state.downcast_mut();\n        let node = self.internal.layout();\n\n        let on_drag = if self.drag_enabled() {\n            &self.on_drag\n        } else {\n            &None\n        };\n\n        let picked_pane = action.picked_pane().map(|(pane, _)| pane);\n\n        for (((pane, content), tree), layout) in self\n            .panes\n            .iter()\n            .copied()\n            .zip(&mut self.contents)\n            .zip(&mut tree.children)\n            .zip(layout.children())\n            .filter(|(((pane, _), _), _)| {\n                self.internal\n                    .maximized()\n                    .is_none_or(|maximized| *pane == maximized)\n            })\n        {\n            let is_picked = picked_pane == Some(pane);\n\n            content.update(\n                tree, event, layout, cursor, renderer, shell, viewport, is_picked,\n            );\n        }\n\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                let bounds = layout.bounds();\n\n                if let Some(cursor_position) = cursor.position_over(bounds) {\n                    shell.capture_event();\n\n                    match &self.on_resize {\n                        Some((leeway, _)) => {\n                            let relative_cursor = Point::new(\n                                cursor_position.x - bounds.x,\n                                cursor_position.y - bounds.y,\n                            );\n\n                            let splits =\n                                node.split_regions(self.spacing, self.min_size, bounds.size());\n\n                            let clicked_split = hovered_split(\n                                splits.iter(),\n                                self.spacing + leeway,\n                                relative_cursor,\n                            );\n\n                            if let Some((split, axis, _)) = clicked_split {\n                                if action.picked_pane().is_none() {\n                                    *action = state::Action::Resizing { split, axis };\n                                }\n                            } else {\n                                click_pane(\n                                    action,\n                                    layout,\n                                    cursor_position,\n                                    shell,\n                                    self.panes.iter().copied().zip(&self.contents),\n                                    &self.on_click,\n                                    on_drag,\n                                );\n                            }\n                        }\n                        None => {\n                            click_pane(\n                                action,\n                                layout,\n                                cursor_position,\n                                shell,\n                                self.panes.iter().copied().zip(&self.contents),\n                                &self.on_click,\n                                on_drag,\n                            );\n                        }\n                    }\n                }\n            }\n            Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerLifted { .. })\n            | Event::Touch(touch::Event::FingerLost { .. }) => {\n                if let Some((pane, origin)) = action.picked_pane()\n                    && let Some(on_drag) = on_drag\n                    && let Some(cursor_position) = cursor.position()\n                {\n                    if cursor_position.distance(origin) > DRAG_DEADBAND_DISTANCE {\n                        let event = if let Some(edge) = in_edge(layout, cursor_position) {\n                            DragEvent::Dropped {\n                                pane,\n                                target: Target::Edge(edge),\n                            }\n                        } else {\n                            let dropped_region = self\n                                .panes\n                                .iter()\n                                .copied()\n                                .zip(&self.contents)\n                                .zip(layout.children())\n                                .find_map(|(target, layout)| {\n                                    layout_region(layout, cursor_position)\n                                        .map(|region| (target, region))\n                                });\n\n                            match dropped_region {\n                                Some(((target, _), region)) if pane != target => {\n                                    DragEvent::Dropped {\n                                        pane,\n                                        target: Target::Pane(target, region),\n                                    }\n                                }\n                                _ => DragEvent::Canceled { pane },\n                            }\n                        };\n\n                        shell.publish(on_drag(event));\n                    } else {\n                        shell.publish(on_drag(DragEvent::Canceled { pane }));\n                    }\n                }\n\n                *action = state::Action::Idle;\n            }\n            Event::Mouse(mouse::Event::CursorMoved { .. })\n            | Event::Touch(touch::Event::FingerMoved { .. }) => {\n                if let Some((_, on_resize)) = &self.on_resize {\n                    if let Some((split, _)) = action.picked_split() {\n                        let bounds = layout.bounds();\n\n                        let splits = node.split_regions(self.spacing, self.min_size, bounds.size());\n\n                        if let Some((axis, rectangle, _)) = splits.get(&split)\n                            && let Some(cursor_position) = cursor.position()\n                        {\n                            let ratio = match axis {\n                                Axis::Horizontal => {\n                                    let position = cursor_position.y - bounds.y - rectangle.y;\n\n                                    (position / rectangle.height).clamp(0.0, 1.0)\n                                }\n                                Axis::Vertical => {\n                                    let position = cursor_position.x - bounds.x - rectangle.x;\n\n                                    (position / rectangle.width).clamp(0.0, 1.0)\n                                }\n                            };\n\n                            shell.publish(on_resize(ResizeEvent { split, ratio }));\n\n                            shell.capture_event();\n                        }\n                    } else if action.picked_pane().is_some() {\n                        shell.request_redraw();\n                    }\n                }\n            }\n            _ => {}\n        }\n\n        if shell.redraw_request() != window::RedrawRequest::NextFrame {\n            let interaction = self\n                .grid_interaction(action, layout, cursor)\n                .or_else(|| {\n                    self.panes\n                        .iter()\n                        .zip(&self.contents)\n                        .zip(layout.children())\n                        .filter(|((pane, _content), _layout)| {\n                            self.internal\n                                .maximized()\n                                .is_none_or(|maximized| **pane == maximized)\n                        })\n                        .find_map(|((_pane, content), layout)| {\n                            content.grid_interaction(layout, cursor, on_drag.is_some())\n                        })\n                })\n                .unwrap_or(mouse::Interaction::None);\n\n            if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n                self.last_mouse_interaction = Some(interaction);\n            } else if self\n                .last_mouse_interaction\n                .is_some_and(|last_mouse_interaction| last_mouse_interaction != interaction)\n            {\n                shell.request_redraw();\n            }\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let Memory { action, .. } = tree.state.downcast_ref();\n\n        if let Some(grid_interaction) = self.grid_interaction(action, layout, cursor) {\n            return grid_interaction;\n        }\n\n        self.panes\n            .iter()\n            .copied()\n            .zip(&self.contents)\n            .zip(&tree.children)\n            .zip(layout.children())\n            .filter(|(((pane, _), _), _)| {\n                self.internal\n                    .maximized()\n                    .is_none_or(|maximized| *pane == maximized)\n            })\n            .map(|(((_, content), tree), layout)| {\n                content.mouse_interaction(\n                    tree,\n                    layout,\n                    cursor,\n                    viewport,\n                    renderer,\n                    self.drag_enabled(),\n                )\n            })\n            .max()\n            .unwrap_or_default()\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        defaults: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let Memory { action, .. } = tree.state.downcast_ref();\n        let node = self.internal.layout();\n        let resize_leeway = self.on_resize.as_ref().map(|(leeway, _)| *leeway);\n\n        let picked_pane = action.picked_pane().filter(|(_, origin)| {\n            cursor\n                .position()\n                .map(|position| position.distance(*origin))\n                .unwrap_or_default()\n                > DRAG_DEADBAND_DISTANCE\n        });\n\n        let picked_split = action\n            .picked_split()\n            .and_then(|(split, axis)| {\n                let bounds = layout.bounds();\n\n                let splits = node.split_regions(self.spacing, self.min_size, bounds.size());\n\n                let (_axis, region, ratio) = splits.get(&split)?;\n\n                let region = axis.split_line_bounds(*region, *ratio, self.spacing);\n\n                Some((axis, region + Vector::new(bounds.x, bounds.y), true))\n            })\n            .or_else(|| match resize_leeway {\n                Some(leeway) => {\n                    let cursor_position = cursor.position()?;\n                    let bounds = layout.bounds();\n\n                    let relative_cursor =\n                        Point::new(cursor_position.x - bounds.x, cursor_position.y - bounds.y);\n\n                    let splits = node.split_regions(self.spacing, self.min_size, bounds.size());\n\n                    let (_split, axis, region) =\n                        hovered_split(splits.iter(), self.spacing + leeway, relative_cursor)?;\n\n                    Some((axis, region + Vector::new(bounds.x, bounds.y), false))\n                }\n                None => None,\n            });\n\n        let pane_cursor = if picked_pane.is_some() {\n            mouse::Cursor::Unavailable\n        } else {\n            cursor\n        };\n\n        let mut render_picked_pane = None;\n\n        let pane_in_edge = if picked_pane.is_some() {\n            cursor\n                .position()\n                .and_then(|cursor_position| in_edge(layout, cursor_position))\n        } else {\n            None\n        };\n\n        let style = Catalog::style(theme, &self.class);\n\n        for (((id, content), tree), pane_layout) in self\n            .panes\n            .iter()\n            .copied()\n            .zip(&self.contents)\n            .zip(&tree.children)\n            .zip(layout.children())\n            .filter(|(((pane, _), _), _)| {\n                self.internal\n                    .maximized()\n                    .is_none_or(|maximized| maximized == *pane)\n            })\n        {\n            match picked_pane {\n                Some((dragging, origin)) if id == dragging => {\n                    render_picked_pane = Some(((content, tree), origin, pane_layout));\n                }\n                Some((dragging, _)) if id != dragging => {\n                    content.draw(\n                        tree,\n                        renderer,\n                        theme,\n                        defaults,\n                        pane_layout,\n                        pane_cursor,\n                        viewport,\n                    );\n\n                    if picked_pane.is_some()\n                        && pane_in_edge.is_none()\n                        && let Some(region) = cursor\n                            .position()\n                            .and_then(|cursor_position| layout_region(pane_layout, cursor_position))\n                    {\n                        let bounds = layout_region_bounds(pane_layout, region);\n\n                        renderer.fill_quad(\n                            renderer::Quad {\n                                bounds,\n                                border: style.hovered_region.border,\n                                ..renderer::Quad::default()\n                            },\n                            style.hovered_region.background,\n                        );\n                    }\n                }\n                _ => {\n                    content.draw(\n                        tree,\n                        renderer,\n                        theme,\n                        defaults,\n                        pane_layout,\n                        pane_cursor,\n                        viewport,\n                    );\n                }\n            }\n        }\n\n        if let Some(edge) = pane_in_edge {\n            let bounds = edge_bounds(layout, edge);\n\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds,\n                    border: style.hovered_region.border,\n                    ..renderer::Quad::default()\n                },\n                style.hovered_region.background,\n            );\n        }\n\n        // Render picked pane last\n        if let Some(((content, tree), origin, layout)) = render_picked_pane\n            && let Some(cursor_position) = cursor.position()\n        {\n            let bounds = layout.bounds();\n\n            let translation = cursor_position - Point::new(origin.x, origin.y);\n\n            renderer.with_translation(translation, |renderer| {\n                renderer.with_layer(bounds, |renderer| {\n                    content.draw(\n                        tree,\n                        renderer,\n                        theme,\n                        defaults,\n                        layout,\n                        pane_cursor,\n                        viewport,\n                    );\n                });\n            });\n        }\n\n        if picked_pane.is_none()\n            && let Some((axis, split_region, is_picked)) = picked_split\n        {\n            let highlight = if is_picked {\n                style.picked_split\n            } else {\n                style.hovered_split\n            };\n\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds: match axis {\n                        Axis::Horizontal => Rectangle {\n                            x: split_region.x,\n                            y: (split_region.y + (split_region.height - highlight.width) / 2.0)\n                                .round(),\n                            width: split_region.width,\n                            height: highlight.width,\n                        },\n                        Axis::Vertical => Rectangle {\n                            x: (split_region.x + (split_region.width - highlight.width) / 2.0)\n                                .round(),\n                            y: split_region.y,\n                            width: highlight.width,\n                            height: split_region.height,\n                        },\n                    },\n                    ..renderer::Quad::default()\n                },\n                highlight.color,\n            );\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        let children = self\n            .panes\n            .iter()\n            .copied()\n            .zip(&mut self.contents)\n            .zip(&mut tree.children)\n            .zip(layout.children())\n            .filter_map(|(((pane, content), state), layout)| {\n                if self\n                    .internal\n                    .maximized()\n                    .is_some_and(|maximized| maximized != pane)\n                {\n                    return None;\n                }\n\n                content.overlay(state, layout, renderer, viewport, translation)\n            })\n            .collect::<Vec<_>>();\n\n        (!children.is_empty()).then(|| Group::with_children(children).overlay())\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<PaneGrid<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(\n        pane_grid: PaneGrid<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(pane_grid)\n    }\n}\n\nfn layout_region(layout: Layout<'_>, cursor_position: Point) -> Option<Region> {\n    let bounds = layout.bounds();\n\n    if !bounds.contains(cursor_position) {\n        return None;\n    }\n\n    let region = if cursor_position.x < (bounds.x + bounds.width / 3.0) {\n        Region::Edge(Edge::Left)\n    } else if cursor_position.x > (bounds.x + 2.0 * bounds.width / 3.0) {\n        Region::Edge(Edge::Right)\n    } else if cursor_position.y < (bounds.y + bounds.height / 3.0) {\n        Region::Edge(Edge::Top)\n    } else if cursor_position.y > (bounds.y + 2.0 * bounds.height / 3.0) {\n        Region::Edge(Edge::Bottom)\n    } else {\n        Region::Center\n    };\n\n    Some(region)\n}\n\nfn click_pane<'a, Message, T>(\n    action: &mut state::Action,\n    layout: Layout<'_>,\n    cursor_position: Point,\n    shell: &mut Shell<'_, Message>,\n    contents: impl Iterator<Item = (Pane, T)>,\n    on_click: &Option<Box<dyn Fn(Pane) -> Message + 'a>>,\n    on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,\n) where\n    T: Draggable,\n{\n    let mut clicked_region = contents\n        .zip(layout.children())\n        .filter(|(_, layout)| layout.bounds().contains(cursor_position));\n\n    if let Some(((pane, content), layout)) = clicked_region.next() {\n        if let Some(on_click) = &on_click {\n            shell.publish(on_click(pane));\n        }\n\n        if let Some(on_drag) = &on_drag\n            && content.can_be_dragged_at(layout, cursor_position)\n        {\n            *action = state::Action::Dragging {\n                pane,\n                origin: cursor_position,\n            };\n\n            shell.publish(on_drag(DragEvent::Picked { pane }));\n        }\n    }\n}\n\nfn in_edge(layout: Layout<'_>, cursor: Point) -> Option<Edge> {\n    let bounds = layout.bounds();\n\n    let height_thickness = bounds.height / THICKNESS_RATIO;\n    let width_thickness = bounds.width / THICKNESS_RATIO;\n    let thickness = height_thickness.min(width_thickness);\n\n    if cursor.x > bounds.x && cursor.x < bounds.x + thickness {\n        Some(Edge::Left)\n    } else if cursor.x > bounds.x + bounds.width - thickness && cursor.x < bounds.x + bounds.width {\n        Some(Edge::Right)\n    } else if cursor.y > bounds.y && cursor.y < bounds.y + thickness {\n        Some(Edge::Top)\n    } else if cursor.y > bounds.y + bounds.height - thickness && cursor.y < bounds.y + bounds.height\n    {\n        Some(Edge::Bottom)\n    } else {\n        None\n    }\n}\n\nfn edge_bounds(layout: Layout<'_>, edge: Edge) -> Rectangle {\n    let bounds = layout.bounds();\n\n    let height_thickness = bounds.height / THICKNESS_RATIO;\n    let width_thickness = bounds.width / THICKNESS_RATIO;\n    let thickness = height_thickness.min(width_thickness);\n\n    match edge {\n        Edge::Top => Rectangle {\n            height: thickness,\n            ..bounds\n        },\n        Edge::Left => Rectangle {\n            width: thickness,\n            ..bounds\n        },\n        Edge::Right => Rectangle {\n            x: bounds.x + bounds.width - thickness,\n            width: thickness,\n            ..bounds\n        },\n        Edge::Bottom => Rectangle {\n            y: bounds.y + bounds.height - thickness,\n            height: thickness,\n            ..bounds\n        },\n    }\n}\n\nfn layout_region_bounds(layout: Layout<'_>, region: Region) -> Rectangle {\n    let bounds = layout.bounds();\n\n    match region {\n        Region::Center => bounds,\n        Region::Edge(edge) => match edge {\n            Edge::Top => Rectangle {\n                height: bounds.height / 2.0,\n                ..bounds\n            },\n            Edge::Left => Rectangle {\n                width: bounds.width / 2.0,\n                ..bounds\n            },\n            Edge::Right => Rectangle {\n                x: bounds.x + bounds.width / 2.0,\n                width: bounds.width / 2.0,\n                ..bounds\n            },\n            Edge::Bottom => Rectangle {\n                y: bounds.y + bounds.height / 2.0,\n                height: bounds.height / 2.0,\n                ..bounds\n            },\n        },\n    }\n}\n\n/// An event produced during a drag and drop interaction of a [`PaneGrid`].\n#[derive(Debug, Clone, Copy)]\npub enum DragEvent {\n    /// A [`Pane`] was picked for dragging.\n    Picked {\n        /// The picked [`Pane`].\n        pane: Pane,\n    },\n\n    /// A [`Pane`] was dropped on top of another [`Pane`].\n    Dropped {\n        /// The picked [`Pane`].\n        pane: Pane,\n\n        /// The [`Target`] where the picked [`Pane`] was dropped on.\n        target: Target,\n    },\n\n    /// A [`Pane`] was picked and then dropped outside of other [`Pane`]\n    /// boundaries.\n    Canceled {\n        /// The picked [`Pane`].\n        pane: Pane,\n    },\n}\n\n/// The [`Target`] area a pane can be dropped on.\n#[derive(Debug, Clone, Copy)]\npub enum Target {\n    /// An [`Edge`] of the full [`PaneGrid`].\n    Edge(Edge),\n    /// A single [`Pane`] of the [`PaneGrid`].\n    Pane(Pane, Region),\n}\n\n/// The region of a [`Pane`].\n#[derive(Debug, Clone, Copy, Default)]\npub enum Region {\n    /// Center region.\n    #[default]\n    Center,\n    /// Edge region.\n    Edge(Edge),\n}\n\n/// The edges of an area.\n#[derive(Debug, Clone, Copy)]\npub enum Edge {\n    /// Top edge.\n    Top,\n    /// Left edge.\n    Left,\n    /// Right edge.\n    Right,\n    /// Bottom edge.\n    Bottom,\n}\n\n/// An event produced during a resize interaction of a [`PaneGrid`].\n#[derive(Debug, Clone, Copy)]\npub struct ResizeEvent {\n    /// The [`Split`] that is being dragged for resizing.\n    pub split: Split,\n\n    /// The new ratio of the [`Split`].\n    ///\n    /// The ratio is a value in [0, 1], representing the exact position of a\n    /// [`Split`] between two panes.\n    pub ratio: f32,\n}\n\n/*\n * Helpers\n */\nfn hovered_split<'a>(\n    mut splits: impl Iterator<Item = (&'a Split, &'a (Axis, Rectangle, f32))>,\n    spacing: f32,\n    cursor_position: Point,\n) -> Option<(Split, Axis, Rectangle)> {\n    splits.find_map(|(split, (axis, region, ratio))| {\n        let bounds = axis.split_line_bounds(*region, *ratio, spacing);\n\n        if bounds.contains(cursor_position) {\n            Some((*split, *axis, bounds))\n        } else {\n            None\n        }\n    })\n}\n\n/// The appearance of a [`PaneGrid`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The appearance of a hovered region highlight.\n    pub hovered_region: Highlight,\n    /// The appearance of a picked split.\n    pub picked_split: Line,\n    /// The appearance of a hovered split.\n    pub hovered_split: Line,\n}\n\n/// The appearance of a highlight of the [`PaneGrid`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Highlight {\n    /// The [`Background`] of the pane region.\n    pub background: Background,\n    /// The [`Border`] of the pane region.\n    pub border: Border,\n}\n\n/// A line.\n///\n/// It is normally used to define the highlight of something, like a split.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Line {\n    /// The [`Color`] of the [`Line`].\n    pub color: Color,\n    /// The width of the [`Line`].\n    pub width: f32,\n}\n\n/// The theme catalog of a [`PaneGrid`].\npub trait Catalog: container::Catalog {\n    /// The item class of this [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by this [`Catalog`].\n    fn default<'a>() -> <Self as Catalog>::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &<Self as Catalog>::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`PaneGrid`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> StyleFn<'a, Self> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &StyleFn<'_, Self>) -> Style {\n        class(self)\n    }\n}\n\n/// The default style of a [`PaneGrid`].\npub fn default(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    Style {\n        hovered_region: Highlight {\n            background: Background::Color(Color {\n                a: 0.5,\n                ..palette.primary.base.color\n            }),\n            border: Border {\n                width: 2.0,\n                color: palette.primary.strong.color,\n                radius: 0.0.into(),\n            },\n        },\n        hovered_split: Line {\n            color: palette.primary.base.color,\n            width: 2.0,\n        },\n        picked_split: Line {\n            color: palette.primary.strong.color,\n            width: 2.0,\n        },\n    }\n}\n"
  },
  {
    "path": "widget/src/pick_list.rs",
    "content": "//! Pick lists display a dropdown list of selectable options.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::pick_list;\n//!\n//! struct State {\n//!    favorite: Option<Fruit>,\n//! }\n//!\n//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n//! enum Fruit {\n//!     Apple,\n//!     Orange,\n//!     Strawberry,\n//!     Tomato,\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     FruitSelected(Fruit),\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     let fruits = [\n//!         Fruit::Apple,\n//!         Fruit::Orange,\n//!         Fruit::Strawberry,\n//!         Fruit::Tomato,\n//!     ];\n//!\n//!     pick_list(\n//!         state.favorite,\n//!         fruits,\n//!         Fruit::to_string,\n//!     )\n//!     .on_select(Message::FruitSelected)\n//!     .placeholder(\"Select your favorite fruit...\")\n//!     .into()\n//! }\n//!\n//! fn update(state: &mut State, message: Message) {\n//!     match message {\n//!         Message::FruitSelected(fruit) => {\n//!             state.favorite = Some(fruit);\n//!         }\n//!     }\n//! }\n//!\n//! impl std::fmt::Display for Fruit {\n//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n//!         f.write_str(match self {\n//!             Self::Apple => \"Apple\",\n//!             Self::Orange => \"Orange\",\n//!             Self::Strawberry => \"Strawberry\",\n//!             Self::Tomato => \"Tomato\",\n//!         })\n//!     }\n//! }\n//! ```\nuse crate::core::alignment;\nuse crate::core::keyboard;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::text::paragraph;\nuse crate::core::text::{self, Text};\nuse crate::core::touch;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    Background, Border, Color, Element, Event, Layout, Length, Padding, Pixels, Point, Rectangle,\n    Shell, Size, Theme, Vector, Widget,\n};\nuse crate::overlay::menu::{self, Menu};\n\nuse std::borrow::Borrow;\nuse std::f32;\n\n/// A widget for selecting a single value from a list of options.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::pick_list;\n///\n/// struct State {\n///    favorite: Option<Fruit>,\n/// }\n///\n/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n/// enum Fruit {\n///     Apple,\n///     Orange,\n///     Strawberry,\n///     Tomato,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     FruitSelected(Fruit),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     let fruits = [\n///         Fruit::Apple,\n///         Fruit::Orange,\n///         Fruit::Strawberry,\n///         Fruit::Tomato,\n///     ];\n///\n///     pick_list(\n///         state.favorite,\n///         fruits,\n///         Fruit::to_string,\n///     )\n///     .on_select(Message::FruitSelected)\n///     .placeholder(\"Select your favorite fruit...\")\n///     .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::FruitSelected(fruit) => {\n///             state.favorite = Some(fruit);\n///         }\n///     }\n/// }\n///\n/// impl std::fmt::Display for Fruit {\n///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n///         f.write_str(match self {\n///             Self::Apple => \"Apple\",\n///             Self::Orange => \"Orange\",\n///             Self::Strawberry => \"Strawberry\",\n///             Self::Tomato => \"Tomato\",\n///         })\n///     }\n/// }\n/// ```\npub struct PickList<'a, T, L, V, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    T: PartialEq + Clone,\n    L: Borrow<[T]> + 'a,\n    V: Borrow<T> + 'a,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    options: L,\n    to_string: Box<dyn Fn(&T) -> String + 'a>,\n    on_select: Option<Box<dyn Fn(T) -> Message + 'a>>,\n    on_open: Option<Message>,\n    on_close: Option<Message>,\n    placeholder: Option<String>,\n    selected: Option<V>,\n    width: Length,\n    padding: Padding,\n    text_size: Option<Pixels>,\n    line_height: text::LineHeight,\n    shaping: text::Shaping,\n    ellipsis: text::Ellipsis,\n    font: Option<Renderer::Font>,\n    handle: Handle<Renderer::Font>,\n    class: <Theme as Catalog>::Class<'a>,\n    menu_class: <Theme as menu::Catalog>::Class<'a>,\n    last_status: Option<Status>,\n    menu_height: Length,\n}\n\nimpl<'a, T, L, V, Message, Theme, Renderer> PickList<'a, T, L, V, Message, Theme, Renderer>\nwhere\n    T: PartialEq + Clone,\n    L: Borrow<[T]> + 'a,\n    V: Borrow<T> + 'a,\n    Message: Clone,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// Creates a new [`PickList`] with the given list of options, the current\n    /// selected value, and the message to produce when an option is selected.\n    pub fn new(selected: Option<V>, options: L, to_string: impl Fn(&T) -> String + 'a) -> Self {\n        Self {\n            to_string: Box::new(to_string),\n            on_select: None,\n            on_open: None,\n            on_close: None,\n            options,\n            placeholder: None,\n            selected,\n            width: Length::Shrink,\n            padding: crate::button::DEFAULT_PADDING,\n            text_size: None,\n            line_height: text::LineHeight::default(),\n            shaping: text::Shaping::default(),\n            ellipsis: text::Ellipsis::End,\n            font: None,\n            handle: Handle::default(),\n            class: <Theme as Catalog>::default(),\n            menu_class: <Theme as Catalog>::default_menu(),\n            last_status: None,\n            menu_height: Length::Shrink,\n        }\n    }\n\n    /// Sets the placeholder of the [`PickList`].\n    pub fn placeholder(mut self, placeholder: impl Into<String>) -> Self {\n        self.placeholder = Some(placeholder.into());\n        self\n    }\n\n    /// Sets the width of the [`PickList`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Menu`].\n    pub fn menu_height(mut self, menu_height: impl Into<Length>) -> Self {\n        self.menu_height = menu_height.into();\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`PickList`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the text size of the [`PickList`].\n    pub fn text_size(mut self, size: impl Into<Pixels>) -> Self {\n        self.text_size = Some(size.into());\n        self\n    }\n\n    /// Sets the text [`text::LineHeight`] of the [`PickList`].\n    pub fn line_height(mut self, line_height: impl Into<text::LineHeight>) -> Self {\n        self.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the [`text::Shaping`] strategy of the [`PickList`].\n    pub fn shaping(mut self, shaping: text::Shaping) -> Self {\n        self.shaping = shaping;\n        self\n    }\n\n    /// Sets the [`text::Ellipsis`] strategy of the [`PickList`].\n    pub fn ellipsis(mut self, ellipsis: text::Ellipsis) -> Self {\n        self.ellipsis = ellipsis;\n        self\n    }\n\n    /// Sets the font of the [`PickList`].\n    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {\n        self.font = Some(font.into());\n        self\n    }\n\n    /// Sets the [`Handle`] of the [`PickList`].\n    pub fn handle(mut self, handle: Handle<Renderer::Font>) -> Self {\n        self.handle = handle;\n        self\n    }\n\n    /// Sets the message that will be produced when the [`PickList`] selected value changes.\n    pub fn on_select(mut self, on_select: impl Fn(T) -> Message + 'a) -> Self {\n        self.on_select = Some(Box::new(on_select));\n        self\n    }\n\n    /// Sets the message that will be produced when the [`PickList`] is opened.\n    pub fn on_open(mut self, on_open: Message) -> Self {\n        self.on_open = Some(on_open);\n        self\n    }\n\n    /// Sets the message that will be produced when the [`PickList`] is closed.\n    pub fn on_close(mut self, on_close: Message) -> Self {\n        self.on_close = Some(on_close);\n        self\n    }\n\n    /// Sets the style of the [`PickList`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        <Theme as Catalog>::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style of the [`Menu`].\n    #[must_use]\n    pub fn menu_style(mut self, style: impl Fn(&Theme) -> menu::Style + 'a) -> Self\n    where\n        <Theme as menu::Catalog>::Class<'a>: From<menu::StyleFn<'a, Theme>>,\n    {\n        self.menu_class = (Box::new(style) as menu::StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`PickList`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<<Theme as Catalog>::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n\n    /// Sets the style class of the [`Menu`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn menu_class(mut self, class: impl Into<<Theme as menu::Catalog>::Class<'a>>) -> Self {\n        self.menu_class = class.into();\n        self\n    }\n}\n\nimpl<'a, T, L, V, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for PickList<'a, T, L, V, Message, Theme, Renderer>\nwhere\n    T: Clone + PartialEq + 'a,\n    L: Borrow<[T]>,\n    V: Borrow<T>,\n    Message: Clone + 'a,\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State<Renderer::Paragraph>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::<Renderer::Paragraph>::new())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();\n\n        let font = self.font.unwrap_or_else(|| renderer.default_font());\n        let text_size = self.text_size.unwrap_or_else(|| renderer.default_size());\n        let options = self.options.borrow();\n\n        let option_text = Text {\n            content: \"\",\n            bounds: Size::new(\n                limits.max().width,\n                self.line_height.to_absolute(text_size).into(),\n            ),\n            size: text_size,\n            line_height: self.line_height,\n            font,\n            align_x: text::Alignment::Default,\n            align_y: alignment::Vertical::Center,\n            shaping: self.shaping,\n            wrapping: text::Wrapping::None,\n            ellipsis: self.ellipsis,\n            hint_factor: renderer.scale_factor(),\n        };\n\n        if let Some(placeholder) = &self.placeholder {\n            let _ = state.placeholder.update(Text {\n                content: placeholder,\n                ..option_text\n            });\n        }\n\n        let max_width = match self.width {\n            Length::Shrink => {\n                state.options.resize_with(options.len(), Default::default);\n\n                for (option, paragraph) in options.iter().zip(state.options.iter_mut()) {\n                    let label = (self.to_string)(option);\n\n                    let _ = paragraph.update(Text {\n                        content: &label,\n                        ..option_text\n                    });\n                }\n\n                let labels_width = state.options.iter().fold(0.0, |width, paragraph| {\n                    f32::max(width, paragraph.min_width())\n                });\n\n                labels_width.max(\n                    self.placeholder\n                        .as_ref()\n                        .map(|_| state.placeholder.min_width())\n                        .unwrap_or(0.0),\n                )\n            }\n            _ => 0.0,\n        };\n\n        let size = {\n            let intrinsic = Size::new(\n                max_width + text_size.0 + self.padding.left,\n                f32::from(self.line_height.to_absolute(text_size)),\n            );\n\n            limits\n                .width(self.width)\n                .shrink(self.padding)\n                .resolve(self.width, Length::Shrink, intrinsic)\n                .expand(self.padding)\n        };\n\n        layout::Node::new(size)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();\n\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                if state.is_open {\n                    // Event wasn't processed by overlay, so cursor was clicked either outside its\n                    // bounds or on the drop-down, either way we close the overlay.\n                    state.is_open = false;\n\n                    if let Some(on_close) = &self.on_close {\n                        shell.publish(on_close.clone());\n                    }\n\n                    shell.capture_event();\n                } else if cursor.is_over(layout.bounds()) {\n                    let selected = self.selected.as_ref().map(Borrow::borrow);\n\n                    state.is_open = true;\n                    state.hovered_option = self\n                        .options\n                        .borrow()\n                        .iter()\n                        .position(|option| Some(option) == selected);\n\n                    if let Some(on_open) = &self.on_open {\n                        shell.publish(on_open.clone());\n                    }\n\n                    shell.capture_event();\n                }\n            }\n            Event::Mouse(mouse::Event::WheelScrolled {\n                delta: mouse::ScrollDelta::Lines { y, .. },\n            }) => {\n                let Some(on_select) = &self.on_select else {\n                    return;\n                };\n\n                if state.keyboard_modifiers.command()\n                    && cursor.is_over(layout.bounds())\n                    && !state.is_open\n                {\n                    fn find_next<'a, T: PartialEq>(\n                        selected: &'a T,\n                        mut options: impl Iterator<Item = &'a T>,\n                    ) -> Option<&'a T> {\n                        let _ = options.find(|&option| option == selected);\n\n                        options.next()\n                    }\n\n                    let options = self.options.borrow();\n                    let selected = self.selected.as_ref().map(Borrow::borrow);\n\n                    let next_option = if *y < 0.0 {\n                        if let Some(selected) = selected {\n                            find_next(selected, options.iter())\n                        } else {\n                            options.first()\n                        }\n                    } else if *y > 0.0 {\n                        if let Some(selected) = selected {\n                            find_next(selected, options.iter().rev())\n                        } else {\n                            options.last()\n                        }\n                    } else {\n                        None\n                    };\n\n                    if let Some(next_option) = next_option {\n                        shell.publish(on_select(next_option.clone()));\n                    }\n\n                    shell.capture_event();\n                }\n            }\n            Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => {\n                state.keyboard_modifiers = *modifiers;\n            }\n            _ => {}\n        };\n\n        let status = {\n            let is_hovered = cursor.is_over(layout.bounds());\n\n            if self.on_select.is_none() {\n                Status::Disabled\n            } else if state.is_open {\n                Status::Opened { is_hovered }\n            } else if is_hovered {\n                Status::Hovered\n            } else {\n                Status::Active\n            }\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.last_status = Some(status);\n        } else if self\n            .last_status\n            .is_some_and(|last_status| last_status != status)\n        {\n            shell.request_redraw();\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let bounds = layout.bounds();\n        let is_mouse_over = cursor.is_over(bounds);\n\n        if is_mouse_over {\n            if self.on_select.is_some() {\n                mouse::Interaction::Pointer\n            } else {\n                mouse::Interaction::Idle\n            }\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let font = self.font.unwrap_or_else(|| renderer.default_font());\n        let selected = self.selected.as_ref().map(Borrow::borrow);\n        let state = tree.state.downcast_ref::<State<Renderer::Paragraph>>();\n\n        let bounds = layout.bounds();\n\n        let style = Catalog::style(\n            theme,\n            &self.class,\n            self.last_status.unwrap_or(Status::Active),\n        );\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds,\n                border: style.border,\n                ..renderer::Quad::default()\n            },\n            style.background,\n        );\n\n        let handle = match &self.handle {\n            Handle::Arrow { size } => Some((\n                Renderer::ICON_FONT,\n                Renderer::ARROW_DOWN_ICON,\n                *size,\n                text::LineHeight::default(),\n                text::Shaping::Basic,\n            )),\n            Handle::Static(Icon {\n                font,\n                code_point,\n                size,\n                line_height,\n                shaping,\n            }) => Some((*font, *code_point, *size, *line_height, *shaping)),\n            Handle::Dynamic { open, closed } => {\n                if state.is_open {\n                    Some((\n                        open.font,\n                        open.code_point,\n                        open.size,\n                        open.line_height,\n                        open.shaping,\n                    ))\n                } else {\n                    Some((\n                        closed.font,\n                        closed.code_point,\n                        closed.size,\n                        closed.line_height,\n                        closed.shaping,\n                    ))\n                }\n            }\n            Handle::None => None,\n        };\n\n        if let Some((font, code_point, size, line_height, shaping)) = handle {\n            let size = size.unwrap_or_else(|| renderer.default_size());\n\n            renderer.fill_text(\n                Text {\n                    content: code_point.to_string(),\n                    size,\n                    line_height,\n                    font,\n                    bounds: Size::new(bounds.width, f32::from(line_height.to_absolute(size))),\n                    align_x: text::Alignment::Right,\n                    align_y: alignment::Vertical::Center,\n                    shaping,\n                    wrapping: text::Wrapping::None,\n                    ellipsis: text::Ellipsis::None,\n                    hint_factor: None,\n                },\n                Point::new(\n                    bounds.x + bounds.width - self.padding.right,\n                    bounds.center_y(),\n                ),\n                style.handle_color,\n                *viewport,\n            );\n        }\n\n        let label = selected.map(&self.to_string);\n\n        if let Some(label) = label.or_else(|| self.placeholder.clone()) {\n            let text_size = self.text_size.unwrap_or_else(|| renderer.default_size());\n\n            renderer.fill_text(\n                Text {\n                    content: label,\n                    size: text_size,\n                    line_height: self.line_height,\n                    font,\n                    bounds: Size::new(\n                        bounds.width - self.padding.x(),\n                        f32::from(self.line_height.to_absolute(text_size)),\n                    ),\n                    align_x: text::Alignment::Default,\n                    align_y: alignment::Vertical::Center,\n                    shaping: self.shaping,\n                    wrapping: text::Wrapping::None,\n                    ellipsis: self.ellipsis,\n                    hint_factor: renderer.scale_factor(),\n                },\n                Point::new(bounds.x + self.padding.left, bounds.center_y()),\n                if selected.is_some() {\n                    style.text_color\n                } else {\n                    style.placeholder_color\n                },\n                *viewport,\n            );\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        let Some(on_select) = &self.on_select else {\n            return None;\n        };\n\n        let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();\n        let font = self.font.unwrap_or_else(|| renderer.default_font());\n\n        if state.is_open {\n            let bounds = layout.bounds();\n\n            let mut menu = Menu::new(\n                &mut state.menu,\n                self.options.borrow(),\n                &mut state.hovered_option,\n                &self.to_string,\n                |option| {\n                    state.is_open = false;\n\n                    (on_select)(option)\n                },\n                None,\n                &self.menu_class,\n            )\n            .width(bounds.width)\n            .padding(self.padding)\n            .font(font)\n            .ellipsis(self.ellipsis)\n            .shaping(self.shaping);\n\n            if let Some(text_size) = self.text_size {\n                menu = menu.text_size(text_size);\n            }\n\n            Some(menu.overlay(\n                layout.position() + translation,\n                *viewport,\n                bounds.height,\n                self.menu_height,\n            ))\n        } else {\n            None\n        }\n    }\n}\n\nimpl<'a, T, L, V, Message, Theme, Renderer> From<PickList<'a, T, L, V, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    T: Clone + PartialEq + 'a,\n    L: Borrow<[T]> + 'a,\n    V: Borrow<T> + 'a,\n    Message: Clone + 'a,\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n{\n    fn from(pick_list: PickList<'a, T, L, V, Message, Theme, Renderer>) -> Self {\n        Self::new(pick_list)\n    }\n}\n\n#[derive(Debug)]\nstruct State<P: text::Paragraph> {\n    menu: menu::State,\n    keyboard_modifiers: keyboard::Modifiers,\n    is_open: bool,\n    hovered_option: Option<usize>,\n    options: Vec<paragraph::Plain<P>>,\n    placeholder: paragraph::Plain<P>,\n}\n\nimpl<P: text::Paragraph> State<P> {\n    /// Creates a new [`State`] for a [`PickList`].\n    fn new() -> Self {\n        Self {\n            menu: menu::State::default(),\n            keyboard_modifiers: keyboard::Modifiers::default(),\n            is_open: bool::default(),\n            hovered_option: Option::default(),\n            options: Vec::new(),\n            placeholder: paragraph::Plain::default(),\n        }\n    }\n}\n\nimpl<P: text::Paragraph> Default for State<P> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// The handle to the right side of the [`PickList`].\n#[derive(Debug, Clone, PartialEq)]\npub enum Handle<Font> {\n    /// Displays an arrow icon (▼).\n    ///\n    /// This is the default.\n    Arrow {\n        /// Font size of the content.\n        size: Option<Pixels>,\n    },\n    /// A custom static handle.\n    Static(Icon<Font>),\n    /// A custom dynamic handle.\n    Dynamic {\n        /// The [`Icon`] used when [`PickList`] is closed.\n        closed: Icon<Font>,\n        /// The [`Icon`] used when [`PickList`] is open.\n        open: Icon<Font>,\n    },\n    /// No handle will be shown.\n    None,\n}\n\nimpl<Font> Default for Handle<Font> {\n    fn default() -> Self {\n        Self::Arrow { size: None }\n    }\n}\n\n/// The icon of a [`Handle`].\n#[derive(Debug, Clone, PartialEq)]\npub struct Icon<Font> {\n    /// Font that will be used to display the `code_point`,\n    pub font: Font,\n    /// The unicode code point that will be used as the icon.\n    pub code_point: char,\n    /// Font size of the content.\n    pub size: Option<Pixels>,\n    /// Line height of the content.\n    pub line_height: text::LineHeight,\n    /// The shaping strategy of the icon.\n    pub shaping: text::Shaping,\n}\n\n/// The possible status of a [`PickList`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`PickList`] can be interacted with.\n    Active,\n    /// The [`PickList`] is being hovered.\n    Hovered,\n    /// The [`PickList`] is open.\n    Opened {\n        /// Whether the [`PickList`] is hovered, while open.\n        is_hovered: bool,\n    },\n    /// The [`PickList`] is disabled.\n    Disabled,\n}\n\n/// The appearance of a pick list.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The text [`Color`] of the pick list.\n    pub text_color: Color,\n    /// The placeholder [`Color`] of the pick list.\n    pub placeholder_color: Color,\n    /// The handle [`Color`] of the pick list.\n    pub handle_color: Color,\n    /// The [`Background`] of the pick list.\n    pub background: Background,\n    /// The [`Border`] of the pick list.\n    pub border: Border,\n}\n\n/// The theme catalog of a [`PickList`].\npub trait Catalog: menu::Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> <Self as Catalog>::Class<'a>;\n\n    /// The default class for the menu of the [`PickList`].\n    fn default_menu<'a>() -> <Self as menu::Catalog>::Class<'a> {\n        <Self as menu::Catalog>::default()\n    }\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &<Self as Catalog>::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`PickList`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> StyleFn<'a, Self> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &StyleFn<'_, Self>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// The default style of the field of a [`PickList`].\npub fn default(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    let active = Style {\n        text_color: palette.background.weak.text,\n        background: palette.background.weak.color.into(),\n        placeholder_color: palette.secondary.base.color,\n        handle_color: palette.background.weak.text,\n        border: Border {\n            radius: 2.0.into(),\n            width: 1.0,\n            color: palette.background.strong.color,\n        },\n    };\n\n    match status {\n        Status::Active => active,\n        Status::Hovered | Status::Opened { .. } => Style {\n            border: Border {\n                color: palette.primary.strong.color,\n                ..active.border\n            },\n            ..active\n        },\n        Status::Disabled => Style {\n            text_color: palette.background.strongest.color,\n            background: palette.background.weaker.color.into(),\n            placeholder_color: palette.background.strongest.color,\n            handle_color: palette.background.strongest.color,\n            border: Border {\n                color: palette.background.weak.color,\n                ..active.border\n            },\n        },\n    }\n}\n"
  },
  {
    "path": "widget/src/pin.rs",
    "content": "//! A pin widget positions a widget at some fixed coordinates inside its boundaries.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::Length::Fill; }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! use iced::widget::pin;\n//! use iced::Fill;\n//!\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     pin(\"This text is displayed at coordinates (50, 50)!\")\n//!         .x(50)\n//!         .y(50)\n//!         .into()\n//! }\n//! ```\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget;\nuse crate::core::{\n    self, Element, Event, Layout, Length, Pixels, Point, Rectangle, Shell, Size, Vector, Widget,\n};\n\n/// A widget that positions its contents at some fixed coordinates inside of its boundaries.\n///\n/// By default, a [`Pin`] widget will try to fill its parent.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::Length::Fill; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::pin;\n/// use iced::Fill;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     pin(\"This text is displayed at coordinates (50, 50)!\")\n///         .x(50)\n///         .y(50)\n///         .into()\n/// }\n/// ```\npub struct Pin<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    content: Element<'a, Message, Theme, Renderer>,\n    width: Length,\n    height: Length,\n    position: Point,\n}\n\nimpl<'a, Message, Theme, Renderer> Pin<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    /// Creates a [`Pin`] widget with the given content.\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            content: content.into(),\n            width: Length::Fill,\n            height: Length::Fill,\n            position: Point::ORIGIN,\n        }\n    }\n\n    /// Sets the width of the [`Pin`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Pin`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the position of the [`Pin`]; where the pinned widget will be displayed.\n    pub fn position(mut self, position: impl Into<Point>) -> Self {\n        self.position = position.into();\n        self\n    }\n\n    /// Sets the X coordinate of the [`Pin`].\n    pub fn x(mut self, x: impl Into<Pixels>) -> Self {\n        self.position.x = x.into().0;\n        self\n    }\n\n    /// Sets the Y coordinate of the [`Pin`].\n    pub fn y(mut self, y: impl Into<Pixels>) -> Self {\n        self.position.y = y.into().0;\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Pin<'_, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    fn tag(&self) -> widget::tree::Tag {\n        self.content.as_widget().tag()\n    }\n\n    fn state(&self) -> widget::tree::State {\n        self.content.as_widget().state()\n    }\n\n    fn children(&self) -> Vec<widget::Tree> {\n        self.content.as_widget().children()\n    }\n\n    fn diff(&self, tree: &mut widget::Tree) {\n        self.content.as_widget().diff(tree);\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut widget::Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits.width(self.width).height(self.height);\n\n        let available = limits.max() - Size::new(self.position.x, self.position.y);\n\n        let node = self\n            .content\n            .as_widget_mut()\n            .layout(tree, renderer, &layout::Limits::new(Size::ZERO, available))\n            .move_to(self.position);\n\n        let size = limits.resolve(self.width, self.height, node.size());\n        layout::Node::with_children(size, vec![node])\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut widget::Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.content.as_widget_mut().operate(\n            tree,\n            layout.children().next().unwrap(),\n            renderer,\n            operation,\n        );\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut widget::Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget_mut().update(\n            tree,\n            event,\n            layout.children().next().unwrap(),\n            cursor,\n            renderer,\n            shell,\n            viewport,\n        );\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &widget::Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.content.as_widget().mouse_interaction(\n            tree,\n            layout.children().next().unwrap(),\n            cursor,\n            viewport,\n            renderer,\n        )\n    }\n\n    fn draw(\n        &self,\n        tree: &widget::Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        if let Some(clipped_viewport) = bounds.intersection(viewport) {\n            self.content.as_widget().draw(\n                tree,\n                renderer,\n                theme,\n                style,\n                layout.children().next().unwrap(),\n                cursor,\n                &clipped_viewport,\n            );\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut widget::Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.content.as_widget_mut().overlay(\n            tree,\n            layout.children().next().unwrap(),\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Pin<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(pin: Pin<'a, Message, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(pin)\n    }\n}\n"
  },
  {
    "path": "widget/src/progress_bar.rs",
    "content": "//! Progress bars visualize the progression of an extended computer operation, such as a download, file transfer, or installation.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::progress_bar;\n//!\n//! struct State {\n//!    progress: f32,\n//! }\n//!\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     progress_bar(0.0..=100.0, state.progress).into()\n//! }\n//! ```\nuse crate::core::border::{self, Border};\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::widget::Tree;\nuse crate::core::{\n    self, Background, Color, Element, Layout, Length, Rectangle, Size, Theme, Widget,\n};\n\nuse std::ops::RangeInclusive;\n\n/// A bar that displays progress.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::progress_bar;\n///\n/// struct State {\n///    progress: f32,\n/// }\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     progress_bar(0.0..=100.0, state.progress).into()\n/// }\n/// ```\npub struct ProgressBar<'a, Theme = crate::Theme>\nwhere\n    Theme: Catalog,\n{\n    range: RangeInclusive<f32>,\n    value: f32,\n    length: Length,\n    girth: Length,\n    is_vertical: bool,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Theme> ProgressBar<'a, Theme>\nwhere\n    Theme: Catalog,\n{\n    /// The default girth of a [`ProgressBar`].\n    pub const DEFAULT_GIRTH: f32 = 30.0;\n\n    /// Creates a new [`ProgressBar`].\n    ///\n    /// It expects:\n    ///   * an inclusive range of possible values\n    ///   * the current value of the [`ProgressBar`]\n    pub fn new(range: RangeInclusive<f32>, value: f32) -> Self {\n        ProgressBar {\n            value: value.clamp(*range.start(), *range.end()),\n            range,\n            length: Length::Fill,\n            girth: Length::from(Self::DEFAULT_GIRTH),\n            is_vertical: false,\n            class: Theme::default(),\n        }\n    }\n\n    /// Sets the width of the [`ProgressBar`].\n    pub fn length(mut self, length: impl Into<Length>) -> Self {\n        self.length = length.into();\n        self\n    }\n\n    /// Sets the height of the [`ProgressBar`].\n    pub fn girth(mut self, girth: impl Into<Length>) -> Self {\n        self.girth = girth.into();\n        self\n    }\n\n    /// Turns the [`ProgressBar`] into a vertical [`ProgressBar`].\n    ///\n    /// By default, a [`ProgressBar`] is horizontal.\n    pub fn vertical(mut self) -> Self {\n        self.is_vertical = true;\n        self\n    }\n\n    /// Sets the style of the [`ProgressBar`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`ProgressBar`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n\n    fn width(&self) -> Length {\n        if self.is_vertical {\n            self.girth\n        } else {\n            self.length\n        }\n    }\n\n    fn height(&self) -> Length {\n        if self.is_vertical {\n            self.length\n        } else {\n            self.girth\n        }\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for ProgressBar<'_, Theme>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width(),\n            height: self.height(),\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::atomic(limits, self.width(), self.height())\n    }\n\n    fn draw(\n        &self,\n        _tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n        let (range_start, range_end) = self.range.clone().into_inner();\n\n        let length = if self.is_vertical {\n            bounds.height\n        } else {\n            bounds.width\n        };\n\n        let active_progress_length = if range_start >= range_end {\n            0.0\n        } else {\n            length * (self.value - range_start) / (range_end - range_start)\n        };\n\n        let style = theme.style(&self.class);\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: Rectangle { ..bounds },\n                border: style.border,\n                ..renderer::Quad::default()\n            },\n            style.background,\n        );\n\n        if active_progress_length > 0.0 {\n            let bounds = if self.is_vertical {\n                Rectangle {\n                    y: bounds.y + bounds.height - active_progress_length,\n                    height: active_progress_length,\n                    ..bounds\n                }\n            } else {\n                Rectangle {\n                    width: active_progress_length,\n                    ..bounds\n                }\n            };\n\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds,\n                    border: Border {\n                        color: Color::TRANSPARENT,\n                        ..style.border\n                    },\n                    ..renderer::Quad::default()\n                },\n                style.bar,\n            );\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<ProgressBar<'a, Theme>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a + Catalog,\n    Renderer: 'a + core::Renderer,\n{\n    fn from(progress_bar: ProgressBar<'a, Theme>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(progress_bar)\n    }\n}\n\n/// The appearance of a progress bar.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`Background`] of the progress bar.\n    pub background: Background,\n    /// The [`Background`] of the bar of the progress bar.\n    pub bar: Background,\n    /// The [`Border`] of the progress bar.\n    pub border: Border,\n}\n\n/// The theme catalog of a [`ProgressBar`].\npub trait Catalog: Sized {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`ProgressBar`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(primary)\n    }\n\n    fn style(&self, class: &Self::Class<'_>) -> Style {\n        class(self)\n    }\n}\n\n/// The primary style of a [`ProgressBar`].\npub fn primary(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    styled(palette.background.strong.color, palette.primary.base.color)\n}\n\n/// The secondary style of a [`ProgressBar`].\npub fn secondary(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    styled(\n        palette.background.strong.color,\n        palette.secondary.base.color,\n    )\n}\n\n/// The success style of a [`ProgressBar`].\npub fn success(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    styled(palette.background.strong.color, palette.success.base.color)\n}\n\n/// The warning style of a [`ProgressBar`].\npub fn warning(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    styled(palette.background.strong.color, palette.warning.base.color)\n}\n\n/// The danger style of a [`ProgressBar`].\npub fn danger(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    styled(palette.background.strong.color, palette.danger.base.color)\n}\n\nfn styled(background: impl Into<Background>, bar: impl Into<Background>) -> Style {\n    Style {\n        background: background.into(),\n        bar: bar.into(),\n        border: border::rounded(2),\n    }\n}\n"
  },
  {
    "path": "widget/src/qr_code.rs",
    "content": "//! QR codes display information in a type of two-dimensional matrix barcode.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::qr_code;\n//!\n//! struct State {\n//!    data: qr_code::Data,\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     qr_code(&state.data).into()\n//! }\n//! ```\nuse crate::Renderer;\nuse crate::canvas;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer::{self, Renderer as _};\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::{\n    Color, Element, Layout, Length, Pixels, Point, Rectangle, Size, Theme, Vector, Widget,\n};\n\nuse std::cell::RefCell;\nuse thiserror::Error;\n\nconst DEFAULT_CELL_SIZE: f32 = 4.0;\nconst QUIET_ZONE: usize = 2;\n\n/// A type of matrix barcode consisting of squares arranged in a grid which\n/// can be read by an imaging device, such as a camera.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::qr_code;\n///\n/// struct State {\n///    data: qr_code::Data,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     qr_code(&state.data).into()\n/// }\n/// ```\npub struct QRCode<'a, Theme = crate::Theme>\nwhere\n    Theme: Catalog,\n{\n    data: &'a Data,\n    cell_size: f32,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Theme> QRCode<'a, Theme>\nwhere\n    Theme: Catalog,\n{\n    /// Creates a new [`QRCode`] with the provided [`Data`].\n    pub fn new(data: &'a Data) -> Self {\n        Self {\n            data,\n            cell_size: DEFAULT_CELL_SIZE,\n            class: Theme::default(),\n        }\n    }\n\n    /// Sets the size of the squares of the grid cell of the [`QRCode`].\n    pub fn cell_size(mut self, cell_size: impl Into<Pixels>) -> Self {\n        self.cell_size = cell_size.into().0;\n        self\n    }\n\n    /// Sets the size of the entire [`QRCode`].\n    pub fn total_size(mut self, total_size: impl Into<Pixels>) -> Self {\n        self.cell_size = total_size.into().0 / (self.data.width + 2 * QUIET_ZONE) as f32;\n\n        self\n    }\n\n    /// Sets the style of the [`QRCode`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`QRCode`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'_, Theme>\nwhere\n    Theme: Catalog,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: Length::Shrink,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        _limits: &layout::Limits,\n    ) -> layout::Node {\n        let side_length = (self.data.width + 2 * QUIET_ZONE) as f32 * self.cell_size;\n\n        layout::Node::new(Size::new(side_length, side_length))\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_ref::<State>();\n\n        let bounds = layout.bounds();\n        let side_length = self.data.width + 2 * QUIET_ZONE;\n\n        let style = theme.style(&self.class);\n        let mut last_style = state.last_style.borrow_mut();\n\n        if Some(style) != *last_style {\n            self.data.cache.clear();\n\n            *last_style = Some(style);\n        }\n\n        // Reuse cache if possible\n        let geometry = self.data.cache.draw(renderer, bounds.size(), |frame| {\n            // Scale units to cell size\n            frame.scale(self.cell_size);\n\n            // Draw background\n            frame.fill_rectangle(\n                Point::ORIGIN,\n                Size::new(side_length as f32, side_length as f32),\n                style.background,\n            );\n\n            // Avoid drawing on the quiet zone\n            frame.translate(Vector::new(QUIET_ZONE as f32, QUIET_ZONE as f32));\n\n            // Draw contents\n            self.data\n                .contents\n                .iter()\n                .enumerate()\n                .filter(|(_, value)| **value == qrcode::Color::Dark)\n                .for_each(|(index, _)| {\n                    let row = index / self.data.width;\n                    let column = index % self.data.width;\n\n                    frame.fill_rectangle(\n                        Point::new(column as f32, row as f32),\n                        Size::UNIT,\n                        style.cell,\n                    );\n                });\n        });\n\n        renderer.with_translation(bounds.position() - Point::ORIGIN, |renderer| {\n            use crate::graphics::geometry::Renderer as _;\n\n            renderer.draw_geometry(geometry);\n        });\n    }\n}\n\nimpl<'a, Message, Theme> From<QRCode<'a, Theme>> for Element<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog + 'a,\n{\n    fn from(qr_code: QRCode<'a, Theme>) -> Self {\n        Self::new(qr_code)\n    }\n}\n\n/// The data of a [`QRCode`].\n///\n/// It stores the contents that will be displayed.\n#[derive(Debug)]\npub struct Data {\n    contents: Vec<qrcode::Color>,\n    width: usize,\n    cache: canvas::Cache<Renderer>,\n}\n\nimpl Data {\n    /// Creates a new [`Data`] with the provided data.\n    ///\n    /// This method uses an [`ErrorCorrection::Medium`] and chooses the smallest\n    /// size to display the data.\n    pub fn new(data: impl AsRef<[u8]>) -> Result<Self, Error> {\n        let encoded = qrcode::QrCode::new(data)?;\n\n        Ok(Self::build(encoded))\n    }\n\n    /// Creates a new [`Data`] with the provided [`ErrorCorrection`].\n    pub fn with_error_correction(\n        data: impl AsRef<[u8]>,\n        error_correction: ErrorCorrection,\n    ) -> Result<Self, Error> {\n        let encoded = qrcode::QrCode::with_error_correction_level(data, error_correction.into())?;\n\n        Ok(Self::build(encoded))\n    }\n\n    /// Creates a new [`Data`] with the provided [`Version`] and\n    /// [`ErrorCorrection`].\n    pub fn with_version(\n        data: impl AsRef<[u8]>,\n        version: Version,\n        error_correction: ErrorCorrection,\n    ) -> Result<Self, Error> {\n        let encoded = qrcode::QrCode::with_version(data, version.into(), error_correction.into())?;\n\n        Ok(Self::build(encoded))\n    }\n\n    fn build(encoded: qrcode::QrCode) -> Self {\n        let width = encoded.width();\n        let contents = encoded.into_colors();\n\n        Self {\n            contents,\n            width,\n            cache: canvas::Cache::new(),\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n/// The size of a [`QRCode`].\n///\n/// The higher the version the larger the grid of cells, and therefore the more\n/// information the [`QRCode`] can carry.\npub enum Version {\n    /// A normal QR code version. It should be between 1 and 40.\n    Normal(u8),\n\n    /// A micro QR code version. It should be between 1 and 4.\n    Micro(u8),\n}\n\nimpl From<Version> for qrcode::Version {\n    fn from(version: Version) -> Self {\n        match version {\n            Version::Normal(v) => qrcode::Version::Normal(i16::from(v)),\n            Version::Micro(v) => qrcode::Version::Micro(i16::from(v)),\n        }\n    }\n}\n\n/// The error correction level.\n///\n/// It controls the amount of data that can be damaged while still being able\n/// to recover the original information.\n///\n/// A higher error correction level allows for more corrupted data.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum ErrorCorrection {\n    /// Low error correction. 7% of the data can be restored.\n    Low,\n    /// Medium error correction. 15% of the data can be restored.\n    Medium,\n    /// Quartile error correction. 25% of the data can be restored.\n    Quartile,\n    /// High error correction. 30% of the data can be restored.\n    High,\n}\n\nimpl From<ErrorCorrection> for qrcode::EcLevel {\n    fn from(ec_level: ErrorCorrection) -> Self {\n        match ec_level {\n            ErrorCorrection::Low => qrcode::EcLevel::L,\n            ErrorCorrection::Medium => qrcode::EcLevel::M,\n            ErrorCorrection::Quartile => qrcode::EcLevel::Q,\n            ErrorCorrection::High => qrcode::EcLevel::H,\n        }\n    }\n}\n\n/// An error that occurred when building a [`Data`] for a [`QRCode`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]\npub enum Error {\n    /// The data is too long to encode in a QR code for the chosen [`Version`].\n    #[error(\"The data is too long to encode in a QR code for the chosen version\")]\n    DataTooLong,\n\n    /// The chosen [`Version`] and [`ErrorCorrection`] combination is invalid.\n    #[error(\"The chosen version and error correction level combination is invalid.\")]\n    InvalidVersion,\n\n    /// One or more characters in the provided data are not supported by the\n    /// chosen [`Version`].\n    #[error(\n        \"One or more characters in the provided data are not supported by the \\\n        chosen version\"\n    )]\n    UnsupportedCharacterSet,\n\n    /// The chosen ECI designator is invalid. A valid designator should be\n    /// between 0 and 999999.\n    #[error(\n        \"The chosen ECI designator is invalid. A valid designator should be \\\n        between 0 and 999999.\"\n    )]\n    InvalidEciDesignator,\n\n    /// A character that does not belong to the character set was found.\n    #[error(\"A character that does not belong to the character set was found\")]\n    InvalidCharacter,\n}\n\nimpl From<qrcode::types::QrError> for Error {\n    fn from(error: qrcode::types::QrError) -> Self {\n        use qrcode::types::QrError;\n\n        match error {\n            QrError::DataTooLong => Error::DataTooLong,\n            QrError::InvalidVersion => Error::InvalidVersion,\n            QrError::UnsupportedCharacterSet => Error::UnsupportedCharacterSet,\n            QrError::InvalidEciDesignator => Error::InvalidEciDesignator,\n            QrError::InvalidCharacter => Error::InvalidCharacter,\n        }\n    }\n}\n\n#[derive(Default)]\nstruct State {\n    last_style: RefCell<Option<Style>>,\n}\n\n/// The appearance of a QR code.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The color of the QR code data cells\n    pub cell: Color,\n    /// The color of the QR code background\n    pub background: Color,\n}\n\n/// The theme catalog of a [`QRCode`].\npub trait Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`QRCode`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>) -> Style {\n        class(self)\n    }\n}\n\n/// The default style of a [`QRCode`].\npub fn default(theme: &Theme) -> Style {\n    let palette = theme.seed();\n\n    Style {\n        cell: palette.text,\n        background: palette.background,\n    }\n}\n"
  },
  {
    "path": "widget/src/radio.rs",
    "content": "//! Radio buttons let users choose a single option from a bunch of options.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::{column, radio};\n//!\n//! struct State {\n//!    selection: Option<Choice>,\n//! }\n//!\n//! #[derive(Debug, Clone, Copy)]\n//! enum Message {\n//!     RadioSelected(Choice),\n//! }\n//!\n//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n//! enum Choice {\n//!     A,\n//!     B,\n//!     C,\n//!     All,\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     let a = radio(\n//!         \"A\",\n//!         Choice::A,\n//!         state.selection,\n//!         Message::RadioSelected,\n//!     );\n//!\n//!     let b = radio(\n//!         \"B\",\n//!         Choice::B,\n//!         state.selection,\n//!         Message::RadioSelected,\n//!     );\n//!\n//!     let c = radio(\n//!         \"C\",\n//!         Choice::C,\n//!         state.selection,\n//!         Message::RadioSelected,\n//!     );\n//!\n//!     let all = radio(\n//!         \"All of the above\",\n//!         Choice::All,\n//!         state.selection,\n//!         Message::RadioSelected\n//!     );\n//!\n//!     column![a, b, c, all].into()\n//! }\n//! ```\nuse crate::core::alignment;\nuse crate::core::border::{self, Border};\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::text;\nuse crate::core::touch;\nuse crate::core::widget;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    Background, Color, Element, Event, Layout, Length, Pixels, Rectangle, Shell, Size, Theme,\n    Widget,\n};\n\n/// A circular button representing a choice.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::{column, radio};\n///\n/// struct State {\n///    selection: Option<Choice>,\n/// }\n///\n/// #[derive(Debug, Clone, Copy)]\n/// enum Message {\n///     RadioSelected(Choice),\n/// }\n///\n/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n/// enum Choice {\n///     A,\n///     B,\n///     C,\n///     All,\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     let a = radio(\n///         \"A\",\n///         Choice::A,\n///         state.selection,\n///         Message::RadioSelected,\n///     );\n///\n///     let b = radio(\n///         \"B\",\n///         Choice::B,\n///         state.selection,\n///         Message::RadioSelected,\n///     );\n///\n///     let c = radio(\n///         \"C\",\n///         Choice::C,\n///         state.selection,\n///         Message::RadioSelected,\n///     );\n///\n///     let all = radio(\n///         \"All of the above\",\n///         Choice::All,\n///         state.selection,\n///         Message::RadioSelected\n///     );\n///\n///     column![a, b, c, all].into()\n/// }\n/// ```\npub struct Radio<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    is_selected: bool,\n    on_click: Message,\n    label: String,\n    width: Length,\n    size: f32,\n    spacing: f32,\n    text_size: Option<Pixels>,\n    line_height: text::LineHeight,\n    shaping: text::Shaping,\n    wrapping: text::Wrapping,\n    font: Option<Renderer::Font>,\n    class: Theme::Class<'a>,\n    last_status: Option<Status>,\n}\n\nimpl<'a, Message, Theme, Renderer> Radio<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// The default size of a [`Radio`] button.\n    pub const DEFAULT_SIZE: f32 = 16.0;\n\n    /// The default spacing of a [`Radio`] button.\n    pub const DEFAULT_SPACING: f32 = 8.0;\n\n    /// Creates a new [`Radio`] button.\n    ///\n    /// It expects:\n    ///   * the value related to the [`Radio`] button\n    ///   * the label of the [`Radio`] button\n    ///   * the current selected value\n    ///   * a function that will be called when the [`Radio`] is selected. It\n    ///     receives the value of the radio and must produce a `Message`.\n    pub fn new<F, V>(label: impl Into<String>, value: V, selected: Option<V>, f: F) -> Self\n    where\n        V: Eq + Copy,\n        F: FnOnce(V) -> Message,\n    {\n        Radio {\n            is_selected: Some(value) == selected,\n            on_click: f(value),\n            label: label.into(),\n            width: Length::Shrink,\n            size: Self::DEFAULT_SIZE,\n            spacing: Self::DEFAULT_SPACING,\n            text_size: None,\n            line_height: text::LineHeight::default(),\n            shaping: text::Shaping::default(),\n            wrapping: text::Wrapping::default(),\n            font: None,\n            class: Theme::default(),\n            last_status: None,\n        }\n    }\n\n    /// Sets the size of the [`Radio`] button.\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        self.size = size.into().0;\n        self\n    }\n\n    /// Sets the width of the [`Radio`] button.\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the spacing between the [`Radio`] button and the text.\n    pub fn spacing(mut self, spacing: impl Into<Pixels>) -> Self {\n        self.spacing = spacing.into().0;\n        self\n    }\n\n    /// Sets the text size of the [`Radio`] button.\n    pub fn text_size(mut self, text_size: impl Into<Pixels>) -> Self {\n        self.text_size = Some(text_size.into());\n        self\n    }\n\n    /// Sets the text [`text::LineHeight`] of the [`Radio`] button.\n    pub fn line_height(mut self, line_height: impl Into<text::LineHeight>) -> Self {\n        self.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the [`text::Shaping`] strategy of the [`Radio`] button.\n    pub fn shaping(mut self, shaping: text::Shaping) -> Self {\n        self.shaping = shaping;\n        self\n    }\n\n    /// Sets the [`text::Wrapping`] strategy of the [`Radio`] button.\n    pub fn wrapping(mut self, wrapping: text::Wrapping) -> Self {\n        self.wrapping = wrapping;\n        self\n    }\n\n    /// Sets the text font of the [`Radio`] button.\n    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {\n        self.font = Some(font.into());\n        self\n    }\n\n    /// Sets the style of the [`Radio`] button.\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Radio`] button.\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Radio<'_, Message, Theme, Renderer>\nwhere\n    Message: Clone,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<widget::text::State<Renderer::Paragraph>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(widget::text::State::<Renderer::Paragraph>::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::next_to_each_other(\n            &limits.width(self.width),\n            self.spacing,\n            |_| layout::Node::new(Size::new(self.size, self.size)),\n            |limits| {\n                let state = tree\n                    .state\n                    .downcast_mut::<widget::text::State<Renderer::Paragraph>>();\n\n                widget::text::layout(\n                    state,\n                    renderer,\n                    limits,\n                    &self.label,\n                    widget::text::Format {\n                        width: self.width,\n                        height: Length::Shrink,\n                        line_height: self.line_height,\n                        size: self.text_size,\n                        font: self.font,\n                        align_x: text::Alignment::Default,\n                        align_y: alignment::Vertical::Top,\n                        shaping: self.shaping,\n                        wrapping: self.wrapping,\n                        ellipsis: text::Ellipsis::default(),\n                    },\n                )\n            },\n        )\n    }\n\n    fn update(\n        &mut self,\n        _tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                if cursor.is_over(layout.bounds()) {\n                    shell.publish(self.on_click.clone());\n                    shell.capture_event();\n                }\n            }\n            _ => {}\n        }\n\n        let current_status = {\n            let is_mouse_over = cursor.is_over(layout.bounds());\n            let is_selected = self.is_selected;\n\n            if is_mouse_over {\n                Status::Hovered { is_selected }\n            } else {\n                Status::Active { is_selected }\n            }\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.last_status = Some(current_status);\n        } else if self\n            .last_status\n            .is_some_and(|last_status| last_status != current_status)\n        {\n            shell.request_redraw();\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        if cursor.is_over(layout.bounds()) {\n            mouse::Interaction::Pointer\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        defaults: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let mut children = layout.children();\n\n        let style = theme.style(\n            &self.class,\n            self.last_status.unwrap_or(Status::Active {\n                is_selected: self.is_selected,\n            }),\n        );\n\n        {\n            let layout = children.next().unwrap();\n            let bounds = layout.bounds();\n\n            let size = bounds.width;\n            let dot_size = size / 2.0;\n\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds,\n                    border: Border {\n                        radius: (size / 2.0).into(),\n                        width: style.border_width,\n                        color: style.border_color,\n                    },\n                    ..renderer::Quad::default()\n                },\n                style.background,\n            );\n\n            if self.is_selected {\n                renderer.fill_quad(\n                    renderer::Quad {\n                        bounds: Rectangle {\n                            x: bounds.x + dot_size / 2.0,\n                            y: bounds.y + dot_size / 2.0,\n                            width: bounds.width - dot_size,\n                            height: bounds.height - dot_size,\n                        },\n                        border: border::rounded(dot_size / 2.0),\n                        ..renderer::Quad::default()\n                    },\n                    style.dot_color,\n                );\n            }\n        }\n\n        {\n            let label_layout = children.next().unwrap();\n            let state: &widget::text::State<Renderer::Paragraph> = tree.state.downcast_ref();\n\n            crate::text::draw(\n                renderer,\n                defaults,\n                label_layout.bounds(),\n                state.raw(),\n                crate::text::Style {\n                    color: style.text_color,\n                },\n                viewport,\n            );\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Radio<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a + Clone,\n    Theme: 'a + Catalog,\n    Renderer: 'a + text::Renderer,\n{\n    fn from(radio: Radio<'a, Message, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(radio)\n    }\n}\n\n/// The possible status of a [`Radio`] button.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`Radio`] button can be interacted with.\n    Active {\n        /// Indicates whether the [`Radio`] button is currently selected.\n        is_selected: bool,\n    },\n    /// The [`Radio`] button is being hovered.\n    Hovered {\n        /// Indicates whether the [`Radio`] button is currently selected.\n        is_selected: bool,\n    },\n}\n\n/// The appearance of a radio button.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`Background`] of the radio button.\n    pub background: Background,\n    /// The [`Color`] of the dot of the radio button.\n    pub dot_color: Color,\n    /// The border width of the radio button.\n    pub border_width: f32,\n    /// The border [`Color`] of the radio button.\n    pub border_color: Color,\n    /// The text [`Color`] of the radio button.\n    pub text_color: Option<Color>,\n}\n\n/// The theme catalog of a [`Radio`].\npub trait Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`Radio`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// The default style of a [`Radio`] button.\npub fn default(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    let active = Style {\n        background: Color::TRANSPARENT.into(),\n        dot_color: palette.primary.strong.color,\n        border_width: 1.0,\n        border_color: palette.primary.strong.color,\n        text_color: None,\n    };\n\n    match status {\n        Status::Active { .. } => active,\n        Status::Hovered { .. } => Style {\n            dot_color: palette.primary.strong.color,\n            background: palette.primary.weak.color.into(),\n            ..active\n        },\n    }\n}\n"
  },
  {
    "path": "widget/src/responsive.rs",
    "content": "use crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget;\nuse crate::core::widget::Tree;\nuse crate::core::{self, Element, Event, Length, Rectangle, Shell, Size, Vector, Widget};\nuse crate::space;\n\n/// A widget that is aware of its dimensions.\n///\n/// A [`Responsive`] widget will always try to fill all the available space of\n/// its parent.\npub struct Responsive<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    view: Box<dyn Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a>,\n    width: Length,\n    height: Length,\n    content: Element<'a, Message, Theme, Renderer>,\n}\n\nimpl<'a, Message, Theme, Renderer> Responsive<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    /// Creates a new [`Responsive`] widget with a closure that produces its\n    /// contents.\n    ///\n    /// The `view` closure will receive the maximum available space for\n    /// the [`Responsive`] during layout. You can use this [`Size`] to\n    /// conditionally build the contents.\n    pub fn new(view: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a) -> Self {\n        Self {\n            view: Box::new(view),\n            width: Length::Fill,\n            height: Length::Fill,\n            content: Element::new(space()),\n        }\n    }\n\n    /// Sets the width of the [`Responsive`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Responsive`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Responsive<'_, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    fn diff(&self, _tree: &mut Tree) {\n        // Diff is deferred to layout\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits.width(self.width).height(self.height);\n        let size = limits.max();\n\n        self.content = (self.view)(size);\n        tree.diff_children(std::slice::from_ref(&self.content));\n\n        let node =\n            self.content\n                .as_widget_mut()\n                .layout(&mut tree.children[0], renderer, &limits.loose());\n\n        let size = limits.resolve(self.width, self.height, node.size());\n\n        layout::Node::with_children(size, vec![node])\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget_mut().update(\n            &mut tree.children[0],\n            event,\n            layout.children().next().unwrap(),\n            cursor,\n            renderer,\n            shell,\n            viewport,\n        );\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget().draw(\n            &tree.children[0],\n            renderer,\n            theme,\n            style,\n            layout.children().next().unwrap(),\n            cursor,\n            viewport,\n        );\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.content.as_widget().mouse_interaction(\n            &tree.children[0],\n            layout.children().next().unwrap(),\n            cursor,\n            viewport,\n            renderer,\n        )\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.content.as_widget_mut().operate(\n            &mut tree.children[0],\n            layout.children().next().unwrap(),\n            renderer,\n            operation,\n        );\n    }\n\n    fn overlay<'a>(\n        &'a mut self,\n        tree: &'a mut Tree,\n        layout: Layout<'a>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {\n        self.content.as_widget_mut().overlay(\n            &mut tree.children[0],\n            layout.children().next().unwrap(),\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Responsive<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(responsive: Responsive<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(responsive)\n    }\n}\n"
  },
  {
    "path": "widget/src/row.rs",
    "content": "//! Distribute content horizontally.\nuse crate::core::alignment::{self, Alignment};\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget::{Operation, Tree};\nuse crate::core::{\n    Element, Event, Length, Padding, Pixels, Rectangle, Shell, Size, Vector, Widget,\n};\n\n/// A container that distributes its contents horizontally.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{button, row};\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     row![\n///         \"I am to the left!\",\n///         button(\"I am in the middle!\"),\n///         \"I am to the right!\",\n///     ].into()\n/// }\n/// ```\npub struct Row<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    spacing: f32,\n    padding: Padding,\n    width: Length,\n    height: Length,\n    align: Alignment,\n    clip: bool,\n    children: Vec<Element<'a, Message, Theme, Renderer>>,\n}\n\nimpl<'a, Message, Theme, Renderer> Row<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    /// Creates an empty [`Row`].\n    pub fn new() -> Self {\n        Self::from_vec(Vec::new())\n    }\n\n    /// Creates a [`Row`] with the given capacity.\n    pub fn with_capacity(capacity: usize) -> Self {\n        Self::from_vec(Vec::with_capacity(capacity))\n    }\n\n    /// Creates a [`Row`] with the given elements.\n    pub fn with_children(\n        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        let iterator = children.into_iter();\n\n        Self::with_capacity(iterator.size_hint().0).extend(iterator)\n    }\n\n    /// Creates a [`Row`] from an already allocated [`Vec`].\n    ///\n    /// Keep in mind that the [`Row`] will not inspect the [`Vec`], which means\n    /// it won't automatically adapt to the sizing strategy of its contents.\n    ///\n    /// If any of the children have a [`Length::Fill`] strategy, you will need to\n    /// call [`Row::width`] or [`Row::height`] accordingly.\n    pub fn from_vec(children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            spacing: 0.0,\n            padding: Padding::ZERO,\n            width: Length::Shrink,\n            height: Length::Shrink,\n            align: Alignment::Start,\n            clip: false,\n            children,\n        }\n    }\n\n    /// Sets the horizontal spacing _between_ elements.\n    ///\n    /// Custom margins per element do not exist in iced. You should use this\n    /// method instead! While less flexible, it helps you keep spacing between\n    /// elements consistent.\n    pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {\n        self.spacing = amount.into().0;\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`Row`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the width of the [`Row`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Row`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the vertical alignment of the contents of the [`Row`] .\n    pub fn align_y(mut self, align: impl Into<alignment::Vertical>) -> Self {\n        self.align = Alignment::from(align.into());\n        self\n    }\n\n    /// Sets whether the contents of the [`Row`] should be clipped on\n    /// overflow.\n    pub fn clip(mut self, clip: bool) -> Self {\n        self.clip = clip;\n        self\n    }\n\n    /// Adds an [`Element`] to the [`Row`].\n    pub fn push(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        let child = child.into();\n        let child_size = child.as_widget().size_hint();\n\n        if !child_size.is_void() {\n            self.width = self.width.enclose(child_size.width);\n            self.height = self.height.enclose(child_size.height);\n            self.children.push(child);\n        }\n\n        self\n    }\n\n    /// Extends the [`Row`] with the given children.\n    pub fn extend(\n        self,\n        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        children.into_iter().fold(self, Self::push)\n    }\n\n    /// Turns the [`Row`] into a [`Wrapping`] row.\n    ///\n    /// The original alignment of the [`Row`] is preserved per row wrapped.\n    pub fn wrap(self) -> Wrapping<'a, Message, Theme, Renderer> {\n        Wrapping {\n            row: self,\n            vertical_spacing: None,\n            align_x: alignment::Horizontal::Left,\n        }\n    }\n}\n\nimpl<Message, Renderer> Default for Row<'_, Message, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<'a, Message, Theme, Renderer: crate::core::Renderer>\n    FromIterator<Element<'a, Message, Theme, Renderer>> for Row<'a, Message, Theme, Renderer>\n{\n    fn from_iter<T: IntoIterator<Item = Element<'a, Message, Theme, Renderer>>>(iter: T) -> Self {\n        Self::with_children(iter)\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Row<'_, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn children(&self) -> Vec<Tree> {\n        self.children.iter().map(Tree::new).collect()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        tree.diff_children(&self.children);\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::flex::resolve(\n            layout::flex::Axis::Horizontal,\n            renderer,\n            limits,\n            self.width,\n            self.height,\n            self.padding,\n            self.spacing,\n            self.align,\n            &mut self.children,\n            &mut tree.children,\n        )\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        operation.container(None, layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.children\n                .iter_mut()\n                .zip(&mut tree.children)\n                .zip(layout.children())\n                .for_each(|((child, state), layout)| {\n                    child\n                        .as_widget_mut()\n                        .operate(state, layout, renderer, operation);\n                });\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        for ((child, tree), layout) in self\n            .children\n            .iter_mut()\n            .zip(&mut tree.children)\n            .zip(layout.children())\n        {\n            child\n                .as_widget_mut()\n                .update(tree, event, layout, cursor, renderer, shell, viewport);\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.children\n            .iter()\n            .zip(&tree.children)\n            .zip(layout.children())\n            .map(|((child, tree), layout)| {\n                child\n                    .as_widget()\n                    .mouse_interaction(tree, layout, cursor, viewport, renderer)\n            })\n            .max()\n            .unwrap_or_default()\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {\n            let viewport = if self.clip {\n                &clipped_viewport\n            } else {\n                viewport\n            };\n\n            for ((child, tree), layout) in self\n                .children\n                .iter()\n                .zip(&tree.children)\n                .zip(layout.children())\n                .filter(|(_, layout)| layout.bounds().intersects(viewport))\n            {\n                child\n                    .as_widget()\n                    .draw(tree, renderer, theme, style, layout, cursor, viewport);\n            }\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        overlay::from_children(\n            &mut self.children,\n            tree,\n            layout,\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Row<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: crate::core::Renderer + 'a,\n{\n    fn from(row: Row<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(row)\n    }\n}\n\n/// A [`Row`] that wraps its contents.\n///\n/// Create a [`Row`] first, and then call [`Row::wrap`] to\n/// obtain a [`Row`] that wraps its contents.\n///\n/// The original alignment of the [`Row`] is preserved per row wrapped.\npub struct Wrapping<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    row: Row<'a, Message, Theme, Renderer>,\n    vertical_spacing: Option<f32>,\n    align_x: alignment::Horizontal,\n}\n\nimpl<Message, Theme, Renderer> Wrapping<'_, Message, Theme, Renderer> {\n    /// Sets the vertical spacing _between_ lines.\n    pub fn vertical_spacing(mut self, amount: impl Into<Pixels>) -> Self {\n        self.vertical_spacing = Some(amount.into().0);\n        self\n    }\n\n    /// Sets the horizontal alignment of the wrapping [`Row`].\n    pub fn align_x(mut self, align_x: impl Into<alignment::Horizontal>) -> Self {\n        self.align_x = align_x.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Wrapping<'_, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn children(&self) -> Vec<Tree> {\n        self.row.children()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        self.row.diff(tree);\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.row.size()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits\n            .width(self.row.width)\n            .height(self.row.height)\n            .shrink(self.row.padding);\n\n        let child_limits = limits.loose();\n        let spacing = self.row.spacing;\n        let vertical_spacing = self.vertical_spacing.unwrap_or(spacing);\n        let max_width = limits.max().width;\n\n        let mut children: Vec<layout::Node> = Vec::new();\n        let mut intrinsic_size = Size::ZERO;\n        let mut row_start = 0;\n        let mut row_height = 0.0;\n        let mut x = 0.0;\n        let mut y = 0.0;\n\n        let align_factor = match self.row.align {\n            Alignment::Start => 0.0,\n            Alignment::Center => 2.0,\n            Alignment::End => 1.0,\n        };\n\n        let align_y = |row_start: std::ops::Range<usize>,\n                       row_height: f32,\n                       children: &mut Vec<layout::Node>| {\n            if align_factor != 0.0 {\n                for node in &mut children[row_start] {\n                    let height = node.size().height;\n\n                    node.translate_mut(Vector::new(0.0, (row_height - height) / align_factor));\n                }\n            }\n        };\n\n        for (i, child) in self.row.children.iter_mut().enumerate() {\n            let node = child\n                .as_widget_mut()\n                .layout(&mut tree.children[i], renderer, &child_limits);\n\n            let child_size = node.size();\n\n            if x != 0.0 && x + child_size.width > max_width {\n                intrinsic_size.width = intrinsic_size.width.max(x - spacing);\n\n                align_y(row_start..i, row_height, &mut children);\n\n                y += row_height + vertical_spacing;\n                x = 0.0;\n                row_start = i;\n                row_height = 0.0;\n            }\n\n            row_height = row_height.max(child_size.height);\n\n            children.push(node.move_to((x + self.row.padding.left, y + self.row.padding.top)));\n\n            x += child_size.width + spacing;\n        }\n\n        if x != 0.0 {\n            intrinsic_size.width = intrinsic_size.width.max(x - spacing);\n        }\n\n        intrinsic_size.height = y + row_height;\n        align_y(row_start..children.len(), row_height, &mut children);\n\n        let align_factor = match self.align_x {\n            alignment::Horizontal::Left => 0.0,\n            alignment::Horizontal::Center => 2.0,\n            alignment::Horizontal::Right => 1.0,\n        };\n\n        if align_factor != 0.0 {\n            let total_width = intrinsic_size.width;\n\n            let mut row_start = 0;\n\n            for i in 0..children.len() {\n                let bounds = children[i].bounds();\n                let row_width = bounds.x + bounds.width;\n\n                let next_x = children\n                    .get(i + 1)\n                    .map(|node| node.bounds().x)\n                    .unwrap_or_default();\n\n                if next_x == 0.0 {\n                    let translation = Vector::new((total_width - row_width) / align_factor, 0.0);\n\n                    for node in &mut children[row_start..=i] {\n                        node.translate_mut(translation);\n                    }\n\n                    row_start = i + 1;\n                }\n            }\n        }\n\n        let size = limits.resolve(self.row.width, self.row.height, intrinsic_size);\n\n        layout::Node::with_children(size.expand(self.row.padding), children)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        self.row.operate(tree, layout, renderer, operation);\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.row\n            .update(tree, event, layout, cursor, renderer, shell, viewport);\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.row\n            .mouse_interaction(tree, layout, cursor, viewport, renderer)\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.row\n            .draw(tree, renderer, theme, style, layout, cursor, viewport);\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.row\n            .overlay(tree, layout, renderer, viewport, translation)\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Wrapping<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: crate::core::Renderer + 'a,\n{\n    fn from(row: Wrapping<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(row)\n    }\n}\n"
  },
  {
    "path": "widget/src/rule.rs",
    "content": "//! Rules divide space horizontally or vertically.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! use iced::widget::rule;\n//!\n//! #[derive(Clone)]\n//! enum Message {\n//!     // ...,\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     rule::horizontal(2).into()\n//! }\n//! ```\nuse crate::core;\nuse crate::core::border;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::widget::Tree;\nuse crate::core::{Color, Element, Layout, Length, Pixels, Rectangle, Size, Theme, Widget};\n\n/// Creates a new horizontal [`Rule`] with the given height.\npub fn horizontal<'a, Theme>(height: impl Into<Pixels>) -> Rule<'a, Theme>\nwhere\n    Theme: Catalog,\n{\n    Rule {\n        thickness: Length::Fixed(height.into().0),\n        is_vertical: false,\n        class: Theme::default(),\n    }\n}\n\n/// Creates a new vertical [`Rule`] with the given width.\npub fn vertical<'a, Theme>(width: impl Into<Pixels>) -> Rule<'a, Theme>\nwhere\n    Theme: Catalog,\n{\n    Rule {\n        thickness: Length::Fixed(width.into().0),\n        is_vertical: true,\n        class: Theme::default(),\n    }\n}\n\n/// Display a horizontal or vertical rule for dividing content.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::rule;\n///\n/// #[derive(Clone)]\n/// enum Message {\n///     // ...,\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     rule::horizontal(2).into()\n/// }\n/// ```\npub struct Rule<'a, Theme = crate::Theme>\nwhere\n    Theme: Catalog,\n{\n    thickness: Length,\n    is_vertical: bool,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Theme> Rule<'a, Theme>\nwhere\n    Theme: Catalog,\n{\n    /// Sets the style of the [`Rule`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Rule`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Rule<'_, Theme>\nwhere\n    Renderer: core::Renderer,\n    Theme: Catalog,\n{\n    fn size(&self) -> Size<Length> {\n        if self.is_vertical {\n            Size {\n                width: self.thickness,\n                height: Length::Fill,\n            }\n        } else {\n            Size {\n                width: Length::Fill,\n                height: self.thickness,\n            }\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let size = <Self as Widget<(), Theme, Renderer>>::size(self);\n\n        layout::atomic(limits, size.width, size.height)\n    }\n\n    fn draw(\n        &self,\n        _tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n        let style = theme.style(&self.class);\n\n        let mut bounds = if self.is_vertical {\n            let line_x = bounds.x;\n\n            let (offset, line_height) = style.fill_mode.fill(bounds.height);\n            let line_y = bounds.y + offset;\n\n            Rectangle {\n                x: line_x,\n                y: line_y,\n                width: bounds.width,\n                height: line_height,\n            }\n        } else {\n            let line_y = bounds.y;\n\n            let (offset, line_width) = style.fill_mode.fill(bounds.width);\n            let line_x = bounds.x + offset;\n\n            Rectangle {\n                x: line_x,\n                y: line_y,\n                width: line_width,\n                height: bounds.height,\n            }\n        };\n\n        if style.snap {\n            let unit = 1.0 / renderer.scale_factor().unwrap_or(1.0);\n\n            bounds.width = bounds.width.max(unit);\n            bounds.height = bounds.height.max(unit);\n        }\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds,\n                border: border::rounded(style.radius),\n                snap: style.snap,\n                ..renderer::Quad::default()\n            },\n            style.color,\n        );\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Rule<'a, Theme>> for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a + Catalog,\n    Renderer: 'a + core::Renderer,\n{\n    fn from(rule: Rule<'a, Theme>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(rule)\n    }\n}\n\n/// The appearance of a rule.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The color of the rule.\n    pub color: Color,\n    /// The radius of the line corners.\n    pub radius: border::Radius,\n    /// The [`FillMode`] of the rule.\n    pub fill_mode: FillMode,\n    /// Whether the rule should be snapped to the pixel grid.\n    pub snap: bool,\n}\n\n/// The fill mode of a rule.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum FillMode {\n    /// Fill the whole length of the container.\n    Full,\n    /// Fill a percent of the length of the container. The rule\n    /// will be centered in that container.\n    ///\n    /// The range is `[0.0, 100.0]`.\n    Percent(f32),\n    /// Uniform offset from each end, length units.\n    Padded(u16),\n    /// Different offset on each end of the rule, length units.\n    /// First = top or left.\n    AsymmetricPadding(u16, u16),\n}\n\nimpl FillMode {\n    /// Return the starting offset and length of the rule.\n    ///\n    /// * `space` - The space to fill.\n    ///\n    /// # Returns\n    ///\n    /// * (`starting_offset`, `length`)\n    pub fn fill(&self, space: f32) -> (f32, f32) {\n        match *self {\n            FillMode::Full => (0.0, space),\n            FillMode::Percent(percent) => {\n                if percent >= 100.0 {\n                    (0.0, space)\n                } else {\n                    let percent_width = (space * percent / 100.0).round();\n\n                    (((space - percent_width) / 2.0).round(), percent_width)\n                }\n            }\n            FillMode::Padded(padding) => {\n                if padding == 0 {\n                    (0.0, space)\n                } else {\n                    let padding = padding as f32;\n                    let mut line_width = space - (padding * 2.0);\n                    if line_width < 0.0 {\n                        line_width = 0.0;\n                    }\n\n                    (padding, line_width)\n                }\n            }\n            FillMode::AsymmetricPadding(first_pad, second_pad) => {\n                let first_pad = first_pad as f32;\n                let second_pad = second_pad as f32;\n                let mut line_width = space - first_pad - second_pad;\n                if line_width < 0.0 {\n                    line_width = 0.0;\n                }\n\n                (first_pad, line_width)\n            }\n        }\n    }\n}\n\n/// The theme catalog of a [`Rule`].\npub trait Catalog: Sized {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`Rule`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>) -> Style {\n        class(self)\n    }\n}\n\n/// The default styling of a [`Rule`].\npub fn default(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    Style {\n        color: palette.background.strong.color,\n        radius: 0.0.into(),\n        fill_mode: FillMode::Full,\n        snap: true,\n    }\n}\n\n/// A [`Rule`] styling using the weak background color.\npub fn weak(theme: &Theme) -> Style {\n    let palette = theme.palette();\n\n    Style {\n        color: palette.background.weak.color,\n        radius: 0.0.into(),\n        fill_mode: FillMode::Full,\n        snap: true,\n    }\n}\n"
  },
  {
    "path": "widget/src/scrollable.rs",
    "content": "//! Scrollables let users navigate an endless amount of content with a scrollbar.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! use iced::widget::{column, scrollable, space};\n//!\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     scrollable(column![\n//!         \"Scroll me!\",\n//!         space().height(3000),\n//!         \"You did it!\",\n//!     ]).into()\n//! }\n//! ```\nuse crate::container;\nuse crate::core::alignment;\nuse crate::core::border::{self, Border};\nuse crate::core::keyboard;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::text;\nuse crate::core::time::{Duration, Instant};\nuse crate::core::touch;\nuse crate::core::widget;\nuse crate::core::widget::operation::{self, Operation};\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    self, Background, Color, Element, Event, InputMethod, Layout, Length, Padding, Pixels, Point,\n    Rectangle, Shadow, Shell, Size, Theme, Vector, Widget,\n};\n\npub use operation::scrollable::{AbsoluteOffset, RelativeOffset};\n\n/// A widget that can vertically display an infinite amount of content with a\n/// scrollbar.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{column, scrollable, space};\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     scrollable(column![\n///         \"Scroll me!\",\n///         space().height(3000),\n///         \"You did it!\",\n///     ]).into()\n/// }\n/// ```\npub struct Scrollable<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    id: Option<widget::Id>,\n    width: Length,\n    height: Length,\n    direction: Direction,\n    auto_scroll: bool,\n    content: Element<'a, Message, Theme, Renderer>,\n    on_scroll: Option<Box<dyn Fn(Viewport) -> Message + 'a>>,\n    class: Theme::Class<'a>,\n    last_status: Option<Status>,\n}\n\nimpl<'a, Message, Theme, Renderer> Scrollable<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// Creates a new vertical [`Scrollable`].\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self::with_direction(content, Direction::default())\n    }\n\n    /// Creates a new [`Scrollable`] with the given [`Direction`].\n    pub fn with_direction(\n        content: impl Into<Element<'a, Message, Theme, Renderer>>,\n        direction: impl Into<Direction>,\n    ) -> Self {\n        Scrollable {\n            id: None,\n            width: Length::Shrink,\n            height: Length::Shrink,\n            direction: direction.into(),\n            auto_scroll: false,\n            content: content.into(),\n            on_scroll: None,\n            class: Theme::default(),\n            last_status: None,\n        }\n        .enclose()\n    }\n\n    fn enclose(mut self) -> Self {\n        let size_hint = self.content.as_widget().size_hint();\n\n        if self.direction.horizontal().is_none() {\n            self.width = self.width.enclose(size_hint.width);\n        }\n\n        if self.direction.vertical().is_none() {\n            self.height = self.height.enclose(size_hint.height);\n        }\n\n        self\n    }\n\n    /// Makes the [`Scrollable`] scroll horizontally, with default [`Scrollbar`] settings.\n    pub fn horizontal(self) -> Self {\n        self.direction(Direction::Horizontal(Scrollbar::default()))\n    }\n\n    /// Sets the [`Direction`] of the [`Scrollable`].\n    pub fn direction(mut self, direction: impl Into<Direction>) -> Self {\n        self.direction = direction.into();\n        self.enclose()\n    }\n\n    /// Sets the [`widget::Id`] of the [`Scrollable`].\n    pub fn id(mut self, id: impl Into<widget::Id>) -> Self {\n        self.id = Some(id.into());\n        self\n    }\n\n    /// Sets the width of the [`Scrollable`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Scrollable`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets a function to call when the [`Scrollable`] is scrolled.\n    ///\n    /// The function takes the [`Viewport`] of the [`Scrollable`]\n    pub fn on_scroll(mut self, f: impl Fn(Viewport) -> Message + 'a) -> Self {\n        self.on_scroll = Some(Box::new(f));\n        self\n    }\n\n    /// Anchors the vertical [`Scrollable`] direction to the top.\n    pub fn anchor_top(self) -> Self {\n        self.anchor_y(Anchor::Start)\n    }\n\n    /// Anchors the vertical [`Scrollable`] direction to the bottom.\n    pub fn anchor_bottom(self) -> Self {\n        self.anchor_y(Anchor::End)\n    }\n\n    /// Anchors the horizontal [`Scrollable`] direction to the left.\n    pub fn anchor_left(self) -> Self {\n        self.anchor_x(Anchor::Start)\n    }\n\n    /// Anchors the horizontal [`Scrollable`] direction to the right.\n    pub fn anchor_right(self) -> Self {\n        self.anchor_x(Anchor::End)\n    }\n\n    /// Sets the [`Anchor`] of the horizontal direction of the [`Scrollable`], if applicable.\n    pub fn anchor_x(mut self, alignment: Anchor) -> Self {\n        match &mut self.direction {\n            Direction::Horizontal(horizontal) | Direction::Both { horizontal, .. } => {\n                horizontal.alignment = alignment;\n            }\n            Direction::Vertical { .. } => {}\n        }\n\n        self\n    }\n\n    /// Sets the [`Anchor`] of the vertical direction of the [`Scrollable`], if applicable.\n    pub fn anchor_y(mut self, alignment: Anchor) -> Self {\n        match &mut self.direction {\n            Direction::Vertical(vertical) | Direction::Both { vertical, .. } => {\n                vertical.alignment = alignment;\n            }\n            Direction::Horizontal { .. } => {}\n        }\n\n        self\n    }\n\n    /// Embeds the [`Scrollbar`] into the [`Scrollable`], instead of floating on top of the\n    /// content.\n    ///\n    /// The `spacing` provided will be used as space between the [`Scrollbar`] and the contents\n    /// of the [`Scrollable`].\n    pub fn spacing(mut self, new_spacing: impl Into<Pixels>) -> Self {\n        match &mut self.direction {\n            Direction::Horizontal(scrollbar) | Direction::Vertical(scrollbar) => {\n                scrollbar.spacing = Some(new_spacing.into().0);\n            }\n            Direction::Both { .. } => {}\n        }\n\n        self\n    }\n\n    /// Sets whether the user should be allowed to auto-scroll the [`Scrollable`]\n    /// with the middle mouse button.\n    ///\n    /// By default, it is disabled.\n    pub fn auto_scroll(mut self, auto_scroll: bool) -> Self {\n        self.auto_scroll = auto_scroll;\n        self\n    }\n\n    /// Sets the style of this [`Scrollable`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Scrollable`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\n/// The direction of [`Scrollable`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum Direction {\n    /// Vertical scrolling\n    Vertical(Scrollbar),\n    /// Horizontal scrolling\n    Horizontal(Scrollbar),\n    /// Both vertical and horizontal scrolling\n    Both {\n        /// The properties of the vertical scrollbar.\n        vertical: Scrollbar,\n        /// The properties of the horizontal scrollbar.\n        horizontal: Scrollbar,\n    },\n}\n\nimpl Direction {\n    /// Returns the horizontal [`Scrollbar`], if any.\n    pub fn horizontal(&self) -> Option<&Scrollbar> {\n        match self {\n            Self::Horizontal(scrollbar) => Some(scrollbar),\n            Self::Both { horizontal, .. } => Some(horizontal),\n            Self::Vertical(_) => None,\n        }\n    }\n\n    /// Returns the vertical [`Scrollbar`], if any.\n    pub fn vertical(&self) -> Option<&Scrollbar> {\n        match self {\n            Self::Vertical(scrollbar) => Some(scrollbar),\n            Self::Both { vertical, .. } => Some(vertical),\n            Self::Horizontal(_) => None,\n        }\n    }\n\n    fn align(&self, delta: Vector) -> Vector {\n        let horizontal_alignment = self.horizontal().map(|p| p.alignment).unwrap_or_default();\n\n        let vertical_alignment = self.vertical().map(|p| p.alignment).unwrap_or_default();\n\n        let align = |alignment: Anchor, delta: f32| match alignment {\n            Anchor::Start => delta,\n            Anchor::End => -delta,\n        };\n\n        Vector::new(\n            align(horizontal_alignment, delta.x),\n            align(vertical_alignment, delta.y),\n        )\n    }\n}\n\nimpl Default for Direction {\n    fn default() -> Self {\n        Self::Vertical(Scrollbar::default())\n    }\n}\n\n/// A scrollbar within a [`Scrollable`].\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Scrollbar {\n    width: f32,\n    margin: f32,\n    scroller_width: f32,\n    alignment: Anchor,\n    spacing: Option<f32>,\n}\n\nimpl Default for Scrollbar {\n    fn default() -> Self {\n        Self {\n            width: 10.0,\n            margin: 0.0,\n            scroller_width: 10.0,\n            alignment: Anchor::Start,\n            spacing: None,\n        }\n    }\n}\n\nimpl Scrollbar {\n    /// Creates new [`Scrollbar`] for use in a [`Scrollable`].\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Create a [`Scrollbar`] with zero width to allow a [`Scrollable`] to scroll without a visible\n    /// scroller.\n    pub fn hidden() -> Self {\n        Self::default().width(0).scroller_width(0)\n    }\n\n    /// Sets the scrollbar width of the [`Scrollbar`] .\n    pub fn width(mut self, width: impl Into<Pixels>) -> Self {\n        self.width = width.into().0.max(0.0);\n        self\n    }\n\n    /// Sets the scrollbar margin of the [`Scrollbar`] .\n    pub fn margin(mut self, margin: impl Into<Pixels>) -> Self {\n        self.margin = margin.into().0;\n        self\n    }\n\n    /// Sets the scroller width of the [`Scrollbar`] .\n    pub fn scroller_width(mut self, scroller_width: impl Into<Pixels>) -> Self {\n        self.scroller_width = scroller_width.into().0.max(0.0);\n        self\n    }\n\n    /// Sets the [`Anchor`] of the [`Scrollbar`] .\n    pub fn anchor(mut self, alignment: Anchor) -> Self {\n        self.alignment = alignment;\n        self\n    }\n\n    /// Sets whether the [`Scrollbar`] should be embedded in the [`Scrollable`], using\n    /// the given spacing between itself and the contents.\n    ///\n    /// An embedded [`Scrollbar`] will always be displayed, will take layout space,\n    /// and will not float over the contents.\n    pub fn spacing(mut self, spacing: impl Into<Pixels>) -> Self {\n        self.spacing = Some(spacing.into().0);\n        self\n    }\n}\n\n/// The anchor of the scroller of the [`Scrollable`] relative to its [`Viewport`]\n/// on a given axis.\n#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]\npub enum Anchor {\n    /// Scroller is anchored to the start of the [`Viewport`].\n    #[default]\n    Start,\n    /// Content is aligned to the end of the [`Viewport`].\n    End,\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Scrollable<'_, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::new())\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        vec![Tree::new(&self.content)]\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        tree.diff_children(std::slice::from_ref(&self.content));\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let mut layout = |right_padding, bottom_padding| {\n            layout::padded(\n                limits,\n                self.width,\n                self.height,\n                Padding {\n                    right: right_padding,\n                    bottom: bottom_padding,\n                    ..Padding::ZERO\n                },\n                |limits| {\n                    let is_horizontal = self.direction.horizontal().is_some();\n                    let is_vertical = self.direction.vertical().is_some();\n\n                    let child_limits = layout::Limits::with_compression(\n                        limits.min(),\n                        Size::new(\n                            if is_horizontal {\n                                f32::INFINITY\n                            } else {\n                                limits.max().width\n                            },\n                            if is_vertical {\n                                f32::INFINITY\n                            } else {\n                                limits.max().height\n                            },\n                        ),\n                        Size::new(is_horizontal, is_vertical),\n                    );\n\n                    self.content.as_widget_mut().layout(\n                        &mut tree.children[0],\n                        renderer,\n                        &child_limits,\n                    )\n                },\n            )\n        };\n\n        match self.direction {\n            Direction::Vertical(Scrollbar {\n                width,\n                margin,\n                spacing: Some(spacing),\n                ..\n            })\n            | Direction::Horizontal(Scrollbar {\n                width,\n                margin,\n                spacing: Some(spacing),\n                ..\n            }) => {\n                let is_vertical = matches!(self.direction, Direction::Vertical(_));\n\n                let padding = width + margin * 2.0 + spacing;\n                let state = tree.state.downcast_mut::<State>();\n\n                let status_quo = layout(\n                    if is_vertical && state.is_scrollbar_visible {\n                        padding\n                    } else {\n                        0.0\n                    },\n                    if !is_vertical && state.is_scrollbar_visible {\n                        padding\n                    } else {\n                        0.0\n                    },\n                );\n\n                let is_scrollbar_visible = if is_vertical {\n                    status_quo.children()[0].size().height > status_quo.size().height\n                } else {\n                    status_quo.children()[0].size().width > status_quo.size().width\n                };\n\n                if state.is_scrollbar_visible == is_scrollbar_visible {\n                    status_quo\n                } else {\n                    log::trace!(\"Scrollbar status quo has changed\");\n                    state.is_scrollbar_visible = is_scrollbar_visible;\n\n                    layout(\n                        if is_vertical && state.is_scrollbar_visible {\n                            padding\n                        } else {\n                            0.0\n                        },\n                        if !is_vertical && state.is_scrollbar_visible {\n                            padding\n                        } else {\n                            0.0\n                        },\n                    )\n                }\n            }\n            _ => layout(0.0, 0.0),\n        }\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        let state = tree.state.downcast_mut::<State>();\n\n        let bounds = layout.bounds();\n        let content_layout = layout.children().next().unwrap();\n        let content_bounds = content_layout.bounds();\n        let translation = state.translation(self.direction, bounds, content_bounds);\n\n        operation.scrollable(self.id.as_ref(), bounds, content_bounds, translation, state);\n\n        operation.traverse(&mut |operation| {\n            self.content.as_widget_mut().operate(\n                &mut tree.children[0],\n                layout.children().next().unwrap(),\n                renderer,\n                operation,\n            );\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        const AUTOSCROLL_DEADZONE: f32 = 20.0;\n        const AUTOSCROLL_SMOOTHNESS: f32 = 1.5;\n\n        let state = tree.state.downcast_mut::<State>();\n        let bounds = layout.bounds();\n        let cursor_over_scrollable = cursor.position_over(bounds);\n\n        let content = layout.children().next().unwrap();\n        let content_bounds = content.bounds();\n\n        let scrollbars = Scrollbars::new(state, self.direction, bounds, content_bounds);\n\n        let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) = scrollbars.is_mouse_over(cursor);\n\n        let last_offsets = (state.offset_x, state.offset_y);\n\n        if let Some(last_scrolled) = state.last_scrolled {\n            let clear_transaction = match event {\n                Event::Mouse(\n                    mouse::Event::ButtonPressed(_)\n                    | mouse::Event::ButtonReleased(_)\n                    | mouse::Event::CursorLeft,\n                ) => true,\n                Event::Mouse(mouse::Event::CursorMoved { .. }) => {\n                    last_scrolled.elapsed() > Duration::from_millis(100)\n                }\n                _ => last_scrolled.elapsed() > Duration::from_millis(1500),\n            };\n\n            if clear_transaction {\n                state.last_scrolled = None;\n            }\n        }\n\n        let mut update = || {\n            if let Some(scroller_grabbed_at) = state.y_scroller_grabbed_at() {\n                match event {\n                    Event::Mouse(mouse::Event::CursorMoved { .. })\n                    | Event::Touch(touch::Event::FingerMoved { .. }) => {\n                        if let Some(scrollbar) = scrollbars.y {\n                            let Some(cursor_position) = cursor.land().position() else {\n                                return;\n                            };\n\n                            state.scroll_y_to(\n                                scrollbar.scroll_percentage_y(scroller_grabbed_at, cursor_position),\n                                bounds,\n                                content_bounds,\n                            );\n\n                            let _ = notify_scroll(\n                                state,\n                                &self.on_scroll,\n                                bounds,\n                                content_bounds,\n                                shell,\n                            );\n\n                            shell.capture_event();\n                        }\n                    }\n                    _ => {}\n                }\n            } else if mouse_over_y_scrollbar {\n                match event {\n                    Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n                    | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                        let Some(cursor_position) = cursor.position() else {\n                            return;\n                        };\n\n                        if let (Some(scroller_grabbed_at), Some(scrollbar)) =\n                            (scrollbars.grab_y_scroller(cursor_position), scrollbars.y)\n                        {\n                            state.scroll_y_to(\n                                scrollbar.scroll_percentage_y(scroller_grabbed_at, cursor_position),\n                                bounds,\n                                content_bounds,\n                            );\n\n                            state.interaction = Interaction::YScrollerGrabbed(scroller_grabbed_at);\n\n                            let _ = notify_scroll(\n                                state,\n                                &self.on_scroll,\n                                bounds,\n                                content_bounds,\n                                shell,\n                            );\n                        }\n\n                        shell.capture_event();\n                    }\n                    _ => {}\n                }\n            }\n\n            if let Some(scroller_grabbed_at) = state.x_scroller_grabbed_at() {\n                match event {\n                    Event::Mouse(mouse::Event::CursorMoved { .. })\n                    | Event::Touch(touch::Event::FingerMoved { .. }) => {\n                        let Some(cursor_position) = cursor.land().position() else {\n                            return;\n                        };\n\n                        if let Some(scrollbar) = scrollbars.x {\n                            state.scroll_x_to(\n                                scrollbar.scroll_percentage_x(scroller_grabbed_at, cursor_position),\n                                bounds,\n                                content_bounds,\n                            );\n\n                            let _ = notify_scroll(\n                                state,\n                                &self.on_scroll,\n                                bounds,\n                                content_bounds,\n                                shell,\n                            );\n                        }\n\n                        shell.capture_event();\n                    }\n                    _ => {}\n                }\n            } else if mouse_over_x_scrollbar {\n                match event {\n                    Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n                    | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                        let Some(cursor_position) = cursor.position() else {\n                            return;\n                        };\n\n                        if let (Some(scroller_grabbed_at), Some(scrollbar)) =\n                            (scrollbars.grab_x_scroller(cursor_position), scrollbars.x)\n                        {\n                            state.scroll_x_to(\n                                scrollbar.scroll_percentage_x(scroller_grabbed_at, cursor_position),\n                                bounds,\n                                content_bounds,\n                            );\n\n                            state.interaction = Interaction::XScrollerGrabbed(scroller_grabbed_at);\n\n                            let _ = notify_scroll(\n                                state,\n                                &self.on_scroll,\n                                bounds,\n                                content_bounds,\n                                shell,\n                            );\n\n                            shell.capture_event();\n                        }\n                    }\n                    _ => {}\n                }\n            }\n\n            if matches!(state.interaction, Interaction::AutoScrolling { .. })\n                && matches!(\n                    event,\n                    Event::Mouse(\n                        mouse::Event::ButtonPressed(_) | mouse::Event::WheelScrolled { .. }\n                    ) | Event::Touch(_)\n                        | Event::Keyboard(_)\n                )\n            {\n                state.interaction = Interaction::None;\n                shell.capture_event();\n                shell.invalidate_layout();\n                shell.request_redraw();\n                return;\n            }\n\n            if state.last_scrolled.is_none()\n                || !matches!(event, Event::Mouse(mouse::Event::WheelScrolled { .. }))\n            {\n                let translation = state.translation(self.direction, bounds, content_bounds);\n\n                let cursor = match cursor_over_scrollable {\n                    Some(cursor_position)\n                        if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) =>\n                    {\n                        mouse::Cursor::Available(cursor_position + translation)\n                    }\n                    _ => cursor.levitate() + translation,\n                };\n\n                let had_input_method = shell.input_method().is_enabled();\n\n                self.content.as_widget_mut().update(\n                    &mut tree.children[0],\n                    event,\n                    content,\n                    cursor,\n                    renderer,\n                    shell,\n                    &Rectangle {\n                        y: bounds.y + translation.y,\n                        x: bounds.x + translation.x,\n                        ..bounds\n                    },\n                );\n\n                if !had_input_method\n                    && let InputMethod::Enabled { cursor, .. } = shell.input_method_mut()\n                {\n                    *cursor = *cursor - translation;\n                }\n            };\n\n            if matches!(\n                event,\n                Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))\n                    | Event::Touch(\n                        touch::Event::FingerLifted { .. } | touch::Event::FingerLost { .. }\n                    )\n            ) {\n                state.interaction = Interaction::None;\n                return;\n            }\n\n            if shell.is_event_captured() {\n                return;\n            }\n\n            match event {\n                Event::Mouse(mouse::Event::WheelScrolled { delta }) => {\n                    if cursor_over_scrollable.is_none() {\n                        return;\n                    }\n\n                    let delta = match *delta {\n                        mouse::ScrollDelta::Lines { x, y } => {\n                            let is_shift_pressed = state.keyboard_modifiers.shift();\n\n                            // macOS automatically inverts the axes when Shift is pressed\n                            let (x, y) = if cfg!(target_os = \"macos\") && is_shift_pressed {\n                                (y, x)\n                            } else {\n                                (x, y)\n                            };\n\n                            let movement = if !is_shift_pressed {\n                                Vector::new(x, y)\n                            } else {\n                                Vector::new(y, x)\n                            };\n\n                            // TODO: Configurable speed/friction (?)\n                            -movement * 60.0\n                        }\n                        mouse::ScrollDelta::Pixels { x, y } => -Vector::new(x, y),\n                    };\n\n                    state.scroll(self.direction.align(delta), bounds, content_bounds);\n\n                    let has_scrolled =\n                        notify_scroll(state, &self.on_scroll, bounds, content_bounds, shell);\n\n                    let in_transaction = state.last_scrolled.is_some();\n\n                    if has_scrolled || in_transaction {\n                        shell.capture_event();\n                    }\n                }\n                Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Middle))\n                    if self.auto_scroll && matches!(state.interaction, Interaction::None) =>\n                {\n                    let Some(origin) = cursor_over_scrollable else {\n                        return;\n                    };\n\n                    state.interaction = Interaction::AutoScrolling {\n                        origin,\n                        current: origin,\n                        last_frame: None,\n                    };\n\n                    shell.capture_event();\n                    shell.invalidate_layout();\n                    shell.request_redraw();\n                }\n                Event::Touch(event)\n                    if matches!(state.interaction, Interaction::TouchScrolling(_))\n                        || (!mouse_over_y_scrollbar && !mouse_over_x_scrollbar) =>\n                {\n                    match event {\n                        touch::Event::FingerPressed { .. } => {\n                            let Some(position) = cursor_over_scrollable else {\n                                return;\n                            };\n\n                            state.interaction = Interaction::TouchScrolling(position);\n                        }\n                        touch::Event::FingerMoved { .. } => {\n                            let Interaction::TouchScrolling(scroll_box_touched_at) =\n                                state.interaction\n                            else {\n                                return;\n                            };\n\n                            let Some(cursor_position) = cursor.position() else {\n                                return;\n                            };\n\n                            let delta = Vector::new(\n                                scroll_box_touched_at.x - cursor_position.x,\n                                scroll_box_touched_at.y - cursor_position.y,\n                            );\n\n                            state.scroll(self.direction.align(delta), bounds, content_bounds);\n\n                            state.interaction = Interaction::TouchScrolling(cursor_position);\n\n                            // TODO: bubble up touch movements if not consumed.\n                            let _ = notify_scroll(\n                                state,\n                                &self.on_scroll,\n                                bounds,\n                                content_bounds,\n                                shell,\n                            );\n                        }\n                        _ => {}\n                    }\n\n                    shell.capture_event();\n                }\n                Event::Mouse(mouse::Event::CursorMoved { position }) => {\n                    if let Interaction::AutoScrolling {\n                        origin, last_frame, ..\n                    } = state.interaction\n                    {\n                        let delta = *position - origin;\n\n                        state.interaction = Interaction::AutoScrolling {\n                            origin,\n                            current: *position,\n                            last_frame,\n                        };\n\n                        if (delta.x.abs() >= AUTOSCROLL_DEADZONE\n                            || delta.y.abs() >= AUTOSCROLL_DEADZONE)\n                            && last_frame.is_none()\n                        {\n                            shell.request_redraw();\n                        }\n                    }\n                }\n                Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => {\n                    state.keyboard_modifiers = *modifiers;\n                }\n                Event::Window(window::Event::RedrawRequested(now)) => {\n                    if let Interaction::AutoScrolling {\n                        origin,\n                        current,\n                        last_frame,\n                    } = state.interaction\n                    {\n                        if last_frame == Some(*now) {\n                            shell.request_redraw();\n                            return;\n                        }\n\n                        state.interaction = Interaction::AutoScrolling {\n                            origin,\n                            current,\n                            last_frame: None,\n                        };\n\n                        let mut delta = current - origin;\n\n                        if delta.x.abs() < AUTOSCROLL_DEADZONE {\n                            delta.x = 0.0;\n                        }\n\n                        if delta.y.abs() < AUTOSCROLL_DEADZONE {\n                            delta.y = 0.0;\n                        }\n\n                        if delta.x != 0.0 || delta.y != 0.0 {\n                            let time_delta = if let Some(last_frame) = last_frame {\n                                *now - last_frame\n                            } else {\n                                Duration::ZERO\n                            };\n\n                            let scroll_factor = time_delta.as_secs_f32();\n\n                            state.scroll(\n                                self.direction.align(Vector::new(\n                                    delta.x.signum()\n                                        * delta.x.abs().powf(AUTOSCROLL_SMOOTHNESS)\n                                        * scroll_factor,\n                                    delta.y.signum()\n                                        * delta.y.abs().powf(AUTOSCROLL_SMOOTHNESS)\n                                        * scroll_factor,\n                                )),\n                                bounds,\n                                content_bounds,\n                            );\n\n                            let has_scrolled = notify_scroll(\n                                state,\n                                &self.on_scroll,\n                                bounds,\n                                content_bounds,\n                                shell,\n                            );\n\n                            if has_scrolled || time_delta.is_zero() {\n                                state.interaction = Interaction::AutoScrolling {\n                                    origin,\n                                    current,\n                                    last_frame: Some(*now),\n                                };\n\n                                shell.request_redraw();\n                            }\n\n                            return;\n                        }\n                    }\n\n                    let _ = notify_viewport(state, &self.on_scroll, bounds, content_bounds, shell);\n                }\n                _ => {}\n            }\n        };\n\n        update();\n\n        let status = if state.scrollers_grabbed() {\n            Status::Dragged {\n                is_horizontal_scrollbar_dragged: state.x_scroller_grabbed_at().is_some(),\n                is_vertical_scrollbar_dragged: state.y_scroller_grabbed_at().is_some(),\n                is_horizontal_scrollbar_disabled: scrollbars.is_x_disabled(),\n                is_vertical_scrollbar_disabled: scrollbars.is_y_disabled(),\n            }\n        } else if cursor_over_scrollable.is_some() {\n            Status::Hovered {\n                is_horizontal_scrollbar_hovered: mouse_over_x_scrollbar,\n                is_vertical_scrollbar_hovered: mouse_over_y_scrollbar,\n                is_horizontal_scrollbar_disabled: scrollbars.is_x_disabled(),\n                is_vertical_scrollbar_disabled: scrollbars.is_y_disabled(),\n            }\n        } else {\n            Status::Active {\n                is_horizontal_scrollbar_disabled: scrollbars.is_x_disabled(),\n                is_vertical_scrollbar_disabled: scrollbars.is_y_disabled(),\n            }\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.last_status = Some(status);\n        }\n\n        if last_offsets != (state.offset_x, state.offset_y)\n            || self\n                .last_status\n                .is_some_and(|last_status| last_status != status)\n        {\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        defaults: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_ref::<State>();\n\n        let bounds = layout.bounds();\n        let content_layout = layout.children().next().unwrap();\n        let content_bounds = content_layout.bounds();\n\n        let Some(visible_bounds) = bounds.intersection(viewport) else {\n            return;\n        };\n\n        let scrollbars = Scrollbars::new(state, self.direction, bounds, content_bounds);\n\n        let cursor_over_scrollable = cursor.position_over(bounds);\n        let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) = scrollbars.is_mouse_over(cursor);\n\n        let translation = state.translation(self.direction, bounds, content_bounds);\n\n        let cursor = match cursor_over_scrollable {\n            Some(cursor_position) if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) => {\n                mouse::Cursor::Available(cursor_position + translation)\n            }\n            _ => cursor.levitate() + translation,\n        };\n\n        let style = theme.style(\n            &self.class,\n            self.last_status.unwrap_or(Status::Active {\n                is_horizontal_scrollbar_disabled: false,\n                is_vertical_scrollbar_disabled: false,\n            }),\n        );\n\n        container::draw_background(renderer, &style.container, layout.bounds());\n\n        // Draw inner content\n        if scrollbars.active() {\n            let scale_factor = renderer.scale_factor().unwrap_or(1.0);\n            let translation = (translation * scale_factor).round() / scale_factor;\n\n            renderer.with_layer(visible_bounds, |renderer| {\n                renderer.with_translation(\n                    Vector::new(-translation.x, -translation.y),\n                    |renderer| {\n                        self.content.as_widget().draw(\n                            &tree.children[0],\n                            renderer,\n                            theme,\n                            defaults,\n                            content_layout,\n                            cursor,\n                            &Rectangle {\n                                y: visible_bounds.y + translation.y,\n                                x: visible_bounds.x + translation.x,\n                                ..visible_bounds\n                            },\n                        );\n                    },\n                );\n            });\n\n            let draw_scrollbar =\n                |renderer: &mut Renderer, style: Rail, scrollbar: &internals::Scrollbar| {\n                    if scrollbar.bounds.width > 0.0\n                        && scrollbar.bounds.height > 0.0\n                        && (style.background.is_some()\n                            || (style.border.color != Color::TRANSPARENT\n                                && style.border.width > 0.0))\n                    {\n                        renderer.fill_quad(\n                            renderer::Quad {\n                                bounds: scrollbar.bounds,\n                                border: style.border,\n                                ..renderer::Quad::default()\n                            },\n                            style\n                                .background\n                                .unwrap_or(Background::Color(Color::TRANSPARENT)),\n                        );\n                    }\n\n                    if let Some(scroller) = scrollbar.scroller\n                        && scroller.bounds.width > 0.0\n                        && scroller.bounds.height > 0.0\n                        && (style.scroller.background != Background::Color(Color::TRANSPARENT)\n                            || (style.scroller.border.color != Color::TRANSPARENT\n                                && style.scroller.border.width > 0.0))\n                    {\n                        renderer.fill_quad(\n                            renderer::Quad {\n                                bounds: scroller.bounds,\n                                border: style.scroller.border,\n                                ..renderer::Quad::default()\n                            },\n                            style.scroller.background,\n                        );\n                    }\n                };\n\n            renderer.with_layer(\n                Rectangle {\n                    width: (visible_bounds.width + 2.0).min(viewport.width),\n                    height: (visible_bounds.height + 2.0).min(viewport.height),\n                    ..visible_bounds\n                },\n                |renderer| {\n                    if let Some(scrollbar) = scrollbars.y {\n                        draw_scrollbar(renderer, style.vertical_rail, &scrollbar);\n                    }\n\n                    if let Some(scrollbar) = scrollbars.x {\n                        draw_scrollbar(renderer, style.horizontal_rail, &scrollbar);\n                    }\n\n                    if let (Some(x), Some(y)) = (scrollbars.x, scrollbars.y) {\n                        let background = style.gap.or(style.container.background);\n\n                        if let Some(background) = background {\n                            renderer.fill_quad(\n                                renderer::Quad {\n                                    bounds: Rectangle {\n                                        x: y.bounds.x,\n                                        y: x.bounds.y,\n                                        width: y.bounds.width,\n                                        height: x.bounds.height,\n                                    },\n                                    ..renderer::Quad::default()\n                                },\n                                background,\n                            );\n                        }\n                    }\n                },\n            );\n        } else {\n            self.content.as_widget().draw(\n                &tree.children[0],\n                renderer,\n                theme,\n                defaults,\n                content_layout,\n                cursor,\n                &Rectangle {\n                    x: visible_bounds.x + translation.x,\n                    y: visible_bounds.y + translation.y,\n                    ..visible_bounds\n                },\n            );\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let state = tree.state.downcast_ref::<State>();\n        let bounds = layout.bounds();\n        let cursor_over_scrollable = cursor.position_over(bounds);\n\n        let content_layout = layout.children().next().unwrap();\n        let content_bounds = content_layout.bounds();\n\n        let scrollbars = Scrollbars::new(state, self.direction, bounds, content_bounds);\n\n        let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) = scrollbars.is_mouse_over(cursor);\n\n        if state.scrollers_grabbed() {\n            return mouse::Interaction::None;\n        }\n\n        let translation = state.translation(self.direction, bounds, content_bounds);\n\n        let cursor = match cursor_over_scrollable {\n            Some(cursor_position) if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) => {\n                mouse::Cursor::Available(cursor_position + translation)\n            }\n            _ => cursor.levitate() + translation,\n        };\n\n        self.content.as_widget().mouse_interaction(\n            &tree.children[0],\n            content_layout,\n            cursor,\n            &Rectangle {\n                y: bounds.y + translation.y,\n                x: bounds.x + translation.x,\n                ..bounds\n            },\n            renderer,\n        )\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        let state = tree.state.downcast_ref::<State>();\n        let bounds = layout.bounds();\n        let content_layout = layout.children().next().unwrap();\n        let content_bounds = content_layout.bounds();\n        let visible_bounds = bounds.intersection(viewport).unwrap_or(*viewport);\n        let offset = state.translation(self.direction, bounds, content_bounds);\n\n        let overlay = self.content.as_widget_mut().overlay(\n            &mut tree.children[0],\n            layout.children().next().unwrap(),\n            renderer,\n            &visible_bounds,\n            translation - offset,\n        );\n\n        let icon = if let Interaction::AutoScrolling { origin, .. } = state.interaction {\n            let scrollbars = Scrollbars::new(state, self.direction, bounds, content_bounds);\n\n            Some(overlay::Element::new(Box::new(AutoScrollIcon {\n                origin,\n                vertical: scrollbars.y.is_some(),\n                horizontal: scrollbars.x.is_some(),\n                class: &self.class,\n            })))\n        } else {\n            None\n        };\n\n        match (overlay, icon) {\n            (None, None) => None,\n            (None, Some(icon)) => Some(icon),\n            (Some(overlay), None) => Some(overlay),\n            (Some(overlay), Some(icon)) => Some(overlay::Element::new(Box::new(\n                overlay::Group::with_children(vec![overlay, icon]),\n            ))),\n        }\n    }\n}\n\nstruct AutoScrollIcon<'a, Class> {\n    origin: Point,\n    vertical: bool,\n    horizontal: bool,\n    class: &'a Class,\n}\n\nimpl<Class> AutoScrollIcon<'_, Class> {\n    const SIZE: f32 = 40.0;\n    const DOT: f32 = Self::SIZE / 10.0;\n    const PADDING: f32 = Self::SIZE / 10.0;\n}\n\nimpl<Message, Theme, Renderer> core::Overlay<Message, Theme, Renderer>\n    for AutoScrollIcon<'_, Theme::Class<'_>>\nwhere\n    Renderer: text::Renderer,\n    Theme: Catalog,\n{\n    fn layout(&mut self, _renderer: &Renderer, _bounds: Size) -> layout::Node {\n        layout::Node::new(Size::new(Self::SIZE, Self::SIZE))\n            .move_to(self.origin - Vector::new(Self::SIZE, Self::SIZE) / 2.0)\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n    ) {\n        let bounds = layout.bounds();\n        let style = theme\n            .style(\n                self.class,\n                Status::Active {\n                    is_horizontal_scrollbar_disabled: false,\n                    is_vertical_scrollbar_disabled: false,\n                },\n            )\n            .auto_scroll;\n\n        renderer.with_layer(Rectangle::INFINITE, |renderer| {\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds,\n                    border: style.border,\n                    shadow: style.shadow,\n                    snap: false,\n                },\n                style.background,\n            );\n\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds: Rectangle::new(\n                        bounds.center() - Vector::new(Self::DOT, Self::DOT) / 2.0,\n                        Size::new(Self::DOT, Self::DOT),\n                    ),\n                    border: border::rounded(bounds.width),\n                    snap: false,\n                    ..renderer::Quad::default()\n                },\n                style.icon,\n            );\n\n            let arrow = core::Text {\n                content: String::new(),\n                bounds: bounds.size(),\n                size: Pixels::from(12),\n                line_height: text::LineHeight::Relative(1.0),\n                font: Renderer::ICON_FONT,\n                align_x: text::Alignment::Center,\n                align_y: alignment::Vertical::Center,\n                shaping: text::Shaping::Basic,\n                wrapping: text::Wrapping::None,\n                ellipsis: text::Ellipsis::None,\n                hint_factor: None,\n            };\n\n            if self.vertical {\n                renderer.fill_text(\n                    core::Text {\n                        content: Renderer::SCROLL_UP_ICON.to_string(),\n                        align_y: alignment::Vertical::Top,\n                        ..arrow\n                    },\n                    Point::new(bounds.center_x(), bounds.y + Self::PADDING),\n                    style.icon,\n                    bounds,\n                );\n\n                renderer.fill_text(\n                    core::Text {\n                        content: Renderer::SCROLL_DOWN_ICON.to_string(),\n                        align_y: alignment::Vertical::Bottom,\n                        ..arrow\n                    },\n                    Point::new(\n                        bounds.center_x(),\n                        bounds.y + bounds.height - Self::PADDING - 0.5,\n                    ),\n                    style.icon,\n                    bounds,\n                );\n            }\n\n            if self.horizontal {\n                renderer.fill_text(\n                    core::Text {\n                        content: Renderer::SCROLL_LEFT_ICON.to_string(),\n                        align_x: text::Alignment::Left,\n                        ..arrow\n                    },\n                    Point::new(bounds.x + Self::PADDING + 1.0, bounds.center_y() + 1.0),\n                    style.icon,\n                    bounds,\n                );\n\n                renderer.fill_text(\n                    core::Text {\n                        content: Renderer::SCROLL_RIGHT_ICON.to_string(),\n                        align_x: text::Alignment::Right,\n                        ..arrow\n                    },\n                    Point::new(\n                        bounds.x + bounds.width - Self::PADDING - 1.0,\n                        bounds.center_y() + 1.0,\n                    ),\n                    style.icon,\n                    bounds,\n                );\n            }\n        });\n    }\n\n    fn index(&self) -> f32 {\n        f32::MAX\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Scrollable<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a + Catalog,\n    Renderer: 'a + text::Renderer,\n{\n    fn from(\n        text_input: Scrollable<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(text_input)\n    }\n}\n\nfn notify_scroll<Message>(\n    state: &mut State,\n    on_scroll: &Option<Box<dyn Fn(Viewport) -> Message + '_>>,\n    bounds: Rectangle,\n    content_bounds: Rectangle,\n    shell: &mut Shell<'_, Message>,\n) -> bool {\n    if notify_viewport(state, on_scroll, bounds, content_bounds, shell) {\n        state.last_scrolled = Some(Instant::now());\n\n        true\n    } else {\n        false\n    }\n}\n\nfn notify_viewport<Message>(\n    state: &mut State,\n    on_scroll: &Option<Box<dyn Fn(Viewport) -> Message + '_>>,\n    bounds: Rectangle,\n    content_bounds: Rectangle,\n    shell: &mut Shell<'_, Message>,\n) -> bool {\n    if content_bounds.width <= bounds.width && content_bounds.height <= bounds.height {\n        return false;\n    }\n\n    let viewport = Viewport {\n        offset_x: state.offset_x,\n        offset_y: state.offset_y,\n        bounds,\n        content_bounds,\n    };\n\n    // Don't publish redundant viewports to shell\n    if let Some(last_notified) = state.last_notified {\n        let last_relative_offset = last_notified.relative_offset();\n        let current_relative_offset = viewport.relative_offset();\n\n        let last_absolute_offset = last_notified.absolute_offset();\n        let current_absolute_offset = viewport.absolute_offset();\n\n        let unchanged =\n            |a: f32, b: f32| (a - b).abs() <= f32::EPSILON || (a.is_nan() && b.is_nan());\n\n        if last_notified.bounds == bounds\n            && last_notified.content_bounds == content_bounds\n            && unchanged(last_relative_offset.x, current_relative_offset.x)\n            && unchanged(last_relative_offset.y, current_relative_offset.y)\n            && unchanged(last_absolute_offset.x, current_absolute_offset.x)\n            && unchanged(last_absolute_offset.y, current_absolute_offset.y)\n        {\n            return false;\n        }\n    }\n\n    state.last_notified = Some(viewport);\n\n    if let Some(on_scroll) = on_scroll {\n        shell.publish(on_scroll(viewport));\n    }\n\n    true\n}\n\n#[derive(Debug, Clone, Copy)]\nstruct State {\n    offset_y: Offset,\n    offset_x: Offset,\n    interaction: Interaction,\n    keyboard_modifiers: keyboard::Modifiers,\n    last_notified: Option<Viewport>,\n    last_scrolled: Option<Instant>,\n    is_scrollbar_visible: bool,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum Interaction {\n    None,\n    YScrollerGrabbed(f32),\n    XScrollerGrabbed(f32),\n    TouchScrolling(Point),\n    AutoScrolling {\n        origin: Point,\n        current: Point,\n        last_frame: Option<Instant>,\n    },\n}\n\nimpl Default for State {\n    fn default() -> Self {\n        Self {\n            offset_y: Offset::Absolute(0.0),\n            offset_x: Offset::Absolute(0.0),\n            interaction: Interaction::None,\n            keyboard_modifiers: keyboard::Modifiers::default(),\n            last_notified: None,\n            last_scrolled: None,\n            is_scrollbar_visible: true,\n        }\n    }\n}\n\nimpl operation::Scrollable for State {\n    fn snap_to(&mut self, offset: RelativeOffset<Option<f32>>) {\n        State::snap_to(self, offset);\n    }\n\n    fn scroll_to(&mut self, offset: AbsoluteOffset<Option<f32>>) {\n        State::scroll_to(self, offset);\n    }\n\n    fn scroll_by(&mut self, offset: AbsoluteOffset, bounds: Rectangle, content_bounds: Rectangle) {\n        State::scroll_by(self, offset, bounds, content_bounds);\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq)]\nenum Offset {\n    Absolute(f32),\n    Relative(f32),\n}\n\nimpl Offset {\n    fn absolute(self, viewport: f32, content: f32) -> f32 {\n        match self {\n            Offset::Absolute(absolute) => absolute.min((content - viewport).max(0.0)),\n            Offset::Relative(percentage) => ((content - viewport) * percentage).max(0.0),\n        }\n    }\n\n    fn translation(self, viewport: f32, content: f32, alignment: Anchor) -> f32 {\n        let offset = self.absolute(viewport, content);\n\n        match alignment {\n            Anchor::Start => offset,\n            Anchor::End => ((content - viewport).max(0.0) - offset).max(0.0),\n        }\n    }\n}\n\n/// The current [`Viewport`] of the [`Scrollable`].\n#[derive(Debug, Clone, Copy)]\npub struct Viewport {\n    offset_x: Offset,\n    offset_y: Offset,\n    bounds: Rectangle,\n    content_bounds: Rectangle,\n}\n\nimpl Viewport {\n    /// Returns the [`AbsoluteOffset`] of the current [`Viewport`].\n    pub fn absolute_offset(&self) -> AbsoluteOffset {\n        let x = self\n            .offset_x\n            .absolute(self.bounds.width, self.content_bounds.width);\n        let y = self\n            .offset_y\n            .absolute(self.bounds.height, self.content_bounds.height);\n\n        AbsoluteOffset { x, y }\n    }\n\n    /// Returns the [`AbsoluteOffset`] of the current [`Viewport`], but with its\n    /// alignment reversed.\n    ///\n    /// This method can be useful to switch the alignment of a [`Scrollable`]\n    /// while maintaining its scrolling position.\n    pub fn absolute_offset_reversed(&self) -> AbsoluteOffset {\n        let AbsoluteOffset { x, y } = self.absolute_offset();\n\n        AbsoluteOffset {\n            x: (self.content_bounds.width - self.bounds.width).max(0.0) - x,\n            y: (self.content_bounds.height - self.bounds.height).max(0.0) - y,\n        }\n    }\n\n    /// Returns the [`RelativeOffset`] of the current [`Viewport`].\n    pub fn relative_offset(&self) -> RelativeOffset {\n        let AbsoluteOffset { x, y } = self.absolute_offset();\n\n        let x = x / (self.content_bounds.width - self.bounds.width);\n        let y = y / (self.content_bounds.height - self.bounds.height);\n\n        RelativeOffset { x, y }\n    }\n\n    /// Returns the bounds of the current [`Viewport`].\n    pub fn bounds(&self) -> Rectangle {\n        self.bounds\n    }\n\n    /// Returns the content bounds of the current [`Viewport`].\n    pub fn content_bounds(&self) -> Rectangle {\n        self.content_bounds\n    }\n}\n\nimpl State {\n    fn new() -> Self {\n        State::default()\n    }\n\n    fn scroll(&mut self, delta: Vector<f32>, bounds: Rectangle, content_bounds: Rectangle) {\n        if bounds.height < content_bounds.height {\n            self.offset_y = Offset::Absolute(\n                (self.offset_y.absolute(bounds.height, content_bounds.height) + delta.y)\n                    .clamp(0.0, content_bounds.height - bounds.height),\n            );\n        }\n\n        if bounds.width < content_bounds.width {\n            self.offset_x = Offset::Absolute(\n                (self.offset_x.absolute(bounds.width, content_bounds.width) + delta.x)\n                    .clamp(0.0, content_bounds.width - bounds.width),\n            );\n        }\n    }\n\n    fn scroll_y_to(&mut self, percentage: f32, bounds: Rectangle, content_bounds: Rectangle) {\n        self.offset_y = Offset::Relative(percentage.clamp(0.0, 1.0));\n        self.unsnap(bounds, content_bounds);\n    }\n\n    fn scroll_x_to(&mut self, percentage: f32, bounds: Rectangle, content_bounds: Rectangle) {\n        self.offset_x = Offset::Relative(percentage.clamp(0.0, 1.0));\n        self.unsnap(bounds, content_bounds);\n    }\n\n    fn snap_to(&mut self, offset: RelativeOffset<Option<f32>>) {\n        if let Some(x) = offset.x {\n            self.offset_x = Offset::Relative(x.clamp(0.0, 1.0));\n        }\n\n        if let Some(y) = offset.y {\n            self.offset_y = Offset::Relative(y.clamp(0.0, 1.0));\n        }\n    }\n\n    fn scroll_to(&mut self, offset: AbsoluteOffset<Option<f32>>) {\n        if let Some(x) = offset.x {\n            self.offset_x = Offset::Absolute(x.max(0.0));\n        }\n\n        if let Some(y) = offset.y {\n            self.offset_y = Offset::Absolute(y.max(0.0));\n        }\n    }\n\n    /// Scroll by the provided [`AbsoluteOffset`].\n    fn scroll_by(&mut self, offset: AbsoluteOffset, bounds: Rectangle, content_bounds: Rectangle) {\n        self.scroll(Vector::new(offset.x, offset.y), bounds, content_bounds);\n    }\n\n    /// Unsnaps the current scroll position, if snapped, given the bounds of the\n    /// [`Scrollable`] and its contents.\n    fn unsnap(&mut self, bounds: Rectangle, content_bounds: Rectangle) {\n        self.offset_x =\n            Offset::Absolute(self.offset_x.absolute(bounds.width, content_bounds.width));\n        self.offset_y =\n            Offset::Absolute(self.offset_y.absolute(bounds.height, content_bounds.height));\n    }\n\n    /// Returns the scrolling translation of the [`State`], given a [`Direction`],\n    /// the bounds of the [`Scrollable`] and its contents.\n    fn translation(\n        &self,\n        direction: Direction,\n        bounds: Rectangle,\n        content_bounds: Rectangle,\n    ) -> Vector {\n        Vector::new(\n            if let Some(horizontal) = direction.horizontal() {\n                self.offset_x\n                    .translation(bounds.width, content_bounds.width, horizontal.alignment)\n                    .round()\n            } else {\n                0.0\n            },\n            if let Some(vertical) = direction.vertical() {\n                self.offset_y\n                    .translation(bounds.height, content_bounds.height, vertical.alignment)\n                    .round()\n            } else {\n                0.0\n            },\n        )\n    }\n\n    fn scrollers_grabbed(&self) -> bool {\n        matches!(\n            self.interaction,\n            Interaction::YScrollerGrabbed(_) | Interaction::XScrollerGrabbed(_),\n        )\n    }\n\n    pub fn y_scroller_grabbed_at(&self) -> Option<f32> {\n        let Interaction::YScrollerGrabbed(at) = self.interaction else {\n            return None;\n        };\n\n        Some(at)\n    }\n\n    pub fn x_scroller_grabbed_at(&self) -> Option<f32> {\n        let Interaction::XScrollerGrabbed(at) = self.interaction else {\n            return None;\n        };\n\n        Some(at)\n    }\n}\n\n#[derive(Debug)]\n/// State of both [`Scrollbar`]s.\nstruct Scrollbars {\n    y: Option<internals::Scrollbar>,\n    x: Option<internals::Scrollbar>,\n}\n\nimpl Scrollbars {\n    /// Create y and/or x scrollbar(s) if content is overflowing the [`Scrollable`] bounds.\n    fn new(\n        state: &State,\n        direction: Direction,\n        bounds: Rectangle,\n        content_bounds: Rectangle,\n    ) -> Self {\n        let translation = state.translation(direction, bounds, content_bounds);\n\n        let show_scrollbar_x = direction\n            .horizontal()\n            .filter(|_scrollbar| content_bounds.width > bounds.width);\n\n        let show_scrollbar_y = direction\n            .vertical()\n            .filter(|_scrollbar| content_bounds.height > bounds.height);\n\n        let y_scrollbar = if let Some(vertical) = show_scrollbar_y {\n            let Scrollbar {\n                width,\n                margin,\n                scroller_width,\n                ..\n            } = *vertical;\n\n            // Adjust the height of the vertical scrollbar if the horizontal scrollbar\n            // is present\n            let x_scrollbar_height =\n                show_scrollbar_x.map_or(0.0, |h| h.width.max(h.scroller_width) + h.margin);\n\n            let total_scrollbar_width = width.max(scroller_width) + 2.0 * margin;\n\n            // Total bounds of the scrollbar + margin + scroller width\n            let total_scrollbar_bounds = Rectangle {\n                x: bounds.x + bounds.width - total_scrollbar_width,\n                y: bounds.y,\n                width: total_scrollbar_width,\n                height: (bounds.height - x_scrollbar_height).max(0.0),\n            };\n\n            // Bounds of just the scrollbar\n            let scrollbar_bounds = Rectangle {\n                x: bounds.x + bounds.width - total_scrollbar_width / 2.0 - width / 2.0,\n                y: bounds.y,\n                width,\n                height: (bounds.height - x_scrollbar_height).max(0.0),\n            };\n\n            let ratio = bounds.height / content_bounds.height;\n\n            let scroller = if ratio >= 1.0 {\n                None\n            } else {\n                // min height for easier grabbing with super tall content\n                let scroller_height = (scrollbar_bounds.height * ratio).max(2.0);\n                let scroller_offset =\n                    translation.y * ratio * scrollbar_bounds.height / bounds.height;\n\n                let scroller_bounds = Rectangle {\n                    x: bounds.x + bounds.width - total_scrollbar_width / 2.0 - scroller_width / 2.0,\n                    y: (scrollbar_bounds.y + scroller_offset).max(0.0),\n                    width: scroller_width,\n                    height: scroller_height,\n                };\n\n                Some(internals::Scroller {\n                    bounds: scroller_bounds,\n                })\n            };\n\n            Some(internals::Scrollbar {\n                total_bounds: total_scrollbar_bounds,\n                bounds: scrollbar_bounds,\n                scroller,\n                alignment: vertical.alignment,\n                disabled: content_bounds.height <= bounds.height,\n            })\n        } else {\n            None\n        };\n\n        let x_scrollbar = if let Some(horizontal) = show_scrollbar_x {\n            let Scrollbar {\n                width,\n                margin,\n                scroller_width,\n                ..\n            } = *horizontal;\n\n            // Need to adjust the width of the horizontal scrollbar if the vertical scrollbar\n            // is present\n            let scrollbar_y_width =\n                y_scrollbar.map_or(0.0, |scrollbar| scrollbar.total_bounds.width);\n\n            let total_scrollbar_height = width.max(scroller_width) + 2.0 * margin;\n\n            // Total bounds of the scrollbar + margin + scroller width\n            let total_scrollbar_bounds = Rectangle {\n                x: bounds.x,\n                y: bounds.y + bounds.height - total_scrollbar_height,\n                width: (bounds.width - scrollbar_y_width).max(0.0),\n                height: total_scrollbar_height,\n            };\n\n            // Bounds of just the scrollbar\n            let scrollbar_bounds = Rectangle {\n                x: bounds.x,\n                y: bounds.y + bounds.height - total_scrollbar_height / 2.0 - width / 2.0,\n                width: (bounds.width - scrollbar_y_width).max(0.0),\n                height: width,\n            };\n\n            let ratio = bounds.width / content_bounds.width;\n\n            let scroller = if ratio >= 1.0 {\n                None\n            } else {\n                // min width for easier grabbing with extra wide content\n                let scroller_length = (scrollbar_bounds.width * ratio).max(2.0);\n                let scroller_offset = translation.x * ratio * scrollbar_bounds.width / bounds.width;\n\n                let scroller_bounds = Rectangle {\n                    x: (scrollbar_bounds.x + scroller_offset).max(0.0),\n                    y: bounds.y + bounds.height\n                        - total_scrollbar_height / 2.0\n                        - scroller_width / 2.0,\n                    width: scroller_length,\n                    height: scroller_width,\n                };\n\n                Some(internals::Scroller {\n                    bounds: scroller_bounds,\n                })\n            };\n\n            Some(internals::Scrollbar {\n                total_bounds: total_scrollbar_bounds,\n                bounds: scrollbar_bounds,\n                scroller,\n                alignment: horizontal.alignment,\n                disabled: content_bounds.width <= bounds.width,\n            })\n        } else {\n            None\n        };\n\n        Self {\n            y: y_scrollbar,\n            x: x_scrollbar,\n        }\n    }\n\n    fn is_mouse_over(&self, cursor: mouse::Cursor) -> (bool, bool) {\n        if let Some(cursor_position) = cursor.position() {\n            (\n                self.y\n                    .as_ref()\n                    .map(|scrollbar| scrollbar.is_mouse_over(cursor_position))\n                    .unwrap_or(false),\n                self.x\n                    .as_ref()\n                    .map(|scrollbar| scrollbar.is_mouse_over(cursor_position))\n                    .unwrap_or(false),\n            )\n        } else {\n            (false, false)\n        }\n    }\n\n    fn is_y_disabled(&self) -> bool {\n        self.y.map(|y| y.disabled).unwrap_or(false)\n    }\n\n    fn is_x_disabled(&self) -> bool {\n        self.x.map(|x| x.disabled).unwrap_or(false)\n    }\n\n    fn grab_y_scroller(&self, cursor_position: Point) -> Option<f32> {\n        let scrollbar = self.y?;\n        let scroller = scrollbar.scroller?;\n\n        if scrollbar.total_bounds.contains(cursor_position) {\n            Some(if scroller.bounds.contains(cursor_position) {\n                (cursor_position.y - scroller.bounds.y) / scroller.bounds.height\n            } else {\n                0.5\n            })\n        } else {\n            None\n        }\n    }\n\n    fn grab_x_scroller(&self, cursor_position: Point) -> Option<f32> {\n        let scrollbar = self.x?;\n        let scroller = scrollbar.scroller?;\n\n        if scrollbar.total_bounds.contains(cursor_position) {\n            Some(if scroller.bounds.contains(cursor_position) {\n                (cursor_position.x - scroller.bounds.x) / scroller.bounds.width\n            } else {\n                0.5\n            })\n        } else {\n            None\n        }\n    }\n\n    fn active(&self) -> bool {\n        self.y.is_some() || self.x.is_some()\n    }\n}\n\npub(super) mod internals {\n    use crate::core::{Point, Rectangle};\n\n    use super::Anchor;\n\n    #[derive(Debug, Copy, Clone)]\n    pub struct Scrollbar {\n        pub total_bounds: Rectangle,\n        pub bounds: Rectangle,\n        pub scroller: Option<Scroller>,\n        pub alignment: Anchor,\n        pub disabled: bool,\n    }\n\n    impl Scrollbar {\n        /// Returns whether the mouse is over the scrollbar or not.\n        pub fn is_mouse_over(&self, cursor_position: Point) -> bool {\n            self.total_bounds.contains(cursor_position)\n        }\n\n        /// Returns the y-axis scrolled percentage from the cursor position.\n        pub fn scroll_percentage_y(&self, grabbed_at: f32, cursor_position: Point) -> f32 {\n            if let Some(scroller) = self.scroller {\n                let percentage =\n                    (cursor_position.y - self.bounds.y - scroller.bounds.height * grabbed_at)\n                        / (self.bounds.height - scroller.bounds.height);\n\n                match self.alignment {\n                    Anchor::Start => percentage,\n                    Anchor::End => 1.0 - percentage,\n                }\n            } else {\n                0.0\n            }\n        }\n\n        /// Returns the x-axis scrolled percentage from the cursor position.\n        pub fn scroll_percentage_x(&self, grabbed_at: f32, cursor_position: Point) -> f32 {\n            if let Some(scroller) = self.scroller {\n                let percentage =\n                    (cursor_position.x - self.bounds.x - scroller.bounds.width * grabbed_at)\n                        / (self.bounds.width - scroller.bounds.width);\n\n                match self.alignment {\n                    Anchor::Start => percentage,\n                    Anchor::End => 1.0 - percentage,\n                }\n            } else {\n                0.0\n            }\n        }\n    }\n\n    /// The handle of a [`Scrollbar`].\n    #[derive(Debug, Clone, Copy)]\n    pub struct Scroller {\n        /// The bounds of the [`Scroller`].\n        pub bounds: Rectangle,\n    }\n}\n\n/// The possible status of a [`Scrollable`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`Scrollable`] can be interacted with.\n    Active {\n        /// Whether or not the horizontal scrollbar is disabled meaning the content isn't overflowing.\n        is_horizontal_scrollbar_disabled: bool,\n        /// Whether or not the vertical scrollbar is disabled meaning the content isn't overflowing.\n        is_vertical_scrollbar_disabled: bool,\n    },\n    /// The [`Scrollable`] is being hovered.\n    Hovered {\n        /// Indicates if the horizontal scrollbar is being hovered.\n        is_horizontal_scrollbar_hovered: bool,\n        /// Indicates if the vertical scrollbar is being hovered.\n        is_vertical_scrollbar_hovered: bool,\n        /// Whether or not the horizontal scrollbar is disabled meaning the content isn't overflowing.\n        is_horizontal_scrollbar_disabled: bool,\n        /// Whether or not the vertical scrollbar is disabled meaning the content isn't overflowing.\n        is_vertical_scrollbar_disabled: bool,\n    },\n    /// The [`Scrollable`] is being dragged.\n    Dragged {\n        /// Indicates if the horizontal scrollbar is being dragged.\n        is_horizontal_scrollbar_dragged: bool,\n        /// Indicates if the vertical scrollbar is being dragged.\n        is_vertical_scrollbar_dragged: bool,\n        /// Whether or not the horizontal scrollbar is disabled meaning the content isn't overflowing.\n        is_horizontal_scrollbar_disabled: bool,\n        /// Whether or not the vertical scrollbar is disabled meaning the content isn't overflowing.\n        is_vertical_scrollbar_disabled: bool,\n    },\n}\n\n/// The appearance of a scrollable.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`container::Style`] of a scrollable.\n    pub container: container::Style,\n    /// The vertical [`Rail`] appearance.\n    pub vertical_rail: Rail,\n    /// The horizontal [`Rail`] appearance.\n    pub horizontal_rail: Rail,\n    /// The [`Background`] of the gap between a horizontal and vertical scrollbar.\n    pub gap: Option<Background>,\n    /// The appearance of the [`AutoScroll`] overlay.\n    pub auto_scroll: AutoScroll,\n}\n\n/// The appearance of the scrollbar of a scrollable.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Rail {\n    /// The [`Background`] of a scrollbar.\n    pub background: Option<Background>,\n    /// The [`Border`] of a scrollbar.\n    pub border: Border,\n    /// The appearance of the [`Scroller`] of a scrollbar.\n    pub scroller: Scroller,\n}\n\n/// The appearance of the scroller of a scrollable.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Scroller {\n    /// The [`Background`] of the scroller.\n    pub background: Background,\n    /// The [`Border`] of the scroller.\n    pub border: Border,\n}\n\n/// The appearance of the autoscroll overlay of a scrollable.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct AutoScroll {\n    /// The [`Background`] of the [`AutoScroll`] overlay.\n    pub background: Background,\n    /// The [`Border`] of the [`AutoScroll`] overlay.\n    pub border: Border,\n    /// Thje [`Shadow`] of the [`AutoScroll`] overlay.\n    pub shadow: Shadow,\n    /// The [`Color`] for the arrow icons of the [`AutoScroll`] overlay.\n    pub icon: Color,\n}\n\n/// The theme catalog of a [`Scrollable`].\npub trait Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`Scrollable`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// The default style of a [`Scrollable`].\npub fn default(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    let scrollbar = Rail {\n        background: Some(palette.background.weak.color.into()),\n        border: border::rounded(2),\n        scroller: Scroller {\n            background: palette.background.strongest.color.into(),\n            border: border::rounded(2),\n        },\n    };\n\n    let auto_scroll = AutoScroll {\n        background: palette.background.base.color.scale_alpha(0.9).into(),\n        border: border::rounded(u32::MAX)\n            .width(1)\n            .color(palette.background.base.text.scale_alpha(0.8)),\n        shadow: Shadow {\n            color: Color::BLACK.scale_alpha(0.7),\n            offset: Vector::ZERO,\n            blur_radius: 2.0,\n        },\n        icon: palette.background.base.text.scale_alpha(0.8),\n    };\n\n    match status {\n        Status::Active { .. } => Style {\n            container: container::Style::default(),\n            vertical_rail: scrollbar,\n            horizontal_rail: scrollbar,\n            gap: None,\n            auto_scroll,\n        },\n        Status::Hovered {\n            is_horizontal_scrollbar_hovered,\n            is_vertical_scrollbar_hovered,\n            ..\n        } => {\n            let hovered_scrollbar = Rail {\n                scroller: Scroller {\n                    background: palette.primary.strong.color.into(),\n                    ..scrollbar.scroller\n                },\n                ..scrollbar\n            };\n\n            Style {\n                container: container::Style::default(),\n                vertical_rail: if is_vertical_scrollbar_hovered {\n                    hovered_scrollbar\n                } else {\n                    scrollbar\n                },\n                horizontal_rail: if is_horizontal_scrollbar_hovered {\n                    hovered_scrollbar\n                } else {\n                    scrollbar\n                },\n                gap: None,\n                auto_scroll,\n            }\n        }\n        Status::Dragged {\n            is_horizontal_scrollbar_dragged,\n            is_vertical_scrollbar_dragged,\n            ..\n        } => {\n            let dragged_scrollbar = Rail {\n                scroller: Scroller {\n                    background: palette.primary.base.color.into(),\n                    ..scrollbar.scroller\n                },\n                ..scrollbar\n            };\n\n            Style {\n                container: container::Style::default(),\n                vertical_rail: if is_vertical_scrollbar_dragged {\n                    dragged_scrollbar\n                } else {\n                    scrollbar\n                },\n                horizontal_rail: if is_horizontal_scrollbar_dragged {\n                    dragged_scrollbar\n                } else {\n                    scrollbar\n                },\n                gap: None,\n                auto_scroll,\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "widget/src/sensor.rs",
    "content": "//! Generate messages when content pops in and out of view.\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::time::{Duration, Instant};\nuse crate::core::widget;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    self, Element, Event, Layout, Length, Pixels, Rectangle, Shell, Size, Vector, Widget,\n};\n\n/// A widget that can generate messages when its content pops in and out of view.\n///\n/// It can even notify you with anticipation at a given distance!\npub struct Sensor<'a, Key, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    content: Element<'a, Message, Theme, Renderer>,\n    key: Key,\n    on_show: Option<Box<dyn Fn(Size) -> Message + 'a>>,\n    on_resize: Option<Box<dyn Fn(Size) -> Message + 'a>>,\n    on_hide: Option<Message>,\n    anticipate: Pixels,\n    delay: Duration,\n}\n\nimpl<'a, Message, Theme, Renderer> Sensor<'a, (), Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n{\n    /// Creates a new [`Sensor`] widget with the given content.\n    pub fn new(content: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            content: content.into(),\n            key: (),\n            on_show: None,\n            on_resize: None,\n            on_hide: None,\n            anticipate: Pixels::ZERO,\n            delay: Duration::ZERO,\n        }\n    }\n}\n\nimpl<'a, Key, Message, Theme, Renderer> Sensor<'a, Key, Message, Theme, Renderer>\nwhere\n    Key: self::Key,\n    Renderer: core::Renderer,\n{\n    /// Sets the message to be produced when the content pops into view.\n    ///\n    /// The closure will receive the [`Size`] of the content in that moment.\n    pub fn on_show(mut self, on_show: impl Fn(Size) -> Message + 'a) -> Self {\n        self.on_show = Some(Box::new(on_show));\n        self\n    }\n\n    /// Sets the message to be produced when the content changes [`Size`] once its in view.\n    ///\n    /// The closure will receive the new [`Size`] of the content.\n    pub fn on_resize(mut self, on_resize: impl Fn(Size) -> Message + 'a) -> Self {\n        self.on_resize = Some(Box::new(on_resize));\n        self\n    }\n\n    /// Sets the message to be produced when the content pops out of view.\n    pub fn on_hide(mut self, on_hide: Message) -> Self {\n        self.on_hide = Some(on_hide);\n        self\n    }\n\n    /// Sets the key of the [`Sensor`] widget, for continuity.\n    ///\n    /// If the key changes, the [`Sensor`] widget will trigger again.\n    pub fn key<K>(self, key: K) -> Sensor<'a, impl self::Key, Message, Theme, Renderer>\n    where\n        K: Clone + PartialEq + 'static,\n    {\n        Sensor {\n            content: self.content,\n            key: OwnedKey(key),\n            on_show: self.on_show,\n            on_resize: self.on_resize,\n            on_hide: self.on_hide,\n            anticipate: self.anticipate,\n            delay: self.delay,\n        }\n    }\n\n    /// Sets the key of the [`Sensor`], for continuity; using a reference.\n    ///\n    /// If the key changes, the [`Sensor`] will trigger again.\n    pub fn key_ref<K>(self, key: &'a K) -> Sensor<'a, &'a K, Message, Theme, Renderer>\n    where\n        K: ToOwned + PartialEq<K::Owned> + ?Sized,\n        K::Owned: 'static,\n    {\n        Sensor {\n            content: self.content,\n            key,\n            on_show: self.on_show,\n            on_resize: self.on_resize,\n            on_hide: self.on_hide,\n            anticipate: self.anticipate,\n            delay: self.delay,\n        }\n    }\n\n    /// Sets the distance in [`Pixels`] to use in anticipation of the\n    /// content popping into view.\n    ///\n    /// This can be quite useful to lazily load items in a long scrollable\n    /// behind the scenes before the user can notice it!\n    pub fn anticipate(mut self, distance: impl Into<Pixels>) -> Self {\n        self.anticipate = distance.into();\n        self\n    }\n\n    /// Sets the amount of time to wait before firing an [`on_show`] or\n    /// [`on_hide`] event; after the content is shown or hidden.\n    ///\n    /// When combined with [`key`], this can be useful to debounce key changes.\n    ///\n    /// [`on_show`]: Self::on_show\n    /// [`on_hide`]: Self::on_hide\n    /// [`key`]: Self::key\n    pub fn delay(mut self, delay: impl Into<Duration>) -> Self {\n        self.delay = delay.into();\n        self\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct State<Key> {\n    has_popped_in: bool,\n    should_notify_at: Option<(bool, Instant)>,\n    last_size: Option<Size>,\n    last_key: Key,\n}\n\nimpl<Key, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Sensor<'_, Key, Message, Theme, Renderer>\nwhere\n    Key: self::Key,\n    Renderer: core::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State<Key::Owned>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State {\n            has_popped_in: false,\n            should_notify_at: None,\n            last_size: None,\n            last_key: self.key.to_owned(),\n        })\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        vec![Tree::new(&self.content)]\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        tree.diff_children(&[&self.content]);\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        if let Event::Window(window::Event::RedrawRequested(now)) = &event {\n            let state = tree.state.downcast_mut::<State<Key::Owned>>();\n\n            if state.has_popped_in && !self.key.eq(&state.last_key) {\n                state.has_popped_in = false;\n                state.should_notify_at = None;\n                state.last_key = self.key.to_owned();\n            }\n\n            let bounds = layout.bounds();\n            let top_left_distance = viewport.distance(bounds.position());\n\n            let bottom_right_distance =\n                viewport.distance(bounds.position() + Vector::from(bounds.size()));\n\n            let distance = top_left_distance.min(bottom_right_distance);\n\n            if self.on_show.is_none() {\n                if let Some(on_resize) = &self.on_resize {\n                    let size = bounds.size();\n\n                    if Some(size) != state.last_size {\n                        state.last_size = Some(size);\n                        shell.publish(on_resize(size));\n                    }\n                }\n            } else if state.has_popped_in {\n                if distance <= self.anticipate.0 {\n                    if let Some(on_resize) = &self.on_resize {\n                        let size = bounds.size();\n\n                        if Some(size) != state.last_size {\n                            state.last_size = Some(size);\n                            shell.publish(on_resize(size));\n                        }\n                    }\n                } else if self.on_hide.is_some() {\n                    state.has_popped_in = false;\n                    state.should_notify_at = Some((false, *now + self.delay));\n                }\n            } else if distance <= self.anticipate.0 {\n                let size = bounds.size();\n\n                state.has_popped_in = true;\n                state.should_notify_at = Some((true, *now + self.delay));\n                state.last_size = Some(size);\n            }\n\n            match &state.should_notify_at {\n                Some((has_popped_in, at)) if at <= now => {\n                    if *has_popped_in {\n                        if let Some(on_show) = &self.on_show {\n                            shell.publish(on_show(layout.bounds().size()));\n                        }\n                    } else if let Some(on_hide) = self.on_hide.take() {\n                        shell.publish(on_hide);\n                    }\n\n                    state.should_notify_at = None;\n                }\n                Some((_, at)) => {\n                    shell.request_redraw_at(*at);\n                }\n                None => {}\n            }\n        }\n\n        self.content.as_widget_mut().update(\n            &mut tree.children[0],\n            event,\n            layout,\n            cursor,\n            renderer,\n            shell,\n            viewport,\n        );\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.content.as_widget().size()\n    }\n\n    fn size_hint(&self) -> Size<Length> {\n        self.content.as_widget().size_hint()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.content\n            .as_widget_mut()\n            .layout(&mut tree.children[0], renderer, limits)\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: layout::Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget().draw(\n            &tree.children[0],\n            renderer,\n            theme,\n            style,\n            layout,\n            cursor,\n            viewport,\n        );\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: core::Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        self.content\n            .as_widget_mut()\n            .operate(&mut tree.children[0], layout, renderer, operation);\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: core::Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.content.as_widget().mouse_interaction(\n            &tree.children[0],\n            layout,\n            cursor,\n            viewport,\n            renderer,\n        )\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: core::Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: core::Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        self.content.as_widget_mut().overlay(\n            &mut tree.children[0],\n            layout,\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Key, Message, Theme, Renderer> From<Sensor<'a, Key, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Key: self::Key + 'a,\n    Renderer: core::Renderer + 'a,\n    Theme: 'a,\n{\n    fn from(pop: Sensor<'a, Key, Message, Theme, Renderer>) -> Self {\n        Element::new(pop)\n    }\n}\n\n/// The key of a widget.\n///\n/// You should generally not need to care about this trait.\npub trait Key {\n    /// The owned version of the key.\n    type Owned: 'static;\n\n    /// Returns the owned version of the key.\n    fn to_owned(&self) -> Self::Owned;\n\n    /// Compares the key with the given owned version.\n    fn eq(&self, other: &Self::Owned) -> bool;\n}\n\nimpl<T> Key for &T\nwhere\n    T: ToOwned + PartialEq<T::Owned> + ?Sized,\n    T::Owned: 'static,\n{\n    type Owned = T::Owned;\n\n    fn to_owned(&self) -> <Self as Key>::Owned {\n        ToOwned::to_owned(*self)\n    }\n\n    fn eq(&self, other: &Self::Owned) -> bool {\n        *self == other\n    }\n}\n\nstruct OwnedKey<T>(T);\n\nimpl<T> Key for OwnedKey<T>\nwhere\n    T: PartialEq + Clone + 'static,\n{\n    type Owned = T;\n\n    fn to_owned(&self) -> Self::Owned {\n        self.0.clone()\n    }\n\n    fn eq(&self, other: &Self::Owned) -> bool {\n        &self.0 == other\n    }\n}\n\nimpl<T> PartialEq<T> for OwnedKey<T>\nwhere\n    T: PartialEq,\n{\n    fn eq(&self, other: &T) -> bool {\n        &self.0 == other\n    }\n}\n\nimpl Key for () {\n    type Owned = ();\n\n    fn to_owned(&self) -> Self::Owned {}\n\n    fn eq(&self, _other: &Self::Owned) -> bool {\n        true\n    }\n}\n"
  },
  {
    "path": "widget/src/shader/program.rs",
    "content": "use crate::core::Rectangle;\nuse crate::core::mouse;\nuse crate::renderer::wgpu::Primitive;\nuse crate::shader::{self, Action};\n\n/// The state and logic of a [`Shader`] widget.\n///\n/// A [`Program`] can mutate the internal state of a [`Shader`] widget\n/// and produce messages for an application.\n///\n/// [`Shader`]: crate::Shader\npub trait Program<Message> {\n    /// The internal state of the [`Program`].\n    type State: Default + 'static;\n\n    /// The type of primitive this [`Program`] can draw.\n    type Primitive: Primitive + 'static;\n\n    /// Update the internal [`State`] of the [`Program`]. This can be used to reflect state changes\n    /// based on mouse & other events. You can return an [`Action`] to publish a message, request a\n    /// redraw, or capture the event.\n    ///\n    /// By default, this method returns `None`.\n    ///\n    /// [`State`]: Self::State\n    fn update(\n        &self,\n        _state: &mut Self::State,\n        _event: &shader::Event,\n        _bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> Option<Action<Message>> {\n        None\n    }\n\n    /// Draws the [`Primitive`].\n    ///\n    /// [`Primitive`]: Self::Primitive\n    fn draw(\n        &self,\n        state: &Self::State,\n        cursor: mouse::Cursor,\n        bounds: Rectangle,\n    ) -> Self::Primitive;\n\n    /// Returns the current mouse interaction of the [`Program`].\n    ///\n    /// The interaction returned will be in effect even if the cursor position is out of\n    /// bounds of the [`Shader`]'s program.\n    ///\n    /// [`Shader`]: crate::Shader\n    fn mouse_interaction(\n        &self,\n        _state: &Self::State,\n        _bounds: Rectangle,\n        _cursor: mouse::Cursor,\n    ) -> mouse::Interaction {\n        mouse::Interaction::default()\n    }\n}\n"
  },
  {
    "path": "widget/src/shader.rs",
    "content": "//! A custom shader widget for wgpu applications.\nmod program;\n\npub use program::Program;\n\nuse crate::core::event;\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::widget::{self, Widget};\nuse crate::core::{Element, Event, Length, Rectangle, Shell, Size};\nuse crate::renderer::wgpu::primitive;\n\nuse std::marker::PhantomData;\n\npub use crate::Action;\npub use crate::graphics::Viewport;\npub use primitive::{Pipeline, Primitive, Storage};\n\n/// A widget which can render custom shaders with Iced's `wgpu` backend.\n///\n/// Must be initialized with a [`Program`], which describes the internal widget state & how\n/// its [`Program::Primitive`]s are drawn.\npub struct Shader<Message, P: Program<Message>> {\n    width: Length,\n    height: Length,\n    program: P,\n    _message: PhantomData<Message>,\n}\n\nimpl<Message, P: Program<Message>> Shader<Message, P> {\n    /// Create a new custom [`Shader`].\n    pub fn new(program: P) -> Self {\n        Self {\n            width: Length::Fixed(100.0),\n            height: Length::Fixed(100.0),\n            program,\n            _message: PhantomData,\n        }\n    }\n\n    /// Set the `width` of the custom [`Shader`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Set the `height` of the custom [`Shader`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n}\n\nimpl<P, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Shader<Message, P>\nwhere\n    P: Program<Message>,\n    Renderer: primitive::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        struct Tag<T>(T);\n        tree::Tag::of::<Tag<P::State>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(P::State::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::atomic(limits, self.width, self.height)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        let state = tree.state.downcast_mut::<P::State>();\n\n        if let Some(action) = self.program.update(state, event, bounds, cursor) {\n            let (message, redraw_request, event_status) = action.into_inner();\n\n            shell.request_redraw_at(redraw_request);\n\n            if let Some(message) = message {\n                shell.publish(message);\n            }\n\n            if event_status == event::Status::Captured {\n                shell.capture_event();\n            }\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let bounds = layout.bounds();\n        let state = tree.state.downcast_ref::<P::State>();\n\n        self.program.mouse_interaction(state, bounds, cursor)\n    }\n\n    fn draw(\n        &self,\n        tree: &widget::Tree,\n        renderer: &mut Renderer,\n        _theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor_position: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n        let state = tree.state.downcast_ref::<P::State>();\n\n        renderer.draw_primitive(bounds, self.program.draw(state, cursor_position, bounds));\n    }\n}\n\nimpl<'a, Message, Theme, Renderer, P> From<Shader<Message, P>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Renderer: primitive::Renderer,\n    P: Program<Message> + 'a,\n{\n    fn from(custom: Shader<Message, P>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(custom)\n    }\n}\n\nimpl<Message, T> Program<Message> for &T\nwhere\n    T: Program<Message>,\n{\n    type State = T::State;\n    type Primitive = T::Primitive;\n\n    fn update(\n        &self,\n        state: &mut Self::State,\n        event: &Event,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> Option<Action<Message>> {\n        T::update(self, state, event, bounds, cursor)\n    }\n\n    fn draw(\n        &self,\n        state: &Self::State,\n        cursor: mouse::Cursor,\n        bounds: Rectangle,\n    ) -> Self::Primitive {\n        T::draw(self, state, cursor, bounds)\n    }\n\n    fn mouse_interaction(\n        &self,\n        state: &Self::State,\n        bounds: Rectangle,\n        cursor: mouse::Cursor,\n    ) -> mouse::Interaction {\n        T::mouse_interaction(self, state, bounds, cursor)\n    }\n}\n"
  },
  {
    "path": "widget/src/slider.rs",
    "content": "//! Sliders let users set a value by moving an indicator.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::slider;\n//!\n//! struct State {\n//!    value: f32,\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     ValueChanged(f32),\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     slider(0.0..=100.0, state.value, Message::ValueChanged).into()\n//! }\n//!\n//! fn update(state: &mut State, message: Message) {\n//!     match message {\n//!         Message::ValueChanged(value) => {\n//!             state.value = value;\n//!         }\n//!     }\n//! }\n//! ```\nuse crate::core::border::{self, Border};\nuse crate::core::keyboard;\nuse crate::core::keyboard::key::{self, Key};\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::touch;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    self, Background, Color, Element, Event, Layout, Length, Pixels, Point, Rectangle, Shell, Size,\n    Theme, Widget,\n};\n\nuse std::ops::RangeInclusive;\n\n/// An horizontal bar and a handle that selects a single value from a range of\n/// values.\n///\n/// A [`Slider`] will try to fill the horizontal space of its container.\n///\n/// The [`Slider`] range of numeric values is generic and its step size defaults\n/// to 1 unit.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::slider;\n///\n/// struct State {\n///    value: f32,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     ValueChanged(f32),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     slider(0.0..=100.0, state.value, Message::ValueChanged).into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::ValueChanged(value) => {\n///             state.value = value;\n///         }\n///     }\n/// }\n/// ```\npub struct Slider<'a, T, Message, Theme = crate::Theme>\nwhere\n    Theme: Catalog,\n{\n    range: RangeInclusive<T>,\n    step: T,\n    shift_step: Option<T>,\n    value: T,\n    default: Option<T>,\n    on_change: Box<dyn Fn(T) -> Message + 'a>,\n    on_release: Option<Message>,\n    width: Length,\n    height: f32,\n    class: Theme::Class<'a>,\n    status: Option<Status>,\n}\n\nimpl<'a, T, Message, Theme> Slider<'a, T, Message, Theme>\nwhere\n    T: Copy + From<u8> + PartialOrd,\n    Message: Clone,\n    Theme: Catalog,\n{\n    /// The default height of a [`Slider`].\n    pub const DEFAULT_HEIGHT: f32 = 16.0;\n\n    /// Creates a new [`Slider`].\n    ///\n    /// It expects:\n    ///   * an inclusive range of possible values\n    ///   * the current value of the [`Slider`]\n    ///   * a function that will be called when the [`Slider`] is dragged.\n    ///     It receives the new value of the [`Slider`] and must produce a\n    ///     `Message`.\n    pub fn new<F>(range: RangeInclusive<T>, value: T, on_change: F) -> Self\n    where\n        F: 'a + Fn(T) -> Message,\n    {\n        let value = if value >= *range.start() {\n            value\n        } else {\n            *range.start()\n        };\n\n        let value = if value <= *range.end() {\n            value\n        } else {\n            *range.end()\n        };\n\n        Slider {\n            value,\n            default: None,\n            range,\n            step: T::from(1),\n            shift_step: None,\n            on_change: Box::new(on_change),\n            on_release: None,\n            width: Length::Fill,\n            height: Self::DEFAULT_HEIGHT,\n            class: Theme::default(),\n            status: None,\n        }\n    }\n\n    /// Sets the optional default value for the [`Slider`].\n    ///\n    /// If set, the [`Slider`] will reset to this value when ctrl-clicked or command-clicked.\n    pub fn default(mut self, default: impl Into<T>) -> Self {\n        self.default = Some(default.into());\n        self\n    }\n\n    /// Sets the release message of the [`Slider`].\n    /// This is called when the mouse is released from the slider.\n    ///\n    /// Typically, the user's interaction with the slider is finished when this message is produced.\n    /// This is useful if you need to spawn a long-running task from the slider's result, where\n    /// the default on_change message could create too many events.\n    pub fn on_release(mut self, on_release: Message) -> Self {\n        self.on_release = Some(on_release);\n        self\n    }\n\n    /// Sets the width of the [`Slider`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Slider`].\n    pub fn height(mut self, height: impl Into<Pixels>) -> Self {\n        self.height = height.into().0;\n        self\n    }\n\n    /// Sets the step size of the [`Slider`].\n    pub fn step(mut self, step: impl Into<T>) -> Self {\n        self.step = step.into();\n        self\n    }\n\n    /// Sets the optional \"shift\" step for the [`Slider`].\n    ///\n    /// If set, this value is used as the step while the shift key is pressed.\n    pub fn shift_step(mut self, shift_step: impl Into<T>) -> Self {\n        self.shift_step = Some(shift_step.into());\n        self\n    }\n\n    /// Sets the style of the [`Slider`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Slider`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<T, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Slider<'_, T, Message, Theme>\nwhere\n    T: Copy + Into<f64> + num_traits::FromPrimitive,\n    Message: Clone,\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::atomic(limits, self.width, self.height)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_mut::<State>();\n\n        let mut update = || {\n            let current_value = self.value;\n\n            let locate = |cursor_position: Point| -> Option<T> {\n                let bounds = layout.bounds();\n\n                if cursor_position.x <= bounds.x {\n                    Some(*self.range.start())\n                } else if cursor_position.x >= bounds.x + bounds.width {\n                    Some(*self.range.end())\n                } else {\n                    let step = if state.keyboard_modifiers.shift() {\n                        self.shift_step.unwrap_or(self.step)\n                    } else {\n                        self.step\n                    }\n                    .into();\n\n                    let start = (*self.range.start()).into();\n                    let end = (*self.range.end()).into();\n\n                    let percent = f64::from(cursor_position.x - bounds.x) / f64::from(bounds.width);\n\n                    let steps = (percent * (end - start) / step).round();\n                    let value = steps * step + start;\n\n                    T::from_f64(value.min(end))\n                }\n            };\n\n            let increment = |value: T| -> Option<T> {\n                let step = if state.keyboard_modifiers.shift() {\n                    self.shift_step.unwrap_or(self.step)\n                } else {\n                    self.step\n                }\n                .into();\n\n                let steps = (value.into() / step).round();\n                let new_value = step * (steps + 1.0);\n\n                if new_value > (*self.range.end()).into() {\n                    return Some(*self.range.end());\n                }\n\n                T::from_f64(new_value)\n            };\n\n            let decrement = |value: T| -> Option<T> {\n                let step = if state.keyboard_modifiers.shift() {\n                    self.shift_step.unwrap_or(self.step)\n                } else {\n                    self.step\n                }\n                .into();\n\n                let steps = (value.into() / step).round();\n                let new_value = step * (steps - 1.0);\n\n                if new_value < (*self.range.start()).into() {\n                    return Some(*self.range.start());\n                }\n\n                T::from_f64(new_value)\n            };\n\n            let change = |new_value: T| {\n                if (self.value.into() - new_value.into()).abs() > f64::EPSILON {\n                    shell.publish((self.on_change)(new_value));\n\n                    self.value = new_value;\n                }\n            };\n\n            match &event {\n                Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n                | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                    if let Some(cursor_position) = cursor.position_over(layout.bounds()) {\n                        if state.keyboard_modifiers.command() {\n                            let _ = self.default.map(change);\n                            state.is_dragging = false;\n                        } else {\n                            let _ = locate(cursor_position).map(change);\n                            state.is_dragging = true;\n                        }\n\n                        shell.capture_event();\n                    }\n                }\n                Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))\n                | Event::Touch(touch::Event::FingerLifted { .. })\n                | Event::Touch(touch::Event::FingerLost { .. }) => {\n                    if state.is_dragging {\n                        if let Some(on_release) = self.on_release.clone() {\n                            shell.publish(on_release);\n                        }\n                        state.is_dragging = false;\n                    }\n                }\n                Event::Mouse(mouse::Event::CursorMoved { .. })\n                | Event::Touch(touch::Event::FingerMoved { .. }) => {\n                    if state.is_dragging {\n                        let _ = cursor.land().position().and_then(locate).map(change);\n\n                        shell.capture_event();\n                    }\n                }\n                Event::Mouse(mouse::Event::WheelScrolled { delta })\n                    if state.keyboard_modifiers.control() =>\n                {\n                    if cursor.is_over(layout.bounds()) {\n                        let delta = match delta {\n                            mouse::ScrollDelta::Lines { x: _, y } => y,\n                            mouse::ScrollDelta::Pixels { x: _, y } => y,\n                        };\n\n                        if *delta < 0.0 {\n                            let _ = decrement(current_value).map(change);\n                        } else {\n                            let _ = increment(current_value).map(change);\n                        }\n\n                        shell.capture_event();\n                    }\n                }\n                Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => {\n                    if cursor.is_over(layout.bounds()) {\n                        match key {\n                            Key::Named(key::Named::ArrowUp) => {\n                                let _ = increment(current_value).map(change);\n                                shell.capture_event();\n                            }\n                            Key::Named(key::Named::ArrowDown) => {\n                                let _ = decrement(current_value).map(change);\n                                shell.capture_event();\n                            }\n                            _ => (),\n                        }\n                    }\n                }\n                Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => {\n                    state.keyboard_modifiers = *modifiers;\n                }\n                _ => {}\n            }\n        };\n\n        update();\n\n        let current_status = if state.is_dragging {\n            Status::Dragged\n        } else if cursor.is_over(layout.bounds()) {\n            Status::Hovered\n        } else {\n            Status::Active\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.status = Some(current_status);\n        } else if self.status.is_some_and(|status| status != current_status) {\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        _tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        let style = theme.style(&self.class, self.status.unwrap_or(Status::Active));\n\n        let (handle_width, handle_height, handle_border_radius) = match style.handle.shape {\n            HandleShape::Circle { radius } => (radius * 2.0, radius * 2.0, radius.into()),\n            HandleShape::Rectangle {\n                width,\n                border_radius,\n            } => (f32::from(width), bounds.height, border_radius),\n        };\n\n        let value = self.value.into() as f32;\n        let (range_start, range_end) = {\n            let (start, end) = self.range.clone().into_inner();\n\n            (start.into() as f32, end.into() as f32)\n        };\n\n        let offset = if range_start >= range_end {\n            0.0\n        } else {\n            (bounds.width - handle_width) * (value - range_start) / (range_end - range_start)\n        };\n\n        let rail_y = bounds.y + bounds.height / 2.0;\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: Rectangle {\n                    x: bounds.x,\n                    y: rail_y - style.rail.width / 2.0,\n                    width: offset + handle_width / 2.0,\n                    height: style.rail.width,\n                },\n                border: style.rail.border,\n                ..renderer::Quad::default()\n            },\n            style.rail.backgrounds.0,\n        );\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: Rectangle {\n                    x: bounds.x + offset + handle_width / 2.0,\n                    y: rail_y - style.rail.width / 2.0,\n                    width: bounds.width - offset - handle_width / 2.0,\n                    height: style.rail.width,\n                },\n                border: style.rail.border,\n                ..renderer::Quad::default()\n            },\n            style.rail.backgrounds.1,\n        );\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: Rectangle {\n                    x: bounds.x + offset,\n                    y: rail_y - handle_height / 2.0,\n                    width: handle_width,\n                    height: handle_height,\n                },\n                border: Border {\n                    radius: handle_border_radius,\n                    width: style.handle.border_width,\n                    color: style.handle.border_color,\n                },\n                ..renderer::Quad::default()\n            },\n            style.handle.background,\n        );\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let state = tree.state.downcast_ref::<State>();\n\n        if state.is_dragging {\n            // FIXME: Fall back to `Pointer` on Windows\n            // See https://github.com/rust-windowing/winit/issues/1043\n            if cfg!(target_os = \"windows\") {\n                mouse::Interaction::Pointer\n            } else {\n                mouse::Interaction::Grabbing\n            }\n        } else if cursor.is_over(layout.bounds()) {\n            if cfg!(target_os = \"windows\") {\n                mouse::Interaction::Pointer\n            } else {\n                mouse::Interaction::Grab\n            }\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n}\n\nimpl<'a, T, Message, Theme, Renderer> From<Slider<'a, T, Message, Theme>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    T: Copy + Into<f64> + num_traits::FromPrimitive + 'a,\n    Message: Clone + 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(slider: Slider<'a, T, Message, Theme>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(slider)\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\nstruct State {\n    is_dragging: bool,\n    keyboard_modifiers: keyboard::Modifiers,\n}\n\n/// The possible status of a [`Slider`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`Slider`] can be interacted with.\n    Active,\n    /// The [`Slider`] is being hovered.\n    Hovered,\n    /// The [`Slider`] is being dragged.\n    Dragged,\n}\n\n/// The appearance of a slider.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The colors of the rail of the slider.\n    pub rail: Rail,\n    /// The appearance of the [`Handle`] of the slider.\n    pub handle: Handle,\n}\n\nimpl Style {\n    /// Changes the [`HandleShape`] of the [`Style`] to a circle\n    /// with the given radius.\n    pub fn with_circular_handle(mut self, radius: impl Into<Pixels>) -> Self {\n        self.handle.shape = HandleShape::Circle {\n            radius: radius.into().0,\n        };\n        self\n    }\n}\n\n/// The appearance of a slider rail\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Rail {\n    /// The backgrounds of the rail of the slider.\n    pub backgrounds: (Background, Background),\n    /// The width of the stroke of a slider rail.\n    pub width: f32,\n    /// The border of the rail.\n    pub border: Border,\n}\n\n/// The appearance of the handle of a slider.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Handle {\n    /// The shape of the handle.\n    pub shape: HandleShape,\n    /// The [`Background`] of the handle.\n    pub background: Background,\n    /// The border width of the handle.\n    pub border_width: f32,\n    /// The border [`Color`] of the handle.\n    pub border_color: Color,\n}\n\n/// The shape of the handle of a slider.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum HandleShape {\n    /// A circular handle.\n    Circle {\n        /// The radius of the circle.\n        radius: f32,\n    },\n    /// A rectangular shape.\n    Rectangle {\n        /// The width of the rectangle.\n        width: u16,\n        /// The border radius of the corners of the rectangle.\n        border_radius: border::Radius,\n    },\n}\n\n/// The theme catalog of a [`Slider`].\npub trait Catalog: Sized {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`Slider`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// The default style of a [`Slider`].\npub fn default(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    let color = match status {\n        Status::Active => palette.primary.base.color,\n        Status::Hovered => palette.primary.strong.color,\n        Status::Dragged => palette.primary.weak.color,\n    };\n\n    Style {\n        rail: Rail {\n            backgrounds: (color.into(), palette.background.strong.color.into()),\n            width: 4.0,\n            border: Border {\n                radius: 2.0.into(),\n                width: 0.0,\n                color: Color::TRANSPARENT,\n            },\n        },\n        handle: Handle {\n            shape: HandleShape::Circle { radius: 7.0 },\n            background: color.into(),\n            border_color: Color::TRANSPARENT,\n            border_width: 0.0,\n        },\n    }\n}\n"
  },
  {
    "path": "widget/src/space.rs",
    "content": "//! Add some explicit spacing between elements.\nuse crate::core;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::widget::Tree;\nuse crate::core::{Element, Layout, Length, Rectangle, Size, Widget};\n\n/// Creates a new [`Space`] widget that fills the available\n/// horizontal space.\n///\n/// This can be useful to separate widgets in a [`Row`](crate::Row).\npub fn horizontal() -> Space {\n    Space::new().width(Length::Fill)\n}\n\n/// Creates a new [`Space`] widget that fills the available\n/// vertical space.\n///\n/// This can be useful to separate widgets in a [`Column`](crate::Column).\npub fn vertical() -> Space {\n    Space::new().height(Length::Fill)\n}\n\n/// An amount of empty space.\n///\n/// It can be useful if you want to fill some space with nothing.\n#[derive(Debug)]\npub struct Space {\n    width: Length,\n    height: Length,\n}\n\nimpl Space {\n    /// Creates some empty [`Space`] with no size.\n    pub fn new() -> Self {\n        Space {\n            width: Length::Shrink,\n            height: Length::Shrink,\n        }\n    }\n\n    /// Sets the width of the [`Space`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Space`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n}\n\nimpl Default for Space {\n    fn default() -> Self {\n        Space::new()\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Space\nwhere\n    Renderer: core::Renderer,\n{\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::atomic(limits, self.width, self.height)\n    }\n\n    fn draw(\n        &self,\n        _tree: &Tree,\n        _renderer: &mut Renderer,\n        _theme: &Theme,\n        _style: &renderer::Style,\n        _layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Space> for Element<'a, Message, Theme, Renderer>\nwhere\n    Renderer: core::Renderer,\n    Message: 'a,\n{\n    fn from(space: Space) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(space)\n    }\n}\n"
  },
  {
    "path": "widget/src/stack.rs",
    "content": "//! Display content on top of other content.\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget::{Operation, Tree};\nuse crate::core::{Element, Event, Layout, Length, Rectangle, Shell, Size, Vector, Widget};\n\n/// A container that displays children on top of each other.\n///\n/// The first [`Element`] dictates the intrinsic [`Size`] of a [`Stack`] and\n/// will be displayed as the base layer. Every consecutive [`Element`] will be\n/// rendered on top; on its own layer.\n///\n/// You can use [`push_under`](Self::push_under) to push an [`Element`] under\n/// the current [`Stack`] without affecting its intrinsic [`Size`].\n///\n/// Keep in mind that too much layering will normally produce bad UX as well as\n/// introduce certain rendering overhead. Use this widget sparingly!\npub struct Stack<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    width: Length,\n    height: Length,\n    children: Vec<Element<'a, Message, Theme, Renderer>>,\n    clip: bool,\n    base_layer: usize,\n}\n\nimpl<'a, Message, Theme, Renderer> Stack<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    /// Creates an empty [`Stack`].\n    pub fn new() -> Self {\n        Self::from_vec(Vec::new())\n    }\n\n    /// Creates a [`Stack`] with the given capacity.\n    pub fn with_capacity(capacity: usize) -> Self {\n        Self::from_vec(Vec::with_capacity(capacity))\n    }\n\n    /// Creates a [`Stack`] with the given elements.\n    pub fn with_children(\n        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        let iterator = children.into_iter();\n\n        Self::with_capacity(iterator.size_hint().0).extend(iterator)\n    }\n\n    /// Creates a [`Stack`] from an already allocated [`Vec`].\n    ///\n    /// Keep in mind that the [`Stack`] will not inspect the [`Vec`], which means\n    /// it won't automatically adapt to the sizing strategy of its contents.\n    ///\n    /// If any of the children have a [`Length::Fill`] strategy, you will need to\n    /// call [`Stack::width`] or [`Stack::height`] accordingly.\n    pub fn from_vec(children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {\n        Self {\n            width: Length::Shrink,\n            height: Length::Shrink,\n            children,\n            clip: false,\n            base_layer: 0,\n        }\n    }\n\n    /// Sets the width of the [`Stack`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Stack`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Adds an element on top of the [`Stack`].\n    pub fn push(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        let child = child.into();\n        let child_size = child.as_widget().size_hint();\n\n        if !child_size.is_void() {\n            if self.children.is_empty() {\n                self.width = self.width.enclose(child_size.width);\n                self.height = self.height.enclose(child_size.height);\n            }\n\n            self.children.push(child);\n        }\n\n        self\n    }\n\n    /// Adds an element under the [`Stack`].\n    pub fn push_under(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {\n        self.children.insert(0, child.into());\n        self.base_layer += 1;\n        self\n    }\n\n    /// Extends the [`Stack`] with the given children.\n    pub fn extend(\n        self,\n        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        children.into_iter().fold(self, Self::push)\n    }\n\n    /// Sets whether the [`Stack`] should clip overflowing content.\n    ///\n    /// It has a slight performance overhead during presentation.\n    ///\n    /// By default, it is set to `false`.\n    pub fn clip(mut self, clip: bool) -> Self {\n        self.clip = clip;\n        self\n    }\n}\n\nimpl<Message, Renderer> Default for Stack<'_, Message, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Stack<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    fn children(&self) -> Vec<Tree> {\n        self.children.iter().map(Tree::new).collect()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        tree.diff_children(&self.children);\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits.width(self.width).height(self.height);\n\n        if self.children.len() <= self.base_layer {\n            return layout::Node::new(limits.resolve(self.width, self.height, Size::ZERO));\n        }\n\n        let base = self.children[self.base_layer].as_widget_mut().layout(\n            &mut tree.children[self.base_layer],\n            renderer,\n            &limits,\n        );\n\n        let size = limits.resolve(self.width, self.height, base.size());\n        let limits = layout::Limits::new(Size::ZERO, size);\n\n        let (under, above) = self.children.split_at_mut(self.base_layer);\n        let (tree_under, tree_above) = tree.children.split_at_mut(self.base_layer);\n\n        let nodes = under\n            .iter_mut()\n            .zip(tree_under)\n            .map(|(layer, tree)| layer.as_widget_mut().layout(tree, renderer, &limits))\n            .chain(std::iter::once(base))\n            .chain(\n                above[1..]\n                    .iter_mut()\n                    .zip(&mut tree_above[1..])\n                    .map(|(layer, tree)| layer.as_widget_mut().layout(tree, renderer, &limits)),\n            )\n            .collect();\n\n        layout::Node::with_children(size, nodes)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        operation.container(None, layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.children\n                .iter_mut()\n                .zip(&mut tree.children)\n                .zip(layout.children())\n                .for_each(|((child, state), layout)| {\n                    child\n                        .as_widget_mut()\n                        .operate(state, layout, renderer, operation);\n                });\n        });\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        mut cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        if self.children.is_empty() {\n            return;\n        }\n\n        let is_over = cursor.is_over(layout.bounds());\n        let end = self.children.len() - 1;\n\n        for (i, ((child, tree), layout)) in self\n            .children\n            .iter_mut()\n            .rev()\n            .zip(tree.children.iter_mut().rev())\n            .zip(layout.children().rev())\n            .enumerate()\n        {\n            child\n                .as_widget_mut()\n                .update(tree, event, layout, cursor, renderer, shell, viewport);\n\n            if shell.is_event_captured() {\n                return;\n            }\n\n            if i < end && is_over && !cursor.is_levitating() {\n                let interaction = child\n                    .as_widget()\n                    .mouse_interaction(tree, layout, cursor, viewport, renderer);\n\n                if interaction != mouse::Interaction::None {\n                    cursor = cursor.levitate();\n                }\n            }\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.children\n            .iter()\n            .rev()\n            .zip(tree.children.iter().rev())\n            .zip(layout.children().rev())\n            .map(|((child, tree), layout)| {\n                child\n                    .as_widget()\n                    .mouse_interaction(tree, layout, cursor, viewport, renderer)\n            })\n            .find(|&interaction| interaction != mouse::Interaction::None)\n            .unwrap_or_default()\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {\n            let viewport = if self.clip {\n                &clipped_viewport\n            } else {\n                viewport\n            };\n\n            let layers_under = if cursor.is_over(layout.bounds()) {\n                self.children\n                    .iter()\n                    .rev()\n                    .zip(tree.children.iter().rev())\n                    .zip(layout.children().rev())\n                    .position(|((layer, tree), layout)| {\n                        let interaction = layer\n                            .as_widget()\n                            .mouse_interaction(tree, layout, cursor, viewport, renderer);\n\n                        interaction != mouse::Interaction::None\n                    })\n                    .map(|i| self.children.len() - i - 1)\n                    .unwrap_or_default()\n            } else {\n                0\n            };\n\n            let mut layers = self\n                .children\n                .iter()\n                .zip(&tree.children)\n                .zip(layout.children())\n                .enumerate();\n\n            let layers = layers.by_ref();\n\n            let mut draw_layer =\n                |i, layer: &Element<'a, Message, Theme, Renderer>, tree, layout, cursor| {\n                    if i > 0 {\n                        renderer.with_layer(*viewport, |renderer| {\n                            layer\n                                .as_widget()\n                                .draw(tree, renderer, theme, style, layout, cursor, viewport);\n                        });\n                    } else {\n                        layer\n                            .as_widget()\n                            .draw(tree, renderer, theme, style, layout, cursor, viewport);\n                    }\n                };\n\n            for (i, ((layer, tree), layout)) in layers.take(layers_under) {\n                draw_layer(i, layer, tree, layout, mouse::Cursor::Unavailable);\n            }\n\n            for (i, ((layer, tree), layout)) in layers {\n                draw_layer(i, layer, tree, layout, cursor);\n            }\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        overlay::from_children(\n            &mut self.children,\n            tree,\n            layout,\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Stack<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: 'a,\n    Renderer: crate::core::Renderer + 'a,\n{\n    fn from(stack: Stack<'a, Message, Theme, Renderer>) -> Self {\n        Self::new(stack)\n    }\n}\n"
  },
  {
    "path": "widget/src/svg.rs",
    "content": "//! Svg widgets display vector graphics in your application.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! use iced::widget::svg;\n//!\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     svg(\"tiger.svg\").into()\n//! }\n//! ```\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::svg;\nuse crate::core::widget::Tree;\nuse crate::core::window;\nuse crate::core::{\n    Color, ContentFit, Element, Event, Layout, Length, Point, Rectangle, Rotation, Shell, Size,\n    Theme, Vector, Widget,\n};\n\nuse std::path::PathBuf;\n\npub use crate::core::svg::Handle;\n\n/// A vector graphics image.\n///\n/// An [`Svg`] image resizes smoothly without losing any quality.\n///\n/// [`Svg`] images can have a considerable rendering cost when resized,\n/// specially when they are complex.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::svg;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     svg(\"tiger.svg\").into()\n/// }\n/// ```\npub struct Svg<'a, Theme = crate::Theme>\nwhere\n    Theme: Catalog,\n{\n    handle: Handle,\n    width: Length,\n    height: Length,\n    content_fit: ContentFit,\n    class: Theme::Class<'a>,\n    rotation: Rotation,\n    opacity: f32,\n    status: Option<Status>,\n}\n\nimpl<'a, Theme> Svg<'a, Theme>\nwhere\n    Theme: Catalog,\n{\n    /// Creates a new [`Svg`] from the given [`Handle`].\n    pub fn new(handle: impl Into<Handle>) -> Self {\n        Svg {\n            handle: handle.into(),\n            width: Length::Fill,\n            height: Length::Shrink,\n            content_fit: ContentFit::Contain,\n            class: Theme::default(),\n            rotation: Rotation::default(),\n            opacity: 1.0,\n            status: None,\n        }\n    }\n\n    /// Creates a new [`Svg`] that will display the contents of the file at the\n    /// provided path.\n    #[must_use]\n    pub fn from_path(path: impl Into<PathBuf>) -> Self {\n        Self::new(Handle::from_path(path))\n    }\n\n    /// Sets the width of the [`Svg`].\n    #[must_use]\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Svg`].\n    #[must_use]\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the [`ContentFit`] of the [`Svg`].\n    ///\n    /// Defaults to [`ContentFit::Contain`]\n    #[must_use]\n    pub fn content_fit(self, content_fit: ContentFit) -> Self {\n        Self {\n            content_fit,\n            ..self\n        }\n    }\n\n    /// Sets the style of the [`Svg`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Svg`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n\n    /// Applies the given [`Rotation`] to the [`Svg`].\n    pub fn rotation(mut self, rotation: impl Into<Rotation>) -> Self {\n        self.rotation = rotation.into();\n        self\n    }\n\n    /// Sets the opacity of the [`Svg`].\n    ///\n    /// It should be in the [0.0, 1.0] range—`0.0` meaning completely transparent,\n    /// and `1.0` meaning completely opaque.\n    pub fn opacity(mut self, opacity: impl Into<f32>) -> Self {\n        self.opacity = opacity.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Svg<'_, Theme>\nwhere\n    Renderer: svg::Renderer,\n    Theme: Catalog,\n{\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        // The raw w/h of the underlying image\n        let Size { width, height } = renderer.measure_svg(&self.handle);\n        let image_size = Size::new(width as f32, height as f32);\n\n        // The rotated size of the svg\n        let rotated_size = self.rotation.apply(image_size);\n\n        // The size to be available to the widget prior to `Shrink`ing\n        let raw_size = limits.resolve(self.width, self.height, rotated_size);\n\n        // The uncropped size of the image when fit to the bounds above\n        let full_size = self.content_fit.fit(rotated_size, raw_size);\n\n        // Shrink the widget to fit the resized image, if requested\n        let final_size = Size {\n            width: match self.width {\n                Length::Shrink => f32::min(raw_size.width, full_size.width),\n                _ => raw_size.width,\n            },\n            height: match self.height {\n                Length::Shrink => f32::min(raw_size.height, full_size.height),\n                _ => raw_size.height,\n            },\n        };\n\n        layout::Node::new(final_size)\n    }\n\n    fn update(\n        &mut self,\n        _state: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let current_status = if cursor.is_over(layout.bounds()) {\n            Status::Hovered\n        } else {\n            Status::Idle\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.status = Some(current_status);\n        } else if self.status.is_some_and(|status| status != current_status) {\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        _state: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let Size { width, height } = renderer.measure_svg(&self.handle);\n        let image_size = Size::new(width as f32, height as f32);\n        let rotated_size = self.rotation.apply(image_size);\n\n        let bounds = layout.bounds();\n        let adjusted_fit = self.content_fit.fit(rotated_size, bounds.size());\n        let scale = Vector::new(\n            adjusted_fit.width / rotated_size.width,\n            adjusted_fit.height / rotated_size.height,\n        );\n\n        let final_size = image_size * scale;\n\n        let position = match self.content_fit {\n            ContentFit::None => Point::new(\n                bounds.x + (rotated_size.width - adjusted_fit.width) / 2.0,\n                bounds.y + (rotated_size.height - adjusted_fit.height) / 2.0,\n            ),\n            _ => Point::new(\n                bounds.center_x() - final_size.width / 2.0,\n                bounds.center_y() - final_size.height / 2.0,\n            ),\n        };\n\n        let drawing_bounds = Rectangle::new(position, final_size);\n\n        let style = theme.style(&self.class, self.status.unwrap_or(Status::Idle));\n\n        renderer.draw_svg(\n            svg::Svg {\n                handle: self.handle.clone(),\n                color: style.color,\n                rotation: self.rotation.radians(),\n                opacity: self.opacity,\n            },\n            drawing_bounds,\n            bounds,\n        );\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Svg<'a, Theme>> for Element<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog + 'a,\n    Renderer: svg::Renderer + 'a,\n{\n    fn from(icon: Svg<'a, Theme>) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(icon)\n    }\n}\n\n/// The possible status of an [`Svg`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`Svg`] is idle.\n    Idle,\n    /// The [`Svg`] is being hovered.\n    Hovered,\n}\n\n/// The appearance of an [`Svg`].\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub struct Style {\n    /// The [`Color`] filter of an [`Svg`].\n    ///\n    /// Useful for coloring a symbolic icon.\n    ///\n    /// `None` keeps the original color.\n    pub color: Option<Color>,\n}\n\n/// The theme catalog of an [`Svg`].\npub trait Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(|_theme, _status| Style::default())\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// A styling function for an [`Svg`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl<Theme> From<Style> for StyleFn<'_, Theme> {\n    fn from(style: Style) -> Self {\n        Box::new(move |_theme, _status| style)\n    }\n}\n"
  },
  {
    "path": "widget/src/table.rs",
    "content": "//! Display tables.\nuse crate::core;\nuse crate::core::alignment;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::widget;\nuse crate::core::{\n    Alignment, Background, Element, Layout, Length, Pixels, Rectangle, Size, Widget,\n};\n\n/// Creates a new [`Table`] with the given columns and rows.\n///\n/// Columns can be created using the [`column()`] function, while rows can be any\n/// iterator over some data type `T`.\npub fn table<'a, 'b, T, Message, Theme, Renderer>(\n    columns: impl IntoIterator<Item = Column<'a, 'b, T, Message, Theme, Renderer>>,\n    rows: impl IntoIterator<Item = T>,\n) -> Table<'a, Message, Theme, Renderer>\nwhere\n    T: Clone,\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    Table::new(columns, rows)\n}\n\n/// Creates a new [`Column`] with the given header and view function.\n///\n/// The view function will be called for each row in a [`Table`] and it must\n/// produce the resulting contents of a cell.\npub fn column<'a, 'b, T, E, Message, Theme, Renderer>(\n    header: impl Into<Element<'a, Message, Theme, Renderer>>,\n    view: impl Fn(T) -> E + 'b,\n) -> Column<'a, 'b, T, Message, Theme, Renderer>\nwhere\n    T: 'a,\n    E: Into<Element<'a, Message, Theme, Renderer>>,\n{\n    Column {\n        header: header.into(),\n        view: Box::new(move |data| view(data).into()),\n        width: Length::Shrink,\n        align_x: alignment::Horizontal::Left,\n        align_y: alignment::Vertical::Top,\n    }\n}\n\n/// A grid-like visual representation of data distributed in columns and rows.\npub struct Table<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n{\n    columns: Vec<Column_>,\n    cells: Vec<Element<'a, Message, Theme, Renderer>>,\n    width: Length,\n    height: Length,\n    padding_x: f32,\n    padding_y: f32,\n    separator_x: f32,\n    separator_y: f32,\n    class: Theme::Class<'a>,\n}\n\nstruct Column_ {\n    width: Length,\n    align_x: alignment::Horizontal,\n    align_y: alignment::Vertical,\n}\n\nimpl<'a, Message, Theme, Renderer> Table<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    /// Creates a new [`Table`] with the given columns and rows.\n    ///\n    /// Columns can be created using the [`column()`] function, while rows can be any\n    /// iterator over some data type `T`.\n    pub fn new<'b, T>(\n        columns: impl IntoIterator<Item = Column<'a, 'b, T, Message, Theme, Renderer>>,\n        rows: impl IntoIterator<Item = T>,\n    ) -> Self\n    where\n        T: Clone,\n    {\n        let columns = columns.into_iter();\n        let rows = rows.into_iter();\n\n        let mut width = Length::Shrink;\n        let mut height = Length::Shrink;\n\n        let mut cells = Vec::with_capacity(columns.size_hint().0 * (1 + rows.size_hint().0));\n\n        let (mut columns, views): (Vec<_>, Vec<_>) = columns\n            .map(|column| {\n                width = width.enclose(column.width);\n\n                cells.push(column.header);\n\n                (\n                    Column_ {\n                        width: column.width,\n                        align_x: column.align_x,\n                        align_y: column.align_y,\n                    },\n                    column.view,\n                )\n            })\n            .collect();\n\n        for row in rows {\n            for view in &views {\n                let cell = view(row.clone());\n                let size_hint = cell.as_widget().size_hint();\n\n                height = height.enclose(size_hint.height);\n\n                cells.push(cell);\n            }\n        }\n\n        if width == Length::Shrink\n            && let Some(first) = columns.first_mut()\n        {\n            first.width = Length::Fill;\n        }\n\n        Self {\n            columns,\n            cells,\n            width,\n            height,\n            padding_x: 10.0,\n            padding_y: 5.0,\n            separator_x: 1.0,\n            separator_y: 1.0,\n            class: Theme::default(),\n        }\n    }\n\n    /// Sets the width of the [`Table`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the padding of the cells of the [`Table`].\n    pub fn padding(self, padding: impl Into<Pixels>) -> Self {\n        let padding = padding.into();\n\n        self.padding_x(padding).padding_y(padding)\n    }\n\n    /// Sets the horizontal padding of the cells of the [`Table`].\n    pub fn padding_x(mut self, padding: impl Into<Pixels>) -> Self {\n        self.padding_x = padding.into().0;\n        self\n    }\n\n    /// Sets the vertical padding of the cells of the [`Table`].\n    pub fn padding_y(mut self, padding: impl Into<Pixels>) -> Self {\n        self.padding_y = padding.into().0;\n        self\n    }\n\n    /// Sets the thickness of the line separator between the cells of the [`Table`].\n    pub fn separator(self, separator: impl Into<Pixels>) -> Self {\n        let separator = separator.into();\n\n        self.separator_x(separator).separator_y(separator)\n    }\n\n    /// Sets the thickness of the horizontal line separator between the cells of the [`Table`].\n    pub fn separator_x(mut self, separator: impl Into<Pixels>) -> Self {\n        self.separator_x = separator.into().0;\n        self\n    }\n\n    /// Sets the thickness of the vertical line separator between the cells of the [`Table`].\n    pub fn separator_y(mut self, separator: impl Into<Pixels>) -> Self {\n        self.separator_y = separator.into().0;\n        self\n    }\n}\n\nstruct Metrics {\n    columns: Vec<f32>,\n    rows: Vec<f32>,\n}\n\nimpl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Table<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn tag(&self) -> widget::tree::Tag {\n        widget::tree::Tag::of::<Metrics>()\n    }\n\n    fn state(&self) -> widget::tree::State {\n        widget::tree::State::new(Metrics {\n            columns: Vec::new(),\n            rows: Vec::new(),\n        })\n    }\n\n    fn children(&self) -> Vec<widget::Tree> {\n        self.cells\n            .iter()\n            .map(|cell| widget::Tree::new(cell.as_widget()))\n            .collect()\n    }\n\n    fn diff(&self, tree: &mut widget::Tree) {\n        tree.diff_children(&self.cells);\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut widget::Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let metrics = tree.state.downcast_mut::<Metrics>();\n        let columns = self.columns.len();\n        let rows = self.cells.len() / columns;\n\n        let limits = limits.width(self.width).height(self.height);\n        let available = limits.max();\n        let table_fluid = self.width.fluid();\n\n        let mut cells = Vec::with_capacity(self.cells.len());\n        cells.resize(self.cells.len(), layout::Node::default());\n\n        metrics.columns = vec![0.0; self.columns.len()];\n        metrics.rows = vec![0.0; rows];\n\n        let mut column_factors = vec![0; self.columns.len()];\n        let mut total_row_factors = 0;\n        let mut total_fluid_height = 0.0;\n        let mut row_factor = 0;\n\n        let spacing_x = self.padding_x * 2.0 + self.separator_x;\n        let spacing_y = self.padding_y * 2.0 + self.separator_y;\n\n        // FIRST PASS\n        // Lay out non-fluid cells\n        let mut x = self.padding_x;\n        let mut y = self.padding_y;\n\n        for (i, (cell, state)) in self.cells.iter_mut().zip(&mut tree.children).enumerate() {\n            let row = i / columns;\n            let column = i % columns;\n\n            let width = self.columns[column].width;\n            let size = cell.as_widget().size();\n\n            if column == 0 {\n                x = self.padding_x;\n\n                if row > 0 {\n                    y += metrics.rows[row - 1] + spacing_y;\n\n                    if row_factor != 0 {\n                        total_fluid_height += metrics.rows[row - 1];\n                        total_row_factors += row_factor;\n\n                        row_factor = 0;\n                    }\n                }\n            }\n\n            let width_factor = width.fill_factor();\n            let height_factor = size.height.fill_factor();\n\n            if width_factor != 0 || height_factor != 0 || size.width.is_fill() {\n                column_factors[column] = column_factors[column].max(width_factor);\n\n                row_factor = row_factor.max(height_factor);\n\n                continue;\n            }\n\n            let limits = layout::Limits::new(\n                Size::ZERO,\n                Size::new(available.width - x, available.height - y),\n            )\n            .width(width);\n\n            let layout = cell.as_widget_mut().layout(state, renderer, &limits);\n            let size = limits.resolve(width, Length::Shrink, layout.size());\n\n            metrics.columns[column] = metrics.columns[column].max(size.width);\n            metrics.rows[row] = metrics.rows[row].max(size.height);\n            cells[i] = layout;\n\n            x += size.width + spacing_x;\n        }\n\n        // SECOND PASS\n        // Lay out fluid cells, using metrics from the first pass as limits\n        let left = Size::new(\n            available.width\n                - metrics\n                    .columns\n                    .iter()\n                    .enumerate()\n                    .filter(|(i, _)| column_factors[*i] == 0)\n                    .map(|(_, width)| width)\n                    .sum::<f32>(),\n            available.height - total_fluid_height,\n        );\n\n        let width_unit = (left.width\n            - spacing_x * self.columns.len().saturating_sub(1) as f32\n            - self.padding_x * 2.0)\n            / column_factors.iter().sum::<u16>() as f32;\n\n        let height_unit =\n            (left.height - spacing_y * rows.saturating_sub(1) as f32 - self.padding_y * 2.0)\n                / total_row_factors as f32;\n\n        let mut x = self.padding_x;\n        let mut y = self.padding_y;\n\n        for (i, (cell, state)) in self.cells.iter_mut().zip(&mut tree.children).enumerate() {\n            let row = i / columns;\n            let column = i % columns;\n\n            let size = cell.as_widget().size();\n\n            let width = self.columns[column].width;\n            let width_factor = width.fill_factor();\n            let height_factor = size.height.fill_factor();\n\n            if column == 0 {\n                x = self.padding_x;\n\n                if row > 0 {\n                    y += metrics.rows[row - 1] + spacing_y;\n                }\n            }\n\n            if width_factor == 0 && size.width.fill_factor() == 0 && size.height.fill_factor() == 0\n            {\n                continue;\n            }\n\n            let max_width = if width_factor == 0 {\n                if size.width.is_fill() {\n                    metrics.columns[column]\n                } else {\n                    (available.width - x).max(0.0)\n                }\n            } else {\n                width_unit * width_factor as f32\n            };\n\n            let max_height = if height_factor == 0 {\n                if size.height.is_fill() {\n                    metrics.rows[row]\n                } else {\n                    (available.height - y).max(0.0)\n                }\n            } else {\n                height_unit * height_factor as f32\n            };\n\n            let limits =\n                layout::Limits::new(Size::ZERO, Size::new(max_width, max_height)).width(width);\n\n            let layout = cell.as_widget_mut().layout(state, renderer, &limits);\n            let size = limits.resolve(\n                if let Length::Fixed(_) = width {\n                    width\n                } else {\n                    table_fluid\n                },\n                Length::Shrink,\n                layout.size(),\n            );\n\n            metrics.columns[column] = metrics.columns[column].max(size.width);\n            metrics.rows[row] = metrics.rows[row].max(size.height);\n            cells[i] = layout;\n\n            x += size.width + spacing_x;\n        }\n\n        // THIRD PASS\n        // Position each cell\n        let mut x = self.padding_x;\n        let mut y = self.padding_y;\n\n        for (i, cell) in cells.iter_mut().enumerate() {\n            let row = i / columns;\n            let column = i % columns;\n\n            if column == 0 {\n                x = self.padding_x;\n\n                if row > 0 {\n                    y += metrics.rows[row - 1] + spacing_y;\n                }\n            }\n\n            let Column_ {\n                align_x, align_y, ..\n            } = &self.columns[column];\n\n            cell.move_to_mut((x, y));\n            cell.align_mut(\n                Alignment::from(*align_x),\n                Alignment::from(*align_y),\n                Size::new(metrics.columns[column], metrics.rows[row]),\n            );\n\n            x += metrics.columns[column] + spacing_x;\n        }\n\n        let intrinsic = limits.resolve(\n            self.width,\n            self.height,\n            Size::new(\n                x - spacing_x + self.padding_x,\n                y + metrics\n                    .rows\n                    .last()\n                    .copied()\n                    .map(|height| height + self.padding_y)\n                    .unwrap_or_default(),\n            ),\n        );\n\n        layout::Node::with_children(intrinsic, cells)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut widget::Tree,\n        event: &core::Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut core::Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        for ((cell, tree), layout) in self\n            .cells\n            .iter_mut()\n            .zip(&mut tree.children)\n            .zip(layout.children())\n        {\n            cell.as_widget_mut()\n                .update(tree, event, layout, cursor, renderer, shell, viewport);\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &widget::Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        for ((cell, state), layout) in self.cells.iter().zip(&tree.children).zip(layout.children())\n        {\n            cell.as_widget()\n                .draw(state, renderer, theme, style, layout, cursor, viewport);\n        }\n\n        let bounds = layout.bounds();\n        let metrics = tree.state.downcast_ref::<Metrics>();\n        let style = theme.style(&self.class);\n\n        if self.separator_x > 0.0 {\n            let mut x = self.padding_x;\n\n            for width in &metrics.columns[..metrics.columns.len().saturating_sub(1)] {\n                x += width + self.padding_x;\n\n                renderer.fill_quad(\n                    renderer::Quad {\n                        bounds: Rectangle {\n                            x: bounds.x + x,\n                            y: bounds.y,\n                            width: self.separator_x,\n                            height: bounds.height,\n                        },\n                        snap: true,\n                        ..renderer::Quad::default()\n                    },\n                    style.separator_x,\n                );\n\n                x += self.separator_x + self.padding_x;\n            }\n        }\n\n        if self.separator_y > 0.0 {\n            let mut y = self.padding_y;\n\n            for height in &metrics.rows[..metrics.rows.len().saturating_sub(1)] {\n                y += height + self.padding_y;\n\n                renderer.fill_quad(\n                    renderer::Quad {\n                        bounds: Rectangle {\n                            x: bounds.x,\n                            y: bounds.y + y,\n                            width: bounds.width,\n                            height: self.separator_y,\n                        },\n                        snap: true,\n                        ..renderer::Quad::default()\n                    },\n                    style.separator_y,\n                );\n\n                y += self.separator_y + self.padding_y;\n            }\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &widget::Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.cells\n            .iter()\n            .zip(&tree.children)\n            .zip(layout.children())\n            .map(|((cell, tree), layout)| {\n                cell.as_widget()\n                    .mouse_interaction(tree, layout, cursor, viewport, renderer)\n            })\n            .max()\n            .unwrap_or_default()\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut widget::Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        for ((cell, state), layout) in self\n            .cells\n            .iter_mut()\n            .zip(&mut tree.children)\n            .zip(layout.children())\n        {\n            cell.as_widget_mut()\n                .operate(state, layout, renderer, operation);\n        }\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut widget::Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: core::Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        overlay::from_children(\n            &mut self.cells,\n            tree,\n            layout,\n            renderer,\n            viewport,\n            translation,\n        )\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Table<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(table: Table<'a, Message, Theme, Renderer>) -> Self {\n        Element::new(table)\n    }\n}\n\n/// A vertical visualization of some data with a header.\npub struct Column<'a, 'b, T, Message, Theme = crate::Theme, Renderer = crate::Renderer> {\n    header: Element<'a, Message, Theme, Renderer>,\n    view: Box<dyn Fn(T) -> Element<'a, Message, Theme, Renderer> + 'b>,\n    width: Length,\n    align_x: alignment::Horizontal,\n    align_y: alignment::Vertical,\n}\n\nimpl<'a, 'b, T, Message, Theme, Renderer> Column<'a, 'b, T, Message, Theme, Renderer> {\n    /// Sets the width of the [`Column`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the alignment for the horizontal axis of the [`Column`].\n    pub fn align_x(mut self, alignment: impl Into<alignment::Horizontal>) -> Self {\n        self.align_x = alignment.into();\n        self\n    }\n\n    /// Sets the alignment for the vertical axis of the [`Column`].\n    pub fn align_y(mut self, alignment: impl Into<alignment::Vertical>) -> Self {\n        self.align_y = alignment.into();\n        self\n    }\n}\n\n/// The appearance of a [`Table`].\n#[derive(Debug, Clone, Copy)]\npub struct Style {\n    /// The background color of the horizontal line separator between cells.\n    pub separator_x: Background,\n    /// The background color of the vertical line separator between cells.\n    pub separator_y: Background,\n}\n\n/// The theme catalog of a [`Table`].\npub trait Catalog {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>) -> Style;\n}\n\n/// A styling function for a [`Table`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>;\n\nimpl<Theme> From<Style> for StyleFn<'_, Theme> {\n    fn from(style: Style) -> Self {\n        Box::new(move |_theme| style)\n    }\n}\n\nimpl Catalog for crate::Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>) -> Style {\n        class(self)\n    }\n}\n\n/// The default style of a [`Table`].\npub fn default(theme: &crate::Theme) -> Style {\n    let palette = theme.palette();\n    let separator = palette.background.strong.color.into();\n\n    Style {\n        separator_x: separator,\n        separator_y: separator,\n    }\n}\n"
  },
  {
    "path": "widget/src/text/rich.rs",
    "content": "use crate::core::alignment;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::text::{Paragraph, Span};\nuse crate::core::widget::text::{\n    self, Alignment, Catalog, Ellipsis, LineHeight, Shaping, Style, StyleFn, Wrapping,\n};\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::{\n    self, Color, Element, Event, Layout, Length, Pixels, Point, Rectangle, Shell, Size, Vector,\n    Widget,\n};\n\n/// A bunch of [`Rich`] text.\npub struct Rich<'a, Link, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Link: Clone + 'static,\n    Theme: Catalog,\n    Renderer: core::text::Renderer,\n{\n    spans: Box<dyn AsRef<[Span<'a, Link, Renderer::Font>]> + 'a>,\n    size: Option<Pixels>,\n    line_height: LineHeight,\n    width: Length,\n    height: Length,\n    font: Option<Renderer::Font>,\n    align_x: Alignment,\n    align_y: alignment::Vertical,\n    wrapping: Wrapping,\n    ellipsis: Ellipsis,\n    class: Theme::Class<'a>,\n    hovered_link: Option<usize>,\n    on_link_click: Option<Box<dyn Fn(Link) -> Message + 'a>>,\n}\n\nimpl<'a, Link, Message, Theme, Renderer> Rich<'a, Link, Message, Theme, Renderer>\nwhere\n    Link: Clone + 'static,\n    Theme: Catalog,\n    Renderer: core::text::Renderer,\n    Renderer::Font: 'a,\n{\n    /// Creates a new empty [`Rich`] text.\n    pub fn new() -> Self {\n        Self {\n            spans: Box::new([]),\n            size: None,\n            line_height: LineHeight::default(),\n            width: Length::Shrink,\n            height: Length::Shrink,\n            font: None,\n            align_x: Alignment::Default,\n            align_y: alignment::Vertical::Top,\n            wrapping: Wrapping::default(),\n            ellipsis: Ellipsis::default(),\n            class: Theme::default(),\n            hovered_link: None,\n            on_link_click: None,\n        }\n    }\n\n    /// Creates a new [`Rich`] text with the given text spans.\n    pub fn with_spans(spans: impl AsRef<[Span<'a, Link, Renderer::Font>]> + 'a) -> Self {\n        Self {\n            spans: Box::new(spans),\n            ..Self::new()\n        }\n    }\n\n    /// Sets the default size of the [`Rich`] text.\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        self.size = Some(size.into());\n        self\n    }\n\n    /// Sets the default [`LineHeight`] of the [`Rich`] text.\n    pub fn line_height(mut self, line_height: impl Into<LineHeight>) -> Self {\n        self.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the default font of the [`Rich`] text.\n    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {\n        self.font = Some(font.into());\n        self\n    }\n\n    /// Sets the width of the [`Rich`] text boundaries.\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the height of the [`Rich`] text boundaries.\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Centers the [`Rich`] text, both horizontally and vertically.\n    pub fn center(self) -> Self {\n        self.align_x(alignment::Horizontal::Center)\n            .align_y(alignment::Vertical::Center)\n    }\n\n    /// Sets the [`alignment::Horizontal`] of the [`Rich`] text.\n    pub fn align_x(mut self, alignment: impl Into<Alignment>) -> Self {\n        self.align_x = alignment.into();\n        self\n    }\n\n    /// Sets the [`alignment::Vertical`] of the [`Rich`] text.\n    pub fn align_y(mut self, alignment: impl Into<alignment::Vertical>) -> Self {\n        self.align_y = alignment.into();\n        self\n    }\n\n    /// Sets the [`Wrapping`] strategy of the [`Rich`] text.\n    pub fn wrapping(mut self, wrapping: Wrapping) -> Self {\n        self.wrapping = wrapping;\n        self\n    }\n\n    /// Sets the [`Ellipsis`] strategy of the [`Rich`] text.\n    pub fn ellipsis(mut self, ellipsis: Ellipsis) -> Self {\n        self.ellipsis = ellipsis;\n        self\n    }\n\n    /// Sets the message that will be produced when a link of the [`Rich`] text\n    /// is clicked.\n    ///\n    /// If the spans of the [`Rich`] text contain no links, you may need to call\n    /// this method with `on_link_click(never)` in order for the compiler to infer\n    /// the proper `Link` generic type.\n    pub fn on_link_click(mut self, on_link_click: impl Fn(Link) -> Message + 'a) -> Self {\n        self.on_link_click = Some(Box::new(on_link_click));\n        self\n    }\n\n    /// Sets the default style of the [`Rich`] text.\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the default [`Color`] of the [`Rich`] text.\n    pub fn color(self, color: impl Into<Color>) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.color_maybe(Some(color))\n    }\n\n    /// Sets the default [`Color`] of the [`Rich`] text, if `Some`.\n    pub fn color_maybe(self, color: Option<impl Into<Color>>) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        let color = color.map(Into::into);\n\n        self.style(move |_theme| Style { color })\n    }\n\n    /// Sets the default style class of the [`Rich`] text.\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<'a, Link, Message, Theme, Renderer> Default for Rich<'a, Link, Message, Theme, Renderer>\nwhere\n    Link: Clone + 'a,\n    Theme: Catalog,\n    Renderer: core::text::Renderer,\n    Renderer::Font: 'a,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nstruct State<Link, P: Paragraph> {\n    spans: Vec<Span<'static, Link, P::Font>>,\n    span_pressed: Option<usize>,\n    paragraph: P,\n}\n\nimpl<Link, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Rich<'_, Link, Message, Theme, Renderer>\nwhere\n    Link: Clone + 'static,\n    Theme: Catalog,\n    Renderer: core::text::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State<Link, Renderer::Paragraph>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::<Link, _> {\n            spans: Vec::new(),\n            span_pressed: None,\n            paragraph: Renderer::Paragraph::default(),\n        })\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout(\n            tree.state\n                .downcast_mut::<State<Link, Renderer::Paragraph>>(),\n            renderer,\n            limits,\n            self.width,\n            self.height,\n            self.spans.as_ref().as_ref(),\n            self.line_height,\n            self.size,\n            self.font,\n            self.align_x,\n            self.align_y,\n            self.wrapping,\n            self.ellipsis,\n        )\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        defaults: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        if !layout.bounds().intersects(viewport) {\n            return;\n        }\n\n        let state = tree\n            .state\n            .downcast_ref::<State<Link, Renderer::Paragraph>>();\n\n        let style = theme.style(&self.class);\n\n        for (index, span) in self.spans.as_ref().as_ref().iter().enumerate() {\n            let is_hovered_link = self.on_link_click.is_some() && Some(index) == self.hovered_link;\n\n            if span.highlight.is_some() || span.underline || span.strikethrough || is_hovered_link {\n                let translation = layout.position() - Point::ORIGIN;\n                let regions = state.paragraph.span_bounds(index);\n\n                if let Some(highlight) = span.highlight {\n                    for bounds in &regions {\n                        let bounds = Rectangle::new(\n                            bounds.position() - Vector::new(span.padding.left, span.padding.top),\n                            bounds.size() + Size::new(span.padding.x(), span.padding.y()),\n                        );\n\n                        renderer.fill_quad(\n                            renderer::Quad {\n                                bounds: bounds + translation,\n                                border: highlight.border,\n                                ..Default::default()\n                            },\n                            highlight.background,\n                        );\n                    }\n                }\n\n                if span.underline || span.strikethrough || is_hovered_link {\n                    let size = span.size.or(self.size).unwrap_or(renderer.default_size());\n\n                    let line_height = span\n                        .line_height\n                        .unwrap_or(self.line_height)\n                        .to_absolute(size);\n\n                    let color = span.color.or(style.color).unwrap_or(defaults.text_color);\n\n                    let baseline =\n                        translation + Vector::new(0.0, size.0 + (line_height.0 - size.0) / 2.0);\n\n                    if span.underline || is_hovered_link {\n                        for bounds in &regions {\n                            renderer.fill_quad(\n                                renderer::Quad {\n                                    bounds: Rectangle::new(\n                                        bounds.position() + baseline\n                                            - Vector::new(0.0, size.0 * 0.08),\n                                        Size::new(bounds.width, 1.0),\n                                    ),\n                                    ..Default::default()\n                                },\n                                color,\n                            );\n                        }\n                    }\n\n                    if span.strikethrough {\n                        for bounds in &regions {\n                            renderer.fill_quad(\n                                renderer::Quad {\n                                    bounds: Rectangle::new(\n                                        bounds.position() + baseline\n                                            - Vector::new(0.0, size.0 / 2.0),\n                                        Size::new(bounds.width, 1.0),\n                                    ),\n                                    ..Default::default()\n                                },\n                                color,\n                            );\n                        }\n                    }\n                }\n            }\n        }\n\n        text::draw(\n            renderer,\n            defaults,\n            layout.bounds(),\n            &state.paragraph,\n            style,\n            viewport,\n        );\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let Some(on_link_clicked) = &self.on_link_click else {\n            return;\n        };\n\n        let was_hovered = self.hovered_link.is_some();\n\n        if let Some(position) = cursor.position_in(layout.bounds()) {\n            let state = tree\n                .state\n                .downcast_ref::<State<Link, Renderer::Paragraph>>();\n\n            self.hovered_link = state.paragraph.hit_span(position).and_then(|span| {\n                if self.spans.as_ref().as_ref().get(span)?.link.is_some() {\n                    Some(span)\n                } else {\n                    None\n                }\n            });\n        } else {\n            self.hovered_link = None;\n        }\n\n        if was_hovered != self.hovered_link.is_some() {\n            shell.request_redraw();\n        }\n\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {\n                let state = tree\n                    .state\n                    .downcast_mut::<State<Link, Renderer::Paragraph>>();\n\n                if self.hovered_link.is_some() {\n                    state.span_pressed = self.hovered_link;\n                    shell.capture_event();\n                }\n            }\n            Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {\n                let state = tree\n                    .state\n                    .downcast_mut::<State<Link, Renderer::Paragraph>>();\n\n                match state.span_pressed {\n                    Some(span) if Some(span) == self.hovered_link => {\n                        if let Some(link) = self\n                            .spans\n                            .as_ref()\n                            .as_ref()\n                            .get(span)\n                            .and_then(|span| span.link.clone())\n                        {\n                            shell.publish(on_link_clicked(link));\n                        }\n                    }\n                    _ => {}\n                }\n\n                state.span_pressed = None;\n            }\n            _ => {}\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        _layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        if self.hovered_link.is_some() {\n            mouse::Interaction::Pointer\n        } else {\n            mouse::Interaction::None\n        }\n    }\n}\n\nfn layout<Link, Renderer>(\n    state: &mut State<Link, Renderer::Paragraph>,\n    renderer: &Renderer,\n    limits: &layout::Limits,\n    width: Length,\n    height: Length,\n    spans: &[Span<'_, Link, Renderer::Font>],\n    line_height: LineHeight,\n    size: Option<Pixels>,\n    font: Option<Renderer::Font>,\n    align_x: Alignment,\n    align_y: alignment::Vertical,\n    wrapping: Wrapping,\n    ellipsis: Ellipsis,\n) -> layout::Node\nwhere\n    Link: Clone,\n    Renderer: core::text::Renderer,\n{\n    layout::sized(limits, width, height, |limits| {\n        let bounds = limits.max();\n\n        let size = size.unwrap_or_else(|| renderer.default_size());\n        let font = font.unwrap_or_else(|| renderer.default_font());\n\n        let text_with_spans = || core::Text {\n            content: spans,\n            bounds,\n            size,\n            line_height,\n            font,\n            align_x,\n            align_y,\n            shaping: Shaping::Advanced,\n            wrapping,\n            ellipsis,\n            hint_factor: renderer.scale_factor(),\n        };\n\n        if state.spans != spans {\n            state.paragraph = Renderer::Paragraph::with_spans(text_with_spans());\n            state.spans = spans.iter().cloned().map(Span::to_static).collect();\n        } else {\n            match state.paragraph.compare(core::Text {\n                content: (),\n                bounds,\n                size,\n                line_height,\n                font,\n                align_x,\n                align_y,\n                shaping: Shaping::Advanced,\n                wrapping,\n                ellipsis,\n                hint_factor: renderer.scale_factor(),\n            }) {\n                core::text::Difference::None => {}\n                core::text::Difference::Bounds => {\n                    state.paragraph.resize(bounds);\n                }\n                core::text::Difference::Shape => {\n                    state.paragraph = Renderer::Paragraph::with_spans(text_with_spans());\n                }\n            }\n        }\n\n        state.paragraph.min_bounds()\n    })\n}\n\nimpl<'a, Link, Message, Theme, Renderer> FromIterator<Span<'a, Link, Renderer::Font>>\n    for Rich<'a, Link, Message, Theme, Renderer>\nwhere\n    Link: Clone + 'a,\n    Theme: Catalog,\n    Renderer: core::text::Renderer,\n    Renderer::Font: 'a,\n{\n    fn from_iter<T: IntoIterator<Item = Span<'a, Link, Renderer::Font>>>(spans: T) -> Self {\n        Self::with_spans(spans.into_iter().collect::<Vec<_>>())\n    }\n}\n\nimpl<'a, Link, Message, Theme, Renderer> From<Rich<'a, Link, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Link: Clone + 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::text::Renderer + 'a,\n{\n    fn from(\n        text: Rich<'a, Link, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(text)\n    }\n}\n"
  },
  {
    "path": "widget/src/text.rs",
    "content": "//! Draw and interact with text.\nmod rich;\n\npub use crate::core::text::{Fragment, Highlighter, IntoFragment, Span};\npub use crate::core::widget::text::*;\npub use rich::Rich;\n\n/// A bunch of text.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::text;\n/// use iced::color;\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     text(\"Hello, this is iced!\")\n///         .size(20)\n///         .color(color!(0x0000ff))\n///         .into()\n/// }\n/// ```\npub type Text<'a, Theme = crate::Theme, Renderer = crate::Renderer> =\n    crate::core::widget::Text<'a, Theme, Renderer>;\n"
  },
  {
    "path": "widget/src/text_editor.rs",
    "content": "//! Text editors display a multi-line text input for text editing.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::text_editor;\n//!\n//! struct State {\n//!    content: text_editor::Content,\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     Edit(text_editor::Action)\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     text_editor(&state.content)\n//!         .placeholder(\"Type something here...\")\n//!         .on_action(Message::Edit)\n//!         .into()\n//! }\n//!\n//! fn update(state: &mut State, message: Message) {\n//!     match message {\n//!         Message::Edit(action) => {\n//!             state.content.perform(action);\n//!         }\n//!     }\n//! }\n//! ```\nuse crate::core::alignment;\nuse crate::core::clipboard;\nuse crate::core::input_method;\nuse crate::core::keyboard;\nuse crate::core::keyboard::key;\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::text::editor::Editor as _;\nuse crate::core::text::highlighter::{self, Highlighter};\nuse crate::core::text::{self, LineHeight, Text, Wrapping};\nuse crate::core::theme;\nuse crate::core::time::{Duration, Instant};\nuse crate::core::widget::operation;\nuse crate::core::widget::{self, Widget};\nuse crate::core::window;\nuse crate::core::{\n    Background, Border, Color, Element, Event, InputMethod, Length, Padding, Pixels, Point,\n    Rectangle, Shell, Size, SmolStr, Theme, Vector,\n};\n\nuse std::borrow::Cow;\nuse std::cell::RefCell;\nuse std::fmt;\nuse std::ops;\nuse std::ops::DerefMut;\nuse std::sync::Arc;\n\npub use text::editor::{Action, Cursor, Edit, Line, LineEnding, Motion, Position, Selection};\n\n/// A multi-line text input.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::text_editor;\n///\n/// struct State {\n///    content: text_editor::Content,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     Edit(text_editor::Action)\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     text_editor(&state.content)\n///         .placeholder(\"Type something here...\")\n///         .on_action(Message::Edit)\n///         .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::Edit(action) => {\n///             state.content.perform(action);\n///         }\n///     }\n/// }\n/// ```\npub struct TextEditor<'a, Highlighter, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Highlighter: text::Highlighter,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    id: Option<widget::Id>,\n    content: &'a Content<Renderer>,\n    placeholder: Option<text::Fragment<'a>>,\n    font: Option<Renderer::Font>,\n    text_size: Option<Pixels>,\n    line_height: LineHeight,\n    width: Length,\n    height: Length,\n    min_height: f32,\n    max_height: f32,\n    padding: Padding,\n    wrapping: Wrapping,\n    class: Theme::Class<'a>,\n    key_binding: Option<Box<dyn Fn(KeyPress) -> Option<Binding<Message>> + 'a>>,\n    on_edit: Option<Box<dyn Fn(Action) -> Message + 'a>>,\n    highlighter_settings: Highlighter::Settings,\n    highlighter_format: fn(&Highlighter::Highlight, &Theme) -> highlighter::Format<Renderer::Font>,\n    last_status: Option<Status>,\n}\n\nimpl<'a, Message, Theme, Renderer> TextEditor<'a, highlighter::PlainText, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// Creates new [`TextEditor`] with the given [`Content`].\n    pub fn new(content: &'a Content<Renderer>) -> Self {\n        Self {\n            id: None,\n            content,\n            placeholder: None,\n            font: None,\n            text_size: None,\n            line_height: LineHeight::default(),\n            width: Length::Fill,\n            height: Length::Shrink,\n            min_height: 0.0,\n            max_height: f32::INFINITY,\n            padding: Padding::new(5.0),\n            wrapping: Wrapping::default(),\n            class: <Theme as Catalog>::default(),\n            key_binding: None,\n            on_edit: None,\n            highlighter_settings: (),\n            highlighter_format: |_highlight, _theme| highlighter::Format::default(),\n            last_status: None,\n        }\n    }\n}\n\nimpl<'a, Highlighter, Message, Theme, Renderer>\n    TextEditor<'a, Highlighter, Message, Theme, Renderer>\nwhere\n    Highlighter: text::Highlighter,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// Sets the [`Id`](widget::Id) of the [`TextEditor`].\n    pub fn id(mut self, id: impl Into<widget::Id>) -> Self {\n        self.id = Some(id.into());\n        self\n    }\n\n    /// Sets the placeholder of the [`TextEditor`].\n    pub fn placeholder(mut self, placeholder: impl text::IntoFragment<'a>) -> Self {\n        self.placeholder = Some(placeholder.into_fragment());\n        self\n    }\n\n    /// Sets the width of the [`TextEditor`].\n    pub fn width(mut self, width: impl Into<Pixels>) -> Self {\n        self.width = Length::from(width.into());\n        self\n    }\n\n    /// Sets the height of the [`TextEditor`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the minimum height of the [`TextEditor`].\n    pub fn min_height(mut self, min_height: impl Into<Pixels>) -> Self {\n        self.min_height = min_height.into().0;\n        self\n    }\n\n    /// Sets the maximum height of the [`TextEditor`].\n    pub fn max_height(mut self, max_height: impl Into<Pixels>) -> Self {\n        self.max_height = max_height.into().0;\n        self\n    }\n\n    /// Sets the message that should be produced when some action is performed in\n    /// the [`TextEditor`].\n    ///\n    /// If this method is not called, the [`TextEditor`] will be disabled.\n    pub fn on_action(mut self, on_edit: impl Fn(Action) -> Message + 'a) -> Self {\n        self.on_edit = Some(Box::new(on_edit));\n        self\n    }\n\n    /// Sets the [`Font`] of the [`TextEditor`].\n    ///\n    /// [`Font`]: text::Renderer::Font\n    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {\n        self.font = Some(font.into());\n        self\n    }\n\n    /// Sets the text size of the [`TextEditor`].\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        self.text_size = Some(size.into());\n        self\n    }\n\n    /// Sets the [`text::LineHeight`] of the [`TextEditor`].\n    pub fn line_height(mut self, line_height: impl Into<text::LineHeight>) -> Self {\n        self.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`TextEditor`].\n    pub fn padding(mut self, padding: impl Into<Padding>) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the [`Wrapping`] strategy of the [`TextEditor`].\n    pub fn wrapping(mut self, wrapping: Wrapping) -> Self {\n        self.wrapping = wrapping;\n        self\n    }\n\n    /// Highlights the [`TextEditor`] using the given syntax and theme.\n    #[cfg(feature = \"highlighter\")]\n    pub fn highlight(\n        self,\n        syntax: &str,\n        theme: iced_highlighter::Theme,\n    ) -> TextEditor<'a, iced_highlighter::Highlighter, Message, Theme, Renderer>\n    where\n        Renderer: text::Renderer<Font = crate::core::Font>,\n    {\n        self.highlight_with::<iced_highlighter::Highlighter>(\n            iced_highlighter::Settings {\n                theme,\n                token: syntax.to_owned(),\n            },\n            |highlight, _theme| highlight.to_format(),\n        )\n    }\n\n    /// Highlights the [`TextEditor`] with the given [`Highlighter`] and\n    /// a strategy to turn its highlights into some text format.\n    pub fn highlight_with<H: text::Highlighter>(\n        self,\n        settings: H::Settings,\n        to_format: fn(&H::Highlight, &Theme) -> highlighter::Format<Renderer::Font>,\n    ) -> TextEditor<'a, H, Message, Theme, Renderer> {\n        TextEditor {\n            id: self.id,\n            content: self.content,\n            placeholder: self.placeholder,\n            font: self.font,\n            text_size: self.text_size,\n            line_height: self.line_height,\n            width: self.width,\n            height: self.height,\n            min_height: self.min_height,\n            max_height: self.max_height,\n            padding: self.padding,\n            wrapping: self.wrapping,\n            class: self.class,\n            key_binding: self.key_binding,\n            on_edit: self.on_edit,\n            highlighter_settings: settings,\n            highlighter_format: to_format,\n            last_status: self.last_status,\n        }\n    }\n\n    /// Sets the closure to produce key bindings on key presses.\n    ///\n    /// See [`Binding`] for the list of available bindings.\n    pub fn key_binding(\n        mut self,\n        key_binding: impl Fn(KeyPress) -> Option<Binding<Message>> + 'a,\n    ) -> Self {\n        self.key_binding = Some(Box::new(key_binding));\n        self\n    }\n\n    /// Sets the style of the [`TextEditor`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`TextEditor`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n\n    fn input_method<'b>(\n        &self,\n        state: &'b State<Highlighter>,\n        renderer: &Renderer,\n        layout: Layout<'_>,\n    ) -> InputMethod<&'b str> {\n        let Some(Focus {\n            is_window_focused: true,\n            ..\n        }) = &state.focus\n        else {\n            return InputMethod::Disabled;\n        };\n\n        let bounds = layout.bounds();\n        let internal = self.content.0.borrow_mut();\n\n        let text_bounds = bounds.shrink(self.padding);\n        let translation = text_bounds.position() - Point::ORIGIN;\n\n        let cursor = match internal.editor.selection() {\n            Selection::Caret(position) => position,\n            Selection::Range(ranges) => ranges.first().cloned().unwrap_or_default().position(),\n        };\n\n        let line_height = self\n            .line_height\n            .to_absolute(self.text_size.unwrap_or_else(|| renderer.default_size()));\n\n        let position = cursor + translation;\n\n        InputMethod::Enabled {\n            cursor: Rectangle::new(position, Size::new(1.0, f32::from(line_height))),\n            purpose: input_method::Purpose::Normal,\n            preedit: state.preedit.as_ref().map(input_method::Preedit::as_ref),\n        }\n    }\n}\n\n/// The content of a [`TextEditor`].\npub struct Content<R = crate::Renderer>(RefCell<Internal<R>>)\nwhere\n    R: text::Renderer;\n\nstruct Internal<R>\nwhere\n    R: text::Renderer,\n{\n    editor: R::Editor,\n}\n\nimpl<R> Content<R>\nwhere\n    R: text::Renderer,\n{\n    /// Creates an empty [`Content`].\n    pub fn new() -> Self {\n        Self::with_text(\"\")\n    }\n\n    /// Creates a [`Content`] with the given text.\n    pub fn with_text(text: &str) -> Self {\n        Self(RefCell::new(Internal {\n            editor: R::Editor::with_text(text),\n        }))\n    }\n\n    /// Performs an [`Action`] on the [`Content`].\n    pub fn perform(&mut self, action: Action) {\n        let internal = self.0.get_mut();\n\n        internal.editor.perform(action);\n    }\n\n    /// Moves the current cursor to reflect the given one.\n    pub fn move_to(&mut self, cursor: Cursor) {\n        let internal = self.0.get_mut();\n\n        internal.editor.move_to(cursor);\n    }\n\n    /// Returns the current cursor position of the [`Content`].\n    pub fn cursor(&self) -> Cursor {\n        self.0.borrow().editor.cursor()\n    }\n\n    /// Returns the amount of lines of the [`Content`].\n    pub fn line_count(&self) -> usize {\n        self.0.borrow().editor.line_count()\n    }\n\n    /// Returns the text of the line at the given index, if it exists.\n    pub fn line(&self, index: usize) -> Option<Line<'_>> {\n        let internal = self.0.borrow();\n        let line = internal.editor.line(index)?;\n\n        Some(Line {\n            text: Cow::Owned(line.text.into_owned()),\n            ending: line.ending,\n        })\n    }\n\n    /// Returns an iterator of the text of the lines in the [`Content`].\n    pub fn lines(&self) -> impl Iterator<Item = Line<'_>> {\n        (0..)\n            .map(|i| self.line(i))\n            .take_while(Option::is_some)\n            .flatten()\n    }\n\n    /// Returns the text of the [`Content`].\n    pub fn text(&self) -> String {\n        let mut contents = String::new();\n        let mut lines = self.lines().peekable();\n\n        while let Some(line) = lines.next() {\n            contents.push_str(&line.text);\n\n            if lines.peek().is_some() {\n                contents.push_str(if line.ending == LineEnding::None {\n                    LineEnding::default().as_str()\n                } else {\n                    line.ending.as_str()\n                });\n            }\n        }\n\n        contents\n    }\n\n    /// Returns the selected text of the [`Content`].\n    pub fn selection(&self) -> Option<String> {\n        self.0.borrow().editor.copy()\n    }\n\n    /// Returns the kind of [`LineEnding`] used for separating lines in the [`Content`].\n    pub fn line_ending(&self) -> Option<LineEnding> {\n        Some(self.line(0)?.ending)\n    }\n\n    /// Returns whether or not the the [`Content`] is empty.\n    pub fn is_empty(&self) -> bool {\n        self.0.borrow().editor.is_empty()\n    }\n}\n\nimpl<Renderer> Clone for Content<Renderer>\nwhere\n    Renderer: text::Renderer,\n{\n    fn clone(&self) -> Self {\n        Self::with_text(&self.text())\n    }\n}\n\nimpl<Renderer> Default for Content<Renderer>\nwhere\n    Renderer: text::Renderer,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<Renderer> fmt::Debug for Content<Renderer>\nwhere\n    Renderer: text::Renderer,\n    Renderer::Editor: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let internal = self.0.borrow();\n\n        f.debug_struct(\"Content\")\n            .field(\"editor\", &internal.editor)\n            .finish()\n    }\n}\n\n/// The state of a [`TextEditor`].\n#[derive(Debug)]\npub struct State<Highlighter: text::Highlighter> {\n    focus: Option<Focus>,\n    preedit: Option<input_method::Preedit>,\n    last_click: Option<mouse::Click>,\n    drag_click: Option<mouse::click::Kind>,\n    partial_scroll: f32,\n    last_theme: RefCell<Option<String>>,\n    highlighter: RefCell<Highlighter>,\n    highlighter_settings: Highlighter::Settings,\n    highlighter_format_address: usize,\n}\n\n#[derive(Debug, Clone)]\nstruct Focus {\n    updated_at: Instant,\n    now: Instant,\n    is_window_focused: bool,\n}\n\nimpl Focus {\n    const CURSOR_BLINK_INTERVAL_MILLIS: u128 = 500;\n\n    fn now() -> Self {\n        let now = Instant::now();\n\n        Self {\n            updated_at: now,\n            now,\n            is_window_focused: true,\n        }\n    }\n\n    fn is_cursor_visible(&self) -> bool {\n        self.is_window_focused\n            && ((self.now - self.updated_at).as_millis() / Self::CURSOR_BLINK_INTERVAL_MILLIS)\n                .is_multiple_of(2)\n    }\n}\n\nimpl<Highlighter: text::Highlighter> State<Highlighter> {\n    /// Returns whether the [`TextEditor`] is currently focused or not.\n    pub fn is_focused(&self) -> bool {\n        self.focus.is_some()\n    }\n}\n\nimpl<Highlighter: text::Highlighter> operation::Focusable for State<Highlighter> {\n    fn is_focused(&self) -> bool {\n        self.focus.is_some()\n    }\n\n    fn focus(&mut self) {\n        self.focus = Some(Focus::now());\n    }\n\n    fn unfocus(&mut self) {\n        self.focus = None;\n    }\n}\n\nimpl<Highlighter, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for TextEditor<'_, Highlighter, Message, Theme, Renderer>\nwhere\n    Highlighter: text::Highlighter,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn tag(&self) -> widget::tree::Tag {\n        widget::tree::Tag::of::<State<Highlighter>>()\n    }\n\n    fn state(&self) -> widget::tree::State {\n        widget::tree::State::new(State {\n            focus: None,\n            preedit: None,\n            last_click: None,\n            drag_click: None,\n            partial_scroll: 0.0,\n            last_theme: RefCell::default(),\n            highlighter: RefCell::new(Highlighter::new(&self.highlighter_settings)),\n            highlighter_settings: self.highlighter_settings.clone(),\n            highlighter_format_address: self.highlighter_format as usize,\n        })\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut widget::Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> iced_renderer::core::layout::Node {\n        let mut internal = self.content.0.borrow_mut();\n        let state = tree.state.downcast_mut::<State<Highlighter>>();\n\n        if state.highlighter_format_address != self.highlighter_format as usize {\n            state.highlighter.borrow_mut().change_line(0);\n\n            state.highlighter_format_address = self.highlighter_format as usize;\n        }\n\n        if state.highlighter_settings != self.highlighter_settings {\n            state\n                .highlighter\n                .borrow_mut()\n                .update(&self.highlighter_settings);\n\n            state.highlighter_settings = self.highlighter_settings.clone();\n        }\n\n        let limits = limits\n            .width(self.width)\n            .height(self.height)\n            .min_height(self.min_height)\n            .max_height(self.max_height);\n\n        internal.editor.update(\n            limits.shrink(self.padding).max(),\n            self.font.unwrap_or_else(|| renderer.default_font()),\n            self.text_size.unwrap_or_else(|| renderer.default_size()),\n            self.line_height,\n            self.wrapping,\n            renderer.scale_factor(),\n            state.highlighter.borrow_mut().deref_mut(),\n        );\n\n        match self.height {\n            Length::Fill | Length::FillPortion(_) | Length::Fixed(_) => {\n                layout::Node::new(limits.max())\n            }\n            Length::Shrink => {\n                let min_bounds = internal.editor.min_bounds();\n\n                layout::Node::new(\n                    limits\n                        .height(min_bounds.height)\n                        .max()\n                        .expand(Size::new(0.0, self.padding.y())),\n                )\n            }\n        }\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut widget::Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let Some(on_edit) = self.on_edit.as_ref() else {\n            return;\n        };\n\n        let state = tree.state.downcast_mut::<State<Highlighter>>();\n        let is_redraw = matches!(event, Event::Window(window::Event::RedrawRequested(_now)),);\n\n        match event {\n            Event::Window(window::Event::Unfocused) => {\n                if let Some(focus) = &mut state.focus {\n                    focus.is_window_focused = false;\n                }\n            }\n            Event::Window(window::Event::Focused) => {\n                if let Some(focus) = &mut state.focus {\n                    focus.is_window_focused = true;\n                    focus.updated_at = Instant::now();\n\n                    shell.request_redraw();\n                }\n            }\n            Event::Window(window::Event::RedrawRequested(now)) => {\n                if let Some(focus) = &mut state.focus\n                    && focus.is_window_focused\n                {\n                    focus.now = *now;\n\n                    let millis_until_redraw = Focus::CURSOR_BLINK_INTERVAL_MILLIS\n                        - (focus.now - focus.updated_at).as_millis()\n                            % Focus::CURSOR_BLINK_INTERVAL_MILLIS;\n\n                    shell.request_redraw_at(\n                        focus.now + Duration::from_millis(millis_until_redraw as u64),\n                    );\n                }\n            }\n            Event::Clipboard(clipboard::Event::Read(Ok(content))) => {\n                if let clipboard::Content::Text(text) = content.as_ref()\n                    && let Some(focus) = &mut state.focus\n                    && focus.is_window_focused\n                {\n                    shell.publish(on_edit(Action::Edit(Edit::Paste(Arc::new(text.clone())))));\n                }\n            }\n            _ => {}\n        }\n\n        if let Some(update) = Update::from_event(\n            event,\n            state,\n            layout.bounds(),\n            self.padding,\n            cursor,\n            self.key_binding.as_deref(),\n        ) {\n            match update {\n                Update::Click(click) => {\n                    let action = match click.kind() {\n                        mouse::click::Kind::Single => Action::Click(click.position()),\n                        mouse::click::Kind::Double => Action::SelectWord,\n                        mouse::click::Kind::Triple => Action::SelectLine,\n                    };\n\n                    state.focus = Some(Focus::now());\n                    state.last_click = Some(click);\n                    state.drag_click = Some(click.kind());\n\n                    shell.publish(on_edit(action));\n                    shell.capture_event();\n                }\n                Update::Drag(position) => {\n                    shell.publish(on_edit(Action::Drag(position)));\n                }\n                Update::Release => {\n                    state.drag_click = None;\n                }\n                Update::Scroll(lines) => {\n                    let bounds = self.content.0.borrow().editor.bounds();\n\n                    if bounds.height >= i32::MAX as f32 {\n                        return;\n                    }\n\n                    let lines = lines + state.partial_scroll;\n                    state.partial_scroll = lines.fract();\n\n                    shell.publish(on_edit(Action::Scroll {\n                        lines: lines as i32,\n                    }));\n                    shell.capture_event();\n                }\n                Update::InputMethod(update) => match update {\n                    Ime::Toggle(is_open) => {\n                        state.preedit = is_open.then(input_method::Preedit::new);\n\n                        shell.request_redraw();\n                    }\n                    Ime::Preedit { content, selection } => {\n                        state.preedit = Some(input_method::Preedit {\n                            content,\n                            selection,\n                            text_size: self.text_size,\n                        });\n\n                        shell.request_redraw();\n                    }\n                    Ime::Commit(text) => {\n                        shell.publish(on_edit(Action::Edit(Edit::Paste(Arc::new(text)))));\n                    }\n                },\n                Update::Binding(binding) => {\n                    fn apply_binding<H: text::Highlighter, R: text::Renderer, Message>(\n                        binding: Binding<Message>,\n                        content: &Content<R>,\n                        state: &mut State<H>,\n                        on_edit: &dyn Fn(Action) -> Message,\n                        shell: &mut Shell<'_, Message>,\n                    ) {\n                        let mut publish = |action| shell.publish(on_edit(action));\n\n                        match binding {\n                            Binding::Unfocus => {\n                                state.focus = None;\n                                state.drag_click = None;\n                            }\n                            Binding::Copy => {\n                                if let Some(selection) = content.selection() {\n                                    shell.write_clipboard(clipboard::Content::Text(selection));\n                                }\n                            }\n                            Binding::Cut => {\n                                if let Some(selection) = content.selection() {\n                                    shell.write_clipboard(clipboard::Content::Text(selection));\n                                    shell.publish(on_edit(Action::Edit(Edit::Delete)));\n                                }\n                            }\n                            Binding::Paste => {\n                                // TODO: Debounce (?)\n                                shell.read_clipboard(clipboard::Kind::Text);\n                            }\n                            Binding::Move(motion) => {\n                                publish(Action::Move(motion));\n                            }\n                            Binding::Select(motion) => {\n                                publish(Action::Select(motion));\n                            }\n                            Binding::SelectWord => {\n                                publish(Action::SelectWord);\n                            }\n                            Binding::SelectLine => {\n                                publish(Action::SelectLine);\n                            }\n                            Binding::SelectAll => {\n                                publish(Action::SelectAll);\n                            }\n                            Binding::Insert(c) => {\n                                publish(Action::Edit(Edit::Insert(c)));\n                            }\n                            Binding::Enter => {\n                                publish(Action::Edit(Edit::Enter));\n                            }\n                            Binding::Backspace => {\n                                publish(Action::Edit(Edit::Backspace));\n                            }\n                            Binding::Delete => {\n                                publish(Action::Edit(Edit::Delete));\n                            }\n                            Binding::Sequence(sequence) => {\n                                for binding in sequence {\n                                    apply_binding(binding, content, state, on_edit, shell);\n                                }\n                            }\n                            Binding::Custom(message) => {\n                                shell.publish(message);\n                            }\n                        }\n                    }\n\n                    if !matches!(binding, Binding::Unfocus) {\n                        shell.capture_event();\n                    }\n\n                    apply_binding(binding, self.content, state, on_edit, shell);\n\n                    if let Some(focus) = &mut state.focus {\n                        focus.updated_at = Instant::now();\n                    }\n                }\n            }\n        }\n\n        let status = {\n            let is_disabled = self.on_edit.is_none();\n            let is_hovered = cursor.is_over(layout.bounds());\n\n            if is_disabled {\n                Status::Disabled\n            } else if state.focus.is_some() {\n                Status::Focused { is_hovered }\n            } else if is_hovered {\n                Status::Hovered\n            } else {\n                Status::Active\n            }\n        };\n\n        if is_redraw {\n            self.last_status = Some(status);\n\n            shell.request_input_method(&self.input_method(state, renderer, layout));\n        } else if self\n            .last_status\n            .is_some_and(|last_status| status != last_status)\n        {\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &widget::Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _defaults: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        let mut internal = self.content.0.borrow_mut();\n        let state = tree.state.downcast_ref::<State<Highlighter>>();\n\n        let font = self.font.unwrap_or_else(|| renderer.default_font());\n\n        let theme_name = theme.name();\n\n        if state\n            .last_theme\n            .borrow()\n            .as_ref()\n            .is_none_or(|last_theme| last_theme != theme_name)\n        {\n            state.highlighter.borrow_mut().change_line(0);\n            let _ = state.last_theme.borrow_mut().replace(theme_name.to_owned());\n        }\n\n        internal.editor.highlight(\n            font,\n            state.highlighter.borrow_mut().deref_mut(),\n            |highlight| (self.highlighter_format)(highlight, theme),\n        );\n\n        let style = theme.style(&self.class, self.last_status.unwrap_or(Status::Active));\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds,\n                border: style.border,\n                ..renderer::Quad::default()\n            },\n            style.background,\n        );\n\n        let text_bounds = bounds.shrink(self.padding);\n\n        if internal.editor.is_empty() {\n            if let Some(placeholder) = self.placeholder.clone() {\n                renderer.fill_text(\n                    Text {\n                        content: placeholder.into_owned(),\n                        bounds: text_bounds.size(),\n                        size: self.text_size.unwrap_or_else(|| renderer.default_size()),\n                        line_height: self.line_height,\n                        font,\n                        align_x: text::Alignment::Default,\n                        align_y: alignment::Vertical::Top,\n                        shaping: text::Shaping::Advanced,\n                        wrapping: self.wrapping,\n                        ellipsis: text::Ellipsis::None,\n                        hint_factor: renderer.scale_factor(),\n                    },\n                    text_bounds.position(),\n                    style.placeholder,\n                    text_bounds,\n                );\n            }\n        } else {\n            renderer.fill_editor(\n                &internal.editor,\n                text_bounds.position(),\n                style.value,\n                text_bounds,\n            );\n        }\n\n        let translation = text_bounds.position() - Point::ORIGIN;\n\n        if let Some(focus) = state.focus.as_ref() {\n            match internal.editor.selection() {\n                Selection::Caret(position) if focus.is_cursor_visible() => {\n                    let cursor = Rectangle::new(\n                        position + translation,\n                        Size::new(\n                            if renderer::CRISP {\n                                (1.0 / renderer.scale_factor().unwrap_or(1.0)).max(1.0)\n                            } else {\n                                1.0\n                            },\n                            self.line_height\n                                .to_absolute(\n                                    self.text_size.unwrap_or_else(|| renderer.default_size()),\n                                )\n                                .into(),\n                        ),\n                    );\n\n                    if let Some(clipped_cursor) = text_bounds.intersection(&cursor) {\n                        renderer.fill_quad(\n                            renderer::Quad {\n                                bounds: clipped_cursor,\n                                ..renderer::Quad::default()\n                            },\n                            style.value,\n                        );\n                    }\n                }\n                Selection::Range(ranges) => {\n                    for range in ranges\n                        .into_iter()\n                        .filter_map(|range| text_bounds.intersection(&(range + translation)))\n                    {\n                        renderer.fill_quad(\n                            renderer::Quad {\n                                bounds: range,\n                                ..renderer::Quad::default()\n                            },\n                            style.selection,\n                        );\n                    }\n                }\n                Selection::Caret(_) => {\n                    // Drawing an empty quad helps some renderers to track the damage of the blinking cursor\n                    renderer.fill_quad(renderer::Quad::default(), Color::TRANSPARENT);\n                }\n            }\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &widget::Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let is_disabled = self.on_edit.is_none();\n\n        if cursor.is_over(layout.bounds()) {\n            if is_disabled {\n                mouse::Interaction::NotAllowed\n            } else {\n                mouse::Interaction::Text\n            }\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut widget::Tree,\n        layout: Layout<'_>,\n        _renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        let state = tree.state.downcast_mut::<State<Highlighter>>();\n\n        operation.focusable(self.id.as_ref(), layout.bounds(), state);\n    }\n}\n\nimpl<'a, Highlighter, Message, Theme, Renderer>\n    From<TextEditor<'a, Highlighter, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Highlighter: text::Highlighter,\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer,\n{\n    fn from(text_editor: TextEditor<'a, Highlighter, Message, Theme, Renderer>) -> Self {\n        Self::new(text_editor)\n    }\n}\n\n/// A binding to an action in the [`TextEditor`].\n#[derive(Debug, Clone, PartialEq)]\npub enum Binding<Message> {\n    /// Unfocus the [`TextEditor`].\n    Unfocus,\n    /// Copy the selection of the [`TextEditor`].\n    Copy,\n    /// Cut the selection of the [`TextEditor`].\n    Cut,\n    /// Paste the clipboard contents in the [`TextEditor`].\n    Paste,\n    /// Apply a [`Motion`].\n    Move(Motion),\n    /// Select text with a given [`Motion`].\n    Select(Motion),\n    /// Select the word at the current cursor.\n    SelectWord,\n    /// Select the line at the current cursor.\n    SelectLine,\n    /// Select the entire buffer.\n    SelectAll,\n    /// Insert the given character.\n    Insert(char),\n    /// Break the current line.\n    Enter,\n    /// Delete the previous character.\n    Backspace,\n    /// Delete the next character.\n    Delete,\n    /// A sequence of bindings to execute.\n    Sequence(Vec<Self>),\n    /// Produce the given message.\n    Custom(Message),\n}\n\n/// A key press.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct KeyPress {\n    /// The original key pressed without modifiers applied to it.\n    ///\n    /// You should use this key for combinations (e.g. Ctrl+C).\n    pub key: keyboard::Key,\n    /// The key pressed with modifiers applied to it.\n    ///\n    /// You should use this key for any single key bindings (e.g. motions).\n    pub modified_key: keyboard::Key,\n    /// The physical key pressed.\n    ///\n    /// You should use this key for layout-independent bindings.\n    pub physical_key: keyboard::key::Physical,\n    /// The state of the keyboard modifiers.\n    pub modifiers: keyboard::Modifiers,\n    /// The text produced by the key press.\n    pub text: Option<SmolStr>,\n    /// The current [`Status`] of the [`TextEditor`].\n    pub status: Status,\n}\n\nimpl<Message> Binding<Message> {\n    /// Returns the default [`Binding`] for the given key press.\n    pub fn from_key_press(event: KeyPress) -> Option<Self> {\n        let KeyPress {\n            key,\n            modified_key,\n            physical_key,\n            modifiers,\n            text,\n            status,\n        } = event;\n\n        if !matches!(status, Status::Focused { .. }) {\n            return None;\n        }\n\n        let combination = match key.to_latin(physical_key) {\n            Some('c') if modifiers.command() => Some(Self::Copy),\n            Some('x') if modifiers.command() => Some(Self::Cut),\n            Some('v') if modifiers.command() && !modifiers.alt() => Some(Self::Paste),\n            Some('a') if modifiers.command() => Some(Self::SelectAll),\n            _ => None,\n        };\n\n        if let Some(binding) = combination {\n            return Some(binding);\n        }\n\n        #[cfg(target_os = \"macos\")]\n        let modified_key = convert_macos_shortcut(&key, modifiers).unwrap_or(modified_key);\n\n        match modified_key.as_ref() {\n            keyboard::Key::Named(key::Named::Enter) => Some(Self::Enter),\n            keyboard::Key::Named(key::Named::Backspace) => Some(Self::Backspace),\n            keyboard::Key::Named(key::Named::Delete)\n                if text.is_none() || text.as_deref() == Some(\"\\u{7f}\") =>\n            {\n                Some(Self::Delete)\n            }\n            keyboard::Key::Named(key::Named::Escape) => Some(Self::Unfocus),\n            _ => {\n                if let Some(text) = text {\n                    let c = text.chars().find(|c| !c.is_control())?;\n\n                    Some(Self::Insert(c))\n                } else if let keyboard::Key::Named(named_key) = key.as_ref() {\n                    let motion = motion(named_key)?;\n\n                    let motion = if modifiers.macos_command() {\n                        match motion {\n                            Motion::Left => Motion::Home,\n                            Motion::Right => Motion::End,\n                            _ => motion,\n                        }\n                    } else {\n                        motion\n                    };\n\n                    let motion = if modifiers.jump() {\n                        motion.widen()\n                    } else {\n                        motion\n                    };\n\n                    Some(if modifiers.shift() {\n                        Self::Select(motion)\n                    } else {\n                        Self::Move(motion)\n                    })\n                } else {\n                    None\n                }\n            }\n        }\n    }\n}\n\nenum Update<Message> {\n    Click(mouse::Click),\n    Drag(Point),\n    Release,\n    Scroll(f32),\n    InputMethod(Ime),\n    Binding(Binding<Message>),\n}\n\nenum Ime {\n    Toggle(bool),\n    Preedit {\n        content: String,\n        selection: Option<ops::Range<usize>>,\n    },\n    Commit(String),\n}\n\nimpl<Message> Update<Message> {\n    fn from_event<H: Highlighter>(\n        event: &Event,\n        state: &State<H>,\n        bounds: Rectangle,\n        padding: Padding,\n        cursor: mouse::Cursor,\n        key_binding: Option<&dyn Fn(KeyPress) -> Option<Binding<Message>>>,\n    ) -> Option<Self> {\n        let binding = |binding| Some(Update::Binding(binding));\n\n        match event {\n            Event::Mouse(event) => match event {\n                mouse::Event::ButtonPressed(mouse::Button::Left) => {\n                    if let Some(cursor_position) = cursor.position_in(bounds) {\n                        let cursor_position =\n                            cursor_position - Vector::new(padding.left, padding.top);\n\n                        let click = mouse::Click::new(\n                            cursor_position,\n                            mouse::Button::Left,\n                            state.last_click,\n                        );\n\n                        Some(Update::Click(click))\n                    } else if state.focus.is_some() {\n                        binding(Binding::Unfocus)\n                    } else {\n                        None\n                    }\n                }\n                mouse::Event::ButtonReleased(mouse::Button::Left) => Some(Update::Release),\n                mouse::Event::CursorMoved { .. } => match state.drag_click {\n                    Some(mouse::click::Kind::Single) => {\n                        let cursor_position =\n                            cursor.position_in(bounds)? - Vector::new(padding.left, padding.top);\n\n                        Some(Update::Drag(cursor_position))\n                    }\n                    _ => None,\n                },\n                mouse::Event::WheelScrolled { delta } if cursor.is_over(bounds) => {\n                    Some(Update::Scroll(match delta {\n                        mouse::ScrollDelta::Lines { y, .. } => {\n                            if y.abs() > 0.0 {\n                                y.signum() * -(y.abs() * 4.0).max(1.0)\n                            } else {\n                                0.0\n                            }\n                        }\n                        mouse::ScrollDelta::Pixels { y, .. } => -y / 4.0,\n                    }))\n                }\n                _ => None,\n            },\n            Event::InputMethod(event) => match event {\n                input_method::Event::Opened | input_method::Event::Closed => Some(\n                    Update::InputMethod(Ime::Toggle(matches!(event, input_method::Event::Opened))),\n                ),\n                input_method::Event::Preedit(content, selection) if state.focus.is_some() => {\n                    Some(Update::InputMethod(Ime::Preedit {\n                        content: content.clone(),\n                        selection: selection.clone(),\n                    }))\n                }\n                input_method::Event::Commit(content) if state.focus.is_some() => {\n                    Some(Update::InputMethod(Ime::Commit(content.clone())))\n                }\n                _ => None,\n            },\n            Event::Keyboard(keyboard::Event::KeyPressed {\n                key,\n                modified_key,\n                physical_key,\n                modifiers,\n                text,\n                ..\n            }) => {\n                let status = if state.focus.is_some() {\n                    Status::Focused {\n                        is_hovered: cursor.is_over(bounds),\n                    }\n                } else {\n                    Status::Active\n                };\n\n                let key_press = KeyPress {\n                    key: key.clone(),\n                    modified_key: modified_key.clone(),\n                    physical_key: *physical_key,\n                    modifiers: *modifiers,\n                    text: text.clone(),\n                    status,\n                };\n\n                if let Some(key_binding) = key_binding {\n                    key_binding(key_press)\n                } else {\n                    Binding::from_key_press(key_press)\n                }\n                .map(Self::Binding)\n            }\n            _ => None,\n        }\n    }\n}\n\nfn motion(key: key::Named) -> Option<Motion> {\n    match key {\n        key::Named::ArrowLeft => Some(Motion::Left),\n        key::Named::ArrowRight => Some(Motion::Right),\n        key::Named::ArrowUp => Some(Motion::Up),\n        key::Named::ArrowDown => Some(Motion::Down),\n        key::Named::Home => Some(Motion::Home),\n        key::Named::End => Some(Motion::End),\n        key::Named::PageUp => Some(Motion::PageUp),\n        key::Named::PageDown => Some(Motion::PageDown),\n        _ => None,\n    }\n}\n\n/// The possible status of a [`TextEditor`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`TextEditor`] can be interacted with.\n    Active,\n    /// The [`TextEditor`] is being hovered.\n    Hovered,\n    /// The [`TextEditor`] is focused.\n    Focused {\n        /// Whether the [`TextEditor`] is hovered, while focused.\n        is_hovered: bool,\n    },\n    /// The [`TextEditor`] cannot be interacted with.\n    Disabled,\n}\n\n/// The appearance of a text input.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`Background`] of the text input.\n    pub background: Background,\n    /// The [`Border`] of the text input.\n    pub border: Border,\n    /// The [`Color`] of the placeholder of the text input.\n    pub placeholder: Color,\n    /// The [`Color`] of the value of the text input.\n    pub value: Color,\n    /// The [`Color`] of the selection of the text input.\n    pub selection: Color,\n}\n\n/// The theme catalog of a [`TextEditor`].\npub trait Catalog: theme::Base {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`TextEditor`].\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// The default style of a [`TextEditor`].\npub fn default(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    let active = Style {\n        background: Background::Color(palette.background.base.color),\n        border: Border {\n            radius: 2.0.into(),\n            width: 1.0,\n            color: palette.background.strong.color,\n        },\n        placeholder: palette.secondary.base.color,\n        value: palette.background.base.text,\n        selection: palette.primary.weak.color,\n    };\n\n    match status {\n        Status::Active => active,\n        Status::Hovered => Style {\n            border: Border {\n                color: palette.background.base.text,\n                ..active.border\n            },\n            ..active\n        },\n        Status::Focused { .. } => Style {\n            border: Border {\n                color: palette.primary.strong.color,\n                ..active.border\n            },\n            ..active\n        },\n        Status::Disabled => Style {\n            background: Background::Color(palette.background.weak.color),\n            value: active.placeholder,\n            placeholder: palette.background.strongest.color,\n            ..active\n        },\n    }\n}\n\n#[cfg(target_os = \"macos\")]\npub(crate) fn convert_macos_shortcut(\n    key: &keyboard::Key,\n    modifiers: keyboard::Modifiers,\n) -> Option<keyboard::Key> {\n    if modifiers != keyboard::Modifiers::CTRL {\n        return None;\n    }\n\n    let key = match key.as_ref() {\n        keyboard::Key::Character(\"b\") => key::Named::ArrowLeft,\n        keyboard::Key::Character(\"f\") => key::Named::ArrowRight,\n        keyboard::Key::Character(\"a\") => key::Named::Home,\n        keyboard::Key::Character(\"e\") => key::Named::End,\n        keyboard::Key::Character(\"h\") => key::Named::Backspace,\n        keyboard::Key::Character(\"d\") => key::Named::Delete,\n        _ => return None,\n    };\n\n    Some(keyboard::Key::Named(key))\n}\n"
  },
  {
    "path": "widget/src/text_input/cursor.rs",
    "content": "//! Track the cursor of a text input.\nuse crate::text_input::Value;\n\n/// The cursor of a text input.\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub struct Cursor {\n    state: State,\n}\n\n/// The state of a [`Cursor`].\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub enum State {\n    /// Cursor without a selection\n    Index(usize),\n\n    /// Cursor selecting a range of text\n    Selection {\n        /// The start of the selection\n        start: usize,\n        /// The end of the selection\n        end: usize,\n    },\n}\n\nimpl Default for Cursor {\n    fn default() -> Self {\n        Cursor {\n            state: State::Index(0),\n        }\n    }\n}\n\nimpl Cursor {\n    /// Returns the [`State`] of the [`Cursor`].\n    pub fn state(&self, value: &Value) -> State {\n        match self.state {\n            State::Index(index) => State::Index(index.min(value.len())),\n            State::Selection { start, end } => {\n                let start = start.min(value.len());\n                let end = end.min(value.len());\n\n                if start == end {\n                    State::Index(start)\n                } else {\n                    State::Selection { start, end }\n                }\n            }\n        }\n    }\n\n    /// Returns the current selection of the [`Cursor`] for the given [`Value`].\n    ///\n    /// `start` is guaranteed to be <= than `end`.\n    pub fn selection(&self, value: &Value) -> Option<(usize, usize)> {\n        match self.state(value) {\n            State::Selection { start, end } => Some((start.min(end), start.max(end))),\n            State::Index(_) => None,\n        }\n    }\n\n    pub(crate) fn move_to(&mut self, position: usize) {\n        self.state = State::Index(position);\n    }\n\n    pub(crate) fn move_right(&mut self, value: &Value) {\n        self.move_right_by_amount(value, 1);\n    }\n\n    pub(crate) fn move_right_by_words(&mut self, value: &Value) {\n        self.move_to(value.next_end_of_word(self.right(value)));\n    }\n\n    pub(crate) fn move_right_by_amount(&mut self, value: &Value, amount: usize) {\n        match self.state(value) {\n            State::Index(index) => {\n                self.move_to(index.saturating_add(amount).min(value.len()));\n            }\n            State::Selection { start, end } => self.move_to(end.max(start)),\n        }\n    }\n\n    pub(crate) fn move_left(&mut self, value: &Value) {\n        match self.state(value) {\n            State::Index(index) if index > 0 => self.move_to(index - 1),\n            State::Selection { start, end } => self.move_to(start.min(end)),\n            State::Index(_) => self.move_to(0),\n        }\n    }\n\n    pub(crate) fn move_left_by_words(&mut self, value: &Value) {\n        self.move_to(value.previous_start_of_word(self.left(value)));\n    }\n\n    pub(crate) fn select_range(&mut self, start: usize, end: usize) {\n        if start == end {\n            self.state = State::Index(start);\n        } else {\n            self.state = State::Selection { start, end };\n        }\n    }\n\n    pub(crate) fn select_left(&mut self, value: &Value) {\n        match self.state(value) {\n            State::Index(index) if index > 0 => {\n                self.select_range(index, index - 1);\n            }\n            State::Selection { start, end } if end > 0 => {\n                self.select_range(start, end - 1);\n            }\n            _ => {}\n        }\n    }\n\n    pub(crate) fn select_right(&mut self, value: &Value) {\n        match self.state(value) {\n            State::Index(index) if index < value.len() => {\n                self.select_range(index, index + 1);\n            }\n            State::Selection { start, end } if end < value.len() => {\n                self.select_range(start, end + 1);\n            }\n            _ => {}\n        }\n    }\n\n    pub(crate) fn select_left_by_words(&mut self, value: &Value) {\n        match self.state(value) {\n            State::Index(index) => {\n                self.select_range(index, value.previous_start_of_word(index));\n            }\n            State::Selection { start, end } => {\n                self.select_range(start, value.previous_start_of_word(end));\n            }\n        }\n    }\n\n    pub(crate) fn select_right_by_words(&mut self, value: &Value) {\n        match self.state(value) {\n            State::Index(index) => {\n                self.select_range(index, value.next_end_of_word(index));\n            }\n            State::Selection { start, end } => {\n                self.select_range(start, value.next_end_of_word(end));\n            }\n        }\n    }\n\n    pub(crate) fn select_all(&mut self, value: &Value) {\n        self.select_range(0, value.len());\n    }\n\n    pub(crate) fn start(&self, value: &Value) -> usize {\n        let start = match self.state {\n            State::Index(index) => index,\n            State::Selection { start, .. } => start,\n        };\n\n        start.min(value.len())\n    }\n\n    pub(crate) fn end(&self, value: &Value) -> usize {\n        let end = match self.state {\n            State::Index(index) => index,\n            State::Selection { end, .. } => end,\n        };\n\n        end.min(value.len())\n    }\n\n    fn left(&self, value: &Value) -> usize {\n        match self.state(value) {\n            State::Index(index) => index,\n            State::Selection { start, end } => start.min(end),\n        }\n    }\n\n    fn right(&self, value: &Value) -> usize {\n        match self.state(value) {\n            State::Index(index) => index,\n            State::Selection { start, end } => start.max(end),\n        }\n    }\n}\n"
  },
  {
    "path": "widget/src/text_input/editor.rs",
    "content": "use crate::text_input::{Cursor, Value};\n\npub struct Editor<'a> {\n    value: &'a mut Value,\n    cursor: &'a mut Cursor,\n}\n\nimpl<'a> Editor<'a> {\n    pub fn new(value: &'a mut Value, cursor: &'a mut Cursor) -> Editor<'a> {\n        Editor { value, cursor }\n    }\n\n    pub fn contents(&self) -> String {\n        self.value.to_string()\n    }\n\n    pub fn insert(&mut self, character: char) {\n        if let Some((left, right)) = self.cursor.selection(self.value) {\n            self.cursor.move_left(self.value);\n            self.value.remove_many(left, right);\n        }\n\n        self.value.insert(self.cursor.end(self.value), character);\n        self.cursor.move_right(self.value);\n    }\n\n    pub fn paste(&mut self, content: Value) {\n        let length = content.len();\n        if let Some((left, right)) = self.cursor.selection(self.value) {\n            self.cursor.move_left(self.value);\n            self.value.remove_many(left, right);\n        }\n\n        self.value.insert_many(self.cursor.end(self.value), content);\n\n        self.cursor.move_right_by_amount(self.value, length);\n    }\n\n    pub fn backspace(&mut self) {\n        match self.cursor.selection(self.value) {\n            Some((start, end)) => {\n                self.cursor.move_left(self.value);\n                self.value.remove_many(start, end);\n            }\n            None => {\n                let start = self.cursor.start(self.value);\n\n                if start > 0 {\n                    self.cursor.move_left(self.value);\n                    self.value.remove(start - 1);\n                }\n            }\n        }\n    }\n\n    pub fn delete(&mut self) {\n        match self.cursor.selection(self.value) {\n            Some(_) => {\n                self.backspace();\n            }\n            None => {\n                let end = self.cursor.end(self.value);\n\n                if end < self.value.len() {\n                    self.value.remove(end);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "widget/src/text_input/value.rs",
    "content": "use unicode_segmentation::UnicodeSegmentation;\n\n/// The value of a [`TextInput`].\n///\n/// [`TextInput`]: super::TextInput\n// TODO: Reduce allocations, cache results (?)\n#[derive(Debug, Clone)]\npub struct Value {\n    graphemes: Vec<String>,\n}\n\nimpl Value {\n    /// Creates a new [`Value`] from a string slice.\n    pub fn new(string: &str) -> Self {\n        let graphemes = UnicodeSegmentation::graphemes(string, true)\n            .map(String::from)\n            .collect();\n\n        Self { graphemes }\n    }\n\n    /// Returns whether the [`Value`] is empty or not.\n    ///\n    /// A [`Value`] is empty when it contains no graphemes.\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    /// Returns the total amount of graphemes in the [`Value`].\n    pub fn len(&self) -> usize {\n        self.graphemes.len()\n    }\n\n    /// Returns the position of the previous start of a word from the given\n    /// grapheme `index`.\n    pub fn previous_start_of_word(&self, index: usize) -> usize {\n        let previous_string = &self.graphemes[..index.min(self.graphemes.len())].concat();\n\n        UnicodeSegmentation::split_word_bound_indices(previous_string as &str)\n            .rfind(|(_, word)| !word.trim_start().is_empty())\n            .map(|(i, previous_word)| {\n                index\n                    - UnicodeSegmentation::graphemes(previous_word, true).count()\n                    - UnicodeSegmentation::graphemes(\n                        &previous_string[i + previous_word.len()..] as &str,\n                        true,\n                    )\n                    .count()\n            })\n            .unwrap_or(0)\n    }\n\n    /// Returns the position of the next end of a word from the given grapheme\n    /// `index`.\n    pub fn next_end_of_word(&self, index: usize) -> usize {\n        let next_string = &self.graphemes[index.min(self.graphemes.len())..].concat();\n\n        UnicodeSegmentation::split_word_bound_indices(next_string as &str)\n            .find(|(_, word)| !word.trim_start().is_empty())\n            .map(|(i, next_word)| {\n                index\n                    + UnicodeSegmentation::graphemes(next_word, true).count()\n                    + UnicodeSegmentation::graphemes(&next_string[..i] as &str, true).count()\n            })\n            .unwrap_or(self.len())\n    }\n\n    /// Returns a new [`Value`] containing the graphemes from `start` until the\n    /// given `end`.\n    pub fn select(&self, start: usize, end: usize) -> Self {\n        let graphemes = self.graphemes[start.min(self.len())..end.min(self.len())].to_vec();\n\n        Self { graphemes }\n    }\n\n    /// Returns a new [`Value`] containing the graphemes until the given\n    /// `index`.\n    pub fn until(&self, index: usize) -> Self {\n        let graphemes = self.graphemes[..index.min(self.len())].to_vec();\n\n        Self { graphemes }\n    }\n\n    /// Inserts a new `char` at the given grapheme `index`.\n    pub fn insert(&mut self, index: usize, c: char) {\n        self.graphemes.insert(index, c.to_string());\n\n        self.graphemes = UnicodeSegmentation::graphemes(&self.to_string() as &str, true)\n            .map(String::from)\n            .collect();\n    }\n\n    /// Inserts a bunch of graphemes at the given grapheme `index`.\n    pub fn insert_many(&mut self, index: usize, mut value: Value) {\n        let _ = self\n            .graphemes\n            .splice(index..index, value.graphemes.drain(..));\n    }\n\n    /// Removes the grapheme at the given `index`.\n    pub fn remove(&mut self, index: usize) {\n        let _ = self.graphemes.remove(index);\n    }\n\n    /// Removes the graphemes from `start` to `end`.\n    pub fn remove_many(&mut self, start: usize, end: usize) {\n        let _ = self.graphemes.splice(start..end, std::iter::empty());\n    }\n\n    /// Returns a new [`Value`] with all its graphemes replaced with the\n    /// dot ('•') character.\n    pub fn secure(&self) -> Self {\n        Self {\n            graphemes: std::iter::repeat_n(String::from(\"•\"), self.graphemes.len()).collect(),\n        }\n    }\n}\n\nimpl std::fmt::Display for Value {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_str(&self.graphemes.concat())\n    }\n}\n"
  },
  {
    "path": "widget/src/text_input.rs",
    "content": "//! Text inputs display fields that can be filled with text.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::text_input;\n//!\n//! struct State {\n//!    content: String,\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     ContentChanged(String)\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     text_input(\"Type something here...\", &state.content)\n//!         .on_input(Message::ContentChanged)\n//!         .into()\n//! }\n//!\n//! fn update(state: &mut State, message: Message) {\n//!     match message {\n//!         Message::ContentChanged(content) => {\n//!             state.content = content;\n//!         }\n//!     }\n//! }\n//! ```\nmod editor;\nmod value;\n\npub mod cursor;\n\npub use cursor::Cursor;\npub use value::Value;\n\nuse editor::Editor;\n\nuse crate::core::alignment;\nuse crate::core::clipboard;\nuse crate::core::input_method;\nuse crate::core::keyboard;\nuse crate::core::keyboard::key;\nuse crate::core::layout;\nuse crate::core::mouse::{self, click};\nuse crate::core::renderer;\nuse crate::core::text::paragraph::{self, Paragraph as _};\nuse crate::core::text::{self, Text};\nuse crate::core::time::{Duration, Instant};\nuse crate::core::touch;\nuse crate::core::widget;\nuse crate::core::widget::operation::{self, Operation};\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    Alignment, Background, Border, Color, Element, Event, InputMethod, Layout, Length, Padding,\n    Pixels, Point, Rectangle, Shell, Size, Theme, Vector, Widget,\n};\n\n/// A field that can be filled with text.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::text_input;\n///\n/// struct State {\n///    content: String,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     ContentChanged(String)\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     text_input(\"Type something here...\", &state.content)\n///         .on_input(Message::ContentChanged)\n///         .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::ContentChanged(content) => {\n///             state.content = content;\n///         }\n///     }\n/// }\n/// ```\npub struct TextInput<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    id: Option<widget::Id>,\n    placeholder: String,\n    value: Value,\n    is_secure: bool,\n    font: Option<Renderer::Font>,\n    width: Length,\n    padding: Padding,\n    size: Option<Pixels>,\n    line_height: text::LineHeight,\n    alignment: alignment::Horizontal,\n    on_input: Option<Box<dyn Fn(String) -> Message + 'a>>,\n    on_paste: Option<Box<dyn Fn(String) -> Message + 'a>>,\n    on_submit: Option<Message>,\n    icon: Option<Icon<Renderer::Font>>,\n    class: Theme::Class<'a>,\n    last_status: Option<Status>,\n}\n\n/// The default [`Padding`] of a [`TextInput`].\npub const DEFAULT_PADDING: Padding = Padding::new(5.0);\n\nimpl<'a, Message, Theme, Renderer> TextInput<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// Creates a new [`TextInput`] with the given placeholder and\n    /// its current value.\n    pub fn new(placeholder: &str, value: &str) -> Self {\n        TextInput {\n            id: None,\n            placeholder: String::from(placeholder),\n            value: Value::new(value),\n            is_secure: false,\n            font: None,\n            width: Length::Fill,\n            padding: DEFAULT_PADDING,\n            size: None,\n            line_height: text::LineHeight::default(),\n            alignment: alignment::Horizontal::Left,\n            on_input: None,\n            on_paste: None,\n            on_submit: None,\n            icon: None,\n            class: Theme::default(),\n            last_status: None,\n        }\n    }\n\n    /// Sets the [`widget::Id`] of the [`TextInput`].\n    pub fn id(mut self, id: impl Into<widget::Id>) -> Self {\n        self.id = Some(id.into());\n        self\n    }\n\n    /// Converts the [`TextInput`] into a secure password input.\n    pub fn secure(mut self, is_secure: bool) -> Self {\n        self.is_secure = is_secure;\n        self\n    }\n\n    /// Sets the message that should be produced when some text is typed into\n    /// the [`TextInput`].\n    ///\n    /// If this method is not called, the [`TextInput`] will be disabled.\n    pub fn on_input(mut self, on_input: impl Fn(String) -> Message + 'a) -> Self {\n        self.on_input = Some(Box::new(on_input));\n        self\n    }\n\n    /// Sets the message that should be produced when some text is typed into\n    /// the [`TextInput`], if `Some`.\n    ///\n    /// If `None`, the [`TextInput`] will be disabled.\n    pub fn on_input_maybe(mut self, on_input: Option<impl Fn(String) -> Message + 'a>) -> Self {\n        self.on_input = on_input.map(|f| Box::new(f) as _);\n        self\n    }\n\n    /// Sets the message that should be produced when the [`TextInput`] is\n    /// focused and the enter key is pressed.\n    pub fn on_submit(mut self, message: Message) -> Self {\n        self.on_submit = Some(message);\n        self\n    }\n\n    /// Sets the message that should be produced when the [`TextInput`] is\n    /// focused and the enter key is pressed, if `Some`.\n    pub fn on_submit_maybe(mut self, on_submit: Option<Message>) -> Self {\n        self.on_submit = on_submit;\n        self\n    }\n\n    /// Sets the message that should be produced when some text is pasted into\n    /// the [`TextInput`].\n    pub fn on_paste(mut self, on_paste: impl Fn(String) -> Message + 'a) -> Self {\n        self.on_paste = Some(Box::new(on_paste));\n        self\n    }\n\n    /// Sets the message that should be produced when some text is pasted into\n    /// the [`TextInput`], if `Some`.\n    pub fn on_paste_maybe(mut self, on_paste: Option<impl Fn(String) -> Message + 'a>) -> Self {\n        self.on_paste = on_paste.map(|f| Box::new(f) as _);\n        self\n    }\n\n    /// Sets the [`Font`] of the [`TextInput`].\n    ///\n    /// [`Font`]: text::Renderer::Font\n    pub fn font(mut self, font: Renderer::Font) -> Self {\n        self.font = Some(font);\n        self\n    }\n\n    /// Sets the [`Icon`] of the [`TextInput`].\n    pub fn icon(mut self, icon: Icon<Renderer::Font>) -> Self {\n        self.icon = Some(icon);\n        self\n    }\n\n    /// Sets the width of the [`TextInput`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the [`Padding`] of the [`TextInput`].\n    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {\n        self.padding = padding.into();\n        self\n    }\n\n    /// Sets the text size of the [`TextInput`].\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        self.size = Some(size.into());\n        self\n    }\n\n    /// Sets the [`text::LineHeight`] of the [`TextInput`].\n    pub fn line_height(mut self, line_height: impl Into<text::LineHeight>) -> Self {\n        self.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the horizontal alignment of the [`TextInput`].\n    pub fn align_x(mut self, alignment: impl Into<alignment::Horizontal>) -> Self {\n        self.alignment = alignment.into();\n        self\n    }\n\n    /// Sets the style of the [`TextInput`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`TextInput`].\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n\n    /// Lays out the [`TextInput`], overriding its [`Value`] if provided.\n    ///\n    /// [`Renderer`]: text::Renderer\n    pub fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n        value: Option<&Value>,\n    ) -> layout::Node {\n        let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();\n        let value = value.unwrap_or(&self.value);\n\n        let font = self.font.unwrap_or_else(|| renderer.default_font());\n        let text_size = self.size.unwrap_or_else(|| renderer.default_size());\n        let padding = self.padding.fit(Size::ZERO, limits.max());\n        let height = self.line_height.to_absolute(text_size);\n\n        let limits = limits.width(self.width).shrink(padding);\n        let text_bounds = limits.resolve(self.width, height, Size::ZERO);\n\n        let placeholder_text = Text {\n            font,\n            line_height: self.line_height,\n            content: self.placeholder.as_str(),\n            bounds: Size::new(f32::INFINITY, text_bounds.height),\n            size: text_size,\n            align_x: text::Alignment::Default,\n            align_y: alignment::Vertical::Center,\n            shaping: text::Shaping::Advanced,\n            wrapping: text::Wrapping::None,\n            ellipsis: text::Ellipsis::None,\n            hint_factor: renderer.scale_factor(),\n        };\n\n        let _ = state.placeholder.update(placeholder_text);\n\n        let secure_value = self.is_secure.then(|| value.secure());\n        let value = secure_value.as_ref().unwrap_or(value);\n\n        let _ = state.value.update(Text {\n            content: &value.to_string(),\n            ..placeholder_text\n        });\n\n        if let Some(icon) = &self.icon {\n            let mut content = [0; 4];\n\n            let icon_text = Text {\n                line_height: self.line_height,\n                content: icon.code_point.encode_utf8(&mut content) as &_,\n                font: icon.font,\n                size: icon.size.unwrap_or_else(|| renderer.default_size()),\n                bounds: Size::new(f32::INFINITY, text_bounds.height),\n                align_x: text::Alignment::Center,\n                align_y: alignment::Vertical::Center,\n                shaping: text::Shaping::Advanced,\n                wrapping: text::Wrapping::None,\n                ellipsis: text::Ellipsis::None,\n                hint_factor: renderer.scale_factor(),\n            };\n\n            let _ = state.icon.update(icon_text);\n\n            let icon_width = state.icon.min_width();\n\n            let (text_position, icon_position) = match icon.side {\n                Side::Left => (\n                    Point::new(padding.left + icon_width + icon.spacing, padding.top),\n                    Point::new(padding.left, padding.top),\n                ),\n                Side::Right => (\n                    Point::new(padding.left, padding.top),\n                    Point::new(padding.left + text_bounds.width - icon_width, padding.top),\n                ),\n            };\n\n            let text_node =\n                layout::Node::new(text_bounds - Size::new(icon_width + icon.spacing, 0.0))\n                    .move_to(text_position);\n\n            let icon_node =\n                layout::Node::new(Size::new(icon_width, text_bounds.height)).move_to(icon_position);\n\n            layout::Node::with_children(text_bounds.expand(padding), vec![text_node, icon_node])\n        } else {\n            let text =\n                layout::Node::new(text_bounds).move_to(Point::new(padding.left, padding.top));\n\n            layout::Node::with_children(text_bounds.expand(padding), vec![text])\n        }\n    }\n\n    fn input_method<'b>(\n        &self,\n        state: &'b State<Renderer::Paragraph>,\n        layout: Layout<'_>,\n        value: &Value,\n    ) -> InputMethod<&'b str> {\n        let Some(Focus {\n            is_window_focused: true,\n            ..\n        }) = &state.is_focused\n        else {\n            return InputMethod::Disabled;\n        };\n\n        let secure_value = self.is_secure.then(|| value.secure());\n        let value = secure_value.as_ref().unwrap_or(value);\n\n        let text_bounds = layout.children().next().unwrap().bounds();\n\n        let caret_index = match state.cursor.state(value) {\n            cursor::State::Index(position) => position,\n            cursor::State::Selection { start, end } => start.min(end),\n        };\n\n        let text = state.value.raw();\n        let (cursor_x, scroll_offset) =\n            measure_cursor_and_scroll_offset(text, text_bounds, caret_index);\n\n        let alignment_offset =\n            alignment_offset(text_bounds.width, text.min_width(), self.alignment);\n\n        let x = (text_bounds.x + cursor_x).floor() - scroll_offset + alignment_offset;\n\n        InputMethod::Enabled {\n            cursor: Rectangle::new(\n                Point::new(x, text_bounds.y),\n                Size::new(1.0, text_bounds.height),\n            ),\n            purpose: if self.is_secure {\n                input_method::Purpose::Secure\n            } else {\n                input_method::Purpose::Normal\n            },\n            preedit: state.preedit.as_ref().map(input_method::Preedit::as_ref),\n        }\n    }\n\n    /// Draws the [`TextInput`] with the given [`Renderer`], overriding its\n    /// [`Value`] if provided.\n    ///\n    /// [`Renderer`]: text::Renderer\n    pub fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        value: Option<&Value>,\n        viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_ref::<State<Renderer::Paragraph>>();\n        let value = value.unwrap_or(&self.value);\n        let is_disabled = self.on_input.is_none();\n\n        let secure_value = self.is_secure.then(|| value.secure());\n        let value = secure_value.as_ref().unwrap_or(value);\n\n        let bounds = layout.bounds();\n\n        let mut children_layout = layout.children();\n        let text_bounds = children_layout.next().unwrap().bounds();\n\n        let style = theme.style(&self.class, self.last_status.unwrap_or(Status::Disabled));\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds,\n                border: style.border,\n                ..renderer::Quad::default()\n            },\n            style.background,\n        );\n\n        if self.icon.is_some() {\n            let icon_layout = children_layout.next().unwrap();\n\n            let icon = state.icon.raw();\n\n            renderer.fill_paragraph(\n                icon,\n                icon_layout.bounds().anchor(\n                    icon.min_bounds(),\n                    Alignment::Center,\n                    Alignment::Center,\n                ),\n                style.icon,\n                *viewport,\n            );\n        }\n\n        let text = value.to_string();\n\n        let (cursor, offset, is_selecting) = if let Some(focus) = state\n            .is_focused\n            .as_ref()\n            .filter(|focus| focus.is_window_focused)\n        {\n            match state.cursor.state(value) {\n                cursor::State::Index(position) => {\n                    let (text_value_width, offset) =\n                        measure_cursor_and_scroll_offset(state.value.raw(), text_bounds, position);\n\n                    let is_cursor_visible = !is_disabled\n                        && ((focus.now - focus.updated_at).as_millis()\n                            / CURSOR_BLINK_INTERVAL_MILLIS)\n                            .is_multiple_of(2);\n\n                    let cursor = if is_cursor_visible {\n                        Some((\n                            renderer::Quad {\n                                bounds: Rectangle {\n                                    x: text_bounds.x + text_value_width,\n                                    y: text_bounds.y,\n                                    width: if renderer::CRISP {\n                                        (1.0 / renderer.scale_factor().unwrap_or(1.0)).max(1.0)\n                                    } else {\n                                        1.0\n                                    },\n                                    height: text_bounds.height,\n                                },\n                                ..renderer::Quad::default()\n                            },\n                            style.value,\n                        ))\n                    } else {\n                        None\n                    };\n\n                    (cursor, offset, false)\n                }\n                cursor::State::Selection { start, end } => {\n                    let left = start.min(end);\n                    let right = end.max(start);\n\n                    let (left_position, left_offset) =\n                        measure_cursor_and_scroll_offset(state.value.raw(), text_bounds, left);\n\n                    let (right_position, right_offset) =\n                        measure_cursor_and_scroll_offset(state.value.raw(), text_bounds, right);\n\n                    let width = right_position - left_position;\n\n                    (\n                        Some((\n                            renderer::Quad {\n                                bounds: Rectangle {\n                                    x: text_bounds.x + left_position,\n                                    y: text_bounds.y,\n                                    width,\n                                    height: text_bounds.height,\n                                },\n                                ..renderer::Quad::default()\n                            },\n                            style.selection,\n                        )),\n                        if end == right {\n                            right_offset\n                        } else {\n                            left_offset\n                        },\n                        true,\n                    )\n                }\n            }\n        } else {\n            (None, 0.0, false)\n        };\n\n        let draw = |renderer: &mut Renderer, viewport| {\n            let paragraph = if text.is_empty()\n                && state\n                    .preedit\n                    .as_ref()\n                    .map(|preedit| preedit.content.is_empty())\n                    .unwrap_or(true)\n            {\n                state.placeholder.raw()\n            } else {\n                state.value.raw()\n            };\n\n            let alignment_offset =\n                alignment_offset(text_bounds.width, paragraph.min_width(), self.alignment);\n\n            if let Some((cursor, color)) = cursor {\n                renderer.with_translation(\n                    Vector::new(alignment_offset - offset, 0.0),\n                    |renderer| {\n                        renderer.fill_quad(cursor, color);\n                    },\n                );\n            } else {\n                // Drawing an empty quad helps some renderers to track the damage of the blinking cursor\n                renderer.fill_quad(renderer::Quad::default(), Color::TRANSPARENT);\n            }\n\n            renderer.fill_paragraph(\n                paragraph,\n                text_bounds.anchor(paragraph.min_bounds(), Alignment::Start, Alignment::Center)\n                    + Vector::new(alignment_offset - offset, 0.0),\n                if text.is_empty() {\n                    style.placeholder\n                } else {\n                    style.value\n                },\n                viewport,\n            );\n        };\n\n        if is_selecting {\n            renderer.with_layer(text_bounds, |renderer| draw(renderer, *viewport));\n        } else {\n            draw(renderer, text_bounds);\n        }\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for TextInput<'_, Message, Theme, Renderer>\nwhere\n    Message: Clone,\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State<Renderer::Paragraph>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::<Renderer::Paragraph>::new())\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();\n\n        // Stop pasting if input becomes disabled\n        if self.on_input.is_none() {\n            state.is_pasting = None;\n        }\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.layout(tree, renderer, limits, None)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        _renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();\n\n        operation.text_input(self.id.as_ref(), layout.bounds(), state);\n        operation.focusable(self.id.as_ref(), layout.bounds(), state);\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let update_cache = |state, value| {\n            replace_paragraph(\n                renderer,\n                state,\n                layout,\n                value,\n                self.font,\n                self.size,\n                self.line_height,\n            );\n        };\n\n        match &event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                let state = state::<Renderer>(tree);\n                let cursor_before = state.cursor;\n\n                let click_position = cursor.position_over(layout.bounds());\n\n                state.is_focused = if click_position.is_some() {\n                    let now = Instant::now();\n\n                    Some(Focus {\n                        updated_at: now,\n                        now,\n                        is_window_focused: true,\n                    })\n                } else {\n                    None\n                };\n\n                if let Some(cursor_position) = click_position {\n                    let text_layout = layout.children().next().unwrap();\n\n                    let target = {\n                        let text_bounds = text_layout.bounds();\n\n                        let alignment_offset = alignment_offset(\n                            text_bounds.width,\n                            state.value.raw().min_width(),\n                            self.alignment,\n                        );\n\n                        cursor_position.x - text_bounds.x - alignment_offset\n                    };\n\n                    let click =\n                        mouse::Click::new(cursor_position, mouse::Button::Left, state.last_click);\n\n                    match click.kind() {\n                        click::Kind::Single => {\n                            let position = if target > 0.0 {\n                                let value = if self.is_secure {\n                                    self.value.secure()\n                                } else {\n                                    self.value.clone()\n                                };\n\n                                find_cursor_position(text_layout.bounds(), &value, state, target)\n                            } else {\n                                None\n                            }\n                            .unwrap_or(0);\n\n                            if state.keyboard_modifiers.shift() {\n                                state\n                                    .cursor\n                                    .select_range(state.cursor.start(&self.value), position);\n                            } else {\n                                state.cursor.move_to(position);\n                            }\n\n                            state.is_dragging = Some(Drag::Select);\n                        }\n                        click::Kind::Double => {\n                            if self.is_secure {\n                                state.cursor.select_all(&self.value);\n\n                                state.is_dragging = None;\n                            } else {\n                                let position = find_cursor_position(\n                                    text_layout.bounds(),\n                                    &self.value,\n                                    state,\n                                    target,\n                                )\n                                .unwrap_or(0);\n\n                                state.cursor.select_range(\n                                    self.value.previous_start_of_word(position),\n                                    self.value.next_end_of_word(position),\n                                );\n\n                                state.is_dragging = Some(Drag::SelectWords { anchor: position });\n                            }\n                        }\n                        click::Kind::Triple => {\n                            state.cursor.select_all(&self.value);\n                            state.is_dragging = None;\n                        }\n                    }\n\n                    state.last_click = Some(click);\n\n                    if cursor_before != state.cursor {\n                        shell.request_redraw();\n                    }\n\n                    shell.capture_event();\n                }\n            }\n            Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerLifted { .. })\n            | Event::Touch(touch::Event::FingerLost { .. }) => {\n                state::<Renderer>(tree).is_dragging = None;\n            }\n            Event::Mouse(mouse::Event::CursorMoved { position })\n            | Event::Touch(touch::Event::FingerMoved { position, .. }) => {\n                let state = state::<Renderer>(tree);\n\n                if let Some(is_dragging) = &state.is_dragging {\n                    let text_layout = layout.children().next().unwrap();\n\n                    let target = {\n                        let text_bounds = text_layout.bounds();\n\n                        let alignment_offset = alignment_offset(\n                            text_bounds.width,\n                            state.value.raw().min_width(),\n                            self.alignment,\n                        );\n\n                        position.x - text_bounds.x - alignment_offset\n                    };\n\n                    let value = if self.is_secure {\n                        self.value.secure()\n                    } else {\n                        self.value.clone()\n                    };\n\n                    let position =\n                        find_cursor_position(text_layout.bounds(), &value, state, target)\n                            .unwrap_or(0);\n\n                    let selection_before = state.cursor.selection(&value);\n\n                    match is_dragging {\n                        Drag::Select => {\n                            state\n                                .cursor\n                                .select_range(state.cursor.start(&value), position);\n                        }\n                        Drag::SelectWords { anchor } => {\n                            if position < *anchor {\n                                state.cursor.select_range(\n                                    self.value.previous_start_of_word(position),\n                                    self.value.next_end_of_word(*anchor),\n                                );\n                            } else {\n                                state.cursor.select_range(\n                                    self.value.previous_start_of_word(*anchor),\n                                    self.value.next_end_of_word(position),\n                                );\n                            }\n                        }\n                    }\n\n                    if let Some(focus) = &mut state.is_focused {\n                        focus.updated_at = Instant::now();\n                    }\n\n                    if selection_before != state.cursor.selection(&value) {\n                        shell.request_redraw();\n                    }\n\n                    shell.capture_event();\n                }\n            }\n            Event::Keyboard(keyboard::Event::KeyPressed {\n                key,\n                text,\n                modified_key,\n                physical_key,\n                ..\n            }) => {\n                let state = state::<Renderer>(tree);\n\n                if let Some(focus) = &mut state.is_focused {\n                    let modifiers = state.keyboard_modifiers;\n\n                    match key.to_latin(*physical_key) {\n                        Some('c') if state.keyboard_modifiers.command() && !self.is_secure => {\n                            if let Some((start, end)) = state.cursor.selection(&self.value) {\n                                shell.write_clipboard(clipboard::Content::Text(\n                                    self.value.select(start, end).to_string(),\n                                ));\n                            }\n\n                            shell.capture_event();\n                            return;\n                        }\n                        Some('x') if state.keyboard_modifiers.command() && !self.is_secure => {\n                            let Some(on_input) = &self.on_input else {\n                                return;\n                            };\n\n                            if let Some((start, end)) = state.cursor.selection(&self.value) {\n                                shell.write_clipboard(clipboard::Content::Text(\n                                    self.value.select(start, end).to_string(),\n                                ));\n                            }\n\n                            let mut editor = Editor::new(&mut self.value, &mut state.cursor);\n                            editor.delete();\n\n                            let message = (on_input)(editor.contents());\n                            shell.publish(message);\n                            shell.capture_event();\n\n                            focus.updated_at = Instant::now();\n                            update_cache(state, &self.value);\n                            return;\n                        }\n                        Some('v')\n                            if state.keyboard_modifiers.command()\n                                && !state.keyboard_modifiers.alt() =>\n                        {\n                            let Some(on_input) = &self.on_input else {\n                                return;\n                            };\n\n                            let content = match &state.is_pasting {\n                                Some(Paste::Pasting(content)) => content,\n                                Some(Paste::Reading) => return,\n                                None => {\n                                    shell.read_clipboard(clipboard::Kind::Text);\n                                    state.is_pasting = Some(Paste::Reading);\n                                    return;\n                                }\n                            };\n\n                            let mut editor = Editor::new(&mut self.value, &mut state.cursor);\n                            editor.paste(content.clone());\n\n                            let message = if let Some(paste) = &self.on_paste {\n                                (paste)(editor.contents())\n                            } else {\n                                (on_input)(editor.contents())\n                            };\n                            shell.publish(message);\n                            shell.capture_event();\n\n                            focus.updated_at = Instant::now();\n                            update_cache(state, &self.value);\n                            return;\n                        }\n                        Some('a') if state.keyboard_modifiers.command() => {\n                            let cursor_before = state.cursor;\n\n                            state.cursor.select_all(&self.value);\n\n                            if cursor_before != state.cursor {\n                                focus.updated_at = Instant::now();\n\n                                shell.request_redraw();\n                            }\n\n                            shell.capture_event();\n                            return;\n                        }\n                        _ => {}\n                    }\n\n                    if let Some(text) = text {\n                        let Some(on_input) = &self.on_input else {\n                            return;\n                        };\n\n                        state.is_pasting = None;\n\n                        if let Some(c) = text.chars().next().filter(|c| !c.is_control()) {\n                            let mut editor = Editor::new(&mut self.value, &mut state.cursor);\n\n                            editor.insert(c);\n\n                            let message = (on_input)(editor.contents());\n                            shell.publish(message);\n                            shell.capture_event();\n\n                            focus.updated_at = Instant::now();\n                            update_cache(state, &self.value);\n                            return;\n                        }\n                    }\n\n                    #[cfg(target_os = \"macos\")]\n                    let macos_shortcut = crate::text_editor::convert_macos_shortcut(key, modifiers);\n\n                    #[cfg(target_os = \"macos\")]\n                    let modified_key = macos_shortcut.as_ref().unwrap_or(modified_key);\n\n                    match modified_key.as_ref() {\n                        keyboard::Key::Named(key::Named::Enter) => {\n                            if let Some(on_submit) = self.on_submit.clone() {\n                                shell.publish(on_submit);\n                                shell.capture_event();\n                            }\n                        }\n                        keyboard::Key::Named(key::Named::Backspace) => {\n                            let Some(on_input) = &self.on_input else {\n                                return;\n                            };\n\n                            if state.cursor.selection(&self.value).is_none() {\n                                if (self.is_secure && modifiers.jump()) || modifiers.macos_command()\n                                {\n                                    state\n                                        .cursor\n                                        .select_range(state.cursor.start(&self.value), 0);\n                                } else if modifiers.jump() {\n                                    state.cursor.select_left_by_words(&self.value);\n                                }\n                            }\n\n                            let mut editor = Editor::new(&mut self.value, &mut state.cursor);\n                            editor.backspace();\n\n                            let message = (on_input)(editor.contents());\n                            shell.publish(message);\n                            shell.capture_event();\n\n                            focus.updated_at = Instant::now();\n                            update_cache(state, &self.value);\n                        }\n                        keyboard::Key::Named(key::Named::Delete) => {\n                            let Some(on_input) = &self.on_input else {\n                                return;\n                            };\n\n                            if state.cursor.selection(&self.value).is_none() {\n                                if (self.is_secure && modifiers.jump()) || modifiers.macos_command()\n                                {\n                                    state.cursor.select_range(\n                                        state.cursor.start(&self.value),\n                                        self.value.len(),\n                                    );\n                                } else if modifiers.jump() {\n                                    state.cursor.select_right_by_words(&self.value);\n                                }\n                            }\n\n                            let mut editor = Editor::new(&mut self.value, &mut state.cursor);\n                            editor.delete();\n\n                            let message = (on_input)(editor.contents());\n                            shell.publish(message);\n                            shell.capture_event();\n\n                            focus.updated_at = Instant::now();\n                            update_cache(state, &self.value);\n                        }\n                        keyboard::Key::Named(key::Named::Home) => {\n                            let cursor_before = state.cursor;\n\n                            if modifiers.shift() {\n                                state\n                                    .cursor\n                                    .select_range(state.cursor.start(&self.value), 0);\n                            } else {\n                                state.cursor.move_to(0);\n                            }\n\n                            if cursor_before != state.cursor {\n                                focus.updated_at = Instant::now();\n\n                                shell.request_redraw();\n                            }\n\n                            shell.capture_event();\n                        }\n                        keyboard::Key::Named(key::Named::End) => {\n                            let cursor_before = state.cursor;\n\n                            if modifiers.shift() {\n                                state.cursor.select_range(\n                                    state.cursor.start(&self.value),\n                                    self.value.len(),\n                                );\n                            } else {\n                                state.cursor.move_to(self.value.len());\n                            }\n\n                            if cursor_before != state.cursor {\n                                focus.updated_at = Instant::now();\n\n                                shell.request_redraw();\n                            }\n\n                            shell.capture_event();\n                        }\n                        keyboard::Key::Named(key::Named::ArrowLeft) => {\n                            let cursor_before = state.cursor;\n\n                            if (self.is_secure && modifiers.jump()) || modifiers.macos_command() {\n                                if modifiers.shift() {\n                                    state\n                                        .cursor\n                                        .select_range(state.cursor.start(&self.value), 0);\n                                } else {\n                                    state.cursor.move_to(0);\n                                }\n                            } else if modifiers.jump() {\n                                if modifiers.shift() {\n                                    state.cursor.select_left_by_words(&self.value);\n                                } else {\n                                    state.cursor.move_left_by_words(&self.value);\n                                }\n                            } else if modifiers.shift() {\n                                state.cursor.select_left(&self.value);\n                            } else {\n                                state.cursor.move_left(&self.value);\n                            }\n\n                            if cursor_before != state.cursor {\n                                focus.updated_at = Instant::now();\n\n                                shell.request_redraw();\n                            }\n\n                            shell.capture_event();\n                        }\n                        keyboard::Key::Named(key::Named::ArrowRight) => {\n                            let cursor_before = state.cursor;\n\n                            if (self.is_secure && modifiers.jump()) || modifiers.macos_command() {\n                                if modifiers.shift() {\n                                    state.cursor.select_range(\n                                        state.cursor.start(&self.value),\n                                        self.value.len(),\n                                    );\n                                } else {\n                                    state.cursor.move_to(self.value.len());\n                                }\n                            } else if modifiers.jump() {\n                                if modifiers.shift() {\n                                    state.cursor.select_right_by_words(&self.value);\n                                } else {\n                                    state.cursor.move_right_by_words(&self.value);\n                                }\n                            } else if modifiers.shift() {\n                                state.cursor.select_right(&self.value);\n                            } else {\n                                state.cursor.move_right(&self.value);\n                            }\n\n                            if cursor_before != state.cursor {\n                                focus.updated_at = Instant::now();\n\n                                shell.request_redraw();\n                            }\n\n                            shell.capture_event();\n                        }\n                        keyboard::Key::Named(key::Named::Escape) => {\n                            state.is_focused = None;\n                            state.is_dragging = None;\n                            state.is_pasting = None;\n\n                            state.keyboard_modifiers = keyboard::Modifiers::default();\n\n                            shell.capture_event();\n                        }\n                        _ => {}\n                    }\n                }\n            }\n            Event::Keyboard(keyboard::Event::KeyReleased { key, .. }) => {\n                let state = state::<Renderer>(tree);\n\n                if state.is_focused.is_some()\n                    && let keyboard::Key::Character(\"v\") = key.as_ref()\n                {\n                    state.is_pasting = None;\n                    shell.capture_event();\n                }\n\n                state.is_pasting = None;\n            }\n            Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => {\n                let state = state::<Renderer>(tree);\n\n                state.keyboard_modifiers = *modifiers;\n            }\n            Event::Clipboard(clipboard::Event::Read(Ok(content))) => {\n                let Some(on_input) = &self.on_input else {\n                    return;\n                };\n\n                let state = state::<Renderer>(tree);\n\n                let Some(focus) = &mut state.is_focused else {\n                    return;\n                };\n\n                if let clipboard::Content::Text(text) = content.as_ref()\n                    && let Some(Paste::Reading) = state.is_pasting\n                {\n                    state.is_pasting = Some(Paste::Pasting(Value::new(text)));\n\n                    let mut editor = Editor::new(&mut self.value, &mut state.cursor);\n                    editor.paste(Value::new(text));\n\n                    let message = if let Some(paste) = &self.on_paste {\n                        (paste)(editor.contents())\n                    } else {\n                        (on_input)(editor.contents())\n                    };\n                    shell.publish(message);\n                    shell.capture_event();\n\n                    focus.updated_at = Instant::now();\n                    update_cache(state, &self.value);\n                    return;\n                }\n            }\n            Event::InputMethod(event) => match event {\n                input_method::Event::Opened | input_method::Event::Closed => {\n                    let state = state::<Renderer>(tree);\n\n                    state.preedit = matches!(event, input_method::Event::Opened)\n                        .then(input_method::Preedit::new);\n\n                    shell.request_redraw();\n                }\n                input_method::Event::Preedit(content, selection) => {\n                    let state = state::<Renderer>(tree);\n\n                    if state.is_focused.is_some() {\n                        state.preedit = Some(input_method::Preedit {\n                            content: content.to_owned(),\n                            selection: selection.clone(),\n                            text_size: self.size,\n                        });\n\n                        shell.request_redraw();\n                    }\n                }\n                input_method::Event::Commit(text) => {\n                    let state = state::<Renderer>(tree);\n\n                    if let Some(focus) = &mut state.is_focused {\n                        let Some(on_input) = &self.on_input else {\n                            return;\n                        };\n\n                        let mut editor = Editor::new(&mut self.value, &mut state.cursor);\n                        editor.paste(Value::new(text));\n\n                        focus.updated_at = Instant::now();\n                        state.is_pasting = None;\n\n                        let message = (on_input)(editor.contents());\n                        shell.publish(message);\n                        shell.capture_event();\n\n                        update_cache(state, &self.value);\n                    }\n                }\n            },\n            Event::Window(window::Event::Unfocused) => {\n                let state = state::<Renderer>(tree);\n\n                if let Some(focus) = &mut state.is_focused {\n                    focus.is_window_focused = false;\n                }\n            }\n            Event::Window(window::Event::Focused) => {\n                let state = state::<Renderer>(tree);\n\n                if let Some(focus) = &mut state.is_focused {\n                    focus.is_window_focused = true;\n                    focus.updated_at = Instant::now();\n\n                    shell.request_redraw();\n                }\n            }\n            Event::Window(window::Event::RedrawRequested(now)) => {\n                let state = state::<Renderer>(tree);\n\n                if let Some(focus) = &mut state.is_focused\n                    && focus.is_window_focused\n                {\n                    if matches!(state.cursor.state(&self.value), cursor::State::Index(_)) {\n                        focus.now = *now;\n\n                        let millis_until_redraw = CURSOR_BLINK_INTERVAL_MILLIS\n                            - (*now - focus.updated_at).as_millis() % CURSOR_BLINK_INTERVAL_MILLIS;\n\n                        shell.request_redraw_at(\n                            *now + Duration::from_millis(millis_until_redraw as u64),\n                        );\n                    }\n\n                    shell.request_input_method(&self.input_method(state, layout, &self.value));\n                }\n            }\n            _ => {}\n        }\n\n        let state = state::<Renderer>(tree);\n        let is_disabled = self.on_input.is_none();\n\n        let status = if is_disabled {\n            Status::Disabled\n        } else if state.is_focused() {\n            Status::Focused {\n                is_hovered: cursor.is_over(layout.bounds()),\n            }\n        } else if cursor.is_over(layout.bounds()) {\n            Status::Hovered\n        } else {\n            Status::Active\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.last_status = Some(status);\n        } else if self\n            .last_status\n            .is_some_and(|last_status| status != last_status)\n        {\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.draw(tree, renderer, theme, layout, cursor, None, viewport);\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        if cursor.is_over(layout.bounds()) {\n            if self.on_input.is_none() {\n                mouse::Interaction::Idle\n            } else {\n                mouse::Interaction::Text\n            }\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<TextInput<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: Clone + 'a,\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n{\n    fn from(\n        text_input: TextInput<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(text_input)\n    }\n}\n\n/// The content of the [`Icon`].\n#[derive(Debug, Clone)]\npub struct Icon<Font> {\n    /// The font that will be used to display the `code_point`.\n    pub font: Font,\n    /// The unicode code point that will be used as the icon.\n    pub code_point: char,\n    /// The font size of the content.\n    pub size: Option<Pixels>,\n    /// The spacing between the [`Icon`] and the text in a [`TextInput`].\n    pub spacing: f32,\n    /// The side of a [`TextInput`] where to display the [`Icon`].\n    pub side: Side,\n}\n\n/// The side of a [`TextInput`].\n#[derive(Debug, Clone)]\npub enum Side {\n    /// The left side of a [`TextInput`].\n    Left,\n    /// The right side of a [`TextInput`].\n    Right,\n}\n\n/// The state of a [`TextInput`].\n#[derive(Debug, Default, Clone)]\npub struct State<P: text::Paragraph> {\n    value: paragraph::Plain<P>,\n    placeholder: paragraph::Plain<P>,\n    icon: paragraph::Plain<P>,\n    is_focused: Option<Focus>,\n    is_dragging: Option<Drag>,\n    is_pasting: Option<Paste>,\n    preedit: Option<input_method::Preedit>,\n    last_click: Option<mouse::Click>,\n    cursor: Cursor,\n    keyboard_modifiers: keyboard::Modifiers,\n    // TODO: Add stateful horizontal scrolling offset\n}\n\nfn state<Renderer: text::Renderer>(tree: &mut Tree) -> &mut State<Renderer::Paragraph> {\n    tree.state.downcast_mut::<State<Renderer::Paragraph>>()\n}\n\n#[derive(Debug, Clone)]\nstruct Focus {\n    updated_at: Instant,\n    now: Instant,\n    is_window_focused: bool,\n}\n\n#[derive(Debug, Clone)]\nenum Drag {\n    Select,\n    SelectWords { anchor: usize },\n}\n\n#[derive(Debug, Clone)]\nenum Paste {\n    Reading,\n    Pasting(Value),\n}\n\nimpl<P: text::Paragraph> State<P> {\n    /// Creates a new [`State`], representing an unfocused [`TextInput`].\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Returns whether the [`TextInput`] is currently focused or not.\n    pub fn is_focused(&self) -> bool {\n        self.is_focused.is_some()\n    }\n\n    /// Returns the [`Cursor`] of the [`TextInput`].\n    pub fn cursor(&self) -> Cursor {\n        self.cursor\n    }\n\n    /// Focuses the [`TextInput`].\n    pub fn focus(&mut self) {\n        let now = Instant::now();\n\n        self.is_focused = Some(Focus {\n            updated_at: now,\n            now,\n            is_window_focused: true,\n        });\n\n        self.move_cursor_to_end();\n    }\n\n    /// Unfocuses the [`TextInput`].\n    pub fn unfocus(&mut self) {\n        self.is_focused = None;\n    }\n\n    /// Moves the [`Cursor`] of the [`TextInput`] to the front of the input text.\n    pub fn move_cursor_to_front(&mut self) {\n        self.cursor.move_to(0);\n    }\n\n    /// Moves the [`Cursor`] of the [`TextInput`] to the end of the input text.\n    pub fn move_cursor_to_end(&mut self) {\n        self.cursor.move_to(usize::MAX);\n    }\n\n    /// Moves the [`Cursor`] of the [`TextInput`] to an arbitrary location.\n    pub fn move_cursor_to(&mut self, position: usize) {\n        self.cursor.move_to(position);\n    }\n\n    /// Selects all the content of the [`TextInput`].\n    pub fn select_all(&mut self) {\n        self.cursor.select_range(0, usize::MAX);\n    }\n\n    /// Selects the given range of the content of the [`TextInput`].\n    pub fn select_range(&mut self, start: usize, end: usize) {\n        self.cursor.select_range(start, end);\n    }\n}\n\nimpl<P: text::Paragraph> operation::Focusable for State<P> {\n    fn is_focused(&self) -> bool {\n        State::is_focused(self)\n    }\n\n    fn focus(&mut self) {\n        State::focus(self);\n    }\n\n    fn unfocus(&mut self) {\n        State::unfocus(self);\n    }\n}\n\nimpl<P: text::Paragraph> operation::TextInput for State<P> {\n    fn text(&self) -> &str {\n        if self.value.content().is_empty() {\n            self.placeholder.content()\n        } else {\n            self.value.content()\n        }\n    }\n\n    fn move_cursor_to_front(&mut self) {\n        State::move_cursor_to_front(self);\n    }\n\n    fn move_cursor_to_end(&mut self) {\n        State::move_cursor_to_end(self);\n    }\n\n    fn move_cursor_to(&mut self, position: usize) {\n        State::move_cursor_to(self, position);\n    }\n\n    fn select_all(&mut self) {\n        State::select_all(self);\n    }\n\n    fn select_range(&mut self, start: usize, end: usize) {\n        State::select_range(self, start, end);\n    }\n}\n\nfn offset<P: text::Paragraph>(text_bounds: Rectangle, value: &Value, state: &State<P>) -> f32 {\n    if state.is_focused() {\n        let cursor = state.cursor();\n\n        let focus_position = match cursor.state(value) {\n            cursor::State::Index(i) => i,\n            cursor::State::Selection { end, .. } => end,\n        };\n\n        let (_, offset) =\n            measure_cursor_and_scroll_offset(state.value.raw(), text_bounds, focus_position);\n\n        offset\n    } else {\n        0.0\n    }\n}\n\nfn measure_cursor_and_scroll_offset(\n    paragraph: &impl text::Paragraph,\n    text_bounds: Rectangle,\n    cursor_index: usize,\n) -> (f32, f32) {\n    let grapheme_position = paragraph\n        .grapheme_position(0, cursor_index)\n        .unwrap_or(Point::ORIGIN);\n\n    let offset = ((grapheme_position.x + 5.0) - text_bounds.width).max(0.0);\n\n    (grapheme_position.x, offset)\n}\n\n/// Computes the position of the text cursor at the given X coordinate of\n/// a [`TextInput`].\nfn find_cursor_position<P: text::Paragraph>(\n    text_bounds: Rectangle,\n    value: &Value,\n    state: &State<P>,\n    x: f32,\n) -> Option<usize> {\n    let offset = offset(text_bounds, value, state);\n    let value = value.to_string();\n\n    let char_offset = state\n        .value\n        .raw()\n        .hit_test(Point::new(x + offset, text_bounds.height / 2.0))\n        .map(text::Hit::cursor)?;\n\n    Some(\n        unicode_segmentation::UnicodeSegmentation::graphemes(\n            &value[..char_offset.min(value.len())],\n            true,\n        )\n        .count(),\n    )\n}\n\nfn replace_paragraph<Renderer>(\n    renderer: &Renderer,\n    state: &mut State<Renderer::Paragraph>,\n    layout: Layout<'_>,\n    value: &Value,\n    font: Option<Renderer::Font>,\n    text_size: Option<Pixels>,\n    line_height: text::LineHeight,\n) where\n    Renderer: text::Renderer,\n{\n    let font = font.unwrap_or_else(|| renderer.default_font());\n    let text_size = text_size.unwrap_or_else(|| renderer.default_size());\n\n    let mut children_layout = layout.children();\n    let text_bounds = children_layout.next().unwrap().bounds();\n\n    state.value = paragraph::Plain::new(Text {\n        font,\n        line_height,\n        content: value.to_string(),\n        bounds: Size::new(f32::INFINITY, text_bounds.height),\n        size: text_size,\n        align_x: text::Alignment::Default,\n        align_y: alignment::Vertical::Center,\n        shaping: text::Shaping::Advanced,\n        wrapping: text::Wrapping::None,\n        ellipsis: text::Ellipsis::None,\n        hint_factor: renderer.scale_factor(),\n    });\n}\n\nconst CURSOR_BLINK_INTERVAL_MILLIS: u128 = 500;\n\n/// The possible status of a [`TextInput`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`TextInput`] can be interacted with.\n    Active,\n    /// The [`TextInput`] is being hovered.\n    Hovered,\n    /// The [`TextInput`] is focused.\n    Focused {\n        /// Whether the [`TextInput`] is hovered, while focused.\n        is_hovered: bool,\n    },\n    /// The [`TextInput`] cannot be interacted with.\n    Disabled,\n}\n\n/// The appearance of a text input.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The [`Background`] of the text input.\n    pub background: Background,\n    /// The [`Border`] of the text input.\n    pub border: Border,\n    /// The [`Color`] of the icon of the text input.\n    pub icon: Color,\n    /// The [`Color`] of the placeholder of the text input.\n    pub placeholder: Color,\n    /// The [`Color`] of the value of the text input.\n    pub value: Color,\n    /// The [`Color`] of the selection of the text input.\n    pub selection: Color,\n}\n\n/// The theme catalog of a [`TextInput`].\npub trait Catalog: Sized {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`TextInput`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// The default style of a [`TextInput`].\npub fn default(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    let active = Style {\n        background: Background::Color(palette.background.base.color),\n        border: Border {\n            radius: 2.0.into(),\n            width: 1.0,\n            color: palette.background.strong.color,\n        },\n        icon: palette.background.weak.text,\n        placeholder: palette.secondary.base.color,\n        value: palette.background.base.text,\n        selection: palette.primary.weak.color,\n    };\n\n    match status {\n        Status::Active => active,\n        Status::Hovered => Style {\n            border: Border {\n                color: palette.background.base.text,\n                ..active.border\n            },\n            ..active\n        },\n        Status::Focused { .. } => Style {\n            border: Border {\n                color: palette.primary.strong.color,\n                ..active.border\n            },\n            ..active\n        },\n        Status::Disabled => Style {\n            background: Background::Color(palette.background.weak.color),\n            value: active.placeholder,\n            placeholder: palette.background.strongest.color,\n            ..active\n        },\n    }\n}\n\nfn alignment_offset(\n    text_bounds_width: f32,\n    text_min_width: f32,\n    alignment: alignment::Horizontal,\n) -> f32 {\n    if text_min_width > text_bounds_width {\n        0.0\n    } else {\n        match alignment {\n            alignment::Horizontal::Left => 0.0,\n            alignment::Horizontal::Center => (text_bounds_width - text_min_width) / 2.0,\n            alignment::Horizontal::Right => text_bounds_width - text_min_width,\n        }\n    }\n}\n"
  },
  {
    "path": "widget/src/themer.rs",
    "content": "use crate::container;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::theme;\nuse crate::core::widget::Operation;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::{\n    Background, Color, Element, Event, Layout, Length, Rectangle, Shell, Size, Vector, Widget,\n};\n\n/// A widget that applies any `Theme` to its contents.\n///\n/// This widget can be useful to leverage multiple `Theme`\n/// types in an application.\npub struct Themer<'a, Message, Theme, Renderer = crate::Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    content: Element<'a, Message, Theme, Renderer>,\n    theme: Option<Theme>,\n    text_color: Option<fn(&Theme) -> Color>,\n    background: Option<fn(&Theme) -> Background>,\n}\n\nimpl<'a, Message, Theme, Renderer> Themer<'a, Message, Theme, Renderer>\nwhere\n    Renderer: crate::core::Renderer,\n{\n    /// Creates an empty [`Themer`] that applies the given `Theme`\n    /// to the provided `content`.\n    pub fn new(\n        theme: Option<Theme>,\n        content: impl Into<Element<'a, Message, Theme, Renderer>>,\n    ) -> Self {\n        Self {\n            content: content.into(),\n            theme,\n            text_color: None,\n            background: None,\n        }\n    }\n\n    /// Sets the default text [`Color`] of the [`Themer`].\n    pub fn text_color(mut self, f: fn(&Theme) -> Color) -> Self {\n        self.text_color = Some(f);\n        self\n    }\n\n    /// Sets the [`Background`] of the [`Themer`].\n    pub fn background(mut self, f: fn(&Theme) -> Background) -> Self {\n        self.background = Some(f);\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer, AnyTheme> Widget<Message, AnyTheme, Renderer>\n    for Themer<'_, Message, Theme, Renderer>\nwhere\n    Theme: theme::Base,\n    AnyTheme: theme::Base,\n    Renderer: crate::core::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        self.content.as_widget().tag()\n    }\n\n    fn state(&self) -> tree::State {\n        self.content.as_widget().state()\n    }\n\n    fn children(&self) -> Vec<Tree> {\n        self.content.as_widget().children()\n    }\n\n    fn diff(&self, tree: &mut Tree) {\n        self.content.as_widget().diff(tree);\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.content.as_widget().size()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.content.as_widget_mut().layout(tree, renderer, limits)\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn Operation,\n    ) {\n        self.content\n            .as_widget_mut()\n            .operate(tree, layout, renderer, operation);\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        self.content\n            .as_widget_mut()\n            .update(tree, event, layout, cursor, renderer, shell, viewport);\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.content\n            .as_widget()\n            .mouse_interaction(tree, layout, cursor, viewport, renderer)\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &AnyTheme,\n        style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let default_theme = theme::Base::default(theme.mode());\n        let theme = self.theme.as_ref().unwrap_or(&default_theme);\n\n        if let Some(background) = self.background {\n            container::draw_background(\n                renderer,\n                &container::Style {\n                    background: Some(background(theme)),\n                    ..container::Style::default()\n                },\n                layout.bounds(),\n            );\n        }\n\n        let style = if let Some(text_color) = self.text_color {\n            renderer::Style {\n                text_color: text_color(theme),\n            }\n        } else {\n            *style\n        };\n\n        self.content\n            .as_widget()\n            .draw(tree, renderer, theme, &style, layout, cursor, viewport);\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, AnyTheme, Renderer>> {\n        struct Overlay<'a, Message, Theme, Renderer> {\n            theme: &'a Option<Theme>,\n            content: overlay::Element<'a, Message, Theme, Renderer>,\n        }\n\n        impl<Message, Theme, Renderer, AnyTheme> overlay::Overlay<Message, AnyTheme, Renderer>\n            for Overlay<'_, Message, Theme, Renderer>\n        where\n            Theme: theme::Base,\n            AnyTheme: theme::Base,\n            Renderer: crate::core::Renderer,\n        {\n            fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n                self.content.as_overlay_mut().layout(renderer, bounds)\n            }\n\n            fn draw(\n                &self,\n                renderer: &mut Renderer,\n                theme: &AnyTheme,\n                style: &renderer::Style,\n                layout: Layout<'_>,\n                cursor: mouse::Cursor,\n            ) {\n                let default_theme = theme::Base::default(theme.mode());\n                let theme = self.theme.as_ref().unwrap_or(&default_theme);\n\n                self.content\n                    .as_overlay()\n                    .draw(renderer, theme, style, layout, cursor);\n            }\n\n            fn update(\n                &mut self,\n                event: &Event,\n                layout: Layout<'_>,\n                cursor: mouse::Cursor,\n                renderer: &Renderer,\n                shell: &mut Shell<'_, Message>,\n            ) {\n                self.content\n                    .as_overlay_mut()\n                    .update(event, layout, cursor, renderer, shell);\n            }\n\n            fn operate(\n                &mut self,\n                layout: Layout<'_>,\n                renderer: &Renderer,\n                operation: &mut dyn Operation,\n            ) {\n                self.content\n                    .as_overlay_mut()\n                    .operate(layout, renderer, operation);\n            }\n\n            fn mouse_interaction(\n                &self,\n                layout: Layout<'_>,\n                cursor: mouse::Cursor,\n                renderer: &Renderer,\n            ) -> mouse::Interaction {\n                self.content\n                    .as_overlay()\n                    .mouse_interaction(layout, cursor, renderer)\n            }\n\n            fn overlay<'b>(\n                &'b mut self,\n                layout: Layout<'b>,\n                renderer: &Renderer,\n            ) -> Option<overlay::Element<'b, Message, AnyTheme, Renderer>> {\n                self.content\n                    .as_overlay_mut()\n                    .overlay(layout, renderer)\n                    .map(|content| Overlay {\n                        theme: self.theme,\n                        content,\n                    })\n                    .map(|overlay| overlay::Element::new(Box::new(overlay)))\n            }\n        }\n\n        self.content\n            .as_widget_mut()\n            .overlay(tree, layout, renderer, viewport, translation)\n            .map(|content| Overlay {\n                theme: &self.theme,\n                content,\n            })\n            .map(|overlay| overlay::Element::new(Box::new(overlay)))\n    }\n}\n\nimpl<'a, Message, Theme, Renderer, AnyTheme> From<Themer<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, AnyTheme, Renderer>\nwhere\n    Message: 'a,\n    Theme: theme::Base + 'a,\n    AnyTheme: theme::Base,\n    Renderer: 'a + crate::core::Renderer,\n{\n    fn from(\n        themer: Themer<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, AnyTheme, Renderer> {\n        Element::new(themer)\n    }\n}\n"
  },
  {
    "path": "widget/src/toggler.rs",
    "content": "//! Togglers let users make binary choices by toggling a switch.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::toggler;\n//!\n//! struct State {\n//!    is_checked: bool,\n//! }\n//!\n//! enum Message {\n//!     TogglerToggled(bool),\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     toggler(state.is_checked)\n//!         .label(\"Toggle me!\")\n//!         .on_toggle(Message::TogglerToggled)\n//!         .into()\n//! }\n//!\n//! fn update(state: &mut State, message: Message) {\n//!     match message {\n//!         Message::TogglerToggled(is_checked) => {\n//!             state.is_checked = is_checked;\n//!         }\n//!     }\n//! }\n//! ```\nuse crate::core::alignment;\nuse crate::core::border;\nuse crate::core::layout;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::text;\nuse crate::core::touch;\nuse crate::core::widget;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{\n    Background, Border, Color, Element, Event, Layout, Length, Pixels, Rectangle, Shell, Size,\n    Theme, Widget,\n};\n\n/// A toggler widget.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::toggler;\n///\n/// struct State {\n///    is_checked: bool,\n/// }\n///\n/// enum Message {\n///     TogglerToggled(bool),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     toggler(state.is_checked)\n///         .label(\"Toggle me!\")\n///         .on_toggle(Message::TogglerToggled)\n///         .into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::TogglerToggled(is_checked) => {\n///             state.is_checked = is_checked;\n///         }\n///     }\n/// }\n/// ```\npub struct Toggler<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    is_toggled: bool,\n    on_toggle: Option<Box<dyn Fn(bool) -> Message + 'a>>,\n    label: Option<text::Fragment<'a>>,\n    width: Length,\n    size: f32,\n    text_size: Option<Pixels>,\n    line_height: text::LineHeight,\n    alignment: text::Alignment,\n    text_shaping: text::Shaping,\n    wrapping: text::Wrapping,\n    spacing: f32,\n    font: Option<Renderer::Font>,\n    class: Theme::Class<'a>,\n    last_status: Option<Status>,\n}\n\nimpl<'a, Message, Theme, Renderer> Toggler<'a, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    /// The default size of a [`Toggler`].\n    pub const DEFAULT_SIZE: f32 = 16.0;\n\n    /// Creates a new [`Toggler`].\n    ///\n    /// It expects:\n    ///   * a boolean describing whether the [`Toggler`] is checked or not\n    ///   * An optional label for the [`Toggler`]\n    ///   * a function that will be called when the [`Toggler`] is toggled. It\n    ///     will receive the new state of the [`Toggler`] and must produce a\n    ///     `Message`.\n    pub fn new(is_toggled: bool) -> Self {\n        Toggler {\n            is_toggled,\n            on_toggle: None,\n            label: None,\n            width: Length::Shrink,\n            size: Self::DEFAULT_SIZE,\n            text_size: None,\n            line_height: text::LineHeight::default(),\n            alignment: text::Alignment::Default,\n            text_shaping: text::Shaping::default(),\n            wrapping: text::Wrapping::default(),\n            spacing: Self::DEFAULT_SIZE / 2.0,\n            font: None,\n            class: Theme::default(),\n            last_status: None,\n        }\n    }\n\n    /// Sets the label of the [`Toggler`].\n    pub fn label(mut self, label: impl text::IntoFragment<'a>) -> Self {\n        self.label = Some(label.into_fragment());\n        self\n    }\n\n    /// Sets the message that should be produced when a user toggles\n    /// the [`Toggler`].\n    ///\n    /// If this method is not called, the [`Toggler`] will be disabled.\n    pub fn on_toggle(mut self, on_toggle: impl Fn(bool) -> Message + 'a) -> Self {\n        self.on_toggle = Some(Box::new(on_toggle));\n        self\n    }\n\n    /// Sets the message that should be produced when a user toggles\n    /// the [`Toggler`], if `Some`.\n    ///\n    /// If `None`, the [`Toggler`] will be disabled.\n    pub fn on_toggle_maybe(mut self, on_toggle: Option<impl Fn(bool) -> Message + 'a>) -> Self {\n        self.on_toggle = on_toggle.map(|on_toggle| Box::new(on_toggle) as _);\n        self\n    }\n\n    /// Sets the size of the [`Toggler`].\n    pub fn size(mut self, size: impl Into<Pixels>) -> Self {\n        self.size = size.into().0;\n        self\n    }\n\n    /// Sets the width of the [`Toggler`].\n    pub fn width(mut self, width: impl Into<Length>) -> Self {\n        self.width = width.into();\n        self\n    }\n\n    /// Sets the text size o the [`Toggler`].\n    pub fn text_size(mut self, text_size: impl Into<Pixels>) -> Self {\n        self.text_size = Some(text_size.into());\n        self\n    }\n\n    /// Sets the text [`text::LineHeight`] of the [`Toggler`].\n    pub fn line_height(mut self, line_height: impl Into<text::LineHeight>) -> Self {\n        self.line_height = line_height.into();\n        self\n    }\n\n    /// Sets the horizontal alignment of the text of the [`Toggler`]\n    pub fn alignment(mut self, alignment: impl Into<text::Alignment>) -> Self {\n        self.alignment = alignment.into();\n        self\n    }\n\n    /// Sets the [`text::Shaping`] strategy of the [`Toggler`].\n    pub fn shaping(mut self, shaping: text::Shaping) -> Self {\n        self.text_shaping = shaping;\n        self\n    }\n\n    /// Sets the [`text::Wrapping`] strategy of the [`Toggler`].\n    pub fn wrapping(mut self, wrapping: text::Wrapping) -> Self {\n        self.wrapping = wrapping;\n        self\n    }\n\n    /// Sets the spacing between the [`Toggler`] and the text.\n    pub fn spacing(mut self, spacing: impl Into<Pixels>) -> Self {\n        self.spacing = spacing.into().0;\n        self\n    }\n\n    /// Sets the [`Renderer::Font`] of the text of the [`Toggler`]\n    ///\n    /// [`Renderer::Font`]: crate::core::text::Renderer\n    pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {\n        self.font = Some(font.into());\n        self\n    }\n\n    /// Sets the style of the [`Toggler`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Toggler`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Toggler<'_, Message, Theme, Renderer>\nwhere\n    Theme: Catalog,\n    Renderer: text::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<widget::text::State<Renderer::Paragraph>>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(widget::text::State::<Renderer::Paragraph>::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: self.width,\n            height: Length::Shrink,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        let limits = limits.width(self.width);\n\n        layout::next_to_each_other(\n            &limits,\n            if self.label.is_some() {\n                self.spacing\n            } else {\n                0.0\n            },\n            |_| {\n                let size = if renderer::CRISP {\n                    let scale_factor = renderer.scale_factor().unwrap_or(1.0);\n\n                    (self.size * scale_factor).round() / scale_factor\n                } else {\n                    self.size\n                };\n\n                layout::Node::new(Size::new(2.0 * size, size))\n            },\n            |limits| {\n                if let Some(label) = self.label.as_deref() {\n                    let state = tree\n                        .state\n                        .downcast_mut::<widget::text::State<Renderer::Paragraph>>();\n\n                    widget::text::layout(\n                        state,\n                        renderer,\n                        limits,\n                        label,\n                        widget::text::Format {\n                            width: self.width,\n                            height: Length::Shrink,\n                            line_height: self.line_height,\n                            size: self.text_size,\n                            font: self.font,\n                            align_x: self.alignment,\n                            align_y: alignment::Vertical::Top,\n                            shaping: self.text_shaping,\n                            wrapping: self.wrapping,\n                            ellipsis: text::Ellipsis::None,\n                        },\n                    )\n                } else {\n                    layout::Node::new(Size::ZERO)\n                }\n            },\n        )\n    }\n\n    fn update(\n        &mut self,\n        _tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let Some(on_toggle) = &self.on_toggle else {\n            return;\n        };\n\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                let mouse_over = cursor.is_over(layout.bounds());\n\n                if mouse_over {\n                    shell.publish(on_toggle(!self.is_toggled));\n                    shell.capture_event();\n                }\n            }\n            _ => {}\n        }\n\n        let current_status = if self.on_toggle.is_none() {\n            Status::Disabled {\n                is_toggled: self.is_toggled,\n            }\n        } else if cursor.is_over(layout.bounds()) {\n            Status::Hovered {\n                is_toggled: self.is_toggled,\n            }\n        } else {\n            Status::Active {\n                is_toggled: self.is_toggled,\n            }\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.last_status = Some(current_status);\n        } else if self\n            .last_status\n            .is_some_and(|status| status != current_status)\n        {\n            shell.request_redraw();\n        }\n    }\n\n    fn mouse_interaction(\n        &self,\n        _tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        if cursor.is_over(layout.bounds()) {\n            if self.on_toggle.is_some() {\n                mouse::Interaction::Pointer\n            } else {\n                mouse::Interaction::NotAllowed\n            }\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n\n    fn draw(\n        &self,\n        tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        defaults: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        let mut children = layout.children();\n        let toggler_layout = children.next().unwrap();\n\n        let style = theme.style(\n            &self.class,\n            self.last_status.unwrap_or(Status::Disabled {\n                is_toggled: self.is_toggled,\n            }),\n        );\n\n        if self.label.is_some() {\n            let label_layout = children.next().unwrap();\n            let state: &widget::text::State<Renderer::Paragraph> = tree.state.downcast_ref();\n\n            crate::text::draw(\n                renderer,\n                defaults,\n                label_layout.bounds(),\n                state.raw(),\n                crate::text::Style {\n                    color: style.text_color,\n                },\n                viewport,\n            );\n        }\n\n        let scale_factor = renderer.scale_factor().unwrap_or(1.0);\n        let bounds = toggler_layout.bounds();\n\n        let border_radius = style\n            .border_radius\n            .unwrap_or_else(|| border::Radius::new(bounds.height / 2.0));\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds,\n                border: Border {\n                    radius: border_radius,\n                    width: style.background_border_width,\n                    color: style.background_border_color,\n                },\n                ..renderer::Quad::default()\n            },\n            style.background,\n        );\n\n        let toggle_bounds = {\n            // Try to align toggle to the pixel grid\n            let bounds = if renderer::CRISP {\n                (bounds * scale_factor).round()\n            } else {\n                bounds\n            };\n\n            let padding = (style.padding_ratio * bounds.height).round();\n\n            Rectangle {\n                x: bounds.x\n                    + if self.is_toggled {\n                        bounds.width - bounds.height + padding\n                    } else {\n                        padding\n                    },\n                y: bounds.y + padding,\n                width: bounds.height - (2.0 * padding),\n                height: bounds.height - (2.0 * padding),\n            } * (1.0 / scale_factor)\n        };\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: toggle_bounds,\n                border: Border {\n                    radius: border_radius,\n                    width: style.foreground_border_width,\n                    color: style.foreground_border_color,\n                },\n                ..renderer::Quad::default()\n            },\n            style.foreground,\n        );\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Toggler<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n{\n    fn from(\n        toggler: Toggler<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(toggler)\n    }\n}\n\n/// The possible status of a [`Toggler`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum Status {\n    /// The [`Toggler`] can be interacted with.\n    Active {\n        /// Indicates whether the [`Toggler`] is toggled.\n        is_toggled: bool,\n    },\n    /// The [`Toggler`] is being hovered.\n    Hovered {\n        /// Indicates whether the [`Toggler`] is toggled.\n        is_toggled: bool,\n    },\n    /// The [`Toggler`] is disabled.\n    Disabled {\n        /// Indicates whether the [`Toggler`] is toggled.\n        is_toggled: bool,\n    },\n}\n\n/// The appearance of a toggler.\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Style {\n    /// The background [`Color`] of the toggler.\n    pub background: Background,\n    /// The width of the background border of the toggler.\n    pub background_border_width: f32,\n    /// The [`Color`] of the background border of the toggler.\n    pub background_border_color: Color,\n    /// The foreground [`Color`] of the toggler.\n    pub foreground: Background,\n    /// The width of the foreground border of the toggler.\n    pub foreground_border_width: f32,\n    /// The [`Color`] of the foreground border of the toggler.\n    pub foreground_border_color: Color,\n    /// The text [`Color`] of the toggler.\n    pub text_color: Option<Color>,\n    /// The border radius of the toggler.\n    ///\n    /// If `None`, the toggler will be perfectly round.\n    pub border_radius: Option<border::Radius>,\n    /// The ratio of separation between the background and the toggle in relative height.\n    pub padding_ratio: f32,\n}\n\n/// The theme catalog of a [`Toggler`].\npub trait Catalog: Sized {\n    /// The item class of the [`Catalog`].\n    type Class<'a>;\n\n    /// The default class produced by the [`Catalog`].\n    fn default<'a>() -> Self::Class<'a>;\n\n    /// The [`Style`] of a class with the given status.\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style;\n}\n\n/// A styling function for a [`Toggler`].\n///\n/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`.\npub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme, Status) -> Style + 'a>;\n\nimpl Catalog for Theme {\n    type Class<'a> = StyleFn<'a, Self>;\n\n    fn default<'a>() -> Self::Class<'a> {\n        Box::new(default)\n    }\n\n    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {\n        class(self, status)\n    }\n}\n\n/// The default style of a [`Toggler`].\npub fn default(theme: &Theme, status: Status) -> Style {\n    let palette = theme.palette();\n\n    let background = match status {\n        Status::Active { is_toggled } | Status::Hovered { is_toggled } => {\n            if is_toggled {\n                palette.primary.base.color\n            } else {\n                palette.background.strong.color\n            }\n        }\n        Status::Disabled { is_toggled } => {\n            if is_toggled {\n                palette.background.strong.color\n            } else {\n                palette.background.weak.color\n            }\n        }\n    };\n\n    let foreground = match status {\n        Status::Active { is_toggled } => {\n            if is_toggled {\n                palette.primary.base.text\n            } else {\n                palette.background.base.color\n            }\n        }\n        Status::Hovered { is_toggled } => {\n            if is_toggled {\n                Color {\n                    a: 0.5,\n                    ..palette.primary.base.text\n                }\n            } else {\n                palette.background.weak.color\n            }\n        }\n        Status::Disabled { .. } => palette.background.weakest.color,\n    };\n\n    Style {\n        background: background.into(),\n        foreground: foreground.into(),\n        foreground_border_width: 0.0,\n        foreground_border_color: Color::TRANSPARENT,\n        background_border_width: 0.0,\n        background_border_color: Color::TRANSPARENT,\n        text_color: None,\n        border_radius: None,\n        padding_ratio: 0.1,\n    }\n}\n"
  },
  {
    "path": "widget/src/tooltip.rs",
    "content": "//! Tooltips display a hint of information over some element when hovered.\n//!\n//! By default, the tooltip is displayed immediately, however, this can be adjusted\n//! with [`Tooltip::delay`].\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } }\n//! # pub type State = ();\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! use iced::widget::{container, tooltip};\n//!\n//! enum Message {\n//!     // ...\n//! }\n//!\n//! fn view(_state: &State) -> Element<'_, Message> {\n//!     tooltip(\n//!         \"Hover me to display the tooltip!\",\n//!         container(\"This is the tooltip contents!\")\n//!             .padding(10)\n//!             .style(container::rounded_box),\n//!         tooltip::Position::Bottom,\n//!     ).into()\n//! }\n//! ```\nuse crate::container;\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::overlay;\nuse crate::core::renderer;\nuse crate::core::text;\nuse crate::core::time::{Duration, Instant};\nuse crate::core::widget::{self, Widget};\nuse crate::core::window;\nuse crate::core::{Element, Event, Length, Padding, Pixels, Point, Rectangle, Shell, Size, Vector};\n\n/// An element to display a widget over another.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } }\n/// # pub type State = ();\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// use iced::widget::{container, tooltip};\n///\n/// enum Message {\n///     // ...\n/// }\n///\n/// fn view(_state: &State) -> Element<'_, Message> {\n///     tooltip(\n///         \"Hover me to display the tooltip!\",\n///         container(\"This is the tooltip contents!\")\n///             .padding(10)\n///             .style(container::rounded_box),\n///         tooltip::Position::Bottom,\n///     ).into()\n/// }\n/// ```\npub struct Tooltip<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: text::Renderer,\n{\n    content: Element<'a, Message, Theme, Renderer>,\n    tooltip: Element<'a, Message, Theme, Renderer>,\n    position: Position,\n    gap: f32,\n    padding: f32,\n    snap_within_viewport: bool,\n    delay: Duration,\n    class: Theme::Class<'a>,\n}\n\nimpl<'a, Message, Theme, Renderer> Tooltip<'a, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: text::Renderer,\n{\n    /// The default padding of a [`Tooltip`] drawn by this renderer.\n    const DEFAULT_PADDING: f32 = 5.0;\n\n    /// Creates a new [`Tooltip`].\n    ///\n    /// [`Tooltip`]: struct.Tooltip.html\n    pub fn new(\n        content: impl Into<Element<'a, Message, Theme, Renderer>>,\n        tooltip: impl Into<Element<'a, Message, Theme, Renderer>>,\n        position: Position,\n    ) -> Self {\n        Tooltip {\n            content: content.into(),\n            tooltip: tooltip.into(),\n            position,\n            gap: 0.0,\n            padding: Self::DEFAULT_PADDING,\n            snap_within_viewport: true,\n            delay: Duration::ZERO,\n            class: Theme::default(),\n        }\n    }\n\n    /// Sets the gap between the content and its [`Tooltip`].\n    pub fn gap(mut self, gap: impl Into<Pixels>) -> Self {\n        self.gap = gap.into().0;\n        self\n    }\n\n    /// Sets the padding of the [`Tooltip`].\n    pub fn padding(mut self, padding: impl Into<Pixels>) -> Self {\n        self.padding = padding.into().0;\n        self\n    }\n\n    /// Sets the delay before the [`Tooltip`] is shown.\n    ///\n    /// Set to [`Duration::ZERO`] to be shown immediately.\n    pub fn delay(mut self, delay: Duration) -> Self {\n        self.delay = delay;\n        self\n    }\n\n    /// Sets whether the [`Tooltip`] is snapped within the viewport.\n    pub fn snap_within_viewport(mut self, snap: bool) -> Self {\n        self.snap_within_viewport = snap;\n        self\n    }\n\n    /// Sets the style of the [`Tooltip`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme) -> container::Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<container::StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as container::StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`Tooltip`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for Tooltip<'_, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: text::Renderer,\n{\n    fn children(&self) -> Vec<widget::Tree> {\n        vec![\n            widget::Tree::new(&self.content),\n            widget::Tree::new(&self.tooltip),\n        ]\n    }\n\n    fn diff(&self, tree: &mut widget::Tree) {\n        tree.diff_children(&[self.content.as_widget(), self.tooltip.as_widget()]);\n    }\n\n    fn state(&self) -> widget::tree::State {\n        widget::tree::State::new(State::default())\n    }\n\n    fn tag(&self) -> widget::tree::Tag {\n        widget::tree::Tag::of::<State>()\n    }\n\n    fn size(&self) -> Size<Length> {\n        self.content.as_widget().size()\n    }\n\n    fn size_hint(&self) -> Size<Length> {\n        self.content.as_widget().size_hint()\n    }\n\n    fn layout(\n        &mut self,\n        tree: &mut widget::Tree,\n        renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        self.content\n            .as_widget_mut()\n            .layout(&mut tree.children[0], renderer, limits)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut widget::Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        viewport: &Rectangle,\n    ) {\n        if let Event::Mouse(_) | Event::Window(window::Event::RedrawRequested(_)) = event {\n            let state = tree.state.downcast_mut::<State>();\n            let now = Instant::now();\n            let cursor_position = cursor.position_over(layout.bounds());\n\n            match (*state, cursor_position) {\n                (State::Idle, Some(cursor_position)) => {\n                    if self.delay == Duration::ZERO {\n                        *state = State::Open { cursor_position };\n                        shell.invalidate_layout();\n                    } else {\n                        *state = State::Hovered { at: now };\n                    }\n\n                    shell.request_redraw_at(now + self.delay);\n                }\n                (State::Hovered { .. }, None) => {\n                    *state = State::Idle;\n                }\n                (State::Hovered { at, .. }, _) if at.elapsed() < self.delay => {\n                    shell.request_redraw_at(now + self.delay - at.elapsed());\n                }\n                (State::Hovered { .. }, Some(cursor_position)) => {\n                    *state = State::Open { cursor_position };\n                    shell.invalidate_layout();\n                }\n                (\n                    State::Open {\n                        cursor_position: last_position,\n                    },\n                    Some(cursor_position),\n                ) if self.position == Position::FollowCursor\n                    && last_position != cursor_position =>\n                {\n                    *state = State::Open { cursor_position };\n                    shell.request_redraw();\n                }\n                (State::Open { .. }, None) => {\n                    *state = State::Idle;\n                    shell.invalidate_layout();\n\n                    if !matches!(event, Event::Window(window::Event::RedrawRequested(_)),) {\n                        shell.request_redraw();\n                    }\n                }\n                (State::Open { .. }, Some(_)) | (State::Idle, None) => (),\n            }\n        }\n\n        self.content.as_widget_mut().update(\n            &mut tree.children[0],\n            event,\n            layout,\n            cursor,\n            renderer,\n            shell,\n            viewport,\n        );\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &widget::Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n        renderer: &Renderer,\n    ) -> mouse::Interaction {\n        self.content.as_widget().mouse_interaction(\n            &tree.children[0],\n            layout,\n            cursor,\n            viewport,\n            renderer,\n        )\n    }\n\n    fn draw(\n        &self,\n        tree: &widget::Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        inherited_style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        viewport: &Rectangle,\n    ) {\n        self.content.as_widget().draw(\n            &tree.children[0],\n            renderer,\n            theme,\n            inherited_style,\n            layout,\n            cursor,\n            viewport,\n        );\n    }\n\n    fn overlay<'b>(\n        &'b mut self,\n        tree: &'b mut widget::Tree,\n        layout: Layout<'b>,\n        renderer: &Renderer,\n        viewport: &Rectangle,\n        translation: Vector,\n    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {\n        let state = tree.state.downcast_ref::<State>();\n\n        let mut children = tree.children.iter_mut();\n\n        let content = self.content.as_widget_mut().overlay(\n            children.next().unwrap(),\n            layout,\n            renderer,\n            viewport,\n            translation,\n        );\n\n        let tooltip = if let State::Open { cursor_position } = *state {\n            Some(overlay::Element::new(Box::new(Overlay {\n                position: layout.position() + translation,\n                tooltip: &mut self.tooltip,\n                tree: children.next().unwrap(),\n                cursor_position,\n                content_bounds: layout.bounds(),\n                snap_within_viewport: self.snap_within_viewport,\n                positioning: self.position,\n                gap: self.gap,\n                padding: self.padding,\n                class: &self.class,\n            })))\n        } else {\n            None\n        };\n\n        if content.is_some() || tooltip.is_some() {\n            Some(\n                overlay::Group::with_children(content.into_iter().chain(tooltip).collect())\n                    .overlay(),\n            )\n        } else {\n            None\n        }\n    }\n\n    fn operate(\n        &mut self,\n        tree: &mut widget::Tree,\n        layout: Layout<'_>,\n        renderer: &Renderer,\n        operation: &mut dyn widget::Operation,\n    ) {\n        operation.container(None, layout.bounds());\n        operation.traverse(&mut |operation| {\n            self.content.as_widget_mut().operate(\n                &mut tree.children[0],\n                layout,\n                renderer,\n                operation,\n            );\n        });\n    }\n}\n\nimpl<'a, Message, Theme, Renderer> From<Tooltip<'a, Message, Theme, Renderer>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    Message: 'a,\n    Theme: container::Catalog + 'a,\n    Renderer: text::Renderer + 'a,\n{\n    fn from(\n        tooltip: Tooltip<'a, Message, Theme, Renderer>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(tooltip)\n    }\n}\n\n/// The position of the tooltip. Defaults to following the cursor.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum Position {\n    /// The tooltip will appear on the top of the widget.\n    #[default]\n    Top,\n    /// The tooltip will appear on the bottom of the widget.\n    Bottom,\n    /// The tooltip will appear on the left of the widget.\n    Left,\n    /// The tooltip will appear on the right of the widget.\n    Right,\n    /// The tooltip will follow the cursor.\n    FollowCursor,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\nenum State {\n    #[default]\n    Idle,\n    Hovered {\n        at: Instant,\n    },\n    Open {\n        cursor_position: Point,\n    },\n}\n\nstruct Overlay<'a, 'b, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: text::Renderer,\n{\n    position: Point,\n    tooltip: &'b mut Element<'a, Message, Theme, Renderer>,\n    tree: &'b mut widget::Tree,\n    cursor_position: Point,\n    content_bounds: Rectangle,\n    snap_within_viewport: bool,\n    positioning: Position,\n    gap: f32,\n    padding: f32,\n    class: &'b Theme::Class<'a>,\n}\n\nimpl<Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>\n    for Overlay<'_, '_, Message, Theme, Renderer>\nwhere\n    Theme: container::Catalog,\n    Renderer: text::Renderer,\n{\n    fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {\n        let viewport = Rectangle::with_size(bounds);\n\n        let tooltip_layout = self.tooltip.as_widget_mut().layout(\n            self.tree,\n            renderer,\n            &layout::Limits::new(\n                Size::ZERO,\n                if self.snap_within_viewport {\n                    viewport.size()\n                } else {\n                    Size::INFINITE\n                },\n            )\n            .shrink(Padding::new(self.padding)),\n        );\n\n        let text_bounds = tooltip_layout.bounds();\n        let x_center = self.position.x + (self.content_bounds.width - text_bounds.width) / 2.0;\n        let y_center = self.position.y + (self.content_bounds.height - text_bounds.height) / 2.0;\n\n        let mut tooltip_bounds = {\n            let offset = match self.positioning {\n                Position::Top => Vector::new(\n                    x_center,\n                    self.position.y - text_bounds.height - self.gap - self.padding,\n                ),\n                Position::Bottom => Vector::new(\n                    x_center,\n                    self.position.y + self.content_bounds.height + self.gap + self.padding,\n                ),\n                Position::Left => Vector::new(\n                    self.position.x - text_bounds.width - self.gap - self.padding,\n                    y_center,\n                ),\n                Position::Right => Vector::new(\n                    self.position.x + self.content_bounds.width + self.gap + self.padding,\n                    y_center,\n                ),\n                Position::FollowCursor => {\n                    let translation = self.position - self.content_bounds.position();\n\n                    Vector::new(\n                        self.cursor_position.x,\n                        self.cursor_position.y - text_bounds.height,\n                    ) + translation\n                }\n            };\n\n            Rectangle {\n                x: offset.x - self.padding,\n                y: offset.y - self.padding,\n                width: text_bounds.width + self.padding * 2.0,\n                height: text_bounds.height + self.padding * 2.0,\n            }\n        };\n\n        if self.snap_within_viewport {\n            if tooltip_bounds.x < viewport.x {\n                tooltip_bounds.x = viewport.x;\n            } else if viewport.x + viewport.width < tooltip_bounds.x + tooltip_bounds.width {\n                tooltip_bounds.x = viewport.x + viewport.width - tooltip_bounds.width;\n            }\n\n            if tooltip_bounds.y < viewport.y {\n                tooltip_bounds.y = viewport.y;\n            } else if viewport.y + viewport.height < tooltip_bounds.y + tooltip_bounds.height {\n                tooltip_bounds.y = viewport.y + viewport.height - tooltip_bounds.height;\n            }\n        }\n\n        layout::Node::with_children(\n            tooltip_bounds.size(),\n            vec![tooltip_layout.translate(Vector::new(self.padding, self.padding))],\n        )\n        .translate(Vector::new(tooltip_bounds.x, tooltip_bounds.y))\n    }\n\n    fn draw(\n        &self,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        inherited_style: &renderer::Style,\n        layout: Layout<'_>,\n        cursor_position: mouse::Cursor,\n    ) {\n        let style = theme.style(self.class);\n\n        container::draw_background(renderer, &style, layout.bounds());\n\n        let defaults = renderer::Style {\n            text_color: style.text_color.unwrap_or(inherited_style.text_color),\n        };\n\n        self.tooltip.as_widget().draw(\n            self.tree,\n            renderer,\n            theme,\n            &defaults,\n            layout.children().next().unwrap(),\n            cursor_position,\n            &Rectangle::with_size(Size::INFINITE),\n        );\n    }\n}\n"
  },
  {
    "path": "widget/src/vertical_slider.rs",
    "content": "//! Sliders let users set a value by moving an indicator.\n//!\n//! # Example\n//! ```no_run\n//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n//! #\n//! use iced::widget::slider;\n//!\n//! struct State {\n//!    value: f32,\n//! }\n//!\n//! #[derive(Debug, Clone)]\n//! enum Message {\n//!     ValueChanged(f32),\n//! }\n//!\n//! fn view(state: &State) -> Element<'_, Message> {\n//!     slider(0.0..=100.0, state.value, Message::ValueChanged).into()\n//! }\n//!\n//! fn update(state: &mut State, message: Message) {\n//!     match message {\n//!         Message::ValueChanged(value) => {\n//!             state.value = value;\n//!         }\n//!     }\n//! }\n//! ```\nuse std::ops::RangeInclusive;\n\npub use crate::slider::{Catalog, Handle, HandleShape, Status, Style, StyleFn, default};\n\nuse crate::core::border::Border;\nuse crate::core::keyboard;\nuse crate::core::keyboard::key::{self, Key};\nuse crate::core::layout::{self, Layout};\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::touch;\nuse crate::core::widget::tree::{self, Tree};\nuse crate::core::window;\nuse crate::core::{self, Element, Event, Length, Pixels, Point, Rectangle, Shell, Size, Widget};\n\n/// An vertical bar and a handle that selects a single value from a range of\n/// values.\n///\n/// A [`VerticalSlider`] will try to fill the vertical space of its container.\n///\n/// The [`VerticalSlider`] range of numeric values is generic and its step size defaults\n/// to 1 unit.\n///\n/// # Example\n/// ```no_run\n/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }\n/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;\n/// #\n/// use iced::widget::vertical_slider;\n///\n/// struct State {\n///    value: f32,\n/// }\n///\n/// #[derive(Debug, Clone)]\n/// enum Message {\n///     ValueChanged(f32),\n/// }\n///\n/// fn view(state: &State) -> Element<'_, Message> {\n///     vertical_slider(0.0..=100.0, state.value, Message::ValueChanged).into()\n/// }\n///\n/// fn update(state: &mut State, message: Message) {\n///     match message {\n///         Message::ValueChanged(value) => {\n///             state.value = value;\n///         }\n///     }\n/// }\n/// ```\npub struct VerticalSlider<'a, T, Message, Theme = crate::Theme>\nwhere\n    Theme: Catalog,\n{\n    range: RangeInclusive<T>,\n    step: T,\n    shift_step: Option<T>,\n    value: T,\n    default: Option<T>,\n    on_change: Box<dyn Fn(T) -> Message + 'a>,\n    on_release: Option<Message>,\n    width: f32,\n    height: Length,\n    class: Theme::Class<'a>,\n    status: Option<Status>,\n}\n\nimpl<'a, T, Message, Theme> VerticalSlider<'a, T, Message, Theme>\nwhere\n    T: Copy + From<u8> + std::cmp::PartialOrd,\n    Message: Clone,\n    Theme: Catalog,\n{\n    /// The default width of a [`VerticalSlider`].\n    pub const DEFAULT_WIDTH: f32 = 16.0;\n\n    /// Creates a new [`VerticalSlider`].\n    ///\n    /// It expects:\n    ///   * an inclusive range of possible values\n    ///   * the current value of the [`VerticalSlider`]\n    ///   * a function that will be called when the [`VerticalSlider`] is dragged.\n    ///     It receives the new value of the [`VerticalSlider`] and must produce a\n    ///     `Message`.\n    pub fn new<F>(range: RangeInclusive<T>, value: T, on_change: F) -> Self\n    where\n        F: 'a + Fn(T) -> Message,\n    {\n        let value = if value >= *range.start() {\n            value\n        } else {\n            *range.start()\n        };\n\n        let value = if value <= *range.end() {\n            value\n        } else {\n            *range.end()\n        };\n\n        VerticalSlider {\n            value,\n            default: None,\n            range,\n            step: T::from(1),\n            shift_step: None,\n            on_change: Box::new(on_change),\n            on_release: None,\n            width: Self::DEFAULT_WIDTH,\n            height: Length::Fill,\n            class: Theme::default(),\n            status: None,\n        }\n    }\n\n    /// Sets the optional default value for the [`VerticalSlider`].\n    ///\n    /// If set, the [`VerticalSlider`] will reset to this value when ctrl-clicked or command-clicked.\n    pub fn default(mut self, default: impl Into<T>) -> Self {\n        self.default = Some(default.into());\n        self\n    }\n\n    /// Sets the release message of the [`VerticalSlider`].\n    /// This is called when the mouse is released from the slider.\n    ///\n    /// Typically, the user's interaction with the slider is finished when this message is produced.\n    /// This is useful if you need to spawn a long-running task from the slider's result, where\n    /// the default on_change message could create too many events.\n    pub fn on_release(mut self, on_release: Message) -> Self {\n        self.on_release = Some(on_release);\n        self\n    }\n\n    /// Sets the width of the [`VerticalSlider`].\n    pub fn width(mut self, width: impl Into<Pixels>) -> Self {\n        self.width = width.into().0;\n        self\n    }\n\n    /// Sets the height of the [`VerticalSlider`].\n    pub fn height(mut self, height: impl Into<Length>) -> Self {\n        self.height = height.into();\n        self\n    }\n\n    /// Sets the step size of the [`VerticalSlider`].\n    pub fn step(mut self, step: T) -> Self {\n        self.step = step;\n        self\n    }\n\n    /// Sets the optional \"shift\" step for the [`VerticalSlider`].\n    ///\n    /// If set, this value is used as the step while the shift key is pressed.\n    pub fn shift_step(mut self, shift_step: impl Into<T>) -> Self {\n        self.shift_step = Some(shift_step.into());\n        self\n    }\n\n    /// Sets the style of the [`VerticalSlider`].\n    #[must_use]\n    pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self\n    where\n        Theme::Class<'a>: From<StyleFn<'a, Theme>>,\n    {\n        self.class = (Box::new(style) as StyleFn<'a, Theme>).into();\n        self\n    }\n\n    /// Sets the style class of the [`VerticalSlider`].\n    #[cfg(feature = \"advanced\")]\n    #[must_use]\n    pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {\n        self.class = class.into();\n        self\n    }\n}\n\nimpl<T, Message, Theme, Renderer> Widget<Message, Theme, Renderer>\n    for VerticalSlider<'_, T, Message, Theme>\nwhere\n    T: Copy + Into<f64> + num_traits::FromPrimitive,\n    Message: Clone,\n    Theme: Catalog,\n    Renderer: core::Renderer,\n{\n    fn tag(&self) -> tree::Tag {\n        tree::Tag::of::<State>()\n    }\n\n    fn state(&self) -> tree::State {\n        tree::State::new(State::default())\n    }\n\n    fn size(&self) -> Size<Length> {\n        Size {\n            width: Length::Shrink,\n            height: self.height,\n        }\n    }\n\n    fn layout(\n        &mut self,\n        _tree: &mut Tree,\n        _renderer: &Renderer,\n        limits: &layout::Limits,\n    ) -> layout::Node {\n        layout::atomic(limits, self.width, self.height)\n    }\n\n    fn update(\n        &mut self,\n        tree: &mut Tree,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _renderer: &Renderer,\n        shell: &mut Shell<'_, Message>,\n        _viewport: &Rectangle,\n    ) {\n        let state = tree.state.downcast_mut::<State>();\n        let is_dragging = state.is_dragging;\n        let current_value = self.value;\n\n        let locate = |cursor_position: Point| -> Option<T> {\n            let bounds = layout.bounds();\n\n            if cursor_position.y >= bounds.y + bounds.height {\n                Some(*self.range.start())\n            } else if cursor_position.y <= bounds.y {\n                Some(*self.range.end())\n            } else {\n                let step = if state.keyboard_modifiers.shift() {\n                    self.shift_step.unwrap_or(self.step)\n                } else {\n                    self.step\n                }\n                .into();\n\n                let start = (*self.range.start()).into();\n                let end = (*self.range.end()).into();\n\n                let percent =\n                    1.0 - f64::from(cursor_position.y - bounds.y) / f64::from(bounds.height);\n\n                let steps = (percent * (end - start) / step).round();\n                let value = steps * step + start;\n\n                T::from_f64(value.min(end))\n            }\n        };\n\n        let increment = |value: T| -> Option<T> {\n            let step = if state.keyboard_modifiers.shift() {\n                self.shift_step.unwrap_or(self.step)\n            } else {\n                self.step\n            }\n            .into();\n\n            let steps = (value.into() / step).round();\n            let new_value = step * (steps + 1.0);\n\n            if new_value > (*self.range.end()).into() {\n                return Some(*self.range.end());\n            }\n\n            T::from_f64(new_value)\n        };\n\n        let decrement = |value: T| -> Option<T> {\n            let step = if state.keyboard_modifiers.shift() {\n                self.shift_step.unwrap_or(self.step)\n            } else {\n                self.step\n            }\n            .into();\n\n            let steps = (value.into() / step).round();\n            let new_value = step * (steps - 1.0);\n\n            if new_value < (*self.range.start()).into() {\n                return Some(*self.range.start());\n            }\n\n            T::from_f64(new_value)\n        };\n\n        let change = |new_value: T| {\n            if (self.value.into() - new_value.into()).abs() > f64::EPSILON {\n                shell.publish((self.on_change)(new_value));\n\n                self.value = new_value;\n            }\n        };\n\n        match event {\n            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerPressed { .. }) => {\n                if let Some(cursor_position) = cursor.position_over(layout.bounds()) {\n                    if state.keyboard_modifiers.control() || state.keyboard_modifiers.command() {\n                        let _ = self.default.map(change);\n                        state.is_dragging = false;\n                    } else {\n                        let _ = locate(cursor_position).map(change);\n                        state.is_dragging = true;\n                    }\n\n                    shell.capture_event();\n                }\n            }\n            Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))\n            | Event::Touch(touch::Event::FingerLifted { .. })\n            | Event::Touch(touch::Event::FingerLost { .. }) => {\n                if is_dragging {\n                    if let Some(on_release) = self.on_release.clone() {\n                        shell.publish(on_release);\n                    }\n                    state.is_dragging = false;\n                }\n            }\n            Event::Mouse(mouse::Event::CursorMoved { .. })\n            | Event::Touch(touch::Event::FingerMoved { .. }) => {\n                if is_dragging {\n                    let _ = cursor.land().position().and_then(locate).map(change);\n\n                    shell.capture_event();\n                }\n            }\n            Event::Mouse(mouse::Event::WheelScrolled { delta })\n                if state.keyboard_modifiers.control() =>\n            {\n                if cursor.is_over(layout.bounds()) {\n                    let delta = match *delta {\n                        mouse::ScrollDelta::Lines { x: _, y } => y,\n                        mouse::ScrollDelta::Pixels { x: _, y } => y,\n                    };\n\n                    if delta < 0.0 {\n                        let _ = decrement(current_value).map(change);\n                    } else {\n                        let _ = increment(current_value).map(change);\n                    }\n\n                    shell.capture_event();\n                }\n            }\n            Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => {\n                if cursor.is_over(layout.bounds()) {\n                    match key {\n                        Key::Named(key::Named::ArrowUp) => {\n                            let _ = increment(current_value).map(change);\n                            shell.capture_event();\n                        }\n                        Key::Named(key::Named::ArrowDown) => {\n                            let _ = decrement(current_value).map(change);\n                            shell.capture_event();\n                        }\n                        _ => (),\n                    }\n                }\n            }\n            Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => {\n                state.keyboard_modifiers = *modifiers;\n            }\n            _ => {}\n        }\n\n        let current_status = if state.is_dragging {\n            Status::Dragged\n        } else if cursor.is_over(layout.bounds()) {\n            Status::Hovered\n        } else {\n            Status::Active\n        };\n\n        if let Event::Window(window::Event::RedrawRequested(_now)) = event {\n            self.status = Some(current_status);\n        } else if self.status.is_some_and(|status| status != current_status) {\n            shell.request_redraw();\n        }\n    }\n\n    fn draw(\n        &self,\n        _tree: &Tree,\n        renderer: &mut Renderer,\n        theme: &Theme,\n        _style: &renderer::Style,\n        layout: Layout<'_>,\n        _cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n    ) {\n        let bounds = layout.bounds();\n\n        let style = theme.style(&self.class, self.status.unwrap_or(Status::Active));\n\n        let (handle_width, handle_height, handle_border_radius) = match style.handle.shape {\n            HandleShape::Circle { radius } => (radius * 2.0, radius * 2.0, radius.into()),\n            HandleShape::Rectangle {\n                width,\n                border_radius,\n            } => (f32::from(width), bounds.width, border_radius),\n        };\n\n        let value = self.value.into() as f32;\n        let (range_start, range_end) = {\n            let (start, end) = self.range.clone().into_inner();\n\n            (start.into() as f32, end.into() as f32)\n        };\n\n        let offset = if range_start >= range_end {\n            0.0\n        } else {\n            (bounds.height - handle_width) * (value - range_end) / (range_start - range_end)\n        };\n\n        let rail_x = bounds.x + bounds.width / 2.0;\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: Rectangle {\n                    x: rail_x - style.rail.width / 2.0,\n                    y: bounds.y,\n                    width: style.rail.width,\n                    height: offset + handle_width / 2.0,\n                },\n                border: style.rail.border,\n                ..renderer::Quad::default()\n            },\n            style.rail.backgrounds.1,\n        );\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: Rectangle {\n                    x: rail_x - style.rail.width / 2.0,\n                    y: bounds.y + offset + handle_width / 2.0,\n                    width: style.rail.width,\n                    height: bounds.height - offset - handle_width / 2.0,\n                },\n                border: style.rail.border,\n                ..renderer::Quad::default()\n            },\n            style.rail.backgrounds.0,\n        );\n\n        renderer.fill_quad(\n            renderer::Quad {\n                bounds: Rectangle {\n                    x: rail_x - handle_height / 2.0,\n                    y: bounds.y + offset,\n                    width: handle_height,\n                    height: handle_width,\n                },\n                border: Border {\n                    radius: handle_border_radius,\n                    width: style.handle.border_width,\n                    color: style.handle.border_color,\n                },\n                ..renderer::Quad::default()\n            },\n            style.handle.background,\n        );\n    }\n\n    fn mouse_interaction(\n        &self,\n        tree: &Tree,\n        layout: Layout<'_>,\n        cursor: mouse::Cursor,\n        _viewport: &Rectangle,\n        _renderer: &Renderer,\n    ) -> mouse::Interaction {\n        let state = tree.state.downcast_ref::<State>();\n\n        if state.is_dragging {\n            // FIXME: Fall back to `Pointer` on Windows\n            // See https://github.com/rust-windowing/winit/issues/1043\n            if cfg!(target_os = \"windows\") {\n                mouse::Interaction::Pointer\n            } else {\n                mouse::Interaction::Grabbing\n            }\n        } else if cursor.is_over(layout.bounds()) {\n            if cfg!(target_os = \"windows\") {\n                mouse::Interaction::Pointer\n            } else {\n                mouse::Interaction::Grab\n            }\n        } else {\n            mouse::Interaction::default()\n        }\n    }\n}\n\nimpl<'a, T, Message, Theme, Renderer> From<VerticalSlider<'a, T, Message, Theme>>\n    for Element<'a, Message, Theme, Renderer>\nwhere\n    T: Copy + Into<f64> + num_traits::FromPrimitive + 'a,\n    Message: Clone + 'a,\n    Theme: Catalog + 'a,\n    Renderer: core::Renderer + 'a,\n{\n    fn from(\n        slider: VerticalSlider<'a, T, Message, Theme>,\n    ) -> Element<'a, Message, Theme, Renderer> {\n        Element::new(slider)\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\nstruct State {\n    is_dragging: bool,\n    keyboard_modifiers: keyboard::Modifiers,\n}\n"
  },
  {
    "path": "winit/Cargo.toml",
    "content": "[package]\nname = \"iced_winit\"\ndescription = \"A runtime for iced on top of winit\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nhomepage.workspace = true\ncategories.workspace = true\nkeywords.workspace = true\n\n[lints]\nworkspace = true\n\n[features]\ndefault = [\"x11\", \"wayland\"]\ndebug = [\"iced_debug/enable\"]\nsysinfo = [\"dep:sysinfo\"]\nhinting = []\nunconditional-rendering = []\nlinux-theme-detection = [\"dep:mundy\", \"mundy/async-io\", \"mundy/color-scheme\"]\nimage = [\"iced_runtime/image\", \"arboard/image-data\"]\nx11 = [\"winit/x11\"]\nwayland = [\"winit/wayland\", \"winit/wayland-dlopen\", \"winit/wayland-csd-adwaita\", \"arboard/wayland-data-control\"]\n\n[dependencies]\niced_debug.workspace = true\niced_program.workspace = true\niced_runtime.workspace = true\n\nlog.workspace = true\nrustc-hash.workspace = true\nthiserror.workspace = true\ntracing.workspace = true\nwinit.workspace = true\n\nsysinfo.workspace = true\nsysinfo.optional = true\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\narboard.workspace = true\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nweb-sys.workspace = true\nweb-sys.features = [\"Document\", \"Window\", \"HtmlCanvasElement\"]\nwasm-bindgen-futures.workspace = true\n\n[target.'cfg(target_os = \"linux\")'.dependencies]\nmundy.workspace = true\nmundy.optional = true\n\n# Delete once we update to `winit 0.31`\n[target.'cfg(target_os = \"macos\")'.dependencies]\nobjc2 = { version = \"0.5\", features = [\"relax-sign-encoding\"] }\n"
  },
  {
    "path": "winit/README.md",
    "content": "# `iced_winit`\n[![Documentation](https://docs.rs/iced_winit/badge.svg)][documentation]\n[![Crates.io](https://img.shields.io/crates/v/iced_winit.svg)](https://crates.io/crates/iced_winit)\n[![License](https://img.shields.io/crates/l/iced_winit.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)\n[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)\n\n`iced_winit` offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`].\n\nIt exposes a renderer-agnostic `Application` trait that can be implemented and then run with a simple call. The use of this trait is optional. A `conversion` module is provided for users that decide to implement a custom event loop.\n\n<p align=\"center\">\n  <img alt=\"The native target\" src=\"../docs/graphs/native.png\" width=\"80%\">\n</p>\n\n[documentation]: https://docs.rs/iced_winit\n[`iced_native`]: ../native\n[`winit`]: https://github.com/rust-windowing/winit\n"
  },
  {
    "path": "winit/src/clipboard.rs",
    "content": "//! Access the clipboard.\nuse crate::core::clipboard::{Content, Error, Kind};\n\npub use platform::*;\n\nimpl Default for Clipboard {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\nmod platform {\n    use super::*;\n\n    use std::sync::{Arc, Mutex};\n    use std::thread;\n\n    /// A buffer for short-term storage and transfer within and between\n    /// applications.\n    pub struct Clipboard {\n        state: State,\n    }\n\n    enum State {\n        Connected {\n            clipboard: Arc<Mutex<arboard::Clipboard>>,\n        },\n        Unavailable,\n    }\n\n    impl Clipboard {\n        /// Creates a new [`Clipboard`] for the given window.\n        pub fn new() -> Self {\n            let clipboard = arboard::Clipboard::new();\n\n            let state = match clipboard {\n                Ok(clipboard) => State::Connected {\n                    clipboard: Arc::new(Mutex::new(clipboard)),\n                },\n                Err(_) => State::Unavailable,\n            };\n\n            Clipboard { state }\n        }\n\n        /// Reads the current content of the [`Clipboard`] as text.\n        pub fn read(\n            &self,\n            kind: Kind,\n            callback: impl FnOnce(Result<Content, Error>) + Send + 'static,\n        ) {\n            let State::Connected { clipboard } = &self.state else {\n                callback(Err(Error::ClipboardUnavailable));\n                return;\n            };\n\n            let clipboard = clipboard.clone();\n\n            let _ = thread::spawn(move || {\n                let Ok(mut clipboard) = clipboard.lock() else {\n                    callback(Err(Error::ClipboardUnavailable));\n                    return;\n                };\n\n                let get = clipboard.get();\n\n                let result = match kind {\n                    Kind::Text => get.text().map(Content::Text),\n                    Kind::Html => get.html().map(Content::Html),\n                    #[cfg(feature = \"image\")]\n                    Kind::Image => get.image().map(|image| {\n                        let rgba = crate::core::Bytes::from_owner(image.bytes);\n                        let size = crate::core::Size {\n                            width: image.width as u32,\n                            height: image.height as u32,\n                        };\n\n                        Content::Image(crate::core::clipboard::Image { rgba, size })\n                    }),\n                    Kind::Files => get.file_list().map(Content::Files),\n                    kind => {\n                        log::warn!(\"unsupported clipboard kind: {kind:?}\");\n\n                        Err(arboard::Error::ContentNotAvailable)\n                    }\n                }\n                .map_err(to_error);\n\n                callback(result);\n            });\n        }\n\n        /// Writes the given text contents to the [`Clipboard`].\n        pub fn write(\n            &mut self,\n            content: Content,\n            callback: impl FnOnce(Result<(), Error>) + Send + 'static,\n        ) {\n            let State::Connected { clipboard } = &self.state else {\n                callback(Err(Error::ClipboardUnavailable));\n                return;\n            };\n\n            let clipboard = clipboard.clone();\n\n            let _ = thread::spawn(move || {\n                let Ok(mut clipboard) = clipboard.lock() else {\n                    callback(Err(Error::ClipboardUnavailable));\n                    return;\n                };\n\n                let set = clipboard.set();\n\n                let result = match content {\n                    Content::Text(text) => set.text(text),\n                    Content::Html(html) => set.html(html, None),\n                    #[cfg(feature = \"image\")]\n                    Content::Image(image) => set.image(arboard::ImageData {\n                        bytes: image.rgba.as_ref().into(),\n                        width: image.size.width as usize,\n                        height: image.size.height as usize,\n                    }),\n                    Content::Files(files) => set.file_list(&files),\n                    content => {\n                        log::warn!(\"unsupported clipboard content: {content:?}\");\n\n                        Err(arboard::Error::ClipboardNotSupported)\n                    }\n                }\n                .map_err(to_error);\n\n                callback(result);\n            });\n        }\n    }\n\n    fn to_error(error: arboard::Error) -> Error {\n        match error {\n            arboard::Error::ContentNotAvailable => Error::ContentNotAvailable,\n            arboard::Error::ClipboardNotSupported => Error::ClipboardUnavailable,\n            arboard::Error::ClipboardOccupied => Error::ClipboardOccupied,\n            arboard::Error::ConversionFailure => Error::ConversionFailure,\n            arboard::Error::Unknown { description } => Error::Unknown {\n                description: Arc::new(description),\n            },\n            error => Error::Unknown {\n                description: Arc::new(error.to_string()),\n            },\n        }\n    }\n}\n\n// TODO: Wasm support\n#[cfg(target_arch = \"wasm32\")]\nmod platform {\n    use super::*;\n\n    /// A buffer for short-term storage and transfer within and between\n    /// applications.\n    pub struct Clipboard;\n\n    impl Clipboard {\n        /// Creates a new [`Clipboard`] for the given window.\n        pub fn new() -> Self {\n            Self\n        }\n\n        /// Reads the current content of the [`Clipboard`] as text.\n        pub fn read(&self, _kind: Kind, callback: impl FnOnce(Result<Content, Error>)) {\n            callback(Err(Error::ClipboardUnavailable));\n        }\n\n        /// Writes the given text contents to the [`Clipboard`].\n        pub fn write(&mut self, _content: Content, callback: impl FnOnce(Result<(), Error>)) {\n            callback(Err(Error::ClipboardUnavailable));\n        }\n    }\n}\n"
  },
  {
    "path": "winit/src/conversion.rs",
    "content": "//! Convert [`winit`] types into [`iced_runtime`] types, and viceversa.\n//!\n//! [`winit`]: https://github.com/rust-windowing/winit\n//! [`iced_runtime`]: https://github.com/iced-rs/iced/tree/master/runtime\nuse crate::core::input_method;\nuse crate::core::keyboard;\nuse crate::core::mouse;\nuse crate::core::theme;\nuse crate::core::touch;\nuse crate::core::window;\nuse crate::core::{Event, Point, Size};\n\n/// Converts some [`window::Settings`] into some `WindowAttributes` from `winit`.\npub fn window_attributes(\n    settings: window::Settings,\n    title: &str,\n    scale_factor: f32,\n    primary_monitor: Option<winit::monitor::MonitorHandle>,\n    _id: Option<String>,\n) -> winit::window::WindowAttributes {\n    let mut attributes = winit::window::WindowAttributes::default();\n\n    let mut buttons = winit::window::WindowButtons::empty();\n\n    if settings.resizable {\n        buttons |= winit::window::WindowButtons::MAXIMIZE;\n    }\n\n    if settings.closeable {\n        buttons |= winit::window::WindowButtons::CLOSE;\n    }\n\n    if settings.minimizable {\n        buttons |= winit::window::WindowButtons::MINIMIZE;\n    }\n\n    attributes = attributes\n        .with_title(title)\n        .with_inner_size(winit::dpi::LogicalSize {\n            width: settings.size.width * scale_factor,\n            height: settings.size.height * scale_factor,\n        })\n        .with_maximized(settings.maximized)\n        .with_fullscreen(\n            settings\n                .fullscreen\n                .then_some(winit::window::Fullscreen::Borderless(None)),\n        )\n        .with_resizable(settings.resizable)\n        .with_enabled_buttons(buttons)\n        .with_decorations(settings.decorations)\n        .with_transparent(settings.transparent)\n        .with_blur(settings.blur)\n        .with_window_icon(settings.icon.and_then(icon))\n        .with_window_level(window_level(settings.level))\n        .with_visible(settings.visible);\n\n    if let Some(position) = position(primary_monitor.as_ref(), settings.size, settings.position) {\n        attributes = attributes.with_position(position);\n    }\n\n    if let Some(min_size) = settings.min_size {\n        attributes = attributes.with_min_inner_size(winit::dpi::LogicalSize {\n            width: min_size.width,\n            height: min_size.height,\n        });\n    }\n\n    if let Some(max_size) = settings.max_size {\n        attributes = attributes.with_max_inner_size(winit::dpi::LogicalSize {\n            width: max_size.width,\n            height: max_size.height,\n        });\n    }\n\n    #[cfg(any(\n        target_os = \"dragonfly\",\n        target_os = \"freebsd\",\n        target_os = \"netbsd\",\n        target_os = \"openbsd\"\n    ))]\n    {\n        use ::winit::platform::wayland::WindowAttributesExtWayland;\n\n        if let Some(id) = _id {\n            attributes = attributes.with_name(id.clone(), id);\n        }\n    }\n\n    #[cfg(target_os = \"windows\")]\n    {\n        use window::settings::platform;\n        use winit::platform::windows::{CornerPreference, WindowAttributesExtWindows};\n\n        attributes = attributes.with_drag_and_drop(settings.platform_specific.drag_and_drop);\n\n        attributes = attributes.with_skip_taskbar(settings.platform_specific.skip_taskbar);\n\n        attributes =\n            attributes.with_undecorated_shadow(settings.platform_specific.undecorated_shadow);\n\n        attributes =\n            attributes.with_corner_preference(match settings.platform_specific.corner_preference {\n                platform::CornerPreference::Default => CornerPreference::Default,\n                platform::CornerPreference::DoNotRound => CornerPreference::DoNotRound,\n                platform::CornerPreference::Round => CornerPreference::Round,\n                platform::CornerPreference::RoundSmall => CornerPreference::RoundSmall,\n            });\n    }\n\n    #[cfg(target_os = \"macos\")]\n    {\n        use winit::platform::macos::WindowAttributesExtMacOS;\n\n        attributes = attributes\n            .with_title_hidden(settings.platform_specific.title_hidden)\n            .with_titlebar_transparent(settings.platform_specific.titlebar_transparent)\n            .with_fullsize_content_view(settings.platform_specific.fullsize_content_view);\n    }\n\n    #[cfg(target_os = \"linux\")]\n    {\n        #[cfg(feature = \"x11\")]\n        {\n            use winit::platform::x11::WindowAttributesExtX11;\n\n            attributes = attributes\n                .with_override_redirect(settings.platform_specific.override_redirect)\n                .with_name(\n                    &settings.platform_specific.application_id,\n                    &settings.platform_specific.application_id,\n                );\n        }\n        #[cfg(feature = \"wayland\")]\n        {\n            use winit::platform::wayland::WindowAttributesExtWayland;\n\n            attributes = attributes.with_name(\n                &settings.platform_specific.application_id,\n                &settings.platform_specific.application_id,\n            );\n        }\n    }\n\n    attributes\n}\n\n/// Converts a winit window event into an iced event.\npub fn window_event(\n    event: winit::event::WindowEvent,\n    scale_factor: f32,\n    modifiers: winit::keyboard::ModifiersState,\n) -> Option<Event> {\n    use winit::event::Ime;\n    use winit::event::WindowEvent;\n\n    match event {\n        WindowEvent::Resized(new_size) => {\n            let logical_size = new_size.to_logical(f64::from(scale_factor));\n\n            Some(Event::Window(window::Event::Resized(Size {\n                width: logical_size.width,\n                height: logical_size.height,\n            })))\n        }\n        WindowEvent::CloseRequested => Some(Event::Window(window::Event::CloseRequested)),\n        WindowEvent::CursorMoved { position, .. } => {\n            let position = position.to_logical::<f64>(f64::from(scale_factor));\n\n            Some(Event::Mouse(mouse::Event::CursorMoved {\n                position: Point::new(position.x as f32, position.y as f32),\n            }))\n        }\n        WindowEvent::CursorEntered { .. } => Some(Event::Mouse(mouse::Event::CursorEntered)),\n        WindowEvent::CursorLeft { .. } => Some(Event::Mouse(mouse::Event::CursorLeft)),\n        WindowEvent::MouseInput { button, state, .. } => {\n            let button = mouse_button(button);\n\n            Some(Event::Mouse(match state {\n                winit::event::ElementState::Pressed => mouse::Event::ButtonPressed(button),\n                winit::event::ElementState::Released => mouse::Event::ButtonReleased(button),\n            }))\n        }\n        WindowEvent::MouseWheel { delta, .. } => match delta {\n            winit::event::MouseScrollDelta::LineDelta(delta_x, delta_y) => {\n                Some(Event::Mouse(mouse::Event::WheelScrolled {\n                    delta: mouse::ScrollDelta::Lines {\n                        x: delta_x,\n                        y: delta_y,\n                    },\n                }))\n            }\n            winit::event::MouseScrollDelta::PixelDelta(position) => {\n                Some(Event::Mouse(mouse::Event::WheelScrolled {\n                    delta: mouse::ScrollDelta::Pixels {\n                        x: position.x as f32,\n                        y: position.y as f32,\n                    },\n                }))\n            }\n        },\n        // Ignore keyboard presses/releases during window focus/unfocus\n        WindowEvent::KeyboardInput { is_synthetic, .. } if is_synthetic => None,\n        WindowEvent::KeyboardInput { event, .. } => Some(Event::Keyboard({\n            let key = {\n                #[cfg(not(target_arch = \"wasm32\"))]\n                {\n                    use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;\n                    event.key_without_modifiers()\n                }\n\n                #[cfg(target_arch = \"wasm32\")]\n                {\n                    // TODO: Fix inconsistent API on Wasm\n                    event.logical_key.clone()\n                }\n            };\n\n            let text = {\n                #[cfg(not(target_arch = \"wasm32\"))]\n                {\n                    use crate::core::SmolStr;\n                    use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;\n\n                    event.text_with_all_modifiers().map(SmolStr::new)\n                }\n\n                #[cfg(target_arch = \"wasm32\")]\n                {\n                    // TODO: Fix inconsistent API on Wasm\n                    event.text\n                }\n            }\n            .filter(|text| !text.as_str().chars().any(is_private_use));\n\n            let winit::event::KeyEvent {\n                state,\n                location,\n                logical_key,\n                physical_key,\n                repeat,\n                ..\n            } = event;\n\n            let key = self::key(key);\n            let modified_key = self::key(logical_key);\n            let physical_key = self::physical_key(physical_key);\n            let modifiers = self::modifiers(modifiers);\n\n            let location = match location {\n                winit::keyboard::KeyLocation::Standard => keyboard::Location::Standard,\n                winit::keyboard::KeyLocation::Left => keyboard::Location::Left,\n                winit::keyboard::KeyLocation::Right => keyboard::Location::Right,\n                winit::keyboard::KeyLocation::Numpad => keyboard::Location::Numpad,\n            };\n\n            match state {\n                winit::event::ElementState::Pressed => keyboard::Event::KeyPressed {\n                    key,\n                    modified_key,\n                    physical_key,\n                    modifiers,\n                    location,\n                    text,\n                    repeat,\n                },\n                winit::event::ElementState::Released => keyboard::Event::KeyReleased {\n                    key,\n                    modified_key,\n                    physical_key,\n                    modifiers,\n                    location,\n                },\n            }\n        })),\n        WindowEvent::ModifiersChanged(new_modifiers) => Some(Event::Keyboard(\n            keyboard::Event::ModifiersChanged(self::modifiers(new_modifiers.state())),\n        )),\n        WindowEvent::Ime(event) => Some(Event::InputMethod(match event {\n            Ime::Enabled => input_method::Event::Opened,\n            Ime::Preedit(content, size) => {\n                input_method::Event::Preedit(content, size.map(|(start, end)| start..end))\n            }\n            Ime::Commit(content) => input_method::Event::Commit(content),\n            Ime::Disabled => input_method::Event::Closed,\n        })),\n        WindowEvent::Focused(focused) => Some(Event::Window(if focused {\n            window::Event::Focused\n        } else {\n            window::Event::Unfocused\n        })),\n        WindowEvent::HoveredFile(path) => {\n            Some(Event::Window(window::Event::FileHovered(path.clone())))\n        }\n        WindowEvent::DroppedFile(path) => {\n            Some(Event::Window(window::Event::FileDropped(path.clone())))\n        }\n        WindowEvent::HoveredFileCancelled => Some(Event::Window(window::Event::FilesHoveredLeft)),\n        WindowEvent::Touch(touch) => Some(Event::Touch(touch_event(touch, scale_factor))),\n        WindowEvent::Moved(position) => {\n            let winit::dpi::LogicalPosition { x, y } = position.to_logical(f64::from(scale_factor));\n\n            Some(Event::Window(window::Event::Moved(Point::new(x, y))))\n        }\n        WindowEvent::ScaleFactorChanged { scale_factor, .. } => {\n            Some(Event::Window(window::Event::Rescaled(scale_factor as f32)))\n        }\n        _ => None,\n    }\n}\n\n/// Converts a [`window::Level`] into a [`winit`] window level.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\npub fn window_level(level: window::Level) -> winit::window::WindowLevel {\n    match level {\n        window::Level::Normal => winit::window::WindowLevel::Normal,\n        window::Level::AlwaysOnBottom => winit::window::WindowLevel::AlwaysOnBottom,\n        window::Level::AlwaysOnTop => winit::window::WindowLevel::AlwaysOnTop,\n    }\n}\n\n/// Converts a [`window::Position`] into a [`winit`] logical position for a given monitor.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\npub fn position(\n    monitor: Option<&winit::monitor::MonitorHandle>,\n    size: Size,\n    position: window::Position,\n) -> Option<winit::dpi::Position> {\n    match position {\n        window::Position::Default => None,\n        window::Position::Specific(position) => {\n            Some(winit::dpi::Position::Logical(winit::dpi::LogicalPosition {\n                x: f64::from(position.x),\n                y: f64::from(position.y),\n            }))\n        }\n        window::Position::SpecificWith(to_position) => {\n            if let Some(monitor) = monitor {\n                let start = monitor.position();\n\n                let resolution: winit::dpi::LogicalSize<f32> =\n                    monitor.size().to_logical(monitor.scale_factor());\n\n                let position = to_position(size, Size::new(resolution.width, resolution.height));\n\n                let centered: winit::dpi::PhysicalPosition<i32> = winit::dpi::LogicalPosition {\n                    x: position.x,\n                    y: position.y,\n                }\n                .to_physical(monitor.scale_factor());\n\n                Some(winit::dpi::Position::Physical(\n                    winit::dpi::PhysicalPosition {\n                        x: start.x + centered.x,\n                        y: start.y + centered.y,\n                    },\n                ))\n            } else {\n                None\n            }\n        }\n        window::Position::Centered => {\n            if let Some(monitor) = monitor {\n                let start = monitor.position();\n\n                let resolution: winit::dpi::LogicalSize<f64> =\n                    monitor.size().to_logical(monitor.scale_factor());\n\n                let centered: winit::dpi::PhysicalPosition<i32> = winit::dpi::LogicalPosition {\n                    x: (resolution.width - f64::from(size.width)) / 2.0,\n                    y: (resolution.height - f64::from(size.height)) / 2.0,\n                }\n                .to_physical(monitor.scale_factor());\n\n                Some(winit::dpi::Position::Physical(\n                    winit::dpi::PhysicalPosition {\n                        x: start.x + centered.x,\n                        y: start.y + centered.y,\n                    },\n                ))\n            } else {\n                None\n            }\n        }\n    }\n}\n\n/// Converts a [`window::Mode`] into a [`winit`] fullscreen mode.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\npub fn fullscreen(\n    monitor: Option<winit::monitor::MonitorHandle>,\n    mode: window::Mode,\n) -> Option<winit::window::Fullscreen> {\n    match mode {\n        window::Mode::Windowed | window::Mode::Hidden => None,\n        window::Mode::Fullscreen => Some(winit::window::Fullscreen::Borderless(monitor)),\n    }\n}\n\n/// Converts a [`window::Mode`] into a visibility flag.\npub fn visible(mode: window::Mode) -> bool {\n    match mode {\n        window::Mode::Windowed | window::Mode::Fullscreen => true,\n        window::Mode::Hidden => false,\n    }\n}\n\n/// Converts a [`winit`] fullscreen mode into a [`window::Mode`].\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\npub fn mode(mode: Option<winit::window::Fullscreen>) -> window::Mode {\n    match mode {\n        None => window::Mode::Windowed,\n        Some(_) => window::Mode::Fullscreen,\n    }\n}\n\n/// Converts a [`winit`] window theme into a [`theme::Mode`].\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\npub fn theme_mode(theme: winit::window::Theme) -> theme::Mode {\n    match theme {\n        winit::window::Theme::Light => theme::Mode::Light,\n        winit::window::Theme::Dark => theme::Mode::Dark,\n    }\n}\n\n/// Converts a [`theme::Mode`] into a window theme.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\npub fn window_theme(mode: theme::Mode) -> Option<winit::window::Theme> {\n    match mode {\n        theme::Mode::None => None,\n        theme::Mode::Light => Some(winit::window::Theme::Light),\n        theme::Mode::Dark => Some(winit::window::Theme::Dark),\n    }\n}\n\n/// Converts a [`mouse::Interaction`] into a [`winit`] cursor icon.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\npub fn mouse_interaction(interaction: mouse::Interaction) -> Option<winit::window::CursorIcon> {\n    use mouse::Interaction;\n\n    let icon = match interaction {\n        Interaction::Hidden => {\n            return None;\n        }\n        Interaction::None | Interaction::Idle => winit::window::CursorIcon::Default,\n        Interaction::ContextMenu => winit::window::CursorIcon::ContextMenu,\n        Interaction::Help => winit::window::CursorIcon::Help,\n        Interaction::Pointer => winit::window::CursorIcon::Pointer,\n        Interaction::Progress => winit::window::CursorIcon::Progress,\n        Interaction::Wait => winit::window::CursorIcon::Wait,\n        Interaction::Cell => winit::window::CursorIcon::Cell,\n        Interaction::Crosshair => winit::window::CursorIcon::Crosshair,\n        Interaction::Text => winit::window::CursorIcon::Text,\n        Interaction::Alias => winit::window::CursorIcon::Alias,\n        Interaction::Copy => winit::window::CursorIcon::Copy,\n        Interaction::Move => winit::window::CursorIcon::Move,\n        Interaction::NoDrop => winit::window::CursorIcon::NoDrop,\n        Interaction::NotAllowed => winit::window::CursorIcon::NotAllowed,\n        Interaction::Grab => winit::window::CursorIcon::Grab,\n        Interaction::Grabbing => winit::window::CursorIcon::Grabbing,\n        Interaction::ResizingHorizontally => winit::window::CursorIcon::EwResize,\n        Interaction::ResizingVertically => winit::window::CursorIcon::NsResize,\n        Interaction::ResizingDiagonallyUp => winit::window::CursorIcon::NeswResize,\n        Interaction::ResizingDiagonallyDown => winit::window::CursorIcon::NwseResize,\n        Interaction::ResizingColumn => winit::window::CursorIcon::ColResize,\n        Interaction::ResizingRow => winit::window::CursorIcon::RowResize,\n        Interaction::AllScroll => winit::window::CursorIcon::AllScroll,\n        Interaction::ZoomIn => winit::window::CursorIcon::ZoomIn,\n        Interaction::ZoomOut => winit::window::CursorIcon::ZoomOut,\n    };\n\n    Some(icon)\n}\n\n/// Converts a `MouseButton` from [`winit`] to an [`iced`] mouse button.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\n/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12\npub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {\n    match mouse_button {\n        winit::event::MouseButton::Left => mouse::Button::Left,\n        winit::event::MouseButton::Right => mouse::Button::Right,\n        winit::event::MouseButton::Middle => mouse::Button::Middle,\n        winit::event::MouseButton::Back => mouse::Button::Back,\n        winit::event::MouseButton::Forward => mouse::Button::Forward,\n        winit::event::MouseButton::Other(other) => mouse::Button::Other(other),\n    }\n}\n\n/// Converts some `ModifiersState` from [`winit`] to an [`iced`] modifiers\n/// state.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\n/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12\npub fn modifiers(modifiers: winit::keyboard::ModifiersState) -> keyboard::Modifiers {\n    let mut result = keyboard::Modifiers::empty();\n\n    result.set(keyboard::Modifiers::SHIFT, modifiers.shift_key());\n    result.set(keyboard::Modifiers::CTRL, modifiers.control_key());\n    result.set(keyboard::Modifiers::ALT, modifiers.alt_key());\n    result.set(keyboard::Modifiers::LOGO, modifiers.super_key());\n\n    result\n}\n\n/// Converts a physical cursor position into a logical `Point`.\npub fn cursor_position(position: winit::dpi::PhysicalPosition<f64>, scale_factor: f32) -> Point {\n    let logical_position = position.to_logical(f64::from(scale_factor));\n\n    Point::new(logical_position.x, logical_position.y)\n}\n\n/// Converts a `Touch` from [`winit`] to an [`iced`] touch event.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\n/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12\npub fn touch_event(touch: winit::event::Touch, scale_factor: f32) -> touch::Event {\n    let id = touch::Finger(touch.id);\n    let position = {\n        let location = touch.location.to_logical::<f64>(f64::from(scale_factor));\n\n        Point::new(location.x as f32, location.y as f32)\n    };\n\n    match touch.phase {\n        winit::event::TouchPhase::Started => touch::Event::FingerPressed { id, position },\n        winit::event::TouchPhase::Moved => touch::Event::FingerMoved { id, position },\n        winit::event::TouchPhase::Ended => touch::Event::FingerLifted { id, position },\n        winit::event::TouchPhase::Cancelled => touch::Event::FingerLost { id, position },\n    }\n}\n\n/// Converts a `Key` from [`winit`] to an [`iced`] key.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\n/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12\npub fn key(key: winit::keyboard::Key) -> keyboard::Key {\n    use keyboard::key::Named;\n    use winit::keyboard::NamedKey;\n\n    match key {\n        winit::keyboard::Key::Character(c) => keyboard::Key::Character(c),\n        winit::keyboard::Key::Named(named_key) => keyboard::Key::Named(match named_key {\n            NamedKey::Alt => Named::Alt,\n            NamedKey::AltGraph => Named::AltGraph,\n            NamedKey::CapsLock => Named::CapsLock,\n            NamedKey::Control => Named::Control,\n            NamedKey::Fn => Named::Fn,\n            NamedKey::FnLock => Named::FnLock,\n            NamedKey::NumLock => Named::NumLock,\n            NamedKey::ScrollLock => Named::ScrollLock,\n            NamedKey::Shift => Named::Shift,\n            NamedKey::Symbol => Named::Symbol,\n            NamedKey::SymbolLock => Named::SymbolLock,\n            NamedKey::Meta => Named::Meta,\n            NamedKey::Hyper => Named::Hyper,\n            NamedKey::Super => Named::Super,\n            NamedKey::Enter => Named::Enter,\n            NamedKey::Tab => Named::Tab,\n            NamedKey::Space => Named::Space,\n            NamedKey::ArrowDown => Named::ArrowDown,\n            NamedKey::ArrowLeft => Named::ArrowLeft,\n            NamedKey::ArrowRight => Named::ArrowRight,\n            NamedKey::ArrowUp => Named::ArrowUp,\n            NamedKey::End => Named::End,\n            NamedKey::Home => Named::Home,\n            NamedKey::PageDown => Named::PageDown,\n            NamedKey::PageUp => Named::PageUp,\n            NamedKey::Backspace => Named::Backspace,\n            NamedKey::Clear => Named::Clear,\n            NamedKey::Copy => Named::Copy,\n            NamedKey::CrSel => Named::CrSel,\n            NamedKey::Cut => Named::Cut,\n            NamedKey::Delete => Named::Delete,\n            NamedKey::EraseEof => Named::EraseEof,\n            NamedKey::ExSel => Named::ExSel,\n            NamedKey::Insert => Named::Insert,\n            NamedKey::Paste => Named::Paste,\n            NamedKey::Redo => Named::Redo,\n            NamedKey::Undo => Named::Undo,\n            NamedKey::Accept => Named::Accept,\n            NamedKey::Again => Named::Again,\n            NamedKey::Attn => Named::Attn,\n            NamedKey::Cancel => Named::Cancel,\n            NamedKey::ContextMenu => Named::ContextMenu,\n            NamedKey::Escape => Named::Escape,\n            NamedKey::Execute => Named::Execute,\n            NamedKey::Find => Named::Find,\n            NamedKey::Help => Named::Help,\n            NamedKey::Pause => Named::Pause,\n            NamedKey::Play => Named::Play,\n            NamedKey::Props => Named::Props,\n            NamedKey::Select => Named::Select,\n            NamedKey::ZoomIn => Named::ZoomIn,\n            NamedKey::ZoomOut => Named::ZoomOut,\n            NamedKey::BrightnessDown => Named::BrightnessDown,\n            NamedKey::BrightnessUp => Named::BrightnessUp,\n            NamedKey::Eject => Named::Eject,\n            NamedKey::LogOff => Named::LogOff,\n            NamedKey::Power => Named::Power,\n            NamedKey::PowerOff => Named::PowerOff,\n            NamedKey::PrintScreen => Named::PrintScreen,\n            NamedKey::Hibernate => Named::Hibernate,\n            NamedKey::Standby => Named::Standby,\n            NamedKey::WakeUp => Named::WakeUp,\n            NamedKey::AllCandidates => Named::AllCandidates,\n            NamedKey::Alphanumeric => Named::Alphanumeric,\n            NamedKey::CodeInput => Named::CodeInput,\n            NamedKey::Compose => Named::Compose,\n            NamedKey::Convert => Named::Convert,\n            NamedKey::FinalMode => Named::FinalMode,\n            NamedKey::GroupFirst => Named::GroupFirst,\n            NamedKey::GroupLast => Named::GroupLast,\n            NamedKey::GroupNext => Named::GroupNext,\n            NamedKey::GroupPrevious => Named::GroupPrevious,\n            NamedKey::ModeChange => Named::ModeChange,\n            NamedKey::NextCandidate => Named::NextCandidate,\n            NamedKey::NonConvert => Named::NonConvert,\n            NamedKey::PreviousCandidate => Named::PreviousCandidate,\n            NamedKey::Process => Named::Process,\n            NamedKey::SingleCandidate => Named::SingleCandidate,\n            NamedKey::HangulMode => Named::HangulMode,\n            NamedKey::HanjaMode => Named::HanjaMode,\n            NamedKey::JunjaMode => Named::JunjaMode,\n            NamedKey::Eisu => Named::Eisu,\n            NamedKey::Hankaku => Named::Hankaku,\n            NamedKey::Hiragana => Named::Hiragana,\n            NamedKey::HiraganaKatakana => Named::HiraganaKatakana,\n            NamedKey::KanaMode => Named::KanaMode,\n            NamedKey::KanjiMode => Named::KanjiMode,\n            NamedKey::Katakana => Named::Katakana,\n            NamedKey::Romaji => Named::Romaji,\n            NamedKey::Zenkaku => Named::Zenkaku,\n            NamedKey::ZenkakuHankaku => Named::ZenkakuHankaku,\n            NamedKey::Soft1 => Named::Soft1,\n            NamedKey::Soft2 => Named::Soft2,\n            NamedKey::Soft3 => Named::Soft3,\n            NamedKey::Soft4 => Named::Soft4,\n            NamedKey::ChannelDown => Named::ChannelDown,\n            NamedKey::ChannelUp => Named::ChannelUp,\n            NamedKey::Close => Named::Close,\n            NamedKey::MailForward => Named::MailForward,\n            NamedKey::MailReply => Named::MailReply,\n            NamedKey::MailSend => Named::MailSend,\n            NamedKey::MediaClose => Named::MediaClose,\n            NamedKey::MediaFastForward => Named::MediaFastForward,\n            NamedKey::MediaPause => Named::MediaPause,\n            NamedKey::MediaPlay => Named::MediaPlay,\n            NamedKey::MediaPlayPause => Named::MediaPlayPause,\n            NamedKey::MediaRecord => Named::MediaRecord,\n            NamedKey::MediaRewind => Named::MediaRewind,\n            NamedKey::MediaStop => Named::MediaStop,\n            NamedKey::MediaTrackNext => Named::MediaTrackNext,\n            NamedKey::MediaTrackPrevious => Named::MediaTrackPrevious,\n            NamedKey::New => Named::New,\n            NamedKey::Open => Named::Open,\n            NamedKey::Print => Named::Print,\n            NamedKey::Save => Named::Save,\n            NamedKey::SpellCheck => Named::SpellCheck,\n            NamedKey::Key11 => Named::Key11,\n            NamedKey::Key12 => Named::Key12,\n            NamedKey::AudioBalanceLeft => Named::AudioBalanceLeft,\n            NamedKey::AudioBalanceRight => Named::AudioBalanceRight,\n            NamedKey::AudioBassBoostDown => Named::AudioBassBoostDown,\n            NamedKey::AudioBassBoostToggle => Named::AudioBassBoostToggle,\n            NamedKey::AudioBassBoostUp => Named::AudioBassBoostUp,\n            NamedKey::AudioFaderFront => Named::AudioFaderFront,\n            NamedKey::AudioFaderRear => Named::AudioFaderRear,\n            NamedKey::AudioSurroundModeNext => Named::AudioSurroundModeNext,\n            NamedKey::AudioTrebleDown => Named::AudioTrebleDown,\n            NamedKey::AudioTrebleUp => Named::AudioTrebleUp,\n            NamedKey::AudioVolumeDown => Named::AudioVolumeDown,\n            NamedKey::AudioVolumeUp => Named::AudioVolumeUp,\n            NamedKey::AudioVolumeMute => Named::AudioVolumeMute,\n            NamedKey::MicrophoneToggle => Named::MicrophoneToggle,\n            NamedKey::MicrophoneVolumeDown => Named::MicrophoneVolumeDown,\n            NamedKey::MicrophoneVolumeUp => Named::MicrophoneVolumeUp,\n            NamedKey::MicrophoneVolumeMute => Named::MicrophoneVolumeMute,\n            NamedKey::SpeechCorrectionList => Named::SpeechCorrectionList,\n            NamedKey::SpeechInputToggle => Named::SpeechInputToggle,\n            NamedKey::LaunchApplication1 => Named::LaunchApplication1,\n            NamedKey::LaunchApplication2 => Named::LaunchApplication2,\n            NamedKey::LaunchCalendar => Named::LaunchCalendar,\n            NamedKey::LaunchContacts => Named::LaunchContacts,\n            NamedKey::LaunchMail => Named::LaunchMail,\n            NamedKey::LaunchMediaPlayer => Named::LaunchMediaPlayer,\n            NamedKey::LaunchMusicPlayer => Named::LaunchMusicPlayer,\n            NamedKey::LaunchPhone => Named::LaunchPhone,\n            NamedKey::LaunchScreenSaver => Named::LaunchScreenSaver,\n            NamedKey::LaunchSpreadsheet => Named::LaunchSpreadsheet,\n            NamedKey::LaunchWebBrowser => Named::LaunchWebBrowser,\n            NamedKey::LaunchWebCam => Named::LaunchWebCam,\n            NamedKey::LaunchWordProcessor => Named::LaunchWordProcessor,\n            NamedKey::BrowserBack => Named::BrowserBack,\n            NamedKey::BrowserFavorites => Named::BrowserFavorites,\n            NamedKey::BrowserForward => Named::BrowserForward,\n            NamedKey::BrowserHome => Named::BrowserHome,\n            NamedKey::BrowserRefresh => Named::BrowserRefresh,\n            NamedKey::BrowserSearch => Named::BrowserSearch,\n            NamedKey::BrowserStop => Named::BrowserStop,\n            NamedKey::AppSwitch => Named::AppSwitch,\n            NamedKey::Call => Named::Call,\n            NamedKey::Camera => Named::Camera,\n            NamedKey::CameraFocus => Named::CameraFocus,\n            NamedKey::EndCall => Named::EndCall,\n            NamedKey::GoBack => Named::GoBack,\n            NamedKey::GoHome => Named::GoHome,\n            NamedKey::HeadsetHook => Named::HeadsetHook,\n            NamedKey::LastNumberRedial => Named::LastNumberRedial,\n            NamedKey::Notification => Named::Notification,\n            NamedKey::MannerMode => Named::MannerMode,\n            NamedKey::VoiceDial => Named::VoiceDial,\n            NamedKey::TV => Named::TV,\n            NamedKey::TV3DMode => Named::TV3DMode,\n            NamedKey::TVAntennaCable => Named::TVAntennaCable,\n            NamedKey::TVAudioDescription => Named::TVAudioDescription,\n            NamedKey::TVAudioDescriptionMixDown => Named::TVAudioDescriptionMixDown,\n            NamedKey::TVAudioDescriptionMixUp => Named::TVAudioDescriptionMixUp,\n            NamedKey::TVContentsMenu => Named::TVContentsMenu,\n            NamedKey::TVDataService => Named::TVDataService,\n            NamedKey::TVInput => Named::TVInput,\n            NamedKey::TVInputComponent1 => Named::TVInputComponent1,\n            NamedKey::TVInputComponent2 => Named::TVInputComponent2,\n            NamedKey::TVInputComposite1 => Named::TVInputComposite1,\n            NamedKey::TVInputComposite2 => Named::TVInputComposite2,\n            NamedKey::TVInputHDMI1 => Named::TVInputHDMI1,\n            NamedKey::TVInputHDMI2 => Named::TVInputHDMI2,\n            NamedKey::TVInputHDMI3 => Named::TVInputHDMI3,\n            NamedKey::TVInputHDMI4 => Named::TVInputHDMI4,\n            NamedKey::TVInputVGA1 => Named::TVInputVGA1,\n            NamedKey::TVMediaContext => Named::TVMediaContext,\n            NamedKey::TVNetwork => Named::TVNetwork,\n            NamedKey::TVNumberEntry => Named::TVNumberEntry,\n            NamedKey::TVPower => Named::TVPower,\n            NamedKey::TVRadioService => Named::TVRadioService,\n            NamedKey::TVSatellite => Named::TVSatellite,\n            NamedKey::TVSatelliteBS => Named::TVSatelliteBS,\n            NamedKey::TVSatelliteCS => Named::TVSatelliteCS,\n            NamedKey::TVSatelliteToggle => Named::TVSatelliteToggle,\n            NamedKey::TVTerrestrialAnalog => Named::TVTerrestrialAnalog,\n            NamedKey::TVTerrestrialDigital => Named::TVTerrestrialDigital,\n            NamedKey::TVTimer => Named::TVTimer,\n            NamedKey::AVRInput => Named::AVRInput,\n            NamedKey::AVRPower => Named::AVRPower,\n            NamedKey::ColorF0Red => Named::ColorF0Red,\n            NamedKey::ColorF1Green => Named::ColorF1Green,\n            NamedKey::ColorF2Yellow => Named::ColorF2Yellow,\n            NamedKey::ColorF3Blue => Named::ColorF3Blue,\n            NamedKey::ColorF4Grey => Named::ColorF4Grey,\n            NamedKey::ColorF5Brown => Named::ColorF5Brown,\n            NamedKey::ClosedCaptionToggle => Named::ClosedCaptionToggle,\n            NamedKey::Dimmer => Named::Dimmer,\n            NamedKey::DisplaySwap => Named::DisplaySwap,\n            NamedKey::DVR => Named::DVR,\n            NamedKey::Exit => Named::Exit,\n            NamedKey::FavoriteClear0 => Named::FavoriteClear0,\n            NamedKey::FavoriteClear1 => Named::FavoriteClear1,\n            NamedKey::FavoriteClear2 => Named::FavoriteClear2,\n            NamedKey::FavoriteClear3 => Named::FavoriteClear3,\n            NamedKey::FavoriteRecall0 => Named::FavoriteRecall0,\n            NamedKey::FavoriteRecall1 => Named::FavoriteRecall1,\n            NamedKey::FavoriteRecall2 => Named::FavoriteRecall2,\n            NamedKey::FavoriteRecall3 => Named::FavoriteRecall3,\n            NamedKey::FavoriteStore0 => Named::FavoriteStore0,\n            NamedKey::FavoriteStore1 => Named::FavoriteStore1,\n            NamedKey::FavoriteStore2 => Named::FavoriteStore2,\n            NamedKey::FavoriteStore3 => Named::FavoriteStore3,\n            NamedKey::Guide => Named::Guide,\n            NamedKey::GuideNextDay => Named::GuideNextDay,\n            NamedKey::GuidePreviousDay => Named::GuidePreviousDay,\n            NamedKey::Info => Named::Info,\n            NamedKey::InstantReplay => Named::InstantReplay,\n            NamedKey::Link => Named::Link,\n            NamedKey::ListProgram => Named::ListProgram,\n            NamedKey::LiveContent => Named::LiveContent,\n            NamedKey::Lock => Named::Lock,\n            NamedKey::MediaApps => Named::MediaApps,\n            NamedKey::MediaAudioTrack => Named::MediaAudioTrack,\n            NamedKey::MediaLast => Named::MediaLast,\n            NamedKey::MediaSkipBackward => Named::MediaSkipBackward,\n            NamedKey::MediaSkipForward => Named::MediaSkipForward,\n            NamedKey::MediaStepBackward => Named::MediaStepBackward,\n            NamedKey::MediaStepForward => Named::MediaStepForward,\n            NamedKey::MediaTopMenu => Named::MediaTopMenu,\n            NamedKey::NavigateIn => Named::NavigateIn,\n            NamedKey::NavigateNext => Named::NavigateNext,\n            NamedKey::NavigateOut => Named::NavigateOut,\n            NamedKey::NavigatePrevious => Named::NavigatePrevious,\n            NamedKey::NextFavoriteChannel => Named::NextFavoriteChannel,\n            NamedKey::NextUserProfile => Named::NextUserProfile,\n            NamedKey::OnDemand => Named::OnDemand,\n            NamedKey::Pairing => Named::Pairing,\n            NamedKey::PinPDown => Named::PinPDown,\n            NamedKey::PinPMove => Named::PinPMove,\n            NamedKey::PinPToggle => Named::PinPToggle,\n            NamedKey::PinPUp => Named::PinPUp,\n            NamedKey::PlaySpeedDown => Named::PlaySpeedDown,\n            NamedKey::PlaySpeedReset => Named::PlaySpeedReset,\n            NamedKey::PlaySpeedUp => Named::PlaySpeedUp,\n            NamedKey::RandomToggle => Named::RandomToggle,\n            NamedKey::RcLowBattery => Named::RcLowBattery,\n            NamedKey::RecordSpeedNext => Named::RecordSpeedNext,\n            NamedKey::RfBypass => Named::RfBypass,\n            NamedKey::ScanChannelsToggle => Named::ScanChannelsToggle,\n            NamedKey::ScreenModeNext => Named::ScreenModeNext,\n            NamedKey::Settings => Named::Settings,\n            NamedKey::SplitScreenToggle => Named::SplitScreenToggle,\n            NamedKey::STBInput => Named::STBInput,\n            NamedKey::STBPower => Named::STBPower,\n            NamedKey::Subtitle => Named::Subtitle,\n            NamedKey::Teletext => Named::Teletext,\n            NamedKey::VideoModeNext => Named::VideoModeNext,\n            NamedKey::Wink => Named::Wink,\n            NamedKey::ZoomToggle => Named::ZoomToggle,\n            NamedKey::F1 => Named::F1,\n            NamedKey::F2 => Named::F2,\n            NamedKey::F3 => Named::F3,\n            NamedKey::F4 => Named::F4,\n            NamedKey::F5 => Named::F5,\n            NamedKey::F6 => Named::F6,\n            NamedKey::F7 => Named::F7,\n            NamedKey::F8 => Named::F8,\n            NamedKey::F9 => Named::F9,\n            NamedKey::F10 => Named::F10,\n            NamedKey::F11 => Named::F11,\n            NamedKey::F12 => Named::F12,\n            NamedKey::F13 => Named::F13,\n            NamedKey::F14 => Named::F14,\n            NamedKey::F15 => Named::F15,\n            NamedKey::F16 => Named::F16,\n            NamedKey::F17 => Named::F17,\n            NamedKey::F18 => Named::F18,\n            NamedKey::F19 => Named::F19,\n            NamedKey::F20 => Named::F20,\n            NamedKey::F21 => Named::F21,\n            NamedKey::F22 => Named::F22,\n            NamedKey::F23 => Named::F23,\n            NamedKey::F24 => Named::F24,\n            NamedKey::F25 => Named::F25,\n            NamedKey::F26 => Named::F26,\n            NamedKey::F27 => Named::F27,\n            NamedKey::F28 => Named::F28,\n            NamedKey::F29 => Named::F29,\n            NamedKey::F30 => Named::F30,\n            NamedKey::F31 => Named::F31,\n            NamedKey::F32 => Named::F32,\n            NamedKey::F33 => Named::F33,\n            NamedKey::F34 => Named::F34,\n            NamedKey::F35 => Named::F35,\n            _ => return keyboard::Key::Unidentified,\n        }),\n        _ => keyboard::Key::Unidentified,\n    }\n}\n\n/// Converts a `PhysicalKey` from [`winit`] to an [`iced`] physical key.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\n/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12\npub fn physical_key(physical_key: winit::keyboard::PhysicalKey) -> keyboard::key::Physical {\n    match physical_key {\n        winit::keyboard::PhysicalKey::Code(code) => {\n            key_code(code).map(keyboard::key::Physical::Code).unwrap_or(\n                keyboard::key::Physical::Unidentified(keyboard::key::NativeCode::Unidentified),\n            )\n        }\n        winit::keyboard::PhysicalKey::Unidentified(code) => {\n            keyboard::key::Physical::Unidentified(native_key_code(code))\n        }\n    }\n}\n\n/// Converts a `KeyCode` from [`winit`] to an [`iced`] key code.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\n/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12\npub fn key_code(key_code: winit::keyboard::KeyCode) -> Option<keyboard::key::Code> {\n    use winit::keyboard::KeyCode;\n\n    Some(match key_code {\n        KeyCode::Backquote => keyboard::key::Code::Backquote,\n        KeyCode::Backslash => keyboard::key::Code::Backslash,\n        KeyCode::BracketLeft => keyboard::key::Code::BracketLeft,\n        KeyCode::BracketRight => keyboard::key::Code::BracketRight,\n        KeyCode::Comma => keyboard::key::Code::Comma,\n        KeyCode::Digit0 => keyboard::key::Code::Digit0,\n        KeyCode::Digit1 => keyboard::key::Code::Digit1,\n        KeyCode::Digit2 => keyboard::key::Code::Digit2,\n        KeyCode::Digit3 => keyboard::key::Code::Digit3,\n        KeyCode::Digit4 => keyboard::key::Code::Digit4,\n        KeyCode::Digit5 => keyboard::key::Code::Digit5,\n        KeyCode::Digit6 => keyboard::key::Code::Digit6,\n        KeyCode::Digit7 => keyboard::key::Code::Digit7,\n        KeyCode::Digit8 => keyboard::key::Code::Digit8,\n        KeyCode::Digit9 => keyboard::key::Code::Digit9,\n        KeyCode::Equal => keyboard::key::Code::Equal,\n        KeyCode::IntlBackslash => keyboard::key::Code::IntlBackslash,\n        KeyCode::IntlRo => keyboard::key::Code::IntlRo,\n        KeyCode::IntlYen => keyboard::key::Code::IntlYen,\n        KeyCode::KeyA => keyboard::key::Code::KeyA,\n        KeyCode::KeyB => keyboard::key::Code::KeyB,\n        KeyCode::KeyC => keyboard::key::Code::KeyC,\n        KeyCode::KeyD => keyboard::key::Code::KeyD,\n        KeyCode::KeyE => keyboard::key::Code::KeyE,\n        KeyCode::KeyF => keyboard::key::Code::KeyF,\n        KeyCode::KeyG => keyboard::key::Code::KeyG,\n        KeyCode::KeyH => keyboard::key::Code::KeyH,\n        KeyCode::KeyI => keyboard::key::Code::KeyI,\n        KeyCode::KeyJ => keyboard::key::Code::KeyJ,\n        KeyCode::KeyK => keyboard::key::Code::KeyK,\n        KeyCode::KeyL => keyboard::key::Code::KeyL,\n        KeyCode::KeyM => keyboard::key::Code::KeyM,\n        KeyCode::KeyN => keyboard::key::Code::KeyN,\n        KeyCode::KeyO => keyboard::key::Code::KeyO,\n        KeyCode::KeyP => keyboard::key::Code::KeyP,\n        KeyCode::KeyQ => keyboard::key::Code::KeyQ,\n        KeyCode::KeyR => keyboard::key::Code::KeyR,\n        KeyCode::KeyS => keyboard::key::Code::KeyS,\n        KeyCode::KeyT => keyboard::key::Code::KeyT,\n        KeyCode::KeyU => keyboard::key::Code::KeyU,\n        KeyCode::KeyV => keyboard::key::Code::KeyV,\n        KeyCode::KeyW => keyboard::key::Code::KeyW,\n        KeyCode::KeyX => keyboard::key::Code::KeyX,\n        KeyCode::KeyY => keyboard::key::Code::KeyY,\n        KeyCode::KeyZ => keyboard::key::Code::KeyZ,\n        KeyCode::Minus => keyboard::key::Code::Minus,\n        KeyCode::Period => keyboard::key::Code::Period,\n        KeyCode::Quote => keyboard::key::Code::Quote,\n        KeyCode::Semicolon => keyboard::key::Code::Semicolon,\n        KeyCode::Slash => keyboard::key::Code::Slash,\n        KeyCode::AltLeft => keyboard::key::Code::AltLeft,\n        KeyCode::AltRight => keyboard::key::Code::AltRight,\n        KeyCode::Backspace => keyboard::key::Code::Backspace,\n        KeyCode::CapsLock => keyboard::key::Code::CapsLock,\n        KeyCode::ContextMenu => keyboard::key::Code::ContextMenu,\n        KeyCode::ControlLeft => keyboard::key::Code::ControlLeft,\n        KeyCode::ControlRight => keyboard::key::Code::ControlRight,\n        KeyCode::Enter => keyboard::key::Code::Enter,\n        KeyCode::SuperLeft => keyboard::key::Code::SuperLeft,\n        KeyCode::SuperRight => keyboard::key::Code::SuperRight,\n        KeyCode::ShiftLeft => keyboard::key::Code::ShiftLeft,\n        KeyCode::ShiftRight => keyboard::key::Code::ShiftRight,\n        KeyCode::Space => keyboard::key::Code::Space,\n        KeyCode::Tab => keyboard::key::Code::Tab,\n        KeyCode::Convert => keyboard::key::Code::Convert,\n        KeyCode::KanaMode => keyboard::key::Code::KanaMode,\n        KeyCode::Lang1 => keyboard::key::Code::Lang1,\n        KeyCode::Lang2 => keyboard::key::Code::Lang2,\n        KeyCode::Lang3 => keyboard::key::Code::Lang3,\n        KeyCode::Lang4 => keyboard::key::Code::Lang4,\n        KeyCode::Lang5 => keyboard::key::Code::Lang5,\n        KeyCode::NonConvert => keyboard::key::Code::NonConvert,\n        KeyCode::Delete => keyboard::key::Code::Delete,\n        KeyCode::End => keyboard::key::Code::End,\n        KeyCode::Help => keyboard::key::Code::Help,\n        KeyCode::Home => keyboard::key::Code::Home,\n        KeyCode::Insert => keyboard::key::Code::Insert,\n        KeyCode::PageDown => keyboard::key::Code::PageDown,\n        KeyCode::PageUp => keyboard::key::Code::PageUp,\n        KeyCode::ArrowDown => keyboard::key::Code::ArrowDown,\n        KeyCode::ArrowLeft => keyboard::key::Code::ArrowLeft,\n        KeyCode::ArrowRight => keyboard::key::Code::ArrowRight,\n        KeyCode::ArrowUp => keyboard::key::Code::ArrowUp,\n        KeyCode::NumLock => keyboard::key::Code::NumLock,\n        KeyCode::Numpad0 => keyboard::key::Code::Numpad0,\n        KeyCode::Numpad1 => keyboard::key::Code::Numpad1,\n        KeyCode::Numpad2 => keyboard::key::Code::Numpad2,\n        KeyCode::Numpad3 => keyboard::key::Code::Numpad3,\n        KeyCode::Numpad4 => keyboard::key::Code::Numpad4,\n        KeyCode::Numpad5 => keyboard::key::Code::Numpad5,\n        KeyCode::Numpad6 => keyboard::key::Code::Numpad6,\n        KeyCode::Numpad7 => keyboard::key::Code::Numpad7,\n        KeyCode::Numpad8 => keyboard::key::Code::Numpad8,\n        KeyCode::Numpad9 => keyboard::key::Code::Numpad9,\n        KeyCode::NumpadAdd => keyboard::key::Code::NumpadAdd,\n        KeyCode::NumpadBackspace => keyboard::key::Code::NumpadBackspace,\n        KeyCode::NumpadClear => keyboard::key::Code::NumpadClear,\n        KeyCode::NumpadClearEntry => keyboard::key::Code::NumpadClearEntry,\n        KeyCode::NumpadComma => keyboard::key::Code::NumpadComma,\n        KeyCode::NumpadDecimal => keyboard::key::Code::NumpadDecimal,\n        KeyCode::NumpadDivide => keyboard::key::Code::NumpadDivide,\n        KeyCode::NumpadEnter => keyboard::key::Code::NumpadEnter,\n        KeyCode::NumpadEqual => keyboard::key::Code::NumpadEqual,\n        KeyCode::NumpadHash => keyboard::key::Code::NumpadHash,\n        KeyCode::NumpadMemoryAdd => keyboard::key::Code::NumpadMemoryAdd,\n        KeyCode::NumpadMemoryClear => keyboard::key::Code::NumpadMemoryClear,\n        KeyCode::NumpadMemoryRecall => keyboard::key::Code::NumpadMemoryRecall,\n        KeyCode::NumpadMemoryStore => keyboard::key::Code::NumpadMemoryStore,\n        KeyCode::NumpadMemorySubtract => keyboard::key::Code::NumpadMemorySubtract,\n        KeyCode::NumpadMultiply => keyboard::key::Code::NumpadMultiply,\n        KeyCode::NumpadParenLeft => keyboard::key::Code::NumpadParenLeft,\n        KeyCode::NumpadParenRight => keyboard::key::Code::NumpadParenRight,\n        KeyCode::NumpadStar => keyboard::key::Code::NumpadStar,\n        KeyCode::NumpadSubtract => keyboard::key::Code::NumpadSubtract,\n        KeyCode::Escape => keyboard::key::Code::Escape,\n        KeyCode::Fn => keyboard::key::Code::Fn,\n        KeyCode::FnLock => keyboard::key::Code::FnLock,\n        KeyCode::PrintScreen => keyboard::key::Code::PrintScreen,\n        KeyCode::ScrollLock => keyboard::key::Code::ScrollLock,\n        KeyCode::Pause => keyboard::key::Code::Pause,\n        KeyCode::BrowserBack => keyboard::key::Code::BrowserBack,\n        KeyCode::BrowserFavorites => keyboard::key::Code::BrowserFavorites,\n        KeyCode::BrowserForward => keyboard::key::Code::BrowserForward,\n        KeyCode::BrowserHome => keyboard::key::Code::BrowserHome,\n        KeyCode::BrowserRefresh => keyboard::key::Code::BrowserRefresh,\n        KeyCode::BrowserSearch => keyboard::key::Code::BrowserSearch,\n        KeyCode::BrowserStop => keyboard::key::Code::BrowserStop,\n        KeyCode::Eject => keyboard::key::Code::Eject,\n        KeyCode::LaunchApp1 => keyboard::key::Code::LaunchApp1,\n        KeyCode::LaunchApp2 => keyboard::key::Code::LaunchApp2,\n        KeyCode::LaunchMail => keyboard::key::Code::LaunchMail,\n        KeyCode::MediaPlayPause => keyboard::key::Code::MediaPlayPause,\n        KeyCode::MediaSelect => keyboard::key::Code::MediaSelect,\n        KeyCode::MediaStop => keyboard::key::Code::MediaStop,\n        KeyCode::MediaTrackNext => keyboard::key::Code::MediaTrackNext,\n        KeyCode::MediaTrackPrevious => keyboard::key::Code::MediaTrackPrevious,\n        KeyCode::Power => keyboard::key::Code::Power,\n        KeyCode::Sleep => keyboard::key::Code::Sleep,\n        KeyCode::AudioVolumeDown => keyboard::key::Code::AudioVolumeDown,\n        KeyCode::AudioVolumeMute => keyboard::key::Code::AudioVolumeMute,\n        KeyCode::AudioVolumeUp => keyboard::key::Code::AudioVolumeUp,\n        KeyCode::WakeUp => keyboard::key::Code::WakeUp,\n        KeyCode::Meta => keyboard::key::Code::Meta,\n        KeyCode::Hyper => keyboard::key::Code::Hyper,\n        KeyCode::Turbo => keyboard::key::Code::Turbo,\n        KeyCode::Abort => keyboard::key::Code::Abort,\n        KeyCode::Resume => keyboard::key::Code::Resume,\n        KeyCode::Suspend => keyboard::key::Code::Suspend,\n        KeyCode::Again => keyboard::key::Code::Again,\n        KeyCode::Copy => keyboard::key::Code::Copy,\n        KeyCode::Cut => keyboard::key::Code::Cut,\n        KeyCode::Find => keyboard::key::Code::Find,\n        KeyCode::Open => keyboard::key::Code::Open,\n        KeyCode::Paste => keyboard::key::Code::Paste,\n        KeyCode::Props => keyboard::key::Code::Props,\n        KeyCode::Select => keyboard::key::Code::Select,\n        KeyCode::Undo => keyboard::key::Code::Undo,\n        KeyCode::Hiragana => keyboard::key::Code::Hiragana,\n        KeyCode::Katakana => keyboard::key::Code::Katakana,\n        KeyCode::F1 => keyboard::key::Code::F1,\n        KeyCode::F2 => keyboard::key::Code::F2,\n        KeyCode::F3 => keyboard::key::Code::F3,\n        KeyCode::F4 => keyboard::key::Code::F4,\n        KeyCode::F5 => keyboard::key::Code::F5,\n        KeyCode::F6 => keyboard::key::Code::F6,\n        KeyCode::F7 => keyboard::key::Code::F7,\n        KeyCode::F8 => keyboard::key::Code::F8,\n        KeyCode::F9 => keyboard::key::Code::F9,\n        KeyCode::F10 => keyboard::key::Code::F10,\n        KeyCode::F11 => keyboard::key::Code::F11,\n        KeyCode::F12 => keyboard::key::Code::F12,\n        KeyCode::F13 => keyboard::key::Code::F13,\n        KeyCode::F14 => keyboard::key::Code::F14,\n        KeyCode::F15 => keyboard::key::Code::F15,\n        KeyCode::F16 => keyboard::key::Code::F16,\n        KeyCode::F17 => keyboard::key::Code::F17,\n        KeyCode::F18 => keyboard::key::Code::F18,\n        KeyCode::F19 => keyboard::key::Code::F19,\n        KeyCode::F20 => keyboard::key::Code::F20,\n        KeyCode::F21 => keyboard::key::Code::F21,\n        KeyCode::F22 => keyboard::key::Code::F22,\n        KeyCode::F23 => keyboard::key::Code::F23,\n        KeyCode::F24 => keyboard::key::Code::F24,\n        KeyCode::F25 => keyboard::key::Code::F25,\n        KeyCode::F26 => keyboard::key::Code::F26,\n        KeyCode::F27 => keyboard::key::Code::F27,\n        KeyCode::F28 => keyboard::key::Code::F28,\n        KeyCode::F29 => keyboard::key::Code::F29,\n        KeyCode::F30 => keyboard::key::Code::F30,\n        KeyCode::F31 => keyboard::key::Code::F31,\n        KeyCode::F32 => keyboard::key::Code::F32,\n        KeyCode::F33 => keyboard::key::Code::F33,\n        KeyCode::F34 => keyboard::key::Code::F34,\n        KeyCode::F35 => keyboard::key::Code::F35,\n        _ => None?,\n    })\n}\n\n/// Converts a `NativeKeyCode` from [`winit`] to an [`iced`] native key code.\n///\n/// [`winit`]: https://github.com/rust-windowing/winit\n/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12\npub fn native_key_code(\n    native_key_code: winit::keyboard::NativeKeyCode,\n) -> keyboard::key::NativeCode {\n    use winit::keyboard::NativeKeyCode;\n\n    match native_key_code {\n        NativeKeyCode::Unidentified => keyboard::key::NativeCode::Unidentified,\n        NativeKeyCode::Android(code) => keyboard::key::NativeCode::Android(code),\n        NativeKeyCode::MacOS(code) => keyboard::key::NativeCode::MacOS(code),\n        NativeKeyCode::Windows(code) => keyboard::key::NativeCode::Windows(code),\n        NativeKeyCode::Xkb(code) => keyboard::key::NativeCode::Xkb(code),\n    }\n}\n\n/// Converts some [`UserAttention`] into its `winit` counterpart.\n///\n/// [`UserAttention`]: window::UserAttention\npub fn user_attention(user_attention: window::UserAttention) -> winit::window::UserAttentionType {\n    match user_attention {\n        window::UserAttention::Critical => winit::window::UserAttentionType::Critical,\n        window::UserAttention::Informational => winit::window::UserAttentionType::Informational,\n    }\n}\n\n/// Converts some [`window::Direction`] into a [`winit::window::ResizeDirection`].\npub fn resize_direction(resize_direction: window::Direction) -> winit::window::ResizeDirection {\n    match resize_direction {\n        window::Direction::North => winit::window::ResizeDirection::North,\n        window::Direction::South => winit::window::ResizeDirection::South,\n        window::Direction::East => winit::window::ResizeDirection::East,\n        window::Direction::West => winit::window::ResizeDirection::West,\n        window::Direction::NorthEast => winit::window::ResizeDirection::NorthEast,\n        window::Direction::NorthWest => winit::window::ResizeDirection::NorthWest,\n        window::Direction::SouthEast => winit::window::ResizeDirection::SouthEast,\n        window::Direction::SouthWest => winit::window::ResizeDirection::SouthWest,\n    }\n}\n\n/// Converts some [`window::Icon`] into its `winit` counterpart.\n///\n/// Returns `None` if there is an error during the conversion.\npub fn icon(icon: window::Icon) -> Option<winit::window::Icon> {\n    let (pixels, size) = icon.into_raw();\n\n    winit::window::Icon::from_rgba(pixels, size.width, size.height).ok()\n}\n\n/// Converts some [`input_method::Purpose`] into its `winit` counterpart.\npub fn ime_purpose(purpose: input_method::Purpose) -> winit::window::ImePurpose {\n    match purpose {\n        input_method::Purpose::Normal => winit::window::ImePurpose::Normal,\n        input_method::Purpose::Secure => winit::window::ImePurpose::Password,\n        input_method::Purpose::Terminal => winit::window::ImePurpose::Terminal,\n    }\n}\n\n// See: https://en.wikipedia.org/wiki/Private_Use_Areas\nfn is_private_use(c: char) -> bool {\n    ('\\u{E000}'..='\\u{F8FF}').contains(&c)\n}\n"
  },
  {
    "path": "winit/src/error.rs",
    "content": "use crate::futures::futures;\nuse crate::graphics;\n\n/// An error that occurred while running an application.\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    /// The futures executor could not be created.\n    #[error(\"the futures executor could not be created\")]\n    ExecutorCreationFailed(futures::io::Error),\n\n    /// The application window could not be created.\n    #[error(\"the application window could not be created\")]\n    WindowCreationFailed(winit::error::OsError),\n\n    /// The application graphics context could not be created.\n    #[error(\"the application graphics context could not be created\")]\n    GraphicsCreationFailed(graphics::Error),\n}\n\nimpl From<graphics::Error> for Error {\n    fn from(error: graphics::Error) -> Error {\n        Error::GraphicsCreationFailed(error)\n    }\n}\n"
  },
  {
    "path": "winit/src/lib.rs",
    "content": "//! A windowing shell for Iced, on top of [`winit`].\n//!\n//! ![The native path of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)\n//!\n//! `iced_winit` offers some convenient abstractions on top of [`iced_runtime`]\n//! to quickstart development when using [`winit`].\n//!\n//! It exposes a renderer-agnostic [`Program`] trait that can be implemented\n//! and then run with a simple call. The use of this trait is optional.\n//!\n//! Additionally, a [`conversion`] module is available for users that decide to\n//! implement a custom event loop.\n//!\n//! [`iced_runtime`]: https://github.com/iced-rs/iced/tree/master/runtime\n//! [`winit`]: https://github.com/rust-windowing/winit\n//! [`conversion`]: crate::conversion\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg\"\n)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\npub use iced_debug as debug;\npub use iced_program as program;\npub use iced_runtime as runtime;\npub use program::core;\npub use program::graphics;\npub use runtime::futures;\npub use winit;\n\npub mod clipboard;\npub mod conversion;\n\nmod error;\nmod proxy;\nmod window;\n\npub use clipboard::Clipboard;\npub use error::Error;\npub use proxy::Proxy;\n\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::theme;\nuse crate::core::time::Instant;\nuse crate::core::widget::operation;\nuse crate::core::{Point, Renderer, Size};\nuse crate::futures::futures::channel::mpsc;\nuse crate::futures::futures::channel::oneshot;\nuse crate::futures::futures::task;\nuse crate::futures::futures::{Future, StreamExt};\nuse crate::futures::subscription;\nuse crate::futures::{Executor, Runtime};\nuse crate::graphics::{Compositor, Shell, compositor};\nuse crate::runtime::font;\nuse crate::runtime::image;\nuse crate::runtime::system;\nuse crate::runtime::user_interface::{self, UserInterface};\nuse crate::runtime::{Action, Task};\n\nuse program::Program;\nuse window::WindowManager;\n\nuse rustc_hash::FxHashMap;\nuse std::borrow::Cow;\nuse std::mem::ManuallyDrop;\nuse std::slice;\nuse std::sync::Arc;\n\n/// Runs a [`Program`] with the provided settings.\npub fn run<P>(program: P) -> Result<(), Error>\nwhere\n    P: Program + 'static,\n    P::Theme: theme::Base,\n{\n    use winit::event_loop::EventLoop;\n\n    let boot_span = debug::boot();\n    let settings = program.settings();\n    let window_settings = program.window();\n\n    let event_loop = EventLoop::with_user_event()\n        .build()\n        .expect(\"Create event loop\");\n\n    let compositor_settings = compositor::Settings::from(&settings);\n    let renderer_settings = renderer::Settings::from(&settings);\n    let display_handle = event_loop.owned_display_handle();\n\n    let (proxy, worker) = Proxy::new(event_loop.create_proxy());\n\n    #[cfg(feature = \"debug\")]\n    {\n        let proxy = proxy.clone();\n\n        debug::on_hotpatch(move || {\n            proxy.send_action(Action::Reload);\n        });\n    }\n\n    let mut runtime = {\n        let executor = P::Executor::new().map_err(Error::ExecutorCreationFailed)?;\n        executor.spawn(worker);\n\n        Runtime::new(executor, proxy.clone())\n    };\n\n    let (program, task) = runtime.enter(|| program::Instance::new(program));\n    let is_daemon = window_settings.is_none();\n\n    let task = if let Some(window_settings) = window_settings {\n        let mut task = Some(task);\n\n        let (_id, open) = runtime::window::open(window_settings);\n\n        open.then(move |_| task.take().unwrap_or_else(Task::none))\n    } else {\n        task\n    };\n\n    if let Some(stream) = runtime::task::into_stream(task) {\n        runtime.run(stream);\n    }\n\n    runtime.track(subscription::into_recipes(\n        runtime.enter(|| program.subscription().map(Action::Output)),\n    ));\n\n    let (event_sender, event_receiver) = mpsc::unbounded();\n    let (control_sender, control_receiver) = mpsc::unbounded();\n    let (system_theme_sender, system_theme_receiver) = oneshot::channel();\n\n    let instance = Box::pin(run_instance::<P>(\n        program,\n        runtime,\n        proxy.clone(),\n        event_receiver,\n        control_sender,\n        display_handle,\n        is_daemon,\n        compositor_settings,\n        renderer_settings,\n        settings.fonts,\n        system_theme_receiver,\n    ));\n\n    let context = task::Context::from_waker(task::noop_waker_ref());\n\n    struct Runner<Message: 'static, F> {\n        instance: std::pin::Pin<Box<F>>,\n        context: task::Context<'static>,\n        id: Option<String>,\n        sender: mpsc::UnboundedSender<Event<Action<Message>>>,\n        receiver: mpsc::UnboundedReceiver<Control>,\n        error: Option<Error>,\n        system_theme: Option<oneshot::Sender<theme::Mode>>,\n\n        #[cfg(target_arch = \"wasm32\")]\n        canvas: Option<web_sys::HtmlCanvasElement>,\n    }\n\n    let runner = Runner {\n        instance,\n        context,\n        id: settings.id,\n        sender: event_sender,\n        receiver: control_receiver,\n        error: None,\n        system_theme: Some(system_theme_sender),\n\n        #[cfg(target_arch = \"wasm32\")]\n        canvas: None,\n    };\n\n    boot_span.finish();\n\n    impl<Message, F> winit::application::ApplicationHandler<Action<Message>> for Runner<Message, F>\n    where\n        F: Future<Output = ()>,\n    {\n        fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {\n            if let Some(sender) = self.system_theme.take() {\n                let _ = sender.send(\n                    event_loop\n                        .system_theme()\n                        .map(conversion::theme_mode)\n                        .unwrap_or_default(),\n                );\n            }\n        }\n\n        fn new_events(\n            &mut self,\n            event_loop: &winit::event_loop::ActiveEventLoop,\n            cause: winit::event::StartCause,\n        ) {\n            self.process_event(\n                event_loop,\n                Event::EventLoopAwakened(winit::event::Event::NewEvents(cause)),\n            );\n        }\n\n        fn window_event(\n            &mut self,\n            event_loop: &winit::event_loop::ActiveEventLoop,\n            window_id: winit::window::WindowId,\n            event: winit::event::WindowEvent,\n        ) {\n            #[cfg(target_os = \"windows\")]\n            let is_move_or_resize = matches!(\n                event,\n                winit::event::WindowEvent::Resized(_) | winit::event::WindowEvent::Moved(_)\n            );\n\n            self.process_event(\n                event_loop,\n                Event::EventLoopAwakened(winit::event::Event::WindowEvent { window_id, event }),\n            );\n\n            // TODO: Remove when unnecessary\n            // On Windows, we emulate an `AboutToWait` event after every `Resized` event\n            // since the event loop does not resume during resize interaction.\n            // More details: https://github.com/rust-windowing/winit/issues/3272\n            #[cfg(target_os = \"windows\")]\n            {\n                if is_move_or_resize {\n                    self.process_event(\n                        event_loop,\n                        Event::EventLoopAwakened(winit::event::Event::AboutToWait),\n                    );\n                }\n            }\n        }\n\n        fn user_event(\n            &mut self,\n            event_loop: &winit::event_loop::ActiveEventLoop,\n            action: Action<Message>,\n        ) {\n            self.process_event(\n                event_loop,\n                Event::EventLoopAwakened(winit::event::Event::UserEvent(action)),\n            );\n        }\n\n        fn received_url(&mut self, event_loop: &winit::event_loop::ActiveEventLoop, url: String) {\n            self.process_event(\n                event_loop,\n                Event::EventLoopAwakened(winit::event::Event::PlatformSpecific(\n                    winit::event::PlatformSpecific::MacOS(winit::event::MacOS::ReceivedUrl(url)),\n                )),\n            );\n        }\n\n        fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {\n            self.process_event(\n                event_loop,\n                Event::EventLoopAwakened(winit::event::Event::AboutToWait),\n            );\n        }\n    }\n\n    impl<Message, F> Runner<Message, F>\n    where\n        F: Future<Output = ()>,\n    {\n        fn process_event(\n            &mut self,\n            event_loop: &winit::event_loop::ActiveEventLoop,\n            event: Event<Action<Message>>,\n        ) {\n            if event_loop.exiting() {\n                return;\n            }\n\n            self.sender.start_send(event).expect(\"Send event\");\n\n            loop {\n                let poll = self.instance.as_mut().poll(&mut self.context);\n\n                match poll {\n                    task::Poll::Pending => match self.receiver.try_recv() {\n                        Ok(control) => match control {\n                            Control::ChangeFlow(flow) => {\n                                use winit::event_loop::ControlFlow;\n\n                                match (event_loop.control_flow(), flow) {\n                                    (\n                                        ControlFlow::WaitUntil(current),\n                                        ControlFlow::WaitUntil(new),\n                                    ) if current < new => {}\n                                    (ControlFlow::WaitUntil(target), ControlFlow::Wait)\n                                        if target > Instant::now() => {}\n                                    _ => {\n                                        event_loop.set_control_flow(flow);\n                                    }\n                                }\n                            }\n                            Control::CreateWindow {\n                                id,\n                                settings,\n                                title,\n                                scale_factor,\n                                monitor,\n                                on_open,\n                            } => {\n                                let exit_on_close_request = settings.exit_on_close_request;\n\n                                let visible = settings.visible;\n\n                                #[cfg(target_arch = \"wasm32\")]\n                                let target = settings.platform_specific.target.clone();\n\n                                let window_attributes = conversion::window_attributes(\n                                    settings,\n                                    &title,\n                                    scale_factor,\n                                    monitor.or(event_loop.primary_monitor()),\n                                    self.id.clone(),\n                                )\n                                .with_visible(false);\n\n                                #[cfg(target_arch = \"wasm32\")]\n                                let window_attributes = {\n                                    use winit::platform::web::WindowAttributesExtWebSys;\n                                    window_attributes.with_canvas(self.canvas.take())\n                                };\n\n                                log::info!(\n                                    \"Window attributes for id `{id:#?}`: {window_attributes:#?}\"\n                                );\n\n                                // On macOS, the `position` in `WindowAttributes` represents the \"inner\"\n                                // position of the window; while on other platforms it's the \"outer\" position.\n                                // We fix the inconsistency on macOS by positioning the window after creation.\n                                #[cfg(target_os = \"macos\")]\n                                let mut window_attributes = window_attributes;\n\n                                #[cfg(target_os = \"macos\")]\n                                let position = window_attributes.position.take();\n\n                                let window = event_loop\n                                    .create_window(window_attributes)\n                                    .expect(\"Create window\");\n\n                                #[cfg(target_os = \"macos\")]\n                                if let Some(position) = position {\n                                    window.set_outer_position(position);\n                                }\n\n                                #[cfg(target_arch = \"wasm32\")]\n                                {\n                                    use winit::platform::web::WindowExtWebSys;\n\n                                    let canvas = window.canvas().expect(\"Get window canvas\");\n\n                                    let _ = canvas.set_attribute(\n                                        \"style\",\n                                        \"display: block; width: 100%; height: 100%\",\n                                    );\n\n                                    let window = web_sys::window().unwrap();\n                                    let document = window.document().unwrap();\n                                    let body = document.body().unwrap();\n\n                                    let target = target.and_then(|target| {\n                                        body.query_selector(&format!(\"#{target}\"))\n                                            .ok()\n                                            .unwrap_or(None)\n                                    });\n\n                                    match target {\n                                        Some(node) => {\n                                            let _ = node.replace_with_with_node_1(&canvas).expect(\n                                                &format!(\"Could not replace #{}\", node.id()),\n                                            );\n                                        }\n                                        None => {\n                                            let _ = body\n                                                .append_child(&canvas)\n                                                .expect(\"Append canvas to HTML body\");\n                                        }\n                                    };\n                                }\n\n                                self.process_event(\n                                    event_loop,\n                                    Event::WindowCreated {\n                                        id,\n                                        window: Arc::new(window),\n                                        exit_on_close_request,\n                                        make_visible: visible,\n                                        on_open,\n                                    },\n                                );\n                            }\n                            Control::Exit => {\n                                self.process_event(event_loop, Event::Exit);\n                                event_loop.exit();\n                                break;\n                            }\n                            Control::Crash(error) => {\n                                self.error = Some(error);\n                                event_loop.exit();\n                            }\n                            Control::SetAutomaticWindowTabbing(_enabled) => {\n                                #[cfg(target_os = \"macos\")]\n                                {\n                                    use winit::platform::macos::ActiveEventLoopExtMacOS;\n                                    event_loop.set_allows_automatic_window_tabbing(_enabled);\n                                }\n                            }\n                        },\n                        _ => {\n                            break;\n                        }\n                    },\n                    task::Poll::Ready(_) => {\n                        event_loop.exit();\n                        break;\n                    }\n                };\n            }\n        }\n    }\n\n    #[cfg(not(target_arch = \"wasm32\"))]\n    {\n        let mut runner = runner;\n        let _ = event_loop.run_app(&mut runner);\n\n        runner.error.map(Err).unwrap_or(Ok(()))\n    }\n\n    #[cfg(target_arch = \"wasm32\")]\n    {\n        use winit::platform::web::EventLoopExtWebSys;\n        let _ = event_loop.spawn_app(runner);\n\n        Ok(())\n    }\n}\n\n#[derive(Debug)]\nenum Event<Message: 'static> {\n    WindowCreated {\n        id: window::Id,\n        window: Arc<winit::window::Window>,\n        exit_on_close_request: bool,\n        make_visible: bool,\n        on_open: oneshot::Sender<window::Id>,\n    },\n    EventLoopAwakened(winit::event::Event<Message>),\n    Exit,\n}\n\n#[derive(Debug)]\nenum Control {\n    ChangeFlow(winit::event_loop::ControlFlow),\n    Exit,\n    Crash(Error),\n    CreateWindow {\n        id: window::Id,\n        settings: window::Settings,\n        title: String,\n        monitor: Option<winit::monitor::MonitorHandle>,\n        on_open: oneshot::Sender<window::Id>,\n        scale_factor: f32,\n    },\n    SetAutomaticWindowTabbing(bool),\n}\n\nasync fn run_instance<P>(\n    mut program: program::Instance<P>,\n    mut runtime: Runtime<P::Executor, Proxy<P::Message>, Action<P::Message>>,\n    mut proxy: Proxy<P::Message>,\n    mut event_receiver: mpsc::UnboundedReceiver<Event<Action<P::Message>>>,\n    mut control_sender: mpsc::UnboundedSender<Control>,\n    display_handle: winit::event_loop::OwnedDisplayHandle,\n    is_daemon: bool,\n    compositor_settings: compositor::Settings,\n    mut renderer_settings: renderer::Settings,\n    default_fonts: Vec<Cow<'static, [u8]>>,\n    mut _system_theme: oneshot::Receiver<theme::Mode>,\n) where\n    P: Program + 'static,\n    P::Theme: theme::Base,\n{\n    use winit::event;\n    use winit::event_loop::ControlFlow;\n\n    let mut window_manager = WindowManager::new();\n    let mut is_window_opening = !is_daemon;\n\n    let mut compositor = None;\n    let mut events = Vec::new();\n    let mut messages = Vec::new();\n    let mut actions = 0;\n\n    let mut ui_caches = FxHashMap::default();\n    let mut user_interfaces = ManuallyDrop::new(FxHashMap::default());\n    let mut clipboard = Clipboard::new();\n\n    #[cfg(all(feature = \"linux-theme-detection\", target_os = \"linux\"))]\n    let mut system_theme = {\n        let to_mode = |color_scheme| match color_scheme {\n            mundy::ColorScheme::NoPreference => theme::Mode::None,\n            mundy::ColorScheme::Light => theme::Mode::Light,\n            mundy::ColorScheme::Dark => theme::Mode::Dark,\n        };\n\n        runtime.run(\n            mundy::Preferences::stream(mundy::Interest::ColorScheme)\n                .map(move |preferences| {\n                    Action::System(system::Action::NotifyTheme(to_mode(\n                        preferences.color_scheme,\n                    )))\n                })\n                .boxed(),\n        );\n\n        runtime\n            .enter(|| {\n                mundy::Preferences::once_blocking(\n                    mundy::Interest::ColorScheme,\n                    core::time::Duration::from_millis(200),\n                )\n            })\n            .map(|preferences| to_mode(preferences.color_scheme))\n            .unwrap_or_default()\n    };\n\n    #[cfg(not(all(feature = \"linux-theme-detection\", target_os = \"linux\")))]\n    let mut system_theme = _system_theme.try_recv().ok().flatten().unwrap_or_default();\n\n    log::info!(\"System theme: {system_theme:?}\");\n\n    'next_event: loop {\n        // Empty the queue if possible\n        let event = if let Ok(event) = event_receiver.try_recv() {\n            Some(event)\n        } else {\n            event_receiver.next().await\n        };\n\n        let Some(event) = event else {\n            break;\n        };\n\n        match event {\n            Event::WindowCreated {\n                id,\n                window,\n                exit_on_close_request,\n                make_visible,\n                on_open,\n            } => {\n                if compositor.is_none() {\n                    let (compositor_sender, compositor_receiver) = oneshot::channel();\n\n                    let create_compositor = {\n                        let window = window.clone();\n                        let display_handle = display_handle.clone();\n                        let proxy = proxy.clone();\n                        let default_fonts = default_fonts.clone();\n\n                        async move {\n                            let shell = Shell::new(proxy.clone());\n\n                            let mut compositor =\n                                <P::Renderer as compositor::Default>::Compositor::new(\n                                    compositor_settings,\n                                    display_handle,\n                                    window,\n                                    shell,\n                                )\n                                .await;\n\n                            if let Ok(compositor) = &mut compositor {\n                                for font in default_fonts {\n                                    compositor.load_font(font.clone());\n                                }\n                            }\n\n                            compositor_sender\n                                .send(compositor)\n                                .ok()\n                                .expect(\"Send compositor\");\n\n                            // HACK! Send a proxy event on completion to trigger\n                            // a runtime re-poll\n                            // TODO: Send compositor through proxy (?)\n                            {\n                                let (sender, _receiver) = oneshot::channel();\n\n                                proxy.send_action(Action::Window(\n                                    runtime::window::Action::GetLatest(sender),\n                                ));\n                            }\n                        }\n                    };\n\n                    #[cfg(target_arch = \"wasm32\")]\n                    wasm_bindgen_futures::spawn_local(create_compositor);\n\n                    #[cfg(not(target_arch = \"wasm32\"))]\n                    runtime.block_on(create_compositor);\n\n                    match compositor_receiver.await.expect(\"Wait for compositor\") {\n                        Ok(new_compositor) => {\n                            compositor = Some(new_compositor);\n                        }\n                        Err(error) => {\n                            let _ = control_sender.start_send(Control::Crash(error.into()));\n                            continue;\n                        }\n                    }\n                }\n\n                let window_theme = window\n                    .theme()\n                    .map(conversion::theme_mode)\n                    .unwrap_or_default();\n\n                if system_theme != window_theme {\n                    system_theme = window_theme;\n\n                    runtime.broadcast(subscription::Event::SystemThemeChanged(window_theme));\n                }\n\n                let is_first = window_manager.is_empty();\n                let window = window_manager.insert(\n                    id,\n                    window,\n                    &program,\n                    compositor.as_mut().expect(\"Compositor must be initialized\"),\n                    renderer_settings,\n                    exit_on_close_request,\n                    system_theme,\n                );\n\n                window\n                    .raw\n                    .set_theme(conversion::window_theme(window.state.theme_mode()));\n\n                debug::theme_changed(|| {\n                    if is_first {\n                        theme::Base::seed(window.state.theme())\n                    } else {\n                        None\n                    }\n                });\n\n                let logical_size = window.state.logical_size();\n\n                #[cfg(feature = \"hinting\")]\n                window.renderer.hint(window.state.scale_factor());\n\n                let _ = user_interfaces.insert(\n                    id,\n                    build_user_interface(\n                        &program,\n                        user_interface::Cache::default(),\n                        &mut window.renderer,\n                        logical_size,\n                        id,\n                    ),\n                );\n                let _ = ui_caches.insert(id, user_interface::Cache::default());\n\n                if make_visible {\n                    window.raw.set_visible(true);\n                }\n\n                events.push((\n                    id,\n                    core::Event::Window(window::Event::Opened {\n                        position: window.position(),\n                        size: window.state.logical_size(),\n                        scale_factor: window.raw.scale_factor() as f32,\n                    }),\n                ));\n\n                let _ = on_open.send(id);\n                is_window_opening = false;\n            }\n            Event::EventLoopAwakened(event) => {\n                match event {\n                    event::Event::NewEvents(event::StartCause::Init) => {\n                        for (_id, window) in window_manager.iter_mut() {\n                            window.raw.request_redraw();\n                        }\n                    }\n                    event::Event::NewEvents(event::StartCause::ResumeTimeReached { .. }) => {\n                        let now = Instant::now();\n\n                        for (_id, window) in window_manager.iter_mut() {\n                            if let Some(redraw_at) = window.redraw_at\n                                && redraw_at <= now\n                            {\n                                window.raw.request_redraw();\n                                window.redraw_at = None;\n                            }\n                        }\n\n                        if let Some(redraw_at) = window_manager.redraw_at() {\n                            let _ = control_sender\n                                .start_send(Control::ChangeFlow(ControlFlow::WaitUntil(redraw_at)));\n                        } else {\n                            let _ =\n                                control_sender.start_send(Control::ChangeFlow(ControlFlow::Wait));\n                        }\n                    }\n                    event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(\n                        event::MacOS::ReceivedUrl(url),\n                    )) => {\n                        runtime.broadcast(subscription::Event::PlatformSpecific(\n                            subscription::PlatformSpecific::MacOS(\n                                subscription::MacOS::ReceivedUrl(url),\n                            ),\n                        ));\n                    }\n                    event::Event::UserEvent(action) => {\n                        run_action(\n                            action,\n                            &program,\n                            &mut runtime,\n                            &mut compositor,\n                            &mut events,\n                            &mut messages,\n                            &mut clipboard,\n                            &mut control_sender,\n                            &mut user_interfaces,\n                            &mut window_manager,\n                            &mut ui_caches,\n                            &mut is_window_opening,\n                            &mut system_theme,\n                            &mut renderer_settings,\n                        );\n                        actions += 1;\n                    }\n                    event::Event::WindowEvent {\n                        window_id: id,\n                        event: event::WindowEvent::RedrawRequested,\n                        ..\n                    } => {\n                        let Some(mut current_compositor) = compositor.as_mut() else {\n                            continue;\n                        };\n\n                        let Some((id, mut window)) = window_manager.get_mut_alias(id) else {\n                            continue;\n                        };\n\n                        let physical_size = window.state.physical_size();\n                        let mut logical_size = window.state.logical_size();\n\n                        if physical_size.width == 0 || physical_size.height == 0 {\n                            continue;\n                        }\n\n                        // Window was resized between redraws\n                        if window.surface_version != window.state.surface_version() {\n                            #[cfg(feature = \"hinting\")]\n                            window.renderer.hint(window.state.scale_factor());\n\n                            let ui = user_interfaces.remove(&id).expect(\"Remove user interface\");\n\n                            let layout_span = debug::layout(id);\n                            let _ = user_interfaces\n                                .insert(id, ui.relayout(logical_size, &mut window.renderer));\n                            layout_span.finish();\n\n                            current_compositor.configure_surface(\n                                &mut window.surface,\n                                physical_size.width,\n                                physical_size.height,\n                            );\n\n                            window.surface_version = window.state.surface_version();\n                        }\n\n                        let redraw_event =\n                            core::Event::Window(window::Event::RedrawRequested(Instant::now()));\n\n                        let cursor = window.state.cursor();\n\n                        let mut interface =\n                            user_interfaces.get_mut(&id).expect(\"Get user interface\");\n\n                        let interact_span = debug::interact(id);\n                        let mut redraw_count = 0;\n\n                        let state = loop {\n                            let message_count = messages.len();\n                            let (state, _) = interface.update(\n                                slice::from_ref(&redraw_event),\n                                cursor,\n                                &mut window.renderer,\n                                &mut messages,\n                            );\n\n                            if message_count == messages.len() && !state.has_layout_changed() {\n                                break state;\n                            }\n\n                            if redraw_count >= 2 {\n                                log::warn!(\n                                    \"More than 3 consecutive RedrawRequested events \\\n                                    produced layout invalidation\"\n                                );\n\n                                break state;\n                            }\n\n                            redraw_count += 1;\n\n                            if !messages.is_empty() {\n                                let caches: FxHashMap<_, _> =\n                                    ManuallyDrop::into_inner(user_interfaces)\n                                        .into_iter()\n                                        .map(|(id, interface)| (id, interface.into_cache()))\n                                        .collect();\n\n                                let actions = update(&mut program, &mut runtime, &mut messages);\n\n                                user_interfaces = ManuallyDrop::new(build_user_interfaces(\n                                    &program,\n                                    &mut window_manager,\n                                    caches,\n                                ));\n\n                                for action in actions {\n                                    // Defer all window actions to avoid compositor\n                                    // race conditions while redrawing\n                                    if let Action::Window(_) = action {\n                                        proxy.send_action(action);\n                                        continue;\n                                    }\n\n                                    run_action(\n                                        action,\n                                        &program,\n                                        &mut runtime,\n                                        &mut compositor,\n                                        &mut events,\n                                        &mut messages,\n                                        &mut clipboard,\n                                        &mut control_sender,\n                                        &mut user_interfaces,\n                                        &mut window_manager,\n                                        &mut ui_caches,\n                                        &mut is_window_opening,\n                                        &mut system_theme,\n                                        &mut renderer_settings,\n                                    );\n                                }\n\n                                for (window_id, window) in window_manager.iter_mut() {\n                                    // We are already redrawing this window\n                                    if window_id == id {\n                                        continue;\n                                    }\n\n                                    window.raw.request_redraw();\n                                }\n\n                                let Some(next_compositor) = compositor.as_mut() else {\n                                    continue 'next_event;\n                                };\n\n                                current_compositor = next_compositor;\n                                window = window_manager.get_mut(id).unwrap();\n\n                                // Window scale factor changed during a redraw request\n                                if logical_size != window.state.logical_size() {\n                                    logical_size = window.state.logical_size();\n\n                                    log::debug!(\n                                        \"Window scale factor changed during a redraw request\"\n                                    );\n\n                                    let ui =\n                                        user_interfaces.remove(&id).expect(\"Remove user interface\");\n\n                                    let layout_span = debug::layout(id);\n                                    let _ = user_interfaces.insert(\n                                        id,\n                                        ui.relayout(logical_size, &mut window.renderer),\n                                    );\n                                    layout_span.finish();\n                                }\n\n                                interface = user_interfaces.get_mut(&id).unwrap();\n                            }\n                        };\n                        interact_span.finish();\n\n                        let draw_span = debug::draw(id);\n                        interface.draw(\n                            &mut window.renderer,\n                            window.state.theme(),\n                            &renderer::Style {\n                                text_color: window.state.text_color(),\n                            },\n                            cursor,\n                        );\n                        draw_span.finish();\n\n                        if let user_interface::State::Updated {\n                            redraw_request,\n                            input_method,\n                            mouse_interaction,\n                            clipboard: clipboard_requests,\n                            ..\n                        } = state\n                        {\n                            window.request_redraw(redraw_request);\n                            window.request_input_method(input_method);\n                            window.update_mouse(mouse_interaction);\n\n                            run_clipboard(&mut proxy, &mut clipboard, clipboard_requests, id);\n                        }\n\n                        runtime.broadcast(subscription::Event::Interaction {\n                            window: id,\n                            event: redraw_event,\n                            status: core::event::Status::Ignored,\n                        });\n\n                        window.draw_preedit();\n\n                        let present_span = debug::present(id);\n                        match current_compositor.present(\n                            &mut window.renderer,\n                            &mut window.surface,\n                            window.state.viewport(),\n                            window.state.background_color(),\n                            || window.raw.pre_present_notify(),\n                        ) {\n                            Ok(()) => {\n                                present_span.finish();\n                            }\n                            Err(error) => match error {\n                                compositor::SurfaceError::OutOfMemory => {\n                                    // This is an unrecoverable error.\n                                    panic!(\"{error:?}\");\n                                }\n                                compositor::SurfaceError::Outdated\n                                | compositor::SurfaceError::Lost => {\n                                    present_span.finish();\n\n                                    // Reconfigure surface and try redrawing\n                                    let physical_size = window.state.physical_size();\n\n                                    if error == compositor::SurfaceError::Lost {\n                                        window.surface = current_compositor.create_surface(\n                                            window.raw.clone(),\n                                            physical_size.width,\n                                            physical_size.height,\n                                        );\n                                    } else {\n                                        current_compositor.configure_surface(\n                                            &mut window.surface,\n                                            physical_size.width,\n                                            physical_size.height,\n                                        );\n                                    }\n\n                                    window.raw.request_redraw();\n                                }\n                                _ => {\n                                    present_span.finish();\n\n                                    log::error!(\"Error {error:?} when presenting surface.\");\n\n                                    // Try rendering all windows again next frame.\n                                    for (_id, window) in window_manager.iter_mut() {\n                                        window.raw.request_redraw();\n                                    }\n                                }\n                            },\n                        }\n                    }\n                    event::Event::WindowEvent {\n                        event: window_event,\n                        window_id,\n                    } => {\n                        if !is_daemon\n                            && matches!(window_event, winit::event::WindowEvent::Destroyed)\n                            && !is_window_opening\n                            && window_manager.is_empty()\n                        {\n                            control_sender\n                                .start_send(Control::Exit)\n                                .expect(\"Send control action\");\n\n                            continue;\n                        }\n\n                        let Some((id, window)) = window_manager.get_mut_alias(window_id) else {\n                            continue;\n                        };\n\n                        match window_event {\n                            winit::event::WindowEvent::Resized(_) => {\n                                window.raw.request_redraw();\n                            }\n                            winit::event::WindowEvent::ThemeChanged(theme) => {\n                                let mode = conversion::theme_mode(theme);\n\n                                if mode != system_theme {\n                                    system_theme = mode;\n\n                                    runtime\n                                        .broadcast(subscription::Event::SystemThemeChanged(mode));\n                                }\n                            }\n                            _ => {}\n                        }\n\n                        if matches!(window_event, winit::event::WindowEvent::CloseRequested)\n                            && window.exit_on_close_request\n                        {\n                            run_action(\n                                Action::Window(runtime::window::Action::Close(id)),\n                                &program,\n                                &mut runtime,\n                                &mut compositor,\n                                &mut events,\n                                &mut messages,\n                                &mut clipboard,\n                                &mut control_sender,\n                                &mut user_interfaces,\n                                &mut window_manager,\n                                &mut ui_caches,\n                                &mut is_window_opening,\n                                &mut system_theme,\n                                &mut renderer_settings,\n                            );\n                        } else {\n                            window.state.update(&program, &window.raw, &window_event);\n\n                            if let Some(event) = conversion::window_event(\n                                window_event,\n                                window.state.scale_factor(),\n                                window.state.modifiers(),\n                            ) {\n                                events.push((id, event));\n                            }\n                        }\n                    }\n                    event::Event::AboutToWait => {\n                        if actions > 0 {\n                            proxy.free_slots(actions);\n                            actions = 0;\n                        }\n\n                        if events.is_empty() && messages.is_empty() && window_manager.is_idle() {\n                            continue;\n                        }\n\n                        let mut uis_stale = false;\n\n                        for (id, window) in window_manager.iter_mut() {\n                            let interact_span = debug::interact(id);\n                            let mut window_events = vec![];\n\n                            events.retain(|(window_id, event)| {\n                                if *window_id == id {\n                                    window_events.push(event.clone());\n                                    false\n                                } else {\n                                    true\n                                }\n                            });\n\n                            if window_events.is_empty() {\n                                continue;\n                            }\n\n                            let (ui_state, statuses) = user_interfaces\n                                .get_mut(&id)\n                                .expect(\"Get user interface\")\n                                .update(\n                                    &window_events,\n                                    window.state.cursor(),\n                                    &mut window.renderer,\n                                    &mut messages,\n                                );\n\n                            #[cfg(feature = \"unconditional-rendering\")]\n                            window.request_redraw(window::RedrawRequest::NextFrame);\n\n                            match ui_state {\n                                user_interface::State::Updated {\n                                    redraw_request: _redraw_request,\n                                    mouse_interaction,\n                                    clipboard: clipboard_requests,\n                                    ..\n                                } => {\n                                    window.update_mouse(mouse_interaction);\n\n                                    #[cfg(not(feature = \"unconditional-rendering\"))]\n                                    window.request_redraw(_redraw_request);\n\n                                    run_clipboard(\n                                        &mut proxy,\n                                        &mut clipboard,\n                                        clipboard_requests,\n                                        id,\n                                    );\n                                }\n                                user_interface::State::Outdated => {\n                                    uis_stale = true;\n                                }\n                            }\n\n                            for (event, status) in\n                                window_events.into_iter().zip(statuses.into_iter())\n                            {\n                                runtime.broadcast(subscription::Event::Interaction {\n                                    window: id,\n                                    event,\n                                    status,\n                                });\n                            }\n\n                            interact_span.finish();\n                        }\n\n                        for (id, event) in events.drain(..) {\n                            runtime.broadcast(subscription::Event::Interaction {\n                                window: id,\n                                event,\n                                status: core::event::Status::Ignored,\n                            });\n                        }\n\n                        if !messages.is_empty() || uis_stale {\n                            let cached_interfaces: FxHashMap<_, _> =\n                                ManuallyDrop::into_inner(user_interfaces)\n                                    .into_iter()\n                                    .map(|(id, ui)| (id, ui.into_cache()))\n                                    .collect();\n\n                            let actions = update(&mut program, &mut runtime, &mut messages);\n\n                            user_interfaces = ManuallyDrop::new(build_user_interfaces(\n                                &program,\n                                &mut window_manager,\n                                cached_interfaces,\n                            ));\n\n                            for action in actions {\n                                run_action(\n                                    action,\n                                    &program,\n                                    &mut runtime,\n                                    &mut compositor,\n                                    &mut events,\n                                    &mut messages,\n                                    &mut clipboard,\n                                    &mut control_sender,\n                                    &mut user_interfaces,\n                                    &mut window_manager,\n                                    &mut ui_caches,\n                                    &mut is_window_opening,\n                                    &mut system_theme,\n                                    &mut renderer_settings,\n                                );\n                            }\n\n                            for (_id, window) in window_manager.iter_mut() {\n                                window.raw.request_redraw();\n                            }\n                        }\n\n                        if let Some(redraw_at) = window_manager.redraw_at() {\n                            let _ = control_sender\n                                .start_send(Control::ChangeFlow(ControlFlow::WaitUntil(redraw_at)));\n                        } else {\n                            let _ =\n                                control_sender.start_send(Control::ChangeFlow(ControlFlow::Wait));\n                        }\n                    }\n                    _ => {}\n                }\n            }\n            Event::Exit => break,\n        }\n    }\n\n    let _ = ManuallyDrop::into_inner(user_interfaces);\n}\n\n/// Builds a window's [`UserInterface`] for the [`Program`].\nfn build_user_interface<'a, P: Program>(\n    program: &'a program::Instance<P>,\n    cache: user_interface::Cache,\n    renderer: &mut P::Renderer,\n    size: Size,\n    id: window::Id,\n) -> UserInterface<'a, P::Message, P::Theme, P::Renderer>\nwhere\n    P::Theme: theme::Base,\n{\n    let view_span = debug::view(id);\n    let view = program.view(id);\n    view_span.finish();\n\n    let layout_span = debug::layout(id);\n    let user_interface = UserInterface::build(view, size, cache, renderer);\n    layout_span.finish();\n\n    user_interface\n}\n\nfn update<P: Program, E: Executor>(\n    program: &mut program::Instance<P>,\n    runtime: &mut Runtime<E, Proxy<P::Message>, Action<P::Message>>,\n    messages: &mut Vec<P::Message>,\n) -> Vec<Action<P::Message>>\nwhere\n    P::Theme: theme::Base,\n{\n    use futures::futures;\n\n    let mut actions = Vec::new();\n    let mut outputs = Vec::new();\n\n    while !messages.is_empty() {\n        for message in messages.drain(..) {\n            let task = runtime.enter(|| program.update(message));\n\n            if let Some(mut stream) = runtime::task::into_stream(task) {\n                let waker = futures::task::noop_waker_ref();\n                let mut context = futures::task::Context::from_waker(waker);\n\n                // Run immediately available actions synchronously (e.g. widget operations)\n                loop {\n                    match runtime.enter(|| stream.poll_next_unpin(&mut context)) {\n                        futures::task::Poll::Ready(Some(Action::Output(output))) => {\n                            outputs.push(output);\n                        }\n                        futures::task::Poll::Ready(Some(action)) => {\n                            actions.push(action);\n                        }\n                        futures::task::Poll::Ready(None) => {\n                            break;\n                        }\n                        futures::task::Poll::Pending => {\n                            runtime.run(stream);\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        messages.append(&mut outputs);\n    }\n\n    let subscription = runtime.enter(|| program.subscription());\n    let recipes = subscription::into_recipes(subscription.map(Action::Output));\n\n    runtime.track(recipes);\n\n    actions\n}\n\nfn run_action<'a, P, C>(\n    action: Action<P::Message>,\n    program: &'a program::Instance<P>,\n    runtime: &mut Runtime<P::Executor, Proxy<P::Message>, Action<P::Message>>,\n    compositor: &mut Option<C>,\n    events: &mut Vec<(window::Id, core::Event)>,\n    messages: &mut Vec<P::Message>,\n    clipboard: &mut Clipboard,\n    control_sender: &mut mpsc::UnboundedSender<Control>,\n    interfaces: &mut FxHashMap<window::Id, UserInterface<'a, P::Message, P::Theme, P::Renderer>>,\n    window_manager: &mut WindowManager<P, C>,\n    ui_caches: &mut FxHashMap<window::Id, user_interface::Cache>,\n    is_window_opening: &mut bool,\n    system_theme: &mut theme::Mode,\n    renderer_settings: &mut renderer::Settings,\n) where\n    P: Program,\n    C: Compositor<Renderer = P::Renderer> + 'static,\n    P::Theme: theme::Base,\n{\n    use crate::core::Renderer as _;\n    use crate::runtime::clipboard;\n    use crate::runtime::window;\n\n    match action {\n        Action::Output(message) => {\n            messages.push(message);\n        }\n        Action::Clipboard(action) => match action {\n            clipboard::Action::Read { kind, channel } => {\n                clipboard.read(kind, move |result| {\n                    let _ = channel.send(result);\n                });\n            }\n            clipboard::Action::Write { content, channel } => {\n                clipboard.write(content, move |result| {\n                    let _ = channel.send(result);\n                });\n            }\n        },\n        Action::Window(action) => match action {\n            window::Action::Open(id, settings, channel) => {\n                let monitor = window_manager.last_monitor();\n\n                control_sender\n                    .start_send(Control::CreateWindow {\n                        id,\n                        settings,\n                        title: program.title(id),\n                        scale_factor: program.scale_factor(id),\n                        monitor,\n                        on_open: channel,\n                    })\n                    .expect(\"Send control action\");\n\n                *is_window_opening = true;\n            }\n            window::Action::Close(id) => {\n                let _ = ui_caches.remove(&id);\n                let _ = interfaces.remove(&id);\n\n                if window_manager.remove(id).is_some() {\n                    events.push((id, core::Event::Window(core::window::Event::Closed)));\n                }\n\n                if window_manager.is_empty() {\n                    *compositor = None;\n                }\n            }\n            window::Action::GetOldest(channel) => {\n                let id = window_manager.iter_mut().next().map(|(id, _window)| id);\n\n                let _ = channel.send(id);\n            }\n            window::Action::GetLatest(channel) => {\n                let id = window_manager.iter_mut().last().map(|(id, _window)| id);\n\n                let _ = channel.send(id);\n            }\n            window::Action::Drag(id) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let _ = window.raw.drag_window();\n                }\n            }\n            window::Action::DragResize(id, direction) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let _ = window\n                        .raw\n                        .drag_resize_window(conversion::resize_direction(direction));\n                }\n            }\n            window::Action::Resize(id, size) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let _ = window.raw.request_inner_size(\n                        winit::dpi::LogicalSize {\n                            width: size.width,\n                            height: size.height,\n                        }\n                        .to_physical::<f32>(f64::from(window.state.scale_factor())),\n                    );\n                }\n            }\n            window::Action::SetMinSize(id, size) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_min_inner_size(size.map(|size| {\n                        winit::dpi::LogicalSize {\n                            width: size.width,\n                            height: size.height,\n                        }\n                        .to_physical::<f32>(f64::from(window.state.scale_factor()))\n                    }));\n                }\n            }\n            window::Action::SetMaxSize(id, size) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_max_inner_size(size.map(|size| {\n                        winit::dpi::LogicalSize {\n                            width: size.width,\n                            height: size.height,\n                        }\n                        .to_physical::<f32>(f64::from(window.state.scale_factor()))\n                    }));\n                }\n            }\n            window::Action::SetResizeIncrements(id, increments) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_resize_increments(increments.map(|size| {\n                        winit::dpi::LogicalSize {\n                            width: size.width,\n                            height: size.height,\n                        }\n                        .to_physical::<f32>(f64::from(window.state.scale_factor()))\n                    }));\n                }\n            }\n            window::Action::SetResizable(id, resizable) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_resizable(resizable);\n                }\n            }\n            window::Action::GetSize(id, channel) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let size = window.state.logical_size();\n                    let _ = channel.send(Size::new(size.width, size.height));\n                }\n            }\n            window::Action::GetMaximized(id, channel) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let _ = channel.send(window.raw.is_maximized());\n                }\n            }\n            window::Action::Maximize(id, maximized) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_maximized(maximized);\n                }\n            }\n            window::Action::GetMinimized(id, channel) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let _ = channel.send(window.raw.is_minimized());\n                }\n            }\n            window::Action::Minimize(id, minimized) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_minimized(minimized);\n                }\n            }\n            window::Action::GetPosition(id, channel) => {\n                if let Some(window) = window_manager.get(id) {\n                    let position = window\n                        .raw\n                        .outer_position()\n                        .map(|position| {\n                            let position = position.to_logical::<f32>(window.raw.scale_factor());\n\n                            Point::new(position.x, position.y)\n                        })\n                        .ok();\n\n                    let _ = channel.send(position);\n                }\n            }\n            window::Action::GetScaleFactor(id, channel) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let scale_factor = window.raw.scale_factor();\n\n                    let _ = channel.send(scale_factor as f32);\n                }\n            }\n            window::Action::Move(id, position) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_outer_position(winit::dpi::LogicalPosition {\n                        x: position.x,\n                        y: position.y,\n                    });\n                }\n            }\n            window::Action::SetMode(id, mode) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_visible(conversion::visible(mode));\n                    window\n                        .raw\n                        .set_fullscreen(conversion::fullscreen(window.raw.current_monitor(), mode));\n                }\n            }\n            window::Action::SetIcon(id, icon) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_window_icon(conversion::icon(icon));\n                }\n            }\n            window::Action::GetMode(id, channel) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let mode = if window.raw.is_visible().unwrap_or(true) {\n                        conversion::mode(window.raw.fullscreen())\n                    } else {\n                        core::window::Mode::Hidden\n                    };\n\n                    let _ = channel.send(mode);\n                }\n            }\n            window::Action::ToggleMaximize(id) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_maximized(!window.raw.is_maximized());\n                }\n            }\n            window::Action::ToggleDecorations(id) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_decorations(!window.raw.is_decorated());\n                }\n            }\n            window::Action::RequestUserAttention(id, attention_type) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window\n                        .raw\n                        .request_user_attention(attention_type.map(conversion::user_attention));\n                }\n            }\n            window::Action::GainFocus(id) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.focus_window();\n                }\n            }\n            window::Action::SetLevel(id, level) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    window.raw.set_window_level(conversion::window_level(level));\n                }\n            }\n            window::Action::ShowSystemMenu(id) => {\n                if let Some(window) = window_manager.get_mut(id)\n                    && let mouse::Cursor::Available(point) = window.state.cursor()\n                {\n                    window.raw.show_window_menu(winit::dpi::LogicalPosition {\n                        x: point.x,\n                        y: point.y,\n                    });\n                }\n            }\n            window::Action::GetRawId(id, channel) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let _ = channel.send(window.raw.id().into());\n                }\n            }\n            window::Action::Run(id, f) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    f(window);\n                }\n            }\n            window::Action::Screenshot(id, channel) => {\n                if let Some(window) = window_manager.get_mut(id)\n                    && let Some(compositor) = compositor\n                {\n                    let bytes = compositor.screenshot(\n                        &mut window.renderer,\n                        window.state.viewport(),\n                        window.state.background_color(),\n                    );\n\n                    let _ = channel.send(core::window::Screenshot::new(\n                        bytes,\n                        window.state.physical_size(),\n                        window.state.scale_factor(),\n                    ));\n                }\n            }\n            window::Action::EnableMousePassthrough(id) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let _ = window.raw.set_cursor_hittest(false);\n                }\n            }\n            window::Action::DisableMousePassthrough(id) => {\n                if let Some(window) = window_manager.get_mut(id) {\n                    let _ = window.raw.set_cursor_hittest(true);\n                }\n            }\n            window::Action::GetMonitorSize(id, channel) => {\n                if let Some(window) = window_manager.get(id) {\n                    let size = window.raw.current_monitor().map(|monitor| {\n                        let scale = window.state.scale_factor();\n                        let size = monitor.size().to_logical(f64::from(scale));\n\n                        Size::new(size.width, size.height)\n                    });\n\n                    let _ = channel.send(size);\n                }\n            }\n            window::Action::SetAllowAutomaticTabbing(enabled) => {\n                control_sender\n                    .start_send(Control::SetAutomaticWindowTabbing(enabled))\n                    .expect(\"Send control action\");\n            }\n            window::Action::RedrawAll => {\n                for (_id, window) in window_manager.iter_mut() {\n                    window.raw.request_redraw();\n                }\n            }\n            window::Action::RelayoutAll => {\n                for (id, window) in window_manager.iter_mut() {\n                    if let Some(ui) = interfaces.remove(&id) {\n                        let _ = interfaces.insert(\n                            id,\n                            ui.relayout(window.state.logical_size(), &mut window.renderer),\n                        );\n                    }\n\n                    window.raw.request_redraw();\n                }\n            }\n        },\n        Action::System(action) => match action {\n            system::Action::GetInformation(_channel) => {\n                #[cfg(feature = \"sysinfo\")]\n                {\n                    if let Some(compositor) = compositor {\n                        let graphics_info = compositor.information();\n\n                        let _ = std::thread::spawn(move || {\n                            let information = system_information(graphics_info);\n\n                            let _ = _channel.send(information);\n                        });\n                    }\n                }\n            }\n            system::Action::GetTheme(channel) => {\n                let _ = channel.send(*system_theme);\n            }\n            system::Action::NotifyTheme(mode) => {\n                if mode != *system_theme {\n                    *system_theme = mode;\n\n                    runtime.broadcast(subscription::Event::SystemThemeChanged(mode));\n                }\n\n                let Some(theme) = conversion::window_theme(mode) else {\n                    return;\n                };\n\n                for (_id, window) in window_manager.iter_mut() {\n                    window.state.update(\n                        program,\n                        &window.raw,\n                        &winit::event::WindowEvent::ThemeChanged(theme),\n                    );\n                }\n            }\n        },\n        Action::Font(action) => match action {\n            font::Action::Load { bytes, channel } => {\n                if let Some(compositor) = compositor {\n                    let result = compositor.load_font(bytes.clone());\n                    let _ = channel.send(result);\n                }\n            }\n            font::Action::List { channel } => {\n                if let Some(compositor) = compositor {\n                    let fonts = compositor.list_fonts();\n                    let _ = channel.send(fonts);\n                }\n            }\n            font::Action::SetDefaults { font, text_size } => {\n                renderer_settings.default_font = font;\n                renderer_settings.default_text_size = text_size;\n\n                let Some(compositor) = compositor else {\n                    return;\n                };\n\n                // Recreate renderers and relayout all windows\n                for (id, window) in window_manager.iter_mut() {\n                    window.renderer = compositor.create_renderer(*renderer_settings);\n\n                    let Some(ui) = interfaces.remove(&id) else {\n                        continue;\n                    };\n\n                    let size = window.state.logical_size();\n                    let ui = ui.relayout(size, &mut window.renderer);\n                    let _ = interfaces.insert(id, ui);\n\n                    window.raw.request_redraw();\n                }\n            }\n        },\n        Action::Widget(operation) => {\n            let mut current_operation = Some(operation);\n\n            while let Some(mut operation) = current_operation.take() {\n                for (id, ui) in interfaces.iter_mut() {\n                    if let Some(window) = window_manager.get_mut(*id) {\n                        ui.operate(&window.renderer, operation.as_mut());\n                    }\n                }\n\n                match operation.finish() {\n                    operation::Outcome::None => {}\n                    operation::Outcome::Some(()) => {}\n                    operation::Outcome::Chain(next) => {\n                        current_operation = Some(next);\n                    }\n                }\n            }\n\n            // Redraw all windows\n            for (_, window) in window_manager.iter_mut() {\n                window.raw.request_redraw();\n            }\n        }\n        Action::Image(action) => match action {\n            image::Action::Allocate(handle, sender) => {\n                // TODO: Shared image cache in compositor\n                if let Some((_id, window)) = window_manager.iter_mut().next() {\n                    window.renderer.allocate_image(&handle, move |allocation| {\n                        let _ = sender.send(allocation);\n                    });\n                }\n            }\n        },\n        Action::Event { window, event } => {\n            events.push((window, event));\n        }\n        Action::Tick => {\n            for (_id, window) in window_manager.iter_mut() {\n                window.renderer.tick();\n            }\n        }\n        Action::Reload => {\n            for (id, window) in window_manager.iter_mut() {\n                let Some(ui) = interfaces.remove(&id) else {\n                    continue;\n                };\n\n                let cache = ui.into_cache();\n                let size = window.state.logical_size();\n\n                let _ = interfaces.insert(\n                    id,\n                    build_user_interface(program, cache, &mut window.renderer, size, id),\n                );\n\n                window.raw.request_redraw();\n            }\n        }\n        Action::Exit => {\n            control_sender\n                .start_send(Control::Exit)\n                .expect(\"Send control action\");\n        }\n    }\n}\n\n/// Build the user interface for every window.\npub fn build_user_interfaces<'a, P: Program, C>(\n    program: &'a program::Instance<P>,\n    window_manager: &mut WindowManager<P, C>,\n    mut cached_user_interfaces: FxHashMap<window::Id, user_interface::Cache>,\n) -> FxHashMap<window::Id, UserInterface<'a, P::Message, P::Theme, P::Renderer>>\nwhere\n    C: Compositor<Renderer = P::Renderer>,\n    P::Theme: theme::Base,\n{\n    for (id, window) in window_manager.iter_mut() {\n        window.state.synchronize(program, id, &window.raw);\n\n        #[cfg(feature = \"hinting\")]\n        window.renderer.hint(window.state.scale_factor());\n    }\n\n    debug::theme_changed(|| {\n        window_manager\n            .first()\n            .and_then(|window| theme::Base::seed(window.state.theme()))\n    });\n\n    cached_user_interfaces\n        .drain()\n        .filter_map(|(id, cache)| {\n            let window = window_manager.get_mut(id)?;\n\n            Some((\n                id,\n                build_user_interface(\n                    program,\n                    cache,\n                    &mut window.renderer,\n                    window.state.logical_size(),\n                    id,\n                ),\n            ))\n        })\n        .collect()\n}\n\n/// Returns true if the provided event should cause a [`Program`] to\n/// exit.\npub fn user_force_quit(\n    event: &winit::event::WindowEvent,\n    _modifiers: winit::keyboard::ModifiersState,\n) -> bool {\n    match event {\n        #[cfg(target_os = \"macos\")]\n        winit::event::WindowEvent::KeyboardInput {\n            event:\n                winit::event::KeyEvent {\n                    logical_key: winit::keyboard::Key::Character(c),\n                    state: winit::event::ElementState::Pressed,\n                    ..\n                },\n            ..\n        } if c == \"q\" && _modifiers.super_key() => true,\n        _ => false,\n    }\n}\n\n#[cfg(feature = \"sysinfo\")]\nfn system_information(graphics: compositor::Information) -> system::Information {\n    use sysinfo::{Process, System};\n\n    let mut system = System::new_all();\n    system.refresh_all();\n\n    let cpu_brand = system\n        .cpus()\n        .first()\n        .map(|cpu| cpu.brand().to_string())\n        .unwrap_or_default();\n\n    let memory_used = sysinfo::get_current_pid()\n        .and_then(|pid| system.process(pid).ok_or(\"Process not found\"))\n        .map(Process::memory)\n        .ok();\n\n    system::Information {\n        system_name: System::name(),\n        system_kernel: System::kernel_version(),\n        system_version: System::long_os_version(),\n        system_short_version: System::os_version(),\n        cpu_brand,\n        cpu_cores: system.physical_core_count(),\n        memory_total: system.total_memory(),\n        memory_used,\n        graphics_adapter: graphics.adapter,\n        graphics_backend: graphics.backend,\n    }\n}\n\nfn run_clipboard<Message: Send>(\n    proxy: &mut Proxy<Message>,\n    clipboard: &mut Clipboard,\n    requests: core::Clipboard,\n    window: window::Id,\n) {\n    for kind in requests.reads {\n        let proxy = proxy.clone();\n\n        clipboard.read(kind, move |result| {\n            proxy.send_action(Action::Event {\n                window,\n                event: core::Event::Clipboard(core::clipboard::Event::Read(result.map(Arc::new))),\n            });\n        });\n    }\n\n    if let Some(content) = requests.write {\n        let proxy = proxy.clone();\n\n        clipboard.write(content, move |result| {\n            proxy.send_action(Action::Event {\n                window,\n                event: core::Event::Clipboard(core::clipboard::Event::Written(result)),\n            });\n        });\n    }\n}\n"
  },
  {
    "path": "winit/src/proxy.rs",
    "content": "use crate::futures::futures::{\n    Future, Sink, StreamExt,\n    channel::mpsc,\n    select,\n    task::{Context, Poll},\n};\nuse crate::graphics::shell;\nuse crate::runtime::Action;\nuse crate::runtime::window;\nuse std::pin::Pin;\n\n/// An event loop proxy with backpressure that implements `Sink`.\n#[derive(Debug)]\npub struct Proxy<T: 'static> {\n    raw: winit::event_loop::EventLoopProxy<Action<T>>,\n    sender: mpsc::Sender<Action<T>>,\n    notifier: mpsc::Sender<usize>,\n}\n\nimpl<T: 'static> Clone for Proxy<T> {\n    fn clone(&self) -> Self {\n        Self {\n            raw: self.raw.clone(),\n            sender: self.sender.clone(),\n            notifier: self.notifier.clone(),\n        }\n    }\n}\n\nimpl<T: 'static> Proxy<T> {\n    const MAX_SIZE: usize = 100;\n\n    /// Creates a new [`Proxy`] from an `EventLoopProxy`.\n    pub fn new(\n        raw: winit::event_loop::EventLoopProxy<Action<T>>,\n    ) -> (Self, impl Future<Output = ()>) {\n        let (notifier, mut processed) = mpsc::channel(Self::MAX_SIZE);\n        let (sender, mut receiver) = mpsc::channel(Self::MAX_SIZE);\n        let proxy = raw.clone();\n\n        let worker = async move {\n            let mut count = 0;\n\n            loop {\n                if count < Self::MAX_SIZE {\n                    select! {\n                        message = receiver.select_next_some() => {\n                            let _ = proxy.send_event(message);\n                            count += 1;\n\n                        }\n                        amount = processed.select_next_some() => {\n                            count = count.saturating_sub(amount);\n                        }\n                        complete => break,\n                    }\n                } else {\n                    select! {\n                        amount = processed.select_next_some() => {\n                            count = count.saturating_sub(amount);\n                        }\n                        complete => break,\n                    }\n                }\n            }\n        };\n\n        (\n            Self {\n                raw,\n                sender,\n                notifier,\n            },\n            worker,\n        )\n    }\n\n    /// Sends a value to the event loop.\n    ///\n    /// Note: This skips the backpressure mechanism with an unbounded\n    /// channel. Use sparingly!\n    pub fn send(&self, value: T) {\n        self.send_action(Action::Output(value));\n    }\n\n    /// Sends an action to the event loop.\n    ///\n    /// Note: This skips the backpressure mechanism with an unbounded\n    /// channel. Use sparingly!\n    pub fn send_action(&self, action: Action<T>) {\n        let _ = self.raw.send_event(action);\n    }\n\n    /// Frees an amount of slots for additional messages to be queued in\n    /// this [`Proxy`].\n    pub fn free_slots(&mut self, amount: usize) {\n        let _ = self.notifier.start_send(amount);\n    }\n}\n\nimpl<T: 'static> Sink<Action<T>> for Proxy<T> {\n    type Error = mpsc::SendError;\n\n    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.sender.poll_ready(cx)\n    }\n\n    fn start_send(mut self: Pin<&mut Self>, action: Action<T>) -> Result<(), Self::Error> {\n        self.sender.start_send(action)\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        match self.sender.poll_ready(cx) {\n            Poll::Ready(Err(ref e)) if e.is_disconnected() => {\n                // If the receiver disconnected, we consider the sink to be flushed.\n                Poll::Ready(Ok(()))\n            }\n            x => x,\n        }\n    }\n\n    fn poll_close(\n        mut self: Pin<&mut Self>,\n        _cx: &mut Context<'_>,\n    ) -> Poll<Result<(), Self::Error>> {\n        self.sender.disconnect();\n        Poll::Ready(Ok(()))\n    }\n}\n\nimpl<T> shell::Notifier for Proxy<T>\nwhere\n    T: Send,\n{\n    fn tick(&self) {\n        self.send_action(Action::Tick);\n    }\n\n    fn request_redraw(&self) {\n        self.send_action(Action::Window(window::Action::RedrawAll));\n    }\n\n    fn invalidate_layout(&self) {\n        self.send_action(Action::Window(window::Action::RelayoutAll));\n    }\n}\n"
  },
  {
    "path": "winit/src/window/state.rs",
    "content": "use crate::conversion;\nuse crate::core::{Color, Size};\nuse crate::core::{mouse, theme, window};\nuse crate::graphics::Viewport;\nuse crate::program::{self, Program};\n\nuse winit::event::{Touch, WindowEvent};\nuse winit::window::Window;\n\nuse std::fmt::{Debug, Formatter};\n\n/// The state of the window of a [`Program`].\npub struct State<P: Program>\nwhere\n    P::Theme: theme::Base,\n{\n    title: String,\n    scale_factor: f32,\n    viewport: Viewport,\n    surface_version: u64,\n    cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,\n    modifiers: winit::keyboard::ModifiersState,\n    theme: Option<P::Theme>,\n    theme_mode: theme::Mode,\n    default_theme: P::Theme,\n    style: theme::Style,\n}\n\nimpl<P: Program> Debug for State<P>\nwhere\n    P::Theme: theme::Base,\n{\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"window::State\")\n            .field(\"title\", &self.title)\n            .field(\"scale_factor\", &self.scale_factor)\n            .field(\"viewport\", &self.viewport)\n            .field(\"cursor_position\", &self.cursor_position)\n            .field(\"style\", &self.style)\n            .finish()\n    }\n}\n\nimpl<P: Program> State<P>\nwhere\n    P::Theme: theme::Base,\n{\n    /// Creates a new [`State`] for the provided [`Program`]'s `window`.\n    pub fn new(\n        program: &program::Instance<P>,\n        window_id: window::Id,\n        window: &Window,\n        system_theme: theme::Mode,\n    ) -> Self {\n        let title = program.title(window_id);\n        let scale_factor = program.scale_factor(window_id);\n        let theme = program.theme(window_id);\n        let theme_mode = theme.as_ref().map(theme::Base::mode).unwrap_or_default();\n        let default_theme = <P::Theme as theme::Base>::default(system_theme);\n        let style = program.style(theme.as_ref().unwrap_or(&default_theme));\n\n        let viewport = {\n            let physical_size = window.inner_size();\n\n            Viewport::with_physical_size(\n                Size::new(physical_size.width, physical_size.height),\n                window.scale_factor() as f32 * scale_factor,\n            )\n        };\n\n        Self {\n            title,\n            scale_factor,\n            viewport,\n            surface_version: 0,\n            cursor_position: None,\n            modifiers: winit::keyboard::ModifiersState::default(),\n            theme,\n            theme_mode,\n            default_theme,\n            style,\n        }\n    }\n\n    pub fn viewport(&self) -> &Viewport {\n        &self.viewport\n    }\n\n    pub fn surface_version(&self) -> u64 {\n        self.surface_version\n    }\n\n    pub fn physical_size(&self) -> Size<u32> {\n        self.viewport.physical_size()\n    }\n\n    pub fn logical_size(&self) -> Size<f32> {\n        self.viewport.logical_size()\n    }\n\n    pub fn scale_factor(&self) -> f32 {\n        self.viewport.scale_factor()\n    }\n\n    pub fn cursor(&self) -> mouse::Cursor {\n        self.cursor_position\n            .map(|cursor_position| {\n                conversion::cursor_position(cursor_position, self.viewport.scale_factor())\n            })\n            .map(mouse::Cursor::Available)\n            .unwrap_or(mouse::Cursor::Unavailable)\n    }\n\n    pub fn modifiers(&self) -> winit::keyboard::ModifiersState {\n        self.modifiers\n    }\n\n    pub fn theme(&self) -> &P::Theme {\n        self.theme.as_ref().unwrap_or(&self.default_theme)\n    }\n\n    pub fn theme_mode(&self) -> theme::Mode {\n        self.theme_mode\n    }\n\n    pub fn background_color(&self) -> Color {\n        self.style.background_color\n    }\n\n    pub fn text_color(&self) -> Color {\n        self.style.text_color\n    }\n\n    pub fn update(&mut self, program: &program::Instance<P>, window: &Window, event: &WindowEvent) {\n        match event {\n            WindowEvent::Resized(new_size) => {\n                let size = Size::new(new_size.width, new_size.height);\n\n                self.viewport = Viewport::with_physical_size(\n                    size,\n                    window.scale_factor() as f32 * self.scale_factor,\n                );\n                self.surface_version += 1;\n            }\n            WindowEvent::ScaleFactorChanged {\n                scale_factor: new_scale_factor,\n                ..\n            } => {\n                let size = self.viewport.physical_size();\n\n                self.viewport = Viewport::with_physical_size(\n                    size,\n                    *new_scale_factor as f32 * self.scale_factor,\n                );\n                self.surface_version += 1;\n            }\n            WindowEvent::CursorMoved { position, .. }\n            | WindowEvent::Touch(Touch {\n                location: position, ..\n            }) => {\n                self.cursor_position = Some(*position);\n            }\n            WindowEvent::CursorLeft { .. } => {\n                self.cursor_position = None;\n            }\n            WindowEvent::ModifiersChanged(new_modifiers) => {\n                self.modifiers = new_modifiers.state();\n            }\n            WindowEvent::ThemeChanged(theme) => {\n                self.default_theme =\n                    <P::Theme as theme::Base>::default(conversion::theme_mode(*theme));\n\n                if self.theme.is_none() {\n                    self.style = program.style(&self.default_theme);\n                    window.request_redraw();\n                }\n            }\n            _ => {}\n        }\n    }\n\n    pub fn synchronize(\n        &mut self,\n        program: &program::Instance<P>,\n        window_id: window::Id,\n        window: &Window,\n    ) {\n        // Update window title\n        let new_title = program.title(window_id);\n\n        if self.title != new_title {\n            window.set_title(&new_title);\n            self.title = new_title;\n        }\n\n        // Update scale factor\n        let new_scale_factor = program.scale_factor(window_id);\n\n        if self.scale_factor != new_scale_factor {\n            self.viewport = Viewport::with_physical_size(\n                self.viewport.physical_size(),\n                window.scale_factor() as f32 * new_scale_factor,\n            );\n\n            self.scale_factor = new_scale_factor;\n        }\n\n        // Update theme and appearance\n        self.theme = program.theme(window_id);\n        self.style = program.style(self.theme());\n\n        let new_mode = self\n            .theme\n            .as_ref()\n            .map(theme::Base::mode)\n            .unwrap_or_default();\n\n        if self.theme_mode != new_mode {\n            #[cfg(not(target_os = \"linux\"))]\n            {\n                window.set_theme(conversion::window_theme(new_mode));\n\n                // Assume the old mode matches the system one\n                // We will be notified otherwise\n                if new_mode == theme::Mode::None {\n                    self.default_theme = <P::Theme as theme::Base>::default(self.theme_mode);\n\n                    if self.theme.is_none() {\n                        self.style = program.style(&self.default_theme);\n                    }\n                }\n            }\n\n            #[cfg(target_os = \"linux\")]\n            {\n                // mundy always notifies system theme changes, so we\n                // just restore the default theme mode.\n                let new_mode = if new_mode == theme::Mode::None {\n                    theme::Base::mode(&self.default_theme)\n                } else {\n                    new_mode\n                };\n\n                window.set_theme(conversion::window_theme(new_mode));\n            }\n\n            self.theme_mode = new_mode;\n        }\n    }\n}\n"
  },
  {
    "path": "winit/src/window.rs",
    "content": "mod state;\n\nuse state::State;\n\npub use crate::core::window::{Event, Id, RedrawRequest, Settings};\n\nuse crate::conversion;\nuse crate::core::alignment;\nuse crate::core::input_method;\nuse crate::core::mouse;\nuse crate::core::renderer;\nuse crate::core::text;\nuse crate::core::theme;\nuse crate::core::time::Instant;\nuse crate::core::{Color, InputMethod, Padding, Point, Rectangle, Size, Text, Vector};\nuse crate::graphics::Compositor;\nuse crate::program::{self, Program};\nuse crate::runtime::window::raw_window_handle;\n\nuse winit::dpi::{LogicalPosition, LogicalSize};\nuse winit::monitor::MonitorHandle;\n\nuse std::collections::BTreeMap;\nuse std::sync::Arc;\n\npub struct WindowManager<P, C>\nwhere\n    P: Program,\n    C: Compositor<Renderer = P::Renderer>,\n    P::Theme: theme::Base,\n{\n    aliases: BTreeMap<winit::window::WindowId, Id>,\n    entries: BTreeMap<Id, Window<P, C>>,\n}\n\nimpl<P, C> WindowManager<P, C>\nwhere\n    P: Program,\n    C: Compositor<Renderer = P::Renderer>,\n    P::Theme: theme::Base,\n{\n    pub fn new() -> Self {\n        Self {\n            aliases: BTreeMap::new(),\n            entries: BTreeMap::new(),\n        }\n    }\n\n    pub fn insert(\n        &mut self,\n        id: Id,\n        window: Arc<winit::window::Window>,\n        program: &program::Instance<P>,\n        compositor: &mut C,\n        renderer_settings: renderer::Settings,\n        exit_on_close_request: bool,\n        system_theme: theme::Mode,\n    ) -> &mut Window<P, C> {\n        let state = State::new(program, id, &window, system_theme);\n        let surface_size = state.physical_size();\n        let surface_version = state.surface_version();\n        let surface =\n            compositor.create_surface(window.clone(), surface_size.width, surface_size.height);\n        let renderer = compositor.create_renderer(renderer_settings);\n\n        let _ = self.aliases.insert(window.id(), id);\n\n        let _ = self.entries.insert(\n            id,\n            Window {\n                raw: window,\n                state,\n                exit_on_close_request,\n                surface,\n                surface_version,\n                renderer,\n                mouse_interaction: mouse::Interaction::None,\n                redraw_at: None,\n                preedit: None,\n                ime_state: None,\n            },\n        );\n\n        self.entries\n            .get_mut(&id)\n            .expect(\"Get window that was just inserted\")\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.entries.is_empty()\n    }\n\n    pub fn is_idle(&self) -> bool {\n        self.entries\n            .values()\n            .all(|window| window.redraw_at.is_none())\n    }\n\n    pub fn redraw_at(&self) -> Option<Instant> {\n        self.entries\n            .values()\n            .filter_map(|window| window.redraw_at)\n            .min()\n    }\n\n    pub fn first(&self) -> Option<&Window<P, C>> {\n        self.entries.first_key_value().map(|(_id, window)| window)\n    }\n\n    pub fn iter_mut(&mut self) -> impl Iterator<Item = (Id, &mut Window<P, C>)> {\n        self.entries.iter_mut().map(|(k, v)| (*k, v))\n    }\n\n    pub fn get(&self, id: Id) -> Option<&Window<P, C>> {\n        self.entries.get(&id)\n    }\n\n    pub fn get_mut(&mut self, id: Id) -> Option<&mut Window<P, C>> {\n        self.entries.get_mut(&id)\n    }\n\n    pub fn get_mut_alias(\n        &mut self,\n        id: winit::window::WindowId,\n    ) -> Option<(Id, &mut Window<P, C>)> {\n        let id = self.aliases.get(&id).copied()?;\n\n        Some((id, self.get_mut(id)?))\n    }\n\n    pub fn last_monitor(&self) -> Option<MonitorHandle> {\n        self.entries.values().last()?.raw.current_monitor()\n    }\n\n    pub fn remove(&mut self, id: Id) -> Option<Window<P, C>> {\n        let window = self.entries.remove(&id)?;\n        let _ = self.aliases.remove(&window.raw.id());\n\n        Some(window)\n    }\n}\n\nimpl<P, C> Default for WindowManager<P, C>\nwhere\n    P: Program,\n    C: Compositor<Renderer = P::Renderer>,\n    P::Theme: theme::Base,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\npub struct Window<P, C>\nwhere\n    P: Program,\n    C: Compositor<Renderer = P::Renderer>,\n    P::Theme: theme::Base,\n{\n    pub raw: Arc<winit::window::Window>,\n    pub state: State<P>,\n    pub exit_on_close_request: bool,\n    pub mouse_interaction: mouse::Interaction,\n    pub surface: C::Surface,\n    pub surface_version: u64,\n    pub renderer: P::Renderer,\n    pub redraw_at: Option<Instant>,\n    preedit: Option<Preedit<P::Renderer>>,\n    ime_state: Option<(Rectangle, input_method::Purpose)>,\n}\n\nimpl<P, C> Window<P, C>\nwhere\n    P: Program,\n    C: Compositor<Renderer = P::Renderer>,\n    P::Theme: theme::Base,\n{\n    pub fn position(&self) -> Option<Point> {\n        self.raw\n            .outer_position()\n            .ok()\n            .map(|position| position.to_logical(self.raw.scale_factor()))\n            .map(|position| Point {\n                x: position.x,\n                y: position.y,\n            })\n    }\n\n    pub fn request_redraw(&mut self, redraw_request: RedrawRequest) {\n        match redraw_request {\n            RedrawRequest::NextFrame => {\n                self.raw.request_redraw();\n                self.redraw_at = None;\n            }\n            RedrawRequest::At(at) => {\n                self.redraw_at = Some(at);\n            }\n            RedrawRequest::Wait => {}\n        }\n    }\n\n    pub fn request_input_method(&mut self, input_method: InputMethod) {\n        match input_method {\n            InputMethod::Disabled => {\n                self.disable_ime();\n            }\n            InputMethod::Enabled {\n                cursor,\n                purpose,\n                preedit,\n            } => {\n                self.enable_ime(cursor, purpose);\n\n                if let Some(preedit) = preedit {\n                    if preedit.content.is_empty() {\n                        self.preedit = None;\n                    } else {\n                        let mut overlay = self.preedit.take().unwrap_or_else(Preedit::new);\n\n                        overlay.update(\n                            cursor,\n                            &preedit,\n                            self.state.background_color(),\n                            &self.renderer,\n                        );\n\n                        self.preedit = Some(overlay);\n                    }\n                } else {\n                    self.preedit = None;\n                }\n            }\n        }\n    }\n\n    pub fn update_mouse(&mut self, interaction: mouse::Interaction) {\n        if interaction != self.mouse_interaction {\n            if let Some(icon) = conversion::mouse_interaction(interaction) {\n                self.raw.set_cursor(icon);\n\n                if self.mouse_interaction == mouse::Interaction::Hidden {\n                    self.raw.set_cursor_visible(true);\n                }\n            } else {\n                self.raw.set_cursor_visible(false);\n            }\n\n            self.mouse_interaction = interaction;\n        }\n    }\n\n    pub fn draw_preedit(&mut self) {\n        if let Some(preedit) = &self.preedit {\n            preedit.draw(\n                &mut self.renderer,\n                self.state.text_color(),\n                self.state.background_color(),\n                &Rectangle::new(Point::ORIGIN, self.state.viewport().logical_size()),\n            );\n        }\n    }\n\n    fn enable_ime(&mut self, cursor: Rectangle, purpose: input_method::Purpose) {\n        if self.ime_state.is_none() {\n            self.raw.set_ime_allowed(true);\n        }\n\n        if self.ime_state != Some((cursor, purpose)) {\n            self.raw.set_ime_cursor_area(\n                LogicalPosition::new(cursor.x, cursor.y),\n                LogicalSize::new(cursor.width, cursor.height),\n            );\n            self.raw.set_ime_purpose(conversion::ime_purpose(purpose));\n\n            self.ime_state = Some((cursor, purpose));\n        }\n    }\n\n    fn disable_ime(&mut self) {\n        if self.ime_state.is_some() {\n            self.raw.set_ime_allowed(false);\n            self.ime_state = None;\n        }\n\n        self.preedit = None;\n    }\n}\n\nimpl<P, C> raw_window_handle::HasWindowHandle for Window<P, C>\nwhere\n    P: Program,\n    C: Compositor<Renderer = P::Renderer>,\n{\n    fn window_handle(\n        &self,\n    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {\n        self.raw.window_handle()\n    }\n}\n\nimpl<P, C> raw_window_handle::HasDisplayHandle for Window<P, C>\nwhere\n    P: Program,\n    C: Compositor<Renderer = P::Renderer>,\n{\n    fn display_handle(\n        &self,\n    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {\n        self.raw.display_handle()\n    }\n}\n\nstruct Preedit<Renderer>\nwhere\n    Renderer: text::Renderer,\n{\n    position: Point,\n    content: Renderer::Paragraph,\n    spans: Vec<text::Span<'static, (), Renderer::Font>>,\n}\n\nimpl<Renderer> Preedit<Renderer>\nwhere\n    Renderer: text::Renderer,\n{\n    fn new() -> Self {\n        Self {\n            position: Point::ORIGIN,\n            spans: Vec::new(),\n            content: Renderer::Paragraph::default(),\n        }\n    }\n\n    fn update(\n        &mut self,\n        cursor: Rectangle,\n        preedit: &input_method::Preedit,\n        background: Color,\n        renderer: &Renderer,\n    ) {\n        self.position = cursor.position() + Vector::new(0.0, cursor.height);\n\n        let background = Color {\n            a: 1.0,\n            ..background\n        };\n\n        let spans = match &preedit.selection {\n            Some(selection) => {\n                vec![\n                    text::Span::new(&preedit.content[..selection.start]),\n                    text::Span::new(if selection.start == selection.end {\n                        \"\\u{200A}\"\n                    } else {\n                        &preedit.content[selection.start..selection.end]\n                    })\n                    .color(background),\n                    text::Span::new(&preedit.content[selection.end..]),\n                ]\n            }\n            _ => vec![text::Span::new(&preedit.content)],\n        };\n\n        if spans != self.spans.as_slice() {\n            use text::Paragraph as _;\n\n            self.content = Renderer::Paragraph::with_spans(Text {\n                content: &spans,\n                bounds: Size::INFINITE,\n                size: preedit.text_size.unwrap_or_else(|| renderer.default_size()),\n                line_height: text::LineHeight::default(),\n                font: renderer.default_font(),\n                align_x: text::Alignment::Default,\n                align_y: alignment::Vertical::Top,\n                shaping: text::Shaping::Advanced,\n                wrapping: text::Wrapping::None,\n                ellipsis: text::Ellipsis::None,\n                hint_factor: renderer.scale_factor(),\n            });\n\n            self.spans.clear();\n            self.spans\n                .extend(spans.into_iter().map(text::Span::to_static));\n        }\n    }\n\n    fn draw(&self, renderer: &mut Renderer, color: Color, background: Color, viewport: &Rectangle) {\n        use text::Paragraph as _;\n\n        if self.content.min_width() < 1.0 {\n            return;\n        }\n\n        let mut bounds = Rectangle::new(\n            self.position - Vector::new(0.0, self.content.min_height()),\n            self.content.min_bounds(),\n        );\n\n        bounds.x = bounds\n            .x\n            .max(viewport.x)\n            .min(viewport.x + viewport.width - bounds.width);\n\n        bounds.y = bounds\n            .y\n            .max(viewport.y)\n            .min(viewport.y + viewport.height - bounds.height);\n\n        renderer.with_layer(bounds, |renderer| {\n            let background = Color {\n                a: 1.0,\n                ..background\n            };\n\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds,\n                    ..Default::default()\n                },\n                background,\n            );\n\n            renderer.fill_paragraph(&self.content, bounds.position(), color, bounds);\n\n            const UNDERLINE: f32 = 2.0;\n\n            renderer.fill_quad(\n                renderer::Quad {\n                    bounds: bounds.shrink(Padding {\n                        top: bounds.height - UNDERLINE,\n                        ..Default::default()\n                    }),\n                    ..Default::default()\n                },\n                color,\n            );\n\n            for span_bounds in self.content.span_bounds(1) {\n                renderer.fill_quad(\n                    renderer::Quad {\n                        bounds: span_bounds + (bounds.position() - Point::ORIGIN),\n                        ..Default::default()\n                    },\n                    color,\n                );\n            }\n        });\n    }\n}\n"
  }
]