1use crate::NwgError;
2use crate::controls::ControlHandle;
3use crate::win32::window::{
4 RawEventHandler, bind_raw_event_handler_inner, unbind_raw_event_handler,
5};
6use crate::win32::window_helper as wh;
7use std::{
8 cell::{Ref, RefCell, RefMut},
9 ptr,
10 rc::Rc,
11};
12use winapi::shared::windef::HWND;
13
14use stretch::{
15 geometry::{Point, Rect, Size},
16 node::{Node, Stretch},
17 number::Number,
18 style::*,
19};
20
21#[derive(Debug)]
22pub struct FlexboxLayoutItem {
23 control: HWND,
25 style: Style,
26}
27
28pub enum FlexboxLayoutChild {
29 Item(FlexboxLayoutItem),
30 Flexbox(FlexboxLayout),
31}
32
33impl FlexboxLayoutChild {
34 fn modify_style<F>(&mut self, fnc: F)
35 where
36 F: Fn(&mut Style),
37 {
38 match self {
39 FlexboxLayoutChild::Item(item) => fnc(&mut item.style),
40 FlexboxLayoutChild::Flexbox(layout) => fnc(&mut layout.inner.borrow_mut().style),
41 }
42 }
43}
44
45struct FlexboxLayoutInner {
47 base: HWND,
48 handler: Option<RawEventHandler>,
49 style: Style,
50 children: Vec<FlexboxLayoutChild>,
51 parent_layout: Option<FlexboxLayout>,
52}
53
54#[derive(Clone)]
61pub struct FlexboxLayout {
62 inner: Rc<RefCell<FlexboxLayoutInner>>,
63}
64
65impl FlexboxLayout {
66 pub fn builder() -> FlexboxLayoutBuilder {
67 let layout = FlexboxLayoutInner {
68 base: ptr::null_mut(),
69 handler: None,
70 style: Default::default(),
71 children: Vec::new(),
72 parent_layout: None,
73 };
74
75 FlexboxLayoutBuilder {
76 layout,
77 current_index: None,
78 auto_size: true,
79 auto_spacing: Some(5),
80 }
81 }
82
83 pub fn style(&self) -> Style {
90 let inner = self.inner.borrow();
91 if inner.base.is_null() {
92 panic!("Flexbox layout is not yet initialized!");
93 }
94
95 inner.style.clone()
96 }
97
98 pub fn set_style(&self, style: Style) {
105 let mut inner = self.inner.borrow_mut();
106 if inner.base.is_null() {
107 panic!("Flexbox layout is not yet initialized!");
108 }
109
110 inner.style = style;
111 }
112
113 pub fn add_child<W: Into<ControlHandle>>(
121 &self,
122 c: W,
123 style: Style,
124 ) -> Result<(), stretch::Error> {
125 {
126 let mut inner = self.inner.borrow_mut();
127 if inner.base.is_null() {
128 panic!("Flexbox layout is not yet initialized!");
129 }
130
131 let item = FlexboxLayoutItem {
132 control: c
133 .into()
134 .hwnd()
135 .expect("Control must be window like (HWND handle)"),
136 style,
137 };
138
139 inner.children.push(FlexboxLayoutChild::Item(item));
140 }
141
142 self.fit()
143 }
144
145 pub fn remove_child<W: Into<ControlHandle>>(&self, c: W) {
154 let mut inner = self.inner.borrow_mut();
155 if inner.base.is_null() {
156 panic!("Flexbox layout is not yet initialized!");
157 }
158
159 let handle = c
160 .into()
161 .hwnd()
162 .expect("Control must be window like (HWND handle)");
163 let index = inner
164 .children
165 .iter()
166 .position(|child| child.is_item() && child.as_item().control == handle);
167
168 match index {
169 Some(i) => {
170 inner.children.remove(i);
171 }
172 None => {
173 panic!("Control was not found in layout");
174 }
175 }
176 }
177
178 pub fn has_child<W: Into<ControlHandle>>(&self, c: W) -> bool {
187 let inner = self.inner.borrow();
188 if inner.base.is_null() {
189 panic!("Flexbox layout is not yet initialized!");
190 }
191
192 let handle = c
193 .into()
194 .hwnd()
195 .expect("Control must be window like (HWND handle)");
196 inner
197 .children
198 .iter()
199 .any(|child| child.is_item() && child.as_item().control == handle)
200 }
201
202 pub fn children(&self) -> FlexboxLayoutChildren<'_> {
210 let inner = self.inner.borrow();
211 if inner.base.is_null() {
212 panic!("Flexbox layout is not yet initialized!");
213 }
214
215 FlexboxLayoutChildren { inner }
216 }
217
218 pub fn children_mut(&self) -> FlexboxLayoutChildrenMut<'_> {
228 let inner = self.inner.borrow_mut();
229 if inner.base.is_null() {
230 panic!("Flexbox layout is not yet initialized!");
231 }
232
233 FlexboxLayoutChildrenMut { inner }
234 }
235
236 pub fn fit(&self) -> Result<(), stretch::Error> {
243 let inner = self.inner.borrow();
244 if inner.base.is_null() {
245 panic!("FlexboxLayout is not bound to a parent control.")
246 }
247
248 if let Some(parent_layout) = &inner.parent_layout {
249 parent_layout.fit()
250 } else {
251 let (w, h) = wh::get_window_size(inner.base);
252 self.update_layout(w, h, (0, 0))
253 }
254 }
255
256 fn build_child_nodes(
259 children: &Vec<FlexboxLayoutChild>,
260 stretch: &mut Stretch,
261 ) -> Result<(usize, Vec<Node>), stretch::Error> {
262 let mut nodes = Vec::new();
263 let mut item_count = 0;
264
265 for child in children.iter() {
266 match child {
267 FlexboxLayoutChild::Item(child) => {
268 nodes.push(stretch.new_node(child.style, Vec::new())?);
269 item_count += 1;
270 }
271 FlexboxLayoutChild::Flexbox(child) => {
272 let (child_count, child_nodes) =
273 FlexboxLayout::build_child_nodes(child.children().children(), stretch)?;
274 nodes.push(stretch.new_node(child.style(), child_nodes)?);
275 item_count += child_count;
276 }
277 };
278 }
279
280 Ok((item_count, nodes))
281 }
282
283 fn apply_layout_deferred(
286 positioner: &mut wh::DeferredWindowPositioner,
287 stretch: &mut Stretch,
288 nodes: Vec<Node>,
289 children: &Vec<FlexboxLayoutChild>,
290 last_handle: &mut Option<HWND>,
291 offset: (i32, i32),
292 ) -> Result<(), stretch::Error> {
293 use FlexboxLayoutChild as Child;
294
295 for (node, child) in nodes.into_iter().zip(children.iter()) {
296 let layout = stretch.layout(node)?;
297 let Point { x, y } = layout.location;
298 let Size { width, height } = layout.size;
299
300 match child {
301 Child::Item(child) => {
302 positioner
303 .defer_pos(
304 child.control,
305 last_handle.unwrap_or(std::ptr::null_mut()),
306 x as i32 + offset.0,
307 y as i32 + offset.1,
308 width as i32,
309 height as i32,
310 )
311 .ok();
312 last_handle.replace(child.control);
313 }
314 Child::Flexbox(child) => {
315 let children_nodes = stretch.children(node)?;
316 FlexboxLayout::apply_layout_deferred(
317 positioner,
318 stretch,
319 children_nodes,
320 child.children().children(),
321 last_handle,
322 (x as i32, y as i32),
323 )?;
324 }
325 }
326 }
327
328 Ok(())
329 }
330
331 fn apply_layout_immediate(
334 stretch: &mut Stretch,
335 nodes: Vec<Node>,
336 children: &Vec<FlexboxLayoutChild>,
337 last_handle: &mut Option<HWND>,
338 offset: (i32, i32),
339 ) -> Result<(), stretch::Error> {
340 use FlexboxLayoutChild as Child;
341
342 for (node, child) in nodes.into_iter().zip(children.iter()) {
343 let layout = stretch.layout(node)?;
344 let Point { x, y } = layout.location;
345 let Size { width, height } = layout.size;
346
347 match child {
348 Child::Item(child) => {
349 wh::set_window_position(
350 child.control,
351 x as i32 + offset.0,
352 y as i32 + offset.1,
353 );
354 wh::set_window_size(child.control, width as u32, height as u32, false);
355 wh::set_window_after(child.control, *last_handle);
356 last_handle.replace(child.control);
357 }
358 Child::Flexbox(child) => {
359 let children_nodes = stretch.children(node)?;
360 FlexboxLayout::apply_layout_immediate(
361 stretch,
362 children_nodes,
363 child.children().children(),
364 last_handle,
365 (x as i32, y as i32),
366 )?;
367 }
368 }
369 }
370
371 Ok(())
372 }
373
374 fn update_layout(
375 &self,
376 width: u32,
377 height: u32,
378 offset: (i32, i32),
379 ) -> Result<(), stretch::Error> {
380 let inner = self.inner.borrow();
381 if inner.base.is_null() || inner.children.len() == 0 {
382 return Ok(());
383 }
384
385 let mut stretch = Stretch::new();
386 let (item_count, nodes) = FlexboxLayout::build_child_nodes(&inner.children, &mut stretch)?;
387
388 let mut style = inner.style.clone();
389 style.size = Size {
390 width: Dimension::Points(width as f32),
391 height: Dimension::Points(height as f32),
392 };
393 let node = stretch.new_node(style, nodes.clone())?;
394
395 stretch.compute_layout(node, Size::undefined())?;
396
397 if let Ok(mut positioner) = wh::DeferredWindowPositioner::new(item_count as i32) {
399 let layout_result = FlexboxLayout::apply_layout_deferred(
400 &mut positioner,
401 &mut stretch,
402 nodes,
403 self.children().children(),
404 &mut None,
405 offset,
406 );
407 positioner.end();
408
409 layout_result
410 } else {
411 FlexboxLayout::apply_layout_immediate(
412 &mut stretch,
413 nodes,
414 self.children().children(),
415 &mut None,
416 offset,
417 )
418 }
419 }
420}
421
422pub struct FlexboxLayoutBuilder {
423 layout: FlexboxLayoutInner,
424 current_index: Option<usize>,
425 auto_size: bool,
426 auto_spacing: Option<u32>,
427}
428
429impl FlexboxLayoutBuilder {
430 pub fn parent<W: Into<ControlHandle>>(mut self, p: W) -> FlexboxLayoutBuilder {
432 self.layout.base = p.into().hwnd().expect("Parent must be HWND");
433 self
434 }
435
436 pub fn child<W: Into<ControlHandle>>(mut self, child: W) -> FlexboxLayoutBuilder {
439 self.current_index = Some(self.layout.children.len());
440
441 let item = FlexboxLayoutItem {
442 control: child.into().hwnd().unwrap(),
443 style: Style::default(),
444 };
445
446 self.layout.children.push(FlexboxLayoutChild::Item(item));
447
448 self
449 }
450
451 pub fn child_layout(mut self, child: &FlexboxLayout) -> FlexboxLayoutBuilder {
453 self.current_index = Some(self.layout.children.len());
454
455 self.layout
456 .children
457 .push(FlexboxLayoutChild::Flexbox(child.clone()));
458
459 self
460 }
461
462 pub fn auto_size(mut self, auto: bool) -> FlexboxLayoutBuilder {
465 self.auto_size = auto;
466 self
467 }
468
469 pub fn auto_spacing(mut self, auto: Option<u32>) -> FlexboxLayoutBuilder {
472 self.auto_spacing = auto;
473 self
474 }
475
476 pub fn direction(mut self, value: Direction) -> FlexboxLayoutBuilder {
481 self.layout.style.direction = value;
482 self
483 }
484
485 pub fn flex_direction(mut self, value: FlexDirection) -> FlexboxLayoutBuilder {
486 self.layout.style.flex_direction = value;
487 self
488 }
489
490 pub fn flex_wrap(mut self, value: FlexWrap) -> FlexboxLayoutBuilder {
491 self.layout.style.flex_wrap = value;
492 self
493 }
494
495 pub fn overflow(mut self, value: Overflow) -> FlexboxLayoutBuilder {
496 self.layout.style.overflow = value;
497 self
498 }
499
500 pub fn align_items(mut self, value: AlignItems) -> FlexboxLayoutBuilder {
501 self.layout.style.align_items = value;
502 self
503 }
504
505 pub fn align_content(mut self, value: AlignContent) -> FlexboxLayoutBuilder {
506 self.layout.style.align_content = value;
507 self
508 }
509
510 pub fn justify_content(mut self, value: JustifyContent) -> FlexboxLayoutBuilder {
511 self.layout.style.justify_content = value;
512 self
513 }
514
515 pub fn padding(mut self, value: Rect<Dimension>) -> FlexboxLayoutBuilder {
516 self.layout.style.padding = value;
517 self.auto_spacing = None;
518 self
519 }
520
521 pub fn border(mut self, value: Rect<Dimension>) -> FlexboxLayoutBuilder {
522 self.layout.style.border = value;
523 self
524 }
525
526 pub fn min_size(mut self, value: Size<Dimension>) -> FlexboxLayoutBuilder {
527 self.layout.style.min_size = value;
528 self
529 }
530
531 pub fn max_size(mut self, value: Size<Dimension>) -> FlexboxLayoutBuilder {
532 self.layout.style.max_size = value;
533 self
534 }
535
536 pub fn aspect_ratio(mut self, value: Number) -> FlexboxLayoutBuilder {
537 self.layout.style.aspect_ratio = value;
538 self
539 }
540
541 pub fn child_size(mut self, size: Size<Dimension>) -> FlexboxLayoutBuilder {
548 self.modify_current_child_style(|s| s.size = size);
549 self.auto_size = false;
550 self
551 }
552
553 pub fn child_position(mut self, position: Rect<Dimension>) -> FlexboxLayoutBuilder {
556 self.modify_current_child_style(|s| s.position = position);
557 self
558 }
559
560 pub fn child_margin(mut self, value: Rect<Dimension>) -> FlexboxLayoutBuilder {
563 self.modify_current_child_style(|s| s.margin = value);
564 self.auto_spacing = None;
565 self
566 }
567
568 pub fn child_min_size(mut self, value: Size<Dimension>) -> FlexboxLayoutBuilder {
571 self.modify_current_child_style(|s| s.min_size = value);
572 self.auto_size = false;
573 self
574 }
575
576 pub fn child_max_size(mut self, value: Size<Dimension>) -> FlexboxLayoutBuilder {
579 self.modify_current_child_style(|s| s.max_size = value);
580 self.auto_size = false;
581 self
582 }
583
584 pub fn child_flex_grow(mut self, value: f32) -> FlexboxLayoutBuilder {
586 self.modify_current_child_style(|s| s.flex_grow = value);
587 self.auto_size = false;
588 self
589 }
590
591 pub fn child_flex_shrink(mut self, value: f32) -> FlexboxLayoutBuilder {
593 self.modify_current_child_style(|s| s.flex_shrink = value);
594 self.auto_size = false;
595 self
596 }
597
598 pub fn child_flex_basis(mut self, value: Dimension) -> FlexboxLayoutBuilder {
600 self.modify_current_child_style(|s| s.flex_basis = value);
601 self.auto_size = false;
602 self
603 }
604
605 pub fn child_align_self(mut self, value: AlignSelf) -> FlexboxLayoutBuilder {
607 self.modify_current_child_style(|s| s.align_self = value);
608 self
609 }
610
611 pub fn style(mut self, style: Style) -> FlexboxLayoutBuilder {
617 self.modify_current_child_style(|s| *s = style);
618 self
619 }
620
621 fn modify_current_child_style<F>(&mut self, fnc: F)
622 where
623 F: Fn(&mut Style),
624 {
625 assert!(self.current_index.is_some(), "No current children");
626
627 let index = self.current_index.unwrap();
628
629 self.layout.children[index].modify_style(|s| fnc(s));
630 }
631
632 pub fn build(mut self, layout: &FlexboxLayout) -> Result<(), NwgError> {
634 use winapi::shared::minwindef::{HIWORD, LOWORD};
635 use winapi::um::winuser::WM_SIZE;
636
637 if self.layout.base.is_null() {
638 return Err(NwgError::layout_create(
639 "Flexboxlayout does not have a parent.",
640 ));
641 }
642
643 let (w, h) = wh::get_window_size(self.layout.base);
644 let base_handle = ControlHandle::Hwnd(self.layout.base);
645
646 if self.auto_size {
648 let children_count = self.layout.children.len();
649 let size = 1.0f32 / (children_count as f32);
650 for child in self.layout.children.iter_mut() {
651 let child_size = match &self.layout.style.flex_direction {
652 FlexDirection::Row | FlexDirection::RowReverse => Size {
653 width: Dimension::Percent(size),
654 height: Dimension::Auto,
655 },
656 FlexDirection::Column | FlexDirection::ColumnReverse => Size {
657 width: Dimension::Auto,
658 height: Dimension::Percent(size),
659 },
660 };
661
662 child.modify_style(|s| s.size = child_size);
663 }
664 }
665
666 if let Some(spacing) = self.auto_spacing {
668 let spacing = Dimension::Points(spacing as f32);
669 let spacing = Rect {
670 start: spacing,
671 end: spacing,
672 top: spacing,
673 bottom: spacing,
674 };
675 self.layout.style.padding = spacing;
676 for child in self.layout.children.iter_mut() {
677 child.modify_style(|s| s.margin = spacing);
678 }
679 }
680
681 {
683 let mut layout_inner = layout.inner.borrow_mut();
684 if layout_inner.handler.is_some() {
685 drop(unbind_raw_event_handler(
686 layout_inner.handler.as_ref().unwrap(),
687 ));
688 }
689
690 *layout_inner = self.layout;
691 }
692
693 for child in layout.inner.borrow_mut().children.iter_mut() {
695 match child {
696 FlexboxLayoutChild::Item(_) => {}
697 FlexboxLayoutChild::Flexbox(child_layout) => {
698 child_layout
699 .inner
700 .borrow_mut()
701 .parent_layout
702 .replace(layout.clone());
703 }
704 }
705 }
706
707 layout
709 .update_layout(w, h, (0, 0))
710 .expect("Failed to compute layout");
711
712 use std::sync::atomic::{AtomicUsize, Ordering};
714 static FLEX_LAYOUT_ID: AtomicUsize = AtomicUsize::new(0x9FFF);
715 let handler_id = FLEX_LAYOUT_ID.fetch_add(1, Ordering::SeqCst);
716
717 let event_layout = layout.clone();
719 let cb = move |_h, msg, _w, l| {
720 if msg == WM_SIZE {
721 let size = l as u32;
722 let width = LOWORD(size) as i32;
723 let height = HIWORD(size) as i32;
724 let (w, h) = crate::win32::high_dpi::physical_to_logical(width, height);
725 FlexboxLayout::update_layout(&event_layout, w as u32, h as u32, (0, 0))
726 .expect("Failed to compute layout!");
727 }
728 None
729 };
730
731 {
732 let mut layout_inner = layout.inner.borrow_mut();
733 layout_inner.handler =
734 Some(bind_raw_event_handler_inner(&base_handle, handler_id, cb).unwrap());
735 }
736
737 Ok(())
738 }
739
740 pub fn build_partial(mut self, layout: &FlexboxLayout) -> Result<(), NwgError> {
742 if self.layout.base.is_null() {
743 return Err(NwgError::layout_create(
744 "Flexboxlayout does not have a parent.",
745 ));
746 }
747
748 if self.auto_size {
750 let children_count = self.layout.children.len();
751 let size = 1.0f32 / (children_count as f32);
752 for child in self.layout.children.iter_mut() {
753 let child_size = match &self.layout.style.flex_direction {
754 FlexDirection::Row | FlexDirection::RowReverse => Size {
755 width: Dimension::Percent(size),
756 height: Dimension::Auto,
757 },
758 FlexDirection::Column | FlexDirection::ColumnReverse => Size {
759 width: Dimension::Auto,
760 height: Dimension::Percent(size),
761 },
762 };
763
764 child.modify_style(|s| s.size = child_size);
765 }
766 }
767
768 if let Some(spacing) = self.auto_spacing {
770 let spacing = Dimension::Points(spacing as f32);
771 let spacing = Rect {
772 start: spacing,
773 end: spacing,
774 top: spacing,
775 bottom: spacing,
776 };
777 self.layout.style.padding = spacing;
778 for child in self.layout.children.iter_mut() {
779 child.modify_style(|s| s.margin = spacing);
780 }
781 }
782
783 {
785 let mut layout_inner = layout.inner.borrow_mut();
786 if layout_inner.handler.is_some() {
787 drop(unbind_raw_event_handler(
788 layout_inner.handler.as_ref().unwrap(),
789 ));
790 }
791
792 *layout_inner = self.layout;
793 }
794
795 Ok(())
796 }
797}
798
799impl Default for FlexboxLayout {
800 fn default() -> FlexboxLayout {
801 let inner = FlexboxLayoutInner {
802 base: ptr::null_mut(),
803 handler: None,
804 children: Vec::new(),
805 style: Default::default(),
806 parent_layout: None,
807 };
808
809 FlexboxLayout {
810 inner: Rc::new(RefCell::new(inner)),
811 }
812 }
813}
814
815impl FlexboxLayoutChild {
816 pub fn is_item(&self) -> bool {
817 match self {
818 FlexboxLayoutChild::Item(_) => true,
819 _ => false,
820 }
821 }
822
823 pub fn as_item<'a>(&'a self) -> &'a FlexboxLayoutItem {
824 match self {
825 FlexboxLayoutChild::Item(i) => i,
826 _ => panic!("FlexboxLayoutChild is not an item"),
827 }
828 }
829
830 pub fn as_item_mut<'a>(&'a mut self) -> &'a mut FlexboxLayoutItem {
831 match self {
832 FlexboxLayoutChild::Item(i) => i,
833 _ => panic!("FlexboxLayoutChild is not an item"),
834 }
835 }
836
837 pub fn is_flexbox(&self) -> bool {
838 match self {
839 FlexboxLayoutChild::Flexbox(_) => true,
840 _ => false,
841 }
842 }
843}
844
845pub struct FlexboxLayoutChildrenMut<'a> {
849 inner: RefMut<'a, FlexboxLayoutInner>,
850}
851
852impl<'a> FlexboxLayoutChildrenMut<'a> {
853 pub fn children<'b>(&'b mut self) -> &'b mut Vec<FlexboxLayoutChild> {
854 &mut self.inner.children
855 }
856}
857
858pub struct FlexboxLayoutChildren<'a> {
859 inner: Ref<'a, FlexboxLayoutInner>,
860}
861
862impl<'a> FlexboxLayoutChildren<'a> {
863 pub fn children<'b>(&'b self) -> &'b Vec<FlexboxLayoutChild> {
864 &self.inner.children
865 }
866}