#![cfg_attr(target_arch = "xtensa", no_std, no_main)]
#![cfg_attr(
target_arch = "xtensa",
feature(impl_trait_in_assoc_type, type_alias_impl_trait)
)]
use core::ffi::c_void;
use core::ptr::null_mut;
use oxivgl::{
anim::{Anim, anim_path_ease_in_out, anim_set_x},
enums::{EventCode, ObjFlag, ObjState, ScrollDir},
event::Event,
layout::{FlexAlign, FlexFlow},
style::{Selector, lv_pct},
view::{NavAction, View},
widgets::{Align, AsLvHandle, Button, Child, Dropdown, Label, Obj, Roller, RollerMode, Slider, Subject, WidgetError},
};
const DROPDOWN_OPTIONS: &str = "Red\nGreen\nBlue";
const ROLLER_OPTIONS: &str = "Alpha\nBeta\nGamma\nDelta\nEpsilon";
#[derive(Default)]
struct Observer4 {
_main_cont: Option<Obj<'static>>,
cont: Option<Obj<'static>>,
footer: Option<Obj<'static>>,
indicator: Option<Obj<'static>>,
btn_handles: [*mut c_void; 3],
last_tab: i32,
tab_subject: Option<Subject>,
slider_subjects: Option<[Subject; 4]>,
dropdown_subjects: Option<[Subject; 3]>,
roller_subjects: Option<[Subject; 2]>,
}
impl View for Observer4 {
fn create(&mut self, container: &Obj<'static>) -> Result<(), WidgetError> {
let tab_subject = Subject::new_int(0);
let slider_subjects = [
Subject::new_int(25),
Subject::new_int(50),
Subject::new_int(75),
Subject::new_int(40),
];
let dropdown_subjects = [
Subject::new_int(0),
Subject::new_int(1),
Subject::new_int(2),
];
let roller_subjects = [
Subject::new_int(0),
Subject::new_int(2),
];
let main_cont = Obj::new(container)?;
main_cont
.remove_style_all()
.size(lv_pct(100), lv_pct(100))
.pad(0)
.set_flex_flow(FlexFlow::Column);
let cont = Obj::new(&main_cont)?;
cont.remove_style_all()
.set_flex_grow(1)
.pad(8)
.width(lv_pct(100))
.set_scroll_dir(ScrollDir::VER);
let footer = Obj::new(&main_cont)?;
footer
.remove_style_all()
.size(lv_pct(100), 60)
.style_pad_column(8, Selector::DEFAULT)
.pad(8)
.set_flex_flow(FlexFlow::Row)
.set_flex_align(FlexAlign::Center, FlexAlign::Center, FlexAlign::Center);
let btn_labels = ["First", "Second", "Third"];
let mut btn_handles: [*mut c_void; 3] = [null_mut(); 3];
for (i, lbl_text) in btn_labels.iter().enumerate() {
let btn = Child::new(Button::new(&footer)?);
btn.set_flex_grow(1)
.height(lv_pct(100))
.radius(0, Selector::DEFAULT)
.bubble_events();
btn.bind_state_if_eq(&tab_subject, ObjState::CHECKED, i as i32);
let lbl = Child::new(Label::new(&*btn)?);
lbl.text(lbl_text).center();
btn_handles[i] = btn.lv_handle() as *mut c_void;
}
let indicator = Obj::new(&footer)?;
indicator
.remove_style(None, Selector::DEFAULT)
.bg_opa(102) .height(10)
.align(Align::BottomLeft, 0, 0)
.add_flag(ObjFlag::IGNORE_LAYOUT);
indicator.update_layout();
tab_subject.notify();
self._main_cont = Some(main_cont);
self.cont = Some(cont);
self.footer = Some(footer);
self.indicator = Some(indicator);
self.btn_handles = btn_handles;
self.last_tab = -1; self.tab_subject = Some(tab_subject);
self.slider_subjects = Some(slider_subjects);
self.dropdown_subjects = Some(dropdown_subjects);
self.roller_subjects = Some(roller_subjects);
Ok(())
}
fn on_event(&mut self, event: &Event) -> NavAction {
if event.code() != EventCode::CLICKED {
return NavAction::None;
}
let target = event.target_handle() as *mut c_void;
for (i, &handle) in self.btn_handles.iter().enumerate() {
if !handle.is_null() && target == handle {
if let Some(ref tab_subject) = self.tab_subject {
tab_subject.set_int(i as i32);
}
return NavAction::None;
}
}
NavAction::None
}
fn update(&mut self) -> Result<NavAction, WidgetError> {
let tab = if let Some(ref ts) = self.tab_subject { ts.get_int() } else { return Ok(NavAction::None); };
if tab == self.last_tab {
return Ok(NavAction::None);
}
self.last_tab = tab;
let Some(ref cont) = self.cont else { return Ok(NavAction::None); };
cont.clean();
match tab {
0 => {
if let Some(ref slider_subjects) = self.slider_subjects {
for i in 0..4_i32 {
let slider = Child::new(Slider::new(cont)?);
slider
.set_range(0, 100)
.align(Align::TopMid, 0, 10 + i * 30);
slider.bind_value(&slider_subjects[i as usize]);
}
}
}
1 => {
if let Some(ref dropdown_subjects) = self.dropdown_subjects {
for i in 0..3_i32 {
let dd = Child::new(Dropdown::new(cont)?);
dd.set_options(DROPDOWN_OPTIONS)
.align(Align::TopMid, 0, i * 50);
dd.bind_value(&dropdown_subjects[i as usize]);
}
}
}
2 => {
if let Some(ref roller_subjects) = self.roller_subjects {
for i in 0..2_i32 {
let roller = Child::new(Roller::new(cont)?);
roller
.set_options(ROLLER_OPTIONS, RollerMode::Normal)
.align(Align::Center, -80 + i * 160, 0);
roller.bind_value(&roller_subjects[i as usize]);
}
}
}
_ => {}
}
if let Some(ref footer) = self.footer {
if let Some(btn_child) = footer.get_child(tab) {
let btn_x = btn_child.get_x();
let btn_w = btn_child.get_width();
if let Some(ref indicator) = self.indicator {
let ind_x = indicator.get_x();
indicator.width(btn_w);
let mut anim = Anim::new();
anim.set_var(indicator)
.set_exec_cb(Some(anim_set_x))
.set_values(ind_x, btn_x)
.set_duration(300)
.set_path_cb(Some(anim_path_ease_in_out));
anim.start();
}
}
}
Ok(NavAction::None)
}
}
oxivgl_examples_common::example_main!(Observer4::default());