use std::{collections::BTreeMap, sync::mpsc};
use dces::prelude::*;
use crate::{
application::{create_window, ContextProvider},
prelude::*,
render::RenderContext2D,
shell::{ShellRequest, WindowRequest},
theming::prelude::*,
tree::Tree,
};
use super::WidgetContainer;
pub struct Context<'a> {
ecm: &'a mut EntityComponentManager<Tree, StringComponentStore>,
pub entity: Entity,
pub theme: Theme,
provider: &'a ContextProvider,
new_states: BTreeMap<Entity, Box<dyn State>>,
remove_widget_list: Vec<Entity>,
render_context: &'a mut RenderContext2D,
}
impl<'a> Drop for Context<'a> {
fn drop(&mut self) {
self.provider
.states
.borrow_mut()
.append(&mut self.new_states);
}
}
impl<'a> Context<'a> {
pub fn new(
ecs: (
Entity,
&'a mut EntityComponentManager<Tree, StringComponentStore>,
),
theme: &Theme,
provider: &'a ContextProvider,
render_context: &'a mut RenderContext2D,
) -> Self {
Context {
entity: ecs.0,
ecm: ecs.1,
theme: theme.clone(),
provider,
new_states: BTreeMap::new(),
remove_widget_list: vec![],
render_context,
}
}
pub fn get_widget(&mut self, entity: Entity) -> WidgetContainer<'_> {
WidgetContainer::new(
entity,
self.ecm,
&self.theme,
Some(&self.provider.event_queue),
)
}
pub fn widget(&mut self) -> WidgetContainer<'_> {
self.get_widget(self.entity)
}
pub fn window(&mut self) -> WidgetContainer<'_> {
let root = self.ecm.entity_store().root();
self.get_widget(root)
}
pub fn child<'b>(&mut self, id: impl Into<&'b str>) -> WidgetContainer<'_> {
self.entity_of_child(id)
.map(move |child| self.get_widget(child))
.unwrap()
}
pub fn try_child<'b>(&mut self, id: impl Into<&'b str>) -> Option<WidgetContainer<'_>> {
self.entity_of_child(id)
.map(move |child| self.get_widget(child))
}
pub fn parent(&mut self) -> WidgetContainer<'_> {
let entity = self.ecm.entity_store().parent[&self.entity].unwrap();
self.get_widget(entity)
}
pub fn try_parent(&mut self) -> Option<WidgetContainer<'_>> {
if self.ecm.entity_store().parent[&self.entity] == None {
return None;
}
let entity = self.ecm.entity_store().parent[&self.entity].unwrap();
Some(self.get_widget(entity))
}
pub fn parent_from_id<'b>(&mut self, id: impl Into<&'b str>) -> WidgetContainer<'_> {
let mut current = self.entity;
let id = id.into();
while let Some(parent) = self.ecm.entity_store().parent[¤t] {
if let Ok(parent_id) = self.ecm.component_store().get::<String>("id", parent) {
if parent_id == id {
return self.get_widget(parent);
}
}
current = parent;
}
panic!(
"Parent with id: {}, of child with entity: {} could not be found",
id, self.entity.0
);
}
pub fn try_parent_from_id<'b>(
&mut self,
id: impl Into<&'b str>,
) -> Option<WidgetContainer<'_>> {
let mut current = self.entity;
let id = id.into();
while let Some(parent) = self.ecm.entity_store().parent[¤t] {
if let Ok(parent_id) = self.ecm.component_store().get::<String>("id", parent) {
if parent_id == id {
return Some(self.get_widget(parent));
}
}
current = parent;
}
None
}
pub fn child_from_index(&mut self, index: usize) -> WidgetContainer<'_> {
let entity = self.ecm.entity_store().children[&self.entity][index];
self.get_widget(entity)
}
pub fn try_child_from_index(&mut self, index: usize) -> Option<WidgetContainer<'_>> {
if index >= self.ecm.entity_store().children[&self.entity].len() {
return None;
}
let entity = self.ecm.entity_store().children[&self.entity][index];
Some(self.get_widget(entity))
}
pub fn build_context(&mut self) -> BuildContext {
BuildContext::new(
self.ecm,
&self.provider.render_objects,
&self.provider.layouts,
&self.provider.handler_map,
&mut self.new_states,
&self.theme,
&self.provider.event_queue,
)
}
pub fn append_child_to<W: Widget>(&mut self, child: W, parent: Entity) {
let bctx = &mut self.build_context();
let child = child.build(bctx);
bctx.append_child(parent, child);
}
pub fn append_child_to_overlay<W: Widget>(&mut self, child: W) -> Result<(), String> {
if let Some(overlay) = self.ecm.entity_store().overlay {
let bctx = &mut self.build_context();
let child = child.build(bctx);
bctx.append_child(overlay, child);
return Ok(());
}
Err("Context.append_child_to_overlay: Could not find overlay.".to_string())
}
pub fn append_child_entity_to(&mut self, child: Entity, parent: Entity) {
self.build_context().append_child(parent, child)
}
pub fn append_child_entity_to_overlay(&mut self, child: Entity) -> Result<(), String> {
if let Some(overlay) = self.ecm.entity_store().overlay {
self.append_child_entity_to(overlay, child);
return Ok(());
}
Err("Context.append_child_entity_to_overlay: Could not find overlay.".to_string())
}
pub fn append_child<W: Widget>(&mut self, child: W) {
self.append_child_to(child, self.entity);
}
pub fn append_child_entity(&mut self, child: Entity) {
self.append_child_entity_to(self.entity, child);
}
pub fn remove_child(&mut self, child: Entity) {
self.remove_child_from(child, self.entity);
}
pub fn remove_child_from_overlay(&mut self, child: Entity) -> Result<(), String> {
if let Some(overlay) = self.ecm.entity_store().overlay {
self.remove_child_from(child, overlay);
return Ok(());
}
Err("Context.remove_child_from_overlay: Could not find overlay.".to_string())
}
pub fn remove_child_from(&mut self, remove_entity: Entity, parent: Entity) {
let tree = &*self.ecm.entity_store();
if let Some(parent) = find_parent(tree, remove_entity, parent) {
self.remove_widget_list.push(remove_entity);
let index = self.ecm.entity_store().children[&parent]
.iter()
.position(|&r| r == remove_entity)
.unwrap();
if let Some(parent) = self.ecm.entity_store().children.get_mut(&parent) {
parent.remove(index);
}
}
}
pub fn remove_widget_list(&mut self) -> &mut Vec<Entity> {
&mut self.remove_widget_list
}
pub fn clear_children(&mut self) {
self.clear_children_of(self.entity);
}
pub fn clear_children_of(&mut self, parent: Entity) {
let root = self.ecm.entity_store().root();
while !self.ecm.entity_store().children[&parent].is_empty() {
let child = self.ecm.entity_store().children[&parent][0];
if let Some(index) = self
.ecm
.component_store()
.get::<Vec<Entity>>("dirty_widgets", root)
.unwrap()
.iter()
.position(|&r| r == child)
{
if let Ok(dirty_widgets) = self
.ecm
.component_store_mut()
.get_mut::<Vec<Entity>>("dirty_widgets", root)
{
dirty_widgets.remove(index);
}
}
self.remove_child_from(child, parent);
}
}
pub fn entity_of_child<'b>(&mut self, id: impl Into<&'b str>) -> Option<Entity> {
let id = id.into();
let mut current_node = self.entity;
loop {
if let Ok(child_id) = self.ecm.component_store().get::<String>("id", current_node) {
if child_id == id {
return Some(current_node);
}
}
let mut it = self.ecm.entity_store().start_node(current_node).into_iter();
it.next();
if let Some(node) = it.next() {
current_node = node;
} else {
break;
}
}
None
}
pub fn parent_entity_by_style<'b>(&mut self, element: impl Into<&'b str>) -> Option<Entity> {
let mut current = self.entity;
let element = element.into();
while let Some(parent) = self.ecm.entity_store().parent[¤t] {
if let Ok(selector) = self
.ecm
.component_store()
.get::<Selector>("selector", parent)
{
if let Some(parent_element) = &selector.style {
if parent_element == element
&& self
.ecm
.component_store()
.is_origin::<Selector>("selector", parent)
{
return Some(parent);
}
}
}
current = parent;
}
None
}
pub fn entity_of_parent(&mut self) -> Option<Entity> {
self.ecm.entity_store().parent[&self.entity]
}
pub fn index_as_child(&mut self, entity: Entity) -> Option<usize> {
if let Some(parent) = self.ecm.entity_store().parent[&entity] {
return self.ecm.entity_store().children[&parent]
.iter()
.position(|e| *e == entity);
}
None
}
pub fn push_event_strategy<E: Event>(&mut self, event: E, strategy: EventStrategy) {
self.provider
.event_queue
.borrow_mut()
.register_event_with_strategy(event, strategy, self.entity);
}
pub fn push_event<E: Event>(&mut self, event: E) {
self.provider
.event_queue
.borrow_mut()
.register_event(event, self.entity);
}
pub fn push_event_by_entity<E: Event>(&mut self, event: E, entity: Entity) {
self.provider
.event_queue
.borrow_mut()
.register_event(event, entity);
}
pub fn push_event_by_window<E: Event>(&mut self, event: E) {
self.provider
.event_queue
.borrow_mut()
.register_event(event, self.ecm.entity_store().root());
}
pub fn push_event_strategy_by_entity<E: Event>(
&mut self,
event: E,
entity: Entity,
strategy: EventStrategy,
) {
self.provider
.event_queue
.borrow_mut()
.register_event_with_strategy(event, strategy, entity);
}
pub fn show_window<F: Fn(&mut BuildContext) -> Entity + 'static>(&mut self, create_fn: F) {
let (adapter, settings, receiver) = create_window(
self.provider.application_name.clone(),
self.theme.clone(),
self.provider.shell_sender.clone(),
create_fn,
);
self.provider
.shell_sender
.send(ShellRequest::CreateWindow(adapter, settings, receiver))
.expect("Context.show_window: Could not send shell request.");
}
pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
self.render_context
}
pub fn send_window_request(&self, request: WindowRequest) {
self.provider
.window_sender
.send(request)
.expect("Context::send_window_request: could not send request to window.");
}
pub fn window_sender(&self) -> mpsc::Sender<WindowRequest> {
self.provider.window_sender.clone()
}
pub fn new_states_keys(&self) -> Vec<Entity> {
self.new_states.keys().cloned().collect()
}
pub fn switch_theme(&mut self, theme: Theme) {
self.theme = theme.clone();
self.window().get_mut::<Global>("global").theme = theme;
self.window().update_dirty(true);
}
}
pub fn find_parent(tree: &Tree, target_child: Entity, parent: Entity) -> Option<Entity> {
if tree.children[&parent].contains(&target_child) {
return Some(parent);
}
for child in &tree.children[&parent] {
let parent = find_parent(tree, target_child, *child);
if parent.is_some() {
return parent;
}
}
None
}
pub fn get_all_children(children: &mut Vec<Entity>, parent: Entity, tree: &Tree) {
for child in &tree.children[&parent] {
children.push(*child);
get_all_children(children, *child, tree);
}
}