readded separators correctly this time

This commit is contained in:
kkoenig1@optonline.com
2021-10-22 20:36:05 +11:00
committed by Peter Feerick
parent cda649db1f
commit 45e4f05b16
2 changed files with 133 additions and 24 deletions
+100 -23
View File
@@ -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
View File
@@ -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