Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions executables/file_manager/src/file_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ pub(crate) use alloc::{
vec::Vec,
};
use core::ptr::null_mut;
use xila::file_system::{Kind, Path, PathOwned};
use xila::graphics::{
self, EventKind, Window, lvgl,
palette::{self, Hue},
};
use xila::log;
use xila::task;
use xila::virtual_file_system::{Directory, get_instance};
use xila::{
file_system::{Kind, Path, PathOwned},
graphics::symbols,
};

pub struct FileManager {
window: Window,
Expand Down Expand Up @@ -154,7 +157,7 @@ impl FileManager {
return Err(Error::FailedToCreateObject);
}
let up_label = lvgl::lv_label_create(self.up_button);
lvgl::lv_label_set_text(up_label, lvgl::LV_SYMBOL_UP as *const _ as *const i8);
lvgl::lv_label_set_text(up_label, symbols::UP.as_ptr());
lvgl::lv_obj_center(up_label);

// Remove event handler - events bubble up to window
Expand All @@ -166,7 +169,7 @@ impl FileManager {
}

let home_label = lvgl::lv_label_create(self.home_button);
lvgl::lv_label_set_text(home_label, lvgl::LV_SYMBOL_HOME as *const _ as *const i8);
lvgl::lv_label_set_text(home_label, symbols::HOME.as_ptr());
lvgl::lv_obj_center(home_label);

// Remove event handler - events bubble up to window
Expand All @@ -179,10 +182,7 @@ impl FileManager {

let refresh_label = lvgl::lv_label_create(self.refresh_button);

lvgl::lv_label_set_text(
refresh_label,
lvgl::LV_SYMBOL_REFRESH as *const _ as *const i8,
);
lvgl::lv_label_set_text(refresh_label, symbols::REFRESH.as_ptr());
lvgl::lv_obj_center(refresh_label);

// Remove event handler - events bubble up to window
Expand All @@ -207,7 +207,7 @@ impl FileManager {
}

let go_label = lvgl::lv_label_create(self.go_button);
lvgl::lv_label_set_text(go_label, lvgl::LV_SYMBOL_RIGHT as *const _ as *const i8);
lvgl::lv_label_set_text(go_label, symbols::RIGHT.as_ptr());
lvgl::lv_obj_center(go_label);

self.update_path_label();
Expand Down Expand Up @@ -284,8 +284,8 @@ impl FileManager {
let file = &self.files[index];

let icon_symbol = match file.kind {
Kind::Directory => lvgl::LV_SYMBOL_DIRECTORY,
_ => lvgl::LV_SYMBOL_FILE,
Kind::Directory => symbols::DIRECTORY,
_ => symbols::FILE,
};

let name_cstring = CString::new(file.name.clone()).unwrap();
Expand Down
9 changes: 3 additions & 6 deletions executables/shell/graphical/src/layout.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::{Error, Result};
use alloc::{format, string::String};
use core::ptr::null_mut;
use xila::graphics::{self, EventKind, lvgl, theme};
use xila::graphics::{self, EventKind, lvgl, symbols, theme};
use xila::shared::unix_to_human_time;
use xila::time;

Expand Down Expand Up @@ -223,7 +223,7 @@ impl Layout {
return Err(Error::FailedToCreateObject);
}

lvgl::lv_label_set_text(wi_fi, lvgl::LV_SYMBOL_WIFI as *const u8 as *const i8);
lvgl::lv_label_set_text(wi_fi, symbols::WIFI.as_ptr());

wi_fi
};
Expand All @@ -237,10 +237,7 @@ impl Layout {
return Err(Error::FailedToCreateObject);
}

lvgl::lv_label_set_text(
battery,
lvgl::LV_SYMBOL_BATTERY_3 as *const u8 as *const i8,
);
lvgl::lv_label_set_text(battery, symbols::BATTERY_3.as_ptr());

battery
};
Expand Down
1 change: 1 addition & 0 deletions modules/graphics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod macros;
mod manager;
mod point;
mod screen;
pub mod symbols;
mod window;

pub mod lvgl;
Expand Down
32 changes: 32 additions & 0 deletions modules/graphics/src/lvgl.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::ffi::c_char;

pub use lvgl_rust_sys::*;

use crate::Point;
Expand Down Expand Up @@ -62,3 +64,33 @@ pub unsafe fn lv_obj_get_size(object: *mut lv_obj_t) -> Point {
Point::new(width, height)
}
}

/// Add a tab to a tabview and adjust the tab button size
///
/// # Arguments
///
/// * `tabview` - The tabview to add the tab to.
/// * `name` - The name of the tab.
///
/// # Safety
///
/// This function is unsafe because it may dereference raw pointers (e.g. `tabview`).
pub unsafe fn lv_tabview_add_tab(tabview: *mut lv_obj_t, name: *const c_char) -> *mut lv_obj_t {
unsafe {
let page = lvgl_rust_sys::lv_tabview_add_tab(tabview, name);

let bar = lv_tabview_get_tab_bar(tabview);

lv_obj_set_size(bar, LV_SIZE_CONTENT, LV_SIZE_CONTENT);

// get latest tab button
let tab_count = lv_obj_get_child_count(bar);
let button = lv_obj_get_child(bar, (tab_count - 1) as _);

// don't make it grow
lv_obj_set_flex_grow(button, 0);
lv_obj_set_size(button, LV_SIZE_CONTENT, LV_SIZE_CONTENT);

page
}
}
86 changes: 86 additions & 0 deletions modules/graphics/src/symbols.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use core::ffi::CStr;

use crate::lvgl;

// LVGL symbols
pub const BULLET: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BULLET) };
pub const AUDIO: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_AUDIO) };
pub const VIDEO: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_VIDEO) };
pub const LIST: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_LIST) };
pub const OK: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_OK) };
pub const CLOSE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_CLOSE) };
pub const POWER: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_POWER) };
pub const SETTINGS: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_SETTINGS) };
pub const HOME: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_HOME) };
pub const DOWNLOAD: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_DOWNLOAD) };
pub const DRIVE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_DRIVE) };
pub const REFRESH: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_REFRESH) };
pub const MUTE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_MUTE) };
pub const VOLUME_MID: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_VOLUME_MID) };
pub const VOLUME_MAX: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_VOLUME_MAX) };
pub const IMAGE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_IMAGE) };
pub const TINT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_TINT) };
pub const PREV: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_PREV) };
pub const PLAY: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_PLAY) };
pub const PAUSE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_PAUSE) };
pub const STOP: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_STOP) };
pub const NEXT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_NEXT) };
pub const EJECT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_EJECT) };
pub const LEFT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_LEFT) };
pub const RIGHT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_RIGHT) };
pub const PLUS: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_PLUS) };
pub const MINUS: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_MINUS) };
pub const EYE_OPEN: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_EYE_OPEN) };
pub const EYE_CLOSE: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_EYE_CLOSE) };
pub const WARNING: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_WARNING) };
pub const SHUFFLE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_SHUFFLE) };
pub const UP: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_UP) };
pub const DOWN: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_DOWN) };
pub const LOOP: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_LOOP) };
pub const DIRECTORY: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_DIRECTORY) };
pub const UPLOAD: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_UPLOAD) };
pub const CALL: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_CALL) };
pub const CUT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_CUT) };
pub const COPY: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_COPY) };
pub const SAVE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_SAVE) };
pub const BARS: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BARS) };
pub const ENVELOPE: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_ENVELOPE) };
pub const CHARGE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_CHARGE) };
pub const PASTE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_PASTE) };
pub const BELL: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BELL) };
pub const KEYBOARD: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_KEYBOARD) };
pub const GPS: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_GPS) };
pub const FILE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_FILE) };
pub const WIFI: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_WIFI) };
pub const BATTERY_FULL: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BATTERY_FULL) };
pub const BATTERY_3: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BATTERY_3) };
pub const BATTERY_2: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BATTERY_2) };
pub const BATTERY_1: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BATTERY_1) };
pub const BATTERY_EMPTY: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BATTERY_EMPTY) };
pub const USB: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_USB) };
pub const BLUETOOTH: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BLUETOOTH) };
pub const TRASH: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_TRASH) };
pub const EDIT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_EDIT) };
pub const BACKSPACE: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_BACKSPACE) };
pub const SD_CARD: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_SD_CARD) };
pub const NEW_LINE: &CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_NEW_LINE) };
pub const DUMMY: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(lvgl::LV_SYMBOL_DUMMY) };
// Additional symbols
pub const NETWORK_WIRED: &CStr = c"\xEF\x9B\xBF";
89 changes: 86 additions & 3 deletions modules/graphics/src/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ pub const BORDER_COLOR_PRIMARY: Color = Color::new(0x27, 0x27, 0x2a);
pub const SECONDARY_COLOR: Color = palette::get(palette::Hue::Red, palette::Tone::MAIN);
pub const IS_DARK: bool = true;

pub const BORDER_WIDTH: i32 = 2;
pub const RADIUS: i32 = BORDER_WIDTH * 4;
pub const PADDING: i32 = 16;

/// Rust representation of LVGL's `lv_theme_t` structure
///
/// This struct is C FFI compatible and must match the memory layout of the C struct.
Expand Down Expand Up @@ -138,17 +142,64 @@ pub unsafe extern "C" fn theme_apply(_: *mut lvgl::lv_theme_t, object: *mut lvgl
&& lvgl::lv_obj_get_child(tab_view, 0) == parent
&& lvgl::lv_obj_check_type(tab_view, &lvgl::lv_tabview_class)
{
lvgl::lv_obj_set_style_bg_color(
lvgl::lv_obj_set_style_pad_all(object, BORDER_WIDTH * 4, lvgl::LV_PART_MAIN);
lvgl::lv_obj_set_style_radius(object, RADIUS, lvgl::LV_PART_MAIN);

lvgl::lv_obj_set_style_border_side(
object,
lvgl::lv_border_side_t_LV_BORDER_SIDE_FULL,
lvgl::LV_STATE_CHECKED,
);
lvgl::lv_obj_set_style_border_side(
object,
lvgl::lv_border_side_t_LV_BORDER_SIDE_FULL,
lvgl::LV_PART_MAIN,
);
lvgl::lv_obj_set_style_border_color(
object,
PRIMARY_COLOR.into_lvgl_color(),
lvgl::LV_STATE_CHECKED,
);
lvgl::lv_obj_set_style_border_color(
object,
BACKGROUND_COLOR_PRIMARY.into_lvgl_color(),
PRIMARY_COLOR.into_lvgl_color(),
lvgl::LV_PART_MAIN,
);

lvgl::lv_obj_set_style_border_width(object, BORDER_WIDTH, lvgl::LV_PART_MAIN);
lvgl::lv_obj_set_style_border_width(object, BORDER_WIDTH, lvgl::LV_STATE_CHECKED);
lvgl::lv_obj_set_style_border_opa(
object,
lvgl::LV_OPA_TRANSP as _,
lvgl::LV_PART_MAIN,
);
lvgl::lv_obj_set_style_border_opa(
object,
lvgl::LV_OPA_COVER as _,
lvgl::LV_STATE_CHECKED,
);

lvgl::lv_obj_set_style_bg_opa(object, lvgl::LV_OPA_TRANSP as _, lvgl::LV_PART_MAIN);

lvgl::lv_obj_set_style_text_color(
object,
PRIMARY_COLOR.into_lvgl_color(),
lvgl::LV_PART_MAIN,
);

lvgl::lv_obj_set_style_bg_color(
parent,
BACKGROUND_COLOR_PRIMARY_MUTED.into_lvgl_color(),
lvgl::LV_PART_MAIN,
);
lvgl::lv_obj_set_style_radius(parent, RADIUS, lvgl::LV_PART_MAIN);
lvgl::lv_obj_set_style_pad_all(parent, BORDER_WIDTH * 2, lvgl::LV_PART_MAIN);
lvgl::lv_obj_set_flex_align(
parent,
lvgl::lv_flex_align_t_LV_FLEX_ALIGN_CENTER,
lvgl::lv_flex_align_t_LV_FLEX_ALIGN_CENTER,
lvgl::lv_flex_align_t_LV_FLEX_ALIGN_CENTER,
);
}
} else if class == &lvgl::lv_buttonmatrix_class {
apply_default_style(object, lvgl::LV_PART_MAIN);
Expand All @@ -159,12 +210,44 @@ pub unsafe extern "C" fn theme_apply(_: *mut lvgl::lv_theme_t, object: *mut lvgl
lvgl::LV_PART_MAIN,
);

lvgl::lv_obj_set_style_border_width(object, 2, lvgl::LV_PART_ITEMS);
lvgl::lv_obj_set_style_border_width(object, BORDER_WIDTH, lvgl::LV_PART_ITEMS);
lvgl::lv_obj_set_style_text_color(
object,
PRIMARY_COLOR.into_lvgl_color(),
lvgl::LV_PART_ITEMS,
);
} else if class == &lvgl::lv_checkbox_class {
apply_default_style(object, lvgl::LV_PART_MAIN);
apply_default_style(object, lvgl::LV_PART_INDICATOR);
lvgl::lv_obj_set_style_border_color(
object,
PRIMARY_COLOR.into_lvgl_color(),
lvgl::LV_PART_INDICATOR | lvgl::LV_STATE_CHECKED,
);
lvgl::lv_obj_set_style_text_color(
object,
BACKGROUND_COLOR_PRIMARY.into_lvgl_color(),
lvgl::LV_PART_INDICATOR | lvgl::LV_STATE_CHECKED,
);
} else if class == &lvgl::lv_list_text_class {
apply_default_style(object, lvgl::LV_PART_MAIN);
lvgl::lv_obj_set_style_pad_left(object, PADDING, lvgl::LV_PART_MAIN);
lvgl::lv_obj_set_style_bg_color(
object,
BACKGROUND_COLOR_PRIMARY_MUTED.into_lvgl_color(),
lvgl::LV_PART_MAIN,
);
} else if class == &lvgl::lv_list_button_class {
apply_default_style(object, lvgl::LV_PART_MAIN);
lvgl::lv_obj_set_style_pad_left(object, 2 * PADDING, lvgl::LV_PART_MAIN);
} else if class == &lvgl::lv_switch_class {
apply_default_style(object, lvgl::LV_PART_MAIN);
apply_default_style(object, lvgl::LV_PART_INDICATOR);
lvgl::lv_obj_set_style_bg_color(
object,
BACKGROUND_COLOR_PRIMARY.into_lvgl_color(),
lvgl::LV_PART_KNOB | lvgl::LV_STATE_CHECKED,
);
} else {
apply_default_style(object, lvgl::LV_PART_MAIN);
}
Expand Down
8 changes: 2 additions & 6 deletions modules/task/src/manager/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,11 +448,6 @@ async fn test_get_children() {
let root_task = manager.get_current_task_identifier().await;
let spawner = manager.get_spawner(root_task).await.unwrap();

// Initially, root task should have no children
let initial_children = manager.get_children(root_task).await.unwrap();
let initial_count = initial_children.len();
assert_eq!(initial_count, 0);

// Spawn first child
let (child1_handle, child1_task) = manager
.spawn(root_task, "Child Task 1", Some(spawner), async move |_| {
Expand Down Expand Up @@ -480,7 +475,8 @@ async fn test_get_children() {

// After children complete, they should no longer be in the children list
let final_children = manager.get_children(root_task).await.unwrap();
assert_eq!(final_children.len(), initial_count);
assert!(!final_children.contains(&child1_task));
assert!(!final_children.contains(&child2_task));
}

#[ignore]
Expand Down