1#![allow(
8 clippy::cast_possible_truncation,
9 clippy::cast_sign_loss,
10 clippy::as_conversions,
11 clippy::unnecessary_cast
12)]
13use crate::Ui;
14use crate::sys;
15use bitflags::bitflags;
16
17bitflags! {
18 #[repr(transparent)]
20 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21 pub struct OldColumnFlags: i32 {
22 const NONE = sys::ImGuiOldColumnFlags_None as i32;
24 const NO_BORDER = sys::ImGuiOldColumnFlags_NoBorder as i32;
26 const NO_RESIZE = sys::ImGuiOldColumnFlags_NoResize as i32;
28 const NO_PRESERVE_WIDTHS = sys::ImGuiOldColumnFlags_NoPreserveWidths as i32;
30 const NO_FORCE_WITHIN_WINDOW = sys::ImGuiOldColumnFlags_NoForceWithinWindow as i32;
32 const GROW_PARENT_CONTENTS_SIZE = sys::ImGuiOldColumnFlags_GrowParentContentsSize as i32;
34 }
35}
36
37impl Default for OldColumnFlags {
38 fn default() -> Self {
39 OldColumnFlags::NONE
40 }
41}
42
43impl Ui {
45 #[doc(alias = "Columns")]
52 pub fn columns(&self, count: i32, id: impl AsRef<str>, border: bool) {
53 unsafe { sys::igColumns(count, self.scratch_txt(id), border) }
54 }
55
56 #[doc(alias = "BeginColumns")]
63 pub fn begin_columns(&self, id: impl AsRef<str>, count: i32, flags: OldColumnFlags) {
64 unsafe { sys::igBeginColumns(self.scratch_txt(id), count, flags.bits()) }
65 }
66
67 #[doc(alias = "BeginColumns")]
69 pub fn begin_columns_token(
70 &self,
71 id: impl AsRef<str>,
72 count: i32,
73 flags: OldColumnFlags,
74 ) -> ColumnsToken<'_> {
75 self.begin_columns(id, count, flags);
76 ColumnsToken { ui: self }
77 }
78
79 #[doc(alias = "EndColumns")]
81 pub fn end_columns(&self) {
82 unsafe { sys::igEndColumns() }
83 }
84
85 #[doc(alias = "NextColumn")]
89 pub fn next_column(&self) {
90 unsafe { sys::igNextColumn() }
91 }
92
93 #[doc(alias = "GetColumnIndex")]
95 pub fn current_column_index(&self) -> i32 {
96 unsafe { sys::igGetColumnIndex() }
97 }
98
99 #[doc(alias = "GetColumnWidth")]
101 pub fn current_column_width(&self) -> f32 {
102 unsafe { sys::igGetColumnWidth(-1) }
103 }
104
105 #[doc(alias = "GetColumnWidth")]
107 pub fn column_width(&self, column_index: i32) -> f32 {
108 unsafe { sys::igGetColumnWidth(column_index) }
109 }
110
111 #[doc(alias = "SetColumnWidth")]
113 pub fn set_current_column_width(&self, width: f32) {
114 unsafe { sys::igSetColumnWidth(-1, width) };
115 }
116
117 #[doc(alias = "SetColumnWidth")]
119 pub fn set_column_width(&self, column_index: i32, width: f32) {
120 unsafe { sys::igSetColumnWidth(column_index, width) };
121 }
122
123 #[doc(alias = "GetColumnOffset")]
125 pub fn current_column_offset(&self) -> f32 {
126 unsafe { sys::igGetColumnOffset(-1) }
127 }
128
129 #[doc(alias = "GetColumnOffset")]
131 pub fn column_offset(&self, column_index: i32) -> f32 {
132 unsafe { sys::igGetColumnOffset(column_index) }
133 }
134
135 #[doc(alias = "SetColumnOffset")]
137 pub fn set_current_column_offset(&self, offset_x: f32) {
138 unsafe { sys::igSetColumnOffset(-1, offset_x) };
139 }
140
141 #[doc(alias = "SetColumnOffset")]
143 pub fn set_column_offset(&self, column_index: i32, offset_x: f32) {
144 unsafe { sys::igSetColumnOffset(column_index, offset_x) };
145 }
146
147 #[doc(alias = "GetColumnsCount")]
149 pub fn column_count(&self) -> i32 {
150 unsafe { sys::igGetColumnsCount() }
151 }
152
153 #[doc(alias = "PushColumnClipRect")]
160 pub fn push_column_clip_rect(&self, column_index: i32) {
161 unsafe { sys::igPushColumnClipRect(column_index) }
162 }
163
164 #[doc(alias = "PushColumnsBackground")]
166 pub fn push_columns_background(&self) {
167 unsafe { sys::igPushColumnsBackground() }
168 }
169
170 #[doc(alias = "PopColumnsBackground")]
172 pub fn pop_columns_background(&self) {
173 unsafe { sys::igPopColumnsBackground() }
174 }
175
176 #[doc(alias = "GetColumnsID")]
178 pub fn get_columns_id(&self, str_id: impl AsRef<str>, count: i32) -> u32 {
179 unsafe { sys::igGetColumnsID(self.scratch_txt(str_id), count) }
180 }
181
182 pub fn is_any_column_resizing(&self) -> bool {
190 unsafe {
191 let window = sys::igGetCurrentWindowRead();
192 if window.is_null() {
193 return false;
194 }
195
196 let columns = (*window).DC.CurrentColumns;
197 if columns.is_null() {
198 return false;
199 }
200
201 (*columns).IsBeingResized
202 }
203 }
204
205 pub fn get_columns_total_width(&self) -> f32 {
207 let count = self.column_count();
208 if count <= 0 {
209 return 0.0;
210 }
211
212 let mut total_width = 0.0;
213 for i in 0..count {
214 total_width += self.column_width(i);
215 }
216 total_width
217 }
218
219 pub fn set_columns_equal_width(&self) {
221 let count = self.column_count();
222 if count <= 1 {
223 return;
224 }
225
226 let total_width = self.get_columns_total_width();
227 let equal_width = total_width / count as f32;
228
229 for i in 0..count {
230 self.set_column_width(i, equal_width);
231 }
232 }
233
234 pub fn get_column_width_percentage(&self, column_index: i32) -> f32 {
236 let total_width = self.get_columns_total_width();
237 if total_width <= 0.0 {
238 return 0.0;
239 }
240
241 let column_width = self.column_width(column_index);
242 (column_width / total_width) * 100.0
243 }
244
245 pub fn set_column_width_percentage(&self, column_index: i32, percentage: f32) {
247 let total_width = self.get_columns_total_width();
248 if total_width <= 0.0 {
249 return;
250 }
251
252 let new_width = (total_width * percentage) / 100.0;
253 self.set_column_width(column_index, new_width);
254 }
255}
256
257#[must_use]
259pub struct ColumnsToken<'ui> {
260 ui: &'ui Ui,
261}
262
263impl Drop for ColumnsToken<'_> {
264 fn drop(&mut self) {
265 self.ui.end_columns();
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::OldColumnFlags;
272
273 #[test]
274 fn is_any_column_resizing_reads_current_columns_state() {
275 let mut ctx = crate::Context::create();
276 let _ = ctx.font_atlas_mut().build();
277 ctx.io_mut().set_display_size([128.0, 128.0]);
278 ctx.io_mut().set_delta_time(1.0 / 60.0);
279 let ui = ctx.frame();
280
281 ui.window("columns_resize_test").build(|| {
282 assert!(!ui.is_any_column_resizing());
283
284 let _columns = ui.begin_columns_token("legacy_columns", 2, OldColumnFlags::NONE);
285 let window = unsafe { crate::sys::igGetCurrentWindowRead() };
286 assert!(!window.is_null());
287
288 let columns = unsafe { (*window).DC.CurrentColumns };
289 assert!(!columns.is_null());
290 assert!(!ui.is_any_column_resizing());
291
292 unsafe {
293 (*columns).IsBeingResized = true;
294 }
295
296 assert!(ui.is_any_column_resizing());
297 });
298 }
299}