feat(ui): Improvements to color picker (#2909)
* Revised color picker: - add title to popup window - add Save and Cancel buttons - Source value only updated when 'Save'' button pressed - Add editor to select from system theme colors * Center 'Cancel' and 'Save' buttons, make them both the same size and fill available space. Reduce width of dialog box on portrait screens.
This commit is contained in:
@@ -29,15 +29,6 @@ constexpr int BAR_HEIGHT_OFFSET = BAR_TOP_MARGIN + 25;
|
||||
static const char *RGBChars[MAX_BARS] = { "R", "G", "B" };
|
||||
static const char *HSVChars[MAX_BARS] = { "H", "S", "V" };
|
||||
|
||||
// ColorTypes()
|
||||
// A ColorType implements a three bar color editor. Currently we support HSV and RGB
|
||||
enum HSV_BAR_TYPE
|
||||
{
|
||||
HUE = 0,
|
||||
SATURATION = 1,
|
||||
BRIGHTNESS = 2
|
||||
};
|
||||
|
||||
void ColorBar::pressing(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
@@ -186,33 +177,68 @@ uint32_t ColorBar::screenToValue(int pos)
|
||||
return scaledValue;
|
||||
}
|
||||
|
||||
ColorType::ColorType(Window* parent, coord_t screenHeight) :
|
||||
screenHeight(screenHeight)
|
||||
BarColorType::BarColorType(Window* parent)
|
||||
{
|
||||
auto spacePerBar = (parent->width() / MAX_BARS);
|
||||
|
||||
int leftPos = 0;
|
||||
rect_t r;
|
||||
r.y = BAR_TOP_MARGIN;
|
||||
r.w = spacePerBar - BAR_MARGIN - 5;
|
||||
r.h = parent->height() - BAR_HEIGHT_OFFSET;
|
||||
|
||||
for ( int i=0; i < MAX_BARS; i++){
|
||||
rect_t r;
|
||||
r.x = leftPos + BAR_MARGIN;
|
||||
r.y = BAR_TOP_MARGIN;
|
||||
r.w = spacePerBar - BAR_MARGIN - 5;
|
||||
r.h = screenHeight;
|
||||
|
||||
|
||||
bars[i] = new ColorBar(parent, r);
|
||||
leftPos += spacePerBar;
|
||||
|
||||
// bar labels
|
||||
auto bar = bars[i];
|
||||
auto x = bar->left();
|
||||
auto y = bar->bottom();
|
||||
|
||||
barLabels[i] = create_bar_label(parent->getLvObj(), x, y + 9);
|
||||
barValLabels[i] = create_bar_value_label(parent->getLvObj(), x + 10, y + 3);
|
||||
}
|
||||
}
|
||||
|
||||
ColorType::~ColorType()
|
||||
BarColorType::~BarColorType()
|
||||
{
|
||||
for ( int i=0; i < MAX_BARS; i++) {
|
||||
bars[i]->deleteLater();
|
||||
}
|
||||
};
|
||||
|
||||
lv_obj_t* BarColorType::create_bar_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y)
|
||||
{
|
||||
lv_obj_t* obj = lv_label_create(parent);
|
||||
lv_obj_set_pos(obj, x, y);
|
||||
lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
lv_obj_set_style_text_font(obj, getFont(FONT(XXS)), 0);
|
||||
return obj;
|
||||
}
|
||||
|
||||
lv_obj_t* BarColorType::create_bar_value_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y)
|
||||
{
|
||||
lv_obj_t* obj = lv_label_create(parent);
|
||||
lv_obj_set_pos(obj, x, y);
|
||||
lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void BarColorType::setText()
|
||||
{
|
||||
for (int i = 0; i < MAX_BARS; i++) {
|
||||
auto bar = bars[i];
|
||||
lv_label_set_text_static(barLabels[i], getLabelChars()[i]);
|
||||
lv_label_set_text_fmt(barValLabels[i], "%" PRIu32, bar->value);
|
||||
bar->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
HSVColorType::HSVColorType(Window* parent, uint32_t color) :
|
||||
ColorType(parent, parent->height() - BAR_HEIGHT_OFFSET)
|
||||
BarColorType(parent)
|
||||
{
|
||||
auto r = GET_RED(color), g = GET_GREEN(color), b = GET_BLUE(color);
|
||||
float values[MAX_BARS];
|
||||
@@ -256,7 +282,7 @@ const char** HSVColorType::getLabelChars()
|
||||
}
|
||||
|
||||
RGBColorType::RGBColorType(Window* parent, uint32_t color) :
|
||||
ColorType(parent, parent->height() - BAR_HEIGHT_OFFSET)
|
||||
BarColorType(parent)
|
||||
{
|
||||
auto r = GET_RED(color), g = GET_GREEN(color), b = GET_BLUE(color);
|
||||
float values[MAX_BARS];
|
||||
@@ -285,21 +311,54 @@ const char** RGBColorType::getLabelChars()
|
||||
return RGBChars;
|
||||
}
|
||||
|
||||
static lv_obj_t* create_bar_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y)
|
||||
void ThemeColorType::makeButton(Window* parent, uint32_t color)
|
||||
{
|
||||
lv_obj_t* obj = lv_label_create(parent);
|
||||
lv_obj_set_pos(obj, x, y);
|
||||
lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
lv_obj_set_style_text_font(obj, getFont(FONT(XXS)), 0);
|
||||
return obj;
|
||||
auto btn = new TextButton(parent, rect_t{}, " ");
|
||||
btn->setPressHandler([=]() {
|
||||
auto cv = COLOR_VAL(color);
|
||||
m_color = RGB(GET_RED(cv), GET_GREEN(cv), GET_BLUE(cv));
|
||||
lv_event_send(parent->getParent()->getParent()->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
return 0;
|
||||
});
|
||||
btn->padAll(lv_dpx(7));
|
||||
lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(color), LV_PART_MAIN);
|
||||
lv_obj_add_style(btn->getLvObj(), &style, 0);
|
||||
}
|
||||
|
||||
static lv_obj_t* create_bar_value_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y)
|
||||
void ThemeColorType::makeButtonsRow(Window* parent, uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
lv_obj_t* obj = lv_label_create(parent);
|
||||
lv_obj_set_pos(obj, x, y);
|
||||
lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
return obj;
|
||||
auto hbox = new FormGroup(parent, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
|
||||
makeButton(hbox, c1);
|
||||
makeButton(hbox, c2);
|
||||
if (c3 != c2)
|
||||
makeButton(hbox, c3);
|
||||
}
|
||||
|
||||
ThemeColorType::ThemeColorType(Window* parent, uint32_t color) :
|
||||
ColorType()
|
||||
{
|
||||
m_color = color;
|
||||
|
||||
lv_style_init(&style);
|
||||
lv_style_set_border_opa(&style, LV_OPA_100);
|
||||
lv_style_set_border_width(&style, 2);
|
||||
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_GREY));
|
||||
|
||||
auto vbox = new FormGroup(parent, rect_t{});
|
||||
vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, lv_dpx(8));
|
||||
|
||||
makeButtonsRow(vbox, COLOR_THEME_PRIMARY1, COLOR_THEME_PRIMARY2, COLOR_THEME_PRIMARY3);
|
||||
makeButtonsRow(vbox, COLOR_THEME_SECONDARY1, COLOR_THEME_SECONDARY2, COLOR_THEME_SECONDARY3);
|
||||
makeButtonsRow(vbox, COLOR_THEME_FOCUS, COLOR_THEME_EDIT, COLOR_THEME_ACTIVE);
|
||||
makeButtonsRow(vbox, COLOR_THEME_WARNING, COLOR_THEME_DISABLED, COLOR_THEME_DISABLED);
|
||||
}
|
||||
|
||||
uint32_t ThemeColorType::getRGB()
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
@@ -312,19 +371,7 @@ ColorEditor::ColorEditor(Window *parent, const rect_t& rect, uint32_t color,
|
||||
_color(color)
|
||||
{
|
||||
_colorType = new HSVColorType(this, color);
|
||||
|
||||
// bar labels
|
||||
for (int i = 0; i < MAX_BARS; i++) {
|
||||
auto bar = _colorType->bars[i];
|
||||
auto x = bar->left();
|
||||
auto y = bar->bottom();
|
||||
|
||||
barLabels[i] = create_bar_label(lvobj, x, y + 9);
|
||||
lv_label_set_text_static(barLabels[i], _colorType->getLabelChars()[i]);
|
||||
|
||||
barValLabels[i] = create_bar_value_label(lvobj, x + 10, y + 3);
|
||||
lv_label_set_text_fmt(barValLabels[i], "%" PRIu32, bar->value);
|
||||
}
|
||||
_colorType->setText();
|
||||
|
||||
lv_obj_add_event_cb(lvobj, ColorEditor::value_changed, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
@@ -332,27 +379,25 @@ ColorEditor::ColorEditor(Window *parent, const rect_t& rect, uint32_t color,
|
||||
void ColorEditor::setColorEditorType(COLOR_EDITOR_TYPE colorType)
|
||||
{
|
||||
if (_colorType != nullptr) {
|
||||
clear();
|
||||
delete _colorType;
|
||||
}
|
||||
if (colorType == RGB_COLOR_EDITOR) {
|
||||
_colorType = new RGBColorType(this, _color);
|
||||
setRGB();
|
||||
} else {
|
||||
} else if (colorType == HSV_COLOR_EDITOR) {
|
||||
_colorType = new HSVColorType(this, _color);
|
||||
setHSV();
|
||||
} else {
|
||||
_colorType = new ThemeColorType(this, _color);
|
||||
setText();
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void ColorEditor::setText()
|
||||
{
|
||||
for (int i = 0; i < MAX_BARS; i++) {
|
||||
auto bar = _colorType->bars[i];
|
||||
lv_label_set_text_static(barLabels[i], _colorType->getLabelChars()[i]);
|
||||
lv_label_set_text_fmt(barValLabels[i], "%" PRIu32, bar->value);
|
||||
bar->invalidate();
|
||||
}
|
||||
|
||||
_colorType->setText();
|
||||
if (_setValue != nullptr) _setValue(_color);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,34 +47,78 @@ struct ColorBar : public FormField {
|
||||
static void draw_end(lv_event_t* e);
|
||||
};
|
||||
|
||||
struct ColorType
|
||||
// ColorTypes()
|
||||
// A ColorType implements an editor for selecting a color. Currently we support HSV, RGB and SYS (choose from system defined colors)
|
||||
class ColorType
|
||||
{
|
||||
ColorBar* bars[MAX_BARS];
|
||||
uint32_t screenHeight;
|
||||
public:
|
||||
ColorType() {}
|
||||
virtual ~ColorType() {}
|
||||
|
||||
ColorType(Window* parent, coord_t screenHeight);
|
||||
virtual ~ColorType();
|
||||
virtual void setText() {};
|
||||
virtual uint32_t getRGB() { return 0; };
|
||||
|
||||
virtual uint32_t getRGB() = 0;
|
||||
virtual const char** getLabelChars() = 0;
|
||||
protected:
|
||||
};
|
||||
|
||||
struct HSVColorType : public ColorType {
|
||||
// Color editor with three bars for selecting color value. Base class for HSV and RGB color types.
|
||||
class BarColorType : public ColorType
|
||||
{
|
||||
public:
|
||||
BarColorType(Window* parent);
|
||||
~BarColorType() override;
|
||||
|
||||
void setText() override;
|
||||
|
||||
protected:
|
||||
ColorBar* bars[MAX_BARS];
|
||||
lv_obj_t* barLabels[MAX_BARS];
|
||||
lv_obj_t* barValLabels[MAX_BARS];
|
||||
|
||||
virtual const char** getLabelChars() { return nullptr; };
|
||||
|
||||
lv_obj_t* create_bar_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y);
|
||||
lv_obj_t* create_bar_value_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y);
|
||||
};
|
||||
|
||||
// Color editor for HSV color input
|
||||
class HSVColorType : public BarColorType {
|
||||
public:
|
||||
HSVColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
protected:
|
||||
const char** getLabelChars() override;
|
||||
};
|
||||
|
||||
struct RGBColorType : public ColorType {
|
||||
// Color editor for RGB color input
|
||||
class RGBColorType : public BarColorType {
|
||||
public:
|
||||
RGBColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
protected:
|
||||
const char** getLabelChars() override;
|
||||
};
|
||||
|
||||
// Color editor that shows the system theme colors as buttons
|
||||
class ThemeColorType : public ColorType {
|
||||
public:
|
||||
ThemeColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
protected:
|
||||
uint32_t m_color;
|
||||
void makeButton(Window* parent, uint32_t color);
|
||||
void makeButtonsRow(Window* parent, uint32_t c1, uint32_t c2, uint32_t c3);
|
||||
lv_style_t style;
|
||||
};
|
||||
|
||||
enum COLOR_EDITOR_TYPE
|
||||
{
|
||||
RGB_COLOR_EDITOR = 0,
|
||||
HSV_COLOR_EDITOR
|
||||
HSV_COLOR_EDITOR,
|
||||
THM_COLOR_EDITOR
|
||||
};
|
||||
|
||||
// the ColorEditor() control is a group of other controls
|
||||
@@ -92,8 +136,6 @@ class ColorEditor : public FormGroup
|
||||
|
||||
protected:
|
||||
ColorType* _colorType = nullptr;
|
||||
lv_obj_t* barLabels[MAX_BARS];
|
||||
lv_obj_t* barValLabels[MAX_BARS];
|
||||
std::function<void(uint32_t)> _setValue;
|
||||
uint32_t _color;
|
||||
|
||||
|
||||
@@ -40,12 +40,13 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT,
|
||||
|
||||
class ColorEditorPopup : public Dialog
|
||||
{
|
||||
std::function<void(uint32_t)> _setValue;
|
||||
lv_obj_t* colorPad = nullptr;
|
||||
lv_obj_t* hexStr = nullptr;
|
||||
uint32_t m_color;
|
||||
|
||||
void updateColor(uint32_t c)
|
||||
{
|
||||
m_color = c;
|
||||
auto r = GET_RED(c), g = GET_GREEN(c), b = GET_BLUE(c);
|
||||
|
||||
auto lvcolor = lv_color_make(r, g, b);
|
||||
@@ -53,39 +54,33 @@ class ColorEditorPopup : public Dialog
|
||||
lv_label_set_text_fmt(hexStr, "%02X%02X%02X",
|
||||
(uint16_t)r, (uint16_t)g, (uint16_t)b);
|
||||
}
|
||||
|
||||
void setValue(uint32_t c)
|
||||
{
|
||||
if (_setValue) _setValue(c);
|
||||
updateColor(c);
|
||||
}
|
||||
|
||||
public:
|
||||
ColorEditorPopup(Window* parent, uint32_t color,
|
||||
std::function<void(uint32_t)> _setValue) :
|
||||
Dialog(parent, std::string(), rect_t{}),
|
||||
_setValue(std::move(_setValue))
|
||||
Dialog(parent, STR_COLOR_PICKER, rect_t{})
|
||||
{
|
||||
lv_obj_set_style_bg_color(content->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
|
||||
setCloseWhenClickOutside(true);
|
||||
auto form = &content->form;
|
||||
|
||||
FlexGridLayout grid(col_dsc, row_dsc);
|
||||
auto line = form->newLine(&grid);
|
||||
|
||||
rect_t r{ 0, 0, 6 * LV_DPI_DEF / 5, LV_DPI_DEF };
|
||||
auto cedit = new ColorEditor(line, r, color, [=](uint32_t c) { setValue(c); });
|
||||
rect_t r{ 0, 0, 7 * LV_DPI_DEF / 5, 7 * LV_DPI_DEF / 5 };
|
||||
auto cedit = new ColorEditor(line, r, color, [=](uint32_t c) { updateColor(c); });
|
||||
lv_obj_set_style_grid_cell_x_align(cedit->getLvObj(), LV_GRID_ALIGN_CENTER, 0);
|
||||
|
||||
auto vbox = new FormGroup(line, rect_t{});
|
||||
lv_obj_set_style_grid_cell_x_align(vbox->getLvObj(), LV_GRID_ALIGN_CENTER, 0);
|
||||
vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, lv_dpx(8));
|
||||
vbox->setWidth(r.w);
|
||||
vbox->setHeight(r.h);
|
||||
|
||||
auto hbox = new FormGroup(vbox, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
auto hbox_obj = hbox->getLvObj();
|
||||
lv_obj_set_flex_align(hbox_obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
|
||||
colorPad = window_create(hbox_obj);
|
||||
lv_obj_set_style_bg_opa(colorPad, LV_OPA_100, LV_PART_MAIN);
|
||||
@@ -99,13 +94,16 @@ class ColorEditorPopup : public Dialog
|
||||
|
||||
hbox = new FormGroup(vbox, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
|
||||
auto rgbBtn = new TextButton(hbox, rect_t{}, "RGB");
|
||||
auto hsvBtn = new TextButton(hbox, rect_t{}, "HSV");
|
||||
|
||||
auto thmBtn = new TextButton(hbox, rect_t{}, "SYS");
|
||||
|
||||
rgbBtn->setPressHandler([=]() {
|
||||
cedit->setColorEditorType(RGB_COLOR_EDITOR);
|
||||
hsvBtn->check(false);
|
||||
thmBtn->check(false);
|
||||
return 1;
|
||||
});
|
||||
rgbBtn->padAll(lv_dpx(8));
|
||||
@@ -113,14 +111,49 @@ class ColorEditorPopup : public Dialog
|
||||
hsvBtn->setPressHandler([=]() {
|
||||
cedit->setColorEditorType(HSV_COLOR_EDITOR);
|
||||
rgbBtn->check(false);
|
||||
thmBtn->check(false);
|
||||
return 1;
|
||||
});
|
||||
hsvBtn->padAll(lv_dpx(8));
|
||||
|
||||
thmBtn->setPressHandler([=]() {
|
||||
cedit->setColorEditorType(THM_COLOR_EDITOR);
|
||||
rgbBtn->check(false);
|
||||
hsvBtn->check(false);
|
||||
return 1;
|
||||
});
|
||||
thmBtn->padAll(lv_dpx(8));
|
||||
|
||||
// color editor defaults to HSV
|
||||
hsvBtn->check(true);
|
||||
|
||||
hbox = new FormGroup(vbox, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_END, LV_FLEX_ALIGN_SPACE_BETWEEN);
|
||||
lv_obj_set_flex_grow(hbox->getLvObj(), 1);
|
||||
|
||||
auto cancelBtn = new TextButton(hbox, rect_t{}, STR_CANCEL, [=]() -> int8_t {
|
||||
this->deleteLater();
|
||||
return 0;
|
||||
});
|
||||
cancelBtn->padTop(lv_dpx(12));
|
||||
cancelBtn->padBottom(lv_dpx(12));
|
||||
lv_obj_set_flex_grow(cancelBtn->getLvObj(), 1);
|
||||
|
||||
auto okBtn = new TextButton(hbox, rect_t{}, STR_SAVE, [=]() -> int8_t {
|
||||
if (_setValue) _setValue(m_color);
|
||||
this->deleteLater();
|
||||
return 0;
|
||||
});
|
||||
okBtn->padTop(lv_dpx(12));
|
||||
okBtn->padBottom(lv_dpx(12));
|
||||
lv_obj_set_flex_grow(okBtn->getLvObj(), 1);
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
content->setWidth(LCD_W * 0.9);
|
||||
#else
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
#endif
|
||||
content->updateSize();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user