1#![allow(
18 clippy::cast_possible_truncation,
19 clippy::cast_sign_loss,
20 clippy::as_conversions,
21 clippy::unnecessary_cast
22)]
23use crate::Id;
24use crate::Ui;
25use crate::sys;
26use std::ffi::c_void;
27
28fn assert_finite_f32(caller: &str, name: &str, value: f32) {
29 assert!(value.is_finite(), "{caller} {name} must be finite");
30}
31
32fn assert_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
33 assert!(
34 value[0].is_finite() && value[1].is_finite(),
35 "{caller} {name} must contain finite values"
36 );
37}
38
39create_token!(
40 pub struct GroupToken<'ui>;
42
43 drop { unsafe { sys::igEndGroup() } }
46);
47
48create_token!(
49 pub struct ClipRectToken<'ui>;
51
52 drop { unsafe { sys::igPopClipRect() } }
54);
55
56create_token!(
57 pub struct HorizontalStackLayoutToken<'ui>;
63
64 drop { unsafe { sys::ImGuiStack_EndHorizontal() } }
66);
67
68create_token!(
69 pub struct VerticalStackLayoutToken<'ui>;
75
76 drop { unsafe { sys::ImGuiStack_EndVertical() } }
78);
79
80create_token!(
81 pub struct StackLayoutSuspensionToken<'ui>;
83
84 drop { unsafe { sys::ImGuiStack_ResumeLayout() } }
86);
87
88#[derive(Clone, Copy, Debug)]
94pub enum StackLayoutId<'a> {
95 Str(&'a str),
96 Ptr(*const c_void),
97 Int(i32),
98 Raw(Id),
99}
100
101impl<'a> StackLayoutId<'a> {
102 #[inline]
104 pub const fn ptr(ptr: *const c_void) -> Self {
105 Self::Ptr(ptr)
106 }
107
108 #[inline]
111 pub const fn pointer_value(value: usize) -> Self {
112 Self::Ptr(value as *const c_void)
113 }
114}
115
116impl<'a> From<&'a str> for StackLayoutId<'a> {
117 #[inline]
118 fn from(value: &'a str) -> Self {
119 Self::Str(value)
120 }
121}
122
123impl From<i32> for StackLayoutId<'_> {
124 #[inline]
125 fn from(value: i32) -> Self {
126 Self::Int(value)
127 }
128}
129
130impl From<Id> for StackLayoutId<'_> {
131 #[inline]
132 fn from(value: Id) -> Self {
133 Self::Raw(value)
134 }
135}
136
137impl Ui {
139 #[doc(alias = "Separator")]
143 pub fn separator(&self) {
144 unsafe { sys::igSeparator() }
145 }
146
147 #[doc(alias = "SeparatorText")]
149 pub fn separator_with_text(&self, text: impl AsRef<str>) {
150 unsafe { sys::igSeparatorText(self.scratch_txt(text)) }
151 }
152
153 #[doc(alias = "SeparatorEx")]
155 pub fn separator_vertical(&self) {
156 unsafe { sys::igSeparatorEx(sys::ImGuiSeparatorFlags_Vertical as i32, 1.0) }
157 }
158
159 #[doc(alias = "SeparatorEx")]
161 pub fn separator_horizontal(&self) {
162 unsafe { sys::igSeparatorEx(sys::ImGuiSeparatorFlags_Horizontal as i32, 1.0) }
163 }
164
165 #[doc(alias = "SameLine")]
172 pub fn same_line(&self) {
173 self.same_line_with_pos(0.0);
174 }
175
176 #[doc(alias = "SameLine")]
183 pub fn same_line_with_pos(&self, pos_x: f32) {
184 self.same_line_with_spacing(pos_x, -1.0)
185 }
186
187 #[doc(alias = "SameLine")]
191 pub fn same_line_with_spacing(&self, pos_x: f32, spacing_w: f32) {
192 assert_finite_f32("Ui::same_line_with_spacing()", "pos_x", pos_x);
193 assert_finite_f32("Ui::same_line_with_spacing()", "spacing_w", spacing_w);
194 unsafe { sys::igSameLine(pos_x, spacing_w) }
195 }
196
197 #[doc(alias = "NewLine")]
199 pub fn new_line(&self) {
200 unsafe { sys::igNewLine() }
201 }
202
203 #[doc(alias = "Spacing")]
205 pub fn spacing(&self) {
206 unsafe { sys::igSpacing() }
207 }
208
209 #[doc(alias = "Dummy")]
213 pub fn dummy(&self, size: impl Into<[f32; 2]>) {
214 let size = size.into();
215 assert_finite_vec2("Ui::dummy()", "size", size);
216 let size_vec: sys::ImVec2 = size.into();
217 unsafe { sys::igDummy(size_vec) }
218 }
219
220 #[doc(alias = "Indent")]
225 pub fn indent(&self) {
226 self.indent_by(0.0)
227 }
228
229 #[doc(alias = "Indent")]
231 pub fn indent_by(&self, width: f32) {
232 assert_finite_f32("Ui::indent_by()", "width", width);
233 unsafe { sys::igIndent(width) };
234 }
235
236 #[doc(alias = "Unindent")]
241 pub fn unindent(&self) {
242 self.unindent_by(0.0)
243 }
244
245 #[doc(alias = "Unindent")]
247 pub fn unindent_by(&self, width: f32) {
248 assert_finite_f32("Ui::unindent_by()", "width", width);
249 unsafe { sys::igUnindent(width) };
250 }
251
252 #[doc(alias = "BeginGroup")]
256 pub fn begin_group(&self) -> GroupToken<'_> {
257 unsafe { sys::igBeginGroup() };
258 GroupToken::new(self)
259 }
260
261 #[doc(alias = "BeginGroup")]
265 pub fn group<R, F: FnOnce() -> R>(&self, f: F) -> R {
266 let group = self.begin_group();
267 let result = f();
268 group.end();
269 result
270 }
271
272 #[doc(alias = "BeginHorizontal")]
278 pub fn begin_horizontal_stack_layout<'ui, 'id>(
279 &'ui self,
280 id: impl Into<StackLayoutId<'id>>,
281 size: impl Into<[f32; 2]>,
282 align: f32,
283 ) -> HorizontalStackLayoutToken<'ui> {
284 let size = size.into();
285 assert_finite_vec2("Ui::begin_horizontal_stack_layout()", "size", size);
286 assert!(
287 align.is_finite(),
288 "Ui::begin_horizontal_stack_layout() align must be finite"
289 );
290 let size = sys::ImVec2::from(size);
291 unsafe {
292 match id.into() {
293 StackLayoutId::Str(value) => {
294 sys::ImGuiStack_BeginHorizontal_Str(self.scratch_txt(value), size, align);
295 }
296 StackLayoutId::Ptr(value) => {
297 sys::ImGuiStack_BeginHorizontal_Ptr(value, size, align);
298 }
299 StackLayoutId::Int(value) => {
300 sys::ImGuiStack_BeginHorizontal_Int(value, size, align);
301 }
302 StackLayoutId::Raw(value) => {
303 sys::ImGuiStack_BeginHorizontal_Id(value.raw(), size, align);
304 }
305 }
306 }
307 HorizontalStackLayoutToken::new(self)
308 }
309
310 #[doc(alias = "BeginHorizontal")]
315 pub fn begin_horizontal<'ui, 'id>(
316 &'ui self,
317 id: impl Into<StackLayoutId<'id>>,
318 size: impl Into<[f32; 2]>,
319 align: f32,
320 ) -> HorizontalStackLayoutToken<'ui> {
321 self.begin_horizontal_stack_layout(id, size, align)
322 }
323
324 #[doc(alias = "BeginHorizontal", alias = "EndHorizontal")]
326 pub fn horizontal_stack_layout<'id, R>(
327 &self,
328 id: impl Into<StackLayoutId<'id>>,
329 size: impl Into<[f32; 2]>,
330 align: f32,
331 f: impl FnOnce() -> R,
332 ) -> R {
333 let token = self.begin_horizontal_stack_layout(id, size, align);
334 let result = f();
335 token.end();
336 result
337 }
338
339 #[doc(alias = "BeginHorizontal", alias = "EndHorizontal")]
343 pub fn horizontal<'id, R>(
344 &self,
345 id: impl Into<StackLayoutId<'id>>,
346 size: impl Into<[f32; 2]>,
347 align: f32,
348 f: impl FnOnce() -> R,
349 ) -> R {
350 self.horizontal_stack_layout(id, size, align, f)
351 }
352
353 #[doc(alias = "BeginVertical")]
359 pub fn begin_vertical_stack_layout<'ui, 'id>(
360 &'ui self,
361 id: impl Into<StackLayoutId<'id>>,
362 size: impl Into<[f32; 2]>,
363 align: f32,
364 ) -> VerticalStackLayoutToken<'ui> {
365 let size = size.into();
366 assert_finite_vec2("Ui::begin_vertical_stack_layout()", "size", size);
367 assert!(
368 align.is_finite(),
369 "Ui::begin_vertical_stack_layout() align must be finite"
370 );
371 let size = sys::ImVec2::from(size);
372 unsafe {
373 match id.into() {
374 StackLayoutId::Str(value) => {
375 sys::ImGuiStack_BeginVertical_Str(self.scratch_txt(value), size, align);
376 }
377 StackLayoutId::Ptr(value) => {
378 sys::ImGuiStack_BeginVertical_Ptr(value, size, align);
379 }
380 StackLayoutId::Int(value) => {
381 sys::ImGuiStack_BeginVertical_Int(value, size, align);
382 }
383 StackLayoutId::Raw(value) => {
384 sys::ImGuiStack_BeginVertical_Id(value.raw(), size, align);
385 }
386 }
387 }
388 VerticalStackLayoutToken::new(self)
389 }
390
391 #[doc(alias = "BeginVertical")]
396 pub fn begin_vertical<'ui, 'id>(
397 &'ui self,
398 id: impl Into<StackLayoutId<'id>>,
399 size: impl Into<[f32; 2]>,
400 align: f32,
401 ) -> VerticalStackLayoutToken<'ui> {
402 self.begin_vertical_stack_layout(id, size, align)
403 }
404
405 #[doc(alias = "BeginVertical", alias = "EndVertical")]
407 pub fn vertical_stack_layout<'id, R>(
408 &self,
409 id: impl Into<StackLayoutId<'id>>,
410 size: impl Into<[f32; 2]>,
411 align: f32,
412 f: impl FnOnce() -> R,
413 ) -> R {
414 let token = self.begin_vertical_stack_layout(id, size, align);
415 let result = f();
416 token.end();
417 result
418 }
419
420 #[doc(alias = "BeginVertical", alias = "EndVertical")]
424 pub fn vertical<'id, R>(
425 &self,
426 id: impl Into<StackLayoutId<'id>>,
427 size: impl Into<[f32; 2]>,
428 align: f32,
429 f: impl FnOnce() -> R,
430 ) -> R {
431 self.vertical_stack_layout(id, size, align, f)
432 }
433
434 #[doc(alias = "Spring")]
440 pub fn stack_layout_spring(&self, weight: f32, spacing: f32) {
441 assert!(
442 weight.is_finite(),
443 "Ui::stack_layout_spring() weight must be finite"
444 );
445 assert!(
446 spacing.is_finite(),
447 "Ui::stack_layout_spring() spacing must be finite"
448 );
449 unsafe { sys::ImGuiStack_Spring(weight, spacing) }
450 }
451
452 #[doc(alias = "Spring")]
457 pub fn spring(&self, weight: f32, spacing: f32) {
458 self.stack_layout_spring(weight, spacing)
459 }
460
461 #[doc(alias = "SuspendLayout")]
463 pub fn suspend_stack_layout(&self) -> StackLayoutSuspensionToken<'_> {
464 unsafe { sys::ImGuiStack_SuspendLayout() };
465 StackLayoutSuspensionToken::new(self)
466 }
467
468 #[doc(alias = "GetCursorPos")]
470 pub fn cursor_pos(&self) -> [f32; 2] {
471 let pos = unsafe { sys::igGetCursorPos() };
472 [pos.x, pos.y]
473 }
474
475 #[doc(alias = "GetCursorScreenPos")]
477 pub fn cursor_screen_pos(&self) -> [f32; 2] {
478 let pos = unsafe { sys::igGetCursorScreenPos() };
479 [pos.x, pos.y]
480 }
481
482 #[doc(alias = "SetCursorPos")]
484 pub fn set_cursor_pos(&self, pos: impl Into<[f32; 2]>) {
485 let pos_array = pos.into();
486 assert_finite_vec2("Ui::set_cursor_pos()", "position", pos_array);
487 let pos_vec = sys::ImVec2 {
488 x: pos_array[0],
489 y: pos_array[1],
490 };
491 unsafe { sys::igSetCursorPos(pos_vec) };
492 }
493
494 #[doc(alias = "SetCursorScreenPos")]
496 pub fn set_cursor_screen_pos(&self, pos: impl Into<[f32; 2]>) {
497 let pos_array = pos.into();
498 assert_finite_vec2("Ui::set_cursor_screen_pos()", "position", pos_array);
499 let pos_vec = sys::ImVec2 {
500 x: pos_array[0],
501 y: pos_array[1],
502 };
503 unsafe { sys::igSetCursorScreenPos(pos_vec) };
504 }
505
506 #[doc(alias = "GetCursorPosX")]
508 pub fn cursor_pos_x(&self) -> f32 {
509 unsafe { sys::igGetCursorPosX() }
510 }
511
512 #[doc(alias = "GetCursorPosY")]
514 pub fn cursor_pos_y(&self) -> f32 {
515 unsafe { sys::igGetCursorPosY() }
516 }
517
518 #[doc(alias = "SetCursorPosX")]
520 pub fn set_cursor_pos_x(&self, x: f32) {
521 assert_finite_f32("Ui::set_cursor_pos_x()", "x", x);
522 unsafe { sys::igSetCursorPosX(x) };
523 }
524
525 #[doc(alias = "SetCursorPosY")]
527 pub fn set_cursor_pos_y(&self, y: f32) {
528 assert_finite_f32("Ui::set_cursor_pos_y()", "y", y);
529 unsafe { sys::igSetCursorPosY(y) };
530 }
531
532 #[doc(alias = "GetCursorStartPos")]
534 pub fn cursor_start_pos(&self) -> [f32; 2] {
535 let pos = unsafe { sys::igGetCursorStartPos() };
536 [pos.x, pos.y]
537 }
538}
539
540impl Ui {
545 #[doc(alias = "GetTextLineHeight")]
547 pub fn text_line_height(&self) -> f32 {
548 unsafe { sys::igGetTextLineHeight() }
549 }
550
551 #[doc(alias = "GetTextLineHeightWithSpacing")]
553 pub fn text_line_height_with_spacing(&self) -> f32 {
554 unsafe { sys::igGetTextLineHeightWithSpacing() }
555 }
556
557 #[doc(alias = "GetFrameHeight")]
559 pub fn frame_height(&self) -> f32 {
560 unsafe { sys::igGetFrameHeight() }
561 }
562
563 #[doc(alias = "GetFrameHeightWithSpacing")]
565 pub fn frame_height_with_spacing(&self) -> f32 {
566 unsafe { sys::igGetFrameHeightWithSpacing() }
567 }
568
569 #[doc(alias = "PushClipRect")]
571 pub fn push_clip_rect(
572 &self,
573 min: impl Into<[f32; 2]>,
574 max: impl Into<[f32; 2]>,
575 intersect_with_current: bool,
576 ) {
577 let min = min.into();
578 let max = max.into();
579 assert_finite_vec2("Ui::push_clip_rect()", "min", min);
580 assert_finite_vec2("Ui::push_clip_rect()", "max", max);
581 let min_v = sys::ImVec2 {
582 x: min[0],
583 y: min[1],
584 };
585 let max_v = sys::ImVec2 {
586 x: max[0],
587 y: max[1],
588 };
589 unsafe { sys::igPushClipRect(min_v, max_v, intersect_with_current) }
590 }
591
592 #[doc(alias = "PopClipRect")]
594 pub fn pop_clip_rect(&self) {
595 unsafe { sys::igPopClipRect() }
596 }
597
598 pub fn with_clip_rect<R>(
600 &self,
601 min: impl Into<[f32; 2]>,
602 max: impl Into<[f32; 2]>,
603 intersect_with_current: bool,
604 f: impl FnOnce() -> R,
605 ) -> R {
606 self.push_clip_rect(min, max, intersect_with_current);
607 let _t = ClipRectToken::new(self);
608 f()
609 }
610
611 #[doc(alias = "IsRectVisible")]
613 pub fn is_rect_visible_min_max(
614 &self,
615 rect_min: impl Into<[f32; 2]>,
616 rect_max: impl Into<[f32; 2]>,
617 ) -> bool {
618 let mn = rect_min.into();
619 let mx = rect_max.into();
620 assert_finite_vec2("Ui::is_rect_visible_min_max()", "rect_min", mn);
621 assert_finite_vec2("Ui::is_rect_visible_min_max()", "rect_max", mx);
622 let mn_v = sys::ImVec2 { x: mn[0], y: mn[1] };
623 let mx_v = sys::ImVec2 { x: mx[0], y: mx[1] };
624 unsafe { sys::igIsRectVisible_Vec2(mn_v, mx_v) }
625 }
626
627 #[doc(alias = "IsRectVisible")]
629 pub fn is_rect_visible_with_size(&self, size: impl Into<[f32; 2]>) -> bool {
630 let s = size.into();
631 assert_finite_vec2("Ui::is_rect_visible_with_size()", "size", s);
632 let v = sys::ImVec2 { x: s[0], y: s[1] };
633 unsafe { sys::igIsRectVisible_Nil(v) }
634 }
635
636 #[doc(alias = "AlignTextToFramePadding")]
638 pub fn align_text_to_frame_padding(&self) {
639 unsafe { sys::igAlignTextToFramePadding() }
640 }
641}