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,
10 sync::atomic::{AtomicBool, Ordering},
11};
12
13static DEBUG: AtomicBool = AtomicBool::new(false);
14
15#[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);
25crate::macros::group::impl_group_ext!(Group, Fl_Group);
26
27impl Group {
28 #[deprecated(since = "1.2.18", note = "please use `try_current` instead")]
29 pub fn current() -> Group {
31 unsafe {
32 let ptr = Fl_Group_current();
33 assert!(!ptr.is_null());
34 Group::from_widget_ptr(ptr as _)
35 }
36 }
37
38 pub fn try_current() -> Option<Group> {
40 unsafe {
41 let ptr = Fl_Group_current();
42 if ptr.is_null() {
43 None
44 } else {
45 Some(Group::from_widget_ptr(ptr as _))
46 }
47 }
48 }
49
50 pub fn set_current(grp: Option<&impl GroupExt>) {
52 unsafe {
53 if let Some(grp) = grp {
54 Fl_Group_set_current(grp.as_widget_ptr() as _)
55 } else {
56 Fl_Group_set_current(std::ptr::null_mut())
57 }
58 }
59 }
60}
61
62#[derive(Debug)]
64pub struct OverlayGroup {
65 inner: crate::widget::WidgetTracker,
66 is_derived: bool,
67}
68
69crate::macros::widget::impl_widget_ext!(OverlayGroup, Fl_Overlay_Group);
70crate::macros::widget::impl_widget_base!(OverlayGroup, Fl_Overlay_Group);
71crate::macros::widget::impl_widget_default!(OverlayGroup);
72crate::macros::group::impl_group_ext!(OverlayGroup, Fl_Overlay_Group);
73
74#[derive(Debug)]
76pub struct Pack {
77 inner: crate::widget::WidgetTracker,
78 is_derived: bool,
79}
80
81crate::macros::widget::impl_widget_ext!(Pack, Fl_Pack);
82crate::macros::widget::impl_widget_base!(Pack, Fl_Pack);
83crate::macros::widget::impl_widget_default!(Pack);
84crate::macros::group::impl_group_ext!(Pack, Fl_Pack);
85
86#[repr(i32)]
88#[derive(Debug, Copy, Clone, PartialEq, Eq)]
89pub enum PackType {
90 Vertical = 0,
92 Horizontal = 1,
94}
95
96crate::macros::widget::impl_widget_type!(PackType);
97
98impl Pack {
99 pub fn spacing(&self) -> i32 {
101 unsafe { Fl_Pack_spacing(self.inner.widget() as _) }
102 }
103
104 pub fn set_spacing(&mut self, spacing: i32) {
106 unsafe {
107 Fl_Pack_set_spacing(self.inner.widget() as _, spacing);
108 }
109 }
110
111 pub fn auto_layout(&mut self) {
114 let children = self.children();
115 if children == 0 {
116 return;
117 }
118 let spacing = self.spacing() * (children - 1);
119 let t = self.get_type::<PackType>();
120 let w = (self.width() - spacing) / children;
121 let h = (self.height() - spacing) / children;
122
123 for i in 0..children {
124 let mut c = self.child(i).unwrap();
125 let c_w = c.width();
126 let c_h = c.height();
127 if t == PackType::Vertical {
128 c.set_size(c_w, h);
129 } else {
130 c.set_size(w, c_h);
131 }
132 }
133 }
134}
135
136#[derive(Debug)]
138pub struct Scroll {
139 inner: crate::widget::WidgetTracker,
140 is_derived: bool,
141}
142
143crate::macros::widget::impl_widget_ext!(Scroll, Fl_Scroll);
144crate::macros::widget::impl_widget_base!(Scroll, Fl_Scroll);
145crate::macros::widget::impl_widget_default!(Scroll);
146crate::macros::group::impl_group_ext!(Scroll, Fl_Scroll);
147
148#[repr(i32)]
150#[derive(Debug, Copy, Clone, PartialEq, Eq)]
151pub enum ScrollType {
152 None = 0,
154 Horizontal = 1,
156 Vertical = 2,
158 Both = 3,
160 AlwaysOn = 4,
162 HorizontalAlways = 5,
164 VerticalAlways = 6,
166 BothAlways = 7,
168}
169
170crate::macros::widget::impl_widget_type!(ScrollType);
171
172impl Scroll {
173 pub fn scrollbar(&self) -> crate::valuator::Scrollbar {
175 unsafe {
176 let ptr = Fl_Scroll_scrollbar(self.inner.widget() as _);
177 assert!(!ptr.is_null());
178 crate::valuator::Scrollbar::from_widget_ptr(ptr as *mut fltk_sys::widget::Fl_Widget)
179 }
180 }
181
182 pub fn hscrollbar(&self) -> crate::valuator::Scrollbar {
184 unsafe {
185 let ptr = Fl_Scroll_hscrollbar(self.inner.widget() as _);
186 assert!(!ptr.is_null());
187 crate::valuator::Scrollbar::from_widget_ptr(ptr as *mut fltk_sys::widget::Fl_Widget)
188 }
189 }
190
191 pub fn xposition(&self) -> i32 {
193 unsafe { Fl_Scroll_xposition(self.inner.widget() as _) }
194 }
195
196 pub fn yposition(&self) -> i32 {
198 unsafe { Fl_Scroll_yposition(self.inner.widget() as _) }
199 }
200
201 pub fn scroll_to(&mut self, x: i32, y: i32) {
203 unsafe { Fl_Scroll_scroll_to(self.inner.widget() as _, x, y) }
204 }
205
206 pub fn scrollbar_size(&self) -> i32 {
208 unsafe { Fl_Scroll_scrollbar_size(self.inner.widget() as _) }
209 }
210
211 pub fn set_scrollbar_size(&mut self, new_size: i32) {
213 unsafe { Fl_Scroll_set_scrollbar_size(self.inner.widget() as _, new_size) }
214 }
215
216 pub fn auto_layout(&mut self) {
218 self.resize_callback(|t, x, y, w, h| {
219 if t.children() == 1 {
220 if let Some(mut c) = t.child(0) {
221 c.resize(x, y, w, h);
222 }
223 }
224 });
225 }
226}
227
228#[repr(i32)]
230#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
231pub enum TabsOverflow {
232 Compress = 0,
234 Clip,
236 Pulldown,
238 Drag,
240}
241
242#[derive(Debug)]
244pub struct Tabs {
245 inner: crate::widget::WidgetTracker,
246 is_derived: bool,
247}
248
249crate::macros::widget::impl_widget_ext!(Tabs, Fl_Tabs);
250crate::macros::widget::impl_widget_base!(Tabs, Fl_Tabs);
251crate::macros::widget::impl_widget_default!(Tabs);
252crate::macros::group::impl_group_ext!(Tabs, Fl_Tabs);
253
254impl Tabs {
255 pub fn value(&self) -> Option<impl GroupExt> {
257 unsafe {
258 let ptr = Fl_Tabs_value(self.inner.widget() as _);
259 if ptr.is_null() {
260 None
261 } else {
262 Some(Group::from_widget_ptr(
263 ptr as *mut fltk_sys::widget::Fl_Widget,
264 ))
265 }
266 }
267 }
268
269 pub fn set_value<Grp: GroupExt>(&mut self, w: &Grp) -> Result<(), FltkError> {
273 unsafe {
274 match Fl_Tabs_set_value(
275 self.inner.widget() as _,
276 w.as_widget_ptr() as *mut fltk_sys::group::Fl_Widget,
277 ) {
278 0 => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
279 _ => Ok(()),
280 }
281 }
282 }
283
284 pub fn push(&self) -> Option<impl GroupExt> {
286 unsafe {
287 let ptr = Fl_Tabs_push(self.inner.widget() as _);
288 if ptr.is_null() {
289 None
290 } else {
291 Some(Group::from_widget_ptr(
292 ptr as *mut fltk_sys::widget::Fl_Widget,
293 ))
294 }
295 }
296 }
297
298 pub fn set_push<Grp: GroupExt>(&mut self, w: &Grp) -> Result<(), FltkError> {
302 unsafe {
303 match Fl_Tabs_set_push(
304 self.inner.widget() as _,
305 w.as_widget_ptr() as *mut fltk_sys::group::Fl_Widget,
306 ) {
307 0 => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
308 _ => Ok(()),
309 }
310 }
311 }
312
313 pub fn client_area(&self) -> (i32, i32, i32, i32) {
315 unsafe {
316 fltk_sys::fl::Fl_open_display();
317 let mut i1 = 0;
318 let mut i2 = 0;
319 let mut i3 = 0;
320 let mut i4 = 0;
321 Fl_Tabs_client_area(self.inner.widget() as _, &mut i1, &mut i2, &mut i3, &mut i4);
322 (i1, i2, i3, i4)
323 }
324 }
325
326 pub fn set_tab_align(&mut self, a: Align) {
328 unsafe { Fl_Tabs_set_tab_align(self.inner.widget() as _, a.bits()) }
329 }
330
331 pub fn tab_align(&self) -> Align {
333 unsafe { mem::transmute(Fl_Tabs_tab_align(self.inner.widget() as _)) }
334 }
335
336 pub fn auto_layout(&mut self) {
338 for c in self.clone().into_iter() {
339 if let Some(mut c) = c.as_group() {
340 c.resize(self.x(), self.y() + 30, self.w(), self.h() - 30);
341 }
342 }
343 self.resize_callback(|t, x, y, w, h| {
344 for c in t.clone().into_iter() {
345 if let Some(mut c) = c.as_group() {
346 c.resize(x, y + 30, w, h - 30);
347 }
348 }
349 });
350 }
351
352 pub fn handle_overflow(&mut self, ov: TabsOverflow) {
354 unsafe { Fl_Tabs_handle_overflow(self.inner.widget() as _, ov as i32) }
355 }
356}
357
358#[derive(Debug)]
361pub struct Tile {
362 inner: crate::widget::WidgetTracker,
363 is_derived: bool,
364}
365
366crate::macros::widget::impl_widget_ext!(Tile, Fl_Tile);
367crate::macros::widget::impl_widget_base!(Tile, Fl_Tile);
368crate::macros::widget::impl_widget_default!(Tile);
369crate::macros::group::impl_group_ext!(Tile, Fl_Tile);
370
371impl Tile {
372 pub fn move_intersection(&mut self, oldx: i32, oldy: i32, newx: i32, newy: i32) {
391 unsafe {
392 Fl_Tile_move_intersection(self.inner.widget() as _, oldx, oldy, newx, newy);
393 }
394 }
395
396 pub fn size_range_by_index(&mut self, idx: i32, minw: i32, minh: i32, maxw: i32, maxh: i32) {
398 unsafe {
399 Fl_Tile_size_range_by_index(self.inner.widget() as _, idx, minw, minh, maxw, maxh)
400 }
401 }
402
403 pub fn size_range_by_child<W: WidgetExt>(
405 &mut self,
406 w: &W,
407 minw: i32,
408 minh: i32,
409 maxw: i32,
410 maxh: i32,
411 ) {
412 unsafe {
413 Fl_Tile_size_range_by_child(
414 self.inner.widget() as _,
415 w.as_widget_ptr() as _,
416 minw,
417 minh,
418 maxw,
419 maxh,
420 )
421 }
422 }
423}
424
425#[derive(Debug)]
427pub struct Wizard {
428 inner: crate::widget::WidgetTracker,
429 is_derived: bool,
430}
431
432crate::macros::widget::impl_widget_ext!(Wizard, Fl_Wizard);
433crate::macros::widget::impl_widget_base!(Wizard, Fl_Wizard);
434crate::macros::widget::impl_widget_default!(Wizard);
435crate::macros::group::impl_group_ext!(Wizard, Fl_Wizard);
436
437impl Wizard {
438 pub fn next(&mut self) {
440 unsafe { Fl_Wizard_next(self.inner.widget() as _) }
441 }
442
443 pub fn prev(&mut self) {
445 unsafe { Fl_Wizard_prev(self.inner.widget() as _) }
446 }
447
448 #[deprecated(since = "1.2.18", note = "please use `try_current_widget` instead")]
449 pub fn current_widget(&self) -> Widget {
451 unsafe {
452 let ptr = Fl_Wizard_value(self.inner.widget() as _) as *mut fltk_sys::widget::Fl_Widget;
453 assert!(!ptr.is_null());
454 Widget::from_widget_ptr(ptr)
455 }
456 }
457
458 pub fn try_current_widget(&self) -> Option<impl WidgetExt> {
460 unsafe {
461 let ptr = Fl_Wizard_value(self.inner.widget() as _) as *mut fltk_sys::widget::Fl_Widget;
462 if ptr.is_null() {
463 None
464 } else {
465 Some(Widget::from_widget_ptr(ptr))
466 }
467 }
468 }
469
470 pub fn set_current_widget<W: WidgetExt>(&mut self, w: &W) {
472 unsafe {
473 Fl_Wizard_set_value(
474 self.inner.widget() as _,
475 w.as_widget_ptr() as *mut fltk_sys::group::Fl_Widget,
476 )
477 }
478 }
479
480 pub fn set_index(&mut self, idx: i32) -> Result<(), FltkError> {
482 if let Some(w) = self.child(idx) {
483 self.set_current_widget(&w);
484 Ok(())
485 } else {
486 Err(FltkError::Unknown("Index out of bounds".to_string()))
487 }
488 }
489
490 pub fn index(&self) -> Option<i32> {
492 Some(self.find(&self.try_current_widget()?))
493 }
494}
495
496#[derive(Debug)]
498pub struct ColorChooser {
499 inner: crate::widget::WidgetTracker,
500 is_derived: bool,
501}
502
503crate::macros::widget::impl_widget_ext!(ColorChooser, Fl_Color_Chooser);
504crate::macros::widget::impl_widget_base!(ColorChooser, Fl_Color_Chooser);
505crate::macros::widget::impl_widget_default!(ColorChooser);
506crate::macros::group::impl_group_ext!(ColorChooser, Fl_Color_Chooser);
507
508impl ColorChooser {
509 pub fn rgb_color(&self) -> (u8, u8, u8) {
511 unsafe {
512 let r = (Fl_Color_Chooser_r(self.inner.widget() as _) * 255.0) as u8;
513 let g = (Fl_Color_Chooser_g(self.inner.widget() as _) * 255.0) as u8;
514 let b = (Fl_Color_Chooser_b(self.inner.widget() as _) * 255.0) as u8;
515 (r, g, b)
516 }
517 }
518
519 pub fn hex_color(&self) -> u32 {
521 let (r, g, b) = self.rgb_color();
522 crate::utils::rgb2hex(r, g, b)
523 }
524
525 pub fn set_rgb(&mut self, r: u8, g: u8, b: u8) -> Result<(), FltkError> {
527 unsafe {
528 let ret = Fl_Color_Chooser_set_rgb(
529 self.inner.widget() as _,
530 r as f64 / 255.0,
531 g as f64 / 255.0,
532 b as f64 / 255.0,
533 );
534 if ret == 1 {
535 Ok(())
536 } else {
537 Err(FltkError::Internal(FltkErrorKind::FailedOperation))
538 }
539 }
540 }
541
542 pub fn set_tuple_rgb(&mut self, (r, g, b): (u8, u8, u8)) -> Result<(), FltkError> {
544 unsafe {
545 let ret = Fl_Color_Chooser_set_rgb(
546 self.inner.widget() as _,
547 r as f64 / 255.0,
548 g as f64 / 255.0,
549 b as f64 / 255.0,
550 );
551 if ret == 1 {
552 Ok(())
553 } else {
554 Err(FltkError::Internal(FltkErrorKind::FailedOperation))
555 }
556 }
557 }
558}
559
560crate::macros::widget::impl_widget_type!(FlexType);
561
562#[repr(i32)]
564#[derive(Debug, Copy, Clone, PartialEq, Eq)]
565pub enum FlexType {
566 Column = 0,
568 Row,
570}
571
572#[derive(Debug)]
593pub struct Flex {
594 inner: crate::widget::WidgetTracker,
595 is_derived: bool,
596}
597
598crate::macros::widget::impl_widget_ext!(Flex, Fl_Flex);
599crate::macros::widget::impl_widget_base!(Flex, Fl_Flex);
600crate::macros::widget::impl_widget_default!(Flex);
601crate::macros::group::impl_group_ext!(Flex, Fl_Flex);
602
603impl Flex {
604 fn new<T: Into<Option<&'static str>>>(
608 x: i32,
609 y: i32,
610 width: i32,
611 height: i32,
612 title: T,
613 ) -> Self {
614 let mut f = <Flex as WidgetBase>::new(x, y, width, height, title).row();
615 f.set_pad(5);
616 f.debug_();
617 f
618 }
619 pub fn add<W: WidgetExt>(&mut self, widget: &W) {
621 <Self as GroupExt>::add(self, widget);
622 self.recalc();
623 }
624
625 pub fn insert<W: WidgetExt>(&mut self, widget: &W, idx: i32) {
627 <Self as GroupExt>::insert(self, widget, idx);
628 self.recalc();
629 }
630
631 #[deprecated(since = "1.4.8", note = "please use `fixed` instead")]
633 pub fn set_size<W: WidgetExt>(&mut self, w: &W, size: i32) {
634 unsafe { Fl_Flex_set_size(self.inner.widget() as _, w.as_widget_ptr() as _, size) }
635 }
636
637 pub fn fixed<W: WidgetExt>(&mut self, w: &W, size: i32) {
639 unsafe { Fl_Flex_set_size(self.inner.widget() as _, w.as_widget_ptr() as _, size) }
640 }
641
642 pub fn debug(flag: bool) {
644 DEBUG.store(flag, Ordering::Release);
645 }
646
647 fn debug_(&mut self) {
648 if DEBUG.load(Ordering::Relaxed) {
649 self.set_frame(FrameType::BorderBox);
650 if self.get_type::<FlexType>() == FlexType::Row {
651 self.set_color(Color::from_rgb(200, 0, 0));
652 } else {
653 self.set_color(Color::from_rgb(0, 0, 200));
654 }
655 }
656 }
657
658 pub fn column(mut self) -> Self {
660 self.set_type(FlexType::Column);
661 self.debug_();
662 self
663 }
664
665 pub fn row(mut self) -> Self {
667 self.set_type(FlexType::Row);
668 self.debug_();
669 self
670 }
671
672 pub fn recalc(&self) {
674 let mut s = self.clone();
675 s.resize(self.x(), self.y(), self.w(), self.h());
676 s.redraw();
677 }
678
679 pub fn layout(&self) {
681 self.recalc();
682 }
683
684 pub fn set_margin(&mut self, m: i32) {
686 unsafe { Fl_Flex_set_margin(self.inner.widget() as _, m) }
687 }
688
689 pub fn margin(&self) -> i32 {
691 unsafe { Fl_Flex_margin(self.inner.widget() as _) }
692 }
693
694 pub fn set_pad(&mut self, p: i32) {
696 unsafe { Fl_Flex_set_pad(self.inner.widget() as _, p) }
697 }
698
699 pub fn pad(&self) -> i32 {
701 unsafe { Fl_Flex_pad(self.inner.widget() as _) }
702 }
703
704 pub fn set_spacing(&mut self, p: i32) {
706 unsafe { Fl_Flex_set_pad(self.inner.widget() as _, p) }
707 }
708
709 pub fn spacing(&self) -> i32 {
711 unsafe { Fl_Flex_pad(self.inner.widget() as _) }
712 }
713
714 pub fn set_margins(&mut self, left: i32, top: i32, right: i32, bottom: i32) {
716 unsafe { Fl_Flex_set_margins(self.inner.widget() as _, left, top, right, bottom) }
717 }
718
719 pub fn margins(&self) -> (i32, i32, i32, i32) {
721 let mut left = 0;
722 let mut top = 0;
723 let mut right = 0;
724 let mut bottom = 0;
725 unsafe {
726 Fl_Flex_margins(
727 self.inner.widget() as _,
728 &mut left,
729 &mut top,
730 &mut right,
731 &mut bottom,
732 );
733 }
734 (left, top, right, bottom)
735 }
736}
737
738#[derive(Debug, Clone)]
764pub struct VGrid {
765 vpack: Pack,
766 rows: i32,
767 cols: i32,
768 current: i32,
769}
770
771impl Default for VGrid {
772 fn default() -> Self {
773 Self::new(0, 0, 0, 0, None)
774 }
775}
776
777impl VGrid {
778 pub fn default_fill() -> Self {
780 Self::default().size_of_parent()
781 }
782
783 pub fn new<T: Into<Option<&'static str>>>(x: i32, y: i32, w: i32, h: i32, label: T) -> VGrid {
785 let vpack = Pack::new(x, y, w, h, label);
786 VGrid {
787 vpack,
788 rows: 1,
789 cols: 1,
790 current: 0,
791 }
792 }
793
794 pub fn set_params(&mut self, rows: i32, cols: i32, spacing: i32) {
796 self.vpack.set_spacing(spacing);
797 let rows = if rows < 1 { 1 } else { rows };
798 let cols = if cols < 1 { 1 } else { cols };
799 self.rows = rows;
800 self.cols = cols;
801 for _ in 0..rows {
802 let mut p = Pack::new(0, 0, self.vpack.width(), 0, "");
803 p.set_type(PackType::Horizontal);
804 p.set_spacing(spacing);
805 p.end();
806 self.vpack.add(&p);
807 }
808 }
809
810 pub fn add<W: WidgetExt>(&mut self, w: &W) {
812 debug_assert!(self.current < self.rows * self.cols);
813 let rem = (self.current - 1) / self.cols;
814 if rem < self.rows {
815 let hpack = self.vpack.child(rem).unwrap();
816 let mut hpack = unsafe { Pack::from_widget_ptr(hpack.as_widget_ptr()) };
817 hpack.end();
818 hpack.add(w);
819 hpack.auto_layout();
820 self.vpack.auto_layout();
821 self.current += 1;
822 }
823 }
824
825 pub fn end(&mut self) {
827 use std::collections::VecDeque;
828 let children = self.vpack.children();
829 self.current = children - self.rows;
830 debug_assert!(self.current <= self.rows * self.cols);
831 let mut v = VecDeque::new();
832 for i in self.rows..children {
833 let c = self.vpack.child(i).unwrap();
834 v.push_back(c);
835 }
836 for i in 0..self.rows {
837 let hpack = self.vpack.child(i).unwrap();
838 let mut hpack = unsafe { Pack::from_widget_ptr(hpack.as_widget_ptr()) };
839 hpack.end();
840 for _j in 0..self.cols {
841 if let Some(w) = v.pop_front() {
842 self.vpack.remove(&w);
843 hpack.add(&w);
844 }
845 hpack.auto_layout();
846 }
847 }
848 self.vpack.auto_layout();
849 }
850}
851
852crate::widget_extends!(VGrid, Pack, vpack);
853
854#[derive(Debug, Clone)]
880pub struct HGrid {
881 hpack: Pack,
882 rows: i32,
883 cols: i32,
884 current: i32,
885}
886
887impl Default for HGrid {
888 fn default() -> Self {
889 Self::new(0, 0, 0, 0, None)
890 }
891}
892
893impl HGrid {
894 pub fn default_fill() -> Self {
896 Self::default().size_of_parent()
897 }
898
899 pub fn new<T: Into<Option<&'static str>>>(x: i32, y: i32, w: i32, h: i32, label: T) -> HGrid {
901 let mut hpack = Pack::new(x, y, w, h, label);
902 hpack.set_type(PackType::Horizontal);
903 HGrid {
904 hpack,
905 rows: 1,
906 cols: 1,
907 current: 0,
908 }
909 }
910
911 pub fn set_params(&mut self, rows: i32, cols: i32, spacing: i32) {
913 self.hpack.set_spacing(spacing);
914 let rows = if rows < 1 { 1 } else { rows };
915 let cols = if cols < 1 { 1 } else { cols };
916 self.rows = rows;
917 self.cols = cols;
918 for _ in 0..cols {
919 let mut p = Pack::new(0, 0, 0, self.hpack.height(), "");
920 p.set_spacing(spacing);
921 p.end();
922 self.hpack.add(&p);
923 }
924 }
925
926 pub fn add<W: WidgetExt>(&mut self, w: &W) {
928 debug_assert!(self.current < self.rows * self.cols);
929 let rem = (self.current - 1) / self.rows;
930 if rem < self.cols {
931 let vpack = self.hpack.child(rem).unwrap();
932 let mut vpack = unsafe { Pack::from_widget_ptr(vpack.as_widget_ptr()) };
933 vpack.end();
934 vpack.add(w);
935 vpack.auto_layout();
936 self.hpack.auto_layout();
937 self.current += 1;
938 }
939 }
940
941 pub fn end(&mut self) {
943 use std::collections::VecDeque;
944 let children = self.hpack.children();
945 self.current = children - self.cols;
946 debug_assert!(self.current <= self.rows * self.cols);
947 let mut v = VecDeque::new();
948 for i in self.cols..children {
949 let c = self.hpack.child(i).unwrap();
950 v.push_back(c);
951 }
952 for i in 0..self.cols {
953 let vpack = self.hpack.child(i).unwrap();
954 let mut vpack = unsafe { Pack::from_widget_ptr(vpack.as_widget_ptr()) };
955 vpack.end();
956 for _j in 0..self.rows {
957 if let Some(w) = v.pop_front() {
958 self.hpack.remove(&w);
959 vpack.add(&w);
960 }
961 vpack.auto_layout();
962 }
963 }
964 self.hpack.auto_layout();
965 }
966}
967
968crate::widget_extends!(HGrid, Pack, hpack);
969
970#[derive(Debug, Clone)]
972pub struct Column {
973 p: Flex,
974}
975
976impl Default for Column {
977 fn default() -> Self {
978 Self::new(0, 0, 0, 0, None)
979 }
980}
981
982impl Column {
983 pub fn default_fill() -> Self {
985 Self::default().size_of_parent().center_of_parent()
986 }
987
988 pub fn new<T: Into<Option<&'static str>>>(
990 x: i32,
991 y: i32,
992 width: i32,
993 height: i32,
994 label: T,
995 ) -> Column {
996 let mut p = Flex::new(x, y, width, height, label);
997 p.set_type(FlexType::Column);
998 Column { p }
999 }
1000
1001 pub fn add<W: WidgetExt>(&mut self, w: &W) {
1003 self.p.add(w);
1004 }
1005}
1006
1007crate::widget_extends!(Column, Flex, p);
1008
1009#[derive(Debug, Clone)]
1011pub struct Row {
1012 p: Flex,
1013}
1014
1015impl Default for Row {
1016 fn default() -> Self {
1017 Self::new(0, 0, 0, 0, None)
1018 }
1019}
1020
1021impl Row {
1022 pub fn default_fill() -> Self {
1024 Self::default().size_of_parent().center_of_parent()
1025 }
1026
1027 pub fn new<T: Into<Option<&'static str>>>(
1029 x: i32,
1030 y: i32,
1031 width: i32,
1032 height: i32,
1033 label: T,
1034 ) -> Row {
1035 let mut p = Flex::new(x, y, width, height, label);
1036 p.set_type(FlexType::Row);
1037 Row { p }
1038 }
1039
1040 pub fn add<W: WidgetExt>(&mut self, w: &W) {
1042 self.p.add(w);
1043 }
1044}
1045
1046crate::widget_extends!(Row, Flex, p);
1047
1048pub struct GridRange {
1050 start: usize,
1051 end: usize,
1052}
1053
1054impl GridRange {
1055 pub fn len(&self) -> usize {
1057 self.end - self.start
1058 }
1059
1060 pub fn is_empty(&self) -> bool {
1062 self.len() == 0
1063 }
1064}
1065
1066impl From<Range<usize>> for GridRange {
1067 fn from(val: Range<usize>) -> Self {
1068 Self {
1069 start: val.start,
1070 end: val.end,
1071 }
1072 }
1073}
1074
1075impl From<usize> for GridRange {
1076 fn from(val: usize) -> Self {
1077 (val..val + 1).into()
1078 }
1079}
1080
1081bitflags::bitflags! {
1082 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1084 pub struct GridAlign: u16 {
1085 const CENTER = 0x0000;
1087 const TOP = 0x0001;
1089 const BOTTOM = 0x0002;
1091 const LEFT = 0x0004;
1093 const RIGHT = 0x0008;
1095 const HORIZONTAL = 0x0010;
1097 const VERTICAL = 0x0020;
1099 const FILL = 0x0030;
1101 const PROPORTIONAL = 0x0040;
1103 const TOP_LEFT = GridAlign::TOP.bits() | GridAlign::LEFT.bits();
1105 const TOP_RIGHT = GridAlign::TOP.bits() | GridAlign::RIGHT.bits();
1107 const BOTTOM_LEFT = GridAlign::BOTTOM.bits() | GridAlign::LEFT.bits();
1109 const BOTTOM_RIGHT = GridAlign::BOTTOM.bits() | GridAlign::RIGHT.bits();
1111 }
1112}
1113#[derive(Debug)]
1115pub struct Grid {
1116 inner: crate::widget::WidgetTracker,
1117 is_derived: bool,
1118}
1119
1120crate::macros::widget::impl_widget_ext!(Grid, Fl_Grid);
1121crate::macros::widget::impl_widget_base!(Grid, Fl_Grid);
1122crate::macros::widget::impl_widget_default!(Grid);
1123crate::macros::group::impl_group_ext!(Grid, Fl_Grid);
1124
1125impl Grid {
1126 pub fn set_layout_ext(&mut self, rows: i32, cols: i32, margin: i32, gap: i32) {
1128 unsafe { Fl_Grid_set_layout(self.inner.widget() as _, rows, cols, margin, gap) }
1129 }
1130 pub fn set_layout(&mut self, rows: i32, cols: i32) {
1132 unsafe { Fl_Grid_set_layout(self.inner.widget() as _, rows, cols, -1, -1) }
1133 }
1134 pub fn layout(&mut self) {
1136 unsafe { Fl_Grid_layout(self.inner.widget() as _) }
1137 }
1138 pub fn clear_layout(&mut self) {
1140 unsafe { Fl_Grid_clear_layout(self.inner.widget() as _) }
1141 }
1142 pub fn set_need_layout(&mut self, set: bool) {
1144 unsafe { Fl_Grid_set_need_layout(self.inner.widget() as _, set as _) }
1145 }
1146 pub fn need_layout(&self) -> bool {
1148 unsafe { Fl_Grid_need_layout(self.inner.widget() as _) != 0 }
1149 }
1150 pub fn set_margin(&mut self, left: i32, top: i32, right: i32, bottom: i32) {
1152 unsafe { Fl_Grid_set_margin(self.inner.widget() as _, left, top, right, bottom) }
1153 }
1154 pub fn set_margins(&mut self, left: i32, top: i32, right: i32, bottom: i32) {
1156 unsafe { Fl_Grid_set_margin(self.inner.widget() as _, left, top, right, bottom) }
1157 }
1158 pub fn set_gap(&mut self, row_gap: i32, col_gap: i32) {
1160 unsafe { Fl_Grid_set_gap(self.inner.widget() as _, row_gap, col_gap) }
1161 }
1162 #[allow(dead_code)]
1163 pub fn set_widget_<W: WidgetExt>(
1165 &mut self,
1166 wi: &mut W,
1167 row: i32,
1168 col: i32,
1169 align: GridAlign,
1170 ) -> *mut () {
1171 unsafe {
1172 Fl_Grid_set_widget(
1173 self.inner.widget() as _,
1174 wi.as_widget_ptr() as _,
1175 row,
1176 col,
1177 align.bits(),
1178 ) as _
1179 }
1180 }
1181 pub fn set_widget<W: 'static + Clone + WidgetExt>(
1183 &mut self,
1184 widget: &mut W,
1185 row: impl Into<GridRange>,
1186 col: impl Into<GridRange>,
1187 ) -> Result<(), FltkError> {
1188 let row = row.into();
1189 let col = col.into();
1190 self.set_widget_ext(widget, row, col, GridAlign::FILL)
1191 }
1192 fn set_widget_ext_<W: WidgetExt>(
1194 &mut self,
1195 wi: &mut W,
1196 row: i32,
1197 col: i32,
1198 rowspan: i32,
1199 colspan: i32,
1200 align: GridAlign,
1201 ) -> *mut () {
1202 unsafe {
1203 Fl_Grid_set_widget_ext(
1204 self.inner.widget() as _,
1205 wi.as_widget_ptr() as _,
1206 row,
1207 col,
1208 rowspan,
1209 colspan,
1210 align.bits(),
1211 ) as _
1212 }
1213 }
1214 pub fn set_widget_ext<W: 'static + Clone + WidgetExt>(
1216 &mut self,
1217 widget: &mut W,
1218 row: impl Into<GridRange>,
1219 col: impl Into<GridRange>,
1220 align: GridAlign,
1221 ) -> Result<(), FltkError> {
1222 let row = row.into();
1223 let col = col.into();
1224 let e = self.set_widget_ext_(
1225 widget,
1226 row.start as _,
1227 col.start as _,
1228 row.len() as _,
1229 col.len() as _,
1230 align,
1231 );
1232 if e.is_null() {
1233 Err(FltkError::Internal(FltkErrorKind::FailedGridSetWidget))
1234 } else {
1235 Ok(())
1236 }
1237 }
1238 pub fn set_col_width(&mut self, col: i32, value: i32) {
1240 unsafe { Fl_Grid_set_col_width(self.inner.widget() as _, col, value) }
1241 }
1242 pub fn set_col_weight(&mut self, col: i32, value: i32) {
1244 unsafe { Fl_Grid_set_col_weight(self.inner.widget() as _, col, value) }
1245 }
1246 pub fn set_col_gap(&mut self, col: i32, value: i32) {
1248 unsafe { Fl_Grid_set_col_gap(self.inner.widget() as _, col, value) }
1249 }
1250 pub fn set_row_height(&mut self, row: i32, value: i32) {
1252 unsafe { Fl_Grid_set_row_height(self.inner.widget() as _, row, value) }
1253 }
1254 pub fn set_row_weight(&mut self, row: i32, value: i32) {
1256 unsafe { Fl_Grid_set_row_weight(self.inner.widget() as _, row, value) }
1257 }
1258 pub fn set_row_gap(&mut self, row: i32, value: i32) {
1260 unsafe { Fl_Grid_set_row_gap(self.inner.widget() as _, row, value) }
1261 }
1262 pub fn show_grid(&mut self, set: bool) {
1264 unsafe { Fl_Grid_show_grid(self.inner.widget() as _, set as _) }
1265 }
1266 pub fn show_grid_with_color(&mut self, set: bool, col: Color) {
1268 unsafe { Fl_Grid_show_grid_with_color(self.inner.widget() as _, set as _, col.bits()) }
1269 }
1270 pub fn debug(&mut self, level: i32) {
1272 unsafe { Fl_Grid_debug(self.inner.widget() as _, level) }
1273 }
1274}
1275
1276#[allow(missing_docs)]
1277pub mod experimental {
1278 #[allow(unused_imports)]
1279 use super::*;
1280}