2020-05-10 08:32:28 +00:00
|
|
|
use std::collections::{HashMap, HashSet};
|
2020-04-17 13:29:48 +00:00
|
|
|
|
2020-04-25 20:49:57 +00:00
|
|
|
use crate::{
|
2020-05-17 14:42:20 +00:00
|
|
|
containers::{area, collapsing_header, menu, resize, scroll_area, window},
|
2020-05-16 17:38:46 +00:00
|
|
|
widgets::text_edit,
|
2020-04-25 20:49:57 +00:00
|
|
|
Id, Layer, Pos2, Rect,
|
|
|
|
};
|
2020-04-21 12:47:17 +00:00
|
|
|
|
2020-05-07 08:47:03 +00:00
|
|
|
#[derive(Clone, Debug, Default, serde_derive::Deserialize, serde_derive::Serialize)]
|
2020-05-02 09:37:12 +00:00
|
|
|
#[serde(default)]
|
2020-04-17 13:29:48 +00:00
|
|
|
pub struct Memory {
|
2020-05-02 09:37:12 +00:00
|
|
|
#[serde(skip)]
|
2020-05-23 11:38:01 +00:00
|
|
|
pub(crate) interaction: Interaction,
|
2020-04-17 13:29:48 +00:00
|
|
|
|
2020-04-29 19:25:49 +00:00
|
|
|
/// The widget with keyboard focus (i.e. a text input field).
|
2020-05-02 09:37:12 +00:00
|
|
|
#[serde(skip)]
|
2020-04-29 19:25:49 +00:00
|
|
|
pub(crate) kb_focus_id: Option<Id>,
|
|
|
|
|
2020-04-21 18:48:31 +00:00
|
|
|
// states of various types of widgets
|
2020-04-22 16:15:27 +00:00
|
|
|
pub(crate) collapsing_headers: HashMap<Id, collapsing_header::State>,
|
2020-05-10 17:02:17 +00:00
|
|
|
pub(crate) menu_bar: HashMap<Id, menu::BarState>,
|
2020-04-25 12:37:39 +00:00
|
|
|
pub(crate) resize: HashMap<Id, resize::State>,
|
2020-05-16 17:38:46 +00:00
|
|
|
pub(crate) scroll_areas: HashMap<Id, scroll_area::State>,
|
|
|
|
pub(crate) text_edit: HashMap<Id, text_edit::State>,
|
2020-04-17 13:29:48 +00:00
|
|
|
|
2020-05-17 14:42:20 +00:00
|
|
|
#[serde(skip)]
|
2020-05-17 15:44:18 +00:00
|
|
|
pub(crate) window_interaction: Option<window::WindowInteraction>,
|
2020-05-17 14:42:20 +00:00
|
|
|
|
2020-05-10 17:02:17 +00:00
|
|
|
pub(crate) areas: Areas,
|
|
|
|
}
|
|
|
|
|
2020-05-23 11:38:01 +00:00
|
|
|
/// Say there is a butotn in a scroll area.
|
|
|
|
/// If the user clicks the button, the button should click.
|
|
|
|
/// If the user drags the button we should scroll the scroll area.
|
|
|
|
/// So what we do is that when the mouse is pressed we register both the button
|
|
|
|
/// and the scroll area (as `click_id`/`drag_id`).
|
|
|
|
/// If the user releases the button without moving the mouse we register it as a click on `click_id`.
|
|
|
|
/// If the cursor moves too much we clear the `click_id` and start passing move events to `drag_id`.
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
|
|
pub struct Interaction {
|
|
|
|
/// A widget interested in clicks that has a mouse press on it.
|
|
|
|
pub click_id: Option<Id>,
|
|
|
|
|
|
|
|
/// A widget interested in drags that has a mouse press on it.
|
|
|
|
pub drag_id: Option<Id>,
|
2020-05-23 12:01:01 +00:00
|
|
|
|
|
|
|
/// Any interest in catching clicks this frame?
|
|
|
|
/// Cleared to false at start of each frame.
|
|
|
|
pub click_interest: bool,
|
|
|
|
|
|
|
|
/// Any interest in catching clicks this frame?
|
|
|
|
/// Cleared to false at start of each frame.
|
|
|
|
pub drag_interest: bool,
|
2020-05-23 11:38:01 +00:00
|
|
|
}
|
|
|
|
|
2020-05-10 17:02:17 +00:00
|
|
|
#[derive(Clone, Debug, Default, serde_derive::Deserialize, serde_derive::Serialize)]
|
|
|
|
#[serde(default)]
|
|
|
|
pub struct Areas {
|
|
|
|
areas: HashMap<Id, area::State>,
|
2020-04-17 13:29:48 +00:00
|
|
|
/// Top is last
|
2020-05-10 17:02:17 +00:00
|
|
|
order: Vec<Layer>,
|
|
|
|
visible_last_frame: HashSet<Layer>,
|
|
|
|
visible_current_frame: HashSet<Layer>,
|
2020-05-12 14:49:43 +00:00
|
|
|
|
|
|
|
/// When an area want to be on top, it is put in here.
|
|
|
|
/// At the end of the frame, this is used to reorder the layers.
|
|
|
|
/// This means if several layers want to be on top, they will keep their relative order.
|
|
|
|
/// So if you close three windows and then reopen them all in one frame,
|
|
|
|
/// they will all be sent to the top, but keep their previous internal order.
|
|
|
|
wants_to_be_on_top: HashSet<Layer>,
|
2020-04-17 13:29:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Memory {
|
2020-05-23 12:01:01 +00:00
|
|
|
pub(crate) fn begin_frame(&mut self, prev_input: &crate::input::InputState) {
|
|
|
|
self.interaction.click_interest = false;
|
|
|
|
self.interaction.drag_interest = false;
|
|
|
|
|
|
|
|
if !prev_input.mouse.could_be_click {
|
|
|
|
self.interaction.click_id = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !prev_input.mouse.down || prev_input.mouse.pos.is_none() {
|
|
|
|
// mouse was not down last frame
|
|
|
|
self.interaction.click_id = None;
|
|
|
|
self.interaction.drag_id = None;
|
|
|
|
|
|
|
|
let window_interaction = self.window_interaction.take();
|
|
|
|
if let Some(window_interaction) = window_interaction {
|
2020-05-23 20:10:08 +00:00
|
|
|
if window_interaction.is_pure_move() {
|
2020-05-23 12:01:01 +00:00
|
|
|
// Throw windows because it is fun:
|
|
|
|
let area_layer = window_interaction.area_layer;
|
2020-05-24 16:48:19 +00:00
|
|
|
let area_state = self.areas.get(&area_layer.id).clone();
|
2020-05-23 12:01:01 +00:00
|
|
|
if let Some(mut area_state) = area_state {
|
|
|
|
area_state.vel = prev_input.mouse.velocity;
|
|
|
|
self.areas.set_state(area_layer, area_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 14:49:43 +00:00
|
|
|
pub(crate) fn end_frame(&mut self) {
|
|
|
|
self.areas.end_frame()
|
2020-05-10 17:02:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// TODO: call once at the start of the frame for the current mouse pos
|
2020-05-24 16:48:19 +00:00
|
|
|
pub fn layer_at(&self, pos: Pos2) -> Option<&Layer> {
|
2020-05-10 17:02:17 +00:00
|
|
|
self.areas.layer_at(pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Areas {
|
|
|
|
pub(crate) fn count(&self) -> usize {
|
|
|
|
self.areas.len()
|
|
|
|
}
|
|
|
|
|
2020-05-24 16:48:19 +00:00
|
|
|
pub(crate) fn get(&mut self, id: &Id) -> Option<area::State> {
|
2020-05-10 17:02:17 +00:00
|
|
|
self.areas.get(&id).cloned()
|
2020-04-19 21:34:34 +00:00
|
|
|
}
|
|
|
|
|
2020-05-10 17:02:17 +00:00
|
|
|
pub(crate) fn order(&self) -> &[Layer] {
|
|
|
|
&self.order
|
2020-05-10 08:32:28 +00:00
|
|
|
}
|
|
|
|
|
2020-05-10 17:02:17 +00:00
|
|
|
pub(crate) fn set_state(&mut self, layer: Layer, state: area::State) {
|
2020-05-24 16:48:19 +00:00
|
|
|
self.visible_current_frame.insert(layer.clone());
|
|
|
|
let did_insert = self.areas.insert(layer.id.clone(), state).is_none();
|
2020-04-19 21:34:34 +00:00
|
|
|
if did_insert {
|
2020-05-10 17:02:17 +00:00
|
|
|
self.order.push(layer);
|
2020-04-19 21:34:34 +00:00
|
|
|
}
|
2020-04-17 13:29:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 18:46:30 +00:00
|
|
|
/// TODO: call once at the start of the frame for the current mouse pos
|
2020-05-24 16:48:19 +00:00
|
|
|
pub fn layer_at(&self, pos: Pos2) -> Option<&Layer> {
|
2020-05-10 17:02:17 +00:00
|
|
|
for layer in self.order.iter().rev() {
|
|
|
|
if self.is_visible(layer) {
|
|
|
|
if let Some(state) = self.areas.get(&layer.id) {
|
2020-05-10 12:27:02 +00:00
|
|
|
if state.interactable {
|
|
|
|
let rect = Rect::from_min_size(state.pos, state.size);
|
|
|
|
if rect.contains(pos) {
|
2020-05-24 16:48:19 +00:00
|
|
|
return Some(&layer);
|
2020-05-10 12:27:02 +00:00
|
|
|
}
|
2020-05-10 08:32:28 +00:00
|
|
|
}
|
2020-04-17 13:29:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-10 12:27:02 +00:00
|
|
|
None
|
2020-04-17 13:29:48 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 14:49:43 +00:00
|
|
|
pub fn visible_last_frame(&self, layer: &Layer) -> bool {
|
|
|
|
self.visible_last_frame.contains(layer)
|
|
|
|
}
|
|
|
|
|
2020-05-10 17:02:17 +00:00
|
|
|
pub fn is_visible(&self, layer: &Layer) -> bool {
|
|
|
|
self.visible_last_frame.contains(layer) || self.visible_current_frame.contains(layer)
|
2020-05-10 12:27:02 +00:00
|
|
|
}
|
|
|
|
|
2020-05-24 16:48:19 +00:00
|
|
|
pub fn move_to_top(&mut self, layer: &Layer) {
|
|
|
|
self.visible_current_frame.insert(layer.clone());
|
|
|
|
self.wants_to_be_on_top.insert(layer.clone());
|
2020-05-10 12:27:02 +00:00
|
|
|
|
2020-05-24 16:48:19 +00:00
|
|
|
if self.order.iter().find(|x| *x == layer).is_none() {
|
|
|
|
self.order.push(layer.clone());
|
2020-04-17 21:22:28 +00:00
|
|
|
}
|
2020-05-10 08:32:28 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 14:49:43 +00:00
|
|
|
pub(crate) fn end_frame(&mut self) {
|
|
|
|
let Self {
|
|
|
|
visible_last_frame,
|
|
|
|
visible_current_frame,
|
|
|
|
order,
|
|
|
|
wants_to_be_on_top,
|
|
|
|
..
|
|
|
|
} = self;
|
|
|
|
|
|
|
|
*visible_last_frame = std::mem::take(visible_current_frame);
|
|
|
|
order.sort_by_key(|layer| (layer.order, wants_to_be_on_top.contains(layer)));
|
|
|
|
wants_to_be_on_top.clear();
|
2020-04-17 13:29:48 +00:00
|
|
|
}
|
|
|
|
}
|