Skip to main content

dear_imgui_rs/widget/table/
headers.rs

1use crate::draw::ImColor32;
2use crate::internal::len_i32;
3use crate::sys;
4use crate::ui::Ui;
5use crate::widget::table::{
6    TableBackgroundChannelToken, TableColumnChannelToken, TableColumnIndex, TableContextMenuTarget,
7    assert_current_table, assert_current_table_cell, assert_valid_table_column,
8    assert_valid_table_column_in,
9};
10
11/// Safe description of a single angled header cell.
12#[derive(Copy, Clone, Debug, PartialEq)]
13pub struct TableHeaderData {
14    pub index: TableColumnIndex,
15    pub text_color: ImColor32,
16    pub bg_color0: ImColor32,
17    pub bg_color1: ImColor32,
18}
19
20impl TableHeaderData {
21    pub fn new(
22        index: impl Into<TableColumnIndex>,
23        text_color: ImColor32,
24        bg_color0: ImColor32,
25        bg_color1: ImColor32,
26    ) -> Self {
27        Self {
28            index: index.into(),
29            text_color,
30            bg_color0,
31            bg_color1,
32        }
33    }
34}
35impl Ui {
36    /// Maximum label width used for angled headers (when enabled in style/options).
37    #[doc(alias = "TableGetHeaderAngledMaxLabelWidth")]
38    pub fn table_get_header_angled_max_label_width(&self) -> f32 {
39        self.run_with_bound_context(|| unsafe { sys::igTableGetHeaderAngledMaxLabelWidth() })
40    }
41
42    /// Submit angled headers row (requires style/flags enabling angled headers).
43    #[doc(alias = "TableAngledHeadersRow")]
44    pub fn table_angled_headers_row(&self) {
45        self.run_with_bound_context(|| unsafe { sys::igTableAngledHeadersRow() });
46    }
47
48    // Removed legacy TableAngledHeadersRowEx(flags) wrapper; use `table_angled_headers_row_ex_with_data`.
49
50    /// Submit angled headers row with explicit data (Ex variant).
51    ///
52    /// - `row_id`: ImGuiID for the row. Use 0 for automatic if not needed.
53    /// - `angle`: Angle in radians for headers.
54    /// - `max_label_width`: Maximum label width for angled headers.
55    /// - `headers`: Per-column header data.
56    pub fn table_angled_headers_row_ex_with_data(
57        &self,
58        row_id: u32,
59        angle: f32,
60        max_label_width: f32,
61        headers: &[TableHeaderData],
62    ) {
63        if headers.is_empty() {
64            self.run_with_bound_context(|| unsafe { sys::igTableAngledHeadersRow() });
65            return;
66        }
67        let count = len_i32(
68            "Ui::table_angled_headers_row_ex_with_data()",
69            "headers",
70            headers.len(),
71        );
72        let mut data: Vec<sys::ImGuiTableHeaderData> = Vec::with_capacity(headers.len());
73        self.run_with_bound_context(|| {
74            let table = assert_current_table("Ui::table_angled_headers_row_ex_with_data()");
75            for h in headers {
76                assert_valid_table_column_in(
77                    table,
78                    h.index,
79                    "Ui::table_angled_headers_row_ex_with_data()",
80                );
81                data.push(sys::ImGuiTableHeaderData {
82                    Index: h
83                        .index
84                        .into_imgui_column_idx("Ui::table_angled_headers_row_ex_with_data()"),
85                    TextColor: u32::from(h.text_color),
86                    BgColor0: u32::from(h.bg_color0),
87                    BgColor1: u32::from(h.bg_color1),
88                });
89            }
90            unsafe {
91                sys::igTableAngledHeadersRowEx(
92                    row_id,
93                    angle,
94                    max_label_width,
95                    data.as_ptr(),
96                    count,
97                );
98            }
99        });
100    }
101
102    /// Push background draw channel for the current table and return a token to pop it.
103    #[must_use = "dropping the token pops the table background draw channel immediately"]
104    #[doc(alias = "TablePushBackgroundChannel")]
105    pub fn table_background_channel(&self) -> TableBackgroundChannelToken<'_> {
106        self.run_with_bound_context(|| {
107            assert_current_table_cell("Ui::table_background_channel()");
108            unsafe { sys::igTablePushBackgroundChannel() };
109        });
110        TableBackgroundChannelToken::new(self)
111    }
112
113    /// Push column draw channel for the given column index and return a token to pop it.
114    #[must_use = "dropping the token pops the table column draw channel immediately"]
115    #[doc(alias = "TablePushColumnChannel")]
116    pub fn table_column_channel(
117        &self,
118        column: impl Into<TableColumnIndex>,
119    ) -> TableColumnChannelToken<'_> {
120        let column = column.into();
121        self.run_with_bound_context(|| {
122            assert_current_table_cell("Ui::table_column_channel()");
123            let column_n = assert_valid_table_column(column, "Ui::table_column_channel()");
124            unsafe { sys::igTablePushColumnChannel(column_n) };
125        });
126        TableColumnChannelToken::new(self)
127    }
128
129    /// Run a closure after pushing table background channel (auto-pop on return).
130    pub fn with_table_background_channel<R>(&self, f: impl FnOnce() -> R) -> R {
131        let _token = self.table_background_channel();
132        f()
133    }
134
135    /// Run a closure after pushing a table column channel (auto-pop on return).
136    pub fn with_table_column_channel<R>(
137        &self,
138        column: impl Into<TableColumnIndex>,
139        f: impl FnOnce() -> R,
140    ) -> R {
141        let _token = self.table_column_channel(column);
142        f()
143    }
144
145    /// Open the table context menu for the current/default column.
146    #[doc(alias = "TableOpenContextMenu")]
147    pub fn table_open_context_menu(&self, target: impl Into<TableContextMenuTarget>) {
148        let target = target.into();
149        self.run_with_bound_context(|| {
150            let column_n = match target {
151                TableContextMenuTarget::CurrentColumn => -1,
152                TableContextMenuTarget::Column(index) => {
153                    index.into_i32("Ui::table_open_context_menu()")
154                }
155                TableContextMenuTarget::Table => {
156                    let table = assert_current_table("Ui::table_open_context_menu()");
157                    unsafe { (*table).ColumnsCount }
158                }
159            };
160            unsafe { sys::igTableOpenContextMenu(column_n) }
161        });
162    }
163}