fltk/
group.rs

1use crate::enums::{Align, Color, FrameType};
2use crate::prelude::*;
3use crate::utils::FlString;
4use crate::widget::Widget;
5use fltk_sys::group::*;
6use std::{
7    ffi::{CStr, CString},
8    mem,
9    ops::{Range, RangeInclusive},
10    sync::atomic::{AtomicBool, Ordering},
11};
12
13static DEBUG: AtomicBool = AtomicBool::new(false);
14
15/// Creates a group widget
16#[derive(Debug)]
17pub struct Group {
18    inner: crate::widget::WidgetTracker,
19    is_derived: bool,
20}
21
22crate::macros::widget::impl_widget_ext!(Group, Fl_Group);
23crate::macros::widget::impl_widget_base!(Group, Fl_Group);
24crate::macros::widget::impl_widget_default!(Group, Fl_Group);
25crate::macros::group::impl_group_ext!(Group, Fl_Group);
26
27impl Group {
28    /// Tries to get the current group
29    pub fn current() -> Option<Group> {
30        unsafe {
31            let ptr = Fl_Group_current();
32            if ptr.is_null() {
33                None
34            } else {
35                Some(Group::from_widget_ptr(ptr as _))
36            }
37        }
38    }
39
40    /// Sets the current `GroupExt` widget which will take children
41    pub fn set_current(grp: Option<&impl GroupExt>) {
42        unsafe {
43            if let Some(grp) = grp {
44                Fl_Group_set_current(grp.as_widget_ptr() as _);
45            } else {
46                Fl_Group_set_current(std::ptr::null_mut());
47            }
48        }
49    }
50}
51
52/// Creates a widget pack
53#[derive(Debug)]
54pub struct Pack {
55    inner: crate::widget::WidgetTracker,
56    is_derived: bool,
57}
58
59crate::macros::widget::impl_widget_ext!(Pack, Fl_Pack);
60crate::macros::widget::impl_widget_base!(Pack, Fl_Pack);
61crate::macros::widget::impl_widget_default!(Pack, Fl_Pack);
62crate::macros::group::impl_group_ext!(Pack, Fl_Pack);
63
64/// Defines pack types
65#[repr(i32)]
66#[derive(Debug, Copy, Clone, PartialEq, Eq)]
67pub enum PackType {
68    /// Vertical layout pack
69    Vertical = 0,
70    /// Horizontal layout pack
71    Horizontal = 1,
72}
73
74crate::macros::widget::impl_widget_type!(PackType);
75
76impl Pack {
77    /// Get the spacing of the pack
78    pub fn spacing(&self) -> i32 {
79        unsafe { Fl_Pack_spacing(self.inner.widget() as _) }
80    }
81
82    /// Set the spacing of the pack
83    pub fn set_spacing(&mut self, spacing: i32) {
84        unsafe {
85            Fl_Pack_set_spacing(self.inner.widget() as _, spacing);
86        }
87    }
88
89    /// Layout the children of the pack automatically.
90    /// Must be called on existing children
91    pub fn auto_layout(&mut self) {
92        let children = self.children();
93        if children == 0 {
94            return;
95        }
96        let spacing = self.spacing() * (children - 1);
97        let t = self.get_type::<PackType>();
98        let w = (self.w() - spacing) / children;
99        let h = (self.h() - spacing) / children;
100
101        for i in 0..children {
102            let mut c = self.child(i).unwrap();
103            let c_w = c.w();
104            let c_h = c.h();
105            if t == PackType::Vertical {
106                c.resize(c.x(), c.y(), c_w, h);
107            } else {
108                c.resize(c.x(), c.y(), w, c_h);
109            }
110        }
111    }
112}
113
114/// Creates a scroll group
115#[derive(Debug)]
116pub struct Scroll {
117    inner: crate::widget::WidgetTracker,
118    is_derived: bool,
119}
120
121crate::macros::widget::impl_widget_ext!(Scroll, Fl_Scroll);
122crate::macros::widget::impl_widget_base!(Scroll, Fl_Scroll);
123crate::macros::widget::impl_widget_default!(Scroll, Fl_Scroll);
124crate::macros::group::impl_group_ext!(Scroll, Fl_Scroll);
125
126/// Defines Scroll types
127#[repr(i32)]
128#[derive(Debug, Copy, Clone, PartialEq, Eq)]
129pub enum ScrollType {
130    /// Never show bars
131    None = 0,
132    /// Show vertical bar
133    Horizontal = 1,
134    /// Show vertical bar
135    Vertical = 2,
136    /// Show both horizontal and vertical bars
137    Both = 3,
138    /// Always show bars
139    AlwaysOn = 4,
140    /// Show horizontal bar always
141    HorizontalAlways = 5,
142    /// Show vertical bar always
143    VerticalAlways = 6,
144    /// Always show both horizontal and vertical bars
145    BothAlways = 7,
146}
147
148crate::macros::widget::impl_widget_type!(ScrollType);
149
150impl Scroll {
151    /// Returns the vertical scrollbar
152    pub fn scrollbar(&self) -> crate::valuator::Scrollbar {
153        unsafe {
154            let ptr = Fl_Scroll_scrollbar(self.inner.widget() as _);
155            assert!(!ptr.is_null());
156            crate::valuator::Scrollbar::from_widget_ptr(ptr as *mut fltk_sys::widget::Fl_Widget)
157        }
158    }
159
160    /// Returns the horizontal scrollbar
161    pub fn hscrollbar(&self) -> crate::valuator::Scrollbar {
162        unsafe {
163            let ptr = Fl_Scroll_hscrollbar(self.inner.widget() as _);
164            assert!(!ptr.is_null());
165            crate::valuator::Scrollbar::from_widget_ptr(ptr as *mut fltk_sys::widget::Fl_Widget)
166        }
167    }
168
169    /// Returns the x position
170    pub fn xposition(&self) -> i32 {
171        unsafe { Fl_Scroll_xposition(self.inner.widget() as _) }
172    }
173
174    /// Returns the y position
175    pub fn yposition(&self) -> i32 {
176        unsafe { Fl_Scroll_yposition(self.inner.widget() as _) }
177    }
178
179    /// Scrolls to `x` and `y`
180    pub fn scroll_to(&mut self, x: i32, y: i32) {
181        unsafe { Fl_Scroll_scroll_to(self.inner.widget() as _, x, y) }
182    }
183
184    /// Gets the scrollbar size
185    pub fn scrollbar_size(&self) -> i32 {
186        unsafe { Fl_Scroll_scrollbar_size(self.inner.widget() as _) }
187    }
188
189    /// Sets the scrollbar size
190    pub fn set_scrollbar_size(&mut self, new_size: i32) {
191        unsafe { Fl_Scroll_set_scrollbar_size(self.inner.widget() as _, new_size) }
192    }
193
194    /// Auto layout a scroll widget
195    pub fn auto_layout(&mut self) {
196        self.resize_callback(|t, x, y, w, h| {
197            if t.children() == 1 {
198                if let Some(mut c) = t.child(0) {
199                    c.resize(x, y, w, h);
200                }
201            }
202        });
203    }
204}
205
206/// Defines how Tabs handle overflow
207#[repr(i32)]
208#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
209pub enum TabsOverflow {
210    /// Compress tabs
211    Compress = 0,
212    /// Clip tabs
213    Clip,
214    /// Create a pulldown
215    Pulldown,
216    /// Drag tabs
217    Drag,
218}
219
220/// Creates a tab which can contain widgets
221#[derive(Debug)]
222pub struct Tabs {
223    inner: crate::widget::WidgetTracker,
224    is_derived: bool,
225}
226
227crate::macros::widget::impl_widget_ext!(Tabs, Fl_Tabs);
228crate::macros::widget::impl_widget_base!(Tabs, Fl_Tabs);
229crate::macros::widget::impl_widget_default!(Tabs, Fl_Tabs);
230crate::macros::group::impl_group_ext!(Tabs, Fl_Tabs);
231
232impl Tabs {
233    /// Gets the currently visible group
234    pub fn value(&self) -> Option<impl GroupExt> {
235        unsafe {
236            let ptr = Fl_Tabs_value(self.inner.widget() as _);
237            if ptr.is_null() {
238                None
239            } else {
240                Some(Group::from_widget_ptr(
241                    ptr as *mut fltk_sys::widget::Fl_Widget,
242                ))
243            }
244        }
245    }
246
247    /// Sets the currently visible group
248    /// # Errors
249    /// Errors when the value can't be set for the group widget
250    pub fn set_value<Grp: GroupExt>(&mut self, w: &Grp) -> Result<(), FltkError> {
251        unsafe {
252            match Fl_Tabs_set_value(
253                self.inner.widget() as _,
254                w.as_widget_ptr() as *mut fltk_sys::group::Fl_Widget,
255            ) {
256                0 => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
257                _ => Ok(()),
258            }
259        }
260    }
261
262    /// Returns the tab group for the tab the user has currently down-clicked
263    pub fn push(&self) -> Option<impl GroupExt> {
264        unsafe {
265            let ptr = Fl_Tabs_push(self.inner.widget() as _);
266            if ptr.is_null() {
267                None
268            } else {
269                Some(Group::from_widget_ptr(
270                    ptr as *mut fltk_sys::widget::Fl_Widget,
271                ))
272            }
273        }
274    }
275
276    /// This is called by the tab widget's `handle()` method to set the tab group widget the user last pushed
277    /// # Errors
278    /// Errors if `set_push` can't be set for the group widget
279    pub fn set_push<Grp: GroupExt>(&mut self, w: &Grp) -> Result<(), FltkError> {
280        unsafe {
281            match Fl_Tabs_set_push(
282                self.inner.widget() as _,
283                w.as_widget_ptr() as *mut fltk_sys::group::Fl_Widget,
284            ) {
285                0 => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
286                _ => Ok(()),
287            }
288        }
289    }
290
291    /// Returns the position and size available to be used by its children
292    pub fn client_area(&self) -> (i32, i32, i32, i32) {
293        unsafe {
294            fltk_sys::fl::Fl_open_display();
295            let mut i1 = 0;
296            let mut i2 = 0;
297            let mut i3 = 0;
298            let mut i4 = 0;
299            Fl_Tabs_client_area(self.inner.widget() as _, &mut i1, &mut i2, &mut i3, &mut i4);
300            (i1, i2, i3, i4)
301        }
302    }
303
304    /// Sets the tab label alignment
305    pub fn set_tab_align(&mut self, a: Align) {
306        unsafe { Fl_Tabs_set_tab_align(self.inner.widget() as _, a.bits()) }
307    }
308
309    /// Gets the tab label alignment.
310    pub fn tab_align(&self) -> Align {
311        unsafe { mem::transmute(Fl_Tabs_tab_align(self.inner.widget() as _)) }
312    }
313
314    /// Auto layout a tabs widget
315    pub fn auto_layout(&mut self) {
316        for c in self.clone() {
317            if let Some(mut c) = c.as_group() {
318                c.resize(self.x(), self.y() + 30, self.w(), self.h() - 30);
319            }
320        }
321        self.resize_callback(|t, x, y, w, h| {
322            for c in t.clone() {
323                if let Some(mut c) = c.as_group() {
324                    c.resize(x, y + 30, w, h - 30);
325                }
326            }
327        });
328    }
329
330    /// Sets how the Tabs handles overflow
331    pub fn handle_overflow(&mut self, ov: TabsOverflow) {
332        unsafe { Fl_Tabs_handle_overflow(self.inner.widget() as _, ov as i32) }
333    }
334}
335
336/// Creates a tile which can contain widgets. For the tiling to work correctly, the children of a Tile must cover the entire area of the widget, but not overlap. This means that all children must touch each other at their edges, and no gaps can be left inside the Tile.
337/// More info can be found [here](https://www.fltk.org/doc-1.4/classFl__Tile.html#details)
338#[derive(Debug)]
339pub struct Tile {
340    inner: crate::widget::WidgetTracker,
341    is_derived: bool,
342}
343
344crate::macros::widget::impl_widget_ext!(Tile, Fl_Tile);
345crate::macros::widget::impl_widget_base!(Tile, Fl_Tile);
346crate::macros::widget::impl_widget_default!(Tile, Fl_Tile);
347crate::macros::group::impl_group_ext!(Tile, Fl_Tile);
348
349impl Tile {
350    /**
351    Drags the intersection at (\p oldx,\p oldy) to (\p newx,\p newy).
352
353    This redraws all the necessary children.
354
355    If no size ranges are set, the new intersection position is limited to the
356    size of the tile group. The `resizable()` option is not taken into account here.
357
358    If size ranges are set, the actual new position of the intersection will
359    depend on the size range of every individual child. No child will be smaller
360    than their minw and minh. After the new position is found, `move_intersection()`
361    will call `init_sizes()`. The `resizable()` range is ignored.
362
363    params `oldx`, `oldy` move the intersection at this coordinate, pass zero to
364        disable drag in that direction.
365    params `newx`, `newy` move the intersection as close to this new coordinate
366        as possible
367    */
368    pub fn move_intersection(&mut self, oldx: i32, oldy: i32, newx: i32, newy: i32) {
369        unsafe {
370            Fl_Tile_move_intersection(self.inner.widget() as _, oldx, oldy, newx, newy);
371        }
372    }
373
374    /// Set the allowed size range for the child at the given index
375    pub fn size_range_by_index(&mut self, idx: i32, minw: i32, minh: i32, maxw: i32, maxh: i32) {
376        unsafe {
377            Fl_Tile_size_range_by_index(self.inner.widget() as _, idx, minw, minh, maxw, maxh);
378        }
379    }
380
381    /// Set the allowed size range for the given child widget
382    pub fn size_range_by_child<W: WidgetExt>(
383        &mut self,
384        w: &W,
385        minw: i32,
386        minh: i32,
387        maxw: i32,
388        maxh: i32,
389    ) {
390        unsafe {
391            Fl_Tile_size_range_by_child(
392                self.inner.widget() as _,
393                w.as_widget_ptr() as _,
394                minw,
395                minh,
396                maxw,
397                maxh,
398            );
399        }
400    }
401}
402
403/// Creates a wizard widget
404#[derive(Debug)]
405pub struct Wizard {
406    inner: crate::widget::WidgetTracker,
407    is_derived: bool,
408}
409
410crate::macros::widget::impl_widget_ext!(Wizard, Fl_Wizard);
411crate::macros::widget::impl_widget_base!(Wizard, Fl_Wizard);
412crate::macros::widget::impl_widget_default!(Wizard, Fl_Wizard);
413crate::macros::group::impl_group_ext!(Wizard, Fl_Wizard);
414
415impl Wizard {
416    /// Gets the next view of the wizard
417    pub fn next(&mut self) {
418        unsafe { Fl_Wizard_next(self.inner.widget() as _) }
419    }
420
421    /// Gets the previous view of the wizard
422    pub fn prev(&mut self) {
423        unsafe { Fl_Wizard_prev(self.inner.widget() as _) }
424    }
425
426    /// Gets the underlying widget of the current view
427    pub fn current_widget(&self) -> Option<impl WidgetExt> {
428        unsafe {
429            let ptr = Fl_Wizard_value(self.inner.widget() as _) as *mut fltk_sys::widget::Fl_Widget;
430            if ptr.is_null() {
431                None
432            } else {
433                Some(Widget::from_widget_ptr(ptr))
434            }
435        }
436    }
437
438    /// Sets the underlying widget of the current view
439    pub fn set_current_widget<W: WidgetExt>(&mut self, w: &W) {
440        unsafe {
441            Fl_Wizard_set_value(
442                self.inner.widget() as _,
443                w.as_widget_ptr() as *mut fltk_sys::group::Fl_Widget,
444            );
445        }
446    }
447
448    /// Set the index of the wizard
449    pub fn set_index(&mut self, idx: i32) -> Result<(), FltkError> {
450        if let Some(w) = self.child(idx) {
451            self.set_current_widget(&w);
452            Ok(())
453        } else {
454            Err(FltkError::Unknown("Index out of bounds".to_string()))
455        }
456    }
457
458    /// Get the index of the wizard
459    pub fn index(&self) -> Option<i32> {
460        Some(self.find(&self.current_widget()?))
461    }
462}
463
464/// Creates a color chooser widget
465#[derive(Debug)]
466pub struct ColorChooser {
467    inner: crate::widget::WidgetTracker,
468    is_derived: bool,
469}
470
471crate::macros::widget::impl_widget_ext!(ColorChooser, Fl_Color_Chooser);
472crate::macros::widget::impl_widget_base!(ColorChooser, Fl_Color_Chooser);
473crate::macros::widget::impl_widget_default!(ColorChooser, Fl_Color_Chooser);
474crate::macros::group::impl_group_ext!(ColorChooser, Fl_Color_Chooser);
475
476impl ColorChooser {
477    /// Return the rgb color
478    pub fn rgb_color(&self) -> (u8, u8, u8) {
479        unsafe {
480            let r = (Fl_Color_Chooser_r(self.inner.widget() as _) * 255.0) as u8;
481            let g = (Fl_Color_Chooser_g(self.inner.widget() as _) * 255.0) as u8;
482            let b = (Fl_Color_Chooser_b(self.inner.widget() as _) * 255.0) as u8;
483            (r, g, b)
484        }
485    }
486
487    /// Return the hex color
488    pub fn hex_color(&self) -> u32 {
489        let (r, g, b) = self.rgb_color();
490        crate::utils::rgb2hex(r, g, b)
491    }
492
493    /// Set the base color of the `ColorChooser`. Returns an error on failure to change the color (wrong input)
494    pub fn set_rgb(&mut self, r: u8, g: u8, b: u8) -> Result<(), FltkError> {
495        unsafe {
496            let ret = Fl_Color_Chooser_set_rgb(
497                self.inner.widget() as _,
498                f64::from(r) / 255.0,
499                f64::from(g) / 255.0,
500                f64::from(b) / 255.0,
501            );
502            if ret == 1 {
503                Ok(())
504            } else {
505                Err(FltkError::Internal(FltkErrorKind::FailedOperation))
506            }
507        }
508    }
509
510    /// Set the base color of the `ColorChooser`. Returns an error on failure to change the color (wrong input)
511    pub fn set_tuple_rgb(&mut self, (r, g, b): (u8, u8, u8)) -> Result<(), FltkError> {
512        unsafe {
513            let ret = Fl_Color_Chooser_set_rgb(
514                self.inner.widget() as _,
515                f64::from(r) / 255.0,
516                f64::from(g) / 255.0,
517                f64::from(b) / 255.0,
518            );
519            if ret == 1 {
520                Ok(())
521            } else {
522                Err(FltkError::Internal(FltkErrorKind::FailedOperation))
523            }
524        }
525    }
526}
527
528crate::macros::widget::impl_widget_type!(FlexType);
529
530/// Defines Flex types
531#[repr(i32)]
532#[derive(Debug, Copy, Clone, PartialEq, Eq)]
533pub enum FlexType {
534    /// row direction
535    Column = 0,
536    /// column direction
537    Row,
538}
539
540/**
541    a Flexbox widget
542    # Example
543    ```rust,no_run
544    use fltk::{prelude::*, *};
545    fn main() {
546        let a = app::App::default();
547        let mut win = window::Window::default().with_size(400, 300);
548        let mut col = group::Flex::default().size_of_parent();
549        col.set_type(group::FlexType::Column);
550        let expanding = button::Button::default().with_label("Expanding");
551        let mut normal = button::Button::default().with_label("Normal");
552        col.fixed(&mut normal, 30);
553        col.end();
554        win.end();
555        win.show();
556        a.run().unwrap();
557    }
558    ```
559*/
560#[derive(Debug)]
561pub struct Flex {
562    inner: crate::widget::WidgetTracker,
563    is_derived: bool,
564}
565
566crate::macros::widget::impl_widget_ext!(Flex, Fl_Flex);
567crate::macros::widget::impl_widget_base!(Flex, Fl_Flex);
568crate::macros::widget::impl_widget_default!(Flex, Fl_Flex);
569crate::macros::group::impl_group_ext!(Flex, Fl_Flex);
570
571impl Flex {
572    /// Add a widget to the Flex box
573    pub fn add<W: WidgetExt>(&mut self, widget: &W) {
574        <Self as GroupExt>::add(self, widget);
575        self.recalc();
576    }
577
578    /// Add a widget to the Flex box
579    pub fn insert<W: WidgetExt>(&mut self, widget: &W, idx: i32) {
580        <Self as GroupExt>::insert(self, widget, idx);
581        self.recalc();
582    }
583
584    /// Set the size of the widget, same as `set_size`, but more inline with the new FLTK `Fl_Flex` api
585    pub fn fixed<W: WidgetExt>(&mut self, w: &W, size: i32) {
586        unsafe { Fl_Flex_set_size(self.inner.widget() as _, w.as_widget_ptr() as _, size) }
587    }
588
589    /// Debug the flex layout
590    pub fn debug(flag: bool) {
591        DEBUG.store(flag, Ordering::Release);
592    }
593
594    fn debug_(&mut self) {
595        if DEBUG.load(Ordering::Relaxed) {
596            self.set_frame(FrameType::BorderBox);
597            if self.get_type::<FlexType>() == FlexType::Row {
598                self.set_color(Color::from_rgb(200, 0, 0));
599            } else {
600                self.set_color(Color::from_rgb(0, 0, 200));
601            }
602        }
603    }
604
605    /// Set the type to be a column
606    #[must_use]
607    pub fn column(mut self) -> Self {
608        self.set_type(FlexType::Column);
609        self.debug_();
610        self
611    }
612
613    /// Set the type to a row
614    #[must_use]
615    pub fn row(mut self) -> Self {
616        self.set_type(FlexType::Row);
617        self.debug_();
618        self
619    }
620
621    /// Recalculate children's coords and sizes
622    pub fn recalc(&self) {
623        let mut s = self.clone();
624        s.resize(self.x(), self.y(), self.w(), self.h());
625        s.redraw();
626    }
627
628    /// Recalculate children's coords and sizes
629    pub fn layout(&self) {
630        self.recalc();
631    }
632
633    /// Set the margin
634    pub fn set_margin(&mut self, m: i32) {
635        unsafe { Fl_Flex_set_margin(self.inner.widget() as _, m) }
636    }
637
638    /// Get the margin
639    pub fn margin(&self) -> i32 {
640        unsafe { Fl_Flex_margin(self.inner.widget() as _) }
641    }
642
643    /// Set the padding
644    pub fn set_pad(&mut self, p: i32) {
645        unsafe { Fl_Flex_set_pad(self.inner.widget() as _, p) }
646    }
647
648    /// Get the padding
649    pub fn pad(&self) -> i32 {
650        unsafe { Fl_Flex_pad(self.inner.widget() as _) }
651    }
652
653    /// Set the padding
654    pub fn set_spacing(&mut self, p: i32) {
655        unsafe { Fl_Flex_set_pad(self.inner.widget() as _, p) }
656    }
657
658    /// Get the padding
659    pub fn spacing(&self) -> i32 {
660        unsafe { Fl_Flex_pad(self.inner.widget() as _) }
661    }
662
663    /// Set the margins
664    pub fn set_margins(&mut self, left: i32, top: i32, right: i32, bottom: i32) {
665        unsafe { Fl_Flex_set_margins(self.inner.widget() as _, left, top, right, bottom) }
666    }
667
668    /// Get the margins -> returns (left, top, right, bottom)
669    pub fn margins(&self) -> (i32, i32, i32, i32) {
670        let mut left = 0;
671        let mut top = 0;
672        let mut right = 0;
673        let mut bottom = 0;
674        unsafe {
675            Fl_Flex_margins(
676                self.inner.widget() as _,
677                &mut left,
678                &mut top,
679                &mut right,
680                &mut bottom,
681            );
682        }
683        (left, top, right, bottom)
684    }
685}
686
687/// Grid range
688pub struct GridRange {
689    start: usize,
690    end: usize,
691}
692
693impl GridRange {
694    /// Check the length of the `GridRange`
695    pub fn len(&self) -> usize {
696        self.end - self.start
697    }
698
699    /// Check whether the `GridRange` is empty
700    pub fn is_empty(&self) -> bool {
701        self.len() == 0
702    }
703}
704
705impl From<Range<usize>> for GridRange {
706    fn from(val: Range<usize>) -> Self {
707        Self {
708            start: val.start,
709            end: val.end,
710        }
711    }
712}
713
714impl From<RangeInclusive<usize>> for GridRange {
715    fn from(val: RangeInclusive<usize>) -> Self {
716        Self {
717            start: *val.start(),
718            end: *val.end(),
719        }
720    }
721}
722
723impl From<usize> for GridRange {
724    fn from(val: usize) -> Self {
725        (val..=val).into()
726    }
727}
728
729bitflags::bitflags! {
730    /// Defines alignment rules used by FLTK's Grid
731    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
732    pub struct GridAlign: u16 {
733        /** Align the widget at the center of the cell. */
734        const  CENTER          = 0x0000;
735        /** Align the widget at the top of the cell. */
736        const  TOP             = 0x0001;
737        /** Align the widget at the bottom of the cell. */
738        const  BOTTOM          = 0x0002;
739        /** Align the widget at the left side of the cell. */
740        const  LEFT            = 0x0004;
741        /** Align the widget at the right side of the cell. */
742        const  RIGHT           = 0x0008;
743        /** Stretch the widget horizontally to fill the cell. */
744        const  HORIZONTAL      = 0x0010;
745        /** Stretch the widget vertically to fill the cell. */
746        const  VERTICAL        = 0x0020;
747        /** Stretch the widget in both directions to fill the cell. */
748        const  FILL            = 0x0030;
749        /** Stretch the widget proportionally. */
750        const  PROPORTIONAL    = 0x0040;
751        /** Align the widget at the top left of the cell. */
752        const  TOP_LEFT        =  GridAlign::TOP.bits() |  GridAlign::LEFT.bits();
753        /** Align the widget at the top right of the cell. */
754        const  TOP_RIGHT       =  GridAlign::TOP.bits() |  GridAlign::RIGHT.bits();
755        /** Align the widget at the bottom left of the cell. */
756        const  BOTTOM_LEFT     =  GridAlign::BOTTOM.bits() |  GridAlign::LEFT.bits();
757        /** Align the widget at the bottom right of the cell. */
758        const  BOTTOM_RIGHT    =  GridAlign::BOTTOM.bits() |  GridAlign::RIGHT.bits();
759    }
760}
761/// Fltk's grid widget
762#[derive(Debug)]
763pub struct Grid {
764    inner: crate::widget::WidgetTracker,
765    is_derived: bool,
766}
767
768crate::macros::widget::impl_widget_ext!(Grid, Fl_Grid);
769crate::macros::widget::impl_widget_base!(Grid, Fl_Grid);
770crate::macros::widget::impl_widget_default!(Grid, Fl_Grid);
771crate::macros::group::impl_group_ext!(Grid, Fl_Grid);
772
773impl Grid {
774    /// Set the layout of the grid, along with the margin and gap
775    pub fn set_layout_ext(&mut self, rows: i32, cols: i32, margin: i32, gap: i32) {
776        unsafe { Fl_Grid_set_layout(self.inner.widget() as _, rows, cols, margin, gap) }
777    }
778    /// Set the layout of the grid
779    pub fn set_layout(&mut self, rows: i32, cols: i32) {
780        unsafe { Fl_Grid_set_layout(self.inner.widget() as _, rows, cols, -1, -1) }
781    }
782    /// Layout the grid
783    pub fn layout(&mut self) {
784        unsafe { Fl_Grid_layout(self.inner.widget() as _) }
785    }
786    /// Clear the layout
787    pub fn clear_layout(&mut self) {
788        unsafe { Fl_Grid_clear_layout(self.inner.widget() as _) }
789    }
790    /// Set whether the Grid needs layout
791    pub fn set_need_layout(&mut self, set: bool) {
792        unsafe { Fl_Grid_set_need_layout(self.inner.widget() as _, set.into()) }
793    }
794    /// Get whether the Grid needs layout
795    pub fn need_layout(&self) -> bool {
796        unsafe { Fl_Grid_need_layout(self.inner.widget() as _) != 0 }
797    }
798    /// Set the grid's margins
799    pub fn set_margins(&mut self, left: i32, top: i32, right: i32, bottom: i32) {
800        unsafe { Fl_Grid_set_margin(self.inner.widget() as _, left, top, right, bottom) }
801    }
802    /// Set the grid's gap
803    pub fn set_gap(&mut self, row_gap: i32, col_gap: i32) {
804        unsafe { Fl_Grid_set_gap(self.inner.widget() as _, row_gap, col_gap) }
805    }
806    #[allow(dead_code)]
807    /// Set the widget at row/column and alignment
808    pub fn set_widget_<W: WidgetExt>(
809        &mut self,
810        wi: &mut W,
811        row: i32,
812        col: i32,
813        align: GridAlign,
814    ) -> *mut () {
815        unsafe {
816            Fl_Grid_set_widget(
817                self.inner.widget() as _,
818                wi.as_widget_ptr() as _,
819                row,
820                col,
821                align.bits(),
822            ) as _
823        }
824    }
825    /// Set the widget at row/column using ranges
826    pub fn set_widget<W: 'static + Clone + WidgetExt>(
827        &mut self,
828        widget: &mut W,
829        row: impl Into<GridRange>,
830        col: impl Into<GridRange>,
831    ) -> Result<(), FltkError> {
832        let row = row.into();
833        let col = col.into();
834        self.set_widget_ext(widget, row, col, GridAlign::FILL)
835    }
836    /// Set the widget at row/column along with row span and column span and alignment
837    fn set_widget_ext_<W: WidgetExt>(
838        &mut self,
839        wi: &mut W,
840        row: i32,
841        col: i32,
842        rowspan: i32,
843        colspan: i32,
844        align: GridAlign,
845    ) -> *mut () {
846        unsafe {
847            Fl_Grid_set_widget_ext(
848                self.inner.widget() as _,
849                wi.as_widget_ptr() as _,
850                row,
851                col,
852                rowspan,
853                colspan,
854                align.bits(),
855            ) as _
856        }
857    }
858    /// Set the widget at row/column using ranges along with the alignment
859    pub fn set_widget_ext<W: 'static + Clone + WidgetExt>(
860        &mut self,
861        widget: &mut W,
862        row: impl Into<GridRange>,
863        col: impl Into<GridRange>,
864        align: GridAlign,
865    ) -> Result<(), FltkError> {
866        let row = row.into();
867        let col = col.into();
868        let e = self.set_widget_ext_(
869            widget,
870            row.start as _,
871            col.start as _,
872            row.len() as _,
873            col.len() as _,
874            align,
875        );
876        if e.is_null() {
877            Err(FltkError::Internal(FltkErrorKind::FailedGridSetWidget))
878        } else {
879            Ok(())
880        }
881    }
882    /// Set the column width
883    pub fn set_col_width(&mut self, col: i32, value: i32) {
884        unsafe { Fl_Grid_set_col_width(self.inner.widget() as _, col, value) }
885    }
886    /// Set the column weight
887    pub fn set_col_weight(&mut self, col: i32, value: i32) {
888        unsafe { Fl_Grid_set_col_weight(self.inner.widget() as _, col, value) }
889    }
890    /// Set the column gap
891    pub fn set_col_gap(&mut self, col: i32, value: i32) {
892        unsafe { Fl_Grid_set_col_gap(self.inner.widget() as _, col, value) }
893    }
894    /// Set the row height
895    pub fn set_row_height(&mut self, row: i32, value: i32) {
896        unsafe { Fl_Grid_set_row_height(self.inner.widget() as _, row, value) }
897    }
898    /// Set the row weight
899    pub fn set_row_weight(&mut self, row: i32, value: i32) {
900        unsafe { Fl_Grid_set_row_weight(self.inner.widget() as _, row, value) }
901    }
902    /// Set the row gap
903    pub fn set_row_gap(&mut self, row: i32, value: i32) {
904        unsafe { Fl_Grid_set_row_gap(self.inner.widget() as _, row, value) }
905    }
906    /// Show the grid
907    pub fn show_grid(&mut self, set: bool) {
908        unsafe { Fl_Grid_show_grid(self.inner.widget() as _, set.into()) }
909    }
910    /// Show the grid with a certain color
911    pub fn show_grid_with_color(&mut self, set: bool, col: Color) {
912        unsafe { Fl_Grid_show_grid_with_color(self.inner.widget() as _, set.into(), col.bits()) }
913    }
914    /// Debug the grid
915    pub fn debug(&mut self, level: i32) {
916        unsafe { Fl_Grid_debug(self.inner.widget() as _, level) }
917    }
918}
919
920#[allow(missing_docs)]
921pub mod experimental {
922    #[allow(unused_imports)]
923    use super::*;
924}