Revert "added menu separators"

This reverts commit 35a4ebc7fe5b86eec23ddf8a9291d539f44e14b4.
This commit is contained in:
kkoenig1@optonline.com
2021-10-22 20:36:05 +11:00
committed by Peter Feerick
parent bd3781c95e
commit cda649db1f
2 changed files with 222 additions and 369 deletions
+25 -102
View File
@@ -21,59 +21,15 @@
#include "font.h"
#include "theme.h"
// 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(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);
selectedIndex = index;
if (innerHeight > height()) {
setScrollPositionY(MENUS_LINE_HEIGHT * index - 3 * MENUS_LINE_HEIGHT);
}
setIndex(index);
invalidate();
}
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)
{
@@ -81,13 +37,13 @@ void MenuBody::onEvent(event_t event)
if (event == EVT_ROTARY_RIGHT) {
if (!lines.empty()) {
selectNext(DIRECTION_UP);
select(int((selectedIndex + 1) % lines.size()));
onKeyPress();
}
}
else if (event == EVT_ROTARY_LEFT) {
if (!lines.empty()) {
selectNext(DIRECTION_DOWN);
select(int(selectedIndex <= 0 ? lines.size() - 1 : selectedIndex - 1));
onKeyPress();
}
}
@@ -127,39 +83,22 @@ void MenuBody::onEvent(event_t event)
bool MenuBody::onTouchEnd(coord_t /*x*/, coord_t y)
{
Menu * menu = getParentMenu();
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;
int index = y / MENUS_LINE_HEIGHT;
if (index < (int)lines.size()) {
onKeyPress();
if (menu->multiple) {
if (selectedIndex == index)
lines[index].onPress();
else
setIndex(index);
select(index);
menu->invalidate();
}
else {
setIndex(index);
select(index);
menu->deleteLater();
lines[index].onPress();
}
}
return true;
}
#endif
@@ -168,43 +107,37 @@ void MenuBody::paint(BitmapBuffer * dc)
{
dc->clear(COLOR_THEME_PRIMARY2);
int y = 0;
for (int i = 0; i < lines.size(); i++) {
for (unsigned i = 0; i < lines.size(); i++) {
auto& line = lines[i];
LcdFlags flags = COLOR_THEME_SECONDARY1 | MENU_FONT;
// draw selection if appropriate
if (selectedIndex == i && ! line.isSeparator) {
if (selectedIndex == (int)i) {
flags = COLOR_THEME_PRIMARY2 | MENU_FONT;
if (COLOR_THEME_FOCUS != COLOR_THEME_PRIMARY2) {
dc->drawSolidFilledRect(0, y, width(),
dc->drawSolidFilledRect(0, i * MENUS_LINE_HEIGHT, width(),
MENUS_LINE_HEIGHT, COLOR_THEME_FOCUS);
}
}
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);
if (line.drawLine) {
line.drawLine(dc, 0, i * MENUS_LINE_HEIGHT, flags);
} else {
const char* text = line.text.data();
dc->drawText(10,
y + (MENUS_LINE_HEIGHT - getFontHeight(MENU_FONT)) / 2,
i * MENUS_LINE_HEIGHT +
(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,
y + (MENUS_LINE_HEIGHT - 20) / 2,
i * MENUS_LINE_HEIGHT + (MENUS_LINE_HEIGHT - 20) / 2,
0);
}
// if (i > 0 && ! lines[i].isSeparator && ! lines[i-1].isSeparator) {
// dc->drawSolidHorizontalLine(0, y, MENUS_WIDTH, COLOR_THEME_SECONDARY2);
// }
y += line.lineHeight();
if (i > 0) {
dc->drawSolidHorizontalLine(0, i * MENUS_LINE_HEIGHT, MENUS_WIDTH,
COLOR_THEME_SECONDARY2);
}
}
}
@@ -240,22 +173,18 @@ 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, height, MENUS_MAX_HEIGHT);
auto bodyHeight = limit<coord_t>(
MENUS_MIN_HEIGHT, content->body.lines.size() * MENUS_LINE_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(height);
content->body.setInnerHeight(content->body.lines.size() * MENUS_LINE_HEIGHT);
}
void Menu::setTitle(std::string text)
@@ -270,12 +199,6 @@ 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));
+197 -267
View File
@@ -17,300 +17,230 @@
* Lesser General Public License for more details.
*/
#include "menu.h"
#include "font.h"
#include "theme.h"
#pragma once
#include <vector>
#include <functional>
#include <utility>
#include "modal_window.h"
// ensure index is in range and also handle wrapping index
int MenuBody::rangeCheck(int index)
class Menu;
class MenuWindowContent;
class MenuBody: public Window
{
if (index < 0)
index = lines.size() - 1;
else if (index > lines.size() - 1)
index = 0;
friend class MenuWindowContent;
friend class Menu;
return index;
}
class MenuLine {
friend class MenuBody;
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();
public:
MenuLine(std::string text, std::function<void()> onPress, std::function<bool()> isChecked):
text(std::move(text)),
onPress(std::move(onPress)),
isChecked(std::move(isChecked))
{
}
if (innerHeight > height()) {
setScrollPositionY(scrollY - 3 * MENUS_LINE_HEIGHT);
}
MenuLine(std::function<void(BitmapBuffer * /*dc*/, coord_t /*x*/, coord_t /*y*/, LcdFlags /*flags*/)> drawLine, std::function<void()> onPress, std::function<bool()> isChecked):
drawLine(std::move(drawLine)),
onPress(std::move(onPress)),
isChecked(std::move(isChecked))
{
}
invalidate();
}
MenuLine(MenuLine &) = delete;
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);
}
MenuLine(MenuLine &&) = default;
setIndex(index);
}
protected:
std::string text;
std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine;
std::function<void()> onPress;
std::function<bool()> isChecked;
};
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);
}
public:
MenuBody(Window * parent, const rect_t & rect):
Window(parent, rect, OPAQUE)
{
setPageHeight(MENUS_LINE_HEIGHT);
}
setIndex(index);
}
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "MenuBody";
}
#endif
void select(int index);
int selection() const
{
return selectedIndex;
}
int count() const
{
return lines.size();
}
#if defined(HARDWARE_KEYS)
void MenuBody::onEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_ROTARY_RIGHT) {
if (!lines.empty()) {
selectNext(DIRECTION_UP);
onKeyPress();
}
}
else if (event == EVT_ROTARY_LEFT) {
if (!lines.empty()) {
selectNext(DIRECTION_DOWN);
onKeyPress();
}
}
else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
if (!lines.empty()) {
onKeyPress();
if (selectedIndex < 0) {
select(0);
}
else {
Menu * menu = getParentMenu();
if (menu->multiple) {
lines[selectedIndex].onPress();
menu->invalidate();
}
else {
menu->deleteLater();
lines[selectedIndex].onPress();
}
}
}
}
else if (event == EVT_KEY_BREAK(KEY_EXIT)) {
onKeyPress();
if (onCancel) {
onCancel();
}
Window::onEvent(event);
}
else {
Window::onEvent(event);
}
}
void onEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool MenuBody::onTouchEnd(coord_t /*x*/, coord_t y)
{
Menu * menu = getParentMenu();
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
setIndex(index);
menu->invalidate();
}
else {
setIndex(index);
menu->deleteLater();
lines[index].onPress();
}
}
return true;
}
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
void MenuBody::paint(BitmapBuffer * dc)
void addLine(const std::string & text, std::function<void()> onPress, std::function<bool()> isChecked)
{
lines.emplace_back(text, std::move(onPress), std::move(isChecked));
invalidate();
}
void addCustomLine(std::function<void(BitmapBuffer * /*dc*/, coord_t /*x*/, coord_t /*y*/, LcdFlags /*flags*/)> drawLine, std::function<void()> onPress, std::function<bool()> isChecked)
{
lines.emplace_back(std::move(drawLine), std::move(onPress), std::move(isChecked));
invalidate();
}
void removeLines()
{
lines.clear();
invalidate();
}
void setCancelHandler(std::function<void()> handler)
{
onCancel = std::move(handler);
}
void paint(BitmapBuffer * dc) override;
protected:
std::vector<MenuLine> lines;
int selectedIndex = 0;
std::function<void()> onCancel;
inline Menu * getParentMenu();
};
class MenuWindowContent: public ModalWindowContent
{
dc->clear(COLOR_THEME_PRIMARY2);
friend class Menu;
int y = 0;
for (int i = 0; i < lines.size(); i++) {
auto& line = lines[i];
LcdFlags flags = COLOR_THEME_SECONDARY1 | MENU_FONT;
public:
explicit MenuWindowContent(Menu * parent);
// 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, y, width(),
MENUS_LINE_HEIGHT, COLOR_THEME_FOCUS);
void deleteLater(bool detach = true, bool trash = true) override
{
if (_deleted)
return;
body.deleteLater(true, false);
ModalWindowContent::deleteLater(detach, trash);
}
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "MenuWindowContent";
}
#endif
void paint(BitmapBuffer * dc) override;
protected:
MenuBody body;
};
class Menu: public ModalWindow
{
friend class MenuBody;
public:
explicit Menu(Window * parent, bool multiple = false);
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "Menu";
}
#endif
void setCancelHandler(std::function<void()> handler)
{
content->body.setCancelHandler(std::move(handler));
}
void setWaitHandler(std::function<void()> handler)
{
waitHandler = std::move(handler);
}
void setFocusBody(uint8_t flag = SET_FOCUS_DEFAULT)
{
content->body.setFocus(flag);
}
void setToolbar(Window * window)
{
toolbar = window;
content->setLeft(toolbar->right());
content->setTop(toolbar->top());
content->setHeight(toolbar->height());
}
void setTitle(std::string text);
void addLine(const std::string & text, std::function<void()> onPress, std::function<bool()> isChecked = nullptr);
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 removeLines();
unsigned count() const
{
return content->body.count();
}
int selection() const
{
return content->body.selection();
}
void select(int index)
{
content->body.select(index);
}
#if defined(HARDWARE_KEYS)
void onEvent(event_t event) override;
#endif
void checkEvents() override
{
ModalWindow::checkEvents();
if (waitHandler) {
waitHandler();
}
}
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,
y + (MENUS_LINE_HEIGHT - getFontHeight(MENU_FONT)) / 2,
text[0] == '\0' ? "---" : text, flags);
}
void paint(BitmapBuffer * dc) override;
Menu* menu = getParentMenu();
if (menu->multiple && line.isChecked) {
theme->drawCheckBox(dc, line.isChecked(), width() - 35,
y + (MENUS_LINE_HEIGHT - 20) / 2,
0);
}
protected:
MenuWindowContent * content;
bool multiple;
Window * toolbar = nullptr;
std::function<void()> waitHandler;
void updatePosition();
};
// if (i > 0 && ! lines[i].isSeparator && ! lines[i-1].isSeparator) {
// dc->drawSolidHorizontalLine(0, y, MENUS_WIDTH, COLOR_THEME_SECONDARY2);
// }
y += line.lineHeight();
}
}
MenuWindowContent::MenuWindowContent(Menu* parent) :
ModalWindowContent(parent, {(LCD_W - MENUS_WIDTH) / 2,
(LCD_H - MENUS_WIDTH) / 2, MENUS_WIDTH, 0}),
body(this, {0, 0, width(), height()})
Menu * MenuBody::getParentMenu()
{
body.setFocus(SET_FOCUS_DEFAULT);
return static_cast<Menu *>(getParent()->getParent());
}
void MenuWindowContent::paint(BitmapBuffer * dc)
{
// the background
dc->clear(COLOR_THEME_PRIMARY2);
// the title
if (!title.empty()) {
dc->drawText(MENUS_WIDTH / 2,
(POPUP_HEADER_HEIGHT - getFontHeight(MENU_HEADER_FONT)) / 2,
title.c_str(), CENTERED | MENU_HEADER_FONT);
dc->drawSolidHorizontalLine(0, POPUP_HEADER_HEIGHT - 1, MENUS_WIDTH,
COLOR_THEME_SECONDARY2);
}
}
Menu::Menu(Window * parent, bool multiple):
ModalWindow(parent, true),
content(createMenuWindow(this)),
multiple(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, 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(height);
}
void Menu::setTitle(std::string text)
{
content->setTitle(std::move(text));
updatePosition();
}
void Menu::addLine(const std::string & text, std::function<void()> onPress, std::function<bool()> isChecked)
{
content->body.addLine(text, std::move(onPress), std::move(isChecked));
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));
updatePosition();
}
void Menu::removeLines()
{
content->body.removeLines();
updatePosition();
}
#if defined(HARDWARE_KEYS)
void Menu::onEvent(event_t event)
{
if (toolbar && (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN))) {
toolbar->onEvent(event);
}
else if (event == EVT_KEY_BREAK(KEY_EXIT)) {
deleteLater();
}
else if (event == EVT_KEY_BREAK(KEY_ENTER) && !multiple) {
deleteLater();
}
}
#endif
void Menu::paint(BitmapBuffer * dc)
{
ModalWindow::paint(dc);
rect_t r(content->getRect());
if (toolbar) {
r.x = toolbar->left();
r.w += toolbar->width();
}
dc->drawSolidRect(r.x - 1, r.y - 1, r.w + 2, r.h + 2, 1, COLOR_THEME_SECONDARY2);
}