use alloc::vec::Vec;
use core::{ops::Deref, ptr::null_mut};
use oxivgl_sys::*;
use super::{
WidgetError,
obj::{Align, AsLvHandle, Obj},
};
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum ScaleMode {
HorizontalTop = 0,
HorizontalBottom = 1,
VerticalLeft = 2,
VerticalRight = 4,
RoundInner = 8,
RoundOuter = 16,
}
pub const SCALE_LABEL_ROTATE_MATCH_TICKS: i32 = oxivgl_sys::LV_SCALE_LABEL_ROTATE_MATCH_TICKS as i32;
pub const SCALE_LABEL_ROTATE_KEEP_UPRIGHT: i32 = oxivgl_sys::LV_SCALE_LABEL_ROTATE_KEEP_UPRIGHT as i32;
#[derive(Debug)]
pub struct Scale<'p> {
obj: Obj<'p>,
section_styles: core::cell::RefCell<Vec<crate::style::Style>>,
}
impl<'p> AsLvHandle for Scale<'p> {
fn lv_handle(&self) -> *mut lv_obj_t {
self.obj.lv_handle()
}
}
impl<'p> Deref for Scale<'p> {
type Target = Obj<'p>;
fn deref(&self) -> &Obj<'p> {
&self.obj
}
}
impl<'p> Scale<'p> {
pub fn new(parent: &impl AsLvHandle) -> Result<Self, WidgetError> {
let parent_ptr = parent.lv_handle();
assert_ne!(parent_ptr, null_mut(), "Parent widget cannot be null");
let handle = unsafe { lv_scale_create(parent_ptr) };
if handle.is_null() {
Err(WidgetError::LvglNullPointer)
} else {
Ok(Scale { obj: Obj::from_raw(handle), section_styles: core::cell::RefCell::new(Vec::new()) })
}
}
pub fn set_mode(&self, mode: ScaleMode) -> &Self {
unsafe { lv_scale_set_mode(self.lv_handle(), mode as lv_scale_mode_t) };
self
}
pub fn set_total_tick_count(&self, count: u32) -> &Self {
unsafe { lv_scale_set_total_tick_count(self.lv_handle(), count) };
self
}
pub fn set_major_tick_every(&self, interval: u32) -> &Self {
unsafe { lv_scale_set_major_tick_every(self.lv_handle(), interval) };
self
}
pub fn set_range(&self, min: i32, max: i32) -> &Self {
unsafe { lv_scale_set_range(self.lv_handle(), min, max) };
self
}
pub fn set_label_show(&self, show: bool) -> &Self {
unsafe { lv_scale_set_label_show(self.lv_handle(), show) };
self
}
pub fn set_tick_length(&self, part: super::Part, length: i32) -> &Self {
unsafe { lv_obj_set_style_length(self.lv_handle(), length, part as u32) };
self
}
pub fn set_rotation(&self, rotation: i32) -> &Self {
unsafe { lv_scale_set_rotation(self.lv_handle(), rotation) };
self
}
pub fn set_angle_range(&self, angle_range: u32) -> &Self {
unsafe { lv_scale_set_angle_range(self.lv_handle(), angle_range) };
self
}
pub fn get_mode(&self) -> u32 {
unsafe { lv_scale_get_mode(self.lv_handle()) }
}
pub fn get_total_tick_count(&self) -> i32 {
unsafe { lv_scale_get_total_tick_count(self.lv_handle()) }
}
pub fn get_major_tick_every(&self) -> i32 {
unsafe { lv_scale_get_major_tick_every(self.lv_handle()) }
}
pub fn get_rotation(&self) -> i32 {
unsafe { lv_scale_get_rotation(self.lv_handle()) }
}
pub fn get_label_show(&self) -> bool {
unsafe { lv_scale_get_label_show(self.lv_handle()) }
}
pub fn get_angle_range(&self) -> u32 {
unsafe { lv_scale_get_angle_range(self.lv_handle()) }
}
pub fn get_range_min_value(&self) -> i32 {
unsafe { lv_scale_get_range_min_value(self.lv_handle()) }
}
pub fn get_range_max_value(&self) -> i32 {
unsafe { lv_scale_get_range_max_value(self.lv_handle()) }
}
pub fn add_section(&self) -> ScaleSection<'_> {
let ptr = unsafe { lv_scale_add_section(self.lv_handle()) };
ScaleSection { ptr, scale: self.lv_handle(), parent_styles: &self.section_styles }
}
pub fn set_text_src(&self, labels: &'static ScaleLabels) -> &Self {
unsafe { lv_scale_set_text_src(self.lv_handle(), labels.0.as_ptr() as *mut _) };
self
}
pub fn set_line_needle_value(&self, needle_line: &super::Line, needle_length: i32, value: i32) -> &Self {
unsafe { lv_scale_set_line_needle_value(self.lv_handle(), needle_line.lv_handle(), needle_length, value) };
self
}
#[allow(clippy::too_many_arguments)]
pub fn tick_ring(
parent: &impl AsLvHandle,
size: i32,
mode: ScaleMode,
rotation: i32,
sweep: i32,
range_max: i32,
total_ticks: u32,
major_every: u32,
show_labels: bool,
major_len: i32,
minor_len: i32,
major_color: u32,
minor_color: u32,
) -> Result<Self, WidgetError> {
let scale = Scale::new(parent)?;
let h = scale.obj.handle();
unsafe {
lv_obj_set_size(h, size, size);
lv_obj_align(h, Align::Center as lv_align_t, 0, 0);
lv_scale_set_mode(h, mode as lv_scale_mode_t);
lv_scale_set_rotation(h, rotation);
lv_scale_set_angle_range(h, sweep as u32);
lv_scale_set_range(h, 0, range_max);
lv_scale_set_total_tick_count(h, total_ticks);
lv_scale_set_major_tick_every(h, major_every);
lv_scale_set_label_show(h, show_labels);
lv_obj_set_style_arc_width(h, 0, lv_part_t_LV_PART_MAIN as u32);
lv_obj_set_style_line_width(h, 1, lv_part_t_LV_PART_MAIN as u32);
lv_obj_set_style_bg_opa(h, crate::enums::Opa::TRANSP.0 as lv_opa_t, 0);
lv_obj_set_style_border_width(h, 0, 0);
lv_obj_set_style_pad_all(h, 0, 0);
lv_obj_set_style_length(h, minor_len, lv_part_t_LV_PART_ITEMS as u32);
lv_obj_set_style_line_color(h, lv_color_hex(minor_color), lv_part_t_LV_PART_ITEMS as u32);
lv_obj_set_style_line_width(h, 1, lv_part_t_LV_PART_ITEMS as u32);
lv_obj_set_style_length(h, major_len, lv_part_t_LV_PART_INDICATOR as u32);
lv_obj_set_style_line_color(h, lv_color_hex(major_color), lv_part_t_LV_PART_INDICATOR as u32);
lv_obj_set_style_line_width(h, 2, lv_part_t_LV_PART_INDICATOR as u32);
}
Ok(scale)
}
}
#[repr(transparent)]
pub struct ScaleLabels(pub [*const core::ffi::c_char]);
impl core::fmt::Debug for ScaleLabels {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ScaleLabels").finish_non_exhaustive()
}
}
unsafe impl Sync for ScaleLabels {}
#[macro_export]
macro_rules! scale_labels {
($($label:expr),+ $(,)?) => {
unsafe {
&*(&[$($label.as_ptr()),+, ::core::ptr::null()]
as *const [*const ::core::ffi::c_char]
as *const $crate::widgets::ScaleLabels)
}
};
}
pub struct ScaleSection<'s> {
ptr: *mut lv_scale_section_t,
scale: *mut lv_obj_t,
parent_styles: &'s core::cell::RefCell<Vec<crate::style::Style>>,
}
impl<'s> core::fmt::Debug for ScaleSection<'s> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ScaleSection").finish_non_exhaustive()
}
}
impl<'s> ScaleSection<'s> {
pub fn set_range(&self, min: i32, max: i32) -> &Self {
unsafe { lv_scale_set_section_range(self.scale, self.ptr, min, max) };
self
}
pub fn set_indicator_style(&self, style: &crate::style::Style) -> &Self {
self.parent_styles.borrow_mut().push(style.clone());
let style_ptr = style.lv_ptr();
unsafe { lv_scale_set_section_style_indicator(self.scale, self.ptr, style_ptr) };
self
}
pub fn set_items_style(&self, style: &crate::style::Style) -> &Self {
self.parent_styles.borrow_mut().push(style.clone());
let style_ptr = style.lv_ptr();
unsafe { lv_scale_set_section_style_items(self.scale, self.ptr, style_ptr) };
self
}
pub fn set_main_style(&self, style: &crate::style::Style) -> &Self {
self.parent_styles.borrow_mut().push(style.clone());
let style_ptr = style.lv_ptr();
unsafe { lv_scale_set_section_style_main(self.scale, self.ptr, style_ptr) };
self
}
}
#[derive(Debug)]
pub struct ScaleBuilder {
size: i32,
mode: ScaleMode,
rotation: i32,
sweep: i32,
range_max: i32,
total_ticks: u32,
major_every: u32,
show_labels: bool,
major_len: i32,
minor_len: i32,
major_color: u32,
minor_color: u32,
}
impl ScaleBuilder {
pub fn new(size: i32, mode: ScaleMode) -> Self {
Self {
size,
mode,
rotation: 0,
sweep: 360,
range_max: 100,
total_ticks: 11,
major_every: 5,
show_labels: true,
major_len: 10,
minor_len: 5,
major_color: 0x000000,
minor_color: 0x808080,
}
}
pub fn rotation(mut self, v: i32) -> Self {
self.rotation = v;
self
}
pub fn sweep(mut self, v: i32) -> Self {
self.sweep = v;
self
}
pub fn range_max(mut self, v: i32) -> Self {
self.range_max = v;
self
}
pub fn total_ticks(mut self, v: u32) -> Self {
self.total_ticks = v;
self
}
pub fn major_every(mut self, v: u32) -> Self {
self.major_every = v;
self
}
pub fn show_labels(mut self, v: bool) -> Self {
self.show_labels = v;
self
}
pub fn major_len(mut self, v: i32) -> Self {
self.major_len = v;
self
}
pub fn minor_len(mut self, v: i32) -> Self {
self.minor_len = v;
self
}
pub fn major_color(mut self, v: u32) -> Self {
self.major_color = v;
self
}
pub fn minor_color(mut self, v: u32) -> Self {
self.minor_color = v;
self
}
pub fn build(self, parent: &impl AsLvHandle) -> Result<Scale<'_>, WidgetError> {
Scale::tick_ring(
parent,
self.size,
self.mode,
self.rotation,
self.sweep,
self.range_max,
self.total_ticks,
self.major_every,
self.show_labels,
self.major_len,
self.minor_len,
self.major_color,
self.minor_color,
)
}
}