Files
ESP8266lib/ext/lcd/ui/UIList.h
kazu 5cb02880b3 many updates..
new sensors.. display.. led.. drawing.. stuff..
2019-01-17 23:12:01 +01:00

209 lines
4.5 KiB
C++

#ifndef UI_LIST_H
#define UI_LIST_H
#undef min
#undef max
#include <vector>
#include <string>
#include "UIElement.h"
#include "UIButton.h"
class UIListModel {
std::vector<std::string> entries;
public:
void add(const std::string& str) {
entries.push_back(str);
}
void remove(const size_t idx) {
entries.erase(entries.begin()+idx);
}
size_t size() const {
return entries.size();
}
const std::string& get(const size_t idx) const {
return entries[idx];
}
};
class UIList : public UIElement, public UIButton::Listener {
public:
class Listener {
public:
virtual void onSelected(UIList* lst, int idx) = 0;
};
private:
UIListModel model;
int offset = 0;
int selectedIndex = -1;
UIButton btnUp;
UIButton btnDown;
static constexpr const int btnW = 32;
Color cRect = Color::fromRGB(0,0,0);
Color cNormalBG = Color::fromRGB(230,230,230);
Color cSelectedBG = Color::fromRGB(190,190,255);
Color cText = Color::fromRGB(0,0,0);
Listener* listener = nullptr;
static constexpr const char* TAG = "UIList";
public:
/** ctor */
UIList() : btnUp("<"), btnDown(">") {
addChild(&btnUp);
addChild(&btnDown);
btnUp.setListener(this);
btnDown.setListener(this);
}
void setListener(Listener* l) {
this->listener = l;
}
// UIListModel& getModel() {
// setNeedsRedraw();
// return model;
// }
// const UIListModel& getModel() const {
// return model;
// }
void add(const std::string& str) {
model.add(str);
btnUp.setVisible(needsScroll());
btnDown.setVisible(needsScroll());
setNeedsRedraw();
}
void remove(const size_t idx) {
model.remove(idx);
if (idx == selectedIndex) {
selectedIndex = -1;
if (listener) {listener->onSelected(this, selectedIndex);}
} else if (idx < selectedIndex) {
--selectedIndex;
if (listener) {listener->onSelected(this, selectedIndex);}
}
if (offset > maxOffset()) {offset = maxOffset();}
btnUp.setVisible(needsScroll());
btnDown.setVisible(needsScroll());
setNeedsRedraw();
}
size_t size() const {
return model.size();
}
const std::string& get(const size_t idx) const {
return model.get(idx);
}
int getSelectedIndex() const {
return this->selectedIndex;
}
void reLayout() override {
int h = rect.h / 2 - 1;
btnUp.setRect(rect.x+rect.w-btnW-1, rect.y+1, btnW, h);
btnDown.setRect(rect.x+rect.w-btnW-1, rect.y+h+2, btnW, h);
}
virtual void draw(UIPainter& p) override {
debugMod(TAG, "draw()");
debugMod4(TAG, "rect: %d %d %d %d", rect.x, rect.y, rect.w, rect.h);
const uint8_t oy = (elementHeight() - fnt_f1.getHeight()) / 2;
const uint16_t entryW = rect.w - (needsScroll() ? btnW : 0);
// outline rectangle
p.setFG(cNormalBG);
p.fillRect(rect.x+1, rect.y+1, entryW, rect.h-2);
p.setFG(cRect);
p.drawRect(rect);
// display as many elements as fit within the list's height
for (unsigned int i = 0; i < elementsVisible(); ++i) {
// determine position (y-coordinate)
const uint16_t y = i * elementHeight();
// determine element from model
const int idx = i+offset;
const bool selected = idx == selectedIndex;
// draw background depending on selection
//p.setFG( selected ? cSelectedBG : cNormalBG );
//p.fillRect(UIRect(rect.x+1, rect.y+y+1, entryW-1, elementHeight()-1));
if (selected) {
p.setFG( cSelectedBG );
p.fillRect(UIRect(rect.x+1, rect.y+y+1, entryW-1, elementHeight()-1));
}
// draw text
p.setFG(cText);
p.drawText(rect.x+3, rect.y + y + oy, model.get(idx).c_str());
}
}
virtual void onTouchDown(uint16_t, uint16_t y) override {
unsigned int idx = y / elementHeight() + offset;
this->selectedIndex = (idx < numElements()) ? (idx) : (-1);
debugMod1(TAG, "selected: %d", selectedIndex);
setNeedsRedraw();
if (listener) {listener->onSelected(this, selectedIndex);}
}
virtual void onTouch(uint16_t, uint16_t) override {
}
virtual void onTouchUp() override {
}
virtual void onClick(UIButton* btn) override {
if (btn == &btnUp) {
if (offset > 0) {--offset; setNeedsRedraw();}
} else if (btn == &btnDown) {
if (offset < maxOffset()) {++offset; setNeedsRedraw();}
}
}
private:
unsigned int elementHeight() const {return 16;}
unsigned int maxElementsVisible() const {return rect.h / elementHeight();}
unsigned int elementsVisible() const {return std::min(maxElementsVisible(), numElements());}
unsigned int numElements() const {return model.size();}
unsigned int maxOffset() const {return numElements()-maxElementsVisible();}
bool needsScroll() const {return numElements() > maxElementsVisible();}
};
#endif // UI_LIST_H