mirror of
https://github.com/jhbruhn/eurorack.git
synced 2025-03-15 02:55:49 +00:00
Implement editing of values in menus
This commit is contained in:
parent
8f90701c7a
commit
43b75dd2ab
5 changed files with 71 additions and 26 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue