refactor(core/rust/ui): expose page count to python

[no changelog]
pull/2357/head
Martin Milata 2 years ago
parent ee1497b87e
commit dd9a7d30e5

@ -30,6 +30,7 @@ static void _librust_qstrs(void) {
MP_QSTR_paint; MP_QSTR_paint;
MP_QSTR_trace; MP_QSTR_trace;
MP_QSTR_bounds; MP_QSTR_bounds;
MP_QSTR_page_count;
MP_QSTR_title; MP_QSTR_title;
MP_QSTR_action; MP_QSTR_action;

@ -314,6 +314,7 @@ pub struct EventCtx {
place_requested: bool, place_requested: bool,
paint_requested: bool, paint_requested: bool,
anim_frame_scheduled: bool, anim_frame_scheduled: bool,
page_count: Option<usize>,
} }
impl EventCtx { impl EventCtx {
@ -338,6 +339,7 @@ impl EventCtx {
paint_requested: false, /* We also need to paint, but this is supplemented by paint_requested: false, /* We also need to paint, but this is supplemented by
* `Child::marked_for_paint` being true. */ * `Child::marked_for_paint` being true. */
anim_frame_scheduled: false, anim_frame_scheduled: false,
page_count: None,
} }
} }
@ -376,6 +378,16 @@ impl EventCtx {
} }
} }
pub fn set_page_count(&mut self, count: usize) {
#[cfg(feature = "ui_debug")]
assert!(self.page_count.is_none());
self.page_count = Some(count);
}
pub fn page_count(&self) -> Option<usize> {
self.page_count
}
pub fn pop_timer(&mut self) -> Option<(TimerToken, Duration)> { pub fn pop_timer(&mut self) -> Option<(TimerToken, Duration)> {
self.timers.pop() self.timers.pop()
} }
@ -384,6 +396,7 @@ impl EventCtx {
self.place_requested = false; self.place_requested = false;
self.paint_requested = false; self.paint_requested = false;
self.anim_frame_scheduled = false; self.anim_frame_scheduled = false;
self.page_count = None;
} }
fn register_timer(&mut self, token: TimerToken, deadline: Duration) { fn register_timer(&mut self, token: TimerToken, deadline: Duration) {

@ -112,6 +112,7 @@ struct LayoutObjInner {
root: Gc<dyn ObjComponent>, root: Gc<dyn ObjComponent>,
event_ctx: EventCtx, event_ctx: EventCtx,
timer_fn: Obj, timer_fn: Obj,
page_count: u16,
} }
impl LayoutObj { impl LayoutObj {
@ -130,6 +131,7 @@ impl LayoutObj {
root, root,
event_ctx: EventCtx::new(), event_ctx: EventCtx::new(),
timer_fn: Obj::const_none(), timer_fn: Obj::const_none(),
page_count: 1,
}), }),
}) })
} }
@ -174,6 +176,10 @@ impl LayoutObj {
} }
} }
if let Some(count) = inner.event_ctx.page_count() {
inner.page_count = count as u16;
}
Ok(msg) Ok(msg)
} }
@ -247,6 +253,10 @@ impl LayoutObj {
.trace(&mut CallbackTracer(callback)); .trace(&mut CallbackTracer(callback));
} }
fn obj_page_count(&self) -> Obj {
self.inner.borrow().page_count.into()
}
#[cfg(feature = "ui_debug")] #[cfg(feature = "ui_debug")]
fn obj_bounds(&self) { fn obj_bounds(&self) {
use crate::ui::display; use crate::ui::display;
@ -275,6 +285,7 @@ impl LayoutObj {
Qstr::MP_QSTR_paint => obj_fn_1!(ui_layout_paint).as_obj(), Qstr::MP_QSTR_paint => obj_fn_1!(ui_layout_paint).as_obj(),
Qstr::MP_QSTR_trace => obj_fn_2!(ui_layout_trace).as_obj(), Qstr::MP_QSTR_trace => obj_fn_2!(ui_layout_trace).as_obj(),
Qstr::MP_QSTR_bounds => obj_fn_1!(ui_layout_bounds).as_obj(), Qstr::MP_QSTR_bounds => obj_fn_1!(ui_layout_bounds).as_obj(),
Qstr::MP_QSTR_page_count => obj_fn_1!(ui_layout_page_count).as_obj(),
}), }),
}; };
&TYPE &TYPE
@ -411,6 +422,14 @@ extern "C" fn ui_layout_paint(this: Obj) -> Obj {
unsafe { util::try_or_raise(block) } unsafe { util::try_or_raise(block) }
} }
extern "C" fn ui_layout_page_count(this: Obj) -> Obj {
let block = || {
let this: Gc<LayoutObj> = this.try_into()?;
Ok(this.obj_page_count())
};
unsafe { util::try_or_raise(block) }
}
#[cfg(feature = "ui_debug")] #[cfg(feature = "ui_debug")]
#[no_mangle] #[no_mangle]
pub extern "C" fn ui_debug_layout_type() -> &'static Type { pub extern "C" fn ui_debug_layout_type() -> &'static Type {

@ -67,6 +67,7 @@ where
} }
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> { fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
ctx.set_page_count(self.scrollbar.page_count);
if self.scrollbar.has_previous_page() { if self.scrollbar.has_previous_page() {
if let Some(ButtonMsg::Clicked) = self.prev.event(ctx, event) { if let Some(ButtonMsg::Clicked) = self.prev.event(ctx, event) {
// Scroll up. // Scroll up.

@ -67,6 +67,7 @@ where
} }
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> { fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
ctx.set_page_count(self.scrollbar.page_count);
if self.scrollbar.has_previous_page() { if self.scrollbar.has_previous_page() {
if let Some(ButtonMsg::Clicked) = self.prev.event(ctx, event) { if let Some(ButtonMsg::Clicked) = self.prev.event(ctx, event) {
// Scroll up. // Scroll up.

@ -99,6 +99,7 @@ where
} }
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> { fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
ctx.set_page_count(self.scrollbar.page_count);
if let Some(swipe) = self.swipe.event(ctx, event) { if let Some(swipe) = self.swipe.event(ctx, event) {
match swipe { match swipe {
SwipeDirection::Up => { SwipeDirection::Up => {
@ -339,6 +340,7 @@ mod tests {
TouchEvent::TouchMove(p) TouchEvent::TouchMove(p)
}; };
component.event(&mut ctx, Event::Touch(ev)); component.event(&mut ctx, Event::Touch(ev));
ctx.clear();
first = false; first = false;
} }
} }

@ -577,11 +577,19 @@ class spawn(Syscall):
class Timer(Syscall): class Timer(Syscall):
def __init__(self) -> None: def __init__(self) -> None:
self.task: Task | None = None self.task: Task | None = None
# Event::Attach is evaluated before task is set. Use this list to
# buffer timers until task is set.
self.before_task: list[tuple[int, Any]] = []
def handle(self, task: Task) -> None: def handle(self, task: Task) -> None:
self.task = task self.task = task
for deadline, value in self.before_task:
schedule(self.task, value, deadline)
self.before_task.clear()
def schedule(self, deadline: int, value: Any) -> None: def schedule(self, deadline: int, value: Any) -> None:
deadline = utime.ticks_add(utime.ticks_ms(), deadline) deadline = utime.ticks_add(utime.ticks_ms(), deadline)
if self.task is not None: if self.task is not None:
schedule(self.task, value, deadline) schedule(self.task, value, deadline)
else:
self.before_task.append((deadline, value))

@ -16,11 +16,15 @@ async def button_request(
ctx: wire.GenericContext, ctx: wire.GenericContext,
br_type: str, br_type: str,
code: ButtonRequestType = ButtonRequestType.Other, code: ButtonRequestType = ButtonRequestType.Other,
pages: int | None = None,
) -> None: ) -> None:
if __debug__: if __debug__:
log.debug(__name__, "ButtonRequest.type=%s", br_type) log.debug(__name__, "ButtonRequest.type=%s", br_type)
workflow.close_others() workflow.close_others()
await ctx.call(ButtonRequest(code=code), ButtonAck) if pages is not None:
await ctx.call(ButtonRequest(code=code, pages=pages), ButtonAck)
else:
await ctx.call(ButtonRequest(code=code), ButtonAck)
async def interact( async def interact(
@ -34,6 +38,9 @@ async def interact(
assert isinstance(layout, Paginated) assert isinstance(layout, Paginated)
return await layout.interact(ctx, code=br_code) return await layout.interact(ctx, code=br_code)
elif hasattr(layout, "page_count") and layout.page_count() > 1: # type: ignore [Cannot access member "page_count" for type "LayoutType"]
await button_request(ctx, br_type, br_code, pages=layout.page_count()) # type: ignore [Cannot access member "page_count" for type "LayoutType"]
return await ctx.wait(layout)
else: else:
await button_request(ctx, br_type, br_code) await button_request(ctx, br_type, br_code)
return await ctx.wait(layout) return await ctx.wait(layout)

@ -19,6 +19,7 @@ class _RustLayout(ui.Layout):
def __init__(self, layout: Any): def __init__(self, layout: Any):
self.layout = layout self.layout = layout
self.timer = loop.Timer() self.timer = loop.Timer()
self.layout.attach_timer_fn(self.set_timer)
def set_timer(self, token: int, deadline: int) -> None: def set_timer(self, token: int, deadline: int) -> None:
self.timer.schedule(deadline, token) self.timer.schedule(deadline, token)
@ -71,7 +72,6 @@ class _RustLayout(ui.Layout):
def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator] def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator]
touch = loop.wait(io.TOUCH) touch = loop.wait(io.TOUCH)
self._before_render() self._before_render()
self.layout.attach_timer_fn(self.set_timer)
self.layout.paint() self.layout.paint()
# self.layout.bounds() # self.layout.bounds()
while True: while True:
@ -95,6 +95,9 @@ class _RustLayout(ui.Layout):
if msg is not None: if msg is not None:
raise ui.Result(msg) raise ui.Result(msg)
def page_count(self) -> int:
return self.layout.page_count()
async def confirm_action( async def confirm_action(
ctx: wire.GenericContext, ctx: wire.GenericContext,

Loading…
Cancel
Save