use std::fmt::Debug;
use crate::{common::{CommonError, CommonErrorType, CommonResult},
Component, DialogEngine, DialogEngineApi, DialogEngineApplyResponse,
DialogEngineArgs, DialogEngineConfigOptions, EditorEngineConfig,
EventPropagation, FlexBox, FlexBoxId, GlobalData, HasDialogBuffers,
HasFocus, InputEvent, OnDialogEditorChangeFn, OnDialogPressFn,
RenderPipeline, SurfaceBounds, DEBUG_TUI_MOD};
#[derive(Debug, Default)]
pub struct DialogComponent<S, AS>
where
S: Debug + Default + Clone + Sync + Send,
AS: Debug + Default + Clone + Sync + Send,
{
pub data: DialogComponentData<S, AS>,
}
#[derive(Debug, Default)]
pub struct DialogComponentData<S, AS>
where
S: Debug + Default + Clone + Sync + Send,
AS: Debug + Default + Clone + Sync + Send,
{
pub id: FlexBoxId,
pub dialog_engine: DialogEngine,
pub on_dialog_press_handler: Option<OnDialogPressFn<S, AS>>,
pub on_dialog_editor_change_handler: Option<OnDialogEditorChangeFn<S, AS>>,
_phantom: std::marker::PhantomData<AS>,
}
impl<S, AS> Component<S, AS> for DialogComponent<S, AS>
where
S: Debug + Default + Clone + Sync + Send + HasDialogBuffers,
AS: Debug + Default + Clone + Sync + Send,
{
fn reset(&mut self) { self.data.dialog_engine.reset(); }
fn get_id(&self) -> FlexBoxId { self.data.id }
fn render(
&mut self,
global_data: &mut GlobalData<S, AS>,
_current_box: FlexBox,
surface_bounds: SurfaceBounds,
has_focus: &mut HasFocus,
) -> CommonResult<RenderPipeline> {
let GlobalData { state, .. } = global_data;
let DialogComponentData {
id, dialog_engine, ..
} = &mut self.data;
let self_id = *id;
dialog_engine.maybe_surface_bounds = Some(surface_bounds);
match state.get_mut_dialog_buffer(self_id) {
Some(_) => {
let args = {
DialogEngineArgs {
self_id,
global_data,
engine: dialog_engine,
has_focus,
}
};
DialogEngineApi::render_engine(args)
}
None => Ok(RenderPipeline::default()),
}
}
fn handle_event(
&mut self,
global_data: &mut GlobalData<S, AS>,
input_event: InputEvent,
has_focus: &mut HasFocus,
) -> CommonResult<EventPropagation> {
let GlobalData {
state,
main_thread_channel_sender,
..
} = global_data;
let DialogComponentData {
id,
dialog_engine,
on_dialog_press_handler,
on_dialog_editor_change_handler,
..
} = &mut self.data;
let id = *id;
if state.get_mut_dialog_buffer(id).is_some() {
use DialogEngineApplyResponse::{DialogChoice, Noop,
SelectScrollResultsPanel, UpdateEditorBuffer};
match DialogEngineApi::apply_event::<S, AS>(
state,
id,
dialog_engine,
input_event,
)? {
DialogChoice(dialog_choice) => {
has_focus.reset_modal_id();
DEBUG_TUI_MOD.then(|| {
tracing::debug!(
message = "🐝 restore focus to non modal",
has_focus = ?has_focus
);
});
if let Some(fun) = &on_dialog_press_handler {
fun(
dialog_choice,
state,
&mut main_thread_channel_sender.clone(),
);
}
Ok(EventPropagation::ConsumedRender)
}
UpdateEditorBuffer => {
if let Some(it) = &on_dialog_editor_change_handler {
it(state, &mut main_thread_channel_sender.clone());
}
Ok(EventPropagation::ConsumedRender)
}
SelectScrollResultsPanel => Ok(EventPropagation::ConsumedRender),
Noop => Ok(EventPropagation::Propagate),
}
} else {
let msg = format!(
"🐝 DialogComponent::handle_event: dialog_buffer is None for id: {id:?}"
);
CommonError::new_error_result(CommonErrorType::NotFound, &msg)
}
}
}
impl<S, AS> DialogComponent<S, AS>
where
S: Debug + Default + Clone + Sync + Send,
AS: Debug + Default + Clone + Sync + Send,
{
pub fn new(
id: FlexBoxId,
dialog_options: DialogEngineConfigOptions,
editor_options: EditorEngineConfig,
on_dialog_press_handler: OnDialogPressFn<S, AS>,
on_dialog_editor_change_handler: OnDialogEditorChangeFn<S, AS>,
) -> Self {
let dialog_engine = DialogEngine::new(dialog_options, editor_options);
Self {
data: DialogComponentData {
id,
dialog_engine,
on_dialog_press_handler: Some(on_dialog_press_handler),
on_dialog_editor_change_handler: Some(on_dialog_editor_change_handler),
..Default::default()
},
}
}
pub fn new_boxed(
id: FlexBoxId,
dialog_options: DialogEngineConfigOptions,
editor_options: EditorEngineConfig,
on_dialog_press_handler: OnDialogPressFn<S, AS>,
on_dialog_editor_change_handler: OnDialogEditorChangeFn<S, AS>,
) -> Box<Self> {
let it = DialogComponent::new(
id,
dialog_options,
editor_options,
on_dialog_press_handler,
on_dialog_editor_change_handler,
);
Box::new(it)
}
}