emilk / emilk/egui

Allow specifying a custom `Frame` on each widget and container

Open
#7,445 1 comment 0 reactions 0 assignees View on GitHub
egui style
Dominant language
Rust
Stars
30.6k
Forks
2.1k
Avg merge
1d 9h
Merged PRs (30d)
72

Description

## Related
* Part of https://github.com/emilk/egui/issues/3284
* Unblocks https://github.com/emilk/egui/issues/5605
* https://github.com/emilk/egui/issues/4019

## Description
It's very useful to be able to set an inner and outer margin on any one widget or container. For instance: add some inner margin to a `ScrollArea`, or an outer margin to a `Button`.

In the limit we would like to do so via some style engine plugin (https://github.com/emilk/egui/issues/3284), but being able to just set a `Frame` on a `ScrollArea` etc explicitly or in a hard-coded `Style` would already be a very useful feature.

## Making `Frame` and `UiBuilder` compose
Adding a `UiBuilder::frame(…)` would be very useful.

## Example code (copied from #4019)
Add a `min_size` to `Frame`

```rs
/// A frame around some content, including margin and border colors.
///
/// The total (outer) size of a frame is
/// `content_size + inner_margin + border.stroke.width + outer_margin`.
///
/// Everything within the border stroke is filled with the border fill color (if any).
///
/// ```
/// +---------------^-------------------------------+
/// | | outer_margin |
/// | +-----------v----^-----------------------+ |
/// | | | border stroke width | |
/// | | +-------------v---^----------------+ | |
/// | | | | inner_margin | | |
/// | | | +--------------v-------------+ | | |
/// | | | | | | | |
/// | | | | | | | |
/// | | | | content rect | | | |
/// | | | +----------------------------+ | | |
/// | | | | | |
/// | | +----------------------------------+ | |
/// | | widget rect | |
/// | +----------------------------------------+ |
/// | outer rect |
/// +-----------------------------------------------+
/// ```
///
/// `widget rect` is the interactive part of the widget (what sense clicks etc),
/// and is what is returned by [`Response::rect`].
struct Frame {
/// Inner spacing. Called `padding` in CSS.
pub inner_margin: Margin,

/// Stroke, fill color etc.
///
/// The width of the border is counted as part of the size of the frame.
pub border: Border,

/// Optional drop-shadow.
/// Does not affect margins or sizes.
pub shadow: Shadow,

/// Outer spacing. Called `margin` in CSS.
///
/// This does NOT do "Margin Collapse" like in CSS,
/// i.e. when placing two frames next to each other,
/// the distance between their borders is the SUM
/// of their other margin.
/// In CSS the distance would be the MAX of their outer margins.
///
/// Supporting margin collapse is difficult, and would
/// requires complicating the already complicated egui layout code.
///
/// Consider using [`egui::Spacing::item_spacing`] instead
/// for adding space between widgets.
pub outer_margin: Margin,

/// The inner rectangle must be at least this size.
pub min_size: Vec2,
}

/// Stroke, fill, rounding, etc.
///
/// Controls the look of widgets and [`RectShape`].
///
/// Similar to a CSS border.
struct Border {
/// Fills the content and inner padding of a [`Frame`].
///
/// In CSS this is called `background`.
pub fill: Color32,

pub stroke: Stroke,

pub rounding: Rounding,

// TODO: add texturing here eventually
}

struct RectShape {
/// The rectangle on which edge the border stroke is painted.
pub rect: Rect,

pub border: Border,

// TODO: consider moving these into `Border`.
// Care must be taken so that `Border` and `Frame` doesn't become too huge in common cases,
// i.e. when there is no texture, and the rounding is uniform.
pub fill_texture_id: TextureId,
pub uv: Rect,
}
```

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the existing Frame and UiBuilder APIs, then read the related issues #3284, #5605, and #4019 for the intended design. Trace how containers such as ScrollArea and widgets currently handle layout margins. Done should include a coherent way to specify a custom Frame per widget or container, including UiBuilder composition and the requested sizing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.