Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
include(src)
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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_
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_
|
||||
Reference in New Issue
Block a user