1#![warn(
8 missing_docs,
9 future_incompatible,
10 rust_2018_idioms,
11 let_underscore,
12 clippy::missing_docs_in_private_items
13)]
14
15mod layout;
16#[allow(missing_docs, clippy::missing_docs_in_private_items)]
17pub mod prelude;
18
19use std::{
20 cell::RefCell,
21 fmt::Display,
22 rc::{Rc, Weak},
23};
24
25use cursive_core::{event::EventResult, view::IntoBoxedView, Rect, Vec2, View, XY};
26use layout::{Layout, PlacedElement};
27
28pub struct Flexbox {
30 content: Vec<Rc<RefCell<FlexItem>>>,
33 options: FlexBoxOptions,
35 focused: Option<usize>,
37 layout: Option<Layout<Rc<RefCell<FlexItem>>>>,
39 needs_relayout: bool,
41}
42
43impl Default for Flexbox {
44 fn default() -> Self {
45 Self {
46 content: Default::default(),
47 options: Default::default(),
48 focused: Default::default(),
49 layout: Default::default(),
50 needs_relayout: true,
51 }
52 }
53}
54
55pub struct FlexItem {
57 view: Box<dyn View>,
59 flex_grow: u8,
63}
64
65#[derive(Default, Clone, Copy)]
67struct FlexBoxOptions {
68 direction: FlexDirection,
70 justification: JustifyContent,
73 item_alignment: AlignItems,
75 axes_alignment: AlignContent,
77 main_axis_gap: u32,
79 cross_axis_gap: u32,
81 wrap: FlexWrap,
83}
84
85#[non_exhaustive] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
90pub enum FlexDirection {
91 #[default]
93 Row,
94 Column,
98 }
101
102impl Display for FlexDirection {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 write!(
105 f,
106 "{}",
107 match self {
108 Self::Row => "row",
109 Self::Column => "column",
110 }
111 )
112 }
113}
114
115#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
119pub enum FlexWrap {
120 #[default]
122 NoWrap,
123 Wrap,
125 WrapReverse,
127}
128
129impl Display for FlexWrap {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 write!(
132 f,
133 "{}",
134 match self {
135 Self::NoWrap => "nowrap",
136 Self::Wrap => "wrap",
137 Self::WrapReverse => "wrap-reverse",
138 }
139 )
140 }
141}
142
143#[non_exhaustive] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
148pub enum JustifyContent {
149 #[default] FlexStart,
152 FlexEnd,
154 Center,
156 SpaceBetween,
158 SpaceAround,
160 SpaceEvenly, }
163
164impl Display for JustifyContent {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 write!(
167 f,
168 "{}",
169 match self {
170 Self::FlexStart => "flex-start",
171 Self::FlexEnd => "flex-end",
172 Self::Center => "center",
173 Self::SpaceBetween => "space-between",
174 Self::SpaceAround => "space-around",
175 Self::SpaceEvenly => "space-evenly",
176 }
177 )
178 }
179}
180
181#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
186pub enum AlignItems {
187 FlexStart,
189 FlexEnd,
191 Center,
193 #[default] Stretch,
196}
197
198impl Display for AlignItems {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 write!(
201 f,
202 "{}",
203 match self {
204 Self::FlexStart => "flex-start",
205 Self::FlexEnd => "flex-end",
206 Self::Center => "center",
207 Self::Stretch => "stretch",
208 }
209 )
210 }
211}
212
213#[non_exhaustive] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
218pub enum AlignContent {
219 #[default]
221 FlexStart,
222 FlexEnd,
224 Center,
226 Stretch,
228 SpaceBetween,
230 SpaceAround,
232}
233
234impl Display for AlignContent {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 write!(
237 f,
238 "{}",
239 match self {
240 Self::FlexStart => "flex-start",
241 Self::FlexEnd => "flex-end",
242 Self::Center => "center",
243 Self::Stretch => "stretch",
244 Self::SpaceBetween => "space-between",
245 Self::SpaceAround => "space-around",
246 }
247 )
248 }
249}
250
251#[derive(Default)]
254struct FlexboxLayout {
255 size: XY<usize>,
257 options: FlexBoxOptions,
259 main_axes: Vec<MainAxis>,
261}
262
263#[derive(Debug)]
265enum FlexboxError {
266 AxisFull,
268}
269
270impl FlexboxLayout {
271 pub fn windows(&mut self) -> Vec<(Rc<RefCell<FlexItem>>, Rect)> {
274 let mut windows = Vec::new();
275 let mut cross_offset = 0;
276 let mut assignable_free_space = self.cross_axis_free_space();
277
278 for (axis_index, axis) in self.main_axes.iter().enumerate() {
279 match self.options.axes_alignment {
280 AlignContent::FlexEnd => {
281 if assignable_free_space > 0 {
282 cross_offset += assignable_free_space;
283 }
284 assignable_free_space = 0;
285 },
286 AlignContent::Center => {
287 if assignable_free_space > 0 {
288 cross_offset += assignable_free_space / 2;
289 }
290 assignable_free_space = 0;
291 },
292 AlignContent::SpaceAround => {
293 let assigned_space =
294 assignable_free_space / (self.main_axes.len() * 2 - axis_index * 2);
295 if assignable_free_space > 0 {
296 cross_offset += assigned_space;
297 }
298 assignable_free_space -= assigned_space;
299 },
300 _ => {},
301 }
302 for mut combo in axis.windows(self) {
303 match self.options.direction {
304 FlexDirection::Row => combo.1.offset(XY::from((0, cross_offset))),
305 FlexDirection::Column => combo.1.offset(XY::from((cross_offset, 0))),
306 }
307 windows.push(combo);
308 }
309 match self.options.axes_alignment {
310 AlignContent::SpaceBetween => {
311 if assignable_free_space > 0 {
312 let assigned_space =
313 assignable_free_space / (self.main_axes.len() - axis_index - 1);
314 if assignable_free_space > 0 {
315 cross_offset += assigned_space;
316 }
317 assignable_free_space -= assigned_space;
318 }
319 },
320 AlignContent::Stretch => {
321 let assigned_space =
322 assignable_free_space / (self.main_axes.len() - axis_index);
323 if assignable_free_space > 0 {
324 cross_offset += assigned_space;
325 }
326 assignable_free_space -= assigned_space;
327 },
328 AlignContent::SpaceAround => {
329 let assigned_space =
330 assignable_free_space / (self.main_axes.len() * 2 - (axis_index * 2 + 1));
331 if assignable_free_space > 0 {
332 cross_offset += assigned_space;
333 }
334 assignable_free_space -= assigned_space;
335 },
336 _ => {},
337 }
338 cross_offset += axis.cross_axis_size(self) + self.options.cross_axis_gap as usize;
339 }
340
341 windows
342 }
343
344 pub fn cross_axis_free_space(&self) -> usize {
346 let mut used_space = 0;
347
348 for axis in &self.main_axes {
349 used_space += axis.cross_axis_size(self);
350 }
351
352 used_space += (self.main_axis_count() - 1) * self.options.cross_axis_gap as usize;
353
354 match self.options.direction {
355 FlexDirection::Row => self.size.y.saturating_sub(used_space),
356 FlexDirection::Column => self.size.x.saturating_sub(used_space),
357 }
358 }
359
360 pub fn generate(
362 content: &[Weak<RefCell<FlexItem>>],
363 width: usize,
364 height: usize,
365 options: FlexBoxOptions,
366 ) -> Rc<RefCell<Self>> {
367 let layout = Rc::new(RefCell::new(FlexboxLayout {
368 size: XY::from((width, height)),
369 options,
370 main_axes: Vec::new(),
371 }));
372
373 let mut added = 0;
376 let length = content.len();
377
378 while added < length {
379 let mut main_axis = MainAxis::new(Rc::downgrade(&layout));
380
381 loop {
382 let result =
383 main_axis.add_item(content[added].clone(), &mut RefCell::borrow_mut(&layout));
384 if result.is_err() {
385 break;
387 } else if added + 1 == length {
388 added += 1;
390 break;
391 } else {
392 added += 1;
394 }
395 }
396
397 match options.wrap {
399 FlexWrap::NoWrap | FlexWrap::Wrap => {
400 RefCell::borrow_mut(&layout).main_axes.push(main_axis)
401 },
402 FlexWrap::WrapReverse => {
403 RefCell::borrow_mut(&layout).main_axes.insert(0, main_axis)
404 },
405 }
406 }
407
408 layout
409 }
410
411 pub fn flexitem_main_axis_size(&self, item: &mut FlexItem) -> usize {
413 match self.options.direction {
414 FlexDirection::Row => item.view.required_size(self.size).x,
415 FlexDirection::Column => item.view.required_size(self.size).y,
416 }
417 }
418
419 pub fn main_axis_count(&self) -> usize {
421 self.main_axes.len()
422 }
423}
424
425struct MainAxis {
429 items: Vec<Weak<RefCell<FlexItem>>>,
431 free_space: usize,
433}
434
435impl MainAxis {
436 pub fn new(layout: Weak<RefCell<FlexboxLayout>>) -> Self {
438 let layout_upgraded = layout.upgrade().unwrap();
439 let free_space = match RefCell::borrow(&layout_upgraded).options.direction {
440 FlexDirection::Row => RefCell::borrow(&layout_upgraded).size.x,
441 FlexDirection::Column => RefCell::borrow(&layout_upgraded).size.y,
442 };
443 MainAxis {
444 items: Vec::new(),
445 free_space,
446 }
447 }
448
449 pub fn cross_axis_size(&self, layout: &FlexboxLayout) -> usize {
452 let mut maximum_item_cross_axis_size = 0;
453 match layout.options.direction {
454 FlexDirection::Row => {
455 for item in &self.items {
456 maximum_item_cross_axis_size = maximum_item_cross_axis_size.max(
457 RefCell::borrow_mut(&item.upgrade().unwrap())
458 .view
459 .required_size(layout.size)
460 .y,
461 );
462 }
463 },
464 FlexDirection::Column => {
465 for item in &self.items {
466 maximum_item_cross_axis_size = maximum_item_cross_axis_size.max(
467 RefCell::borrow_mut(&item.upgrade().unwrap())
468 .view
469 .required_size(layout.size)
470 .x,
471 );
472 }
473 },
474 }
475
476 maximum_item_cross_axis_size
477 }
478
479 pub fn windows(&self, layout: &FlexboxLayout) -> Vec<(Rc<RefCell<FlexItem>>, Rect)> {
482 let mut windows = Vec::new();
483 let mut offset = 0;
484 let mut assignable_free_space = self.free_space;
485 let combined_grow_factor = self.combined_grow_factor();
486 let mut remaining_grow_factor = combined_grow_factor;
487 let cross_axis_size = self.cross_axis_size(layout);
488
489 for (item_index, item) in self
490 .items
491 .iter()
492 .map(|item| item.upgrade().unwrap())
493 .enumerate()
494 {
495 let mut start_x = 0;
496 let mut start_y = 0;
497 let mut width = 1;
498 let mut height = 1;
499
500 if combined_grow_factor > 0 {
501 let mut current_item_assigned_space = 0;
505 let item_main_axis_size =
506 layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item));
507 if remaining_grow_factor > 0 {
508 current_item_assigned_space =
509 ((RefCell::borrow(&item).flex_grow as f64 / remaining_grow_factor as f64)
510 * assignable_free_space as f64) as usize;
511 }
512
513 match layout.options.direction {
514 FlexDirection::Row => {
515 start_x = offset;
516 width = item_main_axis_size + current_item_assigned_space;
517 },
518 FlexDirection::Column => {
519 start_y = offset;
520 height = item_main_axis_size + current_item_assigned_space;
521 },
522 }
523 offset += item_main_axis_size
524 + layout.options.main_axis_gap as usize
525 + current_item_assigned_space;
526 assignable_free_space -= current_item_assigned_space;
527 remaining_grow_factor -= RefCell::borrow(&item).flex_grow as usize;
528 } else {
529 match layout.options.direction {
533 FlexDirection::Row => {
534 width = RefCell::borrow_mut(&item).view.required_size(layout.size).x;
535 },
536 FlexDirection::Column => {
537 height = RefCell::borrow_mut(&item).view.required_size(layout.size).y;
538 },
539 }
540
541 match layout.options.justification {
543 JustifyContent::FlexStart => {
544 match layout.options.direction {
545 FlexDirection::Row => {
546 start_x = offset;
547 },
548 FlexDirection::Column => {
549 start_y = offset;
550 },
551 }
552
553 offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
554 + layout.options.main_axis_gap as usize;
555 },
556 JustifyContent::FlexEnd => {
557 if assignable_free_space > 0 {
558 offset = assignable_free_space;
559 assignable_free_space = 0;
560 }
561 match layout.options.direction {
562 FlexDirection::Row => {
563 start_x = offset;
564 },
565 FlexDirection::Column => {
566 start_y = offset;
567 },
568 }
569
570 offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
571 + layout.options.main_axis_gap as usize;
572 },
573 JustifyContent::Center => {
574 if assignable_free_space > 0 {
575 offset = assignable_free_space / 2;
576 assignable_free_space = 0;
577 }
578
579 match layout.options.direction {
580 FlexDirection::Row => {
581 start_x = offset;
582 },
583 FlexDirection::Column => {
584 start_y = offset;
585 },
586 }
587
588 offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
589 + layout.options.main_axis_gap as usize;
590 },
591 JustifyContent::SpaceBetween => {
592 match layout.options.direction {
593 FlexDirection::Row => {
594 start_x = offset;
595 },
596 FlexDirection::Column => {
597 start_y = offset;
598 },
599 }
600
601 if assignable_free_space > 0 && item_index + 1 < self.number_of_items() {
602 let extra_free_space = assignable_free_space
603 / (self.number_of_items().saturating_sub(1 + item_index));
604 assignable_free_space -= extra_free_space;
605 offset += extra_free_space;
606 }
607 offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
608 + layout.options.main_axis_gap as usize;
609 },
610 JustifyContent::SpaceAround => {
611 let mut extra_free_space =
612 assignable_free_space / (self.number_of_items() * 2 - item_index * 2);
613 if assignable_free_space > 0 {
614 offset += extra_free_space;
615 }
616 assignable_free_space -= extra_free_space;
617
618 match layout.options.direction {
619 FlexDirection::Row => {
620 start_x = offset;
621 },
622 FlexDirection::Column => {
623 start_y = offset;
624 },
625 }
626
627 extra_free_space = assignable_free_space
628 / (self.number_of_items() * 2 - (item_index * 2 + 1));
629 if assignable_free_space > 0 {
630 offset += extra_free_space;
631 }
632 assignable_free_space -= extra_free_space;
633
634 offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
635 + layout.options.main_axis_gap as usize;
636 },
637 JustifyContent::SpaceEvenly => {
638 let extra_free_space =
639 assignable_free_space / (self.number_of_items() + 1 - item_index);
640 if assignable_free_space > 0 {
641 offset += extra_free_space;
642 }
643 assignable_free_space -= extra_free_space;
644
645 match layout.options.direction {
646 FlexDirection::Row => {
647 start_x = offset;
648 },
649 FlexDirection::Column => {
650 start_y = offset;
651 },
652 }
653
654 offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
655 + layout.options.main_axis_gap as usize;
656 },
657 }
658 }
659
660 match layout.options.item_alignment {
663 AlignItems::FlexStart => match layout.options.direction {
664 FlexDirection::Row => {
665 start_y = 0;
666 height = RefCell::borrow_mut(&item).view.required_size(layout.size).y;
667 },
668 FlexDirection::Column => {
669 start_x = 0;
670 width = RefCell::borrow_mut(&item).view.required_size(layout.size).x;
671 },
672 },
673 AlignItems::FlexEnd => match layout.options.direction {
674 FlexDirection::Row => {
675 height = RefCell::borrow_mut(&item).view.required_size(layout.size).y;
676 start_y = cross_axis_size - height;
677 },
678 FlexDirection::Column => {
679 width = RefCell::borrow_mut(&item).view.required_size(layout.size).x;
680 start_x = cross_axis_size - width;
681 },
682 },
683 AlignItems::Center => match layout.options.direction {
684 FlexDirection::Row => {
685 height = RefCell::borrow_mut(&item).view.required_size(layout.size).y;
686 start_y = (cross_axis_size - height) / 2;
687 },
688 FlexDirection::Column => {
689 width = RefCell::borrow_mut(&item).view.required_size(layout.size).x;
690 start_x = (cross_axis_size - width) / 2;
691 },
692 },
693 AlignItems::Stretch => match layout.options.direction {
694 FlexDirection::Row => {
695 height = cross_axis_size;
696 start_y = 0;
697 },
698 FlexDirection::Column => {
699 width = cross_axis_size;
700 start_x = 0;
701 },
702 },
703 }
704
705 RefCell::borrow_mut(&item)
706 .view
707 .layout((width, height).into());
708 windows.push((item, Rect::from_size((start_x, start_y), (width, height))));
709 }
710
711 windows
712 }
713
714 pub fn add_item(
716 &mut self,
717 item: Weak<RefCell<FlexItem>>,
718 layout: &mut FlexboxLayout,
719 ) -> Result<(), FlexboxError> {
720 let upgraded_item = item.upgrade().unwrap();
721 if self.can_accomodate(&mut RefCell::borrow_mut(&upgraded_item), layout) {
722 self.free_space = self.free_space.saturating_sub(
723 layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&upgraded_item)),
724 );
725
726 if self.number_of_items() >= 1 {
728 self.free_space = self
729 .free_space
730 .saturating_sub(layout.options.main_axis_gap as usize);
731 }
732
733 self.items.push(item);
734
735 Ok(())
736 } else {
737 Err(FlexboxError::AxisFull)
738 }
739 }
740
741 pub fn can_accomodate(&self, item: &mut FlexItem, layout: &mut FlexboxLayout) -> bool {
745 if let FlexWrap::NoWrap = layout.options.wrap {
746 layout.main_axes.len() == 1
748 } else if self.items.is_empty() {
749 true
751 } else {
752 let extra_used_space = if self.number_of_items() >= 1 {
753 layout.flexitem_main_axis_size(item) + layout.options.main_axis_gap as usize
754 } else {
755 layout.flexitem_main_axis_size(item)
756 };
757 extra_used_space <= self.free_space
758 }
759 }
760
761 pub fn number_of_items(&self) -> usize {
763 self.items.len()
764 }
765
766 pub fn combined_grow_factor(&self) -> usize {
768 let mut total_grow_factor = 0usize;
769 self.items.iter().for_each(|item| {
770 total_grow_factor += RefCell::borrow(&item.upgrade().unwrap()).flex_grow as usize;
771 });
772 total_grow_factor
773 }
774}
775
776impl<T: Into<FlexItem>> From<Vec<T>> for Flexbox {
777 fn from(value: Vec<T>) -> Self {
778 let content: Vec<Rc<RefCell<FlexItem>>> = value
779 .into_iter()
780 .map(|item| Rc::new(RefCell::new(item.into())))
781 .collect();
782 Self {
783 content,
784 ..Default::default()
785 }
786 }
787}
788
789impl Flexbox {
790 pub fn new() -> Self {
792 Self::default()
793 }
794
795 pub fn push(&mut self, item: impl Into<FlexItem>) {
797 self.content.push(Rc::new(RefCell::new(item.into())));
798 self.needs_relayout = true;
799 }
800
801 pub fn clear(&mut self) {
803 self.content.clear();
804 self.needs_relayout = true;
805 }
806
807 pub fn insert(&mut self, index: usize, item: impl Into<FlexItem>) {
812 self.content
813 .insert(index, Rc::new(RefCell::new(item.into())));
814 self.needs_relayout = true;
815 }
816
817 pub fn set_flex_grow(&mut self, index: usize, flex_grow: u8) {
822 Rc::as_ref(&self.content[index]).borrow_mut().flex_grow = flex_grow;
823 self.needs_relayout = true;
824 }
825
826 pub fn len(&self) -> usize {
828 self.content.len()
829 }
830
831 pub fn is_empty(&self) -> bool {
833 self.content.is_empty()
834 }
835
836 pub fn remove(&mut self, index: usize) {
841 self.content.remove(index);
842 }
843
844 pub fn main_axis_gap(&self) -> u32 {
846 self.options.main_axis_gap
847 }
848
849 pub fn set_main_axis_gap(&mut self, gap: u32) {
851 self.options.main_axis_gap = gap;
852 self.needs_relayout = true;
853 }
854
855 pub fn cross_axis_gap(&self) -> u32 {
857 self.options.cross_axis_gap
858 }
859
860 pub fn set_cross_axis_gap(&mut self, gap: u32) {
862 self.options.cross_axis_gap = gap;
863 self.needs_relayout = true;
864 }
865
866 pub fn justify_content(&self) -> JustifyContent {
868 self.options.justification
869 }
870
871 pub fn set_justify_content(&mut self, justify_content: JustifyContent) {
873 self.options.justification = justify_content;
874 self.needs_relayout = true;
875 }
876
877 pub fn align_items(&self) -> AlignItems {
879 self.options.item_alignment
880 }
881
882 pub fn set_align_items(&mut self, item_alignment: AlignItems) {
884 self.options.item_alignment = item_alignment;
885 self.needs_relayout = true;
886 }
887
888 pub fn align_content(&self) -> AlignContent {
890 self.options.axes_alignment
891 }
892
893 pub fn set_align_content(&mut self, axes_alignment: AlignContent) {
895 self.options.axes_alignment = axes_alignment;
896 self.needs_relayout = true;
897 }
898
899 pub fn flex_direction(&self) -> FlexDirection {
901 self.options.direction
902 }
903
904 pub fn set_flex_direction(&mut self, direction: FlexDirection) {
906 self.options.direction = direction;
907 self.needs_relayout = true;
908 }
909
910 pub fn flex_wrap(&self) -> FlexWrap {
912 self.options.wrap
913 }
914
915 pub fn set_flex_wrap(&mut self, wrap: FlexWrap) {
917 self.options.wrap = wrap;
918 self.needs_relayout = true;
919 }
920
921 fn generate_layout(&self, constraints: XY<usize>) -> Layout<Rc<RefCell<FlexItem>>> {
923 let layout = FlexboxLayout::generate(
924 &self.content.iter().map(Rc::downgrade).collect::<Vec<_>>(),
925 constraints.x,
926 constraints.y,
927 self.options,
928 );
929 let mut result = Layout {
930 elements: Vec::new(),
931 };
932 RefCell::borrow_mut(&layout)
933 .windows()
934 .into_iter()
935 .for_each(|item| {
936 result.elements.push(PlacedElement {
937 element: item.0,
938 position: item.1,
939 })
940 });
941 result
942 }
943}
944
945impl View for Flexbox {
946 fn draw(&self, printer: &cursive_core::Printer<'_, '_>) {
948 if let Some(ref layout) = self.layout {
949 for placed_element in layout {
950 RefCell::borrow(&placed_element.element)
951 .view
952 .draw(&printer.windowed(placed_element.position));
953 }
954 }
955 }
956
957 fn layout(&mut self, printer_size: Vec2) {
961 self.layout = Some(self.generate_layout(printer_size));
963
964 for placed_element in self.layout.as_ref().unwrap() {
966 RefCell::borrow_mut(&placed_element.element)
967 .view
968 .layout(placed_element.position.size());
969 }
970
971 self.needs_relayout = false;
972 }
973
974 fn needs_relayout(&self) -> bool {
978 self.needs_relayout
981 }
982
983 fn required_size(&mut self, constraint: cursive_core::Vec2) -> cursive_core::Vec2 {
986 constraint
989 }
990
991 fn on_event(
992 &mut self,
993 mut event: cursive_core::event::Event,
994 ) -> cursive_core::event::EventResult {
995 if let cursive_core::event::Event::Mouse {
996 ref mut offset,
997 ref mut position,
998 ..
999 } = event
1000 {
1001 if let Some(ref layout) = self.layout {
1002 if let Some(placed_element) =
1003 layout.element_at(global_to_view_coordinates(*position, *offset))
1004 {
1005 *offset = *offset + placed_element.position.top_left();
1006 RefCell::borrow_mut(&placed_element.element)
1007 .view
1008 .on_event(event)
1009 } else {
1010 EventResult::Ignored
1011 }
1012 } else {
1013 EventResult::Ignored
1014 }
1015 } else if let Some(active_child) = self.focused {
1016 RefCell::borrow_mut(&self.content[active_child])
1017 .view
1018 .on_event(event)
1019 } else {
1020 EventResult::Ignored
1021 }
1022 }
1023
1024 fn focus_view(
1025 &mut self,
1026 selector: &cursive_core::view::Selector<'_>,
1027 ) -> Result<EventResult, cursive_core::view::ViewNotFound> {
1028 for (index, view) in self.content.iter_mut().enumerate() {
1029 if let Ok(event_result) = RefCell::borrow_mut(view).view.focus_view(selector) {
1030 self.focused = Some(index);
1031 return Ok(event_result);
1032 }
1033 }
1034 Err(cursive_core::view::ViewNotFound)
1035 }
1036
1037 fn call_on_any(
1038 &mut self,
1039 selector: &cursive_core::view::Selector<'_>,
1040 callback: cursive_core::event::AnyCb<'_>,
1041 ) {
1042 for view in self.content.iter_mut() {
1043 RefCell::borrow_mut(view)
1044 .view
1045 .call_on_any(selector, callback);
1046 }
1047 }
1048
1049 fn take_focus(
1050 &mut self,
1051 _source: cursive_core::direction::Direction,
1052 ) -> Result<EventResult, cursive_core::view::CannotFocus> {
1053 Ok(EventResult::Consumed(None))
1054 }
1055
1056 fn important_area(&self, _view_size: Vec2) -> Rect {
1057 if let Some(ref layout) = self.layout {
1058 if let Some(focused) = self.focused {
1059 layout.elements[focused].position
1060 } else {
1061 Rect::from_size((0, 0), (1, 1))
1062 }
1063 } else {
1064 Rect::from_size((0, 0), (1, 1))
1065 }
1066 }
1067}
1068
1069impl FlexItem {
1070 pub fn with_flex_grow(view: impl IntoBoxedView, flex_grow: u8) -> Self {
1072 Self {
1073 view: view.into_boxed_view(),
1074 flex_grow,
1075 }
1076 }
1077
1078 pub fn set_flex_grow(&mut self, flex_grow: u8) {
1080 self.flex_grow = flex_grow;
1081 }
1082
1083 pub fn flex_grow(&self) -> u8 {
1085 self.flex_grow
1086 }
1087}
1088
1089impl<T: IntoBoxedView> From<T> for FlexItem {
1090 fn from(value: T) -> Self {
1091 Self {
1092 view: value.into_boxed_view(),
1093 flex_grow: 0,
1094 }
1095 }
1096}
1097
1098fn global_to_view_coordinates(global_coordinates: XY<usize>, view_offset: XY<usize>) -> XY<usize> {
1101 global_coordinates - view_offset
1102}