mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
feature: generalization of modals.get_text()
Added a get_text_multi() method on modals which builds, shows and returns text taken from a modal view with a given amount of fields. Calling get_text() is equal to a call to get_text_multi() with fields = 1.
This commit is contained in:
parent
83e61f5f1b
commit
0b62a2657a
6 changed files with 77 additions and 18 deletions
|
|
@ -70,7 +70,7 @@ impl ItemName {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub struct TextEntryPayload {
|
||||
pub id: u32,
|
||||
pub content: String::<256>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,15 @@ const MAX_FIELDS: i16 = 10;
|
|||
|
||||
pub type ValidatorErr = xous_ipc::String::<256>;
|
||||
|
||||
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub struct TextEntryPayloads ([TextEntryPayload; MAX_FIELDS as usize]);
|
||||
|
||||
impl TextEntryPayloads {
|
||||
pub fn first(&self) -> TextEntryPayload {
|
||||
self.0[0]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, num_derive::FromPrimitive, num_derive::ToPrimitive)]
|
||||
pub enum TextEntryVisibility {
|
||||
/// text is fully visible
|
||||
|
|
@ -33,6 +42,7 @@ pub struct TextEntry {
|
|||
pub validator: Option<fn(TextEntryPayload, u32) -> Option<ValidatorErr>>,
|
||||
pub action_payloads: Vec<TextEntryPayload>,
|
||||
|
||||
max_field_amount: u32,
|
||||
selected_field: i16,
|
||||
}
|
||||
|
||||
|
|
@ -46,6 +56,7 @@ impl Default for TextEntry {
|
|||
validator: Default::default(),
|
||||
selected_field: Default::default(),
|
||||
action_payloads: Default::default(),
|
||||
max_field_amount: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -75,6 +86,11 @@ impl TextEntry {
|
|||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_action_payloads(&mut self, fields: u32) {
|
||||
self.action_payloads = vec![TextEntryPayload::default(); fields as usize];
|
||||
self.max_field_amount = fields;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -99,7 +115,7 @@ impl ActionApi for TextEntry {
|
|||
|
||||
let glyph_height = match self.action_payloads.len() {
|
||||
0 | 1 => 1,
|
||||
_ => glyph_height * self.action_payloads.len() as i16 + 2,
|
||||
_ => glyph_height * (self.action_payloads.len() as i16 + 2),
|
||||
} as i16;
|
||||
|
||||
if self.is_password {
|
||||
|
|
@ -116,13 +132,21 @@ impl ActionApi for TextEntry {
|
|||
PixelColor::Dark
|
||||
};
|
||||
|
||||
for payload in self.action_payloads.clone() {
|
||||
let mut current_height = at_height;
|
||||
let payloads = self.action_payloads.clone();
|
||||
|
||||
for (index, payload) in payloads.iter().enumerate() {
|
||||
current_height = match index {
|
||||
0 => at_height,
|
||||
_ => current_height + at_height,
|
||||
};
|
||||
|
||||
// draw the currently entered text
|
||||
let mut tv = TextView::new(
|
||||
modal.canvas,
|
||||
TextBounds::BoundingBox(Rectangle::new(
|
||||
Point::new(modal.margin, at_height),
|
||||
Point::new(modal.canvas_width - modal.margin, at_height + modal.line_height))
|
||||
Point::new(modal.margin, current_height),
|
||||
Point::new(modal.canvas_width - modal.margin, current_height + modal.line_height))
|
||||
));
|
||||
tv.ellipsis = true;
|
||||
tv.invert = self.is_password;
|
||||
|
|
@ -266,15 +290,19 @@ impl ActionApi for TextEntry {
|
|||
|
||||
// draw a line for where text gets entered (don't use a box, fitting could be awkward)
|
||||
modal.gam.draw_line(modal.canvas, Line::new_with_style(
|
||||
Point::new(modal.margin, at_height + modal.line_height + 4),
|
||||
Point::new(modal.canvas_width - modal.margin, at_height + modal.line_height + 4),
|
||||
Point::new(modal.margin, current_height + modal.line_height + 4),
|
||||
Point::new(modal.canvas_width - modal.margin, current_height + modal.line_height + 4),
|
||||
DrawStyle::new(color, color, 1))
|
||||
).expect("couldn't draw entry line");
|
||||
|
||||
}
|
||||
}
|
||||
fn key_action(&mut self, k: char) -> (Option<ValidatorErr>, bool) {
|
||||
let mut payload = self.action_payloads[self.selected_field as usize];
|
||||
|
||||
let can_move_downwards = !(self.selected_field+1 == self.max_field_amount as i16);
|
||||
let can_move_upwards = !(self.selected_field-1 < 0);
|
||||
|
||||
log::trace!("key_action: {}", k);
|
||||
match k {
|
||||
'←' => {
|
||||
|
|
@ -311,16 +339,23 @@ impl ActionApi for TextEntry {
|
|||
}
|
||||
}
|
||||
|
||||
let buf = Buffer::into_buf(payload).expect("couldn't convert message to payload");
|
||||
let mut payloads: TextEntryPayloads = Default::default();
|
||||
payloads.0[..self.max_field_amount as usize].copy_from_slice(&self.action_payloads[..self.max_field_amount as usize]);
|
||||
let buf = Buffer::into_buf(payloads).expect("couldn't convert message to payload");
|
||||
buf.send(self.action_conn, self.action_opcode).map(|_| ()).expect("couldn't send action message");
|
||||
payload.volatile_clear(); // ensure the local copy of text is zero'd out
|
||||
// TODO: zero out EVERYTHING here!
|
||||
return (None, true)
|
||||
}
|
||||
'↑' => {
|
||||
self.selected_field -= 1
|
||||
if can_move_upwards {
|
||||
self.selected_field -= 1
|
||||
}
|
||||
}
|
||||
'↓' => {
|
||||
self.selected_field += 1
|
||||
if can_move_downwards {
|
||||
self.selected_field += 1
|
||||
}
|
||||
}
|
||||
'\u{0}' => {
|
||||
// ignore null messages
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ pub struct ManagedPromptWithTextResponse {
|
|||
pub validator: Option<[u32; 4]>,
|
||||
/// the opcode to pass the validator
|
||||
pub validator_op: u32,
|
||||
/// the amount of fields to read
|
||||
pub fields: u32,
|
||||
}
|
||||
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone)]
|
||||
pub struct ManagedNotification {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,20 @@ impl Modals {
|
|||
maybe_validator: Option<fn(TextEntryPayload, u32) -> Option<ValidatorErr>>,
|
||||
maybe_validator_op: Option<u32>,
|
||||
) -> Result<TextEntryPayload, xous::Error> {
|
||||
match self.get_text_multi(prompt, maybe_validator, maybe_validator_op, 1) {
|
||||
Ok(res) => {
|
||||
return Ok(res.first())
|
||||
},
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_text_multi(&self,
|
||||
prompt: &str,
|
||||
maybe_validator: Option<fn(TextEntryPayload, u32) -> Option<ValidatorErr>>,
|
||||
maybe_validator_op: Option<u32>,
|
||||
fields: u32,
|
||||
) -> Result<TextEntryPayloads, xous::Error> {
|
||||
self.lock();
|
||||
let validator = if let Some(validator) = maybe_validator {
|
||||
// create a one-time use server
|
||||
|
|
@ -70,7 +84,8 @@ impl Modals {
|
|||
token: self.token,
|
||||
prompt: xous_ipc::String::from_str(prompt),
|
||||
validator,
|
||||
validator_op: maybe_validator_op.unwrap_or(0)
|
||||
validator_op: maybe_validator_op.unwrap_or(0),
|
||||
fields: fields,
|
||||
};
|
||||
let mut buf = Buffer::into_buf(spec).or(Err(xous::Error::InternalError))?;
|
||||
buf.lend_mut(self.conn, Opcode::PromptWithTextResponse.to_u32().unwrap()).or(Err(xous::Error::InternalError))?;
|
||||
|
|
@ -80,7 +95,7 @@ impl Modals {
|
|||
unsafe{xous::disconnect(cid).unwrap()}; // must disconnect before destroy to avoid the CID from hanging out in our outbound table which is limited to 32 entries
|
||||
xous::destroy_server(SID::from_array(server)).expect("couldn't destroy temporary server");
|
||||
}
|
||||
match buf.to_original::<TextEntryPayload, _>() {
|
||||
match buf.to_original::<TextEntryPayloads, _>() {
|
||||
Ok(response) => Ok(response),
|
||||
_ => Err(xous::Error::InternalError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ enum RendererState {
|
|||
RunProgress(ManagedProgress),
|
||||
RunNotification(ManagedNotification),
|
||||
/// response ready state
|
||||
ResponseText(TextEntryPayload),
|
||||
ResponseText(TextEntryPayloads),
|
||||
ResponseRadio(ItemName),
|
||||
ResponseCheckBox(CheckBoxPayload),
|
||||
RunDynamicNotification(DynamicNotification),
|
||||
|
|
@ -142,8 +142,14 @@ fn xmain() -> ! {
|
|||
log::debug!("initiating text entry modal");
|
||||
#[cfg(feature="tts")]
|
||||
tts.tts_simple(config.prompt.as_str().unwrap()).unwrap();
|
||||
|
||||
renderer_modal.modify(
|
||||
Some(ActionType::TextEntry(text_action.clone())),
|
||||
Some(ActionType::TextEntry({
|
||||
let mut ta = text_action.clone();
|
||||
ta.reset_action_payloads(config.fields);
|
||||
|
||||
ta
|
||||
})),
|
||||
Some(config.prompt.as_str().unwrap()), false,
|
||||
None, true, None
|
||||
);
|
||||
|
|
@ -310,9 +316,10 @@ fn xmain() -> ! {
|
|||
RendererState::RunText(config) => {
|
||||
log::trace!("validating text entry modal");
|
||||
let buf = unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) };
|
||||
let text = buf.to_original::<gam::modal::TextEntryPayload, _>().unwrap();
|
||||
let text = buf.to_original::<gam::modal::TextEntryPayloads, _>().unwrap();
|
||||
// TODO: figure out how to associate validation with id's.
|
||||
if let Some(validator_sid) = config.validator {
|
||||
let cid = xous::connect(SID::from_array(validator_sid)).unwrap();
|
||||
/*let cid = xous::connect(SID::from_array(validator_sid)).unwrap();
|
||||
let validation = Validation {
|
||||
text,
|
||||
opcode: config.validator_op,
|
||||
|
|
@ -332,7 +339,7 @@ fn xmain() -> ! {
|
|||
} else {
|
||||
// the change in mutex_op enum type will signal the state change to the caller
|
||||
*mutex_op = RendererState::ResponseText(text);
|
||||
}
|
||||
}*/
|
||||
} else {
|
||||
*mutex_op = RendererState::ResponseText(text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ pub struct Ver {
|
|||
// TODO: remove me
|
||||
impl Ver {
|
||||
fn modal(&self, env: &mut CommonEnv) {
|
||||
log::info!("modal data: {:?}", env.modals.get_text("Get Text", None, None))
|
||||
log::info!("modal data: {:#?}", env.modals.get_text_multi("Get Text", None, None, 4))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue