many updates..
new sensors.. display.. led.. drawing.. stuff..
This commit is contained in:
208
ext/lcd/ui/UIList.h
Normal file
208
ext/lcd/ui/UIList.h
Normal file
@@ -0,0 +1,208 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user