use std::collections::BTreeMap;
use azul_core::{
dom::{DomId, DomNodeId, NodeId},
events::{EventData, EventProvider, EventSource as CoreEventSource, EventType, SyntheticEvent},
selection::TextCursor,
task::Instant,
};
use azul_css::corety::AzString;
#[derive(Debug, Clone)]
#[repr(C)]
pub struct PendingTextEdit {
pub node: DomNodeId,
pub inserted_text: AzString,
pub old_text: AzString,
}
impl PendingTextEdit {
pub fn resulting_text(&self, cursor: Option<&TextCursor>) -> AzString {
let mut result = self.old_text.as_str().to_string();
result.push_str(self.inserted_text.as_str());
let _ = cursor;
result.into()
}
}
#[derive(Debug, Clone)]
#[repr(C, u8)]
pub enum OptionPendingTextEdit {
None,
Some(PendingTextEdit),
}
impl OptionPendingTextEdit {
pub fn into_option(self) -> Option<PendingTextEdit> {
match self {
OptionPendingTextEdit::None => None,
OptionPendingTextEdit::Some(t) => Some(t),
}
}
}
impl From<Option<PendingTextEdit>> for OptionPendingTextEdit {
fn from(o: Option<PendingTextEdit>) -> Self {
match o {
Some(v) => OptionPendingTextEdit::Some(v),
None => OptionPendingTextEdit::None,
}
}
}
impl<'a> From<Option<&'a PendingTextEdit>> for OptionPendingTextEdit {
fn from(o: Option<&'a PendingTextEdit>) -> Self {
match o {
Some(v) => OptionPendingTextEdit::Some(v.clone()),
None => OptionPendingTextEdit::None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextInputSource {
Keyboard,
Ime,
Accessibility,
Programmatic,
}
pub struct TextInputManager {
pub pending_changeset: Option<PendingTextEdit>,
pub input_source: Option<TextInputSource>,
}
impl TextInputManager {
pub fn new() -> Self {
Self {
pending_changeset: None,
input_source: None,
}
}
pub fn record_input(
&mut self,
node: DomNodeId,
inserted_text: String,
old_text: String,
source: TextInputSource,
) -> DomNodeId {
self.pending_changeset = None;
self.pending_changeset = Some(PendingTextEdit {
node,
inserted_text: inserted_text.into(),
old_text: old_text.into(),
});
self.input_source = Some(source);
node
}
pub fn get_pending_changeset(&self) -> Option<&PendingTextEdit> {
self.pending_changeset.as_ref()
}
pub fn clear_changeset(&mut self) {
self.pending_changeset = None;
self.input_source = None;
}
pub fn has_pending_changeset(&self) -> bool {
self.pending_changeset.is_some()
}
}
impl Default for TextInputManager {
fn default() -> Self {
Self::new()
}
}
impl EventProvider for TextInputManager {
fn get_pending_events(&self, timestamp: Instant) -> Vec<SyntheticEvent> {
let mut events = Vec::new();
if let Some(changeset) = &self.pending_changeset {
let event_source = match self.input_source {
Some(TextInputSource::Keyboard) | Some(TextInputSource::Ime) => {
CoreEventSource::User
}
Some(TextInputSource::Accessibility) => CoreEventSource::User,
Some(TextInputSource::Programmatic) => CoreEventSource::Programmatic,
None => CoreEventSource::User,
};
events.push(SyntheticEvent::new(
EventType::Input,
event_source,
changeset.node,
timestamp,
EventData::None,
));
}
events
}
}