568 lines
19 KiB
C
568 lines
19 KiB
C
#include "ui_mixer.h"
|
|
#include "lcd.h"
|
|
|
|
#include "lvgl.h"
|
|
#include "src/draw/sw/lv_draw_sw_utils.h"
|
|
|
|
#include "pico/stdlib.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#define UI_HEADER_H 56
|
|
#define UI_LIST_TOP 58
|
|
#define UI_ROW_H 45
|
|
#define UI_MAX_ROWS 4
|
|
#define UI_BUF_LINES 30
|
|
#define UI_SB_W 8
|
|
#define UI_SB_PAD 4
|
|
#define UI_CONTENT_R (UI_SB_W + UI_SB_PAD + 2) /* right inset for list content */
|
|
|
|
#define COL_BG lv_color_make(10, 14, 20)
|
|
#define COL_PANEL lv_color_make(22, 30, 42)
|
|
#define COL_SEL lv_color_make(28, 48, 72)
|
|
#define COL_ACCENT lv_color_make(0, 200, 210)
|
|
#define COL_ACCENT2 lv_color_make(255, 170, 40)
|
|
#define COL_MUTED lv_color_make(120, 130, 145)
|
|
#define COL_BAR_BG lv_color_make(40, 52, 68)
|
|
#define COL_BAR_HI lv_color_make(80, 230, 170)
|
|
#define COL_VU lv_color_make(255, 200, 60)
|
|
#define COL_VU_HOT lv_color_make(255, 90, 70)
|
|
#define COL_TEXT lv_color_make(235, 240, 245)
|
|
|
|
typedef struct {
|
|
lv_obj_t *row;
|
|
lv_obj_t *name;
|
|
lv_obj_t *pct;
|
|
lv_obj_t *vu;
|
|
lv_obj_t *bar;
|
|
} ui_row_t;
|
|
|
|
static lv_display_t *s_disp;
|
|
static uint8_t s_draw_buf[LCD_WIDTH * UI_BUF_LINES * 2];
|
|
|
|
static lv_obj_t *s_scr;
|
|
static lv_obj_t *s_wait;
|
|
static lv_obj_t *s_main;
|
|
static lv_obj_t *s_master_pct;
|
|
static lv_obj_t *s_master_vu;
|
|
static lv_obj_t *s_master_bar;
|
|
static lv_obj_t *s_empty;
|
|
static lv_obj_t *s_caret;
|
|
static lv_obj_t *s_sb_track;
|
|
static lv_obj_t *s_sb_thumb;
|
|
static ui_row_t s_rows[UI_MAX_ROWS];
|
|
|
|
static bool s_waiting = true;
|
|
static uint8_t s_master = 0xFF;
|
|
static uint8_t s_master_peak = 0xFF;
|
|
static uint8_t s_n = 0xFF;
|
|
static uint8_t s_sel = 0xFF;
|
|
static uint8_t s_page = 0xFF;
|
|
static uint8_t s_count = 0xFF;
|
|
static char s_names[AUSIO_MAX_VISIBLE][AUSIO_NAME_CHARS + 1];
|
|
static uint8_t s_vols[AUSIO_MAX_VISIBLE];
|
|
static uint8_t s_peaks[AUSIO_MAX_VISIBLE];
|
|
|
|
static absolute_time_t s_last_tick;
|
|
static int16_t s_caret_y;
|
|
|
|
static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
|
|
{
|
|
int32_t w = area->x2 - area->x1 + 1;
|
|
int32_t h = area->y2 - area->y1 + 1;
|
|
uint32_t stride = lv_draw_buf_width_to_stride((uint32_t)w, lv_display_get_color_format(disp));
|
|
/* SPI wants big-endian RGB565 bytes (same as lcd_draw_char). */
|
|
if (stride == (uint32_t)w * 2u) {
|
|
lv_draw_sw_rgb565_swap(px_map, (uint32_t)(w * h));
|
|
} else {
|
|
for (int32_t row = 0; row < h; row++) {
|
|
lv_draw_sw_rgb565_swap(px_map + (size_t)row * stride, (uint32_t)w);
|
|
}
|
|
}
|
|
lcd_blit((int16_t)area->x1, (int16_t)area->y1, (int16_t)w, (int16_t)h, px_map,
|
|
(int32_t)stride);
|
|
lv_display_flush_ready(disp);
|
|
}
|
|
|
|
static void style_bar(lv_obj_t *bar, lv_color_t fill)
|
|
{
|
|
lv_obj_set_style_bg_color(bar, COL_BAR_BG, LV_PART_MAIN);
|
|
lv_obj_set_style_bg_opa(bar, LV_OPA_COVER, LV_PART_MAIN);
|
|
lv_obj_set_style_radius(bar, 4, LV_PART_MAIN);
|
|
lv_obj_set_style_pad_all(bar, 0, LV_PART_MAIN);
|
|
lv_obj_set_style_bg_color(bar, fill, LV_PART_INDICATOR);
|
|
lv_obj_set_style_bg_opa(bar, LV_OPA_COVER, LV_PART_INDICATOR);
|
|
lv_obj_set_style_radius(bar, 4, LV_PART_INDICATOR);
|
|
lv_bar_set_range(bar, 0, 100);
|
|
}
|
|
|
|
static void style_vu(lv_obj_t *bar)
|
|
{
|
|
style_bar(bar, COL_VU);
|
|
lv_obj_set_style_radius(bar, 2, LV_PART_MAIN);
|
|
lv_obj_set_style_radius(bar, 2, LV_PART_INDICATOR);
|
|
}
|
|
|
|
static void set_vu_value(lv_obj_t *bar, uint8_t peak)
|
|
{
|
|
lv_color_t c = (peak >= 90) ? COL_VU_HOT : COL_VU;
|
|
lv_obj_set_style_bg_color(bar, c, LV_PART_INDICATOR);
|
|
lv_bar_set_value(bar, peak, LV_ANIM_OFF);
|
|
}
|
|
|
|
static void anim_caret_y(void *obj, int32_t v)
|
|
{
|
|
lv_obj_set_y((lv_obj_t *)obj, (int32_t)v);
|
|
s_caret_y = (int16_t)v;
|
|
}
|
|
|
|
static void move_caret_to(uint8_t row_idx, bool animate)
|
|
{
|
|
int16_t target = (int16_t)(UI_LIST_TOP + (int16_t)row_idx * UI_ROW_H + 8);
|
|
if (!animate) {
|
|
lv_anim_delete(s_caret, anim_caret_y);
|
|
lv_obj_set_y(s_caret, target);
|
|
s_caret_y = target;
|
|
return;
|
|
}
|
|
|
|
lv_anim_t a;
|
|
lv_anim_init(&a);
|
|
lv_anim_set_var(&a, s_caret);
|
|
lv_anim_set_values(&a, s_caret_y, target);
|
|
lv_anim_set_duration(&a, 180);
|
|
lv_anim_set_path_cb(&a, lv_anim_path_ease_out);
|
|
lv_anim_set_exec_cb(&a, anim_caret_y);
|
|
lv_anim_start(&a);
|
|
}
|
|
|
|
static void update_scrollbar(uint8_t total, uint8_t page_start, uint8_t visible)
|
|
{
|
|
if (total <= visible || visible == 0) {
|
|
lv_obj_add_flag(s_sb_track, LV_OBJ_FLAG_HIDDEN);
|
|
return;
|
|
}
|
|
|
|
lv_obj_clear_flag(s_sb_track, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
const int32_t track_h = lv_obj_get_height(s_sb_track);
|
|
/* Thumb shows the visible window; at least ~1/4 of track so it's obvious. */
|
|
int32_t thumb_h = (track_h * (int32_t)visible) / (int32_t)total;
|
|
int32_t min_h = track_h / 4;
|
|
if (min_h < 18) {
|
|
min_h = 18;
|
|
}
|
|
if (thumb_h < min_h) {
|
|
thumb_h = min_h;
|
|
}
|
|
if (thumb_h > track_h) {
|
|
thumb_h = track_h;
|
|
}
|
|
|
|
uint8_t max_start = (uint8_t)(total - visible);
|
|
int32_t travel = track_h - thumb_h;
|
|
int32_t thumb_y = 0;
|
|
if (max_start > 0 && travel > 0) {
|
|
if (page_start > max_start) {
|
|
page_start = max_start;
|
|
}
|
|
thumb_y = (travel * (int32_t)page_start) / (int32_t)max_start;
|
|
}
|
|
|
|
lv_obj_set_height(s_sb_thumb, thumb_h);
|
|
lv_obj_set_y(s_sb_thumb, thumb_y);
|
|
}
|
|
|
|
static void build_wait_screen(void)
|
|
{
|
|
s_wait = lv_obj_create(s_scr);
|
|
lv_obj_set_size(s_wait, LCD_WIDTH, LCD_HEIGHT);
|
|
lv_obj_set_style_bg_color(s_wait, COL_BG, 0);
|
|
lv_obj_set_style_bg_opa(s_wait, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(s_wait, 0, 0);
|
|
lv_obj_set_style_pad_all(s_wait, 0, 0);
|
|
lv_obj_set_style_radius(s_wait, 0, 0);
|
|
lv_obj_clear_flag(s_wait, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t *top = lv_obj_create(s_wait);
|
|
lv_obj_set_size(top, LCD_WIDTH, 3);
|
|
lv_obj_set_pos(top, 0, 0);
|
|
lv_obj_set_style_bg_color(top, COL_ACCENT, 0);
|
|
lv_obj_set_style_bg_opa(top, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(top, 0, 0);
|
|
lv_obj_set_style_radius(top, 0, 0);
|
|
lv_obj_clear_flag(top, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t *spin = lv_spinner_create(s_wait);
|
|
lv_obj_set_size(spin, 42, 42);
|
|
lv_obj_align(spin, LV_ALIGN_CENTER, 0, -28);
|
|
lv_obj_set_style_arc_color(spin, COL_PANEL, LV_PART_MAIN);
|
|
lv_obj_set_style_arc_width(spin, 4, LV_PART_MAIN);
|
|
lv_obj_set_style_arc_color(spin, COL_ACCENT, LV_PART_INDICATOR);
|
|
lv_obj_set_style_arc_width(spin, 4, LV_PART_INDICATOR);
|
|
|
|
lv_obj_t *l1 = lv_label_create(s_wait);
|
|
lv_label_set_text(l1, "Waiting for host");
|
|
lv_obj_set_style_text_color(l1, COL_MUTED, 0);
|
|
lv_obj_set_style_text_font(l1, &lv_font_montserrat_16, 0);
|
|
lv_obj_align(l1, LV_ALIGN_CENTER, 0, 28);
|
|
|
|
lv_obj_t *l2 = lv_label_create(s_wait);
|
|
lv_label_set_text(l2, "Ausiomixer");
|
|
lv_obj_set_style_text_color(l2, COL_ACCENT, 0);
|
|
lv_obj_set_style_text_font(l2, &lv_font_montserrat_20, 0);
|
|
lv_obj_align(l2, LV_ALIGN_CENTER, 0, 54);
|
|
}
|
|
|
|
static void build_main_screen(void)
|
|
{
|
|
s_main = lv_obj_create(s_scr);
|
|
lv_obj_set_size(s_main, LCD_WIDTH, LCD_HEIGHT);
|
|
lv_obj_set_style_bg_color(s_main, COL_BG, 0);
|
|
lv_obj_set_style_bg_opa(s_main, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(s_main, 0, 0);
|
|
lv_obj_set_style_pad_all(s_main, 0, 0);
|
|
lv_obj_set_style_radius(s_main, 0, 0);
|
|
lv_obj_clear_flag(s_main, LV_OBJ_FLAG_SCROLLABLE);
|
|
lv_obj_add_flag(s_main, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
lv_obj_t *header = lv_obj_create(s_main);
|
|
lv_obj_set_size(header, LCD_WIDTH, UI_HEADER_H);
|
|
lv_obj_set_pos(header, 0, 0);
|
|
lv_obj_set_style_bg_color(header, COL_PANEL, 0);
|
|
lv_obj_set_style_bg_opa(header, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(header, 0, 0);
|
|
lv_obj_set_style_pad_all(header, 0, 0);
|
|
lv_obj_set_style_radius(header, 0, 0);
|
|
lv_obj_clear_flag(header, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t *accent = lv_obj_create(header);
|
|
lv_obj_set_size(accent, LCD_WIDTH, 2);
|
|
lv_obj_set_pos(accent, 0, 0);
|
|
lv_obj_set_style_bg_color(accent, COL_ACCENT, 0);
|
|
lv_obj_set_style_bg_opa(accent, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(accent, 0, 0);
|
|
lv_obj_set_style_radius(accent, 0, 0);
|
|
|
|
lv_obj_t *ml = lv_label_create(header);
|
|
lv_label_set_text(ml, "MASTER");
|
|
lv_obj_set_style_text_color(ml, COL_ACCENT, 0);
|
|
lv_obj_set_style_text_font(ml, &lv_font_montserrat_14, 0);
|
|
lv_obj_set_pos(ml, 10, 8);
|
|
|
|
s_master_pct = lv_label_create(header);
|
|
lv_label_set_text(s_master_pct, "0%");
|
|
lv_obj_set_style_text_color(s_master_pct, COL_TEXT, 0);
|
|
lv_obj_set_style_text_font(s_master_pct, &lv_font_montserrat_28, 0);
|
|
lv_obj_align(s_master_pct, LV_ALIGN_TOP_RIGHT, -10, 2);
|
|
|
|
s_master_vu = lv_bar_create(header);
|
|
lv_obj_set_size(s_master_vu, LCD_WIDTH - 20, 5);
|
|
lv_obj_set_pos(s_master_vu, 10, 30);
|
|
style_vu(s_master_vu);
|
|
|
|
s_master_bar = lv_bar_create(header);
|
|
lv_obj_set_size(s_master_bar, LCD_WIDTH - 20, 12);
|
|
lv_obj_set_pos(s_master_bar, 10, 38);
|
|
style_bar(s_master_bar, COL_BAR_HI);
|
|
|
|
for (uint8_t i = 0; i < UI_MAX_ROWS; i++) {
|
|
int16_t y = (int16_t)(UI_LIST_TOP + (int16_t)i * UI_ROW_H);
|
|
ui_row_t *r = &s_rows[i];
|
|
|
|
r->row = lv_obj_create(s_main);
|
|
lv_obj_set_size(r->row, LCD_WIDTH, UI_ROW_H - 1);
|
|
lv_obj_set_pos(r->row, 0, y);
|
|
lv_obj_set_style_bg_color(r->row, COL_BG, 0);
|
|
lv_obj_set_style_bg_opa(r->row, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(r->row, 0, 0);
|
|
lv_obj_set_style_pad_all(r->row, 0, 0);
|
|
lv_obj_set_style_radius(r->row, 0, 0);
|
|
lv_obj_clear_flag(r->row, LV_OBJ_FLAG_SCROLLABLE);
|
|
lv_obj_add_flag(r->row, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
r->name = lv_label_create(r->row);
|
|
lv_label_set_long_mode(r->name, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
|
lv_obj_set_width(r->name, LCD_WIDTH - 14 - 64 - UI_CONTENT_R);
|
|
lv_obj_set_style_text_color(r->name, COL_ACCENT2, 0);
|
|
lv_obj_set_style_text_font(r->name, &lv_font_montserrat_16, 0);
|
|
lv_obj_set_pos(r->name, 14, 2);
|
|
lv_label_set_text(r->name, "");
|
|
|
|
r->pct = lv_label_create(r->row);
|
|
lv_label_set_text(r->pct, "0%");
|
|
lv_obj_set_style_text_color(r->pct, COL_MUTED, 0);
|
|
lv_obj_set_style_text_font(r->pct, &lv_font_montserrat_14, 0);
|
|
lv_obj_align(r->pct, LV_ALIGN_TOP_RIGHT, -(10 + UI_CONTENT_R), 4);
|
|
|
|
r->vu = lv_bar_create(r->row);
|
|
lv_obj_set_size(r->vu, LCD_WIDTH - 28 - UI_CONTENT_R, 5);
|
|
lv_obj_set_pos(r->vu, 14, 22);
|
|
style_vu(r->vu);
|
|
|
|
r->bar = lv_bar_create(r->row);
|
|
lv_obj_set_size(r->bar, LCD_WIDTH - 28 - UI_CONTENT_R, 9);
|
|
lv_obj_set_pos(r->bar, 14, 30);
|
|
style_bar(r->bar, COL_BAR_HI);
|
|
}
|
|
|
|
s_empty = lv_label_create(s_main);
|
|
lv_label_set_text(s_empty, "No audio apps");
|
|
lv_obj_set_style_text_color(s_empty, COL_MUTED, 0);
|
|
lv_obj_set_style_text_font(s_empty, &lv_font_montserrat_16, 0);
|
|
lv_obj_align(s_empty, LV_ALIGN_CENTER, 0, 20);
|
|
lv_obj_add_flag(s_empty, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
s_caret = lv_obj_create(s_main);
|
|
lv_obj_set_size(s_caret, 4, UI_ROW_H - 16);
|
|
lv_obj_set_pos(s_caret, 0, UI_LIST_TOP + 8);
|
|
lv_obj_set_style_bg_color(s_caret, COL_ACCENT, 0);
|
|
lv_obj_set_style_bg_opa(s_caret, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(s_caret, 0, 0);
|
|
lv_obj_set_style_radius(s_caret, 2, 0);
|
|
lv_obj_clear_flag(s_caret, LV_OBJ_FLAG_SCROLLABLE);
|
|
lv_obj_add_flag(s_caret, LV_OBJ_FLAG_HIDDEN);
|
|
s_caret_y = UI_LIST_TOP + 8;
|
|
|
|
/* List scrollbar — visible only when session_count > visible rows. */
|
|
{
|
|
const int16_t list_h = (int16_t)(UI_MAX_ROWS * UI_ROW_H);
|
|
s_sb_track = lv_obj_create(s_main);
|
|
lv_obj_set_size(s_sb_track, UI_SB_W, list_h - 12);
|
|
lv_obj_set_pos(s_sb_track, LCD_WIDTH - UI_SB_W - UI_SB_PAD, UI_LIST_TOP + 6);
|
|
lv_obj_set_style_bg_color(s_sb_track, COL_BAR_BG, 0);
|
|
lv_obj_set_style_bg_opa(s_sb_track, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(s_sb_track, 0, 0);
|
|
lv_obj_set_style_radius(s_sb_track, 4, 0);
|
|
lv_obj_set_style_pad_all(s_sb_track, 0, 0);
|
|
lv_obj_clear_flag(s_sb_track, LV_OBJ_FLAG_SCROLLABLE);
|
|
lv_obj_add_flag(s_sb_track, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
s_sb_thumb = lv_obj_create(s_sb_track);
|
|
lv_obj_set_size(s_sb_thumb, UI_SB_W, 40);
|
|
lv_obj_set_pos(s_sb_thumb, 0, 0);
|
|
lv_obj_set_style_bg_color(s_sb_thumb, COL_ACCENT, 0);
|
|
lv_obj_set_style_bg_opa(s_sb_thumb, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_border_width(s_sb_thumb, 0, 0);
|
|
lv_obj_set_style_radius(s_sb_thumb, 4, 0);
|
|
lv_obj_set_style_pad_all(s_sb_thumb, 0, 0);
|
|
lv_obj_clear_flag(s_sb_thumb, LV_OBJ_FLAG_SCROLLABLE);
|
|
}
|
|
}
|
|
|
|
static void show_waiting(bool on)
|
|
{
|
|
if (on) {
|
|
lv_obj_clear_flag(s_wait, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_add_flag(s_main, LV_OBJ_FLAG_HIDDEN);
|
|
} else {
|
|
lv_obj_add_flag(s_wait, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_clear_flag(s_main, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
s_waiting = on;
|
|
}
|
|
|
|
static void set_row_selected(ui_row_t *r, bool sel)
|
|
{
|
|
lv_obj_set_style_bg_color(r->row, sel ? COL_SEL : COL_BG, 0);
|
|
lv_obj_set_style_text_color(r->name, sel ? COL_TEXT : COL_ACCENT2, 0);
|
|
lv_obj_set_style_text_color(r->pct, sel ? COL_ACCENT : COL_MUTED, 0);
|
|
lv_obj_set_style_bg_color(r->bar, sel ? COL_ACCENT : COL_BAR_HI, LV_PART_INDICATOR);
|
|
}
|
|
|
|
void ui_mixer_init(void)
|
|
{
|
|
lv_init();
|
|
|
|
s_disp = lv_display_create(LCD_WIDTH, LCD_HEIGHT);
|
|
lv_display_set_flush_cb(s_disp, flush_cb);
|
|
lv_display_set_buffers(s_disp, s_draw_buf, NULL, sizeof(s_draw_buf),
|
|
LV_DISPLAY_RENDER_MODE_PARTIAL);
|
|
lv_display_set_color_format(s_disp, LV_COLOR_FORMAT_RGB565);
|
|
|
|
s_scr = lv_screen_active();
|
|
lv_obj_set_style_bg_color(s_scr, COL_BG, 0);
|
|
lv_obj_set_style_bg_opa(s_scr, LV_OPA_COVER, 0);
|
|
|
|
build_wait_screen();
|
|
build_main_screen();
|
|
show_waiting(true);
|
|
|
|
s_last_tick = get_absolute_time();
|
|
s_master = 0xFF;
|
|
s_master_peak = 0xFF;
|
|
s_n = 0xFF;
|
|
s_sel = 0xFF;
|
|
s_page = 0xFF;
|
|
s_count = 0xFF;
|
|
memset(s_names, 0, sizeof(s_names));
|
|
memset(s_vols, 0, sizeof(s_vols));
|
|
memset(s_peaks, 0, sizeof(s_peaks));
|
|
|
|
/* First paint */
|
|
lv_timer_handler();
|
|
}
|
|
|
|
void ui_mixer_task(void)
|
|
{
|
|
absolute_time_t now = get_absolute_time();
|
|
uint32_t elapsed = (uint32_t)absolute_time_diff_us(s_last_tick, now) / 1000u;
|
|
if (elapsed > 0) {
|
|
if (elapsed > 50) {
|
|
elapsed = 50;
|
|
}
|
|
lv_tick_inc(elapsed);
|
|
s_last_tick = now;
|
|
}
|
|
lv_timer_handler();
|
|
}
|
|
|
|
bool ui_mixer_needs_tick(void)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void ui_mixer_draw(const mixer_state_t *st)
|
|
{
|
|
if (!st) {
|
|
return;
|
|
}
|
|
|
|
if (!st->host_alive) {
|
|
if (!s_waiting) {
|
|
show_waiting(true);
|
|
s_master = 0xFF;
|
|
s_master_peak = 0xFF;
|
|
s_n = 0xFF;
|
|
s_sel = 0xFF;
|
|
s_count = 0xFF;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (s_waiting) {
|
|
show_waiting(false);
|
|
s_master = 0xFF;
|
|
s_master_peak = 0xFF;
|
|
s_n = 0xFF;
|
|
s_sel = 0xFF;
|
|
s_page = 0xFF;
|
|
s_count = 0xFF;
|
|
}
|
|
|
|
uint8_t n = st->n_visible;
|
|
if (n > UI_MAX_ROWS) {
|
|
n = UI_MAX_ROWS;
|
|
}
|
|
|
|
if (st->master_vol != s_master) {
|
|
char buf[8];
|
|
snprintf(buf, sizeof(buf), "%u%%", st->master_vol);
|
|
lv_label_set_text(s_master_pct, buf);
|
|
lv_bar_set_value(s_master_bar, st->master_vol, LV_ANIM_ON);
|
|
s_master = st->master_vol;
|
|
}
|
|
if (st->master_peak != s_master_peak) {
|
|
set_vu_value(s_master_vu, st->master_peak);
|
|
s_master_peak = st->master_peak;
|
|
}
|
|
|
|
bool list_changed = (n != s_n) || (st->selected != s_sel) ||
|
|
(st->page_start != s_page) || (st->session_count != s_count);
|
|
if (!list_changed) {
|
|
for (uint8_t i = 0; i < n; i++) {
|
|
if (s_vols[i] != st->visible[i].vol ||
|
|
strncmp(s_names[i], st->visible[i].name, AUSIO_NAME_CHARS) != 0) {
|
|
list_changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool peaks_changed = false;
|
|
if (!list_changed && s_n != 0xFF) {
|
|
for (uint8_t i = 0; i < n; i++) {
|
|
if (s_peaks[i] != st->visible[i].peak) {
|
|
peaks_changed = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!peaks_changed) {
|
|
return;
|
|
}
|
|
for (uint8_t i = 0; i < n; i++) {
|
|
if (s_peaks[i] != st->visible[i].peak) {
|
|
set_vu_value(s_rows[i].vu, st->visible[i].peak);
|
|
s_peaks[i] = st->visible[i].peak;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (n == 0) {
|
|
for (uint8_t i = 0; i < UI_MAX_ROWS; i++) {
|
|
lv_obj_add_flag(s_rows[i].row, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
lv_obj_add_flag(s_caret, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_add_flag(s_sb_track, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_clear_flag(s_empty, LV_OBJ_FLAG_HIDDEN);
|
|
set_vu_value(s_master_vu, 0);
|
|
s_master_peak = 0;
|
|
} else {
|
|
lv_obj_add_flag(s_empty, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_clear_flag(s_caret, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
int rel = (int)st->selected - (int)st->page_start;
|
|
if (rel < 0) {
|
|
rel = 0;
|
|
}
|
|
if (rel >= (int)n) {
|
|
rel = (int)n - 1;
|
|
}
|
|
|
|
bool sel_moved = (st->selected != s_sel) || (st->page_start != s_page) || (s_n == 0xFF);
|
|
bool first = (s_n == 0xFF);
|
|
|
|
for (uint8_t i = 0; i < UI_MAX_ROWS; i++) {
|
|
ui_row_t *r = &s_rows[i];
|
|
if (i >= n) {
|
|
lv_obj_add_flag(r->row, LV_OBJ_FLAG_HIDDEN);
|
|
continue;
|
|
}
|
|
|
|
lv_obj_clear_flag(r->row, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
char name[AUSIO_NAME_CHARS + 1];
|
|
memcpy(name, st->visible[i].name, AUSIO_NAME_CHARS);
|
|
name[AUSIO_NAME_CHARS] = '\0';
|
|
if (strncmp(s_names[i], name, AUSIO_NAME_CHARS + 1) != 0 || s_n == 0xFF) {
|
|
lv_label_set_text(r->name, name);
|
|
memcpy(s_names[i], name, sizeof(name));
|
|
}
|
|
|
|
if (s_vols[i] != st->visible[i].vol || s_n == 0xFF) {
|
|
char pct[8];
|
|
snprintf(pct, sizeof(pct), "%u%%", st->visible[i].vol);
|
|
lv_label_set_text(r->pct, pct);
|
|
lv_bar_set_value(r->bar, st->visible[i].vol, first ? LV_ANIM_OFF : LV_ANIM_ON);
|
|
s_vols[i] = st->visible[i].vol;
|
|
}
|
|
|
|
set_vu_value(r->vu, st->visible[i].peak);
|
|
s_peaks[i] = st->visible[i].peak;
|
|
|
|
bool sel = ((int)i == rel);
|
|
set_row_selected(r, sel);
|
|
}
|
|
|
|
move_caret_to((uint8_t)rel, !first && sel_moved);
|
|
update_scrollbar(st->session_count, st->page_start, n);
|
|
}
|
|
|
|
s_n = n;
|
|
s_sel = st->selected;
|
|
s_page = st->page_start;
|
|
s_count = st->session_count;
|
|
}
|