pub mod widgets;
pub mod consts;
pub mod events;
pub mod utils;
pub mod styles;
pub mod colors;
pub mod routers;
#[macro_use]
pub mod macros;
pub mod prelude {
use bevy::prelude::*;
use bevy::asset::embedded_asset;
use bevy::asset::io::web::WebAssetPlugin;
use std::collections::HashSet;
pub use crate::widgets::*;
pub use crate::consts::*;
pub use crate::events::*;
pub use crate::styles::*;
pub use crate::colors::*;
pub use crate::routers::*;
pub use crate::navigate;
pub use bevy::ui_widgets::observe;
pub use crate::scroll_;
pub use crate::row_;
pub use crate::column_;
pub use crate::root_;
pub use crate::button_;
pub use crate::text_;
pub use crate::checkbox_;
pub use crate::circular_;
pub use crate::progress_bar_;
pub use crate::dropdown_;
pub use crate::image_;
pub use crate::link_;
pub use crate::slider_;
pub use crate::radio_;
pub use crate::radio_group_;
pub use crate::text_input_;
pub use crate::select_;
pub use crate::modal_;
#[derive(Default)]
pub enum RunSchedule {
AtPreUpdate,
AtPostUpdate,
#[default]
AtUpdate
}
#[derive(Resource, Default)]
pub struct CustomFont {
pub font_path: String,
pub font_handle: Option<Handle<Font>>
}
#[derive(Default)]
pub struct MakaraPlugin {
pub run_schedule: RunSchedule,
pub font_path: String
}
impl MakaraPlugin {
pub fn run_at(run_schedule: RunSchedule) -> Self {
Self {
run_schedule,
..default()
}
}
pub fn set_font(mut self, font_path: &str) -> Self {
self.font_path = font_path.to_string();
self
}
}
impl Plugin for MakaraPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(DefaultPlugins.set(WebAssetPlugin {
silence_startup_warning: false,
}));
embedded_asset!(app, "embedded_assets/progress_bar.wgsl");
embedded_asset!(app, "embedded_assets/circular.wgsl");
app.add_plugins(UiMaterialPlugin::<ProgressBarMaterial>::default());
app.add_plugins(UiMaterialPlugin::<CircularMaterial>::default());
app.insert_resource(MakaraTheme::default());
app.insert_resource(MakaraModalState::default());
app.insert_resource(MakaraTextEditContext::default());
app.insert_resource(DropdownOverlayAndTextAdded::default());
app.insert_resource(CanBeScrolled::default());
app.insert_resource(ImageHandleMap::default());
app.insert_resource(CustomStyle::default());
app.insert_resource(Router::default());
app.insert_resource(CustomFont {
font_path: self.font_path.clone(),
font_handle: None
});
#[cfg(target_arch = "wasm32")]
{
let (tx, rx) = crossbeam_channel::bounded::<WasmPaste>(1);
app.insert_resource(WasmPasteAsyncChannel { tx, rx });
}
let systems = (
(
update_button_style_on_theme_change_system,
detect_button_class_change_for_built_in_color,
detect_button_built
)
.run_if(can_run_button_systems),
(
update_text_color_on_theme_change_system,
detect_text_built
)
.run_if(can_run_text_systems),
update_root_style_on_theme_change_system.run_if(can_run_root_systems),
(
update_checkbox_button_style_on_theme_change_system,
update_checkbox_style_on_state_change_system,
detect_checkbox_class_change_for_built_in_color,
detect_checkbox_built
)
.run_if(can_run_checkbox_systems),
(
handle_show_and_hide_modals_system,
update_modal_style_on_theme_change_system,
detect_modal_children_added,
detect_modal_built
)
.run_if(can_run_modal_systems),
(
update_radio_button_style_on_theme_change_system,
update_radio_style_on_state_change_system,
detect_radio_built
)
.run_if(can_run_radio_systems),
(
update_dropdown_style_on_theme_change_system,
show_and_hide_dropdown_overlay_on_state_change_system,
detect_user_provided_children_system,
detect_dropdown_overlay_added,
detect_dropdown_built
)
.run_if(can_run_dropdown_systems),
(
update_select_style_on_theme_change_system,
show_and_hide_select_overlay_on_state_change_system,
detect_select_items_added_and_overlay_resized,
detect_select_placeholder_added
)
.run_if(can_run_select_systems),
(
update_slider_style_on_theme_change_system,
detect_slider_thumb_added,
detect_slider_built
)
.run_if(can_run_slider_systems),
(
update_progress_bar_style_on_theme_change_system,
update_progress_bar_material_u_time,
detect_progress_value_added,
detect_progress_bar_built,
)
.run_if(can_run_progress_bar_systems),
(
detect_circular_added,
detect_circular_class_change_for_built_in_color,
update_circular_material_u_time,
update_circular_style_on_theme_change_system,
)
.run_if(can_run_circular_systems),
(
update_text_input_style_on_theme_change,
detect_new_text_input_added,
update_text_input_render,
handle_text_input_typing,
handle_cursor_blink,
#[cfg(target_arch = "wasm32")]
{
on_wasm_paste
}
)
.run_if(can_run_text_input_systems),
(
detect_scroll_built,
detect_scroll_children_added,
detect_scroll_height_change,
detect_move_panel_height_change,
handle_scrolling
)
.run_if(can_run_scroll_systems),
(
track_image_loading_state,
detect_new_image_added,
detect_image_built
)
.run_if(can_run_image_systems),
update_tooltip_style_on_theme_change_system,
detect_tooltip_built,
detect_column_built,
detect_row_built,
detect_root_built,
detect_link_built
);
app.add_systems(Startup, setup);
app.add_systems(Update, (
detect_makara_text_added,
detect_widget_class_change,
check_unique_id,
handle_match_route_to_root,
detect_row_class_change_for_built_in,
detect_column_class_change_for_built_in,
detect_scroll_class_change_for_built_in,
detect_text_class_change_for_built_in,
detect_bar_class_change_for_built_in_color,
detect_select_class_change_for_built_in,
detect_slider_class_change_for_built_in,
detect_text_input_class_change_for_built_in
));
app.add_systems(
Update,
(
apply_custom_style_to_button,
apply_custom_style_to_checkbox,
apply_custom_style_to_circular,
apply_custom_style_to_row,
apply_custom_style_to_column,
apply_custom_style_to_dropdown,
apply_custom_style_to_image,
apply_custom_style_to_link,
apply_custom_style_to_progress_bar,
apply_custom_style_to_root,
apply_custom_style_to_text,
apply_custom_style_to_slider,
apply_custom_style_to_radio,
apply_custom_style_to_radio_group,
apply_custom_style_to_select,
apply_custom_style_to_text_input.after(apply_custom_style_to_dropdown),
apply_custom_style_to_scroll.after(apply_custom_style_to_text_input),
set_style_unchanged
.after(apply_custom_style_to_button)
.after(apply_custom_style_to_checkbox)
.after(apply_custom_style_to_circular)
.after(apply_custom_style_to_column)
.after(apply_custom_style_to_row)
.after(apply_custom_style_to_dropdown)
.after(apply_custom_style_to_image)
.after(apply_custom_style_to_link)
.after(apply_custom_style_to_progress_bar)
.after(apply_custom_style_to_root)
.after(apply_custom_style_to_scroll)
.after(apply_custom_style_to_text)
.after(apply_custom_style_to_slider)
.after(apply_custom_style_to_radio)
.after(apply_custom_style_to_radio_group)
.after(apply_custom_style_to_select)
.after(apply_custom_style_to_text_input)
)
);
match self.run_schedule {
RunSchedule::AtUpdate => { app.add_systems(Update, systems); },
RunSchedule::AtPreUpdate => { app.add_systems(PreUpdate, systems); },
RunSchedule::AtPostUpdate => { app.add_systems(PostUpdate, systems); },
}
}
}
fn setup(
mut commands: Commands,
mut custom_font: ResMut<CustomFont>,
asset_server: Res<AssetServer>
) {
commands.spawn(Camera2d);
if !custom_font.font_path.is_empty() {
let handle: Handle<Font> = asset_server.load(&custom_font.font_path);
custom_font.font_handle = Some(handle);
}
}
fn detect_makara_text_added(
mut texts: Query<&mut TextFont, Added<MakaraText>>,
custom_font: Res<CustomFont>
) {
for mut text_font in texts.iter_mut() {
if let Some(handle) = &custom_font.font_handle {
text_font.font = handle.clone();
}
}
}
fn check_unique_id(
all_ids: Query<&Id>,
new_ids: Query<Entity, Added<Id>>
) {
if new_ids.is_empty() {
return;
}
let mut seen = HashSet::new();
for id in all_ids.iter() {
if id.0.is_empty() {
continue;
}
if !seen.insert(&id.0) {
panic!("Duplicate ID: '{}'. ID must be unique!", id.0);
}
}
}
}
pub use prelude::*;