mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-11 13:38:35 +00:00
added documentation and examples
This commit is contained in:
parent
56dae31b91
commit
7aba745c3d
134
imgui-examples/examples/tables_api.rs
Normal file
134
imgui-examples/examples/tables_api.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use imgui::*;
|
||||
|
||||
mod support;
|
||||
|
||||
fn main() {
|
||||
let system = support::init(file!());
|
||||
|
||||
let mut t2_flags = TableFlags::REORDERABLE
|
||||
| TableFlags::HIDEABLE
|
||||
| TableFlags::RESIZABLE
|
||||
| TableFlags::NO_BORDERS_IN_BODY;
|
||||
|
||||
system.main_loop(move |_, ui| {
|
||||
Window::new(im_str!("Input text callbacks"))
|
||||
.size([800.0, 400.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
if let Some(_t) = ui.begin_table(im_str!("Basic-Table"), 3) {
|
||||
// we must also call `next_row` here, because we declined
|
||||
// to set up header rows. If we set up header rows ourselves,
|
||||
// we will call `table_header_rows` instead, and if we use
|
||||
// `begin_table_header`, then the initial call will be handled for us.
|
||||
|
||||
ui.table_next_row();
|
||||
|
||||
// note you MUST call `next_column` at least to START
|
||||
// Let's walk through a table like it's an iterator...
|
||||
ui.table_set_column_index(0);
|
||||
ui.text("x: 0, y: 0");
|
||||
|
||||
ui.table_next_column();
|
||||
ui.text("x: 1, y: 0");
|
||||
|
||||
ui.table_next_column();
|
||||
ui.text("x: 2, y: 0");
|
||||
|
||||
// // calling next column again will wrap us around to 0-1,
|
||||
// // since we've exhausted our 3 columns.
|
||||
ui.table_next_column();
|
||||
ui.text("x: 0, y: 1");
|
||||
|
||||
// // Let's do this manually now -- we can set each column ourselves...
|
||||
ui.table_set_column_index(1);
|
||||
ui.text("x: 1, y: 1");
|
||||
|
||||
ui.table_set_column_index(2);
|
||||
ui.text("x: 2, y: 1");
|
||||
|
||||
// you CAN go back...
|
||||
ui.table_set_column_index(1);
|
||||
// however, you should call `new_line`, since otherwise
|
||||
// we'd right on top of our `x: 1, y: 1` text.
|
||||
ui.new_line();
|
||||
ui.text("our of order txt");
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
ui.text("Let's add some headers");
|
||||
if let Some(_t) = ui.begin_table_header(
|
||||
im_str!("table-headers"),
|
||||
[
|
||||
TableColumnSetup::new(im_str!("Name")),
|
||||
TableColumnSetup::new(im_str!("Age")),
|
||||
TableColumnSetup::new(im_str!("Favorite fruit")),
|
||||
],
|
||||
) {
|
||||
// note that we DON'T have to call "table_next_row" here -- that's taken care
|
||||
// of for us by `begin_table_header`, since it actually calls `table_headers_row`
|
||||
|
||||
// but we DO need to call column!
|
||||
// but that's fine, we'll use a loop
|
||||
for i in 0..3 {
|
||||
let names = ["Joonas", "Thom", "Jack"];
|
||||
let fruit = ["Dutch", "Rice", "Mangoes"];
|
||||
|
||||
ui.table_next_column();
|
||||
ui.text(names[i]);
|
||||
|
||||
ui.table_next_column();
|
||||
ui.text((i * 9).to_string());
|
||||
|
||||
ui.table_next_column();
|
||||
ui.text(fruit[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
ui.text("Let's do some context menus");
|
||||
ui.text(
|
||||
"context menus are created, by default, from the flags passed\
|
||||
while making the table, or each row.\n\
|
||||
Notice how toggling these checkboxes changes the context menu.",
|
||||
);
|
||||
|
||||
ui.checkbox_flags(
|
||||
im_str!("Reorderable"),
|
||||
&mut t2_flags,
|
||||
TableFlags::REORDERABLE,
|
||||
);
|
||||
ui.same_line();
|
||||
ui.checkbox_flags(im_str!("Hideable"), &mut t2_flags, TableFlags::HIDEABLE);
|
||||
ui.same_line();
|
||||
ui.checkbox_flags(im_str!("Resizable"), &mut t2_flags, TableFlags::RESIZABLE);
|
||||
|
||||
if let Some(_t) = ui.begin_table_header_with_flags(
|
||||
im_str!("table-headers2"),
|
||||
[
|
||||
TableColumnSetup::new(im_str!("Name")),
|
||||
TableColumnSetup::new(im_str!("Age")),
|
||||
TableColumnSetup::new(im_str!("Favorite fruit")),
|
||||
],
|
||||
t2_flags,
|
||||
) {
|
||||
// note that we DON'T have to call "table_next_row" here -- that's taken care
|
||||
// of for us by `begin_table_header`, since it actually calls `table_headers_row`
|
||||
|
||||
// but we DO need to call column!
|
||||
// but that's fine, we'll use a loop
|
||||
for i in 0..3 {
|
||||
let names = ["Joonas", "Thom", "Jack"];
|
||||
let fruit = ["Dutch", "Rice", "Mangoes"];
|
||||
|
||||
ui.table_next_column();
|
||||
ui.text(names[i]);
|
||||
|
||||
ui.table_next_column();
|
||||
ui.text((i * 9).to_string());
|
||||
|
||||
ui.table_next_column();
|
||||
ui.text(fruit[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -1,110 +1,265 @@
|
||||
use bitflags::bitflags;
|
||||
use std::convert::From;
|
||||
|
||||
use crate::sys;
|
||||
use crate::{Id, ImColor32, ImStr, Ui};
|
||||
|
||||
bitflags! {
|
||||
/// Item hover check option flags
|
||||
/// Flags passed to `begin_table` methods.
|
||||
///
|
||||
/// Important! Sizing policies have complex and subtle side effects, more so than you would expect.
|
||||
/// Read comments/demos carefully + experiment with live demos to get acquainted with them.
|
||||
/// - The DEFAULT sizing policies are:
|
||||
/// - Default to [SizingFixedFit] if [ScrollX] is on, or if host window has (WindowFlags::AlwaysAutoResize)[crate::WindowFlags::AlwaysAutoResize].
|
||||
/// - Default to [SizingStretchSame] if [ScrollX] is off.
|
||||
/// - When [ScrollX] is off:
|
||||
/// - Table defaults to [SizingStretchSame] -> all Columns defaults to [TableColumnFlags::WidthStretch] with same weight.
|
||||
/// - Columns sizing policy allowed: [Stretch] (default), [Fixed]/Auto.
|
||||
/// - [Fixed] Columns will generally obtain their requested width (unless the table cannot fit them all).
|
||||
/// - [Stretch] Columns will share the remaining width.
|
||||
/// - Mixed [Fixed]/[Stretch] columns is possible but has various side-effects on resizing behaviors.
|
||||
/// The typical use of mixing sizing policies is: any number of LEADING [Fixed] columns, followed by one or two TRAILING [Stretch] columns.
|
||||
/// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing).
|
||||
/// - When [ScrollX] is on:
|
||||
/// - Table defaults to [SizingFixedFit] -> all Columns defaults to [TableColumnFlags::WidthFixed]
|
||||
/// - Columns sizing policy allowed: [Fixed]/Auto mostly.
|
||||
/// - [Fixed] Columns can be enlarged as needed. Table will show an horizontal scrollbar if needed.
|
||||
/// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop.
|
||||
/// - Using [Stretch] columns OFTEN DOES NOT MAKE SENSE if [ScrollX] is on, UNLESS you have specified a value for `inner_width` in BeginTable().
|
||||
/// If you specify a value for `inner_width` then effectively the scrolling space is known and [Stretch] or mixed [Fixed]/[Stretch] columns become meaningful again.
|
||||
/// - Read on documentation at the top of imgui_tables.cpp for more details.
|
||||
#[repr(transparent)]
|
||||
pub struct TableFlags: u32 {
|
||||
const NONE = sys::ImGuiTableFlags_None;
|
||||
// Features
|
||||
|
||||
/// Enable resizing columns.
|
||||
const RESIZABLE = sys::ImGuiTableFlags_Resizable;
|
||||
/// Enable reordering columns in header row, though you must set up a header row
|
||||
/// with `begin_table_header` or `table_setup_column`.
|
||||
const REORDERABLE =sys::ImGuiTableFlags_Reorderable;
|
||||
/// Enable hiding/disabling columns in context menu.
|
||||
const HIDEABLE = sys::ImGuiTableFlags_Hideable;
|
||||
/// Enable sorting. See `table_get_sort_specs` to object sort specs. Also see [SortMulti]
|
||||
/// and [SortTristate].
|
||||
const SORTABLE = sys::ImGuiTableFlags_Sortable;
|
||||
/// Disable persisting columns order, width, and sort settings in the .ini file.
|
||||
const NO_SAVED_SETTINGS = sys::ImGuiTableFlags_NoSavedSettings;
|
||||
/// Right-click on columns body/contents will display table context menu.
|
||||
/// By default you can only right click in a headers row.
|
||||
const CONTEXT_MENU_IN_BODY = sys::ImGuiTableFlags_ContextMenuInBody;
|
||||
|
||||
// Decorations
|
||||
|
||||
/// Set each RowBg color with [table_row_bg] or [table_row_bg_alt] (equivalent of calling
|
||||
/// `table_set_bg_color` with `ROW_BG0` on each row manually)
|
||||
const ROW_BG = sys::ImGuiTableFlags_RowBg;
|
||||
/// Draw horizontal borders between rows.
|
||||
const BORDERS_INNER_H = sys::ImGuiTableFlags_BordersInnerH;
|
||||
/// Draw horizontal borders at the top and bottom.
|
||||
const BORDERS_OUTER_H = sys::ImGuiTableFlags_BordersOuterH;
|
||||
/// Draw vertical borders between columns.
|
||||
const BORDERS_INNER_V = sys::ImGuiTableFlags_BordersInnerV;
|
||||
/// Draw vertical borders on the left and right sides.
|
||||
const BORDERS_OUTER_V = sys::ImGuiTableFlags_BordersOuterV;
|
||||
/// Draw all horizontal borders (this is just [BORDERS_INNER_H] | [BORDERS_OUTER_H]).
|
||||
const BORDERS_H = sys::ImGuiTableFlags_BordersH;
|
||||
/// Draw all vertical borders (this is just [BORDERS_INNER_V] | [BORDERS_OUTER_V]).
|
||||
const BORDERS_V = sys::ImGuiTableFlags_BordersV;
|
||||
/// Draw all inner borders (this is just [BORDERS_INNER_H] | [BORDERS_INNER_V]).
|
||||
const BORDERS_INNER = sys::ImGuiTableFlags_BordersInner;
|
||||
/// Draw all outer borders (this is just [BORDERS_OUTER_H] | [BORDERS_OUTER_V]).
|
||||
const BORDERS_OUTER = sys::ImGuiTableFlags_BordersOuter;
|
||||
const BORDERS= sys::ImGuiTableFlags_Borders;
|
||||
/// Draw all borders (this is just [BORDERS_INNER] | [BORDERS_OUTER]).
|
||||
const BORDERS = sys::ImGuiTableFlags_Borders;
|
||||
/// **ALPHA** Disable vertical borders in columns Body (borders will always appears in Headers).
|
||||
/// May move to Style
|
||||
const NO_BORDERS_IN_BODY = sys::ImGuiTableFlags_NoBordersInBody;
|
||||
/// **ALPHA** Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers).
|
||||
/// May move to style
|
||||
const NO_BORDERS_IN_BODY_UNTIL_RESIZE = sys::ImGuiTableFlags_NoBordersInBodyUntilResize;
|
||||
|
||||
// Sizing Policy (read above for defaults)
|
||||
|
||||
/// Columns default to [WidthFixed] or [WidthAuto] (if resizable or not resizable),
|
||||
/// matching contents width.
|
||||
const SIZING_FIXED_FIT = sys::ImGuiTableFlags_SizingFixedFit;
|
||||
/// Columns default to [WidthFixed] or [WidthAuto] (if resizable or not resizable),
|
||||
/// matching the maximum contents width of all columns.
|
||||
/// Implicitly enable [NoKeepColumnsVisible].
|
||||
const SIZING_FIXED_SAME = sys::ImGuiTableFlags_SizingFixedSame;
|
||||
/// Columns default to [WidthStretch] with default weights proportional to each columns
|
||||
/// contents widths.
|
||||
const SIZING_STRETCH_PROP = sys::ImGuiTableFlags_SizingStretchProp;
|
||||
/// Columns default to [WidthStretch] with default weights all equal, unless overridden by
|
||||
/// a column's `TableHeader`.
|
||||
const SIZING_STRETCH_SAME = sys::ImGuiTableFlags_SizingStretchSame;
|
||||
|
||||
// Sizing Extra Options
|
||||
|
||||
/// Make outer width auto-fit to columns, overriding outer_size.x value. Only available when
|
||||
/// [ScrollX]/[ScrollY] are disabled and [Stretch] columns are not used.
|
||||
const NO_HOST_EXTEND_X = sys::ImGuiTableFlags_NoHostExtendX;
|
||||
/// Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).
|
||||
/// Only available when [ScrollX]/[ScrollY] are disabled.
|
||||
/// Data below the limit will be clipped and not visible.
|
||||
const NO_HOST_EXTEND_Y = sys::ImGuiTableFlags_NoHostExtendY;
|
||||
/// Disable keeping column always minimally visible when [ScrollX] is off and table
|
||||
/// gets too small. Not recommended if columns are resizable.
|
||||
const NO_KEEP_COLUMNS_VISIBLE = sys::ImGuiTableFlags_NoKeepColumnsVisible;
|
||||
/// Disable distributing remainder width to stretched columns (width allocation on a 100-wide
|
||||
/// table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33).
|
||||
/// With larger number of columns, resizing will appear to be less smooth.
|
||||
const PRECISE_WIDTHS = sys::ImGuiTableFlags_PreciseWidths;
|
||||
|
||||
// Clipping
|
||||
|
||||
/// Disable clipping rectangle for every individual columns (reduce draw command count, items will
|
||||
/// be able to overflow into other columns). Generally incompatible with [table_setup_scroll_freeze].
|
||||
const NO_CLIP = sys::ImGuiTableFlags_NoClip;
|
||||
|
||||
// Padding
|
||||
|
||||
/// Default if [BordersOuterV] is on. Enable outer-most padding. Generally desirable if you have headers.
|
||||
const PAD_OUTER_X = sys::ImGuiTableFlags_PadOuterX;
|
||||
/// Default if [BordersOuterV] is off. Disable outer-most padding.
|
||||
const NO_PAD_OUTER_X = sys::ImGuiTableFlags_NoPadOuterX;
|
||||
/// Disable inner padding between columns (double inner padding if [BordersOuterV] is on, single
|
||||
/// inner padding if BordersOuterV is off).
|
||||
const NO_PAD_INNER_X = sys::ImGuiTableFlags_NoPadInnerX;
|
||||
|
||||
// Scrolling
|
||||
|
||||
/// Enable horizontal scrolling. Require 'outer_size' parameter of [begin_table] to specify the
|
||||
/// container size. Changes default sizing policy. Because this create a child window,
|
||||
/// [ScrollY] is currently generally recommended when using [ScrollX].
|
||||
const SCROLL_X = sys::ImGuiTableFlags_ScrollX;
|
||||
/// Enable vertical scrolling. Require 'outer_size' parameter of [begin_table] to specify the
|
||||
/// container size.
|
||||
const SCROLL_Y = sys::ImGuiTableFlags_ScrollY;
|
||||
|
||||
// Sorting
|
||||
|
||||
/// Hold shift when clicking headers to sort on multiple column. [table_get_sort_specs] may return specs where `[spec_count] > 1`.
|
||||
const SORT_MULTI = sys::ImGuiTableFlags_SortMulti;
|
||||
/// Allow no sorting, disable default sorting. `table_get_sort_specs` may return specs where `[specs_count] == 0`.
|
||||
const SORT_TRISTATE = sys::ImGuiTableFlags_SortTristate;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags for [table_next_row_with_flags].
|
||||
#[repr(transparent)]
|
||||
pub struct TableRowFlags: u32 {
|
||||
const NONE = sys::ImGuiTableRowFlags_None;
|
||||
/// Identify header row (set default background color + width of its contents
|
||||
/// accounted different for auto column width)
|
||||
const HEADERS = sys::ImGuiTableRowFlags_Headers;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags for [TableColumnSetup] and [table_setup_column_with].
|
||||
#[repr(transparent)]
|
||||
#[derive(Default)]
|
||||
pub struct TableColumnFlags: u32 {
|
||||
// Input configuration flags
|
||||
const NONE = sys::ImGuiTableColumnFlags_None;
|
||||
const DEFAULT_HIDE =sys::ImGuiTableColumnFlags_DefaultHide;
|
||||
const DEFAULT_SORT =sys::ImGuiTableColumnFlags_DefaultSort;
|
||||
const WIDTH_STRETCH=sys::ImGuiTableColumnFlags_WidthStretch;
|
||||
|
||||
/// Default as a hidden/disabled column.
|
||||
const DEFAULT_HIDE = sys::ImGuiTableColumnFlags_DefaultHide;
|
||||
/// Default as a sorting column.
|
||||
const DEFAULT_SORT = sys::ImGuiTableColumnFlags_DefaultSort;
|
||||
/// Column will stretch. Preferable with horizontal scrolling disabled (default
|
||||
/// if table sizing policy is [ImGuiTableFlags::SizingStretchSame] or
|
||||
/// [ImGuiTableFlags::SizingStretchProp]).
|
||||
const WIDTH_STRETCH = sys::ImGuiTableColumnFlags_WidthStretch;
|
||||
/// Column will not stretch. Preferable with horizontal scrolling enabled (default
|
||||
/// if table sizing policy is [ImGuiTableFlags::SizingFixedFit] and table is resizable).
|
||||
const WIDTH_FIXED = sys::ImGuiTableColumnFlags_WidthFixed;
|
||||
/// Disable manual resizing.
|
||||
const NO_RESIZE = sys::ImGuiTableColumnFlags_NoResize;
|
||||
/// Disable manual reordering this column, this will also prevent other columns from
|
||||
/// crossing over this column.
|
||||
const NO_REORDER = sys::ImGuiTableColumnFlags_NoReorder;
|
||||
/// Disable ability to hide/disable this column.
|
||||
const NO_HIDE = sys::ImGuiTableColumnFlags_NoHide;
|
||||
/// Disable clipping for this column (all [NO_CLIP] columns will render in a same
|
||||
/// draw command).
|
||||
const NO_CLIP = sys::ImGuiTableColumnFlags_NoClip;
|
||||
/// Disable ability to sort on this field (even if [ImGuiTableFlags::Sortable] is
|
||||
/// set on the table).
|
||||
const NO_SORT = sys::ImGuiTableColumnFlags_NoSort;
|
||||
/// Disable ability to sort in the ascending direction.
|
||||
const NO_SORT_ASCENDING = sys::ImGuiTableColumnFlags_NoSortAscending;
|
||||
/// Disable ability to sort in the descending direction.
|
||||
const NO_SORT_DESCENDING = sys::ImGuiTableColumnFlags_NoSortDescending;
|
||||
/// Disable header text width contribution to automatic column width.
|
||||
const NO_HEADER_WIDTH = sys::ImGuiTableColumnFlags_NoHeaderWidth;
|
||||
/// Make the initial sort direction Ascending when first sorting on this column (default).
|
||||
const PREFER_SORT_ASCENDING = sys::ImGuiTableColumnFlags_PreferSortAscending;
|
||||
/// Make the initial sort direction Descending when first sorting on this column.
|
||||
const PREFER_SORT_DESCENDING = sys::ImGuiTableColumnFlags_PreferSortDescending;
|
||||
/// Use current Indent value when entering cell (default for column 0).
|
||||
const INDENT_ENABLE = sys::ImGuiTableColumnFlags_IndentEnable;
|
||||
/// Ignore current Indent value when entering cell (default for columns > 0).
|
||||
/// Indentation changes _within_ the cell will still be honored.
|
||||
const INDENT_DISABLE = sys::ImGuiTableColumnFlags_IndentDisable;
|
||||
// Output status flags, read-only via TableGetColumnFlags()
|
||||
|
||||
// Output status flags, read-only via [table_get_column_flags]
|
||||
|
||||
/// Status: is enabled == not hidden by user/api (referred to as "Hide" in
|
||||
/// [DefaultHide] and [NoHide]) flags.
|
||||
const IS_ENABLED = sys::ImGuiTableColumnFlags_IsEnabled;
|
||||
/// Status: is visible == is enabled AND not clipped by scrolling.
|
||||
const IS_VISIBLE = sys::ImGuiTableColumnFlags_IsVisible;
|
||||
/// Status: is currently part of the sort specs
|
||||
const IS_SORTED = sys::ImGuiTableColumnFlags_IsSorted;
|
||||
/// Status: is hovered by mouse
|
||||
const IS_HOVERED = sys::ImGuiTableColumnFlags_IsHovered;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Enum for [table_set_bg_color].
|
||||
/// Background colors are rendering in 3 layers:
|
||||
/// - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set.
|
||||
/// - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set.
|
||||
/// - Layer 2: draw with CellBg color if set.
|
||||
/// The purpose of the two row/columns layers is to let you decide if a background color
|
||||
/// changes should override or blend with the existing color.
|
||||
/// When using [TableFlags::RowBg] on the table, each row has the RowBg0 color automatically
|
||||
/// set for odd/even rows.
|
||||
/// If you set the color of RowBg0 target, your color will override the existing RowBg0 color.
|
||||
/// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color.
|
||||
#[repr(transparent)]
|
||||
pub struct TableBgTarget: u32 {
|
||||
const NONE = sys::ImGuiTableBgTarget_None;
|
||||
/// Set row background color 0 (generally used for background, automatically set when
|
||||
/// [TableFlags::RowBg] is used)
|
||||
const ROW_BG0 = sys::ImGuiTableBgTarget_RowBg0;
|
||||
/// Set row background color 1 (generally used for selection marking)
|
||||
const ROW_BG1 = sys::ImGuiTableBgTarget_RowBg1;
|
||||
/// Set cell background color (top-most color)
|
||||
const CELL_BG = sys::ImGuiTableBgTarget_CellBg;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Begins a table with no flags and with standard sizing contraints.
|
||||
///
|
||||
/// This does no work on styling the headers (the top row) -- see either
|
||||
/// [begin_table_with_headers](Self::begin_table_with_headers) or the more complex
|
||||
/// [table_setup_column](Self::table_setup_column).
|
||||
///
|
||||
/// **NB:** after you begin a table (and after setting up )
|
||||
#[inline]
|
||||
#[must_use = "if return is dropped immediately, table is ended immediately."]
|
||||
pub fn begin_table(&self, str_id: &ImStr, column_count: i32) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_with_flags(str_id, column_count, TableFlags::NONE)
|
||||
self.begin_table_with_flags(str_id, column_count, TableFlags::empty())
|
||||
}
|
||||
|
||||
/// Begins a table with flags and standard sizing contraints.
|
||||
///
|
||||
/// This does no work on styling the headers (the top row) -- see either
|
||||
/// [begin_table_with_headers](Self::begin_table_with_headers) or the more complex
|
||||
/// [table_setup_column](Self::table_setup_column).
|
||||
#[inline]
|
||||
pub fn begin_table_with_flags(
|
||||
&self,
|
||||
str_id: &ImStr,
|
||||
@ -113,6 +268,14 @@ impl<'ui> Ui<'ui> {
|
||||
) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_with_sizing(str_id, column_count, flags, [0.0, 0.0], 0.0)
|
||||
}
|
||||
|
||||
/// Begins a table with all flags and sizing contraints. This is the base method,
|
||||
/// and gives users the most flexibility.
|
||||
///
|
||||
/// This does no work on styling the headers (the top row) -- see either
|
||||
/// [begin_table_header](Self::begin_table_header) or the more complex
|
||||
/// [table_setup_column](Self::table_setup_column).
|
||||
#[inline]
|
||||
pub fn begin_table_with_sizing(
|
||||
&self,
|
||||
str_id: &ImStr,
|
||||
@ -134,25 +297,39 @@ impl<'ui> Ui<'ui> {
|
||||
should_render.then(|| TableToken::new(self))
|
||||
}
|
||||
|
||||
/// Begins a table with no flags and with standard sizing contraints.
|
||||
///
|
||||
/// Takes an array of table header information, the length of which determines
|
||||
/// how many columns will be created.
|
||||
pub fn begin_table_header<'a, const N: usize>(
|
||||
&self,
|
||||
str_id: &ImStr,
|
||||
column_data: [TableHeader<'a>; N],
|
||||
column_data: [TableColumnSetup<'a>; N],
|
||||
) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_header_with_flags(str_id, column_data, TableFlags::NONE)
|
||||
self.begin_table_header_with_flags(str_id, column_data, TableFlags::empty())
|
||||
}
|
||||
|
||||
/// Begins a table with flags and standard sizing contraints.
|
||||
///
|
||||
/// Takes an array of table header information, the length of which determines
|
||||
/// how many columns will be created.
|
||||
pub fn begin_table_header_with_flags<'a, const N: usize>(
|
||||
&self,
|
||||
str_id: &ImStr,
|
||||
column_data: [TableHeader<'a>; N],
|
||||
column_data: [TableColumnSetup<'a>; N],
|
||||
flags: TableFlags,
|
||||
) -> Option<TableToken<'ui>> {
|
||||
self.begin_table_header_with_sizing(str_id, column_data, flags, [0.0, 0.0], 0.0)
|
||||
}
|
||||
|
||||
/// Begins a table with all flags and sizing contraints. This is the base method,
|
||||
/// and gives users the most flexibility.
|
||||
/// Takes an array of table header information, the length of which determines
|
||||
/// how many columns will be created.
|
||||
pub fn begin_table_header_with_sizing<'a, const N: usize>(
|
||||
&self,
|
||||
str_id: &ImStr,
|
||||
column_data: [TableHeader<'a>; N],
|
||||
column_data: [TableColumnSetup<'a>; N],
|
||||
flags: TableFlags,
|
||||
outer_size: [f32; 2],
|
||||
inner_width: f32,
|
||||
@ -160,12 +337,7 @@ impl<'ui> Ui<'ui> {
|
||||
self.begin_table_with_sizing(str_id, N as i32, flags, outer_size, inner_width)
|
||||
.map(|data| {
|
||||
for value in column_data {
|
||||
self.table_setup_column_with_id(
|
||||
value.name,
|
||||
value.flags,
|
||||
value.init_width_or_weight,
|
||||
value.user_id,
|
||||
);
|
||||
self.table_setup_column_with(value);
|
||||
}
|
||||
self.table_headers_row();
|
||||
|
||||
@ -173,16 +345,39 @@ impl<'ui> Ui<'ui> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Moves a table to the next row (ie, down) with no flags,
|
||||
/// and with the next row having a standard computed height.
|
||||
///
|
||||
/// If your table was made with [begin_table], this **must** be called
|
||||
/// before rendering any cells (along with [table_next_column]).
|
||||
/// If your table was made with [begin_table_header], this does not need to be called,
|
||||
/// though [table_next_column] still should be.
|
||||
///
|
||||
/// [begin_table]: Self::begin_table
|
||||
/// [begin_table_header]: Self::begin_table_header
|
||||
/// [table_next_column]: Self::table_next_column
|
||||
#[inline]
|
||||
pub fn table_next_row(&self) {
|
||||
self.table_next_row_with_flags(TableRowFlags::NONE);
|
||||
self.table_next_row_with_flags(TableRowFlags::empty());
|
||||
}
|
||||
|
||||
/// Moves a table to the next row (ie, down), with the given flags,
|
||||
/// and with the next row having a standard computed height.
|
||||
///
|
||||
/// Setting a flag here will make the next row a "header" now, which may
|
||||
/// require setup of column data.
|
||||
///
|
||||
/// See [table_next_row] for information on how moving rows work. To set the row
|
||||
/// with a given height, see [table_next_row_with_height].
|
||||
#[inline]
|
||||
pub fn table_next_row_with_flags(&self, flags: TableRowFlags) {
|
||||
self.table_next_row_with_height(flags, 0.0);
|
||||
}
|
||||
|
||||
/// Moves a table to the next row (ie, down), with the given flags,
|
||||
/// and with the given minimum height.
|
||||
///
|
||||
/// See [table_next_row] for information on how moving rows work.
|
||||
#[inline]
|
||||
pub fn table_next_row_with_height(&self, flags: TableRowFlags, min_row_height: f32) {
|
||||
unsafe {
|
||||
@ -190,100 +385,291 @@ impl<'ui> Ui<'ui> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves onto the next column. If at `column_count`, this will move to the next row.
|
||||
/// In this way, you can use this function as an iterator over each cell in the table.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rs
|
||||
/// ### let ui: Ui<'static> = unimplemented!();
|
||||
/// if let Some(_t) = ui.begin_table(im_str!("Basic-Table"), 2) {
|
||||
/// // we have to call next_row because we didn't make headers..
|
||||
/// ui.table_next_row();
|
||||
///
|
||||
/// // you always have to call this to start...
|
||||
/// // take advantage of this in loops!
|
||||
/// ui.table_next_column();
|
||||
/// ui.text("x: 0, y: 0");
|
||||
///
|
||||
/// ui.table_next_column();
|
||||
/// ui.text("x: 1, y: 0");
|
||||
///
|
||||
/// // notice that we go down a row here too.
|
||||
/// ui.table_next_column();
|
||||
/// ui.text("x: 0, y: 1");
|
||||
///
|
||||
/// ui.table_next_column();
|
||||
/// ui.text("x: 1, y: 1");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This functions returns true if the given column is **visible.** It is not
|
||||
/// marked as must use, as you can still render commands into the not-visible column,
|
||||
/// though you can choose to not as an optimization.
|
||||
pub fn table_next_column(&self) -> bool {
|
||||
unsafe { sys::igTableNextColumn() }
|
||||
}
|
||||
|
||||
/// Moves onto the given column.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rs
|
||||
/// ### let ui: Ui<'static> = unimplemented!();
|
||||
/// if let Some(_t) = ui.begin_table(im_str!("Basic-Table"), 2) {
|
||||
/// // we have to call next_row because we didn't make headers..
|
||||
/// ui.table_next_row();
|
||||
///
|
||||
/// for i in 0..2 {
|
||||
/// ui.table_set_column_index(i);
|
||||
/// ui.text(format!("x: {}", i));
|
||||
/// }
|
||||
///
|
||||
/// // oops I just remembered, i need to add something on idx 0!
|
||||
/// ui.table_set_column_index(0);
|
||||
/// // if i uncomment this line, we'll write on top of our previous "x: 0"
|
||||
/// // line:
|
||||
/// // ui.text("hello from the future on top of the past");
|
||||
/// // so we do a .newline();
|
||||
/// ui.new_line();
|
||||
/// ui.text("hello from the future");
|
||||
///
|
||||
/// // imgui will understand this and row spacing will be adjusted automatically.
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This functions returns true if the given column is **visible.** It is not
|
||||
/// marked as must use, as you can still render commands into the not-visible column,
|
||||
/// though you can choose to not as an optimization.
|
||||
///
|
||||
/// # Panics
|
||||
/// If `column_index >= ui.table_columm_count`, this function will panic. In `debug` releases,
|
||||
/// we will panic on the Rust side, for a nicer error message, though in release, we will
|
||||
/// panic in C++, which will result in an ugly stack overflow.
|
||||
pub fn table_set_column_index(&self, column_index: usize) -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let size = self.table_column_count() as usize;
|
||||
if column_index >= size {
|
||||
panic!(
|
||||
"column_index >= self.table_get_column_count().\
|
||||
Requested {}, but only have {} columns.",
|
||||
column_index, size
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { sys::igTableSetColumnIndex(column_index as i32) }
|
||||
}
|
||||
|
||||
/// Specify label per column, with no flags and default sizing. You can avoid calling
|
||||
/// this method entirely by using [begin_table_header].
|
||||
///
|
||||
/// # Example
|
||||
/// ```rs
|
||||
/// let ui: Ui<'static> = unimplemented!();
|
||||
///
|
||||
/// if let Some(_t) = ui.begin_table(im_str!("My Table"), 2) {
|
||||
/// ui.table_setup_column(im_str!("One"));
|
||||
/// ui.table_setup_column(im_str!("Two"));
|
||||
/// ui.table_setup_column(im_str!("Three"));
|
||||
/// ui.table_headers_row();
|
||||
///
|
||||
/// // call next_column/set_column_index and proceed like normal.
|
||||
/// // the above code is the equivalent of just using `begin_table_header`
|
||||
/// // but does allow for some columns to have headers and others to not
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Along with [table_headers_row](Self::table_headers_row), this method is used to create a header
|
||||
/// row and automatically submit a table header for each column.
|
||||
/// Headers are required to perform: reordering, sorting, and opening the context menu (though,
|
||||
/// the context menu can also be made available in columns body using [TableFlags::ContextMenuInBody].
|
||||
pub fn table_setup_column(&self, str_id: &ImStr) {
|
||||
self.table_setup_column_with_flags(str_id, TableColumnFlags::NONE)
|
||||
self.table_setup_column_with(TableColumnSetup::new(str_id))
|
||||
}
|
||||
|
||||
pub fn table_setup_column_with_flags(&self, str_id: &ImStr, flags: TableColumnFlags) {
|
||||
self.table_setup_column_with_id(str_id, flags, 0.0, Id::Int(0))
|
||||
}
|
||||
pub fn table_setup_column_with_id(
|
||||
&self,
|
||||
str_id: &ImStr,
|
||||
flags: TableColumnFlags,
|
||||
init_width_or_weight: f32,
|
||||
user_id: Id,
|
||||
) {
|
||||
/// Specify label per column, with data given in [TableColumnSetup]. You can avoid calling
|
||||
/// this method entirely by using [begin_table_header].
|
||||
///
|
||||
/// See [table_setup_column](Self::table_setup_column) for an example of how to setup columns
|
||||
/// yourself.
|
||||
///
|
||||
/// Along with [table_headers_row](Self::table_headers_row), this method is used to create a header
|
||||
/// row and automatically submit a table header for each column.
|
||||
/// Headers are required to perform: reordering, sorting, and opening the context menu (though,
|
||||
/// the context menu can also be made available in columns body using [TableFlags::ContextMenuInBody].
|
||||
pub fn table_setup_column_with(&self, data: TableColumnSetup<'_>) {
|
||||
unsafe {
|
||||
sys::igTableSetupColumn(
|
||||
str_id.as_ptr(),
|
||||
flags.bits() as i32,
|
||||
init_width_or_weight,
|
||||
user_id.as_imgui_id(),
|
||||
data.name.as_ptr(),
|
||||
data.flags.bits() as i32,
|
||||
data.init_width_or_weight,
|
||||
data.user_id.as_imgui_id(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Locks columns/rows so they stay visible when scrolled. Generally, you will be calling this
|
||||
/// so that the header column is always visible (though go wild if you want). You can avoid
|
||||
/// calling this entirely by passing `true` to [begin_table_header].
|
||||
///
|
||||
/// # Example
|
||||
/// ```rs
|
||||
/// let ui: Ui<'static> = unimplemented!();
|
||||
///
|
||||
/// const COLUMN_COUNT: usize = 3;
|
||||
/// if let Some(_t) = ui.begin_table(im_str!("scroll-freeze-example"), COLUMN_COUNT) {
|
||||
/// // locks the header row. Notice how we need to call it BEFORE `table_headers_row`.
|
||||
/// ui.table_setup_scroll_freeze(1, COLUMN_COUNT);
|
||||
/// ui.table_setup_column(im_str!("One"));
|
||||
/// ui.table_setup_column(im_str!("Two"));
|
||||
/// ui.table_setup_column(im_str!("Three"));
|
||||
/// ui.table_headers_row();
|
||||
/// }
|
||||
/// ```
|
||||
pub fn table_setup_scroll_freeze(&self, locked_columns: i32, locked_rows: i32) {
|
||||
unsafe {
|
||||
sys::igTableSetupScrollFreeze(locked_columns, locked_rows);
|
||||
}
|
||||
}
|
||||
|
||||
/// Along with [table_setup_column](Self::table_setup_column), this method is used
|
||||
/// to create a header row and automatically submit a table header for each column.
|
||||
///
|
||||
/// For an example of using this method, see [table_setup_column](Self::table_setup_column).
|
||||
///
|
||||
/// Headers are required to perform: reordering, sorting, and opening the context menu (though,
|
||||
/// the context menu can also be made available in columns body using [TableFlags::ContextMenuInBody].
|
||||
///
|
||||
/// You may manually submit headers using [table_next_column] + [table_header] calls, but this is
|
||||
/// only useful in some advanced use cases (e.g. adding custom widgets in header row).
|
||||
/// See [table_header](Self::table_header) for more information.
|
||||
///
|
||||
/// [table_next_column]: Self::table_next_column
|
||||
/// [table_header]: Self::table_header
|
||||
pub fn table_headers_row(&self) {
|
||||
unsafe {
|
||||
sys::igTableHeadersRow();
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this function to manually declare a column cell to be a header. You generally should
|
||||
/// avoid using this outside of specific cases, such as custom widgets. Instead,
|
||||
/// use [table_headers_row](Self::table_headers_row) and [table_setup_column](Self::table_setup_column).
|
||||
pub fn table_header(&self, label: &ImStr) {
|
||||
unsafe {
|
||||
sys::igTableHeader(label.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
//pub fn table_get_sort_specs(&self) -> &TableSortSpecs {
|
||||
// pub fn table_get_sort_specs(&self) -> &TableSortSpecs {
|
||||
// unsafe { sys::igTableGetSortSpecs() }
|
||||
//}
|
||||
// }
|
||||
|
||||
pub fn table_get_column_count(&self) -> i32 {
|
||||
unsafe { sys::igTableGetColumnCount() }
|
||||
}
|
||||
pub fn table_get_column_index(&self) -> i32 {
|
||||
unsafe { sys::igTableGetColumnIndex() }
|
||||
}
|
||||
pub fn table_get_row_index(&self) -> i32 {
|
||||
unsafe { sys::igTableGetRowIndex() }
|
||||
/// Gets the numbers of columns in the current table.
|
||||
pub fn table_column_count(&self) -> usize {
|
||||
unsafe { sys::igTableGetColumnCount() as usize }
|
||||
}
|
||||
|
||||
pub fn table_get_column_flags(&self) -> TableColumnFlags {
|
||||
self.table_get_column_flags_with_column(-1)
|
||||
/// Gets the current column index in the current table.
|
||||
pub fn table_column_index(&self) -> usize {
|
||||
unsafe { sys::igTableGetColumnIndex() as usize }
|
||||
}
|
||||
pub fn table_get_column_flags_with_column(&self, column_n: i32) -> TableColumnFlags {
|
||||
|
||||
/// Gets the current row index in the current table.
|
||||
pub fn table_row_index(&self) -> usize {
|
||||
unsafe { sys::igTableGetRowIndex() as usize }
|
||||
}
|
||||
|
||||
/// Gets the flags on the current column in the current table.
|
||||
pub fn table_column_flags(&self) -> TableColumnFlags {
|
||||
unsafe {
|
||||
TableColumnFlags::from_bits_unchecked(sys::igTableGetColumnFlags(column_n) as u32)
|
||||
TableColumnFlags::from_bits(sys::igTableGetColumnFlags(-1) as u32)
|
||||
.expect("bad column flags")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn table_set_bg_color(&self, target: TableBgTarget, color: [f32; 4]) {
|
||||
self.table_set_bg_color_with_column(target, color, -1);
|
||||
/// Gets the flags on the given column in the current table. To get the current column's
|
||||
/// flags without having to call [table_column_index](Self::table_column_index), use
|
||||
/// [table_column_flags](Self::table_column_flags).
|
||||
pub fn table_column_flags_with_column(&self, column_n: usize) -> TableColumnFlags {
|
||||
unsafe {
|
||||
TableColumnFlags::from_bits(sys::igTableGetColumnFlags(column_n as i32) as u32)
|
||||
.expect("bad column flags")
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the name of the current column. If there is no currently bound name
|
||||
/// for this column, we will return an empty string.
|
||||
///
|
||||
/// Use [table_column_name_with_column](Self::table_column_name_with_column)
|
||||
/// for arbitrary indices.
|
||||
pub fn table_column_name(&mut self) -> &ImStr {
|
||||
unsafe { ImStr::from_ptr_unchecked(sys::igTableGetColumnName(-1)) }
|
||||
}
|
||||
|
||||
/// Gets the name of a given column. If there is no currently bound name
|
||||
/// for this column, we will return an empty string.
|
||||
///
|
||||
/// Use [table_column_name](Self::table_column_name) for the current column.
|
||||
pub fn table_column_name_with_column(&mut self, column: usize) -> &ImStr {
|
||||
unsafe { ImStr::from_ptr_unchecked(sys::igTableGetColumnName(column as i32)) }
|
||||
}
|
||||
|
||||
/// Sets the given background color for this column. See [TableBgTarget]
|
||||
/// for more information on how colors work for tables.
|
||||
///
|
||||
/// Use [table_set_bg_color_with_column](Self::table_set_bg_color_with_column) to set
|
||||
/// for arbitrary indices.
|
||||
pub fn table_set_bg_color(&self, target: TableBgTarget, color: impl Into<ImColor32>) {
|
||||
unsafe {
|
||||
sys::igTableSetBgColor(target.bits() as i32, color.into().into(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the given background color for any column. See [TableBgTarget]
|
||||
/// for more information on how colors work for tables.
|
||||
///
|
||||
/// Use [table_set_bg_color](Self::table_set_bg_color) for the current column.
|
||||
pub fn table_set_bg_color_with_column(
|
||||
&self,
|
||||
target: TableBgTarget,
|
||||
color: [f32; 4],
|
||||
column_n: i32,
|
||||
color: impl Into<ImColor32>,
|
||||
column_index: usize,
|
||||
) {
|
||||
let color = ImColor32::from(color);
|
||||
unsafe {
|
||||
sys::igTableSetBgColor(target.bits() as i32, color.to_bits(), column_n);
|
||||
sys::igTableSetBgColor(
|
||||
target.bits() as i32,
|
||||
color.into().into(),
|
||||
column_index as i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TableHeader<'a> {
|
||||
/// A struct containing all the data needed to setup a table column header
|
||||
/// via [begin_table_header](Ui::begin_table_header) or [table_setup_column](Ui::table_setup_column).
|
||||
pub struct TableColumnSetup<'a> {
|
||||
/// The name of column to be displayed to users.
|
||||
pub name: &'a ImStr,
|
||||
/// The flags this column will have.
|
||||
pub flags: TableColumnFlags,
|
||||
/// The width or weight of the given column.
|
||||
pub init_width_or_weight: f32,
|
||||
/// A user_id, primarily used in sorting operations.
|
||||
pub user_id: Id<'a>,
|
||||
}
|
||||
|
||||
impl<'a> TableHeader<'a> {
|
||||
impl<'a> TableColumnSetup<'a> {
|
||||
pub fn new(name: &'a ImStr) -> Self {
|
||||
Self {
|
||||
name,
|
||||
@ -292,12 +678,12 @@ impl<'a> TableHeader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for TableHeader<'a> {
|
||||
impl<'a> Default for TableColumnSetup<'a> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: Default::default(),
|
||||
flags: Default::default(),
|
||||
init_width_or_weight: Default::default(),
|
||||
flags: TableColumnFlags::empty(),
|
||||
init_width_or_weight: 0.0,
|
||||
user_id: Id::Int(0),
|
||||
}
|
||||
}
|
||||
@ -308,6 +694,6 @@ create_token!(
|
||||
/// or by dropping.
|
||||
pub struct TableToken<'ui>;
|
||||
|
||||
/// Pops a change from the font stack.
|
||||
/// Ends the table.
|
||||
drop { sys::igEndTable() }
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user