1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-26 22:53:14 -04:00
Commit Graph

3988 Commits

Author SHA1 Message Date
YgorSouza
669cdc1fff Remove line breaks when pasting into single line TextEdit (#7441)
The line breaks are now replaced by spaces, matching the usual behavior
of text fields in HTML.

* Closes <https://github.com/emilk/egui/issues/7389>
* [x] I have followed the instructions in the PR template

Co-authored-by: Lucas Meurer <hi@lucasmerlin.me>
2025-09-04 13:53:02 +02:00
Andrew Farkas
1c460b6dc0 Skip zero-length layout job sections (#7430)
Fixes #7378 

Includes a regression test that previously failed and now succeeds.

* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
Co-authored-by: Lucas Meurer <hi@lucasmerlin.me>
2025-09-04 13:17:59 +02:00
Aleksandr Strizhevskiy
763e2df9f9 Fix: prevent calendar popup from closing on dropdown change (#7409)
Currently, DatePickerButton will close without saving whenever a user
clicks a dropdown from year/month/date. The issue is caused because the
system mistakenly interprets the user as clicking off of the calendar.
This is unexpected and creates an unpleasant experience for the user.
This change now allows the user to use the dropdowns as expected; it
will close on save or cancel. The calendar still closes when user clicks
off of it, as before. The changes here are made in:
crates/egui_extras/src/datepicker/button.rs

I will admit that I am not an experienced Rust developer. The changes
were made with the help of ChatGPT 4.0.
I have tested the changes locally, as I am using the date picker in my
project.


* Closes <https://github.com/emilk/egui/issues/THE_RELEVANT_ISSUE>
* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Lucas Meurer <hi@lucasmerlin.me>
2025-09-04 13:13:28 +02:00
darkwater
3a2094e80e Add Memory::move_focus (#7476)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* [X] I have followed the instructions in the PR template

This allows us to programatically move focus around. Another way would
be to inject arrow key inputs, but that requires the backend to
implement a way to do that, and could have unintended side-effects.

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-09-04 13:02:18 +02:00
Lucas Meurer
80d61a7c53 Remove the deadlock_detection feature (#7497)
* related #7494 

Removes the `deadlock_detection` feature, since we now have a more
primitive panic-after-30s deadlock detection which works well enough and
even detects kinds of deadlocks that the `deadlock_detection` feature
never supported.
2025-09-04 12:57:09 +02:00
Lucas Meurer
d66fa63e20 Add reasonable timeouts to all workflows (#7499)
Turns out the default timeout for github actions is 6 hours (!). This PR
sets some reasonable default for all workflows, the ones invoking cargo
in some way are limited to 60 minutes and the remaining ones to
10-15mins.
2025-09-04 12:37:24 +02:00
Lucas Meurer
fa4bee3bf7 Fix deadlock in ImageLoader, FileLoader, EhttpLoader (#7494)
* Recently CI runs started to hang randomly:
https://github.com/emilk/egui/actions/runs/17427449210/job/49477714447?pr=7359

This fixes the deadlock and adds the basic deadlock detection we also
added to Mutexes in #7468.

Also, interestingly, the more sophisticated deadlock detection (behind
the deadlock_detection feature) didn't catch this for some reason. I
wonder why it exists in the first place, when parking_lot also has built
in deadlock detection? It also seems to make tests slower, widget_tests
usually needs ~30s, with the deadlock detection removed its only ~12s.
2025-09-04 10:31:26 +02:00
Lucas Meurer
d3cd6d44cf Add Ui::place, to place widgets without changing the cursor (#7359)
* Closes <https://github.com/emilk/egui/issues/7353>

Currently `ui.put` moves the cursor after the placed widget. In my
opinion that is a bit unexpected and counterproductive in most cases
where `ui.put` makes sense.

The following example breakes with the current behavior and looks right
with my change:
```rs
            ui.horizontal(|ui| {
                let custom_button_id = Id::new("custom_button");
                let response = Button::new((
                    Atom::custom(custom_button_id, Vec2::splat(18.0)),
                    "Look at my mini button!",
                ))
                .atom_ui(ui);
                if let Some(rect) = response.rect(custom_button_id) {
                    ui.put(rect, Button::new("🔎").frame_when_inactive(false));
                }

                let custom_button_id = Id::new("custom_button");
                let response = Button::new((
                    Atom::custom(custom_button_id, Vec2::splat(18.0)),
                    "Look at my mini button!",
                ))
                .atom_ui(ui);
                if let Some(rect) = response.rect(custom_button_id) {
                    ui.put(rect, Button::new("🔎").frame_when_inactive(false));
                }
            });

            ui.add_space(10.0);

            let response = ui.button("Notifications");

            ui.put(
                Rect::from_center_size(response.rect.right_top(), Vec2::splat(12.0)),
                |ui: &mut Ui| {
                    Frame::new()
                        .fill(Color32::RED)
                        .corner_radius(10.0)
                        .show(ui, |ui| {
                            ui.label(RichText::new("11").size(8.0).color(Color32::WHITE));
                        }).response
                },
            );

            ui.button("Some other button");
```

<img width="253" height="86" alt="Screenshot 2025-07-14 at 10 58 30"
src="https://github.com/user-attachments/assets/fca56e60-e3c0-4b59-8e2d-0a39aefea9f9"
/>


<img width="361" height="107" alt="Screenshot 2025-07-14 at 10 58 51"
src="https://github.com/user-attachments/assets/85e2fbf9-9174-41e0-adaa-60c721b16bf6"
/>

I had a look at reruns source code and there are no uses of `ui.put`
that would break with this change (very little usages in general).

## Alternatives
Instead of a breaking change we could of course instead introduce a new
metheod (e.g. `Ui::place`?).
2025-09-04 10:07:35 +02:00
Emil Ernerfeldt
4947b191e4 Make more dependencies workspace dependencies (#7495) 2025-09-04 09:54:59 +02:00
Oscar Gustafsson
b9414bd4cc Selectively update dependencies to reduce total number (#7488)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* [x] I have followed the instructions in the PR template

Update some of the core dependencies and run cargo update for selected
dependencies to remove total number and older versions.
2025-09-04 09:42:46 +02:00
Dot32
01ee9c72d5 Fix typo in the description of the id method in ui.rs (#7457)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* [x] I have followed the instructions in the PR template

The description of the id method in the Ui struct incorrectly wrote
"where" instead of "were".

<img width="668" height="201" alt="Screenshot 2025-08-15 at 7 03 27 pm"
src="https://github.com/user-attachments/assets/df35cdab-b3ad-44d4-a565-cd9a4d883f21"
/>

This PR fixes that typo.
2025-09-04 09:18:53 +02:00
Lucas Meurer
ab8dcee7e7 Fix egui_demo_app missing wgpu backends (#7492)
* This was broken in https://github.com/emilk/egui/pull/7344
2025-09-03 12:55:02 +02:00
n4n5
0a81372cfd Add theme selection for code editor (#7375)
Change the theme selection of the code editor

Before
- was showing the window theme selector

After
- is showing the code editor theme selector


<img width="327" height="262" alt="image"
src="https://github.com/user-attachments/assets/50776218-26cc-4f11-9b91-6f902c022394"
/>


* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-24 16:41:10 +02:00
Sergey Ukolov
2957fd56a5 Fix: use unique id for resize columns in Table (#7414)
Currently the IDs for resize columns in Table are based on the ID of
parent. When placing multiple tables within the same parent the ID clash
for resize columns occurs despite the
[TableBuilder::id_salt](https://docs.rs/egui_extras/0.32.0/egui_extras/struct.TableBuilder.html#method.id_salt)
is being used.
2025-08-24 16:40:44 +02:00
Emil Ernerfeldt
0fad7d8503 Enable more clippy lints (#7474) 2025-08-24 16:27:28 +02:00
Emil Ernerfeldt
608de4a264 Update bytemuck (#7475) 2025-08-24 16:27:21 +02:00
Emil Ernerfeldt
a5a51ced0f Improve egui-winit profile scope 2025-08-24 15:03:57 +02:00
ozwaldorf
454af7aa6c fix: SubMenu should not display when ui is disabled (#7428)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

Adds a check for `ui.is_enabled()` when displaying the SubMenu items.
There were a few places the condition could be placed, but I figured
there was simplest. The inner button will already not be able to be
clicked due to ui being disabled.

cc @lucasmerlin 

* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-24 14:43:31 +02:00
Lucas Meurer
42c2fc58c9 Allow masking widgets in kittest snapshots (#7467)
* Closes <https://github.com/emilk/egui/issues/THE_RELEVANT_ISSUE>
* [ ] I have followed the instructions in the PR template
2025-08-21 17:46:36 +02:00
Lucas Meurer
bf981b8d3e Add SurrenderFocusOn option (#7471)
* [X] I have followed the instructions in the PR template

On touch devices you don't want the keyboard to disappear when
scrolling, so this PR adds a `SurrenderFocusOn` enum to configure on
what interaction to surrender focus.
2025-08-21 17:45:34 +02:00
Emil Ernerfeldt
5453cceded Use official cargo machete action (#7470) 2025-08-21 15:42:10 +02:00
Emil Ernerfeldt
531ead5ad1 Update MSRV to 1.86 (#7469) 2025-08-21 15:38:41 +02:00
Emil Ernerfeldt
1da1d57c11 Panic mutexes that can't lock for 30 seconds, in debug builds (#7468)
I'm trying to debug a suspected deadlock in the CI for
https://github.com/emilk/egui/pull/7467

Since we use our own mutex wrappers, we can just panic if the lock is
too slow. Ugly and effective :)
2025-08-21 15:31:56 +02:00
Emil Ernerfeldt
7c5798289d Bump version numbers to 0.32.1 2025-08-15 13:43:27 +02:00
Emil Ernerfeldt
6a355c3808 Add 0.32.1 to changelogs 2025-08-15 13:42:49 +02:00
Emil Ernerfeldt
b24a56d3f7 Only update snapshot if we didn't pass (#7455)
* Closes https://github.com/emilk/egui/issues/7449
2025-08-15 12:21:51 +02:00
Emil Ernerfeldt
839ee3eaf7 Make sure we always track the root viewport (#7450)
Some sanity checks I added while working on another bug
2025-08-14 12:03:38 +02:00
YgorSouza
a7ae1012e5 Fix debug-panic in ScrollArea if contents fit without scrolling (#7440)
If the ScrollArea's contents are smaller than the inner rect, but the
scrollbar is set to always visible, clicking on it led to a remap from
an empty range to calculate the new offset, which triggered a debug
assertion in the remap function, because the result is indeterminate.

Since in this case there is no need to scroll, we just skip the remap
and set the offset to 0 directly.

* Closes <https://github.com/emilk/egui/issues/7362>
* [x] I have followed the instructions in the PR template
2025-08-14 10:41:51 +02:00
YgorSouza
1937cc4d61 Fix override_text_color priority (#7439)
The override_text_color is now used when rendering text from a String or
&str. This is consistent with the RichText variant and makes the option
behave as advertised, taking precedence over WidgetVisuals and
overriding the color for all text unless explicitly changed for a single
widget (via RichText or LayoutJob).

* Closes <https://github.com/emilk/egui/issues/7367>
* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-14 10:40:04 +02:00
Lucas Meurer
c2de29a8de Fix WidgetText::Text ignoring fallback font and overrides (#7361)
* closes https://github.com/emilk/egui/issues/7356
2025-08-13 14:56:26 +02:00
Luke M
e794de5ffa Document platform compatibility on viewport::WindowLevel and dependents (#7432)
Documents platform compatibility on the WindowLevel struct and some of
the methods that are dependent on it. Provides a link to
`winit:🪟:WindowLevel` documentation section that provides a list
of which platforms are supported.

* Closes [Issue 7419](https://github.com/emilk/egui/issues/7419)
* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-12 12:35:45 +02:00
Emil Ernerfeldt
42bdf5b881 Fix link checker CI (#7308) 2025-08-12 12:34:53 +02:00
Sola
adf463b0a9 Replace winapi with windows-sys crate (#7416)
This the second take of <https://github.com/emilk/egui/pull/5038>,
adjusted for newer version of `windows-sys`, and with merge conflicts
resolved. I added the original author to `Co-authored-by:`.

* Closes <https://github.com/emilk/egui/issues/7334>
* Closes <https://github.com/emilk/egui/pull/5038>
* [x] I have followed the instructions in the PR template

Tested on Windows 10:
<img width="322" height="272" alt="image"
src="https://github.com/user-attachments/assets/15ddf0bf-1f30-452f-8764-07ccfce2b00c"
/>
<img width="802" height="632" alt="image"
src="https://github.com/user-attachments/assets/db6f4586-cfa5-4f7f-996c-06f7e2489df6"
/>

Action run result:
https://github.com/sola-contrib/egui/actions/runs/16748810761

---------

Co-authored-by: Casper Meijn <casper@meijn.net>
2025-08-12 12:28:51 +02:00
RndUsr123
68d456ac0b Fixes sense issues in TextEdit when vertical alignment is used (#7436)
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* Closes <https://github.com/emilk/egui/issues/7433>
* [ ] I have followed the instructions in the PR template

I'm running a rustup-less rust install on Windows, so I don't have
`clippy` nor `fmt` and can't run the .sh script.
It's very little code and I manually tested this, so hopefully that's
ok...

Let me know if the comment in `state.rs` needs to be updated or the
`text_offset` name isn't clear enough.

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-12 12:27:55 +02:00
YgorSouza
53d8c48b4f Fix panic on Stroke style editor widget (#7443)
The infinite limit caused arithmetic issues when rendering the preview
with very large values, which led to a panic. The new limit should still
be higher than anyone would reasonably want to set a stroke width to,
but not high enough to trigger a panic.

* Closes <https://github.com/emilk/egui/issues/7348>
* [x] I have followed the instructions in the PR template
2025-08-12 09:13:50 +02:00
YgorSouza
fb5fe645be Make the hex_color macro const (#7444)
* Closes <https://github.com/emilk/egui/issues/5160>
* [x] I have followed the instructions in the PR template
2025-08-12 09:12:44 +02:00
Emil Ernerfeldt
6fae65a3fa Add emath::fast_midpoint (#7435) 2025-08-08 12:04:51 +02:00
Emil Ernerfeldt
3024c39eaf Enable and fix some more clippy lints (#7426)
One can never have too many lints
2025-08-08 09:57:53 +02:00
Lucas Meurer
e8e99a0bb6 Fix manual Popup not closing (#7383)
Fixes manually created popups (via `Popup::new`) not closing, since
widget_clicked_elsewhere was always false.

This example would never close:

```rs
    let mut open = true;

    eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
        egui::CentralPanel::default().show(ctx, |ui| {
            let response = egui::Popup::new(
                Id::new("popup"),
                ctx.clone(),
                PopupAnchor::Position(Pos2::new(10.0, 10.0)),
                LayerId::new(Order::Foreground, Id::new("popup")),
            )
            .open(open)
            .show(|ui| {
                ui.label("This is a popup!");
                ui.label("You can put anything in here.");
            });

            if let Some(response) = response {
                if response.response.should_close() {
                    open = false;
                }
            }
        });
    })
```

I also noticed that the Color submenu in the popups example had a double
arrow (must have been broken in the atoms PR):

<img width="248" height="110" alt="Screenshot 2025-08-07 at 13 42 28"
src="https://github.com/user-attachments/assets/a4e0c267-ae71-4b2c-a1f0-f53f9662d026"
/>

Also fixed this in the PR.
2025-08-07 14:18:04 +02:00
Emil Ernerfeldt
36a4981f29 Enable clippy::iter_over_hash_type lint (#7421)
This helped discover a few things that _might_ have been buggy.
2025-08-06 13:55:53 +02:00
Emil Ernerfeldt
d42ea3800f Update to winit 0.30.12 (#7420) 2025-08-06 13:53:59 +02:00
satnam72
72fcbb8610 Use Frame::NONE in docstring (#7396)
- Replaced deprecated `egui::Frame::none()` with `egui::Frame::NONE`

<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

* Closes <https://github.com/emilk/egui/issues/7391>
* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-06 13:27:51 +02:00
Emil Ernerfeldt
c8e6f6bfe5 Remove deprecated clippy lint 2025-08-06 11:45:02 +02:00
Lucas Meurer
2c6611d0c6 Enable wgpu default features in eframe / egui_wgpu default features (#7344) 2025-08-05 21:21:00 +02:00
Emil Ernerfeldt
ef039aa566 Enable more clippy lints (#7418)
More is more!
2025-08-05 19:47:26 +02:00
Icekey
e9afd3c52d Add UiBuilder::global_scope and UiBuilder::id (#7372)
I added a new flag to the UiBuilder so that it is possible to move child
widgets around the ui tree without losing state information.
Currently there is no way to create child widgets with the same id at
different locations in the ui tree since ids change in relation the the
parent id. With the new flag a unique global scope can be created which
always results in the same ids even at different locations.
You still need to ensure that the widgets only get rendered once in
frame.

This feature can be used to fix a issue i am having with the
https://github.com/lucasmerlin/hello_egui crate.


* Closes https://github.com/lucasmerlin/hello_egui/issues/75
* [X] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-05 19:26:52 +02:00
Lucas Meurer
3aee525755 Add ComboBox::popup_style (#7360)
* Closes #7349  
* [x] I have followed the instructions in the PR template
2025-08-05 14:55:24 +02:00
Michael Grupp
a1e5501db8 Improve debug_assert when calling add_space() in Grid layout (#7399)
Makes it clearer to understand than the lower-level
`advance_cursor` assert for an user who accidentally does this.
2025-08-05 14:43:02 +02:00
Vanadiae
8333615072 Fix memory leak when forget_image is called while loading (#7380)
This is the same issue that was fixed for the http bytes loader in
239ade9a59

* [x] I have followed the instructions in the PR template

----------------

Funnily, [this
comment](https://github.com/emilk/egui/issues/3747#issuecomment-1872192997)
describes exactly how I encountered this issue:

> That assert is wrong if something calls forget between the start of
the request and the end of it.

I'm displaying lots of images in a scrolling grid (20 or so visible at a
time). It seems like image textures are never freed up automatically so
it stacks up a lot meaning I have to unload the image textures manually
with `egui::Context::forget_image()` in each `eframe::App::update()`
call for the images that are no longer shown when scrolling.

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-08-05 14:41:32 +02:00
Hubert Głuchowski
31eb4d498b Fix multi-line TextShape rotation (#7404)
* Closes <https://github.com/emilk/egui/issues/7397>
* [X] I have followed the instructions in the PR template
I do admit I got a peak NixOS `RequestDeviceError` and deemed it
entirely not worth it to think about that.

https://github.com/emilk/egui/pull/5411 broke rotation of multi-line
`TextShape`s because `PlacedRow::pos` was no longer being rotated, so
let's rotate it.

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
Co-authored-by: Lucas Meurer <hi@lucasmerlin.me>
2025-08-05 13:11:45 +02:00