Skip to content

Commit 1106fcf

Browse files
authored
Merge pull request betrusted-io#277 from gsora/feat/slider-widget
feat: user interaction-enabled slider
2 parents 08de49d + d57088a commit 1106fcf

File tree

6 files changed

+113
-3
lines changed

6 files changed

+113
-3
lines changed

services/gam/src/modal.rs

+8
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,14 @@ impl TextEntryPayload {
115115
}
116116
}
117117

118+
#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
119+
pub struct SliderPayload(pub u32);
120+
impl SliderPayload {
121+
pub fn new(value: u32) -> Self {
122+
SliderPayload(value)
123+
}
124+
}
125+
118126
#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
119127
pub struct RadioButtonPayload(pub ItemName); // returns the name of the item corresponding to the radio button selection
120128
impl RadioButtonPayload {

services/gam/src/modal/slider.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ impl Slider {
4747
show_legend,
4848
}
4949
}
50+
51+
pub fn set_is_progressbar(&mut self, setting: bool) {
52+
self.is_progressbar = setting;
53+
}
54+
5055
pub fn set_is_password(&mut self, setting: bool) {
5156
// this will cause text to be inverted. Untrusted entities can try to set this,
5257
// but the GAM should defeat this for dialog boxes outside of the trusted boot
@@ -194,8 +199,11 @@ impl ActionApi for Slider {
194199
gam.relinquish_focus().unwrap();
195200
xous::yield_slice();
196201

197-
send_message(self.action_conn,
198-
xous::Message::new_scalar(self.action_opcode as usize, self.action_payload as usize, 0, 0, 0)).expect("couldn't pass on action payload");
202+
let ret_payload = SliderPayload(self.action_payload);
203+
204+
let buf = Buffer::into_buf(ret_payload).expect("couldn't convert message to payload");
205+
buf.send(self.action_conn, self.action_opcode).map(|_| ()).expect("couldn't send action message");
206+
199207
return None;
200208
}
201209
_ => {

services/modals/src/api.rs

+4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ pub struct ManagedProgress {
6969
pub end_work: u32,
7070
/// current quanta of work. Used to int the bar, updates are just a scalar with the same value.
7171
pub current_work: u32,
72+
/// can user interact with it?
73+
pub user_interaction: bool,
7274
}
7375

7476
/// This isn't a terribly useful notification -- it's basically read-only, no interactivity,
@@ -98,6 +100,8 @@ pub(crate) enum Opcode {
98100
Bip39 = 31, // ---- note op number
99101
Bip39Input = 32, // ----- note op number
100102
Bip39Return = 33, // ----- note op number
103+
SliderReturn = 34,
104+
Slider = 35,
101105
/// display an image
102106
#[cfg(feature = "ditherpunk")]
103107
Image = 3,

services/modals/src/lib.rs

+27
Original file line numberDiff line numberDiff line change
@@ -302,13 +302,40 @@ impl Modals {
302302
start_work: start,
303303
end_work: end,
304304
current_work: current,
305+
user_interaction: false,
305306
};
306307
let buf = Buffer::into_buf(spec).or(Err(xous::Error::InternalError))?;
307308
buf.lend(self.conn, Opcode::StartProgress.to_u32().unwrap())
308309
.or(Err(xous::Error::InternalError))?;
309310
Ok(())
310311
}
311312

313+
pub fn slider(
314+
&self,
315+
title: &str,
316+
start: u32,
317+
end: u32,
318+
current: u32,
319+
) -> Result<u32, xous::Error> {
320+
self.lock();
321+
let spec = ManagedProgress {
322+
token: self.token,
323+
title: xous_ipc::String::from_str(title),
324+
start_work: start,
325+
end_work: end,
326+
current_work: current,
327+
user_interaction: true,
328+
};
329+
let mut buf = Buffer::into_buf(spec).or(Err(xous::Error::InternalError))?;
330+
buf.lend_mut(self.conn, Opcode::Slider.to_u32().unwrap())
331+
.or(Err(xous::Error::InternalError))?;
332+
333+
let orig = buf.to_original::<SliderPayload, _>().unwrap();
334+
335+
self.unlock();
336+
Ok(orig.0)
337+
}
338+
312339
/// note that this API is not atomically token-locked, so, someone could mess with the progress bar state
313340
/// but, progress updates are meant to be fast and frequent, and generally if a progress bar shows
314341
/// something whacky it's not going to affect a security outcome

services/modals/src/main.rs

+47-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ fn wrapped_main() -> ! {
113113
let mut fixed_items = Vec::<ItemName>::new();
114114
let mut progress_action = Slider::new(
115115
renderer_cid,
116-
Opcode::Gutter.to_u32().unwrap(),
116+
Opcode::SliderReturn.to_u32().unwrap(),
117117
0,
118118
100,
119119
1,
@@ -332,6 +332,24 @@ fn wrapped_main() -> ! {
332332
)
333333
.expect("couldn't initiate UX op");
334334
}
335+
Some(Opcode::Slider) => {
336+
let spec = {
337+
let buffer =
338+
unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) };
339+
buffer.to_original::<ManagedProgress, _>().unwrap()
340+
};
341+
if spec.token != token_lock.unwrap_or(default_nonce) {
342+
log::warn!("Attempt to access modals without a mutex lock. Ignoring.");
343+
continue;
344+
}
345+
op = RendererState::RunProgress(spec);
346+
dr = Some(msg);
347+
send_message(
348+
renderer_cid,
349+
Message::new_scalar(Opcode::InitiateOp.to_usize().unwrap(), 0, 0, 0, 0),
350+
)
351+
.expect("couldn't initiate UX op");
352+
}
335353
Some(Opcode::StopProgress) => msg_blocking_scalar_unpack!(msg, t0, t1, t2, t3, {
336354
let token = [t0 as u32, t1 as u32, t2 as u32, t3 as u32];
337355
if token != token_lock.unwrap_or(default_nonce) {
@@ -593,6 +611,7 @@ fn wrapped_main() -> ! {
593611
end_work
594612
);
595613
progress_action.set_state(last_percentage);
614+
progress_action.set_is_progressbar(!config.user_interaction);
596615
#[cfg(feature = "tts")]
597616
tts.tts_simple(config.title.as_str().unwrap()).unwrap();
598617
renderer_modal.modify(
@@ -603,6 +622,7 @@ fn wrapped_main() -> ! {
603622
true,
604623
Some(DEFAULT_STYLE),
605624
);
625+
606626
renderer_modal.activate();
607627
}
608628
RendererState::RunRadio(config) => {
@@ -764,6 +784,32 @@ fn wrapped_main() -> ! {
764784
xous::return_scalar2(sender, 1, k).unwrap();
765785
}
766786
}),
787+
Some(Opcode::SliderReturn) => match op {
788+
RendererState::RunProgress(_) => {
789+
let buffer =
790+
unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) };
791+
let item = buffer.to_original::<SliderPayload, _>().unwrap();
792+
793+
if let Some(mut origin) = dr.take() {
794+
let mut response = unsafe {
795+
Buffer::from_memory_message_mut(
796+
origin.body.memory_message_mut().unwrap(),
797+
)
798+
};
799+
800+
response.replace(item).unwrap();
801+
op = RendererState::None;
802+
803+
token_lock = next_lock(&mut work_queue);
804+
} else {
805+
log::error!("Ux routine returned but no origin was recorded");
806+
panic!("Ux routine returned but no origin was recorded");
807+
}
808+
},
809+
_ => {
810+
log::warn!("got weird stuff on slider return, ignoring");
811+
}
812+
},
767813
Some(Opcode::TextEntryReturn) => match op {
768814
RendererState::RunText(_config) => {
769815
log::trace!("validating text entry modal");

services/modals/src/tests.rs

+17
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,20 @@ pub fn spawn_test() {
9696
}
9797
Err(e) => log::error!("couldn't get input: {:?}", e),
9898
}
99+
100+
// 6. human interaction-enabled slider
101+
log::info!("testing human interaction-enabled slider");
102+
let result = modals.slider(
103+
"Human interaction-enabled slider!",
104+
0,
105+
100,
106+
50,
107+
).expect("slider test failed");
108+
109+
modals.show_notification(&format!("Slider value: {}", result), None)
110+
.expect("cannot show slider result notification");
111+
112+
log::info!("slider test done");
99113
}
100114
});
101115

@@ -165,6 +179,9 @@ pub fn spawn_test() {
165179
modals.show_image(bm).expect("show image modal failed");
166180
log::info!("image modal test done");
167181
}
182+
183+
// 6. test that human-interactable slider modal
184+
log::info!("testing human interaction-enabled modal");
168185
}
169186
});
170187
}

0 commit comments

Comments
 (0)