Skip to main content

dear_imgui_rs/columns/
ui.rs

1use crate::sys;
2use crate::{Id, Ui};
3
4use super::counts::{column_count_from_i32, columns_count_to_i32};
5use super::flags::{OldColumnFlags, validate_old_column_flags};
6use super::index::{OldColumnIndex, OldColumnOffsetRef, OldColumnRef};
7use super::numeric::assert_non_negative_f32;
8use super::resolve::{
9    assert_valid_column_in, resolve_column_offset_query_ref, resolve_column_offset_ref,
10    resolve_column_query_ref,
11};
12use super::state::{assert_current_columns, assert_no_current_columns, current_columns};
13use super::token::{ColumnsBackgroundToken, ColumnsToken};
14
15/// # Columns
16impl Ui {
17    /// Creates columns layout.
18    ///
19    /// # Arguments
20    /// * `count` - Number of columns (must be >= 1)
21    /// * `id` - Optional ID for the columns (can be empty string)
22    /// * `border` - Whether to draw borders between columns
23    #[doc(alias = "Columns")]
24    pub fn columns(&self, count: usize, id: impl AsRef<str>, border: bool) {
25        let count = columns_count_to_i32(count, "Ui::columns()");
26        let id = self.scratch_txt(id);
27        self.run_with_bound_context(|| unsafe { sys::igColumns(count, id, border) });
28    }
29
30    /// Begin columns layout with advanced flags.
31    ///
32    /// # Arguments
33    /// * `id` - ID for the columns
34    /// * `count` - Number of columns (must be >= 1)
35    /// * `flags` - Column flags
36    #[doc(alias = "BeginColumns")]
37    pub fn begin_columns(
38        &self,
39        id: impl AsRef<str>,
40        count: usize,
41        flags: OldColumnFlags,
42    ) -> ColumnsToken<'_> {
43        let count = columns_count_to_i32(count, "Ui::begin_columns()");
44        validate_old_column_flags("Ui::begin_columns()", flags);
45        let id = self.scratch_txt(id);
46        self.run_with_bound_context(|| {
47            assert_no_current_columns("Ui::begin_columns()");
48            unsafe { sys::igBeginColumns(id, count, flags.bits()) };
49        });
50        ColumnsToken { ui: self }
51    }
52
53    /// End columns layout.
54    #[doc(alias = "EndColumns")]
55    pub(crate) fn end_columns(&self) {
56        self.run_with_bound_context(|| {
57            assert_current_columns("Ui::end_columns()");
58            unsafe { sys::igEndColumns() }
59        });
60    }
61
62    /// Switches to the next column.
63    ///
64    /// If the current row is finished, switches to first column of the next row
65    #[doc(alias = "NextColumn")]
66    pub fn next_column(&self) {
67        self.run_with_bound_context(|| unsafe { sys::igNextColumn() });
68    }
69
70    /// Returns the index of the current column
71    #[doc(alias = "GetColumnIndex")]
72    pub fn current_column_index(&self) -> OldColumnIndex {
73        OldColumnIndex::from_i32(
74            self.run_with_bound_context(|| unsafe { sys::igGetColumnIndex() }),
75            "Ui::current_column_index()",
76        )
77    }
78
79    /// Returns the width of the current column (in pixels)
80    #[doc(alias = "GetColumnWidth")]
81    pub fn current_column_width(&self) -> f32 {
82        self.run_with_bound_context(|| unsafe { sys::igGetColumnWidth(-1) })
83    }
84
85    /// Returns the width of the given column (in pixels)
86    #[doc(alias = "GetColumnWidth")]
87    pub fn column_width(&self, column: impl Into<OldColumnRef>) -> f32 {
88        let column_index = resolve_column_query_ref(column.into(), "Ui::column_width()");
89        self.run_with_bound_context(|| unsafe { sys::igGetColumnWidth(column_index) })
90    }
91
92    /// Sets the width of the current column (in pixels)
93    #[doc(alias = "SetColumnWidth")]
94    pub fn set_current_column_width(&self, width: f32) {
95        assert_non_negative_f32("Ui::set_current_column_width()", "width", width);
96        self.run_with_bound_context(|| {
97            assert_current_columns("Ui::set_current_column_width()");
98            unsafe { sys::igSetColumnWidth(-1, width) };
99        });
100    }
101
102    /// Sets the width of the given column (in pixels)
103    #[doc(alias = "SetColumnWidth")]
104    pub fn set_column_width(&self, column: impl Into<OldColumnIndex>, width: f32) {
105        assert_non_negative_f32("Ui::set_column_width()", "width", width);
106        self.run_with_bound_context(|| {
107            let columns = assert_current_columns("Ui::set_column_width()");
108            let column_index =
109                assert_valid_column_in(columns, column.into(), "Ui::set_column_width()");
110            unsafe { sys::igSetColumnWidth(column_index, width) };
111        });
112    }
113
114    /// Returns the offset of the current column (in pixels from the left side of the content region)
115    #[doc(alias = "GetColumnOffset")]
116    pub fn current_column_offset(&self) -> f32 {
117        self.run_with_bound_context(|| unsafe { sys::igGetColumnOffset(-1) })
118    }
119
120    /// Returns the offset of the given column (in pixels from the left side of the content region)
121    #[doc(alias = "GetColumnOffset")]
122    pub fn column_offset(&self, offset: impl Into<OldColumnOffsetRef>) -> f32 {
123        let column_index = resolve_column_offset_query_ref(offset.into(), "Ui::column_offset()");
124        self.run_with_bound_context(|| unsafe { sys::igGetColumnOffset(column_index) })
125    }
126
127    /// Sets the offset of the current column (in pixels from the left side of the content region)
128    #[doc(alias = "SetColumnOffset")]
129    pub fn set_current_column_offset(&self, offset_x: f32) {
130        assert_non_negative_f32("Ui::set_current_column_offset()", "offset_x", offset_x);
131        self.run_with_bound_context(|| {
132            assert_current_columns("Ui::set_current_column_offset()");
133            unsafe { sys::igSetColumnOffset(-1, offset_x) };
134        });
135    }
136
137    /// Sets the offset of the given column (in pixels from the left side of the content region)
138    #[doc(alias = "SetColumnOffset")]
139    pub fn set_column_offset(&self, offset: impl Into<OldColumnOffsetRef>, offset_x: f32) {
140        assert_non_negative_f32("Ui::set_column_offset()", "offset_x", offset_x);
141        self.run_with_bound_context(|| {
142            let column_index = resolve_column_offset_ref(offset.into(), "Ui::set_column_offset()");
143            unsafe { sys::igSetColumnOffset(column_index, offset_x) };
144        });
145    }
146
147    /// Returns the current amount of columns
148    #[doc(alias = "GetColumnsCount")]
149    pub fn column_count(&self) -> usize {
150        column_count_from_i32(
151            self.run_with_bound_context(|| unsafe { sys::igGetColumnsCount() }),
152            "Ui::column_count()",
153        )
154    }
155
156    // ============================================================================
157    // Advanced column utilities
158    // ============================================================================
159
160    /// Push column clip rect for the given column index.
161    /// This is useful for custom drawing within columns.
162    #[doc(alias = "PushColumnClipRect")]
163    pub fn push_column_clip_rect(
164        &self,
165        column: impl Into<OldColumnIndex>,
166    ) -> crate::layout::ClipRectToken<'_> {
167        self.run_with_bound_context(|| {
168            let columns = assert_current_columns("Ui::push_column_clip_rect()");
169            let column_index =
170                assert_valid_column_in(columns, column.into(), "Ui::push_column_clip_rect()");
171            unsafe { sys::igPushColumnClipRect(column_index) };
172        });
173        crate::layout::ClipRectToken::new(self)
174    }
175
176    /// Push columns background for drawing.
177    #[doc(alias = "PushColumnsBackground")]
178    pub fn push_columns_background(&self) -> ColumnsBackgroundToken<'_> {
179        self.run_with_bound_context(|| {
180            assert_current_columns("Ui::push_columns_background()");
181            unsafe { sys::igPushColumnsBackground() };
182        });
183        ColumnsBackgroundToken { ui: self }
184    }
185
186    /// Pop columns background.
187    #[doc(alias = "PopColumnsBackground")]
188    pub(crate) fn pop_columns_background(&self) {
189        self.run_with_bound_context(|| {
190            assert_current_columns("Ui::pop_columns_background()");
191            unsafe { sys::igPopColumnsBackground() }
192        });
193    }
194
195    /// Get columns ID for the given string ID and count.
196    #[doc(alias = "GetColumnsID")]
197    pub fn get_columns_id(&self, str_id: impl AsRef<str>, count: usize) -> Id {
198        let count = columns_count_to_i32(count, "Ui::get_columns_id()");
199        let str_id = self.scratch_txt(str_id);
200        self.run_with_bound_context(|| unsafe { Id::from(sys::igGetColumnsID(str_id, count)) })
201    }
202
203    // ============================================================================
204    // Column state utilities
205    // ============================================================================
206
207    /// Check if any column in the current legacy columns set is being resized.
208    ///
209    /// Returns `false` when the current window is not inside a legacy columns set.
210    pub fn is_any_column_resizing(&self) -> bool {
211        self.run_with_bound_context(|| unsafe {
212            let window = sys::igGetCurrentWindowRead();
213            if window.is_null() {
214                return false;
215            }
216
217            let columns = (*window).DC.CurrentColumns;
218            if columns.is_null() {
219                return false;
220            }
221
222            (*columns).IsBeingResized
223        })
224    }
225
226    /// Get the total width of all columns.
227    pub fn get_columns_total_width(&self) -> f32 {
228        if current_columns().is_null() {
229            return self.current_column_width();
230        }
231
232        let count = self.column_count();
233
234        let mut total_width = 0.0;
235        for i in 0..count {
236            total_width += self.column_width(i);
237        }
238        total_width
239    }
240
241    /// Set all columns to equal width.
242    pub fn set_columns_equal_width(&self) {
243        let count = self.column_count();
244        if count <= 1 {
245            return;
246        }
247
248        let total_width = self.get_columns_total_width();
249        let equal_width = total_width / count as f32;
250
251        for i in 0..count {
252            self.set_column_width(i, equal_width);
253        }
254    }
255
256    /// Get column width as a percentage of total width.
257    pub fn get_column_width_percentage(&self, column: impl Into<OldColumnRef>) -> f32 {
258        let total_width = self.get_columns_total_width();
259        if total_width <= 0.0 {
260            return 0.0;
261        }
262
263        let column_width = self.column_width(column);
264        (column_width / total_width) * 100.0
265    }
266
267    /// Set column width as a percentage of total width.
268    pub fn set_column_width_percentage(&self, column: impl Into<OldColumnIndex>, percentage: f32) {
269        assert_non_negative_f32(
270            "Ui::set_column_width_percentage()",
271            "percentage",
272            percentage,
273        );
274        let total_width = self.get_columns_total_width();
275        if total_width <= 0.0 {
276            return;
277        }
278
279        let new_width = (total_width * percentage) / 100.0;
280        self.set_column_width(column, new_width);
281    }
282}