use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use super::text_input::CosmicTextData;
#[derive(Component, Deref, Debug)]
pub struct WidgetId(pub String);
#[derive(Component, Deref, Debug)]
pub struct WidgetClasses(pub String);
#[derive(Component)]
pub(crate) struct IsFamiqTooltip;
#[derive(Component)]
pub(crate) struct TooltipEntity(pub Entity);
#[derive(Component)]
pub struct MainWidget;
#[derive(Component)]
pub struct IsFamiqContainableWidget;
#[derive(Component)]
pub struct ReactiveWidget;
#[derive(Component, Debug)]
pub struct ReactiveModelKey(pub String);
#[derive(Bundle, Clone)]
pub struct BaseStyleComponents {
pub node: Node,
pub border_color: BorderColor,
pub border_radius: BorderRadius,
pub background_color: BackgroundColor,
pub z_index: ZIndex,
pub visibility: Visibility,
pub interaction: Interaction,
pub box_shadow: BoxShadow,
}
impl Default for BaseStyleComponents {
fn default() -> Self {
Self {
node: Node::default(),
border_color: BorderColor::default(),
border_radius: BorderRadius::default(),
background_color: BackgroundColor::default(),
z_index: ZIndex::default(),
visibility: Visibility::default(),
interaction: Interaction::default(),
box_shadow: BoxShadow::new(
Color::NONE,
Val::Px(0.0),
Val::Px(0.0),
Val::Px(0.5),
Val::Px(1.0)
)
}
}
}
#[derive(Component)]
pub struct DefaultWidgetConfig {
pub node: Node,
pub border_color: BorderColor,
pub border_radius: BorderRadius,
pub background_color: BackgroundColor,
pub z_index: ZIndex,
pub visibility: Visibility,
pub box_shadow: BoxShadow
}
impl From<BaseStyleComponents> for DefaultWidgetConfig {
fn from(base: BaseStyleComponents) -> Self {
DefaultWidgetConfig {
node: base.node,
border_color: base.border_color,
border_radius: base.border_radius,
background_color: base.background_color,
z_index: base.z_index,
visibility: base.visibility,
box_shadow: base.box_shadow
}
}
}
#[derive(Component)]
pub struct DefaultTextConfig {
pub text: Text,
pub text_font: TextFont,
pub text_color: TextColor,
pub text_layout: TextLayout,
}
impl DefaultTextConfig {
pub fn new(
text: Text,
text_font: TextFont,
text_color: TextColor,
text_layout: TextLayout,
) -> Self {
Self {
text,
text_font,
text_color,
text_layout,
}
}
pub fn new_with_refs(
text: &Text,
text_font: &TextFont,
text_color: &TextColor,
text_layout: &TextLayout,
) -> Self {
Self {
text: text.clone(),
text_font: text_font.clone(),
text_color: text_color.clone(),
text_layout: text_layout.clone(),
}
}
}
#[derive(Component)]
pub struct DefaultCosmicTextEntity {
pub text_data: CosmicTextData
}
impl DefaultCosmicTextEntity {
pub fn new(text_data: CosmicTextData) -> Self {
Self {
text_data
}
}
}
#[derive(Component)]
pub struct DefaultTextSpanConfig {
pub text: TextSpan,
pub text_font: TextFont,
pub text_color: TextColor,
}
impl DefaultTextSpanConfig {
pub fn new(
text: TextSpan,
text_font: TextFont,
text_color: TextColor
) -> Self {
Self {
text,
text_font,
text_color,
}
}
}
#[derive(Component)]
pub struct IsFaWidgetRoot;
#[derive(Default, Debug, Serialize, Deserialize, Clone, Component, PartialEq)]
pub struct WidgetStyle {
pub color: Option<String>, pub font_size: Option<String>, pub background_color: Option<String>,
pub shadow_color: Option<String>,
pub shadow_spread: Option<String>,
pub shadow_blur: Option<String>,
pub shadow_x_offset: Option<String>,
pub shadow_y_offset: Option<String>,
pub border_color: Option<String>,
pub border_radius: Option<String>,
pub visibility: Option<String>,
pub z_index: Option<String>,
pub display: Option<String>,
pub position_type: Option<String>,
pub overflow_x: Option<String>,
pub overflow_y: Option<String>,
pub left: Option<String>,
pub right: Option<String>,
pub top: Option<String>,
pub bottom: Option<String>,
pub width: Option<String>,
pub height: Option<String>,
pub min_width: Option<String>,
pub min_height: Option<String>,
pub max_width: Option<String>,
pub max_height: Option<String>,
pub align_items: Option<String>,
pub justify_items: Option<String>,
pub align_self: Option<String>,
pub justify_content: Option<String>,
pub margin: Option<String>,
pub padding: Option<String>,
pub border: Option<String>,
pub flex_direction: Option<String>,
pub flex_wrap: Option<String>,
pub flex_grow: Option<String>,
pub flex_shrink: Option<String>,
pub flex_basis: Option<String>,
pub margin_left: Option<String>,
pub margin_right: Option<String>,
pub margin_top: Option<String>,
pub margin_bottom: Option<String>,
pub padding_left: Option<String>,
pub padding_right: Option<String>,
pub padding_top: Option<String>,
pub padding_bottom: Option<String>,
pub border_left: Option<String>,
pub border_right: Option<String>,
pub border_top: Option<String>,
pub border_bottom: Option<String>
}
impl WidgetStyle {
pub fn from_external(&mut self, external: &WidgetStyle) {
*self = external.clone();
}
pub fn merge_external(&mut self, external: &WidgetStyle) -> bool {
let mut has_changed = false;
let mut self_map = serde_json::to_value(&mut *self).unwrap();
let external_map = serde_json::to_value(external).unwrap();
let merged_map = self_map.as_object_mut().unwrap();
for (key, value) in external_map.as_object().unwrap() {
let self_field = merged_map.get(key).unwrap();
let external_field = external_map.get(key).unwrap();
if (self_field.is_null() && !external_field.is_null()) ||
(!self_field.is_null() && !external_field.is_null()) {
merged_map.insert(key.clone(), value.clone());
has_changed = true;
}
}
*self = serde_json::from_value(serde_json::Value::Object(merged_map.clone())).unwrap();
has_changed
}
pub fn update_from(&mut self, external: &WidgetStyle) -> bool {
let mut has_changed = false;
let self_json = serde_json::to_value(&mut *self).unwrap();
let external_json = serde_json::to_value(external).unwrap();
if let serde_json::Value::Object(mut self_map) = self_json {
if let serde_json::Value::Object(external_map) = external_json {
for (key, external_value) in external_map {
if self_map.get(&key) != Some(&external_value) {
self_map.insert(key, external_value);
has_changed = true;
}
}
}
*self = serde_json::from_value(serde_json::Value::Object(self_map)).unwrap();
}
has_changed
}
}