mirror of
https://github.com/jhbruhn/eurorack.git
synced 2025-03-15 02:55:49 +00:00
Implement invisible menu items but also destroy scrolling
This commit is contained in:
parent
4ae5d4a9b5
commit
600b139b8e
6 changed files with 145 additions and 35 deletions
|
@ -15,5 +15,5 @@ class BaseDisplay {
|
|||
void Init();
|
||||
|
||||
protected:
|
||||
virtual void InitGLib();
|
||||
virtual void InitGLib() = 0;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "menu.h"
|
||||
#include <algorithm>
|
||||
#include <u8g2.h>
|
||||
|
||||
const int kMenuItemHeight = 12;
|
||||
|
||||
void Menu::render(U8G2* u8g2_, uint8_t xStart, uint8_t yStart, uint8_t width, uint8_t height)
|
||||
|
@ -13,12 +12,25 @@ void Menu::render(U8G2* u8g2_, uint8_t xStart, uint8_t yStart, uint8_t width, ui
|
|||
|
||||
uint8_t itemsToRender = std::min(maxVisibleItems, uint8_t(this->itemCount - currentScrollStart));
|
||||
u8g2_->setFont(u8g2_font_6x10_tf);
|
||||
|
||||
uint8_t itemIndex = this->currentScrollStart;
|
||||
|
||||
for (uint8_t i = 0; i < itemsToRender; i++) {
|
||||
bool selected = this->selectedItem == (i + this->currentScrollStart);
|
||||
bool editing = this->currentEditingItem == (i + this->currentScrollStart);
|
||||
uint8_t yPosition = yStart + i * kMenuItemHeight;
|
||||
|
||||
AbstractMenuItem* item = this->items[i + this->currentScrollStart];
|
||||
AbstractMenuItem* item;
|
||||
|
||||
while (!(item = this->items[itemIndex])->visible()) {
|
||||
itemIndex++;
|
||||
if (itemIndex >= this->itemCount)
|
||||
break;
|
||||
}
|
||||
|
||||
if (itemIndex >= this->itemCount)
|
||||
break;
|
||||
|
||||
bool selected = this->selectedItem == itemIndex;
|
||||
bool editing = this->currentEditingItem == itemIndex;
|
||||
|
||||
u8g2_->setDrawColor(selected ? 1 : 0);
|
||||
|
||||
|
@ -33,19 +45,39 @@ void Menu::render(U8G2* u8g2_, uint8_t xStart, uint8_t yStart, uint8_t width, ui
|
|||
|
||||
uint8_t valueStringWidth = u8g2_->getStrWidth(item->get_string_representation());
|
||||
u8g2_->drawStr(xStart + width - valueStringWidth - 2, yPosition + kMenuItemHeight - 3, item->get_string_representation());
|
||||
|
||||
itemIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::up()
|
||||
{
|
||||
if (this->currentEditingItem >= 0) {
|
||||
// we store the amount of visible items before the counter before
|
||||
// changing and then compare afterwards to move the cursor back to
|
||||
// its intended position if necessary
|
||||
uint8_t visible_count_before = this->visible_item_count_before_selection();
|
||||
|
||||
this->items[this->selectedItem]->decrease();
|
||||
|
||||
uint8_t visible_count_after = this->visible_item_count_before_selection();
|
||||
|
||||
this->selectedItem += visible_count_after - visible_count_before;
|
||||
} else if (this->selectedItem > 0) {
|
||||
if (this->selectedItem - this->currentScrollStart == 1) { // keep scroll start one up
|
||||
uint8_t newItem = this->selectedItem;
|
||||
int8_t i;
|
||||
for (i = this->selectedItem - 1; i >= 0; i--) {
|
||||
if (this->items[i]->visible()) {
|
||||
newItem = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newItem - this->currentScrollStart == i) { // keep scroll start one up
|
||||
this->currentScrollStart--;
|
||||
}
|
||||
|
||||
this->selectedItem--;
|
||||
this->selectedItem = newItem;
|
||||
|
||||
if (this->selectedItem == 0) {
|
||||
this->currentScrollStart = 0;
|
||||
|
@ -56,15 +88,30 @@ void Menu::up()
|
|||
void Menu::down()
|
||||
{
|
||||
if (this->currentEditingItem >= 0) {
|
||||
uint8_t visible_count_before = this->visible_item_count_before_selection();
|
||||
|
||||
this->items[this->selectedItem]->increase();
|
||||
|
||||
uint8_t visible_count_after = this->visible_item_count_before_selection();
|
||||
|
||||
this->selectedItem += visible_count_after - visible_count_before;
|
||||
} else {
|
||||
uint8_t maxVisibleItems = height / kMenuItemHeight;
|
||||
if (this->selectedItem < this->itemCount - 1) {
|
||||
if (this->selectedItem - this->currentScrollStart == maxVisibleItems - 2 && this->itemCount - this->currentScrollStart > maxVisibleItems) {
|
||||
this->currentScrollStart++;
|
||||
}
|
||||
if (this->items[this->selectedItem + 1]->visible()) {
|
||||
if (this->selectedItem - this->currentScrollStart == maxVisibleItems - 2 && this->itemCount - this->currentScrollStart > maxVisibleItems) {
|
||||
this->currentScrollStart++;
|
||||
}
|
||||
|
||||
this->selectedItem++;
|
||||
this->selectedItem++;
|
||||
} else {
|
||||
for (size_t i = this->selectedItem + 1; i < this->itemCount; i++) {
|
||||
if (this->items[i]->visible()) {
|
||||
this->selectedItem = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,5 +35,29 @@ class Menu {
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t visible_item_count()
|
||||
{
|
||||
uint8_t count = 0;
|
||||
|
||||
for (size_t i = 0; i < itemCount; i++) {
|
||||
if (items[i]->visible())
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t visible_item_count_before_selection()
|
||||
{
|
||||
uint8_t count = 0;
|
||||
|
||||
for (size_t i = 0; i <= selectedItem; i++) {
|
||||
if (items[i]->visible())
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void render(U8G2* u8g2_, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
|
||||
};
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "stmlib/stmlib.h"
|
||||
#include <functional>
|
||||
#include <stdio.h>
|
||||
|
||||
static auto always_visible = [] { return true; };
|
||||
|
||||
// MenuItem without template so we can easily store pointers
|
||||
class AbstractMenuItem {
|
||||
private:
|
||||
std::function<bool()> visibility_indicator;
|
||||
|
||||
public:
|
||||
virtual const char* get_label();
|
||||
virtual char* get_string_representation();
|
||||
virtual void increase();
|
||||
virtual void decrease();
|
||||
AbstractMenuItem(std::function<bool()> visibility_indicator = always_visible)
|
||||
: visibility_indicator(visibility_indicator) {};
|
||||
bool visible()
|
||||
{
|
||||
if (visibility_indicator)
|
||||
return visibility_indicator();
|
||||
return true;
|
||||
}
|
||||
virtual const char* get_label() = 0;
|
||||
virtual char* get_string_representation() = 0;
|
||||
virtual void increase() = 0;
|
||||
virtual void decrease() = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
@ -21,9 +35,11 @@ class MenuItem : public AbstractMenuItem {
|
|||
char stringRepresentation[24];
|
||||
|
||||
protected:
|
||||
MenuItem() {};
|
||||
MenuItem(const char* _label, T* _value)
|
||||
: label(_label)
|
||||
MenuItem()
|
||||
: AbstractMenuItem(always_visible) {};
|
||||
MenuItem(const char* _label, T* _value, std::function<bool()> visibility_indicator = always_visible)
|
||||
: AbstractMenuItem(visibility_indicator)
|
||||
, label(_label)
|
||||
, value(_value) {};
|
||||
|
||||
virtual void to_string(char* buf) = 0;
|
||||
|
@ -37,6 +53,13 @@ class MenuItem : public AbstractMenuItem {
|
|||
};
|
||||
|
||||
public:
|
||||
bool visible()
|
||||
{
|
||||
if (this->visibility_indicator)
|
||||
return this->visibility_indicator();
|
||||
return true;
|
||||
}
|
||||
|
||||
T* get_value_ptr()
|
||||
{
|
||||
return value;
|
||||
|
@ -66,8 +89,8 @@ class NumberMenuItem : public MenuItem<T> {
|
|||
|
||||
protected:
|
||||
NumberMenuItem() {};
|
||||
NumberMenuItem(const char* _label, T* _value, T _minimumValue, T _maximumValue, T _step)
|
||||
: MenuItem<T>(_label, _value)
|
||||
NumberMenuItem(const char* _label, T* _value, T _minimumValue, T _maximumValue, T _step, std::function<bool()> visibility_indicator = always_visible)
|
||||
: MenuItem<T>(_label, _value, visibility_indicator)
|
||||
, minimumValue(_minimumValue)
|
||||
, maximumValue(_maximumValue)
|
||||
, step(_step) {};
|
||||
|
@ -104,8 +127,8 @@ class UInt32MenuItem : public NumberMenuItem<uint32_t> {
|
|||
}
|
||||
|
||||
public:
|
||||
UInt32MenuItem(const char* _label, uint32_t* _value, uint32_t _minimumValue, uint32_t _maximumValue, uint32_t _step)
|
||||
: NumberMenuItem(_label, _value, _minimumValue, _maximumValue, _step) {};
|
||||
UInt32MenuItem(const char* _label, uint32_t* _value, uint32_t _minimumValue, uint32_t _maximumValue, uint32_t _step, std::function<bool()> visibility_indicator = always_visible)
|
||||
: NumberMenuItem(_label, _value, _minimumValue, _maximumValue, _step, visibility_indicator) {};
|
||||
UInt32MenuItem() {};
|
||||
};
|
||||
|
||||
|
@ -118,8 +141,8 @@ class UInt8MenuItem : public NumberMenuItem<uint8_t> {
|
|||
}
|
||||
|
||||
public:
|
||||
UInt8MenuItem(const char* _label, uint8_t* _value, uint8_t _minimumValue, uint8_t _maximumValue, uint8_t _step)
|
||||
: NumberMenuItem(_label, _value, _minimumValue, _maximumValue, _step) {};
|
||||
UInt8MenuItem(const char* _label, uint8_t* _value, uint8_t _minimumValue, uint8_t _maximumValue, uint8_t _step, std::function<bool()> visibility_indicator = always_visible)
|
||||
: NumberMenuItem(_label, _value, _minimumValue, _maximumValue, _step, visibility_indicator) {};
|
||||
UInt8MenuItem() {};
|
||||
};
|
||||
|
||||
|
@ -132,8 +155,8 @@ class Int32MenuItem : public NumberMenuItem<int32_t> {
|
|||
}
|
||||
|
||||
public:
|
||||
Int32MenuItem(const char* _label, int32_t* _value, int32_t _minimumValue, int32_t _maximumValue, int32_t _step)
|
||||
: NumberMenuItem(_label, _value, _minimumValue, _maximumValue, _step) {};
|
||||
Int32MenuItem(const char* _label, int32_t* _value, int32_t _minimumValue, int32_t _maximumValue, int32_t _step, std::function<bool()> visibility_indicator = always_visible)
|
||||
: NumberMenuItem(_label, _value, _minimumValue, _maximumValue, _step, visibility_indicator) {};
|
||||
Int32MenuItem();
|
||||
};
|
||||
|
||||
|
@ -146,8 +169,8 @@ class FloatMenuItem : public NumberMenuItem<float> {
|
|||
}
|
||||
|
||||
public:
|
||||
FloatMenuItem(const char* _label, float* _value, float _minimumValue, float _maximumValue, float _step)
|
||||
: NumberMenuItem(_label, _value, _minimumValue, _maximumValue, _step) {};
|
||||
FloatMenuItem(const char* _label, float* _value, float _minimumValue, float _maximumValue, float _step, std::function<bool()> visibility_indicator = always_visible)
|
||||
: NumberMenuItem(_label, _value, _minimumValue, _maximumValue, _step, visibility_indicator) {};
|
||||
FloatMenuItem() {};
|
||||
};
|
||||
|
||||
|
@ -170,8 +193,8 @@ class BoolMenuItem : public NumberMenuItem<bool> {
|
|||
}
|
||||
|
||||
public:
|
||||
BoolMenuItem(const char* _label, bool* _value, const char* _on_string, const char* _off_string)
|
||||
: NumberMenuItem(_label, _value, 0, 1, 1)
|
||||
BoolMenuItem(const char* _label, bool* _value, const char* _on_string, const char* _off_string, std::function<bool()> visibility_indicator = always_visible)
|
||||
: NumberMenuItem(_label, _value, 0, 1, 1, visibility_indicator)
|
||||
, on_string(_on_string)
|
||||
, off_string(_off_string) {};
|
||||
BoolMenuItem() {};
|
||||
|
@ -191,8 +214,8 @@ class StringListMenuItem : public NumberMenuItem<uint8_t> {
|
|||
}
|
||||
|
||||
public:
|
||||
StringListMenuItem(const char* _label, uint8_t* _value, const char** _stringLabels, size_t _itemCount)
|
||||
: NumberMenuItem(_label, _value, 0, _itemCount - 1, 1)
|
||||
StringListMenuItem(const char* _label, uint8_t* _value, const char** _stringLabels, size_t _itemCount, std::function<bool()> visibility_indicator = always_visible)
|
||||
: NumberMenuItem(_label, _value, 0, _itemCount - 1, 1, visibility_indicator)
|
||||
, string_labels(_stringLabels) {};
|
||||
StringListMenuItem() {};
|
||||
};
|
||||
|
@ -219,8 +242,8 @@ class MidiNoteMenuItem : public NumberMenuItem<uint8_t> {
|
|||
return this->string_buffer;
|
||||
}
|
||||
|
||||
MidiNoteMenuItem(const char* _label, uint8_t* _value)
|
||||
: NumberMenuItem(_label, _value, 0, 127, 1)
|
||||
MidiNoteMenuItem(const char* _label, uint8_t* _value, std::function<bool()> visibility_indicator = always_visible)
|
||||
: NumberMenuItem(_label, _value, 0, 127, 1, visibility_indicator)
|
||||
{
|
||||
note_strings[0] = "C";
|
||||
note_strings[1] = "C#";
|
||||
|
|
|
@ -11,6 +11,20 @@
|
|||
#include "stmlib/system/system_clock.h"
|
||||
#include "ui.h"
|
||||
|
||||
namespace std {
|
||||
void __throw_bad_function_call()
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" void __cxa_pure_virtual()
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
using namespace stmlib;
|
||||
|
||||
GPIO gpio;
|
||||
|
|
|
@ -15,7 +15,9 @@ PartMenu::PartMenu(Part* _part)
|
|||
, item_voice_count("voice count", (uint8_t*)&_part->data.part_voice_count, 1, 4, 1)
|
||||
, item_voice_detail("voice detail", (uint8_t*)&_part->data.part_voice_detail, kVoiceDetailStrings, 4)
|
||||
, item_midi_filter_enabled("MIDI filter", &_part->data.midi_filter_channel_enabled, "on", "off")
|
||||
, item_midi_channel("MIDI channel", (uint8_t*)&_part->data.midi_filter_channel, kMidiChannelStrings, 17)
|
||||
, item_midi_channel("MIDI channel", (uint8_t*)&_part->data.midi_filter_channel, kMidiChannelStrings, 17, [_part] {
|
||||
return _part->data.midi_filter_channel_enabled;
|
||||
})
|
||||
, item_midi_input("MIDI input", (uint8_t*)&_part->data.midi_filter_input, kMidiInputStrings, 3)
|
||||
, item_midi_lowest_note("MIDI lowest", (uint8_t*)&_part->data.midi_filter_lowest_note)
|
||||
, item_midi_highest_note("MIDI highest", (uint8_t*)&_part->data.midi_filter_highest_note)
|
||||
|
|
Loading…
Reference in a new issue