Initial commit

This commit is contained in:
Bertrand Songis
2019-10-02 11:05:12 +02:00
parent f8abbd423d
commit 9b14d177c5
59 changed files with 7044 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
include(src)
+31
View File
@@ -0,0 +1,31 @@
set(LIBOPENUI_SRC
libopenui_globals.cpp
libopenui_file.cpp
bitmapbuffer.cpp
window.cpp
form.cpp
button.cpp
static.cpp
checkbox.cpp
slider.cpp
mainwindow.cpp
menu.cpp
menutoolbar.cpp
choice.cpp
filechoice.cpp
numberedit.cpp
textedit.cpp
coloredit.cpp
progress.cpp
page.cpp
dialog.cpp
tabsgroup.cpp
)
if(HARDWARE_TOUCH)
set(LIBOPENUI_SRC
${LIBOPENUI_SRC}
keyboard_text.cpp
keyboard_number.cpp
)
endif()
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _BASENUMBEREDIT_H_
#define _BASENUMBEREDIT_H_
#include "form.h"
class BaseNumberEdit : public FormField {
public:
BaseNumberEdit(Window * parent, const rect_t &rect, int32_t vmin, int32_t vmax,
std::function<int32_t()> getValue, std::function<void(int32_t)> setValue = nullptr, LcdFlags flags = 0):
FormField(parent, rect),
vmin(vmin),
vmax(vmax),
_getValue(std::move(getValue)),
_setValue(std::move(setValue)),
flags(flags)
{
}
void setMin(int32_t value)
{
vmin = value;
}
void setMax(int32_t value)
{
vmax = value;
}
void setDefault(int32_t value)
{
vdefault = value;
}
int32_t getMin() const
{
return vmin;
}
int32_t getMax() const
{
return vmax;
}
int32_t getDefault() const
{
return vdefault;
}
void setStep(int32_t value)
{
step = value;
}
int32_t getStep() const
{
return step;
}
void setValue(int32_t value)
{
_setValue(limit(vmin, value, vmax));
invalidate();
}
void setSetValueHandler(std::function<void(int32_t)> handler)
{
_setValue = handler;
}
int32_t getValue()
{
return _getValue();
}
protected:
int32_t vdefault = 0;
int32_t vmin;
int32_t vmax;
int32_t step = 1;
std::function<int32_t()> _getValue;
std::function<void(int32_t)> _setValue;
LcdFlags flags;
};
#endif // _BASENUMBEREDIT_H_
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _BITFIELD_H
#define _BITFIELD_H
#include <inttypes.h>
// A set of bitfield handling macros
template <typename T>
inline T bfBit(uint8_t n)
{
return T(1) << n;
}
#define BFBIT_SET(y, mask) ( y |= (mask) )
#define BFBIT_CLEAR(y, mask) ( y &= ~(mask) )
#define BFBIT_FLIP(y, mask) ( y ^= (mask) )
#define BF_SINGLE_BIT_SET(y, i) BFBIT_SET(y, bfBit(i))
//! Create a bitmask of length 'len'.
template <typename T>
inline T bfBitmask(uint8_t len)
{
return bfBit<T>(len) - 1;
}
//! Create a bitfield mask of length 'len' starting at bit 'start'.
template <typename T>
inline T bfMask(uint8_t start, uint8_t len)
{
return bfBitmask<T>(len) << start;
}
//! Prepare a bitmask for insertion or combining.
template <typename T>
inline T bfPrep(T x, uint8_t start, uint8_t len)
{
return (x & bfBitmask<T>(len)) << start;
}
//! Extract a bitfield of length 'len' starting at bit 'start' from 'y'.
template <typename T>
inline T bfGet(T y, uint8_t start, uint8_t len)
{
return ((y)>>(start)) & bfBitmask<T>(len);
}
//! Insert 'len' bits of 'x 'into 'y', starting at bit 'start' from 'y'.
template <class T>
inline T bfSet(T to, T from, uint8_t start, uint8_t len)
{
return (to & ~bfMask<T>(start, len)) | bfPrep<T>(from, start, len);
}
template <class T>
inline T bfBitGet(T y, T mask)
{
return (y & mask);
}
template <class T>
inline T bfSingleBitGet(T y, uint8_t i)
{
return bfBitGet(y, bfBit<T>(i));
}
#endif //BITFIELD_H
+925
View File
@@ -0,0 +1,925 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include <math.h>
#include "bitmapbuffer.h"
#include "libopenui_depends.h"
#include "libopenui_globals.h"
#include "libopenui_helpers.h"
#include "libopenui_file.h"
#include "font.h"
void BitmapBuffer::drawAlphaPixel(pixel_t * p, uint8_t opacity, uint16_t color)
{
if (opacity == OPACITY_MAX) {
drawPixel(p, color);
}
else if (opacity != 0) {
uint8_t bgWeight = OPACITY_MAX - opacity;
RGB_SPLIT(color, red, green, blue);
RGB_SPLIT(*p, bgRed, bgGreen, bgBlue);
uint16_t r = (bgRed * bgWeight + red * opacity) / OPACITY_MAX;
uint16_t g = (bgGreen * bgWeight + green * opacity) / OPACITY_MAX;
uint16_t b = (bgBlue * bgWeight + blue * opacity) / OPACITY_MAX;
drawPixel(p, RGB_JOIN(r, g, b));
}
}
void BitmapBuffer::drawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att)
{
APPLY_OFFSET();
if (y >= height || y >= ymax || y < ymin)
return;
if (x+w > width) {
w = width - x;
}
pixel_t * p = getPixelPtr(x, y);
pixel_t color = lcdColorTable[COLOR_IDX(att)];
uint8_t opacity = 0x0F - (att >> 24);
if (pat == SOLID) {
while (w--) {
drawAlphaPixel(p, opacity, color);
MOVE_TO_NEXT_RIGHT_PIXEL(p);
}
}
else {
while (w--) {
if (pat & 1) {
drawAlphaPixel(p, opacity, color);
pat = (pat >> 1) | 0x80;
}
else {
pat = pat >> 1;
}
MOVE_TO_NEXT_RIGHT_PIXEL(p);
}
}
}
void BitmapBuffer::drawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att)
{
APPLY_OFFSET();
if (x < xmin || x >= xmax)
return;
if (h < 0) {
y += h;
h = -h;
}
if (y < ymin) {
h += y-ymin;
y = ymin;
}
if (y + h > ymax) {
h = ymax - y;
}
if (h <= 0)
return;
pixel_t color = lcdColorTable[COLOR_IDX(att)];
uint8_t opacity = 0x0F - (att >> 24);
if (pat == SOLID) {
while (h--) {
drawAlphaPixel(x, y, opacity, color);
y++;
}
}
else {
if (pat==DOTTED && !(y%2)) {
pat = ~pat;
}
while (h--) {
if (pat & 1) {
drawAlphaPixel(x, y, opacity, color);
pat = (pat >> 1) | 0x80;
}
else {
pat = pat >> 1;
}
y++;
}
}
}
void BitmapBuffer::drawRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t thickness, uint8_t pat, LcdFlags att)
{
for (int i=0; i<thickness; i++) {
drawVerticalLine(x+i, y, h, pat, att);
drawVerticalLine(x+w-1-i, y, h, pat, att);
drawHorizontalLine(x, y+h-1-i, w, pat, att);
drawHorizontalLine(x, y+i, w, pat, att);
}
}
void BitmapBuffer::drawSolidFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags)
{
APPLY_OFFSET();
if (x >= xmax || y >= ymax)
return;
if (h < 0) {
y += h;
h = -h;
}
if (y < ymin) {
h += y-ymin;
y = ymin;
}
if (x < xmin) {
w += x - xmin;
x = xmin;
}
if (y + h > ymax)
h = ymax - y;
if (x + w > xmax)
w = xmax - x;
if (!data || h<=0 || w<=0)
return;
DMAFillRect(data, width, height, x, y, w, h, lcdColorTable[COLOR_IDX(flags)]);
}
void BitmapBuffer::drawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att)
{
APPLY_OFFSET();
if (x >= xmax || y >= ymax)
return;
if (h < 0) {
y += h;
h = -h;
}
if (y < ymin) {
h += y-ymin;
y = ymin;
}
if (x < xmin) {
w += x - xmin;
x = xmin;
}
if (y + h > ymax)
h = ymax - y;
if (x + w > xmax)
w = xmax - x;
for (coord_t i=y; i<y+h; i++) {
if ((att & ROUND) && (i==y || i==y+h-1))
drawHorizontalLine(x+1, i, w-2, pat, att);
else
drawHorizontalLine(x, i, w, pat, att);
}
}
//
//void BitmapBuffer::invertRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags att)
//{
// pixel_t color = lcdColorTable[COLOR_IDX(att)];
// RGB_SPLIT(color, red, green, blue);
//
// for (int i=y; i<y+h; i++) {
// pixel_t * p = getPixelPtr(x, i);
// for (int j=0; j<w; j++) {
// // TODO ASSERT_IN_DISPLAY(p);
// RGB_SPLIT(*p, bgRed, bgGreen, bgBlue);
// drawPixel(p, RGB_JOIN(0x1F + red - bgRed, 0x3F + green - bgGreen, 0x1F + blue - bgBlue));
// MOVE_TO_NEXT_RIGHT_PIXEL(p);
// }
// }
//}
//
//void BitmapBuffer::drawCircle(int x0, int y0, int radius)
//{
// int x = radius;
// int y = 0;
// int decisionOver2 = 1 - x;
//
// while (y <= x) {
// drawPixel(x+x0, y+y0, WHITE);
// drawPixel(y+x0, x+y0, WHITE);
// drawPixel(-x+x0, y+y0, WHITE);
// drawPixel(-y+x0, x+y0, WHITE);
// drawPixel(-x+x0, -y+y0, WHITE);
// drawPixel(-y+x0, -x+y0, WHITE);
// drawPixel(x+x0, -y+y0, WHITE);
// drawPixel(y+x0, -x+y0, WHITE);
// y++;
// if (decisionOver2 <= 0) {
// decisionOver2 += 2*y + 1;
// }
// else {
// x--;
// decisionOver2 += 2 * (y-x) + 1;
// }
// }
//}
//
//bool evalSlopes(int * slopes, int startAngle, int endAngle)
//{
// if (startAngle >= 360 || endAngle <= 0)
// return false;
//
// if (startAngle == 0) {
// slopes[1] = 100000;
// slopes[2] = -100000;
// }
// else {
// float angle1 = float(startAngle) * (M_PI / 180.0f);
// if (startAngle >= 180) {
// slopes[1] = -100000;
// slopes[2] = cosf(angle1) * 100 / sinf(angle1);
// }
// else {
// slopes[1] = cosf(angle1) * 100 / sinf(angle1);
// slopes[2] = -100000;
// }
// }
//
// if (endAngle == 360) {
// slopes[0] = -100000;
// slopes[3] = 100000;
// }
// else {
// float angle2 = float(endAngle) * (M_PI / 180.0f);
// if (endAngle >= 180) {
// slopes[0] = -100000;
// slopes[3] = -cosf(angle2) * 100 / sinf(angle2);
// }
// else {
// slopes[0] = cosf(angle2) * 100 / sinf(angle2);
// slopes[3] = -100000;
// }
// }
//
// return true;
//}
//
//void BitmapBuffer::drawPie(int x0, int y0, int radius, int startAngle, int endAngle)
//{
// int slopes[4];
// if (!evalSlopes(slopes, startAngle, endAngle))
// return;
//
// for (int y=0; y<=radius; y++) {
// for (int x=0; x<=radius; x++) {
// if (x*x+y*y <= radius*radius) {
// int slope = (x==0 ? (y<0 ? -99000 : 99000) : y*100/x);
// if (slope >= slopes[0] && slope < slopes[1]) {
// drawPixel(x0+x, y0-y, WHITE);
// }
// if (-slope >= slopes[0] && -slope < slopes[1]) {
// drawPixel(x0+x, y0+y, WHITE);
// }
// if (slope >= slopes[2] && slope < slopes[3]) {
// drawPixel(x0-x, y0-y, WHITE);
// }
// if (-slope >= slopes[2] && -slope < slopes[3]) {
// drawPixel(x0-x, y0+y, WHITE);
// }
// }
// }
// }
//}
void BitmapBuffer::drawMask(coord_t x, coord_t y, const BitmapBuffer * mask, LcdFlags flags, coord_t offset, coord_t width)
{
if (mask == nullptr) {
return;
}
APPLY_OFFSET();
coord_t w = mask->getWidth();
coord_t height = mask->getHeight();
if (!width || width > w) {
width = w;
}
if (x + width > xmax) {
width = xmax - x;
}
if (y >= ymax || x >= xmax || width <= 0 || x + width < xmin || y + height < ymin) {
return;
}
pixel_t color = lcdColorTable[COLOR_IDX(flags)];
for (coord_t row=0; row<height; row++) {
if (y + row < ymin || y + row >= ymax)
continue;
pixel_t * p = getPixelPtr(x, y+row);
const pixel_t * q = mask->getPixelPtr(offset, row);
for (coord_t col=0; col<width; col++) {
drawAlphaPixel(p, *((uint8_t *)q), color);
MOVE_TO_NEXT_RIGHT_PIXEL(p);
MOVE_TO_NEXT_RIGHT_PIXEL(q);
}
}
}
void BitmapBuffer::drawBitmapPattern(coord_t x, coord_t y, const uint8_t * bmp, LcdFlags flags, coord_t offset, coord_t width)
{
APPLY_OFFSET();
coord_t w = *((uint16_t *)bmp);
coord_t height = *(((uint16_t *)bmp)+1);
if (!width || width > w) {
width = w;
}
if (x + width > xmax) {
width = xmax - x;
}
if (y >= ymax || x >= xmax || width <= 0 || x + width < xmin || y + height < ymin) {
return;
}
pixel_t color = lcdColorTable[COLOR_IDX(flags)];
for (coord_t row=0; row<height; row++) {
if (y + row < ymin || y + row >= ymax)
continue;
const uint8_t * q = bmp + 4 + row*w + offset;
for (coord_t col=0; col<width; col++) {
coord_t xpixel, ypixel;
if (flags & VERTICAL) {
xpixel = x + row;
ypixel = y - col;
}
else {
xpixel = x + col;
ypixel = y + row;
}
if (xpixel >= xmin && xpixel < xmax) {
pixel_t * p = getPixelPtr(xpixel, ypixel);
if (p)
drawAlphaPixel(p, *q, color);
}
q++;
}
}
}
uint8_t BitmapBuffer::drawChar(coord_t x, coord_t y, const uint8_t * font, const uint16_t * spec, unsigned int index, LcdFlags flags)
{
coord_t offset = spec[index + 1];
coord_t width = spec[index + 2] - offset;
if (width > 0) {
drawBitmapPattern(x, y, font, flags, offset, width);
}
return width;
}
#define INCREMENT_POS(delta) do { if (flags & VERTICAL) y -= delta; else x += delta; } while(0)
coord_t BitmapBuffer::drawSizedText(coord_t x, coord_t y, const char * s, uint8_t len, LcdFlags flags)
{
MOVE_OFFSET();
int height = getFontHeight(flags);
if (y + height <= ymin || y >= ymax) {
RESTORE_OFFSET();
return x;
}
uint32_t fontindex = FONTINDEX(flags);
const unsigned char * font = fontsTable[fontindex];
const uint16_t * fontspecs = fontspecsTable[fontindex];
if (flags & (RIGHT | CENTERED)) {
int width = getTextWidth(s, len, flags);
if (flags & RIGHT) {
INCREMENT_POS(-width);
}
else if (flags & CENTERED) {
INCREMENT_POS(-width / 2);
}
}
coord_t & pos = (flags & VERTICAL) ? y : x;
const coord_t orig_pos = pos;
while (len--) {
unsigned int c = uint8_t(*s);
if (!c) {
break;
}
else if (c == 0x20) {
INCREMENT_POS(4);
}
else if (c >= 0xFE) {
s++;
c = uint8_t(*s) + ((c & 0x01) << 8) - 1;
if (c >= 0x101)
c -= 1;
c += 187;
uint8_t width = drawChar(x-1, y, font, fontspecs, c, flags);
INCREMENT_POS(width);
}
else if (c >= 0x20) {
uint8_t width = drawChar(x-1, y, font, fontspecs, getMappedChar(c), flags);
INCREMENT_POS(width);
}
else if (c == '\n') {
pos = orig_pos;
if (flags & VERTICAL)
x += height;
else
y += height;
}
s++;
}
RESTORE_OFFSET();
return pos - offsetX;
}
void BitmapBuffer::drawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags, uint8_t len, const char * prefix, const char * suffix)
{
char str[48+1]; // max=16 for the prefix, 16 chars for the number, 16 chars for the suffix
char *s = str+32;
*s = '\0';
int idx = 0;
int mode = MODE(flags);
bool neg = false;
if (val < 0) {
val = -val;
neg = true;
}
do {
*--s = '0' + (val % 10);
++idx;
val /= 10;
if (mode!=0 && idx==mode) {
mode = 0;
*--s = '.';
if (val==0)
*--s = '0';
}
} while (val!=0 || mode>0 || (mode==MODE(LEADING0) && idx<len));
if (neg) *--s = '-';
// TODO needs check on all string lengths ...
if (prefix) {
int len = strlen(prefix);
if (len <= 16) {
s -= len;
strncpy(s, prefix, len);
}
}
if (suffix) {
strncpy(&str[32], suffix, 16);
}
flags &= ~LEADING0;
drawText(x, y, s, flags);
}
void drawSolidRect(BitmapBuffer * dc, coord_t x, coord_t y, coord_t w, coord_t h, uint8_t thickness, LcdFlags att)
{
dc->drawSolidFilledRect(x, y, thickness, h, att);
dc->drawSolidFilledRect(x+w-thickness, y, thickness, h, att);
dc->drawSolidFilledRect(x, y, w, thickness, att);
dc->drawSolidFilledRect(x, y+h-thickness, w, thickness, att);
}
//void BitmapBuffer::drawBitmapPie(int x0, int y0, const uint16_t * img, int startAngle, int endAngle)
//{
// const uint16_t * q = img;
// coord_t width = *q++;
// coord_t height = *q++;
//
// int slopes[4];
// if (!evalSlopes(slopes, startAngle, endAngle))
// return;
//
// int w2 = width/2;
// int h2 = height/2;
//
// for (int y=h2-1; y>=0; y--) {
// for (int x=w2-1; x>=0; x--) {
// int slope = (x==0 ? 99000 : y*100/x);
// if (slope >= slopes[0] && slope < slopes[1]) {
// *getPixelPtr(x0+w2+x, y0+h2-y) = q[(h2-y)*width + w2+x];
// }
// if (-slope >= slopes[0] && -slope < slopes[1]) {
// *getPixelPtr(x0+w2+x, y0+h2+y) = q[(h2+y)*width + w2+x];
// }
// if (slope >= slopes[2] && slope < slopes[3]) {
// *getPixelPtr(x0+w2-x, y0+h2-y) = q[(h2-y)*width + w2-x];
// }
// if (-slope >= slopes[2] && -slope < slopes[3]) {
// *getPixelPtr(x0+w2-x, y0+h2+y) = q[(h2+y)*width + w2-x];
// }
// }
// }
//}
//
//void BitmapBuffer::drawBitmapPatternPie(coord_t x0, coord_t y0, const uint8_t * img, LcdFlags flags, int startAngle, int endAngle)
//{
// coord_t width = *((uint16_t *)img);
// coord_t height = *(((uint16_t *)img)+1);
// const uint8_t * q = img+4;
//
// int slopes[4];
// if (!evalSlopes(slopes, startAngle, endAngle))
// return;
//
// pixel_t color = lcdColorTable[COLOR_IDX(flags)];
//
// int w2 = width/2;
// int h2 = height/2;
//
// for (int y=h2-1; y>=0; y--) {
// for (int x=w2-1; x>=0; x--) {
// int slope = (x==0 ? (y<0 ? -99000 : 99000) : y*100/x);
// if (slope >= slopes[0] && slope < slopes[1]) {
// drawAlphaPixel(x0+w2+x, y0+h2-y, q[(h2-y)*width + w2+x], color);
// }
// if (-slope >= slopes[0] && -slope < slopes[1]) {
// drawAlphaPixel(x0+w2+x, y0+h2+y, q[(h2+y)*width + w2+x], color);
// }
// if (slope >= slopes[2] && slope < slopes[3]) {
// drawAlphaPixel(x0+w2-x, y0+h2-y, q[(h2-y)*width + w2-x], color);
// }
// if (-slope >= slopes[2] && -slope < slopes[3]) {
// drawAlphaPixel(x0+w2-x, y0+h2+y, q[(h2+y)*width + w2-x], color);
// }
// }
// }
//}
BitmapBuffer * BitmapBuffer::load(const char * filename)
{
const char * ext = getFileExtension(filename);
if (ext && !strcmp(ext, ".bmp"))
return load_bmp(filename);
else
return load_stb(filename);
}
BitmapBuffer * BitmapBuffer::loadMask(const char * filename)
{
BitmapBuffer * bitmap = BitmapBuffer::load(filename);
if (bitmap) {
pixel_t * p = bitmap->getPixelPtr(0, 0);
for (int i = bitmap->getWidth() * bitmap->getHeight(); i > 0; i--) {
*((uint8_t *)p) = OPACITY_MAX - ((*p) >> 12);
MOVE_TO_NEXT_RIGHT_PIXEL(p);
}
}
return bitmap;
}
BitmapBuffer * BitmapBuffer::loadMaskOnBackground(const char * filename, LcdFlags foreground, LcdFlags background)
{
BitmapBuffer * result = nullptr;
BitmapBuffer * mask = BitmapBuffer::loadMask(filename);
if (mask) {
result = new BitmapBuffer(BMP_RGB565, mask->getWidth(), mask->getHeight());
if (result) {
result->clear(background);
result->drawMask(0, 0, mask, foreground);
}
delete mask;
}
return result;
}
FIL imgFile __DMA;
BitmapBuffer * BitmapBuffer::load_bmp(const char * filename)
{
UINT read;
uint8_t palette[16];
uint8_t bmpBuf[LCD_W]; /* maximum with LCD_W */
uint8_t * buf = &bmpBuf[0];
FRESULT result = f_open(&imgFile, filename, FA_OPEN_EXISTING | FA_READ);
if (result != FR_OK) {
return nullptr;
}
if (f_size(&imgFile) < 14) {
f_close(&imgFile);
return nullptr;
}
result = f_read(&imgFile, buf, 14, &read);
if (result != FR_OK || read != 14) {
f_close(&imgFile);
return nullptr;
}
if (buf[0] != 'B' || buf[1] != 'M') {
f_close(&imgFile);
return nullptr;
}
uint32_t fsize = *((uint32_t *)&buf[2]);
uint32_t hsize = *((uint32_t *)&buf[10]); /* header size */
uint32_t len = limit((uint32_t)4, (uint32_t)(hsize-14), (uint32_t)32);
result = f_read(&imgFile, buf, len, &read);
if (result != FR_OK || read != len) {
f_close(&imgFile);
return nullptr;
}
uint32_t ihsize = *((uint32_t *)&buf[0]); /* more header size */
/* invalid header size */
if (ihsize + 14 > hsize) {
f_close(&imgFile);
return nullptr;
}
/* sometimes file size is set to some headers size, set a real size in that case */
if (fsize == 14 || fsize == ihsize + 14)
fsize = f_size(&imgFile) - 2;
/* declared file size less than header size */
if (fsize <= hsize) {
f_close(&imgFile);
return nullptr;
}
uint32_t w, h;
switch (ihsize){
case 40: // windib
case 56: // windib v3
case 64: // OS/2 v2
case 108: // windib v4
case 124: // windib v5
w = *((uint32_t *)&buf[4]);
h = *((uint32_t *)&buf[8]);
buf += 12;
break;
case 12: // OS/2 v1
w = *((uint16_t *)&buf[4]);
h = *((uint16_t *)&buf[6]);
buf += 8;
break;
default:
f_close(&imgFile);
return nullptr;
}
if (*((uint16_t *)&buf[0]) != 1) { /* planes */
f_close(&imgFile);
return nullptr;
}
uint16_t depth = *((uint16_t *)&buf[2]);
buf = &bmpBuf[0];
if (depth == 4) {
if (f_lseek(&imgFile, hsize-64) != FR_OK || f_read(&imgFile, buf, 64, &read) != FR_OK || read != 64) {
f_close(&imgFile);
return nullptr;
}
for (uint8_t i=0; i<16; i++) {
palette[i] = buf[4*i];
}
}
else {
if (f_lseek(&imgFile, hsize) != FR_OK) {
f_close(&imgFile);
return nullptr;
}
}
BitmapBuffer * bmp = new BitmapBuffer(BMP_RGB565, w, h);
if (bmp == nullptr || bmp->getData() == nullptr) {
f_close(&imgFile);
return nullptr;
}
uint32_t rowSize;
bool hasAlpha = false;
switch (depth) {
case 32:
for (int i=h-1; i>=0; i--) {
pixel_t * dst = bmp->getPixelPtr(0, i);
for (unsigned int j=0; j<w; j++) {
uint32_t pixel;
result = f_read(&imgFile, (uint8_t *)&pixel, 4, &read);
if (result != FR_OK || read != 4) {
f_close(&imgFile);
delete bmp;
return nullptr;
}
if (hasAlpha) {
*dst = ARGB(pixel & 0xff, (pixel >> 24) & 0xff, (pixel >> 16) & 0xff, (pixel >> 8) & 0xff);
}
else {
if ((pixel & 0xff) == 0xff) {
*dst = RGB(pixel >> 24, (pixel >> 16) & 0xff, (pixel >> 8) & 0xff);
}
else {
hasAlpha = true;
bmp->setFormat(BMP_ARGB4444);
for (pixel_t * p = bmp->getPixelPtr(j, i); p != bmp->getPixelPtr(0, h); MOVE_TO_NEXT_RIGHT_PIXEL(p)) {
pixel_t tmp = *p;
*p = ((tmp >> 1) & 0x0f) + (((tmp >> 7) & 0x0f) << 4) + (((tmp >> 12) & 0x0f) << 8);
}
*dst = ARGB(pixel & 0xff, (pixel >> 24) & 0xff, (pixel >> 16) & 0xff, (pixel >> 8) & 0xff);
}
}
MOVE_TO_NEXT_RIGHT_PIXEL(dst);
}
}
break;
case 1:
break;
case 4:
rowSize = ((4*w+31)/32)*4;
for (int32_t i=h-1; i>=0; i--) {
result = f_read(&imgFile, buf, rowSize, &read);
if (result != FR_OK || read != rowSize) {
f_close(&imgFile);
delete bmp;
return nullptr;
}
pixel_t * dst = bmp->getPixelPtr(0, i);
for (uint32_t j=0; j<w; j++) {
uint8_t index = (buf[j/2] >> ((j & 1) ? 0 : 4)) & 0x0F;
uint8_t val = palette[index];
*dst = RGB(val, val, val);
MOVE_TO_NEXT_RIGHT_PIXEL(dst);
}
}
break;
default:
f_close(&imgFile);
delete bmp;
return nullptr;
}
f_close(&imgFile);
return bmp;
}
#define STB_IMAGE_IMPLEMENTATION
#define STBI_ONLY_PNG
#define STBI_ONLY_JPEG
#define STBI_ONLY_BMP
#define STBI_ONLY_GIF
#define STBI_NO_STDIO
#define STBI_NO_HDR
#define STBI_NO_LINEAR
// #define TRACE_STB_MALLOC
#if defined(TRACE_STB_MALLOC)
#define STBI_MALLOC(sz) stb_malloc(sz)
#define STBI_REALLOC_SIZED(p,oldsz,newsz) stb_realloc(p,oldsz,newsz)
#define STBI_FREE(p) stb_free(p)
void * stb_malloc(unsigned int size)
{
void * res = malloc(size);
TRACE("malloc %d = %p", size, res);
return res;
}
void stb_free(void *ptr)
{
TRACE("free %p", ptr);
free(ptr);
}
void *stb_realloc(void *ptr, unsigned int oldsz, unsigned int newsz)
{
void * res = realloc(ptr, newsz);
TRACE("realloc %p, %d -> %d = %p", ptr, oldsz, newsz, res);
return res;
}
#endif // #if defined(TRACE_STB_MALLOC)
#include "thirdparty/Stb/stb_image.h"
// fill 'data' with 'size' bytes. return number of bytes actually read
int stbc_read(void *user, char *data, int size)
{
FIL * fp = (FIL *)user;
UINT br = 0;
FRESULT res = f_read(fp, data, size, &br);
if (res == FR_OK) {
return (int)br;
}
return 0;
}
// skip the next 'n' bytes, or 'unget' the last -n bytes if negative
void stbc_skip(void *user, int n)
{
FIL * fp = (FIL *)user;
f_lseek(fp, f_tell(fp) + n);
}
// returns nonzero if we are at end of file/data
int stbc_eof(void *user)
{
FIL * fp = (FIL *)user;
int res = f_eof(fp);
return res;
}
// callbacks for stb-image
const stbi_io_callbacks stbCallbacks = {
stbc_read,
stbc_skip,
stbc_eof
};
BitmapBuffer * BitmapBuffer::load_stb(const char * filename)
{
FRESULT result = f_open(&imgFile, filename, FA_OPEN_EXISTING | FA_READ);
if (result != FR_OK) {
return nullptr;
}
int w, h, n;
unsigned char * img = stbi_load_from_callbacks(&stbCallbacks, &imgFile, &w, &h, &n, 4);
f_close(&imgFile);
if (!img) {
return nullptr;
}
// convert to RGB565 or ARGB4444 format
BitmapBuffer * bmp = new BitmapBuffer(n == 4 ? BMP_ARGB4444 : BMP_RGB565, w, h);
if (bmp == NULL) {
TRACE("load_stb() malloc failed");
stbi_image_free(img);
return nullptr;
}
#if 0
DMABitmapConvert(bmp->data, img, w, h, n == 4 ? DMA2D_ARGB4444 : DMA2D_RGB565);
#else
pixel_t * dest = bmp->getPixelPtr(0, 0);
const uint8_t * p = img;
if (n == 4) {
for (int row = 0; row < h; ++row) {
for (int col = 0; col < w; ++col) {
*dest = ARGB(p[3], p[0], p[1], p[2]);
MOVE_TO_NEXT_RIGHT_PIXEL(dest);
p += 4;
}
}
}
else {
for (int row = 0; row < h; ++row) {
for (int col = 0; col < w; ++col) {
*dest = RGB(p[0], p[1], p[2]);
MOVE_TO_NEXT_RIGHT_PIXEL(dest);
p += 4;
}
}
}
#endif
stbi_image_free(img);
return bmp;
}
+489
View File
@@ -0,0 +1,489 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _BITMAP_BUFFER_H_
#define _BITMAP_BUFFER_H_
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "libopenui_types.h"
#include "libopenui_defines.h"
#include "libopenui_depends.h"
#include "debug.h"
constexpr uint8_t SOLID = 0xFF;
constexpr uint8_t DOTTED = 0x55;
constexpr uint8_t STASHED = 0x33;
#define MOVE_OFFSET() coord_t offsetX = this->offsetX; x += offsetX; this->offsetX = 0; coord_t offsetY = this->offsetY; y += offsetY; this->offsetY = 0
#define APPLY_OFFSET() x += offsetX; y += offsetY
#define RESTORE_OFFSET() this->offsetX = offsetX, this->offsetY = offsetY
#if defined(PCBX10) && !defined(SIMU)
#define MOVE_PIXEL_RIGHT(p, count) p -= count
#else
#define MOVE_PIXEL_RIGHT(p, count) p += count
#endif
#define MOVE_TO_NEXT_RIGHT_PIXEL(p) MOVE_PIXEL_RIGHT(p, 1)
#define USE_STB
enum BitmapFormats
{
BMP_RGB565,
BMP_ARGB4444
};
template<class T>
class BitmapBufferBase
{
public:
BitmapBufferBase(uint8_t format, uint16_t width, uint16_t height, T * data):
format(format),
width(width),
height(height),
xmax(width),
ymax(height),
data(data),
data_end(data + (width * height))
{
}
BitmapBufferBase(uint8_t format, T * data):
format(format),
width(*((uint16_t*)data)),
height(*(((uint16_t*)data) + 1)),
xmax(width),
ymax(height),
data(data + 2),
data_end(data + 2 + (width * height))
{
}
inline void clearClippingRect()
{
xmin = 0;
xmax = width;
ymin = 0;
ymax = height;
}
inline void setClippingRect(coord_t xmin, coord_t xmax, coord_t ymin, coord_t ymax)
{
this->xmin = xmin;
this->xmax = xmax;
this->ymin = ymin;
this->ymax = ymax;
}
inline void getClippingRect(coord_t & xmin, coord_t & xmax, coord_t & ymin, coord_t & ymax)
{
xmin = this->xmin;
xmax = this->xmax;
ymin = this->ymin;
ymax = this->ymax;
}
inline void setOffset(coord_t offsetX, coord_t offsetY)
{
this->offsetX = offsetX;
this->offsetY = offsetY;
}
coord_t getOffsetX() const
{
return offsetX;
}
coord_t getOffsetY() const
{
return offsetY;
}
inline uint8_t getFormat() const
{
return format;
}
inline uint16_t getWidth() const
{
return width;
}
inline uint16_t getHeight() const
{
return height;
}
inline T * getData() const
{
return data;
}
uint32_t getDataSize() const
{
return width * height * sizeof(T);
}
inline const pixel_t * getPixelPtr(coord_t x, coord_t y) const
{
#if defined(PCBX10) && !defined(SIMU)
x = width - x - 1;
y = height - y - 1;
#endif
return &data[y*width + x];
}
protected:
uint8_t format;
coord_t width;
coord_t height;
coord_t xmin = 0;
coord_t xmax;
coord_t ymin = 0;
coord_t ymax;
coord_t offsetX = 0;
coord_t offsetY = 0;
T * data;
T * data_end;
};
typedef BitmapBufferBase<const uint16_t> Bitmap;
class RLEBitmap:
public BitmapBufferBase<uint16_t>
{
public:
RLEBitmap(uint8_t format, const uint8_t* rle_data) :
BitmapBufferBase<uint16_t>(format, 0, 0, nullptr)
{
width = *((uint16_t *)rle_data);
height = *(((uint16_t *)rle_data)+1);
uint32_t pixels = width * height;
data = (uint16_t*)malloc(pixels * sizeof(uint16_t));
decode((uint8_t *)data, pixels * sizeof(uint16_t), rle_data+4);
data_end = data + pixels;
}
~RLEBitmap()
{
free(data);
}
static int decode(uint8_t * dest, unsigned int dest_size, const unsigned char* src)
{
//unsigned char count = 0;
unsigned char prev_byte = 0;
bool prev_byte_valid = false;
const unsigned char * dest_end = dest + dest_size;
unsigned char * d = dest;
while (d < dest_end) {
*d++ = *src;
if (prev_byte_valid && (*src == prev_byte)) {
src++;
if (d + *src > dest + dest_size) {
// TRACE("rle_decode_8bit: destination overflow!\n");
return -1;
}
memset(d, prev_byte, *src);
d += *src++;
prev_byte_valid = false;
}
else {
prev_byte = *src++;
prev_byte_valid = true;
}
}
return d - dest;
}
};
class BitmapBuffer: public BitmapBufferBase<uint16_t>
{
private:
bool dataAllocated;
#if defined(DEBUG)
bool leakReported;
#endif
public:
BitmapBuffer(uint8_t format, uint16_t width, uint16_t height):
BitmapBufferBase<uint16_t>(format, width, height, nullptr),
dataAllocated(true)
#if defined(DEBUG)
, leakReported(false)
#endif
{
data = (uint16_t *)malloc(width*height*sizeof(uint16_t));
data_end = data + (width * height);
}
BitmapBuffer(uint8_t format, uint16_t width, uint16_t height, uint16_t * data):
BitmapBufferBase<uint16_t>(format, width, height, data),
dataAllocated(false)
#if defined(DEBUG)
, leakReported(false)
#endif
{
}
~BitmapBuffer()
{
if (dataAllocated) {
free(data);
}
}
inline void setFormat(uint8_t format)
{
this->format = format;
}
inline void clear(LcdFlags flags=0)
{
drawSolidFilledRect(0, 0, width - offsetX, height - offsetY, flags);
}
inline void drawPixel(pixel_t * p, pixel_t value)
{
if (data && (data <= p || p < data_end)) {
*p = value;
}
#if defined(DEBUG)
else if (!leakReported) {
leakReported = true;
TRACE("BitmapBuffer(%p).drawPixel(): buffer overrun, data: %p, written at: %p", this, data, p);
}
#endif
}
inline const pixel_t * getPixelPtr(coord_t x, coord_t y) const
{
#if defined(PCBX10) && !defined(SIMU)
x = width - x - 1;
y = height - y - 1;
#endif
return &data[y*width + x];
}
inline pixel_t * getPixelPtr(coord_t x, coord_t y)
{
#if defined(PCBX10) && !defined(SIMU)
x = width - x - 1;
y = height - y - 1;
#endif
return &data[y*width + x];
}
inline void drawPixel(coord_t x, coord_t y, pixel_t value)
{
pixel_t * p = getPixelPtr(x, y);
drawPixel(p, value);
}
void drawAlphaPixel(pixel_t * p, uint8_t opacity, uint16_t color);
inline void drawAlphaPixel(coord_t x, coord_t y, uint8_t opacity, uint16_t color)
{
pixel_t * p = getPixelPtr(x, y);
drawAlphaPixel(p, opacity, color);
}
void drawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat = SOLID, LcdFlags flags = 0);
void drawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat = SOLID, LcdFlags flags = 0);
inline void drawSolidHorizontalLine(coord_t x, coord_t y, coord_t w, LcdFlags flags)
{
drawSolidFilledRect(x, y, w, 1, flags);
}
inline void drawSolidVerticalLine(coord_t x, coord_t y, coord_t h, LcdFlags flags)
{
drawSolidFilledRect(x, y, 1, h, flags);
}
void drawRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t thickness = 1, uint8_t pat = SOLID, LcdFlags flags = 0);
inline void drawSolidRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t thickness = 1, LcdFlags flags = 0)
{
drawSolidFilledRect(x, y, thickness, h, flags);
drawSolidFilledRect(x+w-thickness, y, thickness, h, flags);
drawSolidFilledRect(x, y, w, thickness, flags);
drawSolidFilledRect(x, y+h-thickness, w, thickness, flags);
}
void drawSolidFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags = 0);
void drawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat = SOLID, LcdFlags flags = 0);
void invertRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags = 0);
void drawCircle(int x0, int y0, int radius);
void drawPie(int x0, int y0, int radius, int startAngle, int endAngle);
void drawBitmapPie(int x0, int y0, const uint16_t * img, int startAngle, int endAngle);
void drawBitmapPatternPie(coord_t x0, coord_t y0, const uint8_t * img, LcdFlags flags, int startAngle, int endAngle);
static BitmapBuffer * load(const char * filename);
static BitmapBuffer * loadMask(const char * filename);
static BitmapBuffer * loadMaskOnBackground(const char * filename, LcdFlags foreground, LcdFlags background);
void drawMask(coord_t x, coord_t y, const BitmapBuffer * mask, LcdFlags flags, coord_t offset=0, coord_t width=0);
void drawBitmapPattern(coord_t x, coord_t y, const uint8_t * bmp, LcdFlags flags, coord_t offset=0, coord_t width=0);
coord_t drawSizedText(coord_t x, coord_t y, const char * s, uint8_t len, LcdFlags flags=0);
void drawText(coord_t x, coord_t y, const char * s, LcdFlags flags = 0)
{
drawSizedText(x, y, s, 255, flags);
}
void drawTextAtIndex(coord_t x, coord_t y, const char * s, uint8_t idx, LcdFlags flags = 0)
{
char length = *s++;
drawSizedText(x, y, s+length*idx, length, flags);
}
void drawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags = 0, uint8_t len = 0, const char * prefix = nullptr, const char * suffix = nullptr);
template<class T>
void drawBitmap(coord_t x, coord_t y, const T * bmp, coord_t srcx=0, coord_t srcy=0, coord_t w=0, coord_t h=0, float scale=0)
{
APPLY_OFFSET();
if (x >= xmax) return;
if (y >= ymax) return;
if (!data || !bmp)
return;
coord_t srcw = bmp->getWidth();
coord_t srch = bmp->getHeight();
if (w == 0)
w = srcw;
if (h == 0)
h = srch;
if (srcx + w > srcw)
w = srcw - srcx;
if (srcy + h > srch)
h = srch - srcy;
if (x < xmin) {
w += x-xmin;
srcx -= x-xmin;
x = xmin;
}
if (y < ymin) {
h += y-ymin;
srcy -= y-ymin;
y = ymin;
}
if (x + w > xmax) {
w = xmax - x;
}
if (y + h > ymax) {
h = ymax - y;
}
if (w <= 0 || h <= 0)
return;
// TRACE("x=%d xmin=%d xmax=%d w=%d", x, xmin, xmax, w);
if (scale == 0) {
/*if (x + w > width) {
w = width - x;
}
if (y + h > height) {
h = height - y;
}*/
if (bmp->getFormat() == BMP_ARGB4444) {
DMACopyAlphaBitmap(data, width, height, x, y, bmp->getData(), srcw, srch, srcx, srcy, w, h);
}
else {
DMACopyBitmap(data, width, height, x, y, bmp->getData(), srcw, srch, srcx, srcy, w, h);
}
}
else {
int scaledw = w * scale;
int scaledh = h * scale;
if (x + scaledw > width)
scaledw = width - x;
if (y + scaledh > height)
scaledh = height - y;
for (int i = 0; i < scaledh; i++) {
pixel_t * p = getPixelPtr(x, y + i);
const pixel_t * qstart = bmp->getPixelPtr(srcx, srcy + int(i / scale));
for (int j = 0; j < scaledw; j++) {
const pixel_t * q = qstart;
MOVE_PIXEL_RIGHT(q, int(j / scale));
if (bmp->getFormat() == BMP_ARGB4444) {
ARGB_SPLIT(*q, a, r, g, b);
drawAlphaPixel(p, a, RGB_JOIN(r<<1, g<<2, b<<1));
}
else {
drawPixel(p, *q);
}
MOVE_TO_NEXT_RIGHT_PIXEL(p);
}
}
}
}
template<class T>
void drawScaledBitmap(const T * bitmap, coord_t x, coord_t y, coord_t w, coord_t h)
{
float vscale = float(h) / bitmap->getHeight();
float hscale = float(w) / bitmap->getWidth();
float scale = vscale < hscale ? vscale : hscale;
int xshift = (w - (bitmap->getWidth() * scale)) / 2;
int yshift = (h - (bitmap->getHeight() * scale)) / 2;
drawBitmap(x + xshift, y + yshift, bitmap, 0, 0, 0, 0, scale);
}
protected:
static BitmapBuffer * load_bmp(const char * filename);
static BitmapBuffer * load_stb(const char * filename);
uint8_t drawChar(coord_t x, coord_t y, const uint8_t * font, const uint16_t * spec, unsigned int index, LcdFlags flags);
};
extern BitmapBuffer * lcd;
#endif // _BITMAP_BUFFER_H_
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "libopenui_config.h"
#include "button.h"
#include "font.h"
#include "theme.h"
void Button::onPress()
{
bool check = (pressHandler && pressHandler());
if (check != bool(flags & BUTTON_CHECKED)) {
flags ^= BUTTON_CHECKED;
invalidate();
}
}
#if defined(HARDWARE_KEYS)
void Button::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
onPress();
}
else {
FormField::onKeyEvent(event);
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool Button::onTouchEnd(coord_t x, coord_t y)
{
if (enabled()) {
onPress();
if (!(flags & BUTTON_NOFOCUS)) {
setFocus();
}
}
return true;
}
#endif
void Button::checkEvents()
{
Window::checkEvents();
if (checkHandler)
checkHandler();
}
void TextButton::paint(BitmapBuffer * dc)
{
FormField::paint(dc);
LcdFlags textColor = TEXT_COLOR;
if (checked()) {
if (hasFocus()) {
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, TEXT_INVERTED_BGCOLOR);
dc->drawSolidFilledRect(3, 3, rect.w - 6, rect.h - 6, TEXT_INVERTED_BGCOLOR);
}
else {
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, CURVE_AXIS_COLOR);
dc->drawSolidFilledRect(2, 2, rect.w - 4, rect.h - 4, TEXT_INVERTED_BGCOLOR);
}
textColor = TEXT_INVERTED_COLOR;
}
else {
if (flags & BUTTON_BACKGROUND) {
if (hasFocus()) {
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, TEXT_INVERTED_BGCOLOR);
dc->drawSolidFilledRect(2, 2, rect.w - 4, rect.h - 4, CURVE_AXIS_COLOR);
}
else {
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, CURVE_AXIS_COLOR);
}
}
else {
if (hasFocus()) {
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, TEXT_INVERTED_BGCOLOR);
}
else {
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, CURVE_AXIS_COLOR);
}
}
}
dc->drawText(rect.w / 2, (rect.h - getFontHeight(flags)) / 2, text.c_str(), CENTERED | textColor);
}
void IconButton::paint(BitmapBuffer * dc)
{
dc->drawBitmap(0, 0, theme->getIcon(icon, checked() ? STATE_PRESSED : STATE_DEFAULT));
}
const uint8_t __alpha_button_on[] {
#include "alpha_button_on.lbm"
};
Bitmap ALPHA_BUTTON_ON(BMP_ARGB4444, (const uint16_t*)__alpha_button_on);
const uint8_t __alpha_button_off[] {
#include "alpha_button_off.lbm"
};
Bitmap ALPHA_BUTTON_OFF(BMP_ARGB4444, (const uint16_t*)__alpha_button_off);
FabIconButton::FabIconButton(Window * parent, coord_t x, coord_t y, uint8_t icon, std::function<uint8_t(void)> pressHandler, uint8_t flags):
Button(parent, { x - 34, y - 34, 68, 68 }, pressHandler, flags),
icon(icon)
{
}
void FabIconButton::paint(BitmapBuffer * dc)
{
dc->drawBitmap(0, 0, checked() ? &ALPHA_BUTTON_ON : &ALPHA_BUTTON_OFF);
const BitmapBuffer * mask = theme->getIconMask(icon);
if (mask) {
dc->drawMask((68 - mask->getWidth()) / 2, (68 - mask->getHeight()) / 2, mask, TEXT_BGCOLOR);
}
}
+180
View File
@@ -0,0 +1,180 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _BUTTON_H_
#define _BUTTON_H_
#include "form.h"
#include <string>
enum ButtonFlags {
BUTTON_BACKGROUND = 1,
BUTTON_CHECKED = 2,
BUTTON_NOFOCUS = 4,
BUTTON_CHECKED_ON_FOCUS = 8,
BUTTON_DISABLED = 16,
};
class Button : public FormField {
public:
Button(Window * parent, const rect_t & rect, std::function<uint8_t(void)> pressHandler=nullptr, uint8_t flags=0):
FormField(parent, rect),
pressHandler(pressHandler),
flags(flags)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "Button";
}
#endif
void enable(bool enabled=true)
{
if (!enabled != bool(flags & BUTTON_DISABLED)) {
flags ^= BUTTON_DISABLED;
invalidate();
}
}
void disable()
{
enable(false);
}
void check(bool checked=true)
{
if (checked != bool(flags & BUTTON_CHECKED)) {
flags ^= BUTTON_CHECKED;
invalidate();
}
}
bool enabled()
{
return !(flags & BUTTON_DISABLED);
}
bool checked()
{
if (flags & BUTTON_CHECKED_ON_FOCUS)
return hasFocus();
else
return flags & BUTTON_CHECKED;
}
void setPressHandler(std::function<uint8_t(void)> handler)
{
pressHandler = std::move(handler);
}
void setCheckHandler(std::function<void(void)> handler)
{
checkHandler = std::move(handler);
}
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event);
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
void checkEvents() override;
protected:
std::function<uint8_t(void)> pressHandler;
std::function<void(void)> checkHandler;
uint8_t flags;
void onPress();
};
class TextButton : public Button {
public:
TextButton(Window * parent, const rect_t & rect, std::string text, std::function<uint8_t(void)> pressHandler=nullptr, uint8_t flags=BUTTON_BACKGROUND):
Button(parent, rect, pressHandler, flags),
text(std::move(text))
{
windowFlags = OPAQUE;
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "TextButton \"" + text + "\"";
}
#endif
void setText(std::string value)
{
if (value != text) {
text = std::move(value);
invalidate();
}
}
void paint(BitmapBuffer * dc) override;
protected:
std::string text;
};
class IconButton: public Button {
public:
IconButton(Window * parent, const rect_t & rect, uint8_t icon, std::function<uint8_t(void)> pressHandler, uint8_t flags = 0):
Button(parent, rect, pressHandler, flags),
icon(icon)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "IconButton(" + std::to_string(icon) + ")";
}
#endif
void paint(BitmapBuffer * dc) override;
protected:
uint8_t icon;
};
class FabIconButton: public Button {
public:
FabIconButton(Window * parent, coord_t x, coord_t y, uint8_t icon, std::function<uint8_t(void)> pressHandler, uint8_t flags=0);
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "FabIconButton(" + std::to_string(icon) + ")";
}
#endif
void paint(BitmapBuffer * dc) override;
protected:
uint8_t icon;
};
#endif
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "checkbox.h"
#include "theme.h"
void CheckBox::paint(BitmapBuffer * dc)
{
theme->drawCheckBox(dc, getValue(), hasFocus());
}
#if defined(HARDWARE_KEYS)
void CheckBox::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
setValue(!getValue());
invalidate({0, 0, 20, 20});
}
else {
FormField::onKeyEvent(event);
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool CheckBox::onTouchEnd(coord_t x, coord_t y)
{
setValue(!getValue());
setFocus();
invalidate({0, 0, 20, 20});
return true;
}
#endif
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _CHECKBOX_H_
#define _CHECKBOX_H_
#include "form.h"
class CheckBox : public FormField {
public:
CheckBox(Window * parent, const rect_t & rect, std::function<uint8_t()> getValue, std::function<void(uint8_t)> setValue,
LcdFlags flags = 0) :
FormField(parent, rect),
getValue(getValue),
setValue(setValue)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "CheckBox";
}
#endif
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
protected:
const char * label;
std::function<uint8_t()> getValue;
std::function<void(uint8_t)> setValue;
};
#endif // _CHECKBOX_H_
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "choice.h"
#include "menu.h"
const uint8_t LBM_DROPDOWN[] = {
#include "mask_dropdown.lbm"
};
Choice::Choice(Window * parent, const rect_t &rect, const char * values, int16_t vmin, int16_t vmax,
std::function<int16_t()> getValue, std::function<void(int16_t)> setValue, LcdFlags flags) :
FormField(parent, rect),
values(values),
vmin(vmin),
vmax(vmax),
getValue(std::move(getValue)),
setValue(std::move(setValue)),
flags(flags)
{
}
void Choice::paint(BitmapBuffer * dc)
{
FormField::paint(dc);
LcdFlags textColor;
if (editMode)
textColor = TEXT_INVERTED_COLOR;
else if (hasFocus())
textColor = TEXT_INVERTED_BGCOLOR;
else
textColor = 0;
if (textHandler)
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, textHandler(getValue()).c_str(), textColor);
else
dc->drawTextAtIndex(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, values, getValue() - vmin, flags | textColor);
dc->drawBitmapPattern(rect.w - 14, (rect.h - 5) / 2, LBM_DROPDOWN, textColor);
}
#if defined(HARDWARE_KEYS)
void Choice::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
editMode = true;
invalidate();
openMenu();
}
else {
FormField::onKeyEvent(event);
}
}
#endif
void Choice::openMenu()
{
auto menu = new Menu();
auto value = getValue();
int count = 0;
int current = -1;
for (int i = vmin; i <= vmax; ++i) {
if (isValueAvailable && !isValueAvailable(i))
continue;
if (textHandler) {
menu->addLine(textHandler(i), [=]() {
setValue(i);
});
}
else {
menu->addLine(TEXT_AT_INDEX(values, i - vmin), [=]() {
setValue(i);
});
}
if (value == i) {
current = count;
}
++count;
}
if (current >= 0) {
menu->select(current);
}
menu->setCloseHandler([=]() {
editMode = false;
setFocus();
});
}
#if defined(HARDWARE_TOUCH)
bool Choice::onTouchEnd(coord_t, coord_t)
{
openMenu();
setFocus();
return true;
}
#endif
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _CHOICE_H_
#define _CHOICE_H_
#include <string>
#include "form.h"
class Choice : public FormField {
public:
Choice(Window * parent, const rect_t & rect, const char * values, int16_t vmin, int16_t vmax, std::function<int16_t()> getValue, std::function<void(int16_t)> setValue = nullptr, LcdFlags flags = 0);
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "Choice";
}
#endif
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
void setSetValueHandler(std::function<void(int16_t)> handler)
{
setValue = std::move(handler);
}
void setAvailableHandler(std::function<bool(int)> handler)
{
isValueAvailable = std::move(handler);
}
void setTextHandler(std::function<std::string(int32_t)> handler)
{
textHandler = std::move(handler);
}
protected:
const char * values;
int16_t vmin;
int16_t vmax;
std::function<int16_t()> getValue;
std::function<void(int16_t)> setValue;
std::function<bool(int)> isValueAvailable;
std::function<std::string(int32_t)> textHandler;
LcdFlags flags;
void openMenu();
};
#endif // _CHOICE_H_
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "coloredit.h"
#include "numberedit.h"
#include "bitfield.h"
constexpr uint8_t PART_BITS[3][2] = { {0, 5}, {5, 6}, {11, 5} };
class ColorBox: public Window {
public:
ColorBox(Window * parent, const rect_t & rect, LcdFlags color):
Window(parent, rect),
color(color)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "ColorBox";
}
#endif
void paint(BitmapBuffer * dc) override
{
lcdSetColor(color);
dc->drawSolidFilledRect(0, 0, width(), height(), TEXT_COLOR);
dc->drawSolidFilledRect(1, 1, width() - 2, height() - 2, CUSTOM_COLOR);
}
void setColor(LcdFlags value)
{
color = value;
invalidate();
}
protected:
LcdFlags color;
};
ColorEdit::ColorEdit(Window * parent, const rect_t & rect, std::function<uint16_t()> getValue, std::function<void(uint16_t)> setValue):
Window(parent, rect, FORWARD_SCROLL)
{
auto width = rect.w / 4 - 5;
// The color box
auto box = new ColorBox(this, {0, 0, rect.w - 3 * width, rect.h}, getValue());
// The 3 parts of RGB
for (uint8_t part = 0; part < 3; part++) {
new NumberEdit(this, {rect.w - (3 - part) * width + 5, 0, width - 5, rect.h}, 0, (1 << PART_BITS[part][1]) - 1,
[=]() {
return bfGet(getValue(), PART_BITS[part][0], PART_BITS[part][1]);
},
[=](uint16_t newValue) {
uint16_t value = getValue();
value = bfSet(value, newValue, PART_BITS[part][0], PART_BITS[part][1]);
setValue(value);
box->setColor(value);
});
}
}
ColorEdit::~ColorEdit()
{
deleteChildren();
}
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _COLOREDIT_H_
#define _COLOREDIT_H_
#include "window.h"
class ColorEdit : public Window {
public:
ColorEdit(Window * parent, const rect_t & rect, std::function<uint16_t()> getValue, std::function<void(uint16_t)> setValue = nullptr);
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "ColorEdit";
}
#endif
~ColorEdit() override;
};
#endif // _COLOREDIT_H_
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "dialog.h"
#include "mainwindow.h"
#include "form.h"
Dialog::Dialog(std::string title, const rect_t rect):
Window(&mainWindow, rect, OPAQUE),
title(std::move(title)),
previousFocus(focusWindow)
{
bringToTop();
FormField::clearCurrentField();
setFocus();
}
void Dialog::paint(BitmapBuffer * dc)
{
dc->drawRect(0, 0, width() - 1, height() - 1, 1, SOLID, TEXT_COLOR);
dc->drawSolidFilledRect(1, 1, width() - 3, PAGE_LINE_HEIGHT, TITLE_BGCOLOR);
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, title.c_str(), MENU_TITLE_COLOR);
dc->drawSolidFilledRect(1, PAGE_LINE_HEIGHT + 1, width() - 3, height() - PAGE_LINE_HEIGHT - 3, TEXT_BGCOLOR_INDEX);
}
void Dialog::deleteLater()
{
if (previousFocus) {
previousFocus->setFocus();
}
Window::deleteLater();
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _DIALOG_H_
#define _DIALOG_H_
#include "window.h"
class Dialog: public Window {
public:
Dialog(std::string title, const rect_t rect);
void paint(BitmapBuffer * dc) override;
void deleteLater();
protected:
std::string title;
Window * previousFocus;
};
#endif // _CONFIRMATION_H_
+158
View File
@@ -0,0 +1,158 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "filechoice.h"
#include "libopenui_file.h"
#include "menu.h"
const uint8_t LBM_FOLDER[] = {
#include "mask_folder.lbm"
};
// comparison, not case sensitive.
bool compare_nocase(const std::string &first, const std::string &second)
{
return strcasecmp(first.c_str(), second.c_str()) < 0;
}
FileChoice::FileChoice(Window * parent, const rect_t & rect, std::string folder, const char * extension, int maxlen, std::function<std::string()> getValue, std::function<void(std::string)> setValue):
FormField(parent, rect),
folder(std::move(folder)),
extension(extension),
maxlen(maxlen),
getValue(std::move(getValue)),
setValue(std::move(setValue))
{
}
void FileChoice::paint(BitmapBuffer * dc)
{
FormField::paint(dc);
const char * displayedValue = getValue().c_str();
LcdFlags textColor;
if (editMode)
textColor = TEXT_INVERTED_COLOR;
else if (hasFocus())
textColor = TEXT_INVERTED_BGCOLOR;
else if (displayedValue[0] == '\0')
textColor = CURVE_AXIS_COLOR;
else
textColor = TEXT_COLOR;
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, displayedValue[0] == '\0' ? "---" : displayedValue, textColor);
dc->drawBitmapPattern(rect.w - 20, (rect.h - 11) / 2, LBM_FOLDER, textColor);
}
void FileChoice::openMenu()
{
FILINFO fno;
DIR dir;
std::list<std::string> files;
const char * fnExt;
uint8_t fnLen, extLen;
FRESULT res = f_opendir(&dir, folder.c_str()); // Open the directory
if (res == FR_OK) {
bool firstTime = true;
for (;;) {
res = sdReadDir(&dir, &fno, firstTime);
if (res != FR_OK || fno.fname[0] == 0)
break; // break on error or end of dir
if (fno.fattrib & AM_DIR)
continue; // skip subfolders
if (fno.fattrib & AM_HID)
continue; // skip hidden files
if (fno.fattrib & AM_SYS)
continue; // skip system files
fnExt = getFileExtension(fno.fname, 0, 0, &fnLen, &extLen);
fnLen -= extLen;
if (!fnLen || fnLen > maxlen)
continue; // wrong size
if (extension && !isExtensionMatching(fnExt, extension))
continue; // wrong extension
files.emplace_back(fno.fname, fnLen);
}
if (files.size() > 0) {
// sort files
files.sort(compare_nocase);
files.push_front("");
auto menu = new Menu();
int count = 0;
int current = -1;
std::string value = getValue();
for (const auto &file: files) {
menu->addLine(file, [=]() {
setValue(file);
});
// TRACE("%s %d %s %d", value.c_str(), value.size(), file.c_str(), file.size());
if (value.compare(file) == 0) {
// TRACE("OK");
current = count;
}
++count;
}
if (current >= 0) {
menu->select(current);
}
menu->setCloseHandler([=]() {
editMode = false;
setFocus();
});
}
else {
TRACE("NO FILES !!!!!");
// TODO popup "NO FILES"
}
}
}
#if defined(HARDWARE_KEYS)
void FileChoice::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
editMode = true;
invalidate();
openMenu();
}
else {
FormField::onKeyEvent(event);
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool FileChoice::onTouchEnd(coord_t, coord_t)
{
openMenu();
setFocus();
return true;
}
#endif
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _FILECHOICE_H_
#define _FILECHOICE_H_
#include "form.h"
#include <string>
class FileChoice: public FormField {
public:
FileChoice(Window * parent, const rect_t & rect, std::string folder, const char * extension, int maxlen, std::function<std::string()> getValue, std::function<void(std::string)> setValue);
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "FileChoice";
}
#endif
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
protected:
std::string folder;
const char * extension;
int maxlen;
std::function<std::string()> getValue;
std::function<void(std::string)> setValue;
void openMenu();
};
#endif // _FILECHOICE_H_
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _FONT_H_
#define _FONT_H_
#include "libopenui_types.h"
uint8_t getMappedChar(uint8_t c);
uint8_t getFontHeight(LcdFlags flags);
int getCharWidth(uint8_t c, const uint16_t * spec);
int getTextWidth(const char * s, int len = 0, LcdFlags flags = 0);
#endif // _FONT_H_
+120
View File
@@ -0,0 +1,120 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "form.h"
#include "bitmapbuffer.h"
#include "libopenui_config.h"
FormField * FormField::current = nullptr;
FormField::FormField(Window *parent, const rect_t &rect, uint8_t flags) :
Window(parent, rect, flags)
{
if (current) {
setPreviousField(current);
current->setNextField(this);
}
FormWindow * form = dynamic_cast<FormWindow *>(parent);
if (form && !form->getFirstField())
form->setFirstField(this);
current = this;
}
#if defined(HARDWARE_KEYS)
void FormWindow::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_BREAK(KEY_EXIT) && first && getFocus() != first) {
first->setFocus();
}
else {
Window::onKeyEvent(event);
}
}
void FormField::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", FormField::getWindowDebugString().c_str(), event);
if (event == EVT_ROTARY_RIGHT/*EVT_KEY_BREAK(KEY_DOWN)*/) {
if (next) {
next->setFocus();
}
}
else if (event == EVT_ROTARY_LEFT/*EVT_KEY_BREAK(KEY_UP)*/) {
if (previous) {
previous->setFocus();
}
}
else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
editMode = !editMode;
invalidate();
}
else if (event == EVT_KEY_BREAK(KEY_EXIT) && editMode) {
editMode = false;
invalidate();
}
else {
Window::onKeyEvent(event);
}
}
void FormGroup::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
editMode = true;
first->setFocus();
}
else if (event == EVT_KEY_BREAK(KEY_EXIT) && editMode) {
editMode = false;
setFocus();
}
else {
FormField::onKeyEvent(event);
}
}
#endif
void FormField::paint(BitmapBuffer * dc)
{
if (editMode) {
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, TEXT_INVERTED_BGCOLOR);
}
else if (hasFocus()) {
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, TEXT_INVERTED_BGCOLOR);
}
else if (!(windowFlags & BORDER_FOCUS_ONLY)) {
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, CURVE_AXIS_COLOR);
}
}
void FormGroup::paint(BitmapBuffer * dc)
{
if (!editMode && hasFocus()) {
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, TEXT_INVERTED_BGCOLOR);
}
else if (!(windowFlags & BORDER_FOCUS_ONLY)) {
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, CURVE_AXIS_COLOR);
}
}
+197
View File
@@ -0,0 +1,197 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _FORM_H_
#define _FORM_H_
#include "window.h"
class FormField: public Window {
friend class FormWindow;
public:
FormField(Window * parent, const rect_t & rect, uint8_t flags=0);
inline void setNextField(FormField *field)
{
next = field;
}
inline void setPreviousField(FormField * field)
{
previous = field;
}
inline static void setCurrentField(FormField * field)
{
current = field;
}
inline static void clearCurrentField()
{
setCurrentField(nullptr);
};
inline static FormField * getCurrentField()
{
return current;
};
inline FormField * getPreviousField()
{
return previous;
};
inline FormField * getNextField()
{
return next;
};
inline static void link(FormField * previous, FormField * next)
{
previous->setNextField(next);
next->setPreviousField(previous);
}
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
protected:
static FormField * current;
FormField * next = nullptr;
FormField * previous = nullptr;
bool editMode = false;
};
class FormGroup: public FormField {
public:
FormGroup(Window * parent, const rect_t & rect, uint8_t flags=0) :
FormField(parent, rect, flags)
{
FormField::current = nullptr;
}
~FormGroup()
{
deleteChildren();
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "FormGroup";
}
#endif
void clear()
{
Window::clear();
first = nullptr;
FormField::current = nullptr;
}
inline void setFirstField(FormField * field)
{
first = field;
}
inline void setLastField(FormField * field = nullptr)
{
// by default the current field is the last one
if (!field)
field = getCurrentField();
FormField::link(field, first);
// now the current field is the group, it will be linked to the next one
FormField::setCurrentField(this);
}
FormField * getFirstField()
{
return first;
}
protected:
FormField * first = nullptr;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
void paint(BitmapBuffer * dc) override;
};
class FormWindow: public Window {
public:
FormWindow(Window * parent, const rect_t & rect) :
Window(parent, rect)
{
FormField::current = nullptr;
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "FormWindow";
}
#endif
void clear()
{
first = nullptr;
Window::clear();
}
FormField * getFirstField()
{
return first;
}
inline void setFirstField(FormField * field)
{
first = field;
field->setFocus();
}
inline void setLastField(FormField * field = nullptr)
{
if (!field)
field = FormField::getCurrentField();
FormField::link(field, first);
}
protected:
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
void paint(BitmapBuffer * dc) override
{
}
protected:
FormField * first = nullptr;
};
#endif
+123
View File
@@ -0,0 +1,123 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _GRIDLAYOUT_H_
#define _GRIDLAYOUT_H_
#include "window.h"
class GridLayout {
public:
GridLayout(coord_t width):
width(width)
{
}
GridLayout(Window * window):
width(window->width())
{
}
rect_t getSlot(uint8_t count = 1, uint8_t index = 0) const
{
coord_t width = (this->width - (count - 1) * PAGE_LINE_SPACING) / count;
coord_t left = (width + PAGE_LINE_SPACING) * index;
return {left, currentY, width, PAGE_LINE_HEIGHT};
}
void spacer(coord_t height=PAGE_LINE_SPACING)
{
currentY += height;
}
void nextLine(coord_t height=PAGE_LINE_HEIGHT)
{
spacer(height + PAGE_LINE_SPACING);
}
void addWindow(Window * window)
{
window->adjustHeight();
currentY += window->rect.h + PAGE_LINE_SPACING;
}
coord_t getWindowHeight() const
{
return currentY;
}
protected:
coord_t width;
coord_t currentY = 0;
};
class FormGridLayout: public GridLayout {
public:
FormGridLayout(coord_t width = LCD_W):
GridLayout(width)
{
}
void setLabelWidth(coord_t value)
{
labelWidth = value;
}
void setMarginLeft(coord_t value)
{
lineMarginLeft = value;
}
void setMarginRight(coord_t value)
{
lineMarginRight = value;
}
rect_t getLineSlot()
{
return { lineMarginLeft, currentY, this->width - lineMarginRight - lineMarginLeft, PAGE_LINE_HEIGHT };
}
rect_t getCenteredSlot(coord_t width = 0 ) const
{
if (width == 0)
width = this->width;
return { lineMarginLeft + (this->width - width)/2, currentY, min(width, this->width - lineMarginRight - lineMarginLeft), PAGE_LINE_HEIGHT };
}
rect_t getLabelSlot(bool indent = false) const
{
coord_t left = indent ? lineMarginLeft + PAGE_INDENT_WIDTH : lineMarginLeft;
return { left, currentY, labelWidth - left, PAGE_LINE_HEIGHT };
}
rect_t getFieldSlot(uint8_t count = 1, uint8_t index = 0) const
{
coord_t width = (this->width - labelWidth - lineMarginRight - (count - 1) * PAGE_LINE_SPACING) / count;
coord_t left = labelWidth + (width + PAGE_LINE_SPACING) * index;
return {left, currentY, width, PAGE_LINE_HEIGHT};
}
protected:
coord_t labelWidth = PAGE_LABEL_WIDTH;
coord_t lineMarginLeft = PAGE_PADDING;
coord_t lineMarginRight = 10;
};
#endif
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _KEYBOARD_BASE_H_
#define _KEYBOARD_BASE_H_
#include "mainwindow.h"
#include "libopenui_types.h"
class Page;
class TabsGroup;
template <class T>
class Keyboard: public Window {
public:
explicit Keyboard(coord_t height):
Window(nullptr, {0, LCD_H - height, LCD_W, height}, OPAQUE)
{
}
void setField(T * newField)
{
field = newField;
attach(&mainWindow);
Window * w = getPageBody();
w->setHeight(LCD_H - height() - w->top());
w->scrollTo(newField);
invalidate();
}
void disable(bool resizePage)
{
detach();
if (field) {
Window * w = getPageBody();
w->setHeight(LCD_H - 0 - w->top());
field = nullptr;
}
}
T * getField() const
{
return field;
}
protected:
T * field = nullptr;
Window * getPageBody()
{
Window * parent = field;
while (true) {
Window * tmp = parent->getParent();
if ((tmp->getWindowFlags() & OPAQUE) && tmp->width() == LCD_W && tmp->height() == LCD_H) {
return parent;
}
parent = tmp;
}
}
};
#endif // _KEYBOARD_BASE_H_
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "keyboard_number.h"
#include "button.h"
#include "basenumberedit.h"
constexpr coord_t KEYBOARD_HEIGHT = 90;
NumberKeyboard * NumberKeyboard::_instance = nullptr;
NumberKeyboard::NumberKeyboard():
Keyboard<BaseNumberEdit>(KEYBOARD_HEIGHT)
{
new TextButton(this, { LCD_W/2 - 115, 10, 50, 30 }, "<<",
[=]() -> uint8_t {
if (field) {
field->setValue(field->getValue() - 10 * field->getStep());
}
return 0;
}, BUTTON_BACKGROUND | BUTTON_NOFOCUS);
new TextButton(this, { LCD_W/2 - 55, 10, 50, 30 }, "-",
[=]() -> uint8_t {
if (field) {
field->setValue(field->getValue() - field->getStep());
}
return 0;
}, BUTTON_BACKGROUND | BUTTON_NOFOCUS);
new TextButton(this, { LCD_W/2 + 5, 10, 50, 30 }, "+",
[=]() -> uint8_t {
if (field) {
field->setValue(field->getValue() + field->getStep());
}
return 0;
}, BUTTON_BACKGROUND | BUTTON_NOFOCUS);
new TextButton(this, { LCD_W/2 + 65, 10, 50, 30 }, ">>",
[=]() -> uint8_t {
if (field) {
field->setValue(field->getValue() + 10 * field->getStep());
}
return 0;
}, BUTTON_BACKGROUND | BUTTON_NOFOCUS);
new TextButton(this, { LCD_W/2 - 115, 50, 50, 30 }, "MIN",
[=]() -> uint8_t {
if (field) {
field->setValue(field->getMin());
}
return 0;
}, BUTTON_BACKGROUND | BUTTON_NOFOCUS);
new TextButton(this, { LCD_W/2 + 65, 50, 50, 30 }, "MAX",
[=]() -> uint8_t {
if (field) {
field->setValue(field->getMax());
}
return 0;
}, BUTTON_BACKGROUND | BUTTON_NOFOCUS);
new TextButton(this, { LCD_W/2 - 55, 50, 110, 30 }, "DEFAULT",
[=]() -> uint8_t {
if (field) {
field->setValue(field->getDefault());
}
return 0;
}, BUTTON_BACKGROUND | BUTTON_NOFOCUS);
}
NumberKeyboard::~NumberKeyboard()
{
_instance = nullptr;
}
void NumberKeyboard::paint(BitmapBuffer * dc)
{
lcdSetColor(RGB(0xE0, 0xE0, 0xE0));
dc->clear(CUSTOM_COLOR);
}
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _KEYBOARD_NUMBER_H_
#define _KEYBOARD_NUMBER_H_
#include "keyboard_base.h"
#include "basenumberedit.h"
class NumberKeyboard : public Keyboard<BaseNumberEdit> {
friend class BaseNumberEdit;
public:
NumberKeyboard();
~NumberKeyboard() override;
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "NumberKeyboard";
}
#endif
static NumberKeyboard * instance()
{
if (!_instance)
_instance = new NumberKeyboard();
return _instance;
}
void paint(BitmapBuffer * dc) override;
protected:
static NumberKeyboard * _instance;
};
#endif // _KEYBOARD_NUMBER_H_
+228
View File
@@ -0,0 +1,228 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "keyboard_text.h"
#include "libopenui_globals.h"
#include "textedit.h"
#include "font.h"
constexpr coord_t KEYBOARD_HEIGHT = 160;
TextKeyboard * TextKeyboard::_instance = nullptr;
const uint8_t LBM_KEY_UPPERCASE[] = {
#include "mask_key_uppercase.lbm"
};
const uint8_t LBM_KEY_LOWERCASE[] = {
#include "mask_key_lowercase.lbm"
};
const uint8_t LBM_KEY_BACKSPACE[] = {
#include "mask_key_backspace.lbm"
};
const uint8_t LBM_KEY_LETTERS[] = {
#include "mask_key_letters.lbm"
};
const uint8_t LBM_KEY_NUMBERS[] = {
#include "mask_key_numbers.lbm"
};
const uint8_t LBM_KEY_SPACEBAR[] = {
#include "mask_key_spacebar.lbm"
};
const uint8_t * const LBM_SPECIAL_KEYS[] = {
LBM_KEY_BACKSPACE,
LBM_KEY_UPPERCASE,
LBM_KEY_LOWERCASE,
LBM_KEY_LETTERS,
LBM_KEY_NUMBERS,
};
const char * const KEYBOARD_LOWERCASE[] = {
"qwertyuiop",
" asdfghjkl",
"\201zxcvbnm\200",
"\204\t\n"
};
const char * const KEYBOARD_UPPERCASE[] = {
"QWERTYUIOP",
" ASDFGHJKL",
"\202ZXCVBNM\200",
"\204\t\n"
};
const char * const KEYBOARD_NUMBERS[] = {
"1234567890",
"_-",
" \200",
"\203\t\n"
};
const char * const * const KEYBOARD_LAYOUTS[] = {
KEYBOARD_UPPERCASE,
KEYBOARD_LOWERCASE,
KEYBOARD_LOWERCASE,
KEYBOARD_NUMBERS,
};
TextKeyboard::TextKeyboard():
Keyboard<TextEdit>(KEYBOARD_HEIGHT),
layout(KEYBOARD_LOWERCASE)
{
}
TextKeyboard::~TextKeyboard()
{
_instance = nullptr;
}
void TextKeyboard::setCursorPos(coord_t x)
{
if (!field)
return;
uint8_t size = field->getMaxLength();
char * data = field->getData();
coord_t rest = x;
for (cursorIndex = 0; cursorIndex < size; cursorIndex++) {
if (data[cursorIndex] == '\0')
break;
char c = data[cursorIndex];
uint8_t w = getCharWidth(c, fontspecsTable[0]);
if (rest < w)
break;
rest -= w;
}
cursorPos = x - rest;
field->invalidate();
}
void TextKeyboard::paint(BitmapBuffer * dc)
{
lcdSetColor(RGB(0xE0, 0xE0, 0xE0));
dc->clear(CUSTOM_COLOR);
for (uint8_t i=0; i<4; i++) {
coord_t y = 15 + i * 40;
coord_t x = 15;
const char * c = layout[i];
while(*c) {
if (*c == ' ') {
x += 15;
}
else if (*c == '\t') {
// spacebar
dc->drawBitmapPattern(x, y, LBM_KEY_SPACEBAR, TEXT_COLOR);
x += 135;
}
else if (*c == '\n') {
// enter
dc->drawSolidFilledRect(x, y-2, 80, 25, TEXT_DISABLE_COLOR);
dc->drawText(x+40, y, "ENTER", CENTERED);
x += 80;
}
else if (int8_t(*c) < 0) {
dc->drawBitmapPattern(x, y, LBM_SPECIAL_KEYS[uint8_t(*c - 128)], TEXT_COLOR);
x += 45;
}
else {
dc->drawSizedText(x, y, c, 1);
x += 30;
}
c++;
}
}
}
bool TextKeyboard::onTouchEnd(coord_t x, coord_t y)
{
if (!field)
return false;
uint8_t size = field->getMaxLength();
char * data = field->getData();
char c = 0;
uint8_t row = max<coord_t>(0, y - 5) / 40;
const char * key = layout[row];
while(*key) {
if (*key == ' ') {
x -= 15;
}
else if (*key == '\t') {
if (x <= 135) {
c = ' ';
break;
}
x -= 135;
}
else if (*key == '\n') {
if (x <= 80) {
// enter
disable(true);
return true;
}
x -= 80;
}
else if (int8_t(*key) < 0) {
if (x <= 45) {
uint8_t specialKey = *key;
if (specialKey == 128) {
// backspace
if (cursorIndex > 0) {
char c = data[cursorIndex - 1];
memmove(data + cursorIndex - 1, data + cursorIndex, size - cursorIndex);
data[size - 1] = '\0';
cursorPos -= getCharWidth(c, fontspecsTable[0]);
--cursorIndex;
}
}
else {
layout = KEYBOARD_LAYOUTS[specialKey - 129];
invalidate();
}
break;
}
x -= 45;
}
else {
if (x <= 30) {
c = *key;
break;
}
x -= 30;
}
key++;
}
if (c && size - cursorIndex > 1) {
memmove(data + cursorIndex + 1, data + cursorIndex, size - cursorIndex - 1);
data[cursorIndex++] = c;
cursorPos += getCharWidth(c, fontspecsTable[0]);
}
field->invalidate();
return true;
}
+67
View File
@@ -0,0 +1,67 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _KEYBOARD_TEXT_H_
#define _KEYBOARD_TEXT_H_
#include "keyboard_base.h"
#include "textedit.h"
class TextKeyboard : public Keyboard<TextEdit> {
friend class TextEdit;
public:
TextKeyboard();
~TextKeyboard() override;
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "TextKeyboard";
}
#endif
static TextKeyboard * instance() {
if (!_instance)
_instance = new TextKeyboard();
return _instance;
}
coord_t getCursorPos() const
{
return cursorPos;
}
void setCursorPos(coord_t x);
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
protected:
static TextKeyboard * _instance;
coord_t cursorPos = 0;
uint8_t cursorIndex = 0;
const char * const * layout;
};
#endif // _KEYBOARD_TEXT_H_
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _LIBOPEUI_DEFINES_H_
#define _LIBOPEUI_DEFINES_H_
#include "libopenui_types.h"
/* lcd common flags */
#define BLINK 0x01
/* drawText flags */
#define INVERS 0x02
#define LEFT 0x00 /* align left */
#define CENTERED 0x04 /* align center */
#define RIGHT 0x08 /* align right */
#define SHADOWED 0x80 /* black copy at +1 +1 */
/* drawNumber flags */
#define LEADING0 0x10
#define PREC1 0x20
#define PREC2 0x30
#define MODE(flags) ((((int8_t)(flags) & 0x30) - 0x10) >> 4)
/* rect, square flags */
#define ROUND 0x04
/* telemetry flags */
#define NO_UNIT 0x40
enum FontSizeIndex
{
STDSIZE_INDEX,
TINSIZE_INDEX,
SMLSIZE_INDEX,
MIDSIZE_INDEX,
DBLSIZE_INDEX,
XXLSIZE_INDEX,
SPARE6_INDEX,
SPARE7_INDEX,
STDSIZE_BOLD_INDEX,
SPARE9_INDEX,
SPAREa_INDEX,
SPAREb_INDEX,
SPAREc_INDEX,
SPAREd_INDEX,
SPAREe_INDEX,
SPAREf_INDEX,
};
#define STDSIZE (STDSIZE_INDEX << 8)
#define TINSIZE (TINSIZE_INDEX << 8)
#define SMLSIZE (SMLSIZE_INDEX << 8)
#define MIDSIZE (MIDSIZE_INDEX << 8)
#define DBLSIZE (DBLSIZE_INDEX << 8)
#define XXLSIZE (XXLSIZE_INDEX << 8)
#define BOLD (STDSIZE_BOLD_INDEX << 8)
#define FONTSIZE_MASK 0x0f00
#if !defined(BOOT)
#define FONTSIZE(flags) ((flags) & FONTSIZE_MASK)
#define FONTINDEX(flags) (FONTSIZE(flags) >> 8)
#else
#define FONTSIZE(flags) STDSIZE
#define FONTINDEX(flags) STDSIZE_INDEX
#endif
#define TIMEBLINK 0x1000
#define TIMEHOUR 0x2000
#define EXPANDED 0x2000
#define VERTICAL 0x4000
#define ARGB_SPLIT(color, a, r, g, b) \
uint16_t a = ((color) & 0xF000) >> 12; \
uint16_t r = ((color) & 0x0F00) >> 8; \
uint16_t g = ((color) & 0x00F0) >> 4; \
uint16_t b = ((color) & 0x000F)
#define RGB_SPLIT(color, r, g, b) \
uint16_t r = ((color) & 0xF800) >> 11; \
uint16_t g = ((color) & 0x07E0) >> 5; \
uint16_t b = ((color) & 0x001F)
#define RGB_JOIN(r, g, b) \
(((r) << 11) + ((g) << 5) + (b))
#define GET_RED(color) \
(((color) & 0xF800) >> 8)
#define GET_GREEN(color) \
(((color) & 0x07E0) >> 3)
#define GET_BLUE(color) \
(((color) & 0x001F) << 3)
// remove windows default definitions
#undef OPAQUE
#undef RGB
#define OPACITY_MAX 0x0F
#define OPACITY(x) ((x)<<24)
#define RGB(r, g, b) (uint16_t)((((r) & 0xF8) << 8) + (((g) & 0xFC) << 3) + (((b) & 0xF8) >> 3))
#define ARGB(a, r, g, b) (uint16_t)((((a) & 0xF0) << 8) + (((r) & 0xF0) << 4) + (((g) & 0xF0) << 0) + (((b) & 0xF0) >> 4))
#define COLOR(index) LcdFlags((index) << 16)
#define COLOR_IDX(att) uint8_t((att) >> 16)
#endif
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _LIBOPEUI_DEPENDS_H_
#define _LIBOPEUI_DEPENDS_H_
#include <inttypes.h>
#include "libopenui_config.h"
void lcdNextLayer();
void lcdSetColor(uint16_t color);
void DMACopyBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h);
void DMACopyAlphaBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h);
void onKeyPress();
void onKeyError();
#endif // _LIBOPEUI_DEPENDS_H_
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include <inttypes.h>
#include <string.h>
#include "libopenui_file.h"
const char * getFileExtension(const char * filename, uint8_t size, uint8_t extMaxLen, uint8_t * fnlen, uint8_t * extlen)
{
int len = size;
if (!size) {
len = strlen(filename);
}
if (!extMaxLen) {
extMaxLen = LEN_FILE_EXTENSION_MAX;
}
if (fnlen != nullptr) {
*fnlen = (uint8_t)len;
}
for (int i=len-1; i >= 0 && len-i <= extMaxLen; --i) {
if (filename[i] == '.') {
if (extlen) {
*extlen = len-i;
}
return &filename[i];
}
}
if (extlen != nullptr) {
*extlen = 0;
}
return nullptr;
}
// returns true if current working dir is at the root level
bool isCwdAtRoot()
{
char path[10];
if (f_getcwd(path, sizeof(path)-1) == FR_OK) {
return (strcasecmp("/", path) == 0);
}
return false;
}
/*
Wrapper around the f_readdir() function which
also returns ".." entry for sub-dirs. (FatFS 0.12 does
not return ".", ".." dirs anymore)
*/
FRESULT sdReadDir(DIR * dir, FILINFO * fno, bool & firstTime)
{
FRESULT res;
if (firstTime && !isCwdAtRoot()) {
// fake parent directory entry
strcpy(fno->fname, "..");
fno->fattrib = AM_DIR;
res = FR_OK;
}
else {
res = f_readdir(dir, fno); /* Read a directory item */
}
firstTime = false;
return res;
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _LIBOPEUI_FILE_H_
#define _LIBOPEUI_FILE_H_
#include <inttypes.h>
#include "ff.h"
constexpr uint8_t LEN_FILE_EXTENSION_MAX = 5; // longest used, including the dot, excluding null term.
const char * getFileExtension(const char * filename, uint8_t size = 0, uint8_t extMaxLen = 0, uint8_t * fnlen = nullptr, uint8_t * extlen = nullptr);
bool isExtensionMatching(const char * extension, const char * pattern, char * match = nullptr);
FRESULT sdReadDir(DIR * dir, FILINFO * fno, bool & firstTime);
#endif
@@ -0,0 +1,23 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "libopenui_globals.h"
uint16_t lcdColorTable[LCD_COLOR_COUNT];
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _LIBOPEUI_GLOBALS_H_
#define _LIBOPEUI_GLOBALS_H_
#include <inttypes.h>
#include "libopenui_config.h"
extern uint16_t lcdColorTable[LCD_COLOR_COUNT];
extern const uint16_t * const fontspecsTable[FONT_TABLE_SIZE];
extern const uint8_t * fontsTable[FONT_TABLE_SIZE];
#endif // _LIBOPEUI_GLOBALS_H_
@@ -0,0 +1,21 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "libopenui_helpers.h"
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _LIBOPEUI_HELPERS_H_
#define _LIBOPEUI_HELPERS_H_
#include <string>
template<class T>
inline T min(T a, T b)
{
return a < b ? a : b;
}
template<class T>
inline T max(T a, T b)
{
return a > b ? a : b;
}
template<class T>
inline T limit(T vmin, T x, T vmax)
{
return min(max(vmin, x), vmax);
}
inline int divRoundClosest(const int n, const int d)
{
if (d == 0)
return 0;
else
return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d);
}
inline std::string TEXT_AT_INDEX(const char * val, uint8_t idx)
{
const char * start = val + 1 + idx * val[0];
return std::string(start, min<uint8_t>(val[0], strlen(start)));
}
#endif
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _LIBOPEUI_TYPES_H_
#define _LIBOPEUI_TYPES_H_
#include <inttypes.h>
typedef uint16_t pixel_t;
typedef int coord_t;
struct point_t
{
coord_t x;
coord_t y;
};
struct rect_t
{
coord_t x, y, w, h;
constexpr coord_t left() const
{
return x;
}
constexpr coord_t right() const
{
return x + w;
}
constexpr coord_t top() const
{
return y;
}
constexpr coord_t bottom() const
{
return y + h;
}
};
typedef uint32_t LcdFlags;
typedef uint16_t event_t;
#endif // _LIBOPEUI_TYPES_H_
+111
View File
@@ -0,0 +1,111 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "mainwindow.h"
#if defined(HARDWARE_TOUCH)
#include "touch.h"
#endif
MainWindow mainWindow;
#if defined(HARDWARE_TOUCH)
STRUCT_TOUCH touchState;
#endif
void MainWindow::emptyTrash()
{
for (auto window: trash) {
delete window;
}
trash.clear();
}
void MainWindow::checkEvents(bool trash)
{
#if defined(HARDWARE_TOUCH)
if (touchState.Event == TE_DOWN) {
onTouchStart(touchState.X + scrollPositionX, touchState.Y + scrollPositionY);
// touchState.Event = TE_NONE;
}
else if (touchState.Event == TE_UP) {
touchState.Event = TE_NONE;
onTouchEnd(touchState.startX + scrollPositionX, touchState.startY + scrollPositionY);
}
else if (touchState.Event == TE_SLIDE) {
coord_t x = touchState.X - touchState.lastX;
coord_t y = touchState.Y - touchState.lastY;
onTouchSlide(touchState.X, touchState.Y, touchState.startX, touchState.startY, x, y);
touchState.lastX = touchState.X;
touchState.lastY = touchState.Y;
}
#endif
Window::checkEvents();
if (trash) {
emptyTrash();
}
}
void MainWindow::invalidate(const rect_t & rect)
{
if (invalidatedRect.w) {
coord_t left = min(invalidatedRect.left(), rect.left());
coord_t right = max(invalidatedRect.right(), rect.right());
coord_t top = min(invalidatedRect.top(), rect.top());
coord_t bottom = max(invalidatedRect.bottom(), rect.bottom());
invalidatedRect = {left, top, right - left, bottom - top};
}
else {
invalidatedRect = rect;
}
}
bool MainWindow::refresh()
{
if (invalidatedRect.w) {
if (invalidatedRect.x > 0 || invalidatedRect.y > 0 || invalidatedRect.w < LCD_W || invalidatedRect.h < LCD_H) {
TRACE_WINDOWS("Refresh rect: left=%d top=%d width=%d height=%d", invalidatedRect.left(), invalidatedRect.top(), invalidatedRect.w, invalidatedRect.h);
BitmapBuffer * previous = lcd;
lcdNextLayer();
lcdCopy(lcd->getData(), previous->getData());
}
else {
TRACE_WINDOWS("Refresh full screen");
lcdNextLayer();
}
lcd->setOffset(0, 0);
lcd->setClippingRect(invalidatedRect.left(), invalidatedRect.right(), invalidatedRect.top(), invalidatedRect.bottom());
fullPaint(lcd);
invalidatedRect.w = 0;
return true;
}
else {
return false;
}
}
void MainWindow::run(bool trash)
{
checkEvents(trash);
if (refresh()) {
lcdRefresh();
}
}
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _MAINWINDOW_H_
#define _MAINWINDOW_H_
#include <utility>
#include "window.h"
#include "bitmapbuffer.h"
class MainWindow: public Window {
public:
MainWindow():
Window(nullptr, {0, 0, LCD_W, LCD_H}),
invalidatedRect(rect)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "MainWindow";
}
#endif
void checkEvents(bool trash=true);
void invalidate()
{
invalidate({0, 0, rect.w, rect.h});
}
void invalidate(const rect_t & rect) override;
bool refresh();
void run(bool trash=true);
protected:
void emptyTrash();
rect_t invalidatedRect;
const char * shutdown = nullptr;
};
extern MainWindow mainWindow;
#endif // _MAINWINDOW_H_
+148
View File
@@ -0,0 +1,148 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "menu.h"
MenuWindow::MenuWindow(Menu * parent):
Window(parent, {LCD_W / 2 - 100, LCD_H / 2, 200, 0}, OPAQUE)
{
setFocus();
}
void MenuWindow::select(int index)
{
selectedIndex = index;
if (innerHeight > height()) {
setScrollPositionY(lineHeight * index - 3 * lineHeight);
}
invalidate();
}
#if defined(HARDWARE_KEYS)
void MenuWindow::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_ROTARY_RIGHT) {
select((selectedIndex + 1) % lines.size());
}
else if (event == EVT_ROTARY_LEFT) {
select(selectedIndex == 0 ? lines.size() - 1 : selectedIndex - 1);
}
else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
Window::onKeyEvent(event); // the window above will be closed on event
lines[selectedIndex].onPress();
}
else if (event == EVT_KEY_BREAK(KEY_EXIT)) {
if (onCancel)
onCancel();
Window::onKeyEvent(event);
}
else {
Window::onKeyEvent(event);
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool MenuWindow::onTouchEnd(coord_t x, coord_t y)
{
int index = y / lineHeight;
lines[index].onPress();
return false; // = close the menu (inverted so that click outside the menu closes it)
}
#endif
void MenuWindow::paint(BitmapBuffer * dc)
{
int width = (innerHeight > height() ? 195 : 200);
dc->clear(HEADER_BGCOLOR);
for (unsigned i = 0; i < lines.size(); i++) {
auto & line = lines[i];
LcdFlags flags = (selectedIndex == (int) i ? WARNING_COLOR : MENU_TITLE_COLOR);
if (line.drawLine) {
line.drawLine(dc, 0, i * lineHeight /*+ (lineHeight - 20) / 2*/, flags);
}
else {
const char *text = line.text.data();
dc->drawText(10, i * lineHeight + (lineHeight - 20) / 2, text[0] == '\0' ? "---" : text, flags);
}
if (i > 0) {
dc->drawSolidHorizontalLine(0, i * lineHeight - 1, width, CURVE_AXIS_COLOR);
}
}
}
void Menu::updatePosition()
{
if (!toolbar) {
// there is no navigation bar at the left, we may center the window on screen
int count = min<int>(MenuWindow::maxLines, menuWindow.lines.size());
coord_t h = count * MenuWindow::lineHeight - 1;
menuWindow.setTop((LCD_H - h) / 2 + 20);
menuWindow.setHeight(h);
}
menuWindow.setInnerHeight(menuWindow.lines.size() * MenuWindow::lineHeight - 1);
}
void Menu::addLine(const std::string & text, std::function<void()> onPress)
{
menuWindow.addLine(text, std::move(onPress));
updatePosition();
}
void Menu::addLine(std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine, std::function<void()> onPress)
{
menuWindow.addLine(drawLine, std::move(onPress));
updatePosition();
}
void Menu::removeLines()
{
menuWindow.removeLines();
updatePosition();
}
#if defined(HARDWARE_KEYS)
void Menu::onKeyEvent(event_t event)
{
if (toolbar && (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN))) {
toolbar->onKeyEvent(event);
}
else if (event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER)) {
deleteLater();
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool Menu::onTouchEnd(coord_t x, coord_t y)
{
if (!Window::onTouchEnd(x, y)) {
deleteLater();
}
return true;
}
bool Menu::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY)
{
Window::onTouchSlide(x, y, startX, startY, slideX, slideY);
return true;
}
#endif
+196
View File
@@ -0,0 +1,196 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _MENU_H_
#define _MENU_H_
#include <vector>
#include <functional>
#include <utility>
#include <string>
#include "mainwindow.h"
class Menu;
class MenuWindow: public Window {
friend class Menu;
class MenuLine {
friend class MenuWindow;
public:
MenuLine(std::string text, std::function<void()> onPress):
text(std::move(text)),
onPress(std::move(onPress))
{
}
MenuLine(std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine, std::function<void()> onPress):
drawLine(std::move(drawLine)),
onPress(std::move(onPress))
{
}
MenuLine(MenuLine &) = delete;
MenuLine(MenuLine &&) = default;
protected:
std::string text;
std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine;
std::function<void()> onPress;
};
public:
MenuWindow(Menu * parent);
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "MenuWindow";
}
#endif
void setCancelHandler(std::function<void()> handler)
{
onCancel = handler;
}
void addLine(const std::string & text, std::function<void()> onPress)
{
lines.emplace_back(text, onPress);
invalidate();
}
void addLine(std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine, std::function<void()> onPress)
{
lines.emplace_back(drawLine, onPress);
invalidate();
}
void removeLines()
{
lines.clear();
invalidate();
}
void select(int index);
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
protected:
std::vector<MenuLine> lines;
#if defined(HARDWARE_TOUCH)
int selectedIndex = -1;
#else
int selectedIndex = 0;
#endif
std::function<void()> onCancel;
static constexpr uint8_t maxLines = 7; // TODO NV14 was 8
static constexpr uint8_t lineHeight = 30; // TODO NV14 was 40
};
class Menu : public Window {
public:
Menu() :
Window(&mainWindow, {0, 0, LCD_W, LCD_H}, TRANSPARENT),
#if !defined(HARDWARE_TOUCH)
previousFocus(focusWindow),
#endif
menuWindow(this)
{
}
~Menu() override
{
delete toolbar;
}
void setCancelHandler(std::function<void()> handler)
{
menuWindow.setCancelHandler(handler);
}
void deleteLater()
{
#if !defined(HARDWARE_TOUCH)
if (previousFocus) {
previousFocus->setFocus();
}
#endif
Window::deleteLater();
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "Menu";
}
#endif
void setToolbar(Window * window)
{
toolbar = window;
menuWindow.setLeft(toolbar->right());
menuWindow.setTop(toolbar->top());
menuWindow.setHeight(toolbar->height());
}
void addLine(const std::string & text, std::function<void()> onPress);
void addLine(std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine, std::function<void()> onPress);
void removeLines();
void select(int index)
{
menuWindow.select(index);
}
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchStart(coord_t x, coord_t y) override
{
return true;
}
bool onTouchEnd(coord_t x, coord_t y) override;
bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override;
#endif
protected:
Window * previousFocus;
MenuWindow menuWindow;
Window * toolbar = nullptr;
void updatePosition();
};
#endif
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "menutoolbar.h"
#include "font.h"
void MenuToolbarButton::paint(BitmapBuffer * dc)
{
if (checked()) {
dc->drawSolidFilledRect(MENUS_TOOLBAR_BUTTON_PADDING, MENUS_TOOLBAR_BUTTON_PADDING, MENUS_TOOLBAR_BUTTON_WIDTH - 2 * MENUS_TOOLBAR_BUTTON_PADDING, MENUS_TOOLBAR_BUTTON_WIDTH - 2 * MENUS_TOOLBAR_BUTTON_PADDING, HEADER_BGCOLOR);
dc->drawSizedText(rect.w / 2, (rect.h - getFontHeight(flags)) / 2 + 1, &picto, 1, CENTERED | MENU_TITLE_COLOR);
}
else {
dc->drawSizedText(rect.w / 2, (rect.h - getFontHeight(flags)) / 2 + 1, &picto, 1, CENTERED | TEXT_COLOR);
}
}
+180
View File
@@ -0,0 +1,180 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _MENUTOOLBAR_H_
#define _MENUTOOLBAR_H_
#include "button.h"
#include "menu.h"
int getFirstAvailable(int min, int max, std::function<bool(int)>isValueAvailable);
class MenuToolbarButton: public Button {
public:
MenuToolbarButton(Window * window, const rect_t & rect, char picto):
#if defined(HARDWARE_TOUCH)
Button(window, rect, nullptr, BUTTON_CHECKED_ON_FOCUS),
#else
Button(window, rect, nullptr),
#endif
picto(picto)
{
}
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override
{
if (hasFocus()) {
check(false);
clearFocus();
}
else {
setFocus();
}
onPress();
return true;
}
#endif
void check(bool checked=true)
{
Button::check(checked);
onPress();
Button::check(checked);
}
protected:
char picto;
};
template <class T>
class MenuToolbar: public Window {
friend T;
public:
MenuToolbar(T * choice, Menu * menu):
Window(menu, MENUS_TOOLBAR_RECT, NO_SCROLLBAR),
choice(choice),
menu(menu)
{
FormField::clearCurrentField();
}
~MenuToolbar() override
{
deleteChildren();
}
void paint(BitmapBuffer * dc) override
{
dc->clear(CURVE_AXIS_COLOR);
}
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override
{
if (event == EVT_KEY_BREAK(KEY_PGDN)) {
if (current == children.end()) {
current = children.begin();
}
else {
static_cast<MenuToolbarButton *>(*current)->check(false);
++current;
}
if (current != children.end()) {
auto button = static_cast<MenuToolbarButton *>(*current);
button->check(true);
scrollTo(button);
}
else {
setScrollPositionY(0);
}
}
else if (event == EVT_KEY_LONG(KEY_PGDN)) {
killEvents(event);
if (current == children.end()) {
--current;
}
else {
static_cast<MenuToolbarButton *>(*current)->check(false);
if (current == children.begin())
current = children.end();
else
--current;
}
if (current != children.end()) {
auto button = static_cast<MenuToolbarButton *>(*current);
button->check(true);
scrollTo(button);
}
else {
setScrollPositionY(0);
}
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override
{
Window::onTouchEnd(x, y);
return true; // = don't close the menu (inverted so that click outside the menu closes it)
}
#endif
protected:
std::list<Window *>::iterator current = children.end();
T * choice;
Menu * menu;
coord_t y = 0; // TODO NV14 was 5;
void addButton(char picto, int16_t filtermin, int16_t filtermax)
{
int vmin = choice->vmin;
int vmax = choice->vmax;
if (vmin > filtermin || vmax < filtermin)
return;
if (choice->isValueAvailable && getFirstAvailable(filtermin, filtermax, choice->isValueAvailable) == 0)
return;
auto button = new MenuToolbarButton(this, {0, y, MENUS_TOOLBAR_BUTTON_WIDTH, MENUS_TOOLBAR_BUTTON_WIDTH}, picto);
button->setPressHandler([=]() {
if (button->checked()) {
choice->fillMenu(menu, [=](int16_t index) {
return index >= filtermin && index <= filtermax;
});
}
else {
choice->fillMenu(menu);
}
return 1;
});
y += 30;
setInnerHeight(y);
}
};
#endif // _MENUTOOLBAR_H_
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "numberedit.h"
#if defined(HARDWARE_TOUCH)
#include "keyboard_number.h"
#endif
NumberEdit::NumberEdit(Window * parent, const rect_t & rect, int32_t vmin, int32_t vmax, std::function<int32_t()> getValue, std::function<void(int32_t)> setValue, LcdFlags flags):
BaseNumberEdit(parent, rect, vmin, vmax, std::move(getValue), std::move(setValue), flags)
{
}
void NumberEdit::paint(BitmapBuffer * dc)
{
FormField::paint(dc);
LcdFlags textColor;
if (editMode)
textColor = TEXT_INVERTED_COLOR;
else if (hasFocus())
textColor = TEXT_INVERTED_BGCOLOR;
else if (enabled)
textColor = TEXT_COLOR;
else
textColor = CURVE_AXIS_COLOR;
int32_t value = getValue();
if (displayFunction)
displayFunction(dc, textColor, value);
else if (value == 0 && !zeroText.empty())
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, zeroText.c_str(), textColor | flags);
else
dc->drawNumber(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, value, textColor | flags, 0, prefix.c_str(), suffix.c_str());
}
#if defined(HARDWARE_KEYS)
void NumberEdit::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (editMode) {
if (event == EVT_ROTARY_RIGHT) {
int value = getValue();
do {
value += rotencSpeed * step;
} while (isValueAvailable && !isValueAvailable(value) && value <= vmax);
if (value <= vmax)
setValue(value);
else
onKeyError();
return;
}
else if (event == EVT_ROTARY_LEFT) {
int value = getValue();
do {
value -= rotencSpeed * step;
} while (isValueAvailable && !isValueAvailable(value) && value >= vmin);
if (value >= vmin)
setValue(value);
else
onKeyError();
return;
}
}
FormField::onKeyEvent(event);
}
#endif
#if defined(HARDWARE_TOUCH)
bool NumberEdit::onTouchEnd(coord_t, coord_t)
{
if (!enabled) {
return true;
}
if (!hasFocus()) {
setFocus();
}
NumberKeyboard * keyboard = NumberKeyboard::instance();
if (keyboard->getField() != this) {
keyboard->setField(this);
}
return true;
}
#endif
void NumberEdit::onFocusLost()
{
#if defined(HARDWARE_TOUCH)
NumberKeyboard::instance()->disable(true);
#endif
FormField::onFocusLost();
}
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _NUMBEREDIT_H_
#define _NUMBEREDIT_H_
#include "basenumberedit.h"
#include <string>
class NumberEdit : public BaseNumberEdit {
public:
NumberEdit(Window * parent, const rect_t & rect, int32_t vmin, int32_t vmax,
std::function<int32_t()> getValue, std::function<void(int32_t)> setValue = nullptr, LcdFlags flags = 0);
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "NumberEdit(" + std::to_string(getValue()) + ")";
}
#endif
void paint(BitmapBuffer * dc) override;
void enable(bool enabled)
{
this->enabled = enabled;
}
void setAvailableHandler(std::function<bool(int)> handler)
{
isValueAvailable = std::move(handler);
}
void setPrefix(std::string value)
{
prefix = std::move(value);
}
void setSuffix(std::string value)
{
suffix = std::move(value);
}
void setZeroText(std::string value)
{
zeroText = std::move(value);
}
void setDisplayHandler(std::function<void(BitmapBuffer *, LcdFlags, int32_t)> function)
{
displayFunction = std::move(function);
}
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
void onFocusLost() override;
protected:
std::function<void(BitmapBuffer *, LcdFlags, int32_t)> displayFunction;
std::string prefix;
std::string suffix;
std::string zeroText;
bool enabled = true;
std::function<bool(int)> isValueAvailable;
};
#endif // _NUMBEREDIT_H_
+100
View File
@@ -0,0 +1,100 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "page.h"
#include "mainwindow.h"
#include "keyboard_number.h"
#include "keyboard_text.h"
#include "keyboard_curve.h"
#include "opentx.h" // TODO for constants
PageHeader::PageHeader(Page * parent, uint8_t icon):
Window(parent, { 0, 0, LCD_W, MENU_HEADER_HEIGHT }, OPAQUE),
icon(icon)
#if defined(HARDWARE_TOUCH)
, back(this, { 0, 0, MENU_HEADER_BUTTON_WIDTH, MENU_HEADER_BUTTON_WIDTH }, ICON_BACK,
[=]() -> uint8_t {
parent->deleteLater();
return 0;
}, BUTTON_NOFOCUS)
#endif
{
}
void PageHeader::paint(BitmapBuffer * dc)
{
theme->drawPageHeader(dc, this);
}
Page::Page(unsigned icon):
Window(&mainWindow, {0, 0, LCD_W, LCD_H}, OPAQUE),
header(this, icon),
body(this, { 0, MENU_HEADER_HEIGHT, LCD_W, LCD_H - MENU_HEADER_HEIGHT }),
previousFocus(focusWindow)
{
setFocus();
}
Page::~Page()
{
#if defined(HARDWARE_TOUCH)
TextKeyboard::instance()->disable(false);
NumberKeyboard::instance()->disable(false);
CurveKeyboard::instance()->disable(false);
#endif
}
void Page::deleteLater()
{
if (previousFocus) {
previousFocus->setFocus();
}
Window::deleteLater();
}
void Page::paint(BitmapBuffer * dc)
{
dc->clear(TEXT_BGCOLOR);
}
#if defined(HARDWARE_KEYS)
void Page::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_LONG(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT)) {
killEvents(event);
deleteLater();
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool Page::onTouchEnd(coord_t x, coord_t y)
{
if (Window::onTouchEnd(x, y))
return true;
TextKeyboard::instance()->disable(true);
NumberKeyboard::instance()->disable(true);
CurveKeyboard::instance()->disable(true);
return true;
}
#endif
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _PAGE_H_
#define _PAGE_H_
#include "window.h"
#include "button.h"
class Page;
class PageHeader: public Window {
public:
PageHeader(Page * parent, uint8_t icon);
void paint(BitmapBuffer * dc) override;
uint8_t getIcon() const
{
return icon;
}
protected:
uint8_t icon;
#if defined(HARDWARE_TOUCH)
IconButton back;
#endif
};
class Page: public Window {
public:
explicit Page(unsigned icon);
~Page() override;
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "Page";
}
#endif
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchStart(coord_t x, coord_t y) override
{
Window::onTouchStart(x, y);
return true;
}
bool onTouchEnd(coord_t x, coord_t y) override;
bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override
{
Window::onTouchSlide(x, y, startX, startY, slideX, slideY);
return true;
}
#endif
void deleteLater();
void paint(BitmapBuffer * dc) override;
protected:
PageHeader header;
FormWindow body;
Window * previousFocus;
};
#endif // _PAGE_H_
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "progress.h"
#include "theme.h"
void Progress::paint(BitmapBuffer * dc)
{
theme->drawProgressBar(dc, 0, 0, width(), height(), value);
}
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _PROGRESS_H_
#define _PROGRESS_H_
#include "window.h"
class Progress : public Window {
public:
Progress(Window * parent, const rect_t & rect):
Window(parent, rect)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "Progress";
}
#endif
void setValue(int value)
{
this->value = value;
invalidate();
}
void paint(BitmapBuffer * dc) override;
protected:
int value;
};
#endif
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "slider.h"
#include "theme.h"
void Slider::paint(BitmapBuffer * dc)
{
theme->drawSlider(dc, vmin, vmax, getValue(), rect, editMode, hasFocus());
}
int Slider::value(coord_t x) const
{
return vmin + ((vmax - vmin) * x + (rect.w / 2)) / rect.w;
}
#if defined(HARDWARE_KEYS)
void Slider::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (editMode) {
if (event == EVT_ROTARY_RIGHT) {
setValue(getValue() + rotencSpeed);
return;
}
else if (event == EVT_ROTARY_LEFT) {
setValue(getValue() - rotencSpeed);
return;
}
}
FormField::onKeyEvent(event);
}
#endif
#if defined(HARDWARE_TOUCH)
bool Slider::onTouchStart(coord_t x, coord_t y)
{
if (!hasFocus()) {
setFocus();
}
sliding = (value(x) == getValue());
return true;
}
bool Slider::onTouchEnd(coord_t x, coord_t y)
{
setValue(value(x));
invalidate();
return true;
}
bool Slider::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY)
{
if (hasFocus() && sliding) {
int newValue = value(x);
if (getValue() != newValue) {
setValue(newValue);
invalidate();
}
}
return true;
}
#endif
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _SLIDER_H_
#define _SLIDER_H_
#include "form.h"
class Slider : public FormField {
public:
Slider(Window * parent, const rect_t & rect, int32_t vmin, int32_t vmax, std::function<int32_t()> getValue, std::function<void(int32_t)> setValue):
FormField(parent, rect),
vmin(vmin),
vmax(vmax),
getValue(std::move(getValue)),
_setValue(std::move(setValue))
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "Slider";
}
#endif
void setValue(int32_t value)
{
_setValue(limit(vmin, value, vmax));
invalidate();
}
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchStart(coord_t x, coord_t y) override;
bool onTouchEnd(coord_t x, coord_t y) override;
bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override;
#endif
protected:
int value(coord_t x) const;
int32_t vmin;
int32_t vmax;
bool sliding = false;
std::function<int32_t()> getValue;
std::function<void(int32_t)> _setValue;
};
#endif
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "static.h"
#include "font.h"
void StaticText::paint(BitmapBuffer * dc)
{
if (flags & BUTTON_BACKGROUND)
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, CURVE_AXIS_COLOR);
if (flags & CENTERED)
dc->drawText(rect.w / 2, (rect.h - getFontHeight(flags)) / 2, text.c_str(), CENTERED | flags);
else
dc->drawText(0, 0, text.c_str(), flags);
}
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _STATIC_H_
#define _STATIC_H_
#include <string>
#include "window.h"
#include "button.h" // TODO just for BUTTON_BACKGROUND
class StaticText : public Window {
public:
StaticText(Window * parent, const rect_t & rect, std::string text = "", LcdFlags flags = 0) :
Window(parent, rect),
text(std::move(text)),
flags(flags)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "StaticText \"" + text + "\"";
}
#endif
void setFlags(LcdFlags flags)
{
this->flags = flags;
invalidate();
}
void paint(BitmapBuffer * dc) override;
void setText(std::string value)
{
text = std::move(value);
invalidate();
}
protected:
std::string text;
LcdFlags flags;
};
class Subtitle: public StaticText {
public:
Subtitle(Window * parent, const rect_t & rect, const char * text):
StaticText(parent, rect, text, BOLD)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "Subtitle \"" + text + "\"";
}
#endif
};
class StaticBitmap: public Window {
public:
StaticBitmap(Window * parent, const rect_t & rect, const char * filename):
Window(parent, rect),
bitmap(BitmapBuffer::load(filename))
{
}
StaticBitmap(Window * parent, const rect_t & rect, const BitmapBuffer * bitmap):
Window(parent, rect),
bitmap(bitmap)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "StaticBitmap";
}
#endif
void paint(BitmapBuffer * dc) override
{
dc->drawBitmap(0, 0, bitmap);
}
protected:
const BitmapBuffer * bitmap;
};
#endif
+194
View File
@@ -0,0 +1,194 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "tabsgroup.h"
#include "mainwindow.h"
#if defined(HARDWARE_TOUCH)
#include "keyboard_number.h"
#include "keyboard_text.h"
#include "keyboard_curve.h"
#endif
#include "opentx.h" // TODO for constants...
#include "view_main.h"
TabsGroupHeader::TabsGroupHeader(TabsGroup * parent, uint8_t icon):
Window(parent, { 0, 0, LCD_W, MENU_BODY_TOP }, OPAQUE),
#if defined(HARDWARE_TOUCH)
back(this, { 0, 0, MENU_HEADER_BUTTON_WIDTH, MENU_HEADER_BUTTON_WIDTH }, ICON_BACK,
[=]() -> uint8_t {
parent->deleteLater();
return 1;
}, BUTTON_NOFOCUS),
#endif
icon(icon),
carousel(this, parent)
{
}
void TabsGroupHeader::paint(BitmapBuffer * dc)
{
static_cast<ThemeBase *>(theme)->drawMenuBackground(dc, icon, title);
}
TabsCarousel::TabsCarousel(Window * parent, TabsGroup * menu):
Window(parent, { MENU_HEADER_BUTTONS_LEFT, 0, LCD_W - MENU_HEADER_BUTTONS_LEFT, MENU_HEADER_HEIGHT + 10 }, TRANSPARENT),
menu(menu)
{
}
void TabsCarousel::updateInnerWidth()
{
setInnerWidth(padding_left + MENU_HEADER_BUTTON_WIDTH * menu->tabs.size());
}
void TabsCarousel::paint(BitmapBuffer * dc)
{
static_cast<ThemeBase *>(theme)->drawMenuHeader(dc, menu->tabs, currentIndex);
}
#if defined(HARDWARE_TOUCH)
bool TabsCarousel::onTouchEnd(coord_t x, coord_t y)
{
unsigned index = (x - padding_left) / MENU_HEADER_BUTTON_WIDTH;
menu->setCurrentTab(index);
setCurrentIndex(index);
return true;
}
#endif
TabsGroup::TabsGroup(uint8_t icon):
Window(&mainWindow, { 0, 0, LCD_W, LCD_H }, OPAQUE),
header(this, icon),
body(this, { 0, MENU_BODY_TOP, LCD_W, MENU_BODY_HEIGHT })
{
}
TabsGroup::~TabsGroup()
{
#if defined(HARDWARE_TOUCH)
TextKeyboard::instance()->disable(false);
NumberKeyboard::instance()->disable(false);
CurveKeyboard::instance()->disable(false);
#endif
for (auto tab: tabs) {
delete tab;
}
body.deleteChildren();
}
void TabsGroup::addTab(PageTab * page)
{
tabs.push_back(page);
if (!currentTab) {
setCurrentTab(0);
}
header.carousel.updateInnerWidth();
}
void TabsGroup::removeTab(unsigned index)
{
if (currentTab == tabs[index]) {
setCurrentTab(max<unsigned>(0, index - 1));
}
tabs.erase(tabs.begin() + index);
header.carousel.updateInnerWidth();
}
void TabsGroup::removeAllTabs()
{
for (auto * tab: tabs) {
delete tab;
}
tabs.clear();
currentTab = nullptr;
header.carousel.updateInnerWidth();
}
void TabsGroup::setVisibleTab(PageTab * tab)
{
if (tab != currentTab) {
setFocus();
FormField::clearCurrentField();
body.clear();
#if defined(HARDWARE_TOUCH)
TextKeyboard::instance()->disable(false);
NumberKeyboard::instance()->disable(false);
CurveKeyboard::instance()->disable(false);
#endif
currentTab = tab;
tab->build(&body);
header.setTitle(tab->title.c_str());
invalidate();
}
}
void TabsGroup::checkEvents()
{
Window::checkEvents();
if (currentTab) {
currentTab->checkEvents();
}
}
#if defined(HARDWARE_KEYS)
void TabsGroup::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_BREAK(KEY_PGDN)) {
uint8_t current = header.carousel.getCurrentIndex() + 1;
setCurrentTab(current >= tabs.size() ? 0 : current);
}
else if (event == EVT_KEY_LONG(KEY_PGDN)) {
killEvents(event);
uint8_t current = header.carousel.getCurrentIndex();
setCurrentTab(current == 0 ? tabs.size() - 1 : current - 1);
}
else if (event == EVT_KEY_LONG(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT)) {
killEvents(event);
ViewMain::instance->setFocus();
deleteLater();
}
else if (parent) {
parent->onKeyEvent(event);
}
}
#endif
void TabsGroup::paint(BitmapBuffer * dc)
{
dc->clear(TEXT_BGCOLOR);
}
#if defined(HARDWARE_TOUCH)
bool TabsGroup::onTouchEnd(coord_t x, coord_t y)
{
if (Window::onTouchEnd(x, y))
return true;
TextKeyboard::instance()->disable(true);
NumberKeyboard::instance()->disable(true);
CurveKeyboard::instance()->disable(true);
return true;
}
#endif
+191
View File
@@ -0,0 +1,191 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _TABSGROUP_H_
#define _TABSGROUP_H_
#include <vector>
#include "button.h"
#include "form.h"
class TabsGroup;
class PageTab {
friend class TabsCarousel;
friend class TabsGroup;
public:
PageTab(std::string title, unsigned icon):
title(std::move(title)),
icon(icon)
{
}
virtual ~PageTab() = default;
virtual void build(FormWindow * window) = 0;
virtual void checkEvents()
{
}
void destroy()
{
if (onPageDestroyed) {
onPageDestroyed();
}
delete this;
}
void setOnPageDestroyedHandler(std::function<void()> handler)
{
onPageDestroyed = std::move(handler);
}
void setTitle(std::string value)
{
title = std::move(value);
}
unsigned getIcon() const
{
return icon;
}
protected:
std::string title;
unsigned icon;
std::function<void()> onPageDestroyed;
};
class TabsCarousel: public Window {
public:
TabsCarousel(Window * parent, TabsGroup * menu);
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "TabsCarousel";
}
#endif
inline void setCurrentIndex(uint8_t index)
{
currentIndex = index;
}
inline uint8_t getCurrentIndex()
{
return currentIndex;
}
void updateInnerWidth();
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
protected:
constexpr static uint8_t padding_left = 3;
TabsGroup * menu;
uint8_t currentIndex = 0;
};
class TabsGroupHeader: public Window {
friend class TabsGroup;
public:
TabsGroupHeader(TabsGroup * menu, uint8_t icon);
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "TabsGroupHeader";
}
#endif
void paint(BitmapBuffer * dc) override;
void setTitle(const char * value)
{
title = value;
}
protected:
#if defined(HARDWARE_TOUCH)
IconButton back;
#endif
uint8_t icon;
TabsCarousel carousel;
const char * title = nullptr;
};
class TabsGroup: public Window {
friend class TabsCarousel;
public:
explicit TabsGroup(uint8_t icon);
~TabsGroup() override;
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "TabsGroup";
}
#endif
void addTab(PageTab * page);
void removeTab(unsigned index);
void removeAllTabs();
void setCurrentTab(unsigned index)
{
if (index < tabs.size()) {
header.carousel.setCurrentIndex(index);
setVisibleTab(tabs[index]);
}
}
void checkEvents() override;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
protected:
TabsGroupHeader header;
FormWindow body;
std::vector<PageTab *> tabs;
PageTab * currentTab = nullptr;
void setVisibleTab(PageTab * tab);
};
#endif
+168
View File
@@ -0,0 +1,168 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "textedit.h"
#include "font.h"
#if defined(HARDWARE_TOUCH)
#include "keyboard_text.h"
#endif
void TextEdit::paint(BitmapBuffer * dc)
{
FormField::paint(dc);
if (editMode) {
dc->drawSizedText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, value, length, TEXT_INVERTED_COLOR);
coord_t left = (cursorPos == 0 ? 0 : getTextWidth(value, cursorPos));
char s[] = { value[cursorPos], '\0' };
dc->drawSolidFilledRect(FIELD_PADDING_LEFT + left - 1, FIELD_PADDING_TOP + 1, getTextWidth(s, 1) + 1, height() - 2, TEXT_INVERTED_COLOR);
dc->drawText(FIELD_PADDING_LEFT + left, FIELD_PADDING_TOP, s, TEXT_COLOR);
}
else {
const char * displayedValue = value;
LcdFlags textColor;
if (strlen(value) == 0) {
displayedValue = "---";
textColor = hasFocus() ? TEXT_INVERTED_BGCOLOR : CURVE_AXIS_COLOR;
}
else if (hasFocus()) {
textColor = TEXT_INVERTED_BGCOLOR;
}
else {
textColor = TEXT_COLOR;
}
dc->drawSizedText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, displayedValue, length, textColor);
}
#if defined(HARDWARE_TOUCH)
auto keyboard = TextKeyboard::instance();
if (hasFocus() && keyboard->getField() == this) {
coord_t cursorPos = keyboard->getCursorPos();
dc->drawSolidFilledRect(cursorPos + 2, FIELD_PADDING_TOP, 2, 21, 0); // TEXT_INVERTED_BGCOLOR);
}
#endif
}
#if defined(HARDWARE_KEYS)
void TextEdit::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (editMode) {
int c = value[cursorPos];
int v = c;
switch (event) {
case EVT_ROTARY_RIGHT:
for (int i = 0; i < rotencSpeed; i++) {
v = getNextChar(v);
}
break;
case EVT_ROTARY_LEFT:
for (int i = 0; i < rotencSpeed; i++) {
v = getPreviousChar(v);
}
break;
case EVT_KEY_BREAK(KEY_LEFT):
if (cursorPos > 0) {
cursorPos--;
invalidate();
}
break;
case EVT_KEY_BREAK(KEY_RIGHT):
if (cursorPos < length - 1) {
cursorPos++;
invalidate();
}
break;
case EVT_KEY_BREAK(KEY_ENTER):
if (cursorPos < length - 1) {
cursorPos++;
invalidate();
}
else {
FormField::onKeyEvent(event);
}
break;
case EVT_KEY_BREAK(KEY_EXIT):
cursorPos = 0;
FormField::onKeyEvent(event);
break;
case EVT_KEY_LONG(KEY_ENTER):
if (v == 0) {
killEvents(event);
FormField::onKeyEvent(EVT_KEY_BREAK(KEY_ENTER));
break;
}
// no break
case EVT_KEY_LONG(KEY_LEFT):
case EVT_KEY_LONG(KEY_RIGHT):
if (v >= -26 && v <= 26) {
v = -v; // toggle case
if (event == EVT_KEY_LONG(KEY_LEFT)) {
killEvents(KEY_LEFT);
}
}
break;
}
if (c != v) {
// TRACE("value[%d] = %d", cursorPos, v);
value[cursorPos] = v;
invalidate();
// TODO storageDirty(...);
}
}
else {
FormField::onKeyEvent(event);
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool TextEdit::onTouchEnd(coord_t x, coord_t y)
{
if (!hasFocus()) {
setFocus();
}
auto keyboard = TextKeyboard::instance();
if (keyboard->getField() != this) {
keyboard->setField(this);
}
keyboard->setCursorPos(x);
return true;
}
void TextEdit::onFocusLost()
{
TextKeyboard::instance()->disable(true);
// TODO storageDirty(...);
}
#endif
+100
View File
@@ -0,0 +1,100 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _TEXTEDIT_H_
#define _TEXTEDIT_H_
#include "form.h"
class TextEdit : public FormField {
friend class TextKeyboard;
public:
TextEdit(Window * parent, const rect_t &rect, char * value, uint8_t length, LcdFlags flags = 0) :
FormField(parent, rect),
value(value),
length(length)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() override
{
return "TextEdit";
}
#endif
uint8_t getMaxLength()
{
return length;
}
char * getData()
{
return value;
}
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onKeyEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
void onFocusLost() override;
#endif
protected:
char * value;
uint8_t length;
uint8_t cursorPos = 0;
static uint8_t getPreviousChar(uint8_t c)
{
if (c == 'A')
return ' ';
else if (c == 'a')
return 'Z';
else if (c == '0')
return 'z';
else if (c == ' ')
return '>';
else
return c - 1;
}
static uint8_t getNextChar(uint8_t c)
{
if (c == ' ')
return 'A';
else if (c == 'Z')
return 'a';
else if (c == 'z')
return '0';
else if (c == '>')
return ' ';
else
return c + 1;
}
};
#endif // _TEXTEDIT_H_
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _THEME_H_
#define _THEME_H_
#include "bitmapbuffer.h"
class PageHeader;
enum IconState {
STATE_DEFAULT,
STATE_PRESSED,
};
class Theme {
public:
virtual void drawMessageBox(const char * title, const char * text, const char * action, LcdFlags flags) const = 0;
virtual void drawProgressBar(BitmapBuffer * dc, coord_t x, coord_t y, coord_t w, coord_t h, int value) const = 0;
virtual void drawCheckBox(BitmapBuffer * dc, bool value, bool focus) const = 0;
virtual void drawSlider(BitmapBuffer * dc, int vmin, int vmax, int value, const rect_t & rect, bool edit, bool focus) const = 0;
virtual void drawPageHeader(BitmapBuffer * dc, const PageHeader * page) const = 0;
virtual const BitmapBuffer * getIcon(uint8_t index, IconState state) const = 0;
virtual const BitmapBuffer * getIconMask(uint8_t index) const = 0;
};
extern Theme * theme;
#endif // _THEME_H_
+395
View File
@@ -0,0 +1,395 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "window.h"
Window * Window::focusWindow = nullptr;
std::list<Window *> Window::trash;
Window::Window(Window * parent, const rect_t & rect, uint8_t flags):
parent(parent),
rect(rect),
innerWidth(rect.w),
innerHeight(rect.h),
windowFlags(flags)
{
if (parent) {
parent->addChild(this);
if (!(flags & TRANSPARENT)) {
invalidate();
}
}
}
Window::~Window()
{
TRACE_WINDOWS("Destroy %p %s", this, getWindowDebugString().c_str());
if (focusWindow == this) {
focusWindow = nullptr;
}
}
void Window::attach(Window * window)
{
if (parent)
detach();
parent = window;
parent->addChild(this);
}
void Window::detach()
{
if (parent) {
parent->removeChild(this);
parent = nullptr;
}
}
void Window::deleteLater(bool detach)
{
TRACE_WINDOWS("Delete %p %s", this, getWindowDebugString().c_str());
if (static_cast<Window *>(focusWindow) == static_cast<Window *>(this)) {
focusWindow = nullptr;
}
if (detach)
this->detach();
else
parent = nullptr;
if (closeHandler) {
closeHandler();
}
trash.push_back(this);
}
void Window::clear()
{
scrollPositionX = 0;
scrollPositionY = 0;
innerWidth = rect.w;
innerHeight = rect.h;
deleteChildren();
invalidate();
}
void Window::deleteChildren()
{
for (auto window: children) {
window->deleteLater(false);
}
children.clear();
}
void Window::clearFocus()
{
if (focusWindow) {
focusWindow->onFocusLost();
focusWindow = nullptr;
}
}
void Window::setFocus()
{
TRACE_WINDOWS("%s setFocus()", getWindowDebugString().c_str());
if (focusWindow != this) {
clearFocus();
focusWindow = this;
if (focusHandler) {
focusHandler();
}
}
Window * parent = this->parent;
while (parent && parent->getWindowFlags() & FORWARD_SCROLL) {
parent = parent->parent;
}
if (parent) {
parent->scrollTo(this);
invalidate();
}
}
void Window::setScrollPositionX(coord_t value)
{
coord_t newScrollPosition = max<coord_t>(0, min<coord_t>(innerWidth - width(), value));
if (newScrollPosition != scrollPositionX) {
scrollPositionX = newScrollPosition;
invalidate();
}
}
void Window::setScrollPositionY(coord_t value)
{
coord_t newScrollPosition = max<coord_t>(0, min<coord_t>(innerHeight - height(), value));
if (newScrollPosition != scrollPositionY) {
scrollPositionY = newScrollPosition;
invalidate();
}
}
void Window::scrollTo(Window * child)
{
coord_t offsetY = 0;
Window * parent = child->getParent();
while (parent && parent != this) {
offsetY += parent->top();
parent = parent->getParent();
}
coord_t top = offsetY + child->top();
coord_t bottom = offsetY + child->bottom();
if (top < scrollPositionY) {
setScrollPositionY(top - 5);
}
else if (bottom > scrollPositionY + height() - 5) {
setScrollPositionY(bottom - height() + 5);
}
}
void Window::fullPaint(BitmapBuffer * dc)
{
TRACE_WINDOWS("%s", getWindowDebugString().c_str());
if (windowFlags & PAINT_CHILDREN_FIRST) {
coord_t xmin, xmax, ymin, ymax;
coord_t x = dc->getOffsetX();
coord_t y = dc->getOffsetY();
dc->getClippingRect(xmin, xmax, ymin, ymax);
paintChildren(dc);
dc->setOffset(x, y);
dc->setClippingRect(xmin, xmax, ymin, ymax);
}
paint(dc);
if (!(windowFlags & NO_SCROLLBAR)) {
drawVerticalScrollbar(dc);
}
if (!(windowFlags & PAINT_CHILDREN_FIRST)) {
paintChildren(dc);
}
}
bool Window::isChildFullSize(Window * child)
{
return child->top() == 0 && child->height() == height() && child->left() == 0 && child->width() == width();
}
bool Window::isChildVisible(Window * window)
{
for (auto rit = children.rbegin(); rit != children.rend(); rit++) {
auto child = *rit;
if (child == window) {
return true;
}
if ((child->getWindowFlags() & OPAQUE) & isChildFullSize(child)) {
return false;
}
}
return false;
}
void Window::paintChildren(BitmapBuffer * dc)
{
coord_t x = dc->getOffsetX();
coord_t y = dc->getOffsetY();
coord_t xmin, xmax, ymin, ymax;
dc->getClippingRect(xmin, xmax, ymin, ymax);
auto it = children.end();
while(it != children.begin()) {
auto child = *(--it);
if ((child->windowFlags & OPAQUE) && isChildFullSize(child)) {
break;
}
}
for (; it != children.end(); it++) {
auto child = *it;
coord_t child_xmin = x + child->rect.x;
if (child_xmin >= xmax)
continue;
coord_t child_ymin = y + child->rect.y;
if (child_ymin >= ymax)
continue;
coord_t child_xmax = child_xmin + child->rect.w;
if (child_xmax <= xmin)
continue;
coord_t child_ymax = child_ymin + child->rect.h;
if (child_ymax <= ymin)
continue;
dc->setOffset(x + child->rect.x - child->scrollPositionX, y + child->rect.y - child->scrollPositionY);
dc->setClippingRect(max(xmin, x + child->rect.left()),
min(xmax, x + child->rect.right()),
max(ymin, y + child->rect.top()),
min(ymax, y + child->rect.bottom()));
child->fullPaint(dc);
}
}
void Window::checkEvents()
{
auto copy = children;
for (auto child: copy) {
child->checkEvents();
}
#if defined(HARDWARE_KEYS)
if (this == focusWindow) {
event_t event = getEvent(false);
if (event) {
TRACE_WINDOWS("Event 0x%x received ...", event);
this->onKeyEvent(event);
}
}
#endif
if (windowFlags & REFRESH_ALWAYS) {
invalidate();
}
}
#if defined(HARDWARE_KEYS)
void Window::onKeyEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", Window::getWindowDebugString().c_str(), event);
if (parent) {
parent->onKeyEvent(event);
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool Window::onTouchStart(coord_t x, coord_t y)
{
for (auto it = children.rbegin(); it != children.rend(); ++it) {
auto child = *it;
if (pointInRect(x, y, child->rect)) {
if (child->onTouchStart(x - child->rect.x + child->scrollPositionX, y - child->rect.y + child->scrollPositionY)) {
return true;
}
}
}
return false;
}
bool Window::onTouchEnd(coord_t x, coord_t y)
{
for (auto it = children.rbegin(); it != children.rend(); ++it) {
auto child = *it;
if (pointInRect(x, y, child->rect)) {
if (child->onTouchEnd(x - child->rect.x + child->scrollPositionX, y - child->rect.y + child->scrollPositionY)) {
return true;
}
}
}
return false;
}
bool Window::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY)
{
for (auto it = children.rbegin(); it != children.rend(); ++it) {
auto child = *it;
if (pointInRect(startX, startY, child->rect)) {
if (child->onTouchSlide(x - child->rect.x, y - child->rect.y, startX - child->rect.x, startY - child->rect.y, slideX, slideY)) {
return true;
}
}
}
if (slideY && innerHeight > rect.h) {
setScrollPositionY(scrollPositionY - slideY);
return true;
}
if (slideX && innerWidth > rect.w) {
setScrollPositionX(scrollPositionX - slideX);
return true;
}
return false;
}
#endif
void Window::adjustInnerHeight()
{
innerHeight = 0;
for (auto child: children) {
innerHeight = max(innerHeight, child->rect.y + child->rect.h);
}
}
coord_t Window::adjustHeight()
{
adjustInnerHeight();
coord_t old = rect.h;
rect.h = innerHeight;
return rect.h - old;
}
void Window::moveWindowsTop(coord_t y, coord_t delta)
{
for (auto child: children) {
if (child->rect.y > y) {
child->rect.y += delta;
}
}
innerHeight += delta;
}
void Window::invalidate(const rect_t & rect)
{
if (isVisible()) {
parent->invalidate({this->rect.x + rect.x - parent->scrollPositionX, this->rect.y + rect.y - parent->scrollPositionY, rect.w, rect.h});
}
}
void Window::drawVerticalScrollbar(BitmapBuffer * dc)
{
if (innerHeight > rect.h) {
coord_t x = rect.w - 3;
coord_t y = scrollPositionY + 3;
coord_t h = rect.h - 6;
// lcd->drawSolidFilledRect(x, y, 1, h, LINE_COLOR);
coord_t yofs = (h*scrollPositionY + innerHeight/2) / innerHeight;
coord_t yhgt = (h*rect.h + innerHeight/2) / innerHeight;
if (yhgt + yofs > h)
yhgt = h - yofs;
if (yhgt < 15) {
yhgt = 15;
if (y + yofs + yhgt > innerHeight) {
yofs = innerHeight - y - yhgt;
}
}
dc->drawSolidFilledRect(x-1, y + yofs, 3, yhgt, SCROLLBOX_COLOR);
}
}
+323
View File
@@ -0,0 +1,323 @@
/*
* Copyright (C) OpenTX
*
* Source:
* https://github.com/opentx/libopenui
*
* This file is a part of libopenui library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef _WINDOW_H_
#define _WINDOW_H_
#include <stdlib.h>
#include <list>
#include <string.h>
#include <utility>
#include <functional>
#include <string>
#include "bitmapbuffer.h"
#include "libopenui_defines.h"
#include "libopenui_helpers.h"
#include "libopenui_config.h"
// OPAQUE/TRANSPARENT defined in WinGDI
#ifndef OPAQUE
#define OPAQUE 1
#define TRANSPARENT 2
#endif
constexpr uint8_t NO_SCROLLBAR = 4;
constexpr uint8_t FORWARD_SCROLL = 8;
constexpr uint8_t REFRESH_ALWAYS = 16;
constexpr uint8_t BORDER_FOCUS_ONLY = 32;
constexpr uint8_t PAINT_CHILDREN_FIRST = 64;
class Window {
friend class GridLayout;
public:
Window(Window * parent, const rect_t & rect, uint8_t flags=0);
virtual ~Window();
#if defined(DEBUG_WINDOWS)
virtual std::string getName()
{
return "Window";
}
std::string getRectString()
{
char result[32];
sprintf(result, "[%d, %d, %d, %d]", left(), top(), width(), height());
return result;
}
std::string getIndentString()
{
std::string result;
auto tmp = parent;
while (tmp) {
result += " ";
tmp = tmp->getParent();
}
return result;
}
std::string getWindowDebugString()
{
return getIndentString() + getName() + " " + getRectString();
}
#endif
Window * getParent() const
{
return parent;
}
uint8_t getWindowFlags() const
{
return windowFlags;
}
void setWindowFlags(uint8_t flags)
{
windowFlags = flags;
}
void setCloseHandler(std::function<void()> handler)
{
closeHandler = std::move(handler);
}
void setFocusHandler(std::function<void()> handler)
{
focusHandler = std::move(handler);
}
void deleteLater(bool detach=true);
void clear();
void deleteChildren();
bool hasFocus() const
{
return focusWindow == this;
}
static Window * getFocus()
{
return focusWindow;
}
void scrollTo(Window * child);
static void clearFocus();
void setFocus();
void setRect(rect_t rect)
{
this->rect = rect;
invalidate();
}
void setWidth(coord_t value)
{
rect.w = value;
invalidate();
}
void setHeight(coord_t value)
{
rect.h = value;
if (innerHeight <= value) {
setScrollPositionY(0);
}
invalidate();
}
coord_t getHeight()
{
return rect.h;
}
void setLeft(coord_t x)
{
rect.x = x;
invalidate();
}
void setTop(coord_t y)
{
rect.y = y;
invalidate();
}
coord_t left() const
{
return rect.x;
}
coord_t right() const
{
return rect.x + rect.w;
}
coord_t top() const
{
return rect.y;
}
coord_t bottom() const
{
return rect.y + rect.h;
}
coord_t width() const
{
return rect.w;
}
coord_t height() const
{
return rect.h;
}
rect_t getRect() const
{
return rect;
}
void setInnerWidth(coord_t w)
{
innerWidth = w;
if (width() >= w) {
scrollPositionX = 0;
}
}
void setInnerHeight(coord_t h)
{
innerHeight = h;
if (height() >= h) {
scrollPositionY = 0;
}
}
coord_t getScrollPositionY() const
{
return scrollPositionY;
}
void setScrollPositionX(coord_t value);
void setScrollPositionY(coord_t value);
bool isChildVisible(Window * window);
bool isChildFullSize(Window * window);
bool isVisible()
{
return parent && parent->isChildVisible(this);
}
virtual void paint(BitmapBuffer * dc)
{
}
void drawVerticalScrollbar(BitmapBuffer * dc);
void paintChildren(BitmapBuffer * dc);
void fullPaint(BitmapBuffer * dc);
bool pointInRect(coord_t x, coord_t y, rect_t & rect)
{
return (x >= rect.x && x < rect.x + rect.w && y >= rect.y && y < rect.y + rect.h);
}
virtual void onFocusLost()
{
TRACE_WINDOWS("%s onFocusLost()", getWindowDebugString().c_str());
invalidate();
};
#if defined(HARDWARE_KEYS)
virtual void onKeyEvent(event_t event);
#endif
#if defined(HARDWARE_TOUCH)
virtual bool onTouchStart(coord_t x, coord_t y);
virtual bool onTouchEnd(coord_t x, coord_t y);
virtual bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY);
#endif
void adjustInnerHeight();
coord_t adjustHeight();
void moveWindowsTop(coord_t y, coord_t delta);
void invalidate()
{
invalidate({0, 0, rect.w, rect.h});
}
void bringToTop()
{
attach(parent); // does a detach + attach
}
virtual void checkEvents();
protected:
Window * parent;
std::list<Window *> children;
rect_t rect;
coord_t innerWidth;
coord_t innerHeight;
coord_t scrollPositionX = 0;
coord_t scrollPositionY = 0;
uint8_t windowFlags;
static Window * focusWindow;
static std::list<Window *> trash;
std::function<void()> closeHandler;
std::function<void()> focusHandler;
void attach(Window * window);
void detach();
void addChild(Window * window)
{
children.push_back(window);
}
void removeChild(Window * window)
{
children.remove(window);
invalidate();
}
virtual void invalidate(const rect_t & rect);
};
#endif // _WINDOW_H_