Commit Graph

23 Commits

Author SHA1 Message Date
Emil Ernerfeldt 72b9b9d750
Increase default text size from 12.5 to 13.0 (#7521) 2025-09-09 15:47:24 +02:00
valadaptive d5b0a6f446
More even text kerning (#7431)
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-09-08 17:29:41 +02:00
Emil Ernerfeldt aedd43c88f
kittest: Add `UPDATE_SNAPSHOTS=force` (#7508)
This adds a new mode, `UPDATE_SNAPSHOTS=force`, which will lower the
threshold to zero, overwriting every image that is not _exactly_ the
same.

Most comparisons has a threshold because different GPUs render slightly
differently. However, setting that threshold accurately can be hard.

Sometimes a test will pass locally, but fail on CI. In those cases you
want to force an update of the failing test. You can use
`UPDATE_SNAPSHOTS=force` for that.

And sometimes a small change _should_ update all images, but the change
is so tiny that it falls under the threshold. Still, you want to make a
point of showing that these images have changes. You can use
`UPDATE_SNAPSHOTS=force` for that.
2025-09-05 16:45:36 +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
Emil Ernerfeldt f46926aaf1
Improve texture filtering by doing it in gamma space (#7311)
* Closes https://github.com/emilk/egui/pull/5839

This makes some transparent images look a lot nicer when blended:


![image](https://github.com/user-attachments/assets/7f370aaf-886a-423c-8391-c378849b63ca)

Cursive text will also look nicer.

This unfortunately changes the contract of what
`register_native_texture` expects

---------

Co-authored-by: Adrian Blumer <blumer.adrian@gmail.com>
2025-07-07 17:46:27 +02:00
Emil Ernerfeldt 09596a5e7b
egui_kittest: more ergonomic functions taking `Impl Into<String>` (#7307) 2025-07-07 13:50:53 +02:00
Emil Ernerfeldt 0857527f1d
Add `Visuals::weak_text_alpha` and `weak_text_color` (#7285)
* Closes https://github.com/emilk/egui/issues/7262

This also makes the default weak color slightly less weak in most cases.
2025-07-01 20:42:54 +02:00
Emil Ernerfeldt 9e021f78da
Change `ui.disable()` to modify opacity (#7282)
* Closes https://github.com/emilk/egui/pull/6765


Branched off of https://github.com/emilk/egui/pull/6765 by @tye-exe.

I needed to branch off to update snapshot images

---------

Co-authored-by: tye-exe <tye@mailbox.org>
Co-authored-by: Tye <131195812+tye-exe@users.noreply.github.com>
2025-07-01 14:05:53 +02:00
Emil Ernerfeldt b2995dcb83
Use Rust edition 2024 (#7280) 2025-06-30 14:01:57 +02:00
Lucas Meurer 0152a87519
Create custom `egui_kittest::Node` (#7138)
This adds a custom Node struct with proper support for egui types
(`Key`, `Modifiers`, `egui::Event`, `Rect`) instead of needing to use
the kittest / accesskit types.

I also changed the `click` function to do a proper mouse move / mouse
down instead of the accesskit click. Also added `accesskit_click` to
trigger the accesskit event. This resulted in some changed snapshots,
since the elements are now hovered.

Also renamed `press_key` to `key_press` for consistency with
`key_down/key_up`.

Also removed the Deref to the AccessKit Node, to make it clearer when to
expect egui and when to expect accesskit types.

* Closes #5705 
* [x] I have followed the instructions in the PR template
2025-06-17 12:17:38 +02:00
Lucas Meurer 6eb7bb6e08
Add `AtomLayout`, abstracing layouting within widgets (#5830)
Today each widget does its own custom layout, which has some drawbacks:
- not very flexible
- you can add an `Image` to `Button` but it will always be shown on the
left side
  - you can't add a `Image` to a e.g. a `SelectableLabel`
- a lot of duplicated code

This PR introduces `Atoms` and `AtomLayout` which abstracts over "widget
content" and layout within widgets, so it'd be possible to add images /
text / custom rendering (for e.g. the checkbox) to any widget.

A simple custom button implementation is now as easy as this:
```rs
pub struct ALButton<'a> {
    al: AtomicLayout<'a>,
}

impl<'a> ALButton<'a> {
    pub fn new(content: impl IntoAtomics) -> Self {
        Self { al: content.into_atomics() }
    }
}

impl<'a> Widget for ALButton<'a> {
    fn ui(mut self, ui: &mut Ui) -> Response {
        let response = ui.ctx().read_response(ui.next_auto_id());

        let visuals = response.map_or(&ui.style().visuals.widgets.inactive, |response| {
            ui.style().interact(&response)
        });

        self.al.frame = self
            .al
            .frame
            .inner_margin(ui.style().spacing.button_padding)
            .fill(visuals.bg_fill)
            .stroke(visuals.bg_stroke)
            .corner_radius(visuals.corner_radius);

        self.al.show(ui)
    }
}

```

The initial implementation only does very basic layout, just enough to
be able to implement most current egui widgets, so:
- only horizontal layout
- everything is centered
- a single item may grow/shrink based on the available space
- everything can be contained in a Frame


There is a trait `IntoAtoms` that conveniently allows you to construct
`Atoms` from a tuple
```
   ui.button((Image::new("image.png"), "Click me!"))
```
to get a button with image and text.


This PR reimplements three egui widgets based on the new AtomLayout:
 - Button
   - matches the old button pixel-by-pixel
- Button with image is now [properly
aligned](https://github.com/emilk/egui/pull/5830/files#diff-962ce2c68ab50724b01c6b64c683c4067edd9b79fcdcb39a6071021e33ebe772)
in justified layouts
   - selected button style now matches SelecatbleLabel look
- For some reason the DragValue text seems shifted by a pixel almost
everywhere, but I think it's more centered now, yay?
 - Checkbox
- basically pixel-perfect but apparently the check mesh is very slightly
different so I had to update the snapshot
   - somehow needs a bit more space in some snapshot tests?
 - RadioButton
   - pixel-perfect
   - somehow needs a bit more space in some snapshot tests?

I plan on updating TextEdit based on AtomLayout in a separate PR (so
you could use it to add a icon within the textedit frame).
2025-06-13 09:39:52 +02:00
Emil Ernerfeldt f9245954eb
Enable more clippy lints (#6853)
* Follows https://github.com/emilk/egui/pull/6848
2025-04-24 17:32:50 +02:00
Emil Ernerfeldt 7ea3f762b8
Make text underline and strikethrough pixel perfect crisp (#5857)
Small visual fix: pixel-align any text underline or strikethrough.
Before they could be often be blurry.
2025-03-28 20:37:38 +01:00
Nicolas 2024295f78
Make ImageLoader use background thread (#5394)
This is the same change as in #4069 but as this is stale I wanted to
reopen a non stale PR

Modifies ImageLoader's load function to use background threads for the
image decoding work. This avoids blocking the main thread that is
especially noticeable when loading many images at once.

This was modelled after the other loader implementations that also use
threads.

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

---------

Co-authored-by: lucasmerlin <lucasmeurer96@gmail.com>
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2025-03-25 10:17:31 +01:00
Emil Ernerfeldt 2058dcb881
Improve text sharpness (#5838)
This improves the sharpness of text slightly, thanks to
<https://hikogui.org/2022/10/24/the-trouble-with-anti-aliasing.html> by
@hikogui (🙏 ).

The difference is very small, but in dark mode (bright text on dark
background) text is sometimes significantly sharper, and also slightly
brighter.

The difference in light mode (dark text on light background) is much
smaller (barely perceptable).

To compare the before/after I suggest you open both in new tabs, then
quickly change between them.

### Low-DPI
#### Before
![Code Editor
old](https://github.com/user-attachments/assets/e10a3cad-932f-48cd-b7d6-5bfe70954c5e)

#### After
![Code
Editor](https://github.com/user-attachments/assets/2e7383fe-8023-4425-91c8-93df3c22c0fe)

#### Before

![old-white](https://github.com/user-attachments/assets/51c41c59-e897-4831-857a-f3ffe17ce7d4)

#### After

![new-white](https://github.com/user-attachments/assets/4ac6f951-8c57-4bcc-a5d5-788cf52ea7d8)

### High-DPI
The difference is starkest on low-DPI screens (like the above
screenshots). On high-DPI screens, the difference is much smaller

#### Before
![widget_gallery
old](https://github.com/user-attachments/assets/f2149a30-aef8-4383-b48c-73d33a03ca02)

#### After

![widget_gallery](https://github.com/user-attachments/assets/c9ceb8be-8a32-490c-9364-2c6562b741f6)
2025-03-21 12:56:47 +01:00
Emil Ernerfeldt 3f731ec794
Fix semi-transparent colors appearing too bright (#5824)
The bug was in `Color32::from_rgba_unmultiplied` and by extension
affects:

* `Color32::from_rgba_unmultiplied`
* `hex_color!`
* `HexColor`
* `ColorImage::from_rgba_unmultiplied`
* All images with transparency (png, webp, …)
* `Color32::from_white_alpha`

The bug caused translucent colors to appear too bright.

## More
Color is hard.

When I started out egui I thought "linear space is objectively better,
for everything!" and then I've been slowly walking that back for various
reasons:

* sRGB textures not available everywhere
* gamma-space is more _perceptually_ even, so it makes sense to use for
anti-aliasing
* other applications do everything in gamma space, so that's what people
expect (this PR)

Similarly, pre-multiplied alpha _makes sense_ for blending colors. It
also enables additive colors, which is nice. But it does complicate
things. Especially when mixed with sRGB/gamma (As @karhu [points
out](https://github.com/emilk/egui/pull/5824#issuecomment-2738099254)).

## Related
* Closes https://github.com/emilk/egui/issues/5751
* Closes https://github.com/emilk/egui/issues/5771 ? (probably; hard to
tell without a repro)
* But not https://github.com/emilk/egui/issues/5810

## TODO
* [x] I broke the RGBA u8 color picker. Fix it

---------

Co-authored-by: Andreas Reich <andreas@rerun.io>
2025-03-21 10:45:25 +01:00
Emil Ernerfeldt c6bda9a38c
Make the ends of vline/hline sharper (#5676)
TL;DR: line caps are annoying in two ways:

A) we only add them for lines wider than a pixel
B) they always make the line longer (if added)
2025-02-04 15:31:51 +01:00
lucasmerlin b8051cc301
Add `SnapshotResults` struct to egui_kittest (#5672)
I got annoyed by all the slightly different variations of "collect
snapshot results and unwrap them at the end of test" I've written, so I
added a struct to make this nice and simple.

One controversial thing: It panics when dropped. I wanted to ensure
people cannot forget to unwrap the results at the end, and this was the
best thing I could come up with. I don't think this is possible via
clippy lint or something like that.

* [x] I have followed the instructions in the PR template
2025-02-04 14:01:32 +01:00
Emil Ernerfeldt 3c07e01d08
Improve tessellation quality (#5669)
## Defining what `Rounding` is
This PR defines what `Rounding` means: it is the corner radius of
underlying `RectShape` rectangle. If you use `StrokeKind::Inside`, this
means the rounding is of the outer part of the stroke. Conversely, if
you use `StrokeKind::Outside`, the stroke is outside the rounded
rectangle, so the stroke has an inner radius or `rounding`, and an outer
radius that is larger by `stroke.width`.

This definitions is the same as Figma uses.

## Improving general shape rendering
The rendering of filled shapes (rectangles, circles, paths, bezier) has
been rewritten. Instead of first painting the fill with the stroke on
top, we now paint them as one single mesh with shared vertices at the
border. This has several benefits:

* Less work (faster and with fewer vertices produced)
* No overdraw (nicer rendering of translucent shapes)
* Correct blending of stroke and fill

The logic for rendering thin strokes has also been improved, so that the
width of a stroke of `StrokeKind::Outside` never affects the filled area
(this used to be wrong for thin strokes).

## Improving of rectangle rendering
Rectangles also has specific improvements in how thin rectangles are
painted.
The handling of "Blur width" is also a lot better, and now works for
rectangles with strokes.
There also used to be bugs with specific combinations of corner radius
and stroke width, that are now fixed.

##  But why?
With the new `egui::Scene` we end up with a lot of zoomed out shapes,
with sub-pixel strokes. These need to look good! One thing led to
another, and then I became obsessive 😅

## Tessellation Test
In order to investigate the rendering, I created a Tessellation Test in
the `egui_demo_lib`.

[Try it
here](https://egui-pr-preview.github.io/pr/5669-emilkimprove-tessellator)

![Screenshot 2025-02-04 at 08 45
50](https://github.com/user-attachments/assets/20b47a30-de6a-4ff5-885b-2e2fd6d88321)


![image](https://github.com/user-attachments/assets/e17c50eb-5ae7-48d4-bb0d-4f2165075897)
2025-02-04 11:30:12 +01:00
Emil Ernerfeldt 525d435a84
Require a `StrokeKind` when painting rectangles with strokes (#5648)
This is a breaking change, requiring users to think about wether the
stroke is inside/centered/outside the rect.

When in doubt, add `egui::StrokeKind::Inside` to the function call.
2025-01-29 15:52:49 +01:00
lucasmerlin 52060c0c41
Change `Harness::run` to run until no more repaints are requested (#5580)
Previously, `Harness::run` just called `Harness::step` 3 times. If that
wasn't enough, tests would often call run multiple times so all
animations would finish properly.

Also, I introduced `HarnessBuilder::with_step_dt` to customize with how
big of a dt each frame is called. I set the default to 1.0 / 6.0 (~6fps)
so we don't waste cpu in tests waiting on animations.

`HarnessBuilder::max_steps` allows us to control how many steps
`Harness::run` should run before panicing.
The default is 6, so we run for up to 1.0 logical seconds (six frames at
6 fps), which should be enough to finish most animations.

Turns out a lot of snapshots where rendered before fully shown and had a
light opacity, those are now fixed.

* [x] I have followed the instructions in the PR template
2025-01-07 08:33:44 +01:00
Emil Ernerfeldt 6607cd95f9
⚠️ `Frame` now includes stroke width as part of padding (#5575)
* Part of https://github.com/emilk/egui/issues/4019

`Frame` now includes the width of the stroke as part of its size. From
the new docs:

### `Frame` docs
The total (outer) size of a frame is `content_size + inner_margin +
2*stroke.width + outer_margin`.

Everything within the stroke is filled with the fill color (if any).

```text
+-----------------^-------------------------------------- -+
|                 | outer_margin                           |
|    +------------v----^------------------------------+    |
|    |                 | stroke width                 |    |
|    |    +------------v---^---------------------+    |    |
|    |    |                | inner_margin        |    |    |
|    |    |    +-----------v----------------+    |    |    |
|    |    |    |             ^              |    |    |    |
|    |    |    |             |              |    |    |    |
|    |    |    |<------ content_size ------>|    |    |    |
|    |    |    |             |              |    |    |    |
|    |    |    |             v              |    |    |    |
|    |    |    +------- content_rect -------+    |    |    |
|    |    |                                      |    |    |
|    |    +-------------fill_rect ---------------+    |    |
|    |                                                |    |
|    +----------------- widget_rect ------------------+    |
|                                                          |
+---------------------- outer_rect ------------------------+
```

The four rectangles, from inside to outside, are:
* `content_rect`: the rectangle that is made available to the inner
[`Ui`] or widget.
* `fill_rect`: the rectangle that is filled with the fill color (inside
the stroke, if any).
* `widget_rect`: is the interactive part of the widget (what sense
clicks etc).
* `outer_rect`: what is allocated in the outer [`Ui`], and is what is
returned by [`Response::rect`].

### Notes
This required rewriting a lot of the layout code for `egui::Window`,
which was a massive pain. But now the window margin and stroke width is
properly accounted for everywhere.
2025-01-04 10:29:22 +01:00
lucasmerlin 46b58e5bcc
Add `Harness::new_eframe` and `TestRenderer` trait (#5539)
Co-authored-by: Andreas Reich <r_andreas2@web.de>
2025-01-02 17:48:39 +01:00