readded separators correctly this time
This commit is contained in:
committed by
Peter Feerick
parent
cda649db1f
commit
45e4f05b16
+100
-23
@@ -21,15 +21,59 @@
|
||||
#include "font.h"
|
||||
#include "theme.h"
|
||||
|
||||
void MenuBody::select(int index)
|
||||
|
||||
// ensure index is in range and also handle wrapping index
|
||||
int MenuBody::rangeCheck(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = lines.size() - 1;
|
||||
else if (index > lines.size() - 1)
|
||||
index = 0;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void MenuBody::setIndex(int index)
|
||||
{
|
||||
selectedIndex = index;
|
||||
// calculate the correct scroll postion based on there being separators
|
||||
int scrollY = 0;
|
||||
for (int i = 0; i < selectedIndex; i++)
|
||||
scrollY += lines[i].lineHeight();
|
||||
|
||||
if (innerHeight > height()) {
|
||||
setScrollPositionY(MENUS_LINE_HEIGHT * index - 3 * MENUS_LINE_HEIGHT);
|
||||
setScrollPositionY(scrollY - 3 * MENUS_LINE_HEIGHT);
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void MenuBody::select(int index)
|
||||
{
|
||||
// adjust the selection based on separators
|
||||
for (int i = 0; i <= index; i++) {
|
||||
if (lines[i].isSeparator)
|
||||
index++;
|
||||
index = rangeCheck(index);
|
||||
}
|
||||
|
||||
setIndex(index);
|
||||
}
|
||||
|
||||
void MenuBody::selectNext(MENU_DIRECTION direction)
|
||||
{
|
||||
// look for the next non separator line
|
||||
int index = selectedIndex + direction;
|
||||
index = rangeCheck(index);
|
||||
while (lines[index].isSeparator) {
|
||||
index += direction;
|
||||
index = rangeCheck(index);
|
||||
}
|
||||
|
||||
setIndex(index);
|
||||
}
|
||||
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void MenuBody::onEvent(event_t event)
|
||||
{
|
||||
@@ -37,13 +81,13 @@ void MenuBody::onEvent(event_t event)
|
||||
|
||||
if (event == EVT_ROTARY_RIGHT) {
|
||||
if (!lines.empty()) {
|
||||
select(int((selectedIndex + 1) % lines.size()));
|
||||
selectNext(DIRECTION_UP);
|
||||
onKeyPress();
|
||||
}
|
||||
}
|
||||
else if (event == EVT_ROTARY_LEFT) {
|
||||
if (!lines.empty()) {
|
||||
select(int(selectedIndex <= 0 ? lines.size() - 1 : selectedIndex - 1));
|
||||
selectNext(DIRECTION_DOWN);
|
||||
onKeyPress();
|
||||
}
|
||||
}
|
||||
@@ -83,22 +127,39 @@ void MenuBody::onEvent(event_t event)
|
||||
bool MenuBody::onTouchEnd(coord_t /*x*/, coord_t y)
|
||||
{
|
||||
Menu * menu = getParentMenu();
|
||||
int index = y / MENUS_LINE_HEIGHT;
|
||||
|
||||
int index = 0;
|
||||
|
||||
// dynamically find the selected element based on variable line heights
|
||||
coord_t yAccumulator = 0;
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
if (y >= yAccumulator && y <= yAccumulator + lines[i].lineHeight()) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
yAccumulator += lines[i].lineHeight();
|
||||
}
|
||||
|
||||
// dont allow selecting separators
|
||||
if (lines[index].isSeparator)
|
||||
return false;
|
||||
|
||||
if (index < (int)lines.size()) {
|
||||
onKeyPress();
|
||||
if (menu->multiple) {
|
||||
if (selectedIndex == index)
|
||||
lines[index].onPress();
|
||||
else
|
||||
select(index);
|
||||
setIndex(index);
|
||||
menu->invalidate();
|
||||
}
|
||||
else {
|
||||
select(index);
|
||||
setIndex(index);
|
||||
menu->deleteLater();
|
||||
lines[index].onPress();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -107,37 +168,43 @@ void MenuBody::paint(BitmapBuffer * dc)
|
||||
{
|
||||
dc->clear(COLOR_THEME_PRIMARY2);
|
||||
|
||||
for (unsigned i = 0; i < lines.size(); i++) {
|
||||
int y = 0;
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
auto& line = lines[i];
|
||||
LcdFlags flags = COLOR_THEME_SECONDARY1 | MENU_FONT;
|
||||
if (selectedIndex == (int)i) {
|
||||
|
||||
// draw selection if appropriate
|
||||
if (selectedIndex == i && ! line.isSeparator) {
|
||||
flags = COLOR_THEME_PRIMARY2 | MENU_FONT;
|
||||
if (COLOR_THEME_FOCUS != COLOR_THEME_PRIMARY2) {
|
||||
dc->drawSolidFilledRect(0, i * MENUS_LINE_HEIGHT, width(),
|
||||
dc->drawSolidFilledRect(0, y, width(),
|
||||
MENUS_LINE_HEIGHT, COLOR_THEME_FOCUS);
|
||||
}
|
||||
}
|
||||
if (line.drawLine) {
|
||||
line.drawLine(dc, 0, i * MENUS_LINE_HEIGHT, flags);
|
||||
|
||||
if (line.isSeparator) {
|
||||
dc->drawHorizontalLine(5, y + MENUS_SEPARATOR_HEIGHT / 2, width() - 10, 255, COLOR_THEME_SECONDARY2);
|
||||
} else if (line.drawLine) {
|
||||
line.drawLine(dc, 0, y, flags);
|
||||
} else {
|
||||
const char* text = line.text.data();
|
||||
dc->drawText(10,
|
||||
i * MENUS_LINE_HEIGHT +
|
||||
(MENUS_LINE_HEIGHT - getFontHeight(MENU_FONT)) / 2,
|
||||
y + (MENUS_LINE_HEIGHT - getFontHeight(MENU_FONT)) / 2,
|
||||
text[0] == '\0' ? "---" : text, flags);
|
||||
}
|
||||
|
||||
Menu* menu = getParentMenu();
|
||||
if (menu->multiple && line.isChecked) {
|
||||
theme->drawCheckBox(dc, line.isChecked(), width() - 35,
|
||||
i * MENUS_LINE_HEIGHT + (MENUS_LINE_HEIGHT - 20) / 2,
|
||||
y + (MENUS_LINE_HEIGHT - 20) / 2,
|
||||
0);
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
dc->drawSolidHorizontalLine(0, i * MENUS_LINE_HEIGHT, MENUS_WIDTH,
|
||||
COLOR_THEME_SECONDARY2);
|
||||
}
|
||||
// if (i > 0 && ! lines[i].isSeparator && ! lines[i-1].isSeparator) {
|
||||
// dc->drawSolidHorizontalLine(0, y, MENUS_WIDTH, COLOR_THEME_SECONDARY2);
|
||||
// }
|
||||
|
||||
y += line.lineHeight();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,18 +240,22 @@ Menu::Menu(Window * parent, bool multiple):
|
||||
|
||||
void Menu::updatePosition()
|
||||
{
|
||||
// calcualte the correct menu height given that the line heights are variable
|
||||
coord_t height = 0;
|
||||
for (int i = 0; i < content->body.lines.size(); i++)
|
||||
height += content->body.lines[i].lineHeight();
|
||||
|
||||
if (!toolbar) {
|
||||
// there is no navigation bar at the left, we may center the window on screen
|
||||
auto headerHeight = content->title.empty() ? 0 : POPUP_HEADER_HEIGHT;
|
||||
auto bodyHeight = limit<coord_t>(
|
||||
MENUS_MIN_HEIGHT, content->body.lines.size() * MENUS_LINE_HEIGHT,
|
||||
MENUS_MAX_HEIGHT);
|
||||
auto bodyHeight = limit<coord_t>(MENUS_MIN_HEIGHT, height, MENUS_MAX_HEIGHT);
|
||||
content->setTop((LCD_H - headerHeight - bodyHeight) / 2 + MENUS_OFFSET_TOP);
|
||||
content->setHeight(headerHeight + bodyHeight);
|
||||
content->body.setTop(headerHeight);
|
||||
content->body.setHeight(bodyHeight);
|
||||
}
|
||||
content->body.setInnerHeight(content->body.lines.size() * MENUS_LINE_HEIGHT);
|
||||
|
||||
content->body.setInnerHeight(height);
|
||||
}
|
||||
|
||||
void Menu::setTitle(std::string text)
|
||||
@@ -199,6 +270,12 @@ void Menu::addLine(const std::string & text, std::function<void()> onPress, std:
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::addSeparator()
|
||||
{
|
||||
content->body.addSeparator();
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::addCustomLine(std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine, std::function<void()> onPress, std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addCustomLine(std::move(drawLine), std::move(onPress), std::move(isChecked));
|
||||
|
||||
+33
-1
@@ -32,6 +32,12 @@ class MenuBody: public Window
|
||||
friend class MenuWindowContent;
|
||||
friend class Menu;
|
||||
|
||||
enum MENU_DIRECTION
|
||||
{
|
||||
DIRECTION_UP = 1,
|
||||
DIRECTION_DOWN = -1
|
||||
};
|
||||
|
||||
class MenuLine {
|
||||
friend class MenuBody;
|
||||
|
||||
@@ -50,11 +56,21 @@ class MenuBody: public Window
|
||||
{
|
||||
}
|
||||
|
||||
MenuLine(bool isSeparator) :
|
||||
isSeparator(true),
|
||||
height(MENUS_SEPARATOR_HEIGHT)
|
||||
{
|
||||
}
|
||||
|
||||
inline coord_t lineHeight() { return height; }
|
||||
|
||||
MenuLine(MenuLine &) = delete;
|
||||
|
||||
MenuLine(MenuLine &&) = default;
|
||||
|
||||
protected:
|
||||
bool isSeparator = false;
|
||||
coord_t height = MENUS_LINE_HEIGHT;
|
||||
std::string text;
|
||||
std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine;
|
||||
std::function<void()> onPress;
|
||||
@@ -79,7 +95,12 @@ class MenuBody: public Window
|
||||
|
||||
int selection() const
|
||||
{
|
||||
return selectedIndex;
|
||||
int index = selectedIndex;
|
||||
for (int i = 0; i < selectedIndex; i++)
|
||||
if (lines[i].isSeparator)
|
||||
index--;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int count() const
|
||||
@@ -107,6 +128,11 @@ class MenuBody: public Window
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void addSeparator()
|
||||
{
|
||||
lines.emplace_back(true);
|
||||
}
|
||||
|
||||
void removeLines()
|
||||
{
|
||||
lines.clear();
|
||||
@@ -121,6 +147,10 @@ class MenuBody: public Window
|
||||
void paint(BitmapBuffer * dc) override;
|
||||
|
||||
protected:
|
||||
void selectNext(MENU_DIRECTION direction);
|
||||
int rangeCheck(int);
|
||||
void setIndex(int index);
|
||||
|
||||
std::vector<MenuLine> lines;
|
||||
int selectedIndex = 0;
|
||||
std::function<void()> onCancel;
|
||||
@@ -200,6 +230,8 @@ class Menu: public ModalWindow
|
||||
|
||||
void addCustomLine(std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine, std::function<void()> onPress, std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addSeparator();
|
||||
|
||||
void removeLines();
|
||||
|
||||
unsigned count() const
|
||||
|
||||
Reference in New Issue
Block a user