feat(color): Add alternate layouts for model list in Manage Models page (#4524)
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
@@ -957,19 +957,20 @@ PACK(struct RadioData {
|
||||
|
||||
// Radio level tabs control (global settings)
|
||||
#if defined(COLORLCD)
|
||||
uint8_t radioThemesDisabled:1;
|
||||
NOBACKUP(uint8_t modelSelectLayout:2);
|
||||
NOBACKUP(uint8_t radioThemesDisabled:1);
|
||||
#endif
|
||||
uint8_t radioGFDisabled:1;
|
||||
uint8_t radioTrainerDisabled:1;
|
||||
NOBACKUP(uint8_t radioGFDisabled:1);
|
||||
NOBACKUP(uint8_t radioTrainerDisabled:1);
|
||||
// Model level tabs control (global setting)
|
||||
uint8_t modelHeliDisabled:1;
|
||||
uint8_t modelFMDisabled:1;
|
||||
uint8_t modelCurvesDisabled:1;
|
||||
uint8_t modelGVDisabled:1;
|
||||
uint8_t modelLSDisabled:1;
|
||||
uint8_t modelSFDisabled:1;
|
||||
uint8_t modelCustomScriptsDisabled:1;
|
||||
uint8_t modelTelemetryDisabled:1;
|
||||
NOBACKUP(uint8_t modelHeliDisabled:1);
|
||||
NOBACKUP(uint8_t modelFMDisabled:1);
|
||||
NOBACKUP(uint8_t modelCurvesDisabled:1);
|
||||
NOBACKUP(uint8_t modelGVDisabled:1);
|
||||
NOBACKUP(uint8_t modelLSDisabled:1);
|
||||
NOBACKUP(uint8_t modelSFDisabled:1);
|
||||
NOBACKUP(uint8_t modelCustomScriptsDisabled:1);
|
||||
NOBACKUP(uint8_t modelTelemetryDisabled:1);
|
||||
|
||||
NOBACKUP(uint8_t getBrightness() const
|
||||
{
|
||||
|
||||
@@ -191,6 +191,18 @@ static const uint8_t stick_pointer[] = {
|
||||
static const uint8_t stick_background[] = {
|
||||
#include "alpha_stick_background.lbm"
|
||||
};
|
||||
static const uint8_t mask_model_grid_large[] = {
|
||||
#include "mask_model_grid_large.lbm"
|
||||
};
|
||||
static const uint8_t mask_model_grid_small[] = {
|
||||
#include "mask_model_grid_small.lbm"
|
||||
};
|
||||
static const uint8_t mask_model_list_one[] = {
|
||||
#include "mask_model_list_one.lbm"
|
||||
};
|
||||
static const uint8_t mask_model_list_two[] = {
|
||||
#include "mask_model_list_two.lbm"
|
||||
};
|
||||
|
||||
BitmapBuffer * calibStick = nullptr;
|
||||
BitmapBuffer * calibStickBackground = nullptr;
|
||||
@@ -285,6 +297,10 @@ static const _BuiltinIcon _builtinIcons[] = {
|
||||
{ICON_MONITOR_CHANNELS3, mask_monitor_channels3},
|
||||
{ICON_MONITOR_CHANNELS4, mask_monitor_channels4},
|
||||
{ICON_MONITOR_LOGICAL_SWITCHES, mask_monitor_logsw},
|
||||
{ICON_MODEL_GRID_LARGE, mask_model_grid_large},
|
||||
{ICON_MODEL_GRID_SMALL, mask_model_grid_small},
|
||||
{ICON_MODEL_LIST_TWO, mask_model_list_two},
|
||||
{ICON_MODEL_LIST_ONE, mask_model_list_one},
|
||||
};
|
||||
|
||||
const uint8_t* getBuiltinIcon(MenuIcons id)
|
||||
|
||||
@@ -78,6 +78,10 @@ enum MenuIcons {
|
||||
ICON_MONITOR_CHANNELS3,
|
||||
ICON_MONITOR_CHANNELS4,
|
||||
ICON_MONITOR_LOGICAL_SWITCHES,
|
||||
ICON_MODEL_GRID_LARGE,
|
||||
ICON_MODEL_GRID_SMALL,
|
||||
ICON_MODEL_LIST_TWO,
|
||||
ICON_MODEL_LIST_ONE,
|
||||
MENUS_ICONS_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -32,17 +32,32 @@
|
||||
|
||||
inline tmr10ms_t getTicks() { return g_tmr10ms; }
|
||||
|
||||
constexpr coord_t MODEL_CELL_PADDING = 6;
|
||||
constexpr coord_t MODEL_SELECT_CELL_HEIGHT = 92;
|
||||
constexpr int BUTTONS_HEIGHT = 32;
|
||||
constexpr int MODEL_CELLS_PER_LINE = 2;
|
||||
|
||||
struct ModelButtonLayout {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t padding;
|
||||
bool hsaImage;
|
||||
uint16_t font;
|
||||
};
|
||||
|
||||
ModelButtonLayout modelLayouts[] = {
|
||||
#if LCD_W > LCD_H // Landscape
|
||||
{165, 92, 6, true, FONT(STD)},
|
||||
{108, 61, 6, true, FONT(XS)},
|
||||
{165, 32, 4, false, FONT(STD)},
|
||||
{336, 32, 4, false, FONT(STD)},
|
||||
#else // Portrait
|
||||
{147, 92, 6, true, FONT(STD)},
|
||||
{96, 61, 6, true, FONT(XS)},
|
||||
{147, 32, 4, false, FONT(STD)},
|
||||
{300, 32, 4, false, FONT(STD)},
|
||||
#endif
|
||||
};
|
||||
|
||||
#if LCD_W > LCD_H // Landscape
|
||||
constexpr int LABELS_WIDTH = 132;
|
||||
constexpr int LAY_MARGIN = 5;
|
||||
constexpr coord_t MODEL_SELECT_CELL_WIDTH =
|
||||
(LCD_W - LABELS_WIDTH - (MODEL_CELLS_PER_LINE + 1) * MODEL_CELL_PADDING) /
|
||||
MODEL_CELLS_PER_LINE;
|
||||
constexpr int LABELS_ROW = 0;
|
||||
constexpr int MODELS_COL = 1;
|
||||
constexpr int MODELS_ROW = 0;
|
||||
@@ -50,10 +65,6 @@ constexpr int MODELS_ROW_CNT = 2;
|
||||
constexpr int BUTTONS_ROW = 1;
|
||||
#else // Portrait
|
||||
constexpr int LAY_MARGIN = 8;
|
||||
constexpr int LABELS_HEIGHT = 140;
|
||||
constexpr coord_t MODEL_SELECT_CELL_WIDTH =
|
||||
(LCD_W - LAY_MARGIN - (MODEL_CELLS_PER_LINE + 1) * MODEL_CELL_PADDING) /
|
||||
MODEL_CELLS_PER_LINE;
|
||||
constexpr int LABELS_ROW = 1;
|
||||
constexpr int MODELS_COL = 0;
|
||||
constexpr int MODELS_ROW = 0;
|
||||
@@ -65,16 +76,17 @@ class ModelButton : public Button
|
||||
{
|
||||
public:
|
||||
ModelButton(FormWindow *parent, const rect_t &rect, ModelCell *modelCell,
|
||||
std::function<void()> setSelected) :
|
||||
std::function<void()> setSelected, uint8_t layout) :
|
||||
Button(parent, rect, nullptr, 0, 0, etx_button_create),
|
||||
layout(layout),
|
||||
modelCell(modelCell),
|
||||
m_setSelected(std::move(setSelected))
|
||||
{
|
||||
padAll(0);
|
||||
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
setWidth(MODEL_SELECT_CELL_WIDTH);
|
||||
setHeight(MODEL_SELECT_CELL_HEIGHT);
|
||||
setWidth(modelLayouts[layout].width);
|
||||
setHeight(modelLayouts[layout].height);
|
||||
|
||||
check(modelCell == modelslist.getCurrentModel());
|
||||
|
||||
@@ -98,38 +110,53 @@ class ModelButton : public Button
|
||||
coord_t w = width() - 8;
|
||||
coord_t h = height() - 8;
|
||||
|
||||
GET_FILENAME(filename, BITMAPS_PATH, modelCell->modelBitmap, "");
|
||||
const BitmapBuffer *bitmap = BitmapBuffer::loadBitmap(filename);
|
||||
LcdFlags font = modelLayouts[layout].font;
|
||||
if ((getTextWidth(modelCell->modelName, 0, font) > w))
|
||||
font = (font == FONT(STD)) ? FONT(XS) : FONT(XXS);
|
||||
|
||||
if (bitmap) {
|
||||
buffer = new BitmapBuffer(BMP_RGB565, w, h);
|
||||
if (buffer) {
|
||||
buffer->clear(bg_color);
|
||||
buffer->drawScaledBitmap(bitmap, 0, 0, w, h);
|
||||
delete bitmap;
|
||||
if (modelLayouts[layout].hsaImage) {
|
||||
GET_FILENAME(filename, BITMAPS_PATH, modelCell->modelBitmap, "");
|
||||
const BitmapBuffer *bitmap = BitmapBuffer::loadBitmap(filename);
|
||||
|
||||
lv_obj_t *bm = lv_canvas_create(lvobj);
|
||||
lv_obj_center(bm);
|
||||
lv_canvas_set_buffer(bm, buffer->getData(), buffer->width(),
|
||||
buffer->height(), LV_IMG_CF_TRUE_COLOR);
|
||||
if (bitmap) {
|
||||
buffer = new BitmapBuffer(BMP_RGB565, w, h);
|
||||
if (buffer) {
|
||||
buffer->clear(bg_color);
|
||||
buffer->drawScaledBitmap(bitmap, 0, 0, w, h);
|
||||
delete bitmap;
|
||||
|
||||
lv_obj_t *bm = lv_canvas_create(lvobj);
|
||||
lv_obj_center(bm);
|
||||
lv_canvas_set_buffer(bm, buffer->getData(), buffer->width(),
|
||||
buffer->height(), LV_IMG_CF_TRUE_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
std::string errorMsg = "(";
|
||||
errorMsg += STR_NO_PICTURE;
|
||||
errorMsg += ")";
|
||||
new StaticText(this, {2, h / 2, w, 17}, errorMsg, 0,
|
||||
CENTERED | COLOR_THEME_SECONDARY1 | FONT(XS));
|
||||
}
|
||||
if (!buffer) {
|
||||
std::string errorMsg = "(";
|
||||
errorMsg += STR_NO_PICTURE;
|
||||
errorMsg += ")";
|
||||
new StaticText(this, {2, h / 2, w, 17}, errorMsg, 0,
|
||||
CENTERED | COLOR_THEME_SECONDARY1 | FONT(XS));
|
||||
}
|
||||
|
||||
auto name =
|
||||
new StaticText(this, {2, 2, width() - 8, 17}, modelCell->modelName, 0,
|
||||
CENTERED | COLOR_THEME_SECONDARY1);
|
||||
name->setHeight(17);
|
||||
name->setBackgroudOpacity(LV_OPA_80);
|
||||
name->setBackgroundColor(bg_color);
|
||||
name->padTop(-3);
|
||||
coord_t fh = (font == FONT(STD)) ? 17 : (font == FONT(XS)) ? 14 : 11;
|
||||
coord_t fo = (font == FONT(STD)) ? -3 : (font == FONT(XS)) ? -3 : -1;
|
||||
|
||||
auto name = new StaticText(this, {2, 2, w, fh}, modelCell->modelName, 0,
|
||||
CENTERED | COLOR_THEME_SECONDARY1 | font);
|
||||
lv_label_set_long_mode(name->getLvObj(), LV_LABEL_LONG_DOT);
|
||||
name->setWidth(w);
|
||||
name->setHeight(fh);
|
||||
name->setBackgroudOpacity(LV_OPA_80);
|
||||
name->setBackgroundColor(bg_color);
|
||||
name->padTop(fo);
|
||||
} else {
|
||||
auto name = new StaticText(this, {2, 4, w, 24}, modelCell->modelName, 0,
|
||||
COLOR_THEME_SECONDARY1 | font);
|
||||
lv_label_set_long_mode(name->getLvObj(), LV_LABEL_LONG_DOT);
|
||||
name->setWidth(w);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_draw(lv_event_t *e)
|
||||
@@ -157,6 +184,7 @@ class ModelButton : public Button
|
||||
|
||||
protected:
|
||||
bool loaded = false;
|
||||
uint8_t layout;
|
||||
ModelCell *modelCell;
|
||||
BitmapBuffer *buffer = nullptr;
|
||||
std::function<void()> m_setSelected = nullptr;
|
||||
@@ -182,14 +210,16 @@ class ModelsPageBody : public FormWindow
|
||||
#else
|
||||
padLeft(LAY_MARGIN);
|
||||
#endif
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, MODEL_CELL_PADDING);
|
||||
padRow(MODEL_CELL_PADDING);
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
clear();
|
||||
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW_WRAP,
|
||||
modelLayouts[g_eeGeneral.modelSelectLayout].padding);
|
||||
padRow(modelLayouts[g_eeGeneral.modelSelectLayout].padding);
|
||||
|
||||
ModelsVector models;
|
||||
if (selectedLabels.size()) {
|
||||
models = modelslabels.getModelsInLabels(selectedLabels);
|
||||
@@ -206,8 +236,9 @@ class ModelsPageBody : public FormWindow
|
||||
ModelButton *focusedButton = nullptr;
|
||||
|
||||
for (auto &model : models) {
|
||||
auto button = new ModelButton(this, rect_t{}, model,
|
||||
[=]() { focusedModel = model; });
|
||||
auto button = new ModelButton(
|
||||
this, rect_t{}, model, [=]() { focusedModel = model; },
|
||||
g_eeGeneral.modelSelectLayout);
|
||||
|
||||
if (!firstButton) firstButton = button;
|
||||
if (model == modelslist.getCurrentModel()) focusedButton = button;
|
||||
@@ -481,6 +512,46 @@ class LabelDialog : public Dialog
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ModelLayoutButton : public TextButton
|
||||
{
|
||||
public:
|
||||
ModelLayoutButton(Window *parent, std::function<uint8_t(void)> pressHandler) :
|
||||
TextButton(parent, {0, 0, 32, 32}, "", pressHandler)
|
||||
{
|
||||
}
|
||||
|
||||
~ModelLayoutButton()
|
||||
{
|
||||
if (bmBuffer) delete bmBuffer;
|
||||
}
|
||||
|
||||
uint8_t getLayout() const { return layout; }
|
||||
|
||||
void setLayout(uint8_t newLayout)
|
||||
{
|
||||
layout = newLayout;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer *dc) override
|
||||
{
|
||||
auto maskData = getBuiltinIcon((MenuIcons)(ICON_MODEL_GRID_LARGE + layout));
|
||||
auto mask = BitmapBuffer::load8bitMaskLZ4(maskData);
|
||||
if (!bmBuffer)
|
||||
bmBuffer = new BitmapBuffer(BMP_RGB565, mask->width(), mask->height());
|
||||
bmBuffer->clear(COLOR_THEME_PRIMARY2);
|
||||
bmBuffer->drawMask(0, 0, mask, COLOR_THEME_SECONDARY1);
|
||||
delete mask;
|
||||
dc->drawBitmap(3, 3, bmBuffer);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t layout;
|
||||
BitmapBuffer *bmBuffer = nullptr;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL)
|
||||
{
|
||||
buildHead(&header);
|
||||
@@ -629,7 +700,7 @@ void ModelLabelsWindow::buildHead(PageHeader *hdr)
|
||||
setTitle();
|
||||
|
||||
// new model button
|
||||
auto btn = new TextButton(hdr, rect_t{}, STR_NEW, [=]() {
|
||||
auto btn = new TextButton(hdr, rect_t{0, 0, 60, 32}, STR_NEW, [=]() {
|
||||
auto menu = new Menu(this);
|
||||
menu->setTitle(STR_CREATE_NEW);
|
||||
menu->addLine(STR_NEW_MODEL, [=]() { newModel(); });
|
||||
@@ -642,14 +713,28 @@ void ModelLabelsWindow::buildHead(PageHeader *hdr)
|
||||
// button placement
|
||||
hdr->padRight(lv_dpx(8));
|
||||
lv_obj_align(btn->getLvObj(), LV_ALIGN_RIGHT_MID, 0, 0);
|
||||
|
||||
mldLayout = new ModelLayoutButton(this, [=]() {
|
||||
uint8_t l = mldLayout->getLayout();
|
||||
l = (l + 1) & 3;
|
||||
mldLayout->setLayout(l);
|
||||
g_eeGeneral.modelSelectLayout = l;
|
||||
storageDirty(EE_GENERAL);
|
||||
mdlselector->update();
|
||||
return 0;
|
||||
});
|
||||
mldLayout->setLayout(g_eeGeneral.modelSelectLayout);
|
||||
lv_obj_set_pos(mldLayout->getLvObj(), LCD_W - 105, 6);
|
||||
}
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
constexpr int LABELS_WIDTH = 132;
|
||||
static const lv_coord_t col_dsc[] = {LABELS_WIDTH, LV_GRID_FR(1),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_FR(1), BUTTONS_HEIGHT,
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
#else
|
||||
constexpr int LABELS_HEIGHT = 140;
|
||||
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_FR(1), LABELS_HEIGHT,
|
||||
BUTTONS_HEIGHT, LV_GRID_TEMPLATE_LAST};
|
||||
@@ -672,6 +757,9 @@ void ModelLabelsWindow::buildBody(FormWindow *window)
|
||||
lv_obj_set_grid_cell(mdl_obj, LV_GRID_ALIGN_STRETCH, MODELS_COL, 1,
|
||||
LV_GRID_ALIGN_STRETCH, MODELS_ROW, MODELS_ROW_CNT);
|
||||
|
||||
if (mdlselector->getSortOrder() == NO_SORT)
|
||||
mdlselector->setSortOrder(NAME_ASC);
|
||||
|
||||
// Labels
|
||||
auto box = new Window(window, rect_t{});
|
||||
box->padAll(0);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "tabsgroup.h"
|
||||
|
||||
class ModelsPageBody;
|
||||
class ModelLayoutButton;
|
||||
|
||||
class ModelLabelsWindow : public Page
|
||||
{
|
||||
@@ -38,6 +39,7 @@ class ModelLabelsWindow : public Page
|
||||
char tmpLabel[LABEL_LENGTH + 1] = "\0";
|
||||
ListBox *lblselector;
|
||||
ModelsPageBody *mdlselector;
|
||||
ModelLayoutButton *mldLayout;
|
||||
std::string currentLabel;
|
||||
|
||||
LabelsVector getLabels()
|
||||
|
||||
@@ -840,7 +840,7 @@ bool ModelMap::updateModelFile(ModelCell *cell)
|
||||
/**
|
||||
* @brief Sorts a ModelsVector by sortby
|
||||
*
|
||||
* @param mv ModeslVector to sort
|
||||
* @param mv ModelsVector to sort
|
||||
* @param sortby NO_SORT, NAME_ASC, NAME_DES, DATE_ASC, DATE_DES,
|
||||
*/
|
||||
|
||||
|
||||
@@ -367,6 +367,7 @@ static const struct YamlNode struct_RadioData[] = {
|
||||
YAML_SIGNED( "uartSampleMode", 2 ),
|
||||
YAML_UNSIGNED( "stickDeadZone", 3 ),
|
||||
YAML_STRING("selectedTheme", 26),
|
||||
YAML_UNSIGNED( "modelSelectLayout", 2 ),
|
||||
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
|
||||
YAML_UNSIGNED( "radioGFDisabled", 1 ),
|
||||
YAML_UNSIGNED( "radioTrainerDisabled", 1 ),
|
||||
|
||||
@@ -367,6 +367,7 @@ static const struct YamlNode struct_RadioData[] = {
|
||||
YAML_SIGNED( "uartSampleMode", 2 ),
|
||||
YAML_UNSIGNED( "stickDeadZone", 3 ),
|
||||
YAML_STRING("selectedTheme", 26),
|
||||
YAML_UNSIGNED( "modelSelectLayout", 2 ),
|
||||
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
|
||||
YAML_UNSIGNED( "radioGFDisabled", 1 ),
|
||||
YAML_UNSIGNED( "radioTrainerDisabled", 1 ),
|
||||
|
||||
@@ -369,6 +369,7 @@ static const struct YamlNode struct_RadioData[] = {
|
||||
YAML_SIGNED( "imuMax", 8 ),
|
||||
YAML_SIGNED( "imuOffset", 8 ),
|
||||
YAML_STRING("selectedTheme", 26),
|
||||
YAML_UNSIGNED( "modelSelectLayout", 2 ),
|
||||
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
|
||||
YAML_UNSIGNED( "radioGFDisabled", 1 ),
|
||||
YAML_UNSIGNED( "radioTrainerDisabled", 1 ),
|
||||
|
||||
@@ -369,6 +369,7 @@ static const struct YamlNode struct_RadioData[] = {
|
||||
YAML_SIGNED( "imuMax", 8 ),
|
||||
YAML_SIGNED( "imuOffset", 8 ),
|
||||
YAML_STRING("selectedTheme", 26),
|
||||
YAML_UNSIGNED( "modelSelectLayout", 2 ),
|
||||
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
|
||||
YAML_UNSIGNED( "radioGFDisabled", 1 ),
|
||||
YAML_UNSIGNED( "radioTrainerDisabled", 1 ),
|
||||
|
||||
Reference in New Issue
Block a user