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:
philmoz
2022-12-22 18:47:26 +10:00
committed by GitHub
parent 458dc049e5
commit da5d056257
3 changed files with 196 additions and 76 deletions
+96 -51
View File
@@ -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);
}
+54 -12
View File
@@ -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;
+46 -13
View File
@@ -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();
}
};