|
|
|
@@ -0,0 +1,467 @@
|
|
|
|
|
/*
|
|
|
|
|
* ui.c
|
|
|
|
|
*
|
|
|
|
|
* LVGL (v9) UI of the Box-3 looper display/controller.
|
|
|
|
|
*
|
|
|
|
|
* Tab "Pistes": 4 track pads (state color + VU) + transport bar
|
|
|
|
|
* Tab "Réglages": gains/pans, input, SD sessions
|
|
|
|
|
*
|
|
|
|
|
* The UI holds no looper logic: every interaction emits a CMD over the
|
|
|
|
|
* link, the display follows the next STATE frame (<= 50 ms later).
|
|
|
|
|
*/
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#include "lvgl.h"
|
|
|
|
|
|
|
|
|
|
#include "link_task.h"
|
|
|
|
|
#include "ui.h"
|
|
|
|
|
|
|
|
|
|
/* track pad colors by state */
|
|
|
|
|
#define COL_EMPTY 0x3A3A3A
|
|
|
|
|
#define COL_DATA 0x2A4A8A /* has data, stopped */
|
|
|
|
|
#define COL_PLAY 0x22883A
|
|
|
|
|
#define COL_REC 0xB02020
|
|
|
|
|
#define COL_ERASE 0xC87010
|
|
|
|
|
#define COL_BG 0x181818
|
|
|
|
|
|
|
|
|
|
static lv_obj_t *track_pad[LINK_TRACK_CNT];
|
|
|
|
|
static lv_obj_t *track_vu[LINK_TRACK_CNT];
|
|
|
|
|
static lv_obj_t *track_label[LINK_TRACK_CNT];
|
|
|
|
|
static lv_obj_t *pos_bar;
|
|
|
|
|
static lv_obj_t *len_line;
|
|
|
|
|
static lv_obj_t *bpm_btn_label;
|
|
|
|
|
static lv_obj_t *click_btn;
|
|
|
|
|
static lv_obj_t *vu_in_bar;
|
|
|
|
|
static lv_obj_t *vu_out_bar;
|
|
|
|
|
static lv_obj_t *gain_slider[LINK_TRACK_CNT];
|
|
|
|
|
static lv_obj_t *pan_slider[LINK_TRACK_CNT];
|
|
|
|
|
static lv_obj_t *gain_in_slider;
|
|
|
|
|
static lv_obj_t *src_btn_label;
|
|
|
|
|
static lv_obj_t *sd_dropdown;
|
|
|
|
|
static lv_obj_t *sd_progress;
|
|
|
|
|
static lv_obj_t *sd_status_label;
|
|
|
|
|
static lv_obj_t *disconnected_banner;
|
|
|
|
|
|
|
|
|
|
static uint16_t last_bpm = 120;
|
|
|
|
|
|
|
|
|
|
/* ---- command callbacks ---- */
|
|
|
|
|
|
|
|
|
|
static void track_pad_event_cb(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
uint32_t n = (uint32_t)(uintptr_t)lv_event_get_user_data(e);
|
|
|
|
|
lv_event_code_t code = lv_event_get_code(e);
|
|
|
|
|
|
|
|
|
|
if (code == LV_EVENT_SHORT_CLICKED)
|
|
|
|
|
{
|
|
|
|
|
/* active track -> stop it, otherwise select (rec/play/overdub) */
|
|
|
|
|
lv_color_t c = lv_obj_get_style_bg_color(track_pad[n], 0);
|
|
|
|
|
bool active = (lv_color_to_u32(c) & 0xFFFFFF) != COL_EMPTY
|
|
|
|
|
&& (lv_color_to_u32(c) & 0xFFFFFF) != COL_DATA;
|
|
|
|
|
link_send_cmd(active ? LINK_CMD_STOP_TRACK : LINK_CMD_SELECT_TRACK,
|
|
|
|
|
(uint8_t)n, 0);
|
|
|
|
|
}
|
|
|
|
|
else if (code == LV_EVENT_LONG_PRESSED)
|
|
|
|
|
{
|
|
|
|
|
link_send_cmd(LINK_CMD_ERASE_TRACK, (uint8_t)n, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void simple_cmd_event_cb(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
uint32_t op = (uint32_t)(uintptr_t)lv_event_get_user_data(e);
|
|
|
|
|
link_send_cmd((uint8_t)op, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bpm_event_cb(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
(void)e;
|
|
|
|
|
uint16_t bpm = last_bpm + 5;
|
|
|
|
|
if (bpm > 240)
|
|
|
|
|
{
|
|
|
|
|
bpm = 60;
|
|
|
|
|
}
|
|
|
|
|
link_send_cmd(LINK_CMD_SET_TEMPO, 0, bpm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void gain_slider_event_cb(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
uint32_t n = (uint32_t)(uintptr_t)lv_event_get_user_data(e);
|
|
|
|
|
lv_obj_t *sl = lv_event_get_target(e);
|
|
|
|
|
uint16_t v = (uint16_t)((lv_slider_get_value(sl) * 65535) / 255);
|
|
|
|
|
link_send_cmd(LINK_CMD_GAIN_OUT, (uint8_t)n, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void pan_slider_event_cb(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
uint32_t n = (uint32_t)(uintptr_t)lv_event_get_user_data(e);
|
|
|
|
|
lv_obj_t *sl = lv_event_get_target(e);
|
|
|
|
|
uint16_t v = (uint16_t)((lv_slider_get_value(sl) * 65535) / 255);
|
|
|
|
|
link_send_cmd(LINK_CMD_PAN, (uint8_t)n, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void gain_in_slider_event_cb(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_t *sl = lv_event_get_target(e);
|
|
|
|
|
uint16_t v = (uint16_t)((lv_slider_get_value(sl) * 65535) / 255);
|
|
|
|
|
link_send_cmd(LINK_CMD_GAIN_IN, 0, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sd_save_event_cb(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
(void)e;
|
|
|
|
|
lv_label_set_text(sd_status_label, "Sauvegarde...");
|
|
|
|
|
link_send_cmd(LINK_CMD_SD_SAVE,
|
|
|
|
|
(uint8_t)lv_dropdown_get_selected(sd_dropdown), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sd_load_event_cb(lv_event_t *e)
|
|
|
|
|
{
|
|
|
|
|
(void)e;
|
|
|
|
|
lv_label_set_text(sd_status_label, "Chargement...");
|
|
|
|
|
link_send_cmd(LINK_CMD_SD_LOAD,
|
|
|
|
|
(uint8_t)lv_dropdown_get_selected(sd_dropdown), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ---- small builders ---- */
|
|
|
|
|
|
|
|
|
|
static lv_obj_t *make_btn(lv_obj_t *parent, const char *txt,
|
|
|
|
|
lv_event_cb_t cb, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_t *btn = lv_button_create(parent);
|
|
|
|
|
lv_obj_add_event_cb(btn, cb, LV_EVENT_CLICKED, user_data);
|
|
|
|
|
lv_obj_t *label = lv_label_create(btn);
|
|
|
|
|
lv_label_set_text(label, txt);
|
|
|
|
|
lv_obj_center(label);
|
|
|
|
|
return btn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static lv_obj_t *make_hbar(lv_obj_t *parent, int32_t w, int32_t h)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_t *bar = lv_bar_create(parent);
|
|
|
|
|
lv_obj_set_size(bar, w, h);
|
|
|
|
|
lv_bar_set_range(bar, 0, 255);
|
|
|
|
|
lv_bar_set_value(bar, 0, LV_ANIM_OFF);
|
|
|
|
|
return bar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ---- tab "Pistes" ---- */
|
|
|
|
|
|
|
|
|
|
static void ui_build_tracks_tab(lv_obj_t *tab)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_set_style_pad_all(tab, 4, 0);
|
|
|
|
|
lv_obj_set_flex_flow(tab, LV_FLEX_FLOW_COLUMN);
|
|
|
|
|
lv_obj_set_style_pad_row(tab, 4, 0);
|
|
|
|
|
lv_obj_clear_flag(tab, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
|
|
|
|
|
|
/* row of 4 track pads */
|
|
|
|
|
lv_obj_t *row = lv_obj_create(tab);
|
|
|
|
|
lv_obj_set_size(row, lv_pct(100), 110);
|
|
|
|
|
lv_obj_set_style_bg_opa(row, LV_OPA_TRANSP, 0);
|
|
|
|
|
lv_obj_set_style_border_width(row, 0, 0);
|
|
|
|
|
lv_obj_set_style_pad_all(row, 0, 0);
|
|
|
|
|
lv_obj_set_flex_flow(row, LV_FLEX_FLOW_ROW);
|
|
|
|
|
lv_obj_set_style_pad_column(row, 4, 0);
|
|
|
|
|
lv_obj_clear_flag(row, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
|
|
|
|
|
|
for (uint32_t n = 0; n < LINK_TRACK_CNT; n++)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_t *pad = lv_obj_create(row);
|
|
|
|
|
lv_obj_set_flex_grow(pad, 1);
|
|
|
|
|
lv_obj_set_height(pad, lv_pct(100));
|
|
|
|
|
lv_obj_set_style_bg_color(pad, lv_color_hex(COL_EMPTY), 0);
|
|
|
|
|
lv_obj_set_style_border_width(pad, 0, 0);
|
|
|
|
|
lv_obj_set_style_radius(pad, 6, 0);
|
|
|
|
|
lv_obj_set_style_pad_all(pad, 4, 0);
|
|
|
|
|
lv_obj_add_flag(pad, LV_OBJ_FLAG_CLICKABLE);
|
|
|
|
|
lv_obj_clear_flag(pad, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
|
lv_obj_add_event_cb(pad, track_pad_event_cb, LV_EVENT_SHORT_CLICKED,
|
|
|
|
|
(void *)(uintptr_t)n);
|
|
|
|
|
lv_obj_add_event_cb(pad, track_pad_event_cb, LV_EVENT_LONG_PRESSED,
|
|
|
|
|
(void *)(uintptr_t)n);
|
|
|
|
|
track_pad[n] = pad;
|
|
|
|
|
|
|
|
|
|
track_label[n] = lv_label_create(pad);
|
|
|
|
|
lv_label_set_text_fmt(track_label[n], "T%u", (unsigned)(n + 1));
|
|
|
|
|
lv_obj_set_style_text_color(track_label[n], lv_color_white(), 0);
|
|
|
|
|
lv_obj_align(track_label[n], LV_ALIGN_TOP_MID, 0, 0);
|
|
|
|
|
|
|
|
|
|
lv_obj_t *vu = lv_bar_create(pad);
|
|
|
|
|
lv_obj_set_size(vu, 12, 70);
|
|
|
|
|
lv_obj_align(vu, LV_ALIGN_BOTTOM_MID, 0, 0);
|
|
|
|
|
lv_bar_set_range(vu, 0, 255);
|
|
|
|
|
lv_bar_set_value(vu, 0, LV_ANIM_OFF);
|
|
|
|
|
track_vu[n] = vu;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* loop position */
|
|
|
|
|
pos_bar = make_hbar(tab, lv_pct(100), 10);
|
|
|
|
|
lv_bar_set_range(pos_bar, 0, 1000);
|
|
|
|
|
/* loop length marker: thin vertical line overlaid on the bar */
|
|
|
|
|
len_line = lv_obj_create(pos_bar);
|
|
|
|
|
lv_obj_set_size(len_line, 3, 10);
|
|
|
|
|
lv_obj_set_style_bg_color(len_line, lv_color_hex(0xFFD000), 0);
|
|
|
|
|
lv_obj_set_style_border_width(len_line, 0, 0);
|
|
|
|
|
lv_obj_set_style_radius(len_line, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* transport row */
|
|
|
|
|
lv_obj_t *transport = lv_obj_create(tab);
|
|
|
|
|
lv_obj_set_size(transport, lv_pct(100), 46);
|
|
|
|
|
lv_obj_set_style_bg_opa(transport, LV_OPA_TRANSP, 0);
|
|
|
|
|
lv_obj_set_style_border_width(transport, 0, 0);
|
|
|
|
|
lv_obj_set_style_pad_all(transport, 0, 0);
|
|
|
|
|
lv_obj_set_flex_flow(transport, LV_FLEX_FLOW_ROW);
|
|
|
|
|
lv_obj_set_style_pad_column(transport, 4, 0);
|
|
|
|
|
lv_obj_clear_flag(transport, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
|
|
|
|
|
|
make_btn(transport, "Len", simple_cmd_event_cb,
|
|
|
|
|
(void *)(uintptr_t)LINK_CMD_SET_LENGTH);
|
|
|
|
|
make_btn(transport, LV_SYMBOL_PLAY, simple_cmd_event_cb,
|
|
|
|
|
(void *)(uintptr_t)LINK_CMD_START_ALL);
|
|
|
|
|
make_btn(transport, LV_SYMBOL_STOP, simple_cmd_event_cb,
|
|
|
|
|
(void *)(uintptr_t)LINK_CMD_STOP_ALL);
|
|
|
|
|
|
|
|
|
|
click_btn = lv_button_create(transport);
|
|
|
|
|
lv_obj_add_event_cb(click_btn, simple_cmd_event_cb, LV_EVENT_CLICKED,
|
|
|
|
|
(void *)(uintptr_t)LINK_CMD_CLICK_TOGGLE);
|
|
|
|
|
lv_obj_t *click_label = lv_label_create(click_btn);
|
|
|
|
|
lv_label_set_text(click_label, LV_SYMBOL_BELL);
|
|
|
|
|
lv_obj_center(click_label);
|
|
|
|
|
|
|
|
|
|
lv_obj_t *bpm_btn = lv_button_create(transport);
|
|
|
|
|
lv_obj_add_event_cb(bpm_btn, bpm_event_cb, LV_EVENT_CLICKED, NULL);
|
|
|
|
|
bpm_btn_label = lv_label_create(bpm_btn);
|
|
|
|
|
lv_label_set_text(bpm_btn_label, "120");
|
|
|
|
|
lv_obj_center(bpm_btn_label);
|
|
|
|
|
|
|
|
|
|
/* in/out VU */
|
|
|
|
|
lv_obj_t *vu_col = lv_obj_create(transport);
|
|
|
|
|
lv_obj_set_flex_grow(vu_col, 1);
|
|
|
|
|
lv_obj_set_height(vu_col, lv_pct(100));
|
|
|
|
|
lv_obj_set_style_bg_opa(vu_col, LV_OPA_TRANSP, 0);
|
|
|
|
|
lv_obj_set_style_border_width(vu_col, 0, 0);
|
|
|
|
|
lv_obj_set_style_pad_all(vu_col, 2, 0);
|
|
|
|
|
lv_obj_set_flex_flow(vu_col, LV_FLEX_FLOW_COLUMN);
|
|
|
|
|
lv_obj_set_style_pad_row(vu_col, 4, 0);
|
|
|
|
|
lv_obj_clear_flag(vu_col, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
|
vu_in_bar = make_hbar(vu_col, lv_pct(100), 8);
|
|
|
|
|
vu_out_bar = make_hbar(vu_col, lv_pct(100), 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ---- tab "Réglages" ---- */
|
|
|
|
|
|
|
|
|
|
static void ui_build_settings_tab(lv_obj_t *tab)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_set_style_pad_all(tab, 6, 0);
|
|
|
|
|
lv_obj_set_flex_flow(tab, LV_FLEX_FLOW_COLUMN);
|
|
|
|
|
lv_obj_set_style_pad_row(tab, 6, 0);
|
|
|
|
|
|
|
|
|
|
for (uint32_t n = 0; n < LINK_TRACK_CNT; n++)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_t *row = lv_obj_create(tab);
|
|
|
|
|
lv_obj_set_size(row, lv_pct(100), 34);
|
|
|
|
|
lv_obj_set_style_bg_opa(row, LV_OPA_TRANSP, 0);
|
|
|
|
|
lv_obj_set_style_border_width(row, 0, 0);
|
|
|
|
|
lv_obj_set_style_pad_all(row, 0, 0);
|
|
|
|
|
lv_obj_set_flex_flow(row, LV_FLEX_FLOW_ROW);
|
|
|
|
|
lv_obj_set_style_pad_column(row, 8, 0);
|
|
|
|
|
lv_obj_set_flex_align(row, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER,
|
|
|
|
|
LV_FLEX_ALIGN_CENTER);
|
|
|
|
|
lv_obj_clear_flag(row, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
|
|
|
|
|
|
lv_obj_t *name = lv_label_create(row);
|
|
|
|
|
lv_label_set_text_fmt(name, "T%u", (unsigned)(n + 1));
|
|
|
|
|
|
|
|
|
|
gain_slider[n] = lv_slider_create(row);
|
|
|
|
|
lv_obj_set_flex_grow(gain_slider[n], 2);
|
|
|
|
|
lv_slider_set_range(gain_slider[n], 0, 255);
|
|
|
|
|
lv_slider_set_value(gain_slider[n], 255, LV_ANIM_OFF);
|
|
|
|
|
lv_obj_add_event_cb(gain_slider[n], gain_slider_event_cb,
|
|
|
|
|
LV_EVENT_VALUE_CHANGED, (void *)(uintptr_t)n);
|
|
|
|
|
|
|
|
|
|
pan_slider[n] = lv_slider_create(row);
|
|
|
|
|
lv_obj_set_flex_grow(pan_slider[n], 1);
|
|
|
|
|
lv_slider_set_range(pan_slider[n], 0, 255);
|
|
|
|
|
lv_slider_set_value(pan_slider[n], 128, LV_ANIM_OFF);
|
|
|
|
|
lv_obj_add_event_cb(pan_slider[n], pan_slider_event_cb,
|
|
|
|
|
LV_EVENT_VALUE_CHANGED, (void *)(uintptr_t)n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* input row */
|
|
|
|
|
lv_obj_t *in_row = lv_obj_create(tab);
|
|
|
|
|
lv_obj_set_size(in_row, lv_pct(100), 36);
|
|
|
|
|
lv_obj_set_style_bg_opa(in_row, LV_OPA_TRANSP, 0);
|
|
|
|
|
lv_obj_set_style_border_width(in_row, 0, 0);
|
|
|
|
|
lv_obj_set_style_pad_all(in_row, 0, 0);
|
|
|
|
|
lv_obj_set_flex_flow(in_row, LV_FLEX_FLOW_ROW);
|
|
|
|
|
lv_obj_set_style_pad_column(in_row, 8, 0);
|
|
|
|
|
lv_obj_set_flex_align(in_row, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER,
|
|
|
|
|
LV_FLEX_ALIGN_CENTER);
|
|
|
|
|
lv_obj_clear_flag(in_row, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
|
|
|
|
|
|
lv_obj_t *in_label = lv_label_create(in_row);
|
|
|
|
|
lv_label_set_text(in_label, "In");
|
|
|
|
|
|
|
|
|
|
gain_in_slider = lv_slider_create(in_row);
|
|
|
|
|
lv_obj_set_flex_grow(gain_in_slider, 1);
|
|
|
|
|
lv_slider_set_range(gain_in_slider, 0, 255);
|
|
|
|
|
lv_slider_set_value(gain_in_slider, 255, LV_ANIM_OFF);
|
|
|
|
|
lv_obj_add_event_cb(gain_in_slider, gain_in_slider_event_cb,
|
|
|
|
|
LV_EVENT_VALUE_CHANGED, NULL);
|
|
|
|
|
|
|
|
|
|
lv_obj_t *src_btn = lv_button_create(in_row);
|
|
|
|
|
lv_obj_add_event_cb(src_btn, simple_cmd_event_cb, LV_EVENT_CLICKED,
|
|
|
|
|
(void *)(uintptr_t)LINK_CMD_TOGGLE_SRC);
|
|
|
|
|
src_btn_label = lv_label_create(src_btn);
|
|
|
|
|
lv_label_set_text(src_btn_label, "Line");
|
|
|
|
|
lv_obj_center(src_btn_label);
|
|
|
|
|
|
|
|
|
|
/* SD row */
|
|
|
|
|
lv_obj_t *sd_row = lv_obj_create(tab);
|
|
|
|
|
lv_obj_set_size(sd_row, lv_pct(100), 40);
|
|
|
|
|
lv_obj_set_style_bg_opa(sd_row, LV_OPA_TRANSP, 0);
|
|
|
|
|
lv_obj_set_style_border_width(sd_row, 0, 0);
|
|
|
|
|
lv_obj_set_style_pad_all(sd_row, 0, 0);
|
|
|
|
|
lv_obj_set_flex_flow(sd_row, LV_FLEX_FLOW_ROW);
|
|
|
|
|
lv_obj_set_style_pad_column(sd_row, 8, 0);
|
|
|
|
|
lv_obj_set_flex_align(sd_row, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER,
|
|
|
|
|
LV_FLEX_ALIGN_CENTER);
|
|
|
|
|
lv_obj_clear_flag(sd_row, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
|
|
|
|
|
|
sd_dropdown = lv_dropdown_create(sd_row);
|
|
|
|
|
lv_dropdown_set_options(sd_dropdown,
|
|
|
|
|
"Session 0\nSession 1\nSession 2\nSession 3\n"
|
|
|
|
|
"Session 4\nSession 5\nSession 6\nSession 7");
|
|
|
|
|
lv_obj_set_width(sd_dropdown, 120);
|
|
|
|
|
|
|
|
|
|
make_btn(sd_row, LV_SYMBOL_SAVE, sd_save_event_cb, NULL);
|
|
|
|
|
make_btn(sd_row, LV_SYMBOL_DOWNLOAD, sd_load_event_cb, NULL);
|
|
|
|
|
|
|
|
|
|
sd_progress = make_hbar(tab, lv_pct(100), 8);
|
|
|
|
|
lv_bar_set_range(sd_progress, 0, 100);
|
|
|
|
|
|
|
|
|
|
sd_status_label = lv_label_create(tab);
|
|
|
|
|
lv_label_set_text(sd_status_label, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ---- public API ---- */
|
|
|
|
|
|
|
|
|
|
void ui_init(void)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_t *scr = lv_screen_active();
|
|
|
|
|
lv_obj_set_style_bg_color(scr, lv_color_hex(COL_BG), 0);
|
|
|
|
|
|
|
|
|
|
lv_obj_t *tv = lv_tabview_create(scr);
|
|
|
|
|
lv_tabview_set_tab_bar_size(tv, 28);
|
|
|
|
|
lv_obj_set_style_bg_color(tv, lv_color_hex(COL_BG), 0);
|
|
|
|
|
|
|
|
|
|
ui_build_tracks_tab(lv_tabview_add_tab(tv, "Pistes"));
|
|
|
|
|
ui_build_settings_tab(lv_tabview_add_tab(tv, "Réglages"));
|
|
|
|
|
|
|
|
|
|
disconnected_banner = lv_obj_create(scr);
|
|
|
|
|
lv_obj_set_size(disconnected_banner, lv_pct(100), lv_pct(100));
|
|
|
|
|
lv_obj_set_style_bg_color(disconnected_banner, lv_color_hex(0x101010), 0);
|
|
|
|
|
lv_obj_set_style_bg_opa(disconnected_banner, LV_OPA_90, 0);
|
|
|
|
|
lv_obj_t *label = lv_label_create(disconnected_banner);
|
|
|
|
|
lv_label_set_text(label, "Looper déconnecté\n(liaison UART inactive)");
|
|
|
|
|
lv_obj_set_style_text_color(label, lv_color_hex(0xE0E0E0), 0);
|
|
|
|
|
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
|
|
|
|
lv_obj_center(label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ui_set_connected(bool on)
|
|
|
|
|
{
|
|
|
|
|
if (on)
|
|
|
|
|
{
|
|
|
|
|
lv_obj_add_flag(disconnected_banner, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lv_obj_clear_flag(disconnected_banner, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ui_apply_state(const link_state_t *s)
|
|
|
|
|
{
|
|
|
|
|
for (uint32_t n = 0; n < LINK_TRACK_CNT; n++)
|
|
|
|
|
{
|
|
|
|
|
uint8_t f = s->flags[n];
|
|
|
|
|
uint32_t col = COL_EMPTY;
|
|
|
|
|
if (f & LINK_TRK_ERASE)
|
|
|
|
|
{
|
|
|
|
|
col = COL_ERASE;
|
|
|
|
|
}
|
|
|
|
|
else if (f & LINK_TRK_REC)
|
|
|
|
|
{
|
|
|
|
|
col = COL_REC;
|
|
|
|
|
}
|
|
|
|
|
else if (f & LINK_TRK_ACTIVE)
|
|
|
|
|
{
|
|
|
|
|
col = COL_PLAY;
|
|
|
|
|
}
|
|
|
|
|
else if (f & LINK_TRK_DATA)
|
|
|
|
|
{
|
|
|
|
|
col = COL_DATA;
|
|
|
|
|
}
|
|
|
|
|
lv_obj_set_style_bg_color(track_pad[n], lv_color_hex(col), 0);
|
|
|
|
|
lv_bar_set_value(track_vu[n], s->vu[n], LV_ANIM_OFF);
|
|
|
|
|
|
|
|
|
|
if (!lv_obj_has_state(gain_slider[n], LV_STATE_PRESSED))
|
|
|
|
|
{
|
|
|
|
|
lv_slider_set_value(gain_slider[n], s->gain_out[n], LV_ANIM_OFF);
|
|
|
|
|
}
|
|
|
|
|
if (!lv_obj_has_state(pan_slider[n], LV_STATE_PRESSED))
|
|
|
|
|
{
|
|
|
|
|
lv_slider_set_value(pan_slider[n], s->pan[n], LV_ANIM_OFF);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* position within the current loop length */
|
|
|
|
|
uint16_t len = (s->len > 0) ? s->len : 1;
|
|
|
|
|
uint32_t pos_rel = ((uint32_t)s->pos * 1000u) / len;
|
|
|
|
|
if (pos_rel > 1000)
|
|
|
|
|
{
|
|
|
|
|
pos_rel = 1000;
|
|
|
|
|
}
|
|
|
|
|
lv_bar_set_value(pos_bar, (int32_t)pos_rel, LV_ANIM_OFF);
|
|
|
|
|
int32_t bar_w = lv_obj_get_width(pos_bar);
|
|
|
|
|
lv_obj_set_x(len_line, (bar_w * s->len) / 65535 - 2);
|
|
|
|
|
|
|
|
|
|
last_bpm = s->tempo_bpm;
|
|
|
|
|
lv_label_set_text_fmt(bpm_btn_label, "%u", (unsigned)s->tempo_bpm);
|
|
|
|
|
lv_obj_set_style_bg_color(click_btn,
|
|
|
|
|
lv_color_hex(s->click_on ? 0x22883A : 0x3A3A3A),
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
lv_bar_set_value(vu_in_bar, s->vu[LINK_TRACK_CNT], LV_ANIM_OFF);
|
|
|
|
|
lv_bar_set_value(vu_out_bar, s->vu[LINK_TRACK_CNT + 1], LV_ANIM_OFF);
|
|
|
|
|
|
|
|
|
|
if (!lv_obj_has_state(gain_in_slider, LV_STATE_PRESSED))
|
|
|
|
|
{
|
|
|
|
|
lv_slider_set_value(gain_in_slider, s->gain_in, LV_ANIM_OFF);
|
|
|
|
|
}
|
|
|
|
|
lv_label_set_text(src_btn_label, s->input_src ? "Mic" : "Line");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ui_apply_evt(const link_evt_t *e)
|
|
|
|
|
{
|
|
|
|
|
switch (e->code)
|
|
|
|
|
{
|
|
|
|
|
case LINK_EVT_SD_PROGRESS:
|
|
|
|
|
lv_bar_set_value(sd_progress, e->arg, LV_ANIM_OFF);
|
|
|
|
|
break;
|
|
|
|
|
case LINK_EVT_SD_DONE:
|
|
|
|
|
lv_bar_set_value(sd_progress, 100, LV_ANIM_OFF);
|
|
|
|
|
lv_label_set_text_fmt(sd_status_label, "Session %u OK",
|
|
|
|
|
(unsigned)e->arg);
|
|
|
|
|
break;
|
|
|
|
|
case LINK_EVT_SD_ERROR:
|
|
|
|
|
lv_label_set_text_fmt(sd_status_label, "Erreur SD (code %u)",
|
|
|
|
|
(unsigned)e->arg);
|
|
|
|
|
break;
|
|
|
|
|
case LINK_EVT_RESET_DONE:
|
|
|
|
|
lv_label_set_text(sd_status_label, "Reset effectué");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|