use std::{borrow::Cow, fmt::Debug, sync::Arc};
use async_trait::async_trait;
use r3bl_rs_utils_core::*;
use tokio::sync::RwLock;
use crate::*;
#[derive(Clone, Default)]
pub struct DialogComponent<S, A>
where
S: Debug + Default + Clone + PartialEq + Sync + Send,
A: Debug + Default + Clone + Sync + Send,
{
pub id: FlexBoxId,
pub dialog_engine: DialogEngine,
pub on_dialog_press_handler: Option<OnDialogPressFn<S, A>>,
pub on_dialog_editor_change_handler: Option<OnDialogEditorChangeFn<S, A>>,
}
#[async_trait]
impl<S, A> Component<S, A> for DialogComponent<S, A>
where
S: HasDialogBuffers + Default + Clone + PartialEq + Debug + Sync + Send,
A: Debug + Default + Clone + Sync + Send,
{
fn reset(&mut self) { self.dialog_engine.reset(); }
fn get_id(&self) -> FlexBoxId { self.id }
async fn render(
&mut self,
args: ComponentScopeArgs<'_, S, A>,
_current_box: &FlexBox,
surface_bounds: SurfaceBounds,
) -> CommonResult<RenderPipeline> {
self.dialog_engine.maybe_surface_bounds = Some(surface_bounds);
let ComponentScopeArgs {
state,
shared_store,
shared_global_data,
component_registry,
window_size,
} = args;
let dialog_buffer: Cow<DialogBuffer> =
if let Some(it) = state.get_dialog_buffer(self.get_id()) {
Cow::Borrowed(it)
} else {
Cow::Owned(DialogBuffer::new_empty())
};
let dialog_engine_args = {
DialogEngineArgs {
shared_global_data,
shared_store,
state,
component_registry,
self_id: self.get_id(),
dialog_engine: &mut self.dialog_engine,
dialog_buffer: &dialog_buffer,
window_size,
}
};
DialogEngineApi::render_engine(dialog_engine_args).await
}
async fn handle_event(
&mut self,
args: ComponentScopeArgs<'_, S, A>,
input_event: &InputEvent,
) -> CommonResult<EventPropagation> {
let ComponentScopeArgs {
state,
shared_store,
shared_global_data,
component_registry,
window_size,
} = args;
let dialog_buffer: Cow<DialogBuffer> =
if let Some(it) = state.get_dialog_buffer(self.get_id()) {
Cow::Borrowed(it)
} else {
Cow::Owned(DialogBuffer::new_empty())
};
let dialog_engine_args = {
DialogEngineArgs {
shared_global_data,
shared_store,
state,
component_registry,
self_id: self.get_id(),
dialog_engine: &mut self.dialog_engine,
dialog_buffer: &dialog_buffer,
window_size,
}
};
match DialogEngineApi::apply_event(dialog_engine_args, input_event).await? {
DialogEngineApplyResponse::DialogChoice(dialog_choice) => {
component_registry.has_focus.reset_modal_id();
call_if_true!(DEBUG_TUI_MOD, {
let msg = format!(
"🐝 restore focus to non modal: {:?}",
component_registry.has_focus
);
log_debug(msg);
});
if let Some(it) = &self.on_dialog_press_handler {
it(dialog_choice, shared_store);
};
Ok(EventPropagation::ConsumedRender)
}
DialogEngineApplyResponse::UpdateEditorBuffer(new_editor_buffer) => {
if let Some(it) = &self.on_dialog_editor_change_handler {
it(new_editor_buffer, shared_store);
};
Ok(EventPropagation::Consumed)
}
DialogEngineApplyResponse::SelectScrollResultsPanel => {
Ok(EventPropagation::ConsumedRender)
}
_ => Ok(EventPropagation::Propagate),
}
}
}
impl<S, A> DialogComponent<S, A>
where
S: Debug + Default + Clone + PartialEq + Sync + Send,
A: Debug + Default + Clone + Sync + Send,
{
pub fn new(
id: FlexBoxId,
dialog_options: DialogEngineConfigOptions,
editor_options: EditorEngineConfig,
on_dialog_press_handler: OnDialogPressFn<S, A>,
on_dialog_editor_change_handler: OnDialogEditorChangeFn<S, A>,
) -> Self {
Self {
dialog_engine: DialogEngine::new(dialog_options, editor_options),
id,
on_dialog_press_handler: Some(on_dialog_press_handler),
on_dialog_editor_change_handler: Some(on_dialog_editor_change_handler),
}
}
pub fn new_shared(
id: FlexBoxId,
dialog_options: DialogEngineConfigOptions,
editor_options: EditorEngineConfig,
on_dialog_press_handler: OnDialogPressFn<S, A>,
on_dialog_editor_change_handler: OnDialogEditorChangeFn<S, A>,
) -> Arc<RwLock<Self>> {
Arc::new(RwLock::new(DialogComponent::new(
id,
dialog_options,
editor_options,
on_dialog_press_handler,
on_dialog_editor_change_handler,
)))
}
}