Skip to content

Commit

Permalink
Add Ui::columns_const() (emilk#4764)
Browse files Browse the repository at this point in the history
# Changes

- Adds a new function `egui::Ui::columns_const()`, which is the same as
`egui::Ui::columns()` except that it uses a `const` parameter for the
column count.
- Backed by an array `[Ui; NUM_COL] instead of a `Vec<Ui>`, so fewer
allocations
- Inner closure takes in an array reference, instead of a slice
reference. This makes it possible to use pattern destructuring on the
columns, as shown in the example, and makes it more ergonomic to use

# Example

```rust
// ORIGINAL
ui.columns(2, |cols| {
    cols[0].label("one");
    cols[1].label("two");
});


// NEW
ui.columns_const(|[a,b]| {
    a.label("one");
    b.label("two");
});

```

# Checks

- [X] `cargo fmt`
- [X] `cargo clippy`
- [X] `./scripts/check.sh`
- [X] Docs
- [ ] Review
  • Loading branch information
v0x0g authored and lucasmerlin committed Jul 30, 2024
1 parent 41ae7af commit 5265f97
Showing 1 changed file with 52 additions and 0 deletions.
52 changes: 52 additions & 0 deletions crates/egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2389,6 +2389,58 @@ impl Ui {
result
}

/// Temporarily split a [`Ui`] into several columns.
///
/// The same as [`Self::columns()`], but uses a constant for the column count.
/// This allows for compile-time bounds checking, and makes the compiler happy.
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// ui.columns_const(|[col_1, col_2]| {
/// col_1.label("First column");
/// col_2.label("Second column");
/// });
/// # });
/// ```
#[inline]
pub fn columns_const<const NUM_COL: usize, R>(
&mut self,
add_contents: impl FnOnce(&mut [Self; NUM_COL]) -> R,
) -> R {
// TODO(emilk): ensure there is space
let spacing = self.spacing().item_spacing.x;
let total_spacing = spacing * (NUM_COL as f32 - 1.0);
let column_width = (self.available_width() - total_spacing) / (NUM_COL as f32);
let top_left = self.cursor().min;

let mut columns = std::array::from_fn(|col_idx| {
let pos = top_left + vec2((col_idx as f32) * (column_width + spacing), 0.0);
let child_rect = Rect::from_min_max(
pos,
pos2(pos.x + column_width, self.max_rect().right_bottom().y),
);
let mut column_ui =
self.child_ui(child_rect, Layout::top_down_justified(Align::LEFT), None);
column_ui.set_width(column_width);
column_ui
});
let result = add_contents(&mut columns);

let mut max_column_width = column_width;
let mut max_height = 0.0;
for column in &columns {
max_column_width = max_column_width.max(column.min_rect().width());
max_height = column.min_size().y.max(max_height);
}

// Make sure we fit everything next frame:
let total_required_width = total_spacing + max_column_width * (NUM_COL as f32);

let size = vec2(self.available_width().max(total_required_width), max_height);
self.advance_cursor_after_rect(Rect::from_min_size(top_left, size));
result
}

/// Create something that can be drag-and-dropped.
///
/// The `id` needs to be globally unique.
Expand Down

0 comments on commit 5265f97

Please sign in to comment.