Implement editing of values in menus

This commit is contained in:
Jan-Henrik 2020-02-21 01:39:20 +01:00
parent 8f90701c7a
commit 43b75dd2ab
5 changed files with 71 additions and 26 deletions

View file

@ -15,27 +15,32 @@ void Menu::render(u8g2_t* u8g2_, uint8_t xStart, uint8_t yStart, uint8_t width,
u8g2_SetFont(u8g2_, u8g2_font_6x12_tf); u8g2_SetFont(u8g2_, u8g2_font_6x12_tf);
for (uint8_t i = 0; i < itemsToRender; i++) { for (uint8_t i = 0; i < itemsToRender; i++) {
bool selected = this->selectedItem == (i + this->currentScrollStart); bool selected = this->selectedItem == (i + this->currentScrollStart);
bool editing = this->currentEditingItem == (i + this->currentScrollStart);
uint8_t yPosition = yStart + i * MENU_ITEM_HEIGHT; uint8_t yPosition = yStart + i * MENU_ITEM_HEIGHT;
AbstractMenuItem* item = this->items[i + this->currentScrollStart]; AbstractMenuItem* item = this->items[i + this->currentScrollStart];
u8g2_SetDrawColor(u8g2_, selected ? 1 : 0); u8g2_SetDrawColor(u8g2_, selected ? 1 : 0);
if (selected) { if(editing) {
u8g2_DrawFrame(u8g2_, xStart, yPosition, width, MENU_ITEM_HEIGHT);
} else if (selected) {
u8g2_DrawBox(u8g2_, xStart, yPosition, width, MENU_ITEM_HEIGHT); u8g2_DrawBox(u8g2_, xStart, yPosition, width, MENU_ITEM_HEIGHT);
} }
u8g2_SetDrawColor(u8g2_, !selected ? 1 : 0); u8g2_SetDrawColor(u8g2_, editing || !selected ? 1 : 0);
u8g2_DrawStr(u8g2_, xStart + 2, yPosition + MENU_ITEM_HEIGHT - 4, item->get_label()); u8g2_DrawStr(u8g2_, xStart + 2, yPosition + MENU_ITEM_HEIGHT - 3, item->get_label());
uint8_t valueStringWidth = u8g2_GetStrWidth(u8g2_, item->get_string_representation()); uint8_t valueStringWidth = u8g2_GetStrWidth(u8g2_, item->get_string_representation());
u8g2_DrawStr(u8g2_, xStart + width - valueStringWidth - 2, yPosition + MENU_ITEM_HEIGHT - 4, item->get_string_representation()); u8g2_DrawStr(u8g2_, xStart + width - valueStringWidth - 2, yPosition + MENU_ITEM_HEIGHT - 3, item->get_string_representation());
} }
} }
void Menu::up() void Menu::up()
{ {
if (this->selectedItem > 0) { if (this->currentEditingItem >= 0) {
this->items[this->selectedItem]->decrease();
} else if (this->selectedItem > 0) {
if (this->selectedItem - this->currentScrollStart == 1) { // keep scroll start one up if (this->selectedItem - this->currentScrollStart == 1) { // keep scroll start one up
this->currentScrollStart--; this->currentScrollStart--;
} }
@ -50,6 +55,9 @@ void Menu::up()
void Menu::down() void Menu::down()
{ {
if (this->currentEditingItem >= 0) {
this->items[this->selectedItem]->increase();
} else {
uint8_t maxVisibleItems = height / MENU_ITEM_HEIGHT; uint8_t maxVisibleItems = height / MENU_ITEM_HEIGHT;
if (this->selectedItem < this->itemCount - 1) { if (this->selectedItem < this->itemCount - 1) {
if (this->selectedItem - this->currentScrollStart == maxVisibleItems - 2 && this->itemCount - this->currentScrollStart > maxVisibleItems) { if (this->selectedItem - this->currentScrollStart == maxVisibleItems - 2 && this->itemCount - this->currentScrollStart > maxVisibleItems) {
@ -58,4 +66,14 @@ void Menu::down()
this->selectedItem++; this->selectedItem++;
} }
}
}
void Menu::enter()
{
if (this->currentEditingItem >= 0) {
this->currentEditingItem = -1;
return;
}
this->currentEditingItem = this->selectedItem;
} }

View file

@ -8,6 +8,8 @@ class AbstractMenuItem {
public: public:
virtual const char* get_label(); virtual const char* get_label();
virtual char* get_string_representation(); virtual char* get_string_representation();
virtual void increase();
virtual void decrease();
}; };
template <class T> template <class T>
@ -55,15 +57,16 @@ class MenuItem : public AbstractMenuItem {
template <class T> template <class T>
class NumberMenuItem : public MenuItem<T> { class NumberMenuItem : public MenuItem<T> {
private: private:
T step;
T minimumValue; T minimumValue;
T maximumValue; T maximumValue;
T step;
protected: protected:
NumberMenuItem(const char* _label, T _initialValue, T _minimumValue, T _maximumValue, T _step) NumberMenuItem(const char* _label, T _initialValue, T _minimumValue, T _maximumValue, T _step)
: MenuItem<T>(_label, _initialValue) : MenuItem<T>(_label, _initialValue)
, minimumValue(_minimumValue) , minimumValue(_minimumValue)
, maximumValue(_maximumValue) {}; , maximumValue(_maximumValue)
, step(_step) {};
virtual const char* get_format_string() = 0; virtual const char* get_format_string() = 0;
@ -75,13 +78,13 @@ class NumberMenuItem : public MenuItem<T> {
public: public:
void increase() void increase()
{ {
if (this->get_value() + step <= maximumValue) if (this->get_value() + step <= maximumValue && this->get_value() + step >= minimumValue)
this->set_value(this->get_value() + step); this->set_value(this->get_value() + step);
}; };
void decrease() void decrease()
{ {
if (this->get_value() - step >= minimumValue) if (this->get_value() - step >= minimumValue && this->get_value() - step <= maximumValue)
this->set_value(this->get_value() - step); this->set_value(this->get_value() - step);
}; };
}; };
@ -117,7 +120,7 @@ class FloatMenuItem : public NumberMenuItem<float> {
protected: protected:
const char* get_format_string() const char* get_format_string()
{ {
return "%f.2"; return "%.2f";
} }
public: public:

View file

@ -48,9 +48,8 @@ void PendSV_Handler() {}
// called every 1ms // called every 1ms
void SysTick_Handler() void SysTick_Handler()
{ {
IWDG_ReloadCounter();
system_clock.Tick();
ui.Poll(); ui.Poll();
system_clock.Tick();
} }
void TIM2_IRQHandler(void) void TIM2_IRQHandler(void)
@ -110,7 +109,7 @@ void Init(void)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
system_clock.Init(); system_clock.Init();
SysTick_Config(F_CPU / 8000); SysTick_Config(F_CPU / 1000);
//IWDG_Enable(); //IWDG_Enable();
gpio.Init(); gpio.Init();
@ -130,5 +129,6 @@ int main(void)
// do we want to call the watchdog here? it's the only part thats getting interrupted after all // do we want to call the watchdog here? it's the only part thats getting interrupted after all
// (next to the interrupts themselves potentially interrupting each other) // (next to the interrupts themselves potentially interrupting each other)
ui.DoEvents(); ui.DoEvents();
IWDG_ReloadCounter();
} }
} }

View file

@ -9,7 +9,8 @@
using namespace stmlib; using namespace stmlib;
#define HEADER_HEIGHT 16 #define HEADER_HEIGHT 14
const uint32_t kEncoderLongPressTime = 600;
const char part_names[4][2] = { "A", "B", "C", "D" }; const char part_names[4][2] = { "A", "B", "C", "D" };
@ -20,7 +21,7 @@ UIntMenuItem item3("ralle", 0, 0, 100, 1);
UIntMenuItem item4("ralle1", 0, 0, 100, 1); UIntMenuItem item4("ralle1", 0, 0, 100, 1);
UIntMenuItem item5("ralle2", 0, 0, 100, 1); UIntMenuItem item5("ralle2", 0, 0, 100, 1);
UIntMenuItem item6("ralle3", 0, 0, 100, 1); UIntMenuItem item6("ralle3", 0, 0, 100, 1);
UIntMenuItem item7("ralle4", 0, 0, 100, 1); FloatMenuItem item7("ralle4", 0, 0, 100, .25f);
void UI::Init() void UI::Init()
{ {
@ -38,6 +39,24 @@ void UI::Init()
void UI::Poll() void UI::Poll()
{ {
encoder.Debounce(); encoder.Debounce();
if (encoder.just_pressed()) {
encoder_press_time_ = system_clock.milliseconds();
encoder_long_press_event_sent_ = false;
}
if (!encoder_long_press_event_sent_) {
if (encoder.pressed()) {
uint32_t duration = system_clock.milliseconds() - encoder_press_time_;
if (duration >= kEncoderLongPressTime && !encoder_long_press_event_sent_) {
input_queue.AddEvent(CONTROL_ENCODER_LONG_CLICK, 0, 0);
encoder_long_press_event_sent_ = true;
}
}
if (encoder.released()) {
input_queue.AddEvent(CONTROL_ENCODER_CLICK, 0, 0);
}
}
int32_t increment = encoder.increment(); int32_t increment = encoder.increment();
if (increment != 0) { if (increment != 0) {
input_queue.AddEvent(CONTROL_ENCODER, 0, increment); input_queue.AddEvent(CONTROL_ENCODER, 0, increment);
@ -53,9 +72,9 @@ void UI::Draw()
case MENU_PART_2: case MENU_PART_2:
case MENU_PART_3: case MENU_PART_3:
case MENU_PART_4: case MENU_PART_4:
//DrawHeader(); DrawHeader();
//DrawPartMenu(current_menu); //DrawPartMenu(current_menu);
menu.render(display.u8g2(), 0, 0, 128, 64); menu.render(display.u8g2(), 0, 15, 128, 64 - 15);
break; break;
default: default:
@ -77,7 +96,7 @@ void UI::DrawHeader()
u8g2_DrawFrame(display.u8g2(), i * (DISPLAY_WIDTH / PART_COUNT), 0, (DISPLAY_WIDTH / PART_COUNT) - 1, HEADER_HEIGHT); u8g2_DrawFrame(display.u8g2(), i * (DISPLAY_WIDTH / PART_COUNT), 0, (DISPLAY_WIDTH / PART_COUNT) - 1, HEADER_HEIGHT);
u8g2_SetDrawColor(display.u8g2(), 2); u8g2_SetDrawColor(display.u8g2(), 2);
u8g2_DrawStr(display.u8g2(), i * (DISPLAY_WIDTH / PART_COUNT) + 5, 2 + 10, part_names[i]); u8g2_DrawStr(display.u8g2(), i * (DISPLAY_WIDTH / PART_COUNT) + 5, 0 + 10, part_names[i]);
u8g2_SetDrawColor(display.u8g2(), 1); u8g2_SetDrawColor(display.u8g2(), 1);
} }
} }
@ -120,6 +139,7 @@ bool UI::DoEvents()
void UI::OnClick() void UI::OnClick()
{ {
menu.enter();
} }
void UI::OnLongClick() void UI::OnLongClick()

View file

@ -23,17 +23,21 @@ class UI {
bool DoEvents(); bool DoEvents();
private: private:
Menu_t current_menu; Menu_t current_menu;
stmlib::EventQueue<16> input_queue; stmlib::EventQueue<16> input_queue;
bool long_press_event_sent_;
uint32_t start_stop_press_time_;
bool encoder_long_press_event_sent_;
uint32_t encoder_press_time_;
void Draw(); void Draw();
void DrawHeader(); void DrawHeader();
void DrawPartMenu(Menu_t menu); void DrawPartMenu(Menu_t menu);
void OnClick(); void OnClick();
void OnLongClick(); void OnLongClick();
void OnIncrement(stmlib::Event &e); void OnIncrement(stmlib::Event& e);
DISALLOW_COPY_AND_ASSIGN(UI); DISALLOW_COPY_AND_ASSIGN(UI);
}; };