megaui/widgets/
group.rs

1use crate::{
2    types::{Rect, Vector2},
3    ui::{Drag, DragState},
4    Id, Layout, Ui,
5};
6
7#[derive(Debug, Clone)]
8pub struct Group {
9    id: Id,
10    position: Option<Vector2>,
11    layout: Layout,
12    size: Vector2,
13    draggable: bool,
14    highlight: bool,
15    hoverable: bool,
16}
17
18impl Group {
19    pub fn new(id: Id, size: Vector2) -> Group {
20        Group {
21            id,
22            size,
23            position: None,
24            layout: Layout::Horizontal,
25            draggable: false,
26            highlight: false,
27            hoverable: false,
28        }
29    }
30
31    pub fn position(self, position: Vector2) -> Group {
32        Group {
33            position: Some(position),
34            ..self
35        }
36    }
37
38    pub fn layout(self, layout: Layout) -> Group {
39        Group { layout, ..self }
40    }
41
42    pub fn draggable(self, draggable: bool) -> Group {
43        Group { draggable, ..self }
44    }
45
46    pub fn hoverable(self, hoverable: bool) -> Group {
47        Group { hoverable, ..self }
48    }
49
50    pub fn highlight(self, highlight: bool) -> Group {
51        Group { highlight, ..self }
52    }
53
54    pub fn ui<F: FnOnce(&mut Ui)>(self, ui: &mut Ui, f: F) -> Drag {
55        let token = self.begin(ui);
56        f(ui);
57        token.end(ui)
58    }
59
60    pub fn begin(self, ui: &mut Ui) -> GroupToken {
61        let mut drag = Drag::No;
62
63        let parent = ui.get_active_window_context();
64
65        let parent_rect = parent.window.content_rect();
66
67        parent.window.childs.push(self.id);
68
69        let pos = parent.window.cursor.fit(
70            self.size,
71            self.position.map_or(self.layout, Layout::Free),
72        );
73        let rect = Rect::new(pos.x, pos.y, self.size.x, self.size.y);
74        let parent_id = Some(parent.window.id);
75
76        let mut context = ui.begin_window(self.id, parent_id, pos, self.size, 0., true);
77
78        let hovered =
79            (self.hoverable || self.draggable) && rect.contains(context.input.mouse_position);
80
81        if self.draggable && context.dragging.is_none() && hovered && context.input.click_down {
82            *context.dragging = Some((self.id, DragState::Clicked(context.input.mouse_position)));
83        }
84
85        if let Some((id, DragState::Clicked(orig))) = context.dragging {
86            if *id == self.id
87                && context.input.is_mouse_down
88                && context.input.mouse_position.distance(*orig) > 5.
89            {
90                *context.dragging = Some((self.id, DragState::Dragging(*orig)));
91            }
92            if context.input.is_mouse_down == false {
93                *context.dragging = None;
94            }
95        }
96
97        if let Some((id, DragState::Dragging(_))) = context.dragging {
98            let id = *id;
99
100            if id == self.id {
101                drag = Drag::Dragging(context.input.mouse_position, *context.drag_hovered_previous_frame);
102
103                if context.input.is_mouse_down == false {
104                    *context.dragging = None;
105                    drag = Drag::Dropped(context.input.mouse_position, *context.drag_hovered_previous_frame);
106                }
107            }
108
109            if id != self.id && hovered {
110                *context.drag_hovered = Some(self.id);
111            }
112        }
113
114	context.window.draw_commands.clip(parent_rect);
115
116	context.scroll_area();
117
118        let clip_rect = context.window.content_rect();
119        context.window.draw_commands.clip(clip_rect);
120        context.window.draw_commands.draw_rect(
121            rect,
122            context
123                .global_style
124                .drag_border(context.focused, hovered, self.highlight),
125            None,
126        );
127
128        GroupToken {
129            draggable: self.draggable,
130            drag,
131            pos,
132            size: self.size,
133        }
134    }
135}
136
137#[must_use = "Must call `.end()` to finish Group"]
138pub struct GroupToken {
139    draggable: bool,
140    drag: Drag,
141    pos: Vector2,
142    size: Vector2,
143}
144
145impl GroupToken {
146    pub fn end(self, ui: &mut Ui) -> Drag {
147        let context = ui.get_active_window_context();
148
149        context.window.draw_commands.clip(None);
150
151        if context.focused && self.draggable {
152            if
153                //parent.dragging.is_none()
154                context.input.is_mouse_down
155                    && Rect::new(self.pos.x, self.pos.y, self.size.x, self.size.y)
156                    .contains(context.input.mouse_position)
157            {
158                // *context.dragging = Some((
159                //     id,
160                //     DragState::Clicked(context.input.mouse_position, Vector2::new(rect.x, rect.y)),
161                // ));
162            }
163        }
164
165        ui.end_window();
166
167        self.drag
168    }
169}
170
171impl Ui {
172    pub fn group<F: FnOnce(&mut Ui)>(&mut self, id: Id, size: Vector2, f: F) -> Drag {
173        Group::new(id, size).ui(self, f)
174    }
175}