v0.8.00b
This commit is contained in:
78
yoRadio/src/displays/widgets/pages.cpp
Normal file
78
yoRadio/src/displays/widgets/pages.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "../dspcore.h"
|
||||
#if DSP_MODEL!=DSP_DUMMY
|
||||
|
||||
#include "pages.h"
|
||||
|
||||
void Pager::begin(){
|
||||
|
||||
}
|
||||
|
||||
void Pager::loop(){
|
||||
for(const auto& p: _pages)
|
||||
if(p->isActive()) p->loop();
|
||||
}
|
||||
|
||||
Page& Pager::addPage(Page* page, bool setNow){
|
||||
_pages.add(page);
|
||||
if(setNow) setPage(page);
|
||||
return *page;
|
||||
}
|
||||
|
||||
bool Pager::removePage(Page* page){
|
||||
page->setActive(false);
|
||||
dsp.clearDsp();
|
||||
return _pages.remove(page);
|
||||
}
|
||||
|
||||
void Pager::setPage(Page* page, bool black){
|
||||
for(const auto& p: _pages) p->setActive(false);
|
||||
dsp.clearDsp(black);
|
||||
page->setActive(true);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
Page::Page() : _widgets(LinkedList<Widget * >([](Widget * wd) { delete wd;})), _pages(LinkedList<Page*>([](Page* pg){ delete pg; })) {
|
||||
_active = false;
|
||||
}
|
||||
|
||||
Page::~Page() {
|
||||
for (const auto& w : _widgets) removeWidget(w);
|
||||
}
|
||||
|
||||
void Page::loop() {
|
||||
if(_active) for (const auto& w : _widgets) w->loop();
|
||||
}
|
||||
|
||||
Widget& Page::addWidget(Widget* widget) {
|
||||
_widgets.add(widget);
|
||||
widget->setActive(_active, _active);
|
||||
return *widget;
|
||||
}
|
||||
|
||||
bool Page::removeWidget(Widget* widget){
|
||||
widget->setActive(false, _active);
|
||||
return _widgets.remove(widget);
|
||||
}
|
||||
|
||||
Page& Page::addPage(Page* page){
|
||||
_pages.add(page);
|
||||
return *page;
|
||||
}
|
||||
|
||||
bool Page::removePage(Page* page){
|
||||
return _pages.remove(page);
|
||||
}
|
||||
|
||||
void Page::setActive(bool act) {
|
||||
for(const auto& w: _widgets) w->setActive(act);
|
||||
for(const auto& p: _pages) p->setActive(act);
|
||||
_active = act;
|
||||
}
|
||||
|
||||
bool Page::isActive() {
|
||||
return _active;
|
||||
}
|
||||
|
||||
#endif // #if DSP_MODEL!=DSP_DUMMY
|
||||
38
yoRadio/src/displays/widgets/pages.h
Normal file
38
yoRadio/src/displays/widgets/pages.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef pages_h
|
||||
#define pages_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "StringArray.h"
|
||||
|
||||
class Page {
|
||||
protected:
|
||||
LinkedList<Widget*> _widgets;
|
||||
LinkedList<Page*> _pages;
|
||||
bool _active;
|
||||
public:
|
||||
Page();
|
||||
~Page();
|
||||
void loop();
|
||||
Widget& addWidget(Widget* widget);
|
||||
bool removeWidget(Widget* widget);
|
||||
Page& addPage(Page* page);
|
||||
bool removePage(Page* page);
|
||||
void setActive(bool act);
|
||||
bool isActive();
|
||||
};
|
||||
|
||||
class Pager{
|
||||
public:
|
||||
Pager() : _pages(LinkedList<Page*>([](Page* pg){ delete pg; })) {}
|
||||
void begin();
|
||||
void loop();
|
||||
Page& addPage(Page* page, bool setNow = false);
|
||||
bool removePage(Page* page);
|
||||
void setPage(Page* page, bool black=false);
|
||||
private:
|
||||
LinkedList<Page*> _pages;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
494
yoRadio/src/displays/widgets/widgets.cpp
Normal file
494
yoRadio/src/displays/widgets/widgets.cpp
Normal file
@@ -0,0 +1,494 @@
|
||||
#include "../dspcore.h"
|
||||
#if DSP_MODEL!=DSP_DUMMY
|
||||
|
||||
#include "widgets.h"
|
||||
#include "../../core/player.h" // for VU widget
|
||||
|
||||
/************************
|
||||
FILL WIDGET
|
||||
************************/
|
||||
void FillWidget::init(FillConfig conf, uint16_t bgcolor){
|
||||
Widget::init(conf.widget, bgcolor, bgcolor);
|
||||
_width = conf.width;
|
||||
_height = conf.height;
|
||||
|
||||
}
|
||||
|
||||
void FillWidget::_draw(){
|
||||
if(!_active) return;
|
||||
dsp.fillRect(_config.left, _config.top, _width, _height, _bgcolor);
|
||||
}
|
||||
|
||||
/************************
|
||||
TEXT WIDGET
|
||||
************************/
|
||||
TextWidget::~TextWidget() {
|
||||
free(_text);
|
||||
free(_oldtext);
|
||||
}
|
||||
|
||||
void TextWidget::init(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
Widget::init(wconf, fgcolor, bgcolor);
|
||||
_buffsize = buffsize;
|
||||
_text = (char *) malloc(sizeof(char) * _buffsize);
|
||||
memset(_text, 0, _buffsize);
|
||||
_oldtext = (char *) malloc(sizeof(char) * _buffsize);
|
||||
memset(_oldtext, 0, _buffsize);
|
||||
//_charWidth = wconf.textsize * CHARWIDTH; // default GFX font
|
||||
//_textheight = wconf.textsize * CHARHEIGHT; // default GFX font
|
||||
dsp.charSize(_config.textsize, _charWidth, _textheight);
|
||||
_textwidth = _oldtextwidth = _oldleft = 0;
|
||||
_uppercase = uppercase;
|
||||
}
|
||||
|
||||
void TextWidget::setText(const char* txt) {
|
||||
strlcpy(_text, dsp.utf8Rus(txt, _uppercase), _buffsize);
|
||||
_textwidth = strlen(_text) * _charWidth;
|
||||
if (strcmp(_oldtext, _text) == 0) return;
|
||||
if (_active) dsp.fillRect(_oldleft == 0 ? _realLeft() : min(_oldleft, _realLeft()), _config.top, max(_oldtextwidth, _textwidth), _textheight, _bgcolor);
|
||||
_oldtextwidth = _textwidth;
|
||||
_oldleft = _realLeft();
|
||||
if (_active) _draw();
|
||||
}
|
||||
|
||||
void TextWidget::setText(int val, const char *format){
|
||||
char buf[_buffsize];
|
||||
snprintf(buf, _buffsize, format, val);
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
void TextWidget::setText(const char* txt, const char *format){
|
||||
char buf[_buffsize];
|
||||
snprintf(buf, _buffsize, format, txt);
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
uint16_t TextWidget::_realLeft() {
|
||||
switch (_config.align) {
|
||||
case WA_CENTER: return (dsp.width() - _textwidth) / 2; break;
|
||||
case WA_RIGHT: return (dsp.width() - _textwidth - _config.left); break;
|
||||
default: return _config.left; break;
|
||||
}
|
||||
}
|
||||
|
||||
void TextWidget::_draw() {
|
||||
if(!_active) return;
|
||||
dsp.setTextColor(_fgcolor, _bgcolor);
|
||||
dsp.setCursor(_realLeft(), _config.top);
|
||||
dsp.setFont();
|
||||
dsp.setTextSize(_config.textsize);
|
||||
dsp.print(_text);
|
||||
strlcpy(_oldtext, _text, _buffsize);
|
||||
}
|
||||
|
||||
/************************
|
||||
SCROLL WIDGET
|
||||
************************/
|
||||
ScrollWidget::ScrollWidget(const char* separator, ScrollConfig conf, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
init(separator, conf, fgcolor, bgcolor);
|
||||
}
|
||||
|
||||
ScrollWidget::~ScrollWidget() {
|
||||
free(_sep);
|
||||
free(_window);
|
||||
}
|
||||
|
||||
void ScrollWidget::init(const char* separator, ScrollConfig conf, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
TextWidget::init(conf.widget, conf.buffsize, conf.uppercase, fgcolor, bgcolor);
|
||||
_sep = (char *) malloc(sizeof(char) * 4);
|
||||
memset(_sep, 0, 4);
|
||||
snprintf(_sep, 4, " %.*s ", 1, separator);
|
||||
_x = conf.widget.left;
|
||||
_startscrolldelay = conf.startscrolldelay;
|
||||
_scrolldelta = conf.scrolldelta;
|
||||
_scrolltime = conf.scrolltime;
|
||||
//_charWidth = CHARWIDTH * _config.textsize; // default GFX font
|
||||
//_textheight = CHARHEIGHT * _config.textsize; // default GFX font
|
||||
dsp.charSize(_config.textsize, _charWidth, _textheight);
|
||||
_sepwidth = strlen(_sep) * _charWidth;
|
||||
_width = conf.width;
|
||||
_backMove.width = _width;
|
||||
_window = (char *) malloc(sizeof(char) * (MAX_WIDTH / _charWidth + 1));
|
||||
memset(_window, 0, (MAX_WIDTH / _charWidth + 1)); // +1?
|
||||
_doscroll = false;
|
||||
}
|
||||
|
||||
void ScrollWidget::_setTextParams() {
|
||||
if (_config.textsize == 0) return;
|
||||
dsp.setTextSize(_config.textsize);
|
||||
dsp.setTextColor(_fgcolor, _bgcolor);
|
||||
}
|
||||
|
||||
bool ScrollWidget::_checkIsScrollNeeded() {
|
||||
return _textwidth > _width;
|
||||
}
|
||||
|
||||
void ScrollWidget::setText(const char* txt) {
|
||||
strlcpy(_text, dsp.utf8Rus(txt, _uppercase), _buffsize - 1);
|
||||
if (strcmp(_oldtext, _text) == 0) return;
|
||||
_textwidth = strlen(_text) * _charWidth;
|
||||
_x = _config.left;
|
||||
_doscroll = _checkIsScrollNeeded();
|
||||
if (dsp.getScrollId() == this) dsp.setScrollId(NULL);
|
||||
_scrolldelay = millis();
|
||||
if (_active) {
|
||||
_setTextParams();
|
||||
if (_doscroll) {
|
||||
dsp.fillRect(_config.left, _config.top, _width, _textheight, _bgcolor);
|
||||
dsp.setCursor(_config.left, _config.top);
|
||||
snprintf(_window, _width / _charWidth + 1, "%s", _text); //TODO
|
||||
dsp.setClipping({_config.left, _config.top, _width, _textheight});
|
||||
dsp.print(_window);
|
||||
dsp.clearClipping();
|
||||
} else {
|
||||
dsp.fillRect(_config.left, _config.top, _width, _textheight, _bgcolor);
|
||||
dsp.setCursor(_realLeft(), _config.top);
|
||||
//dsp.setClipping({_config.left, _config.top, _width, _textheight});
|
||||
dsp.print(_text);
|
||||
//dsp.clearClipping();
|
||||
}
|
||||
strlcpy(_oldtext, _text, _buffsize);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWidget::setText(const char* txt, const char *format){
|
||||
char buf[_buffsize];
|
||||
snprintf(buf, _buffsize, format, txt);
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
void ScrollWidget::loop() {
|
||||
if(_locked) return;
|
||||
if (!_doscroll || _config.textsize == 0 || (dsp.getScrollId() != NULL && dsp.getScrollId() != this)) return;
|
||||
if (_checkDelay(_x == _config.left ? _startscrolldelay : _scrolltime, _scrolldelay)) {
|
||||
_calcX();
|
||||
if (_active) _draw();
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWidget::_clear(){
|
||||
dsp.fillRect(_config.left, _config.top, _width, _textheight, _bgcolor);
|
||||
}
|
||||
|
||||
void ScrollWidget::_draw() {
|
||||
if(!_active || _locked) return;
|
||||
_setTextParams();
|
||||
if (_doscroll) {
|
||||
uint16_t _newx = _config.left - _x;
|
||||
const char* _cursor = _text + _newx / _charWidth;
|
||||
uint16_t hiddenChars = _cursor - _text;
|
||||
if (hiddenChars < strlen(_text)) {
|
||||
snprintf(_window, _width / _charWidth + 1, "%s%s%s", _cursor, _sep, _text);
|
||||
} else {
|
||||
const char* _scursor = _sep + (_cursor - (_text + strlen(_text)));
|
||||
snprintf(_window, _width / _charWidth + 1, "%s%s", _scursor, _text);
|
||||
}
|
||||
dsp.setCursor(_x + hiddenChars * _charWidth, _config.top);
|
||||
dsp.setClipping({_config.left, _config.top, _width, _textheight});
|
||||
dsp.print(_window);
|
||||
#ifndef DSP_LCD
|
||||
dsp.print(" ");
|
||||
#endif
|
||||
dsp.clearClipping();
|
||||
} else {
|
||||
dsp.fillRect(_config.left, _config.top, _width, _textheight, _bgcolor);
|
||||
dsp.setCursor(_realLeft(), _config.top);
|
||||
dsp.setClipping({_realLeft(), _config.top, _width, _textheight});
|
||||
dsp.print(_text);
|
||||
dsp.clearClipping();
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWidget::_calcX() {
|
||||
if (!_doscroll || _config.textsize == 0) return;
|
||||
_x -= _scrolldelta;
|
||||
if (-_x > _textwidth + _sepwidth - _config.left) {
|
||||
_x = _config.left;
|
||||
dsp.setScrollId(NULL);
|
||||
} else {
|
||||
dsp.setScrollId(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool ScrollWidget::_checkDelay(int m, uint32_t &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWidget::_reset(){
|
||||
dsp.setScrollId(NULL);
|
||||
_x = _config.left;
|
||||
_scrolldelay = millis();
|
||||
_doscroll = _checkIsScrollNeeded();
|
||||
}
|
||||
|
||||
/************************
|
||||
SLIDER WIDGET
|
||||
************************/
|
||||
void SliderWidget::init(FillConfig conf, uint16_t fgcolor, uint16_t bgcolor, uint32_t maxval, uint16_t oucolor) {
|
||||
Widget::init(conf.widget, fgcolor, bgcolor);
|
||||
_width = conf.width; _height = conf.height; _outlined = conf.outlined; _oucolor = oucolor, _max = maxval;
|
||||
_oldvalwidth = _value = 0;
|
||||
}
|
||||
|
||||
void SliderWidget::setValue(uint32_t val) {
|
||||
_value = val;
|
||||
if (_active && !_locked) _drawslider();
|
||||
|
||||
}
|
||||
|
||||
void SliderWidget::_drawslider() {
|
||||
uint16_t valwidth = map(_value, 0, _max, 0, _width - _outlined * 2);
|
||||
if (_oldvalwidth == valwidth) return;
|
||||
dsp.fillRect(_config.left + _outlined + min(valwidth, _oldvalwidth), _config.top + _outlined, abs(_oldvalwidth - valwidth), _height - _outlined * 2, _oldvalwidth > valwidth ? _bgcolor : _fgcolor);
|
||||
_oldvalwidth = valwidth;
|
||||
}
|
||||
|
||||
void SliderWidget::_draw() {
|
||||
if(_locked) return;
|
||||
_clear();
|
||||
if(!_active) return;
|
||||
if (_outlined) dsp.drawRect(_config.left, _config.top, _width, _height, _oucolor);
|
||||
uint16_t valwidth = map(_value, 0, _max, 0, _width - _outlined * 2);
|
||||
dsp.fillRect(_config.left + _outlined, _config.top + _outlined, valwidth, _height - _outlined * 2, _fgcolor);
|
||||
}
|
||||
|
||||
void SliderWidget::_clear() {
|
||||
_oldvalwidth = 0;
|
||||
dsp.fillRect(_config.left, _config.top, _width, _height, _bgcolor);
|
||||
}
|
||||
/************************
|
||||
VU WIDGET
|
||||
************************/
|
||||
#if !defined(DSP_LCD) && !defined(DSP_OLED)
|
||||
VuWidget::~VuWidget() {
|
||||
if(_canvas) free(_canvas);
|
||||
}
|
||||
|
||||
void VuWidget::init(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor, uint16_t vumincolor, uint16_t bgcolor) {
|
||||
Widget::init(wconf, bgcolor, bgcolor);
|
||||
_vumaxcolor = vumaxcolor;
|
||||
_vumincolor = vumincolor;
|
||||
_bands = bands;
|
||||
_canvas = new Canvas(_bands.width * 2 + _bands.space, _bands.height);
|
||||
}
|
||||
|
||||
void VuWidget::_draw(){
|
||||
if(!_active || _locked) return;
|
||||
#if !defined(USE_NEXTION) && I2S_DOUT==255
|
||||
static uint8_t cc = 0;
|
||||
cc++;
|
||||
if(cc>1){
|
||||
player.getVUlevel();
|
||||
cc=0;
|
||||
}
|
||||
#endif
|
||||
static uint16_t measL, measR;
|
||||
uint16_t bandColor;
|
||||
uint16_t dimension = _config.align?_bands.width:_bands.height;
|
||||
uint8_t L = map(player.vuLeft, 255, 0, 0, dimension);
|
||||
uint8_t R = map(player.vuRight, 255, 0, 0, dimension);
|
||||
bool played = player.isRunning();
|
||||
if(played){
|
||||
measL=(L>=measL)?measL + _bands.fadespeed:L;
|
||||
measR=(R>=measR)?measR + _bands.fadespeed:R;
|
||||
}else{
|
||||
if(measL<dimension) measL += _bands.fadespeed;
|
||||
if(measR<dimension) measR += _bands.fadespeed;
|
||||
}
|
||||
if(measL>dimension) measL=dimension;
|
||||
if(measR>dimension) measR=dimension;
|
||||
uint8_t h=(dimension/_bands.perheight)-_bands.vspace;
|
||||
_canvas->fillRect(0,0,_bands.width * 2 + _bands.space,_bands.height, _bgcolor);
|
||||
for(int i=0; i<dimension; i++){
|
||||
if(i%(dimension/_bands.perheight)==0){
|
||||
if(_config.align){
|
||||
#ifndef BOOMBOX_STYLE
|
||||
bandColor = (i>_bands.width-(_bands.width/_bands.perheight)*4)?_vumaxcolor:_vumincolor;
|
||||
_canvas->fillRect(i, 0, h, _bands.height, bandColor);
|
||||
_canvas->fillRect(i + _bands.width + _bands.space, 0, h, _bands.height, bandColor);
|
||||
#else
|
||||
bandColor = (i>(_bands.width/_bands.perheight))?_vumincolor:_vumaxcolor;
|
||||
_canvas->fillRect(i, 0, h, _bands.height, bandColor);
|
||||
bandColor = (i>_bands.width-(_bands.width/_bands.perheight)*3)?_vumaxcolor:_vumincolor;
|
||||
_canvas->fillRect(i + _bands.width + _bands.space, 0, h, _bands.height, bandColor);
|
||||
#endif
|
||||
}else{
|
||||
bandColor = (i<(_bands.height/_bands.perheight)*3)?_vumaxcolor:_vumincolor;
|
||||
_canvas->fillRect(0, i, _bands.width, h, bandColor);
|
||||
_canvas->fillRect(_bands.width + _bands.space, i, _bands.width, h, bandColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(_config.align){
|
||||
#ifndef BOOMBOX_STYLE
|
||||
_canvas->fillRect(_bands.width-measL, 0, measL, _bands.width, _bgcolor);
|
||||
_canvas->fillRect(_bands.width * 2 + _bands.space - measR, 0, measR, _bands.width, _bgcolor);
|
||||
dsp.drawRGBBitmap(_config.left, _config.top, _canvas->getBuffer(), _bands.width * 2 + _bands.space, _bands.height);
|
||||
#else
|
||||
_canvas->fillRect(0, 0, _bands.width-(_bands.width-measL), _bands.width, _bgcolor);
|
||||
_canvas->fillRect(_bands.width * 2 + _bands.space - measR, 0, measR, _bands.width, _bgcolor);
|
||||
dsp->drawRGBBitmap(_config.left, _config.top, _canvas->getBuffer(), _bands.width * 2 + _bands.space, _bands.height);
|
||||
#endif
|
||||
}else{
|
||||
_canvas->fillRect(0, 0, _bands.width, measL, _bgcolor);
|
||||
_canvas->fillRect(_bands.width + _bands.space, 0, _bands.width, measR, _bgcolor);
|
||||
dsp.drawRGBBitmap(_config.left, _config.top, _canvas->getBuffer(), _bands.width * 2 + _bands.space, _bands.height);
|
||||
}
|
||||
}
|
||||
|
||||
void VuWidget::loop(){
|
||||
if(_active || !_locked) _draw();
|
||||
}
|
||||
|
||||
void VuWidget::_clear(){
|
||||
dsp.fillRect(_config.left, _config.top, _bands.width * 2 + _bands.space, _bands.height, _bgcolor);
|
||||
}
|
||||
#else // DSP_LCD
|
||||
VuWidget::~VuWidget() { }
|
||||
void VuWidget::init(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor, uint16_t vumincolor, uint16_t bgcolor) {
|
||||
Widget::init(wconf, bgcolor, bgcolor);
|
||||
}
|
||||
void VuWidget::_draw(){ }
|
||||
void VuWidget::loop(){ }
|
||||
void VuWidget::_clear(){ }
|
||||
#endif
|
||||
/************************
|
||||
NUM WIDGET
|
||||
************************/
|
||||
void NumWidget::init(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
Widget::init(wconf, fgcolor, bgcolor);
|
||||
_buffsize = buffsize;
|
||||
_text = (char *) malloc(sizeof(char) * _buffsize);
|
||||
memset(_text, 0, _buffsize);
|
||||
_oldtext = (char *) malloc(sizeof(char) * _buffsize);
|
||||
memset(_oldtext, 0, _buffsize);
|
||||
_textwidth = _oldtextwidth = _oldleft = 0;
|
||||
_uppercase = uppercase;
|
||||
_textheight = wconf.textsize;
|
||||
}
|
||||
|
||||
void NumWidget::setText(const char* txt) {
|
||||
strlcpy(_text, txt, _buffsize);
|
||||
_getBounds();
|
||||
if (strcmp(_oldtext, _text) == 0) return;
|
||||
if (_active) dsp.fillRect(_oldleft == 0 ? _realLeft() : min(_oldleft, _realLeft()), _config.top-_textheight+1, max(_oldtextwidth, _textwidth), _textheight, _bgcolor);
|
||||
_oldtextwidth = _textwidth;
|
||||
_oldleft = _realLeft();
|
||||
if (_active) _draw();
|
||||
}
|
||||
|
||||
void NumWidget::setText(int val, const char *format){
|
||||
char buf[_buffsize];
|
||||
snprintf(buf, _buffsize, format, val);
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
void NumWidget::_getBounds() {
|
||||
_textwidth= dsp.textWidth(_text);
|
||||
}
|
||||
|
||||
void NumWidget::_draw() {
|
||||
if(!_active) return;
|
||||
dsp.setNumFont(); // --------------SetBigFont
|
||||
//dsp.setTextSize(1);
|
||||
dsp.setTextColor(_fgcolor, _bgcolor);
|
||||
dsp.setCursor(_realLeft(), _config.top);
|
||||
dsp.print(_text);
|
||||
strlcpy(_oldtext, _text, _buffsize);
|
||||
dsp.setFont();
|
||||
}
|
||||
|
||||
/**************************
|
||||
PROGRESS WIDGET
|
||||
**************************/
|
||||
void ProgressWidget::_progress() {
|
||||
char buf[_width + 1];
|
||||
snprintf(buf, _width, "%*s%.*s%*s", _pg <= _barwidth ? 0 : _pg - _barwidth, "", _pg <= _barwidth ? _pg : 5, ".....", _width - _pg, "");
|
||||
_pg++; if (_pg >= _width + _barwidth) _pg = 0;
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
bool ProgressWidget::_checkDelay(int m, uint32_t &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressWidget::loop() {
|
||||
if (_checkDelay(_speed, _scrolldelay)) {
|
||||
_progress();
|
||||
}
|
||||
}
|
||||
|
||||
/**************************
|
||||
CLOCK WIDGET
|
||||
**************************/
|
||||
void ClockWidget::draw(){
|
||||
if(!_active) return;
|
||||
dsp.printClock(_config.top, _config.left, _config.textsize, false);
|
||||
}
|
||||
|
||||
void ClockWidget::_draw(){
|
||||
if(!_active) return;
|
||||
dsp.printClock(_config.top, _config.left, _config.textsize, true);
|
||||
}
|
||||
|
||||
void ClockWidget::_clear(){
|
||||
dsp.clearClock();
|
||||
}
|
||||
|
||||
void BitrateWidget::init(BitrateConfig bconf, uint16_t fgcolor, uint16_t bgcolor){
|
||||
Widget::init(bconf.widget, fgcolor, bgcolor);
|
||||
_dimension = bconf.dimension;
|
||||
_bitrate = 0;
|
||||
_format = BF_UNCNOWN;
|
||||
dsp.charSize(bconf.widget.textsize, _charWidth, _textheight);
|
||||
memset(_buf, 0, 6);
|
||||
}
|
||||
|
||||
void BitrateWidget::setBitrate(uint16_t bitrate){
|
||||
_bitrate = bitrate;
|
||||
_draw();
|
||||
}
|
||||
|
||||
void BitrateWidget::setFormat(BitrateFormat format){
|
||||
_format = format;
|
||||
_draw();
|
||||
}
|
||||
|
||||
void BitrateWidget::_draw(){
|
||||
_clear();
|
||||
if(!_active || _format == BF_UNCNOWN || _bitrate==0) return;
|
||||
dsp.drawRect(_config.left, _config.top, _dimension, _dimension, _fgcolor);
|
||||
dsp.fillRect(_config.left, _config.top + _dimension/2, _dimension, _dimension/2, _fgcolor);
|
||||
dsp.setFont();
|
||||
dsp.setTextSize(_config.textsize);
|
||||
dsp.setTextColor(_fgcolor, _bgcolor);
|
||||
snprintf(_buf, 6, "%d", _bitrate);
|
||||
dsp.setCursor(_config.left + _dimension/2 - _charWidth*strlen(_buf)/2, _config.top + _dimension/4 - _textheight/2+1);
|
||||
dsp.print(_buf);
|
||||
dsp.setTextColor(_bgcolor, _fgcolor);
|
||||
dsp.setCursor(_config.left + _dimension/2 - _charWidth*3/2, _config.top + _dimension - _dimension/4 - _textheight/2);
|
||||
switch(_format){
|
||||
case BF_MP3: dsp.print("MP3"); break;
|
||||
case BF_AAC: dsp.print("AAC"); break;
|
||||
case BF_FLAC: dsp.print("FLC"); break;
|
||||
case BF_OGG: dsp.print("OGG"); break;
|
||||
case BF_WAV: dsp.print("WAV"); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void BitrateWidget::_clear() {
|
||||
dsp.fillRect(_config.left, _config.top, _dimension, _dimension, _bgcolor);
|
||||
}
|
||||
|
||||
#endif // #if DSP_MODEL!=DSP_DUMMY
|
||||
267
yoRadio/src/displays/widgets/widgets.h
Normal file
267
yoRadio/src/displays/widgets/widgets.h
Normal file
@@ -0,0 +1,267 @@
|
||||
#ifndef widgets_h
|
||||
#define widgets_h
|
||||
|
||||
#include "Arduino.h"
|
||||
//#include "../../core/config.h"
|
||||
enum WidgetAlign { WA_LEFT, WA_CENTER, WA_RIGHT };
|
||||
enum BitrateFormat { BF_UNCNOWN, BF_MP3, BF_AAC, BF_FLAC, BF_OGG, BF_WAV };
|
||||
|
||||
typedef struct clipArea {
|
||||
uint16_t left;
|
||||
uint16_t top;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
} clipArea;
|
||||
|
||||
struct WidgetConfig {
|
||||
uint16_t left;
|
||||
uint16_t top;
|
||||
uint16_t textsize;
|
||||
WidgetAlign align;
|
||||
};
|
||||
|
||||
struct ScrollConfig {
|
||||
WidgetConfig widget;
|
||||
uint16_t buffsize;
|
||||
bool uppercase;
|
||||
uint16_t width;
|
||||
uint16_t startscrolldelay;
|
||||
uint8_t scrolldelta;
|
||||
uint16_t scrolltime;
|
||||
};
|
||||
|
||||
struct FillConfig {
|
||||
WidgetConfig widget;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
bool outlined;
|
||||
};
|
||||
|
||||
struct ProgressConfig {
|
||||
uint16_t speed;
|
||||
uint16_t width;
|
||||
uint16_t barwidth;
|
||||
};
|
||||
|
||||
struct VUBandsConfig {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t space;
|
||||
uint8_t vspace;
|
||||
uint8_t perheight;
|
||||
uint8_t fadespeed;
|
||||
};
|
||||
|
||||
struct MoveConfig {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
int16_t width;
|
||||
};
|
||||
|
||||
struct BitrateConfig {
|
||||
WidgetConfig widget;
|
||||
uint16_t dimension;
|
||||
};
|
||||
|
||||
class Widget{
|
||||
public:
|
||||
Widget(){ _active = false; }
|
||||
virtual ~Widget(){}
|
||||
virtual void loop(){}
|
||||
virtual void init(WidgetConfig conf, uint16_t fgcolor, uint16_t bgcolor){
|
||||
_config = conf;
|
||||
_fgcolor = fgcolor;
|
||||
_bgcolor = bgcolor;
|
||||
_width = _backMove.width = 0;
|
||||
_backMove.x = _config.left;
|
||||
_backMove.y = _config.top;
|
||||
_moved = _locked = false;
|
||||
}
|
||||
void setAlign(WidgetAlign align){
|
||||
_config.align = align;
|
||||
}
|
||||
void setActive(bool act, bool clr=false) { _active = act; if(_active && !_locked) _draw(); if(clr && !_locked) _clear(); }
|
||||
void lock(bool lck=true) { _locked = lck; if(_locked) _reset(); if(_locked && _active) _clear(); }
|
||||
void unlock() { _locked = false; }
|
||||
bool locked() { return _locked; }
|
||||
void moveTo(MoveConfig mv){
|
||||
if(mv.width<0) return;
|
||||
_moved = true;
|
||||
if(_active && !_locked) _clear();
|
||||
_config.left = mv.x;
|
||||
_config.top = mv.y;
|
||||
if(mv.width>0) _width = mv.width;
|
||||
_reset();
|
||||
_draw();
|
||||
}
|
||||
void moveBack(){
|
||||
if(!_moved) return;
|
||||
if(_active && !_locked) _clear();
|
||||
_config.left = _backMove.x;
|
||||
_config.top = _backMove.y;
|
||||
_width = _backMove.width;
|
||||
_moved = false;
|
||||
_reset();
|
||||
_draw();
|
||||
}
|
||||
protected:
|
||||
bool _active, _moved, _locked;
|
||||
uint16_t _fgcolor, _bgcolor, _width;
|
||||
WidgetConfig _config;
|
||||
MoveConfig _backMove;
|
||||
virtual void _draw() {}
|
||||
virtual void _clear() {}
|
||||
virtual void _reset() {}
|
||||
};
|
||||
|
||||
class TextWidget: public Widget {
|
||||
public:
|
||||
TextWidget() {}
|
||||
TextWidget(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor) { init(wconf, buffsize, uppercase, fgcolor, bgcolor); }
|
||||
~TextWidget();
|
||||
void init(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor);
|
||||
void setText(const char* txt);
|
||||
void setText(int val, const char *format);
|
||||
void setText(const char* txt, const char *format);
|
||||
bool uppercase() { return _uppercase; }
|
||||
protected:
|
||||
char *_text;
|
||||
char *_oldtext;
|
||||
bool _uppercase;
|
||||
uint16_t _buffsize, _textwidth, _oldtextwidth, _oldleft, _textheight;
|
||||
uint8_t _charWidth;
|
||||
protected:
|
||||
void _draw();
|
||||
uint16_t _realLeft();
|
||||
};
|
||||
|
||||
class FillWidget: public Widget {
|
||||
public:
|
||||
FillWidget() {}
|
||||
FillWidget(FillConfig conf, uint16_t bgcolor) { init(conf, bgcolor); }
|
||||
void init(FillConfig conf, uint16_t bgcolor);
|
||||
protected:
|
||||
uint16_t _height;
|
||||
void _draw();
|
||||
};
|
||||
|
||||
class ScrollWidget: public TextWidget {
|
||||
public:
|
||||
ScrollWidget(){}
|
||||
ScrollWidget(const char* separator, ScrollConfig conf, uint16_t fgcolor, uint16_t bgcolor);
|
||||
~ScrollWidget();
|
||||
void init(const char* separator, ScrollConfig conf, uint16_t fgcolor, uint16_t bgcolor);
|
||||
void loop();
|
||||
void setText(const char* txt);
|
||||
void setText(const char* txt, const char *format);
|
||||
private:
|
||||
char *_sep;
|
||||
char *_window;
|
||||
int16_t _x;
|
||||
bool _doscroll;
|
||||
uint8_t _scrolldelta;
|
||||
uint16_t _scrolltime;
|
||||
uint32_t _scrolldelay;
|
||||
uint16_t _sepwidth, _startscrolldelay;
|
||||
uint8_t _charWidth;
|
||||
private:
|
||||
void _setTextParams();
|
||||
void _calcX();
|
||||
void _drawFrame();
|
||||
void _draw();
|
||||
bool _checkIsScrollNeeded();
|
||||
bool _checkDelay(int m, uint32_t &tstamp);
|
||||
void _clear();
|
||||
void _reset();
|
||||
};
|
||||
|
||||
class SliderWidget: public Widget {
|
||||
public:
|
||||
SliderWidget(){}
|
||||
SliderWidget(FillConfig conf, uint16_t fgcolor, uint16_t bgcolor, uint32_t maxval, uint16_t oucolor=0){
|
||||
init(conf, fgcolor, bgcolor, maxval, oucolor);
|
||||
}
|
||||
void init(FillConfig conf, uint16_t fgcolor, uint16_t bgcolor, uint32_t maxval, uint16_t oucolor=0);
|
||||
void setValue(uint32_t val);
|
||||
protected:
|
||||
uint16_t _height, _oucolor, _oldvalwidth;
|
||||
uint32_t _max, _value;
|
||||
bool _outlined;
|
||||
void _draw();
|
||||
void _drawslider();
|
||||
void _clear();
|
||||
};
|
||||
|
||||
class VuWidget: public Widget {
|
||||
public:
|
||||
VuWidget() {}
|
||||
VuWidget(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor, uint16_t vumincolor, uint16_t bgcolor) { init(wconf, bands, vumaxcolor, vumincolor, bgcolor); }
|
||||
~VuWidget();
|
||||
void init(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor, uint16_t vumincolor, uint16_t bgcolor);
|
||||
void loop();
|
||||
protected:
|
||||
#if !defined(DSP_LCD) && !defined(DSP_OLED)
|
||||
Canvas *_canvas;
|
||||
#endif
|
||||
VUBandsConfig _bands;
|
||||
uint16_t _vumaxcolor, _vumincolor;
|
||||
void _draw();
|
||||
void _clear();
|
||||
};
|
||||
|
||||
class NumWidget: public TextWidget {
|
||||
public:
|
||||
void init(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor);
|
||||
void setText(const char* txt);
|
||||
void setText(int val, const char *format);
|
||||
protected:
|
||||
void _getBounds();
|
||||
void _draw();
|
||||
};
|
||||
|
||||
class ProgressWidget: public TextWidget {
|
||||
public:
|
||||
ProgressWidget() {}
|
||||
ProgressWidget(WidgetConfig conf, ProgressConfig pconf, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
init(conf, pconf, fgcolor, bgcolor);
|
||||
}
|
||||
void init(WidgetConfig conf, ProgressConfig pconf, uint16_t fgcolor, uint16_t bgcolor){
|
||||
TextWidget::init(conf, pconf.width, false, fgcolor, bgcolor);
|
||||
_speed = pconf.speed; _width = pconf.width; _barwidth = pconf.barwidth;
|
||||
_pg = 0;
|
||||
}
|
||||
void loop();
|
||||
private:
|
||||
uint8_t _pg;
|
||||
uint16_t _speed, _barwidth;
|
||||
uint32_t _scrolldelay;
|
||||
void _progress();
|
||||
bool _checkDelay(int m, uint32_t &tstamp);
|
||||
};
|
||||
|
||||
class ClockWidget: public Widget {
|
||||
public:
|
||||
void draw();
|
||||
protected:
|
||||
void _draw();
|
||||
void _clear();
|
||||
};
|
||||
|
||||
class BitrateWidget: public Widget {
|
||||
public:
|
||||
BitrateWidget() {}
|
||||
BitrateWidget(BitrateConfig bconf, uint16_t fgcolor, uint16_t bgcolor) { init(bconf, fgcolor, bgcolor); }
|
||||
~BitrateWidget(){}
|
||||
void init(BitrateConfig bconf, uint16_t fgcolor, uint16_t bgcolor);
|
||||
void setBitrate(uint16_t bitrate);
|
||||
void setFormat(BitrateFormat format);
|
||||
protected:
|
||||
BitrateFormat _format;
|
||||
char _buf[6];
|
||||
uint8_t _charWidth;
|
||||
uint16_t _dimension, _bitrate, _textheight;
|
||||
void _draw();
|
||||
void _clear();
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user