mirror of
https://github.com/tsl0922/EPD-nRF5.git
synced 2025-12-06 15:42:48 +08:00
add calendar support
This commit is contained in:
943
GUI/Adafruit_GFX.c
Normal file
943
GUI/Adafruit_GFX.c
Normal file
@@ -0,0 +1,943 @@
|
||||
/*
|
||||
This is the core graphics library for all our displays, providing a common
|
||||
set of graphics primitives (points, lines, circles, etc.). It needs to be
|
||||
paired with a hardware-specific library for each display device we carry
|
||||
(to handle the lower-level functions).
|
||||
|
||||
Adafruit invests time and resources providing this open source code, please
|
||||
support Adafruit & open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
Copyright (c) 2013 Adafruit Industries. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "Adafruit_GFX.h"
|
||||
|
||||
#ifndef abs
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef _swap_int16_t
|
||||
#define _swap_int16_t(a, b) \
|
||||
{ \
|
||||
int16_t t = a; \
|
||||
a = b; \
|
||||
b = t; \
|
||||
}
|
||||
#endif
|
||||
|
||||
static void GFX_u8g2_draw_hv_line(int16_t x, int16_t y, int16_t len,
|
||||
uint8_t dir, uint16_t color, void *arg)
|
||||
{
|
||||
Adafruit_GFX *gfx = (Adafruit_GFX *)arg;
|
||||
switch(dir) {
|
||||
case 0:
|
||||
GFX_drawFastHLine(gfx, x, y, len, color);
|
||||
break;
|
||||
case 1:
|
||||
GFX_drawFastVLine(gfx, x, y, len, color);
|
||||
break;
|
||||
case 2:
|
||||
GFX_drawFastHLine(gfx, x - len + 1, y, len, color);
|
||||
break;
|
||||
case 3:
|
||||
GFX_drawFastVLine(gfx, x, y - len + 1, len, color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instatiate a GFX context for graphics
|
||||
@param w Display width, in pixels
|
||||
@param h Display height, in pixels
|
||||
@param buffer_height Page buffer height
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_begin(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height) {
|
||||
memset(gfx, 0, sizeof(Adafruit_GFX));
|
||||
memset(&gfx->u8g2, 0, sizeof(gfx->u8g2));
|
||||
gfx->WIDTH = gfx->_width = w;
|
||||
gfx->HEIGHT = gfx->_height = h;
|
||||
gfx->u8g2.draw_hv_line = GFX_u8g2_draw_hv_line;
|
||||
gfx->u8g2.draw_hv_line_arg = gfx;
|
||||
gfx->buffer = malloc(((gfx->WIDTH + 7) / 8) * buffer_height);
|
||||
gfx->page_height = buffer_height;
|
||||
gfx->total_pages = (gfx->HEIGHT / gfx->page_height) + (gfx->HEIGHT % gfx->page_height > 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instatiate a 3-color GFX context for graphics
|
||||
@param w Display width, in pixels
|
||||
@param h Display height, in pixels
|
||||
@param buffer_height Page buffer height, should be multiple of 2
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_begin_3c(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height) {
|
||||
GFX_begin(gfx, w, h, buffer_height);
|
||||
gfx->page_height = buffer_height / 2;
|
||||
gfx->color = gfx->buffer + ((gfx->WIDTH + 7) / 8) * gfx->page_height;
|
||||
gfx->total_pages = (gfx->HEIGHT / gfx->page_height) + (gfx->HEIGHT % gfx->page_height > 0);
|
||||
}
|
||||
|
||||
void GFX_end(Adafruit_GFX *gfx) {
|
||||
if (gfx->buffer) free(gfx->buffer);
|
||||
}
|
||||
|
||||
void GFX_firstPage(Adafruit_GFX *gfx) {
|
||||
GFX_fillScreen(gfx, GFX_WHITE);
|
||||
gfx->current_page = 0;
|
||||
}
|
||||
|
||||
bool GFX_nextPage(Adafruit_GFX *gfx, buffer_callback callback) {
|
||||
int16_t page_y = gfx->current_page * gfx->page_height;
|
||||
int16_t height = min(gfx->page_height, gfx->HEIGHT - page_y);
|
||||
if (callback)
|
||||
callback(gfx->buffer, gfx->color, 0, page_y, gfx->WIDTH, height);
|
||||
|
||||
gfx->current_page++;
|
||||
GFX_fillScreen(gfx, GFX_WHITE);
|
||||
|
||||
return gfx->current_page < gfx->total_pages;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set rotation setting for display
|
||||
@param r 0 thru 3 corresponding to 4 cardinal rotations
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_setRotation(Adafruit_GFX *gfx, GFX_Rotate r) {
|
||||
gfx->rotation = r;
|
||||
switch (gfx->rotation) {
|
||||
case GFX_ROTATE_0:
|
||||
case GFX_ROTATE_180:
|
||||
gfx->_width = gfx->WIDTH;
|
||||
gfx->_height = gfx->HEIGHT;
|
||||
break;
|
||||
case GFX_ROTATE_90:
|
||||
case GFX_ROTATE_270:
|
||||
gfx->_width = gfx->HEIGHT;
|
||||
gfx->_height = gfx->WIDTH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a pixel
|
||||
@param x x coordinate
|
||||
@param y y coordinate
|
||||
@param color 16-bit 5-6-5 Color to fill with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawPixel(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t color) {
|
||||
if (x < 0 || x >= gfx->_width || y < 0 || y >= gfx->_height) return;
|
||||
|
||||
switch (gfx->rotation) {
|
||||
case GFX_ROTATE_0:
|
||||
break;
|
||||
case GFX_ROTATE_90:
|
||||
_swap_int16_t(x, y);
|
||||
x = gfx->WIDTH - x - 1;
|
||||
break;
|
||||
case GFX_ROTATE_180:
|
||||
x = gfx->WIDTH - x - 1;
|
||||
y = gfx->HEIGHT - y - 1;
|
||||
break;
|
||||
case GFX_ROTATE_270:
|
||||
_swap_int16_t(x, y);
|
||||
y = gfx->HEIGHT - y - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
y -= gfx->current_page * gfx->page_height;
|
||||
if (y < 0 || y >= gfx->page_height) return;
|
||||
|
||||
uint16_t i = x / 8 + y * (gfx->WIDTH / 8);
|
||||
if (gfx->color != NULL) {
|
||||
gfx->buffer[i] |= 0x80 >> (x & 7); // white
|
||||
gfx->color[i] |= 0x80 >> (x & 7);
|
||||
if (color == GFX_BLACK)
|
||||
gfx->buffer[i] &= ~(0x80 >> (x & 7));
|
||||
else if (color == GFX_RED)
|
||||
gfx->color[i] &= ~(0x80 >> (x & 7));
|
||||
} else {
|
||||
if (color == GFX_WHITE)
|
||||
gfx->buffer[i] |= 0x80 >> (x & 7);
|
||||
else
|
||||
gfx->buffer[i] &= ~(0x80 >> (x & 7));
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a line. Bresenham's algorithm - thx wikpedia
|
||||
@param x0 Start point x coordinate
|
||||
@param y0 Start point y coordinate
|
||||
@param x1 End point x coordinate
|
||||
@param y1 End point y coordinate
|
||||
@param color 16-bit 5-6-5 Color to draw with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawLine(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1,
|
||||
uint16_t color) {
|
||||
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
|
||||
if (steep) {
|
||||
_swap_int16_t(x0, y0);
|
||||
_swap_int16_t(x1, y1);
|
||||
}
|
||||
|
||||
if (x0 > x1) {
|
||||
_swap_int16_t(x0, x1);
|
||||
_swap_int16_t(y0, y1);
|
||||
}
|
||||
|
||||
int16_t dx, dy;
|
||||
dx = x1 - x0;
|
||||
dy = abs(y1 - y0);
|
||||
|
||||
int16_t err = dx / 2;
|
||||
int16_t ystep;
|
||||
|
||||
if (y0 < y1) {
|
||||
ystep = 1;
|
||||
} else {
|
||||
ystep = -1;
|
||||
}
|
||||
|
||||
for (; x0 <= x1; x0++) {
|
||||
if (steep) {
|
||||
GFX_drawPixel(gfx, y0, x0, color);
|
||||
} else {
|
||||
GFX_drawPixel(gfx, x0, y0, color);
|
||||
}
|
||||
err -= dy;
|
||||
if (err < 0) {
|
||||
y0 += ystep;
|
||||
err += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a perfectly vertical line
|
||||
@param x Top-most x coordinate
|
||||
@param y Top-most y coordinate
|
||||
@param h Height in pixels
|
||||
@param color 16-bit 5-6-5 Color to fill with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawFastVLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t h,
|
||||
uint16_t color) {
|
||||
GFX_drawLine(gfx, x, y, x, y + h - 1, color);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a perfectly horizontal line
|
||||
@param x Left-most x coordinate
|
||||
@param y Left-most y coordinate
|
||||
@param w Width in pixels
|
||||
@param color 16-bit 5-6-5 Color to fill with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawFastHLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w,
|
||||
uint16_t color) {
|
||||
GFX_drawLine(gfx, x, y, x + w - 1, y, color);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Fill a rectangle completely with one color.
|
||||
@param x Top left corner x coordinate
|
||||
@param y Top left corner y coordinate
|
||||
@param w Width in pixels
|
||||
@param h Height in pixels
|
||||
@param color 16-bit 5-6-5 Color to fill with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_fillRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, int16_t h,
|
||||
uint16_t color) {
|
||||
for (int16_t i = x; i < x + w; i++) {
|
||||
GFX_drawFastVLine(gfx, i, y, h, color);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Fill the screen completely with one color.
|
||||
@param color 16-bit 5-6-5 Color to fill with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_fillScreen(Adafruit_GFX *gfx, uint16_t color) {
|
||||
uint32_t size = ((gfx->WIDTH + 7) / 8) * gfx->page_height;
|
||||
memset(gfx->buffer, color == GFX_WHITE ? 0xFF : 0x00, size);
|
||||
if (gfx->color != NULL)
|
||||
memset(gfx->color, color == GFX_RED ? 0x00 : 0xFF, size);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a circle outline
|
||||
@param x0 Center-point x coordinate
|
||||
@param y0 Center-point y coordinate
|
||||
@param r Radius of circle
|
||||
@param color 16-bit 5-6-5 Color to draw with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r,
|
||||
uint16_t color) {
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
GFX_drawPixel(gfx, x0, y0 + r, color);
|
||||
GFX_drawPixel(gfx, x0, y0 - r, color);
|
||||
GFX_drawPixel(gfx, x0 + r, y0, color);
|
||||
GFX_drawPixel(gfx, x0 - r, y0, color);
|
||||
|
||||
while (x < y) {
|
||||
if (f >= 0) {
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
GFX_drawPixel(gfx, x0 + x, y0 + y, color);
|
||||
GFX_drawPixel(gfx, x0 - x, y0 + y, color);
|
||||
GFX_drawPixel(gfx, x0 + x, y0 - y, color);
|
||||
GFX_drawPixel(gfx, x0 - x, y0 - y, color);
|
||||
GFX_drawPixel(gfx, x0 + y, y0 + x, color);
|
||||
GFX_drawPixel(gfx, x0 - y, y0 + x, color);
|
||||
GFX_drawPixel(gfx, x0 + y, y0 - x, color);
|
||||
GFX_drawPixel(gfx, x0 - y, y0 - x, color);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Quarter-circle drawer, used to do circles and roundrects
|
||||
@param x0 Center-point x coordinate
|
||||
@param y0 Center-point y coordinate
|
||||
@param r Radius of circle
|
||||
@param cornername Mask bit #1 or bit #2 to indicate which quarters of
|
||||
the circle we're doing
|
||||
@param color 16-bit 5-6-5 Color to draw with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r,
|
||||
uint8_t cornername, uint16_t color) {
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x < y) {
|
||||
if (f >= 0) {
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
if (cornername & 0x4) {
|
||||
GFX_drawPixel(gfx, x0 + x, y0 + y, color);
|
||||
GFX_drawPixel(gfx, x0 + y, y0 + x, color);
|
||||
}
|
||||
if (cornername & 0x2) {
|
||||
GFX_drawPixel(gfx, x0 + x, y0 - y, color);
|
||||
GFX_drawPixel(gfx, x0 + y, y0 - x, color);
|
||||
}
|
||||
if (cornername & 0x8) {
|
||||
GFX_drawPixel(gfx, x0 - y, y0 + x, color);
|
||||
GFX_drawPixel(gfx, x0 - x, y0 + y, color);
|
||||
}
|
||||
if (cornername & 0x1) {
|
||||
GFX_drawPixel(gfx, x0 - y, y0 - x, color);
|
||||
GFX_drawPixel(gfx, x0 - x, y0 - y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a circle with filled color
|
||||
@param x0 Center-point x coordinate
|
||||
@param y0 Center-point y coordinate
|
||||
@param r Radius of circle
|
||||
@param color 16-bit 5-6-5 Color to fill with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_fillCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r,
|
||||
uint16_t color) {
|
||||
GFX_drawFastVLine(gfx, x0, y0 - r, 2 * r + 1, color);
|
||||
GFX_fillCircleHelper(gfx, x0, y0, r, 3, 0, color);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Quarter-circle drawer with fill, used for circles and roundrects
|
||||
@param x0 Center-point x coordinate
|
||||
@param y0 Center-point y coordinate
|
||||
@param r Radius of circle
|
||||
@param corners Mask bits indicating which quarters we're doing
|
||||
@param delta Offset from center-point, used for round-rects
|
||||
@param color 16-bit 5-6-5 Color to fill with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_fillCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r,
|
||||
uint8_t corners, int16_t delta, uint16_t color) {
|
||||
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
int16_t px = x;
|
||||
int16_t py = y;
|
||||
|
||||
delta++; // Avoid some +1's in the loop
|
||||
|
||||
while (x < y) {
|
||||
if (f >= 0) {
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
// These checks avoid double-drawing certain lines, important
|
||||
// for the SSD1306 library which has an INVERT drawing mode.
|
||||
if (x < (y + 1)) {
|
||||
if (corners & 1)
|
||||
GFX_drawFastVLine(gfx, x0 + x, y0 - y, 2 * y + delta, color);
|
||||
if (corners & 2)
|
||||
GFX_drawFastVLine(gfx, x0 - x, y0 - y, 2 * y + delta, color);
|
||||
}
|
||||
if (y != py) {
|
||||
if (corners & 1)
|
||||
GFX_drawFastVLine(gfx, x0 + py, y0 - px, 2 * px + delta, color);
|
||||
if (corners & 2)
|
||||
GFX_drawFastVLine(gfx, x0 - py, y0 - px, 2 * px + delta, color);
|
||||
py = y;
|
||||
}
|
||||
px = x;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a rectangle with no fill color
|
||||
@param x Top left corner x coordinate
|
||||
@param y Top left corner y coordinate
|
||||
@param w Width in pixels
|
||||
@param h Height in pixels
|
||||
@param color 16-bit 5-6-5 Color to draw with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, int16_t h,
|
||||
uint16_t color) {
|
||||
GFX_drawFastHLine(gfx, x, y, w, color);
|
||||
GFX_drawFastHLine(gfx, x, y + h - 1, w, color);
|
||||
GFX_drawFastVLine(gfx, x, y, h, color);
|
||||
GFX_drawFastVLine(gfx, x + w - 1, y, h, color);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a rounded rectangle with no fill color
|
||||
@param x Top left corner x coordinate
|
||||
@param y Top left corner y coordinate
|
||||
@param w Width in pixels
|
||||
@param h Height in pixels
|
||||
@param r Radius of corner rounding
|
||||
@param color 16-bit 5-6-5 Color to draw with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawRoundRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w,
|
||||
int16_t h, int16_t r, uint16_t color) {
|
||||
int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
|
||||
if (r > max_radius)
|
||||
r = max_radius;
|
||||
// smarter version
|
||||
GFX_drawFastHLine(gfx, x + r, y, w - 2 * r, color); // Top
|
||||
GFX_drawFastHLine(gfx, x + r, y + h - 1, w - 2 * r, color); // Bottom
|
||||
GFX_drawFastVLine(gfx, x, y + r, h - 2 * r, color); // Left
|
||||
GFX_drawFastVLine(gfx, x + w - 1, y + r, h - 2 * r, color); // Right
|
||||
// draw four corners
|
||||
GFX_drawCircleHelper(gfx, x + r, y + r, r, 1, color);
|
||||
GFX_drawCircleHelper(gfx, x + w - r - 1, y + r, r, 2, color);
|
||||
GFX_drawCircleHelper(gfx, x + w - r - 1, y + h - r - 1, r, 4, color);
|
||||
GFX_drawCircleHelper(gfx, x + r, y + h - r - 1, r, 8, color);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a rounded rectangle with fill color
|
||||
@param x Top left corner x coordinate
|
||||
@param y Top left corner y coordinate
|
||||
@param w Width in pixels
|
||||
@param h Height in pixels
|
||||
@param r Radius of corner rounding
|
||||
@param color 16-bit 5-6-5 Color to draw/fill with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_fillRoundRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w,
|
||||
int16_t h, int16_t r, uint16_t color) {
|
||||
int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
|
||||
if (r > max_radius)
|
||||
r = max_radius;
|
||||
// smarter version
|
||||
GFX_fillRect(gfx, x + r, y, w - 2 * r, h, color);
|
||||
// draw four corners
|
||||
GFX_fillCircleHelper(gfx, x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
|
||||
GFX_fillCircleHelper(gfx, x + r, y + r, r, 2, h - 2 * r - 1, color);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a triangle with no fill color
|
||||
@param x0 Vertex #0 x coordinate
|
||||
@param y0 Vertex #0 y coordinate
|
||||
@param x1 Vertex #1 x coordinate
|
||||
@param y1 Vertex #1 y coordinate
|
||||
@param x2 Vertex #2 x coordinate
|
||||
@param y2 Vertex #2 y coordinate
|
||||
@param color 16-bit 5-6-5 Color to draw with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1,
|
||||
int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
|
||||
GFX_drawLine(gfx, x0, y0, x1, y1, color);
|
||||
GFX_drawLine(gfx, x1, y1, x2, y2, color);
|
||||
GFX_drawLine(gfx, x2, y2, x0, y0, color);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a triangle with color-fill
|
||||
@param x0 Vertex #0 x coordinate
|
||||
@param y0 Vertex #0 y coordinate
|
||||
@param x1 Vertex #1 x coordinate
|
||||
@param y1 Vertex #1 y coordinate
|
||||
@param x2 Vertex #2 x coordinate
|
||||
@param y2 Vertex #2 y coordinate
|
||||
@param color 16-bit 5-6-5 Color to fill/draw with
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_fillTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1,
|
||||
int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
|
||||
|
||||
int16_t a, b, y, last;
|
||||
|
||||
// Sort coordinates by Y order (y2 >= y1 >= y0)
|
||||
if (y0 > y1) {
|
||||
_swap_int16_t(y0, y1);
|
||||
_swap_int16_t(x0, x1);
|
||||
}
|
||||
if (y1 > y2) {
|
||||
_swap_int16_t(y2, y1);
|
||||
_swap_int16_t(x2, x1);
|
||||
}
|
||||
if (y0 > y1) {
|
||||
_swap_int16_t(y0, y1);
|
||||
_swap_int16_t(x0, x1);
|
||||
}
|
||||
|
||||
if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
|
||||
a = b = x0;
|
||||
if (x1 < a)
|
||||
a = x1;
|
||||
else if (x1 > b)
|
||||
b = x1;
|
||||
if (x2 < a)
|
||||
a = x2;
|
||||
else if (x2 > b)
|
||||
b = x2;
|
||||
GFX_drawFastHLine(gfx, a, y0, b - a + 1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0,
|
||||
dx12 = x2 - x1, dy12 = y2 - y1;
|
||||
int32_t sa = 0, sb = 0;
|
||||
|
||||
// For upper part of triangle, find scanline crossings for segments
|
||||
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
|
||||
// is included here (and second loop will be skipped, avoiding a /0
|
||||
// error there), otherwise scanline y1 is skipped here and handled
|
||||
// in the second loop...which also avoids a /0 error here if y0=y1
|
||||
// (flat-topped triangle).
|
||||
if (y1 == y2)
|
||||
last = y1; // Include y1 scanline
|
||||
else
|
||||
last = y1 - 1; // Skip it
|
||||
|
||||
for (y = y0; y <= last; y++) {
|
||||
a = x0 + sa / dy01;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx01;
|
||||
sb += dx02;
|
||||
/* longhand:
|
||||
a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
|
||||
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
|
||||
*/
|
||||
if (a > b)
|
||||
_swap_int16_t(a, b);
|
||||
GFX_drawFastHLine(gfx, a, y, b - a + 1, color);
|
||||
}
|
||||
|
||||
// For lower part of triangle, find scanline crossings for segments
|
||||
// 0-2 and 1-2. This loop is skipped if y1=y2.
|
||||
sa = (int32_t)dx12 * (y - y1);
|
||||
sb = (int32_t)dx02 * (y - y0);
|
||||
for (; y <= y2; y++) {
|
||||
a = x1 + sa / dy12;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx12;
|
||||
sb += dx02;
|
||||
/* longhand:
|
||||
a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
|
||||
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
|
||||
*/
|
||||
if (a > b)
|
||||
_swap_int16_t(a, b);
|
||||
GFX_drawFastHLine(gfx, a, y, b - a + 1, color);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a RAM-resident 1-bit image at the specified (x,y) position,
|
||||
using the specified foreground color (unset bits are transparent).
|
||||
@param x Top left corner x coordinate
|
||||
@param y Top left corner y coordinate
|
||||
@param bitmap byte array with monochrome bitmap
|
||||
@param w Width of bitmap in pixels
|
||||
@param h Height of bitmap in pixels
|
||||
@param color 16-bit 5-6-5 Color to draw with
|
||||
@param invert When true, will invert the bitmap
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void GFX_drawBitmap(Adafruit_GFX *gfx, int16_t x, int16_t y, const uint8_t bitmap[],
|
||||
int16_t w, int16_t h, uint16_t color, bool invert) {
|
||||
|
||||
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
|
||||
uint8_t byte = 0;
|
||||
|
||||
for (int16_t j = 0; j < h; j++) {
|
||||
for (int16_t i = 0; i < w; i++) {
|
||||
if (i & 7)
|
||||
byte <<= 1;
|
||||
else
|
||||
byte = bitmap[j * byteWidth + i / 8];
|
||||
if (((byte & 0x80) == 0x80) ^ invert)
|
||||
GFX_drawPixel(gfx, x + i, y + j, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
U8g2_for_Adafruit_GFX.cpp
|
||||
|
||||
Add unicode support and U8g2 fonts to Adafruit GFX libraries.
|
||||
|
||||
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
|
||||
|
||||
Copyright (c) 2018, olikraus@gmail.com
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
void GFX_setCursor(Adafruit_GFX *gfx, int16_t x, int16_t y) {
|
||||
gfx->tx = x;
|
||||
gfx->ty = y;
|
||||
gfx->utf8_state = 0;
|
||||
}
|
||||
|
||||
void GFX_setFont(Adafruit_GFX *gfx, const uint8_t *font) {
|
||||
u8g2_SetFont(&gfx->u8g2, font);
|
||||
}
|
||||
|
||||
void GFX_setFontMode(Adafruit_GFX *gfx, uint8_t is_transparent) {
|
||||
u8g2_SetFontMode(&gfx->u8g2, is_transparent);
|
||||
}
|
||||
|
||||
void GFX_setFontDirection(Adafruit_GFX *gfx, GFX_Rotate d) {
|
||||
u8g2_SetFontDirection(&gfx->u8g2, (uint8_t)d);
|
||||
}
|
||||
|
||||
void GFX_setTextColor(Adafruit_GFX *gfx, uint16_t fg, uint16_t bg) {
|
||||
u8g2_SetForegroundColor(&gfx->u8g2, fg);
|
||||
u8g2_SetBackgroundColor(&gfx->u8g2, bg);
|
||||
}
|
||||
|
||||
int8_t GFX_getFontAscent(Adafruit_GFX *gfx) {
|
||||
return gfx->u8g2.font_info.ascent_A;
|
||||
}
|
||||
|
||||
int8_t GFX_getFontDescent(Adafruit_GFX *gfx) {
|
||||
return gfx->u8g2.font_info.descent_g;
|
||||
}
|
||||
|
||||
int16_t GFX_drawGlyph(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t e) {
|
||||
return u8g2_DrawGlyph(&gfx->u8g2, x, y, e);
|
||||
}
|
||||
|
||||
int16_t GFX_drawStr(Adafruit_GFX *gfx, int16_t x, int16_t y, const char *s) {
|
||||
return u8g2_DrawStr(&gfx->u8g2, x, y, s);
|
||||
}
|
||||
|
||||
static uint16_t utf8_next(Adafruit_GFX *gfx, uint8_t b)
|
||||
{
|
||||
if ( b == 0 ) /* '\n' terminates the string to support the string list procedures */
|
||||
return 0x0ffff; /* end of string detected, pending UTF8 is discarded */
|
||||
if ( gfx->utf8_state == 0 )
|
||||
{
|
||||
if ( b >= 0xfc ) /* 6 byte sequence */
|
||||
{
|
||||
gfx->utf8_state = 5;
|
||||
b &= 1;
|
||||
}
|
||||
else if ( b >= 0xf8 )
|
||||
{
|
||||
gfx->utf8_state = 4;
|
||||
b &= 3;
|
||||
}
|
||||
else if ( b >= 0xf0 )
|
||||
{
|
||||
gfx->utf8_state = 3;
|
||||
b &= 7;
|
||||
}
|
||||
else if ( b >= 0xe0 )
|
||||
{
|
||||
gfx->utf8_state = 2;
|
||||
b &= 15;
|
||||
}
|
||||
else if ( b >= 0xc0 )
|
||||
{
|
||||
gfx->utf8_state = 1;
|
||||
b &= 0x01f;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* do nothing, just use the value as encoding */
|
||||
return b;
|
||||
}
|
||||
gfx->encoding = b;
|
||||
return 0x0fffe;
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx->utf8_state--;
|
||||
/* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
|
||||
gfx->encoding<<=6;
|
||||
b &= 0x03f;
|
||||
gfx->encoding |= b;
|
||||
if ( gfx->utf8_state != 0 )
|
||||
return 0x0fffe; /* nothing to do yet */
|
||||
}
|
||||
return gfx->encoding;
|
||||
}
|
||||
|
||||
int16_t GFX_drawUTF8(Adafruit_GFX *gfx, int16_t x, int16_t y, const char *str)
|
||||
{
|
||||
uint16_t e;
|
||||
int16_t delta, sum;
|
||||
|
||||
gfx->utf8_state = 0;
|
||||
sum = 0;
|
||||
for(;;)
|
||||
{
|
||||
e = utf8_next(gfx, (uint8_t)*str);
|
||||
if ( e == 0x0ffff )
|
||||
break;
|
||||
str++;
|
||||
if ( e != 0x0fffe )
|
||||
{
|
||||
delta = u8g2_DrawGlyph(&gfx->u8g2, x, y, e);
|
||||
|
||||
switch(gfx->u8g2.font_decode.dir)
|
||||
{
|
||||
case 0:
|
||||
x += delta;
|
||||
break;
|
||||
case 1:
|
||||
y += delta;
|
||||
break;
|
||||
case 2:
|
||||
x -= delta;
|
||||
break;
|
||||
case 3:
|
||||
y -= delta;
|
||||
break;
|
||||
}
|
||||
|
||||
sum += delta;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int16_t GFX_getUTF8Width(Adafruit_GFX *gfx, const char *str)
|
||||
{
|
||||
uint16_t e;
|
||||
int16_t dx, w;
|
||||
|
||||
gfx->u8g2.font_decode.glyph_width = 0;
|
||||
gfx->utf8_state = 0;
|
||||
w = 0;
|
||||
dx = 0;
|
||||
for(;;)
|
||||
{
|
||||
e = utf8_next(gfx, (uint8_t)*str);
|
||||
if ( e == 0x0ffff )
|
||||
break;
|
||||
str++;
|
||||
if ( e != 0x0fffe )
|
||||
{
|
||||
dx = u8g2_GetGlyphWidth(&gfx->u8g2, e);
|
||||
w += dx;
|
||||
}
|
||||
}
|
||||
/* adjust the last glyph, check for issue #16: do not adjust if width is 0 */
|
||||
if ( gfx->u8g2.font_decode.glyph_width != 0 )
|
||||
{
|
||||
w -= dx;
|
||||
w += gfx->u8g2.font_decode.glyph_width; /* the real pixel width of the glyph, sideeffect of GetGlyphWidth */
|
||||
/* issue #46: we have to add the x offset also */
|
||||
w += gfx->u8g2.glyph_x_offset; /* this value is set as a side effect of u8g2_GetGlyphWidth() */
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
size_t GFX_print(Adafruit_GFX *gfx, const char c) {
|
||||
int16_t delta;
|
||||
uint16_t e = utf8_next(gfx, (uint8_t)c);
|
||||
if ( e == '\n' )
|
||||
{
|
||||
gfx->tx = 0;
|
||||
gfx->ty += gfx->u8g2.font_info.ascent_para - gfx->u8g2.font_info.descent_para;
|
||||
}
|
||||
else if ( e == '\r' )
|
||||
{
|
||||
gfx->tx = 0;
|
||||
}
|
||||
else if ( e < 0x0fffe )
|
||||
{
|
||||
delta = u8g2_DrawGlyph(&gfx->u8g2, gfx->tx, gfx->ty, e);
|
||||
switch(gfx->u8g2.font_decode.dir)
|
||||
{
|
||||
case 0:
|
||||
gfx->tx += delta;
|
||||
break;
|
||||
case 1:
|
||||
gfx->ty += delta;
|
||||
break;
|
||||
case 2:
|
||||
gfx->tx -= delta;
|
||||
break;
|
||||
case 3:
|
||||
gfx->ty -= delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t GFX_write(Adafruit_GFX *gfx, const char *buffer, size_t size) {
|
||||
size_t cnt = 0;
|
||||
while( size > 0 ) {
|
||||
cnt += GFX_print(gfx, *buffer++);
|
||||
size--;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
size_t GFX_printf(Adafruit_GFX *gfx, const char* format, ...) {
|
||||
va_list va;
|
||||
char tmp[64] = {0};
|
||||
char *buf = tmp;
|
||||
size_t len;
|
||||
|
||||
va_start(va, format);
|
||||
len = vsnprintf(tmp, sizeof(tmp), format, va);
|
||||
va_end(va);
|
||||
|
||||
if (len > sizeof(tmp) - 1)
|
||||
{
|
||||
buf = malloc(len + 1);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
va_start(va, format);
|
||||
vsnprintf(buf, len + 1, format, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
return GFX_write(gfx, buf, len);
|
||||
}
|
||||
91
GUI/Adafruit_GFX.h
Normal file
91
GUI/Adafruit_GFX.h
Normal file
@@ -0,0 +1,91 @@
|
||||
#ifndef _ADAFRUIT_GFX_H
|
||||
#define _ADAFRUIT_GFX_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "u8g2_font.h"
|
||||
|
||||
#define GFX_BLACK 0x0000
|
||||
#define GFX_WHITE 0xFFFF
|
||||
#define GFX_RED 0xF800
|
||||
|
||||
typedef void (*buffer_callback)(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
|
||||
typedef enum {
|
||||
GFX_ROTATE_0 = 0,
|
||||
GFX_ROTATE_90 = 1,
|
||||
GFX_ROTATE_180 = 2,
|
||||
GFX_ROTATE_270 = 3,
|
||||
} GFX_Rotate;
|
||||
|
||||
// GRAPHICS CONTEXT
|
||||
typedef struct {
|
||||
int16_t WIDTH; ///< This is the 'raw' display width - never changes
|
||||
int16_t HEIGHT; ///< This is the 'raw' display height - never changes
|
||||
int16_t _width; ///< Display width as modified by current rotation
|
||||
int16_t _height; ///< Display height as modified by current rotation
|
||||
GFX_Rotate rotation; ///< Display rotation (0 thru 3)
|
||||
|
||||
u8g2_font_t u8g2;
|
||||
int16_t tx, ty; // current position for the print command
|
||||
uint16_t encoding; // the unicode, detected by the utf-8 decoder
|
||||
uint8_t utf8_state; // current state of the utf-8 decoder, contains the remaining bytes for a detected unicode glyph
|
||||
|
||||
uint8_t *buffer; // black pixel buffer
|
||||
uint8_t *color; // color pixel buffer
|
||||
int16_t page_height;
|
||||
int16_t current_page;
|
||||
int16_t total_pages;
|
||||
} Adafruit_GFX;
|
||||
|
||||
// CONTROL API
|
||||
void GFX_begin(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height);
|
||||
void GFX_begin_3c(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height);
|
||||
void GFX_setRotation(Adafruit_GFX *gfx, GFX_Rotate r);
|
||||
void GFX_firstPage(Adafruit_GFX *gfx);
|
||||
bool GFX_nextPage(Adafruit_GFX *gfx, buffer_callback callback);
|
||||
void GFX_end(Adafruit_GFX *gfx);
|
||||
|
||||
// DRAW API
|
||||
void GFX_drawPixel(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t color);
|
||||
void GFX_drawLine(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
|
||||
void GFX_drawFastVLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void GFX_drawFastHLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
void GFX_fillRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void GFX_fillScreen(Adafruit_GFX *gfx, uint16_t color);
|
||||
void GFX_drawRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void GFX_drawCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint16_t color);
|
||||
void GFX_drawCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
|
||||
uint16_t color);
|
||||
void GFX_fillCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint16_t color);
|
||||
void GFX_fillCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
|
||||
int16_t delta, uint16_t color);
|
||||
void GFX_drawTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
|
||||
int16_t y2, uint16_t color);
|
||||
void GFX_fillTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
|
||||
int16_t y2, uint16_t color);
|
||||
void GFX_drawRoundRect(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t w, int16_t h,
|
||||
int16_t radius, uint16_t color);
|
||||
void GFX_fillRoundRect(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t w, int16_t h,
|
||||
int16_t radius, uint16_t color);
|
||||
void GFX_drawBitmap(Adafruit_GFX *gfx, int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
|
||||
int16_t h, uint16_t color, bool invert);
|
||||
|
||||
// U8G2 FONT API
|
||||
void GFX_setCursor(Adafruit_GFX *gfx, int16_t x, int16_t y);
|
||||
void GFX_setFont(Adafruit_GFX *gfx, const uint8_t *font);
|
||||
void GFX_setFontMode(Adafruit_GFX *gfx, uint8_t is_transparent);
|
||||
void GFX_setFontDirection(Adafruit_GFX *gfx, GFX_Rotate d);
|
||||
void GFX_setTextColor(Adafruit_GFX *gfx, uint16_t fg, uint16_t bg);
|
||||
int8_t GFX_getFontAscent(Adafruit_GFX *gfx);
|
||||
int8_t GFX_getFontDescent(Adafruit_GFX *gfx);
|
||||
int16_t GFX_drawGlyph(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t e);
|
||||
int16_t GFX_drawStr(Adafruit_GFX *gfx, int16_t x, int16_t y, const char *s);
|
||||
int16_t GFX_drawUTF8(Adafruit_GFX *gfx, int16_t x, int16_t y, const char *str);
|
||||
int16_t GFX_getUTF8Width(Adafruit_GFX *gfx, const char *str);
|
||||
size_t GFX_print(Adafruit_GFX *gfx, const char c);
|
||||
size_t GFX_write(Adafruit_GFX *gfx, const char *buffer, size_t size);
|
||||
size_t GFX_printf(Adafruit_GFX *gfx, const char* format, ...);
|
||||
|
||||
#endif // _ADAFRUIT_GFX_H
|
||||
106
GUI/Calendar.c
Normal file
106
GUI/Calendar.c
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "fonts.h"
|
||||
#include "EPD_driver.h"
|
||||
#include "Lunar.h"
|
||||
#include "Calendar.h"
|
||||
|
||||
#define PAGE_HEIGHT 32
|
||||
|
||||
static void DrawDateHeader(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, struct Lunar_Date *Lunar)
|
||||
{
|
||||
GFX_setCursor(gfx, x, y);
|
||||
GFX_setFont(gfx, u8g2_font_wqy12b_t_lunar);
|
||||
GFX_setTextColor(gfx, GFX_BLACK, GFX_WHITE);
|
||||
GFX_printf(gfx, "%d年%02d月%02d日 星期%s", tm->tm_year + YEAR0, tm->tm_mon + 1, tm->tm_mday, Lunar_DayString[tm->tm_wday]);
|
||||
|
||||
LUNAR_SolarToLunar(Lunar, tm->tm_year + YEAR0, tm->tm_mon + 1, tm->tm_mday);
|
||||
GFX_setFont(gfx, u8g2_font_wqy9_t_lunar);
|
||||
GFX_setCursor(gfx, x + 226, y);
|
||||
GFX_printf(gfx, "农历: %s%s%s %s%s[%s]年", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month],
|
||||
Lunar_DateString[Lunar->Date], Lunar_StemStrig[LUNAR_GetStem(Lunar)],
|
||||
Lunar_BranchStrig[LUNAR_GetBranch(Lunar)], Lunar_ZodiacString[LUNAR_GetZodiac(Lunar)]);
|
||||
}
|
||||
|
||||
static void DrawWeekHeader(Adafruit_GFX *gfx, int16_t x, int16_t y)
|
||||
{
|
||||
GFX_setTextColor(gfx, GFX_WHITE, GFX_RED);
|
||||
GFX_fillRect(gfx, x, y, 380, 18, GFX_RED);
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
GFX_setCursor(gfx, x + 15 + i * 55, y + 14);
|
||||
GFX_printf(gfx, "%s", Lunar_DayString[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawMonthDay(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, struct Lunar_Date *Lunar, uint8_t day)
|
||||
{
|
||||
if (day == tm->tm_mday)
|
||||
{
|
||||
GFX_fillCircle(gfx, x + 10, y + 9, 22, GFX_RED);
|
||||
GFX_setTextColor(gfx, GFX_WHITE, GFX_RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFX_setTextColor(gfx, GFX_BLACK, GFX_WHITE);
|
||||
}
|
||||
|
||||
GFX_setFont(gfx, u8g2_font_wqy12b_t_lunar);
|
||||
GFX_setCursor(gfx, x + 2, y + 4);
|
||||
GFX_printf(gfx, "%d", day);
|
||||
|
||||
GFX_setFont(gfx, u8g2_font_wqy9_t_lunar);
|
||||
GFX_setCursor(gfx, x, y + 24);
|
||||
uint8_t JQdate;
|
||||
if (GetJieQi(tm->tm_year + YEAR0, tm->tm_mon + 1, day, &JQdate) && JQdate == day)
|
||||
{
|
||||
uint8_t JQ = (tm->tm_mon + 1 - 1) * 2;
|
||||
if (day >= 15)
|
||||
JQ++;
|
||||
if (day != tm->tm_mday) GFX_setTextColor(gfx, GFX_RED, GFX_WHITE);
|
||||
GFX_printf(gfx, "%s", JieQiStr[JQ]);
|
||||
}
|
||||
else
|
||||
{
|
||||
LUNAR_SolarToLunar(Lunar, tm->tm_year + YEAR0, tm->tm_mon + 1, day);
|
||||
if (Lunar->Date == 1)
|
||||
GFX_printf(gfx, "%s", Lunar_MonthString[Lunar->Month]);
|
||||
else
|
||||
GFX_printf(gfx, "%s", Lunar_DateString[Lunar->Date]);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawCalendar(uint32_t timestamp)
|
||||
{
|
||||
tm_t tm = {0};
|
||||
struct Lunar_Date Lunar;
|
||||
epd_driver_t *driver = epd_driver_get();
|
||||
|
||||
transformTime(timestamp, &tm);
|
||||
|
||||
uint8_t firstDayWeek = get_first_day_week(tm.tm_year + YEAR0, tm.tm_mon + 1);
|
||||
uint8_t monthMaxDays = thisMonthMaxDays(tm.tm_year + YEAR0, tm.tm_mon + 1);
|
||||
|
||||
Adafruit_GFX gfx;
|
||||
|
||||
if (driver->id == EPD_DRIVER_4IN2B_V2)
|
||||
GFX_begin_3c(&gfx, driver->width, driver->height, PAGE_HEIGHT);
|
||||
else
|
||||
GFX_begin(&gfx, driver->width, driver->height, PAGE_HEIGHT);
|
||||
|
||||
GFX_firstPage(&gfx);
|
||||
do {
|
||||
GFX_fillScreen(&gfx, GFX_WHITE);
|
||||
|
||||
DrawDateHeader(&gfx, 10, 22, &tm, &Lunar);
|
||||
DrawWeekHeader(&gfx, 10, 26);
|
||||
|
||||
for (uint8_t i = 0; i < monthMaxDays; i++)
|
||||
{
|
||||
DrawMonthDay(&gfx, 22 + (firstDayWeek + i) % 7 * 55, 60 + (firstDayWeek + i) / 7 * 50, &tm, &Lunar, i + 1);
|
||||
}
|
||||
} while(GFX_nextPage(&gfx, driver->write_image));
|
||||
|
||||
GFX_end(&gfx);
|
||||
|
||||
driver->display();
|
||||
}
|
||||
8
GUI/Calendar.h
Normal file
8
GUI/Calendar.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef __CALENDAR_H
|
||||
#define __CALENDAR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void DrawCalendar(uint32_t timestamp);
|
||||
|
||||
#endif
|
||||
550
GUI/Lunar.c
Normal file
550
GUI/Lunar.c
Normal file
@@ -0,0 +1,550 @@
|
||||
#include "Lunar.h"
|
||||
|
||||
const char Lunar_MonthString[13][7] = {
|
||||
"未知",
|
||||
"正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月",
|
||||
"冬月", "腊月"};
|
||||
|
||||
const char Lunar_MonthLeapString[2][4] = {
|
||||
" ",
|
||||
"闰"};
|
||||
|
||||
const char Lunar_DateString[31][7] = {
|
||||
"未知",
|
||||
"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
|
||||
"十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
|
||||
"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"};
|
||||
|
||||
const char Lunar_DayString[7][4] = {
|
||||
"日",
|
||||
"一", "二", "三", "四", "五", "六"};
|
||||
|
||||
const char Lunar_ZodiacString[12][4] = {
|
||||
"猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"};
|
||||
|
||||
const char Lunar_StemStrig[10][4] = {
|
||||
"庚", "辛", "壬", "癸", "甲", "乙", "丙", "丁", "戊", "已"};
|
||||
|
||||
const char Lunar_BranchStrig[12][4] = {
|
||||
"申", "酉", "戌", "亥", "子", "丑", "寅", "卯", "辰", "巳", "午", "未"};
|
||||
|
||||
/* 2000 ~ 2199 */
|
||||
const uint32_t lunar_month_days[] = {
|
||||
1997,
|
||||
0x0000B26D, 0x0000125C, 0x0000192C, 0x00009A95, 0x00001A94, 0x00001B4A, 0x00004B55, 0x00000AD4, 0x0000F55B,
|
||||
0x000004BA, 0x0000125A, 0x0000B92B, 0x0000152A, 0x00001694, 0x000096AA, 0x000015AA, 0x00012AB5, 0x00000974,
|
||||
0x000014B6, 0x0000CA57, 0x00000A56, 0x00001526, 0x00008E95, 0x00000D54, 0x000015AA, 0x000049B5, 0x0000096C,
|
||||
0x0000D4AE, 0x0000149C, 0x00001A4C, 0x0000BD26, 0x00001AA6, 0x00000B54, 0x00006D6A, 0x000012DA, 0x0001695D,
|
||||
0x0000095A, 0x0000149A, 0x0000DA4B, 0x00001A4A, 0x00001AA4, 0x0000BB54, 0x000016B4, 0x00000ADA, 0x0000495B,
|
||||
0x00000936, 0x0000F497, 0x00001496, 0x0000154A, 0x0000B6A5, 0x00000DA4, 0x000015B4, 0x00006AB6, 0x0000126E,
|
||||
0x0001092F, 0x0000092E, 0x00000C96, 0x0000CD4A, 0x00001D4A, 0x00000D64, 0x0000956C, 0x0000155C, 0x0000125C,
|
||||
0x0000792E, 0x0000192C, 0x0000FA95, 0x00001A94, 0x00001B4A, 0x0000AB55, 0x00000AD4, 0x000014DA, 0x00008A5D,
|
||||
0x00000A5A, 0x0001152B, 0x0000152A, 0x00001694, 0x0000D6AA, 0x000015AA, 0x00000AB4, 0x000094BA, 0x000014B6,
|
||||
0x00000A56, 0x00007527, 0x00000D26, 0x0000EE53, 0x00000D54, 0x000015AA, 0x0000A9B5, 0x0000096C, 0x000014AE,
|
||||
0x00008A4E, 0x00001A4C, 0x00011D26, 0x00001AA4, 0x00001B54, 0x0000CD6A, 0x00000ADA, 0x0000095C, 0x0000949D,
|
||||
0x0000149A, 0x00001A2A, 0x00005B25, 0x00001AA4, 0x0000FB52, 0x000016B4, 0x00000ABA, 0x0000A95B, 0x00000936,
|
||||
0x00001496, 0x00009A4B, 0x0000154A, 0x000136A5, 0x00000DA4, 0x000015AC, 0x0000CAB6, 0x0000126E, 0x0000092E,
|
||||
0x00008C97, 0x00000A96, 0x00000D4A, 0x00006DA5, 0x00000D54, 0x0000F56A, 0x0000155A, 0x00000A5C, 0x0000B92E,
|
||||
0x0000152C, 0x00001A94, 0x00009D4A, 0x00001B2A, 0x00016B55, 0x00000AD4, 0x000014DA, 0x0000CA5D, 0x00000A5A,
|
||||
0x0000151A, 0x0000BA95, 0x00001654, 0x000016AA, 0x00004AD5, 0x00000AB4, 0x0000F4BA, 0x000014B6, 0x00000A56,
|
||||
0x0000B517, 0x00000D16, 0x00000E52, 0x000096AA, 0x00000D6A, 0x000165B5, 0x0000096C, 0x000014AE, 0x0000CA2E,
|
||||
0x00001A2C, 0x00001D16, 0x0000AD52, 0x00001B52, 0x00000B6A, 0x0000656D, 0x0000055C, 0x0000F45D, 0x0000145A,
|
||||
0x00001A2A, 0x0000DA95, 0x000016A4, 0x00001AD2, 0x00008B5A, 0x00000AB6, 0x0001455B, 0x000008B6, 0x00001456,
|
||||
0x0000D52B, 0x0000152A, 0x00001694, 0x0000B6AA, 0x000015AA, 0x00000AB6, 0x000064B7, 0x000008AE, 0x0000EC57,
|
||||
0x00000A56, 0x00000D2A, 0x0000CD95, 0x00000B54, 0x0000156A, 0x00008A6D, 0x0000095C, 0x000014AE, 0x00004A56,
|
||||
0x00001A54, 0x0000DD2A, 0x00001AAA, 0x00000B54, 0x0000B56A, 0x000014DA, 0x0000095C, 0x000074AB, 0x0000149A,
|
||||
0x0000FA4B, 0x00001652, 0x000016AA, 0x0000CAD5, 0x000005B4};
|
||||
|
||||
/* 2000 ~ 2199 */
|
||||
const uint32_t solar_1_1[] = {
|
||||
1997,
|
||||
0x000F9C3C, 0x000F9E50, 0x000FA045, 0x000FA238, 0x000FA44C, 0x000FA641, 0x000FA836, 0x000FAA49, 0x000FAC3D,
|
||||
0x000FAE52, 0x000FB047, 0x000FB23A, 0x000FB44E, 0x000FB643, 0x000FB837, 0x000FBA4A, 0x000FBC3F, 0x000FBE53,
|
||||
0x000FC048, 0x000FC23C, 0x000FC450, 0x000FC645, 0x000FC839, 0x000FCA4C, 0x000FCC41, 0x000FCE36, 0x000FD04A,
|
||||
0x000FD23D, 0x000FD451, 0x000FD646, 0x000FD83A, 0x000FDA4D, 0x000FDC43, 0x000FDE37, 0x000FE04B, 0x000FE23F,
|
||||
0x000FE453, 0x000FE648, 0x000FE83C, 0x000FEA4F, 0x000FEC44, 0x000FEE38, 0x000FF04C, 0x000FF241, 0x000FF436,
|
||||
0x000FF64A, 0x000FF83E, 0x000FFA51, 0x000FFC46, 0x000FFE3A, 0x0010004E, 0x00100242, 0x00100437, 0x0010064B,
|
||||
0x00100841, 0x00100A53, 0x00100C48, 0x00100E3C, 0x0010104F, 0x00101244, 0x00101438, 0x0010164C, 0x00101842,
|
||||
0x00101A35, 0x00101C49, 0x00101E3D, 0x00102051, 0x00102245, 0x0010243A, 0x0010264E, 0x00102843, 0x00102A37,
|
||||
0x00102C4B, 0x00102E3F, 0x00103053, 0x00103247, 0x0010343B, 0x0010364F, 0x00103845, 0x00103A38, 0x00103C4C,
|
||||
0x00103E42, 0x00104036, 0x00104249, 0x0010443D, 0x00104651, 0x00104846, 0x00104A3A, 0x00104C4E, 0x00104E43,
|
||||
0x00105038, 0x0010524A, 0x0010543E, 0x00105652, 0x00105847, 0x00105A3B, 0x00105C4F, 0x00105E45, 0x00106039,
|
||||
0x0010624C, 0x00106441, 0x00106635, 0x00106849, 0x00106A3D, 0x00106C51, 0x00106E47, 0x0010703C, 0x0010724F,
|
||||
0x00107444, 0x00107638, 0x0010784C, 0x00107A3F, 0x00107C53, 0x00107E48, 0x0010803D, 0x00108250, 0x00108446,
|
||||
0x0010863A, 0x0010884E, 0x00108A42, 0x00108C36, 0x00108E4A, 0x0010903E, 0x00109251, 0x00109447, 0x0010963B,
|
||||
0x0010984F, 0x00109A43, 0x00109C37, 0x00109E4B, 0x0010A041, 0x0010A253, 0x0010A448, 0x0010A63D, 0x0010A851,
|
||||
0x0010AA45, 0x0010AC39, 0x0010AE4D, 0x0010B042, 0x0010B236, 0x0010B44A, 0x0010B63E, 0x0010B852, 0x0010BA47,
|
||||
0x0010BC3B, 0x0010BE4F, 0x0010C044, 0x0010C237, 0x0010C44B, 0x0010C641, 0x0010C854, 0x0010CA48, 0x0010CC3D,
|
||||
0x0010CE50, 0x0010D045, 0x0010D239, 0x0010D44C, 0x0010D642, 0x0010D837, 0x0010DA4A, 0x0010DC3E, 0x0010DE52,
|
||||
0x0010E047, 0x0010E23A, 0x0010E44E, 0x0010E643, 0x0010E838, 0x0010EA4B, 0x0010EC41, 0x0010EE54, 0x0010F049,
|
||||
0x0010F23C, 0x0010F450, 0x0010F645, 0x0010F839, 0x0010FA4C, 0x0010FC42, 0x0010FE37, 0x0011004B, 0x0011023E,
|
||||
0x00110452, 0x00110647, 0x0011083B, 0x00110A4E, 0x00110C43, 0x00110E38, 0x0011104C, 0x0011123F, 0x00111435,
|
||||
0x00111648, 0x0011183C, 0x00111A4F, 0x00111C45, 0x00111E39, 0x0011204D, 0x00112242, 0x00112436, 0x0011264A,
|
||||
0x0011283E, 0x00112A51, 0x00112C46, 0x00112E3B, 0x0011304F};
|
||||
|
||||
static uint32_t GetBitInt(uint32_t data, uint8_t length, uint8_t shift)
|
||||
{
|
||||
return (data & (((1 << length) - 1) << shift)) >> shift;
|
||||
}
|
||||
|
||||
// WARNING: Dates before Oct. 1582 are inaccurate
|
||||
static uint16_t SolarToInt(uint16_t y, uint8_t m, uint8_t d)
|
||||
{
|
||||
m = (m + 9) % 12;
|
||||
y = y - m / 10;
|
||||
return 365 * y + y / 4 - y / 100 + y / 400 + (m * 306 + 5) / 10 + (d - 1);
|
||||
}
|
||||
|
||||
void LUNAR_SolarToLunar(struct Lunar_Date *lunar, uint16_t solar_year, uint8_t solar_month, uint8_t solar_date)
|
||||
{
|
||||
uint8_t i, lunarM, m, d, leap, dm;
|
||||
uint16_t year_index, lunarY, y, offset;
|
||||
uint32_t solar_data, solar11, days;
|
||||
|
||||
if (solar_month < 1 || solar_month > 12 || solar_date < 1 || solar_date > 31 ||
|
||||
(solar_year - solar_1_1[0] < 3) || ((solar_year - solar_1_1[0]) > (sizeof(solar_1_1) / sizeof(uint32_t) - 2)))
|
||||
{
|
||||
lunar->Year = 0;
|
||||
lunar->Month = 0;
|
||||
lunar->Date = 0;
|
||||
lunar->IsLeap = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
year_index = solar_year - solar_1_1[0];
|
||||
solar_data = ((uint32_t)solar_year << 9) | ((uint32_t)solar_month << 5) | ((uint32_t)solar_date);
|
||||
if (solar_1_1[year_index] > solar_data)
|
||||
{
|
||||
year_index -= 1;
|
||||
}
|
||||
solar11 = solar_1_1[year_index];
|
||||
y = GetBitInt(solar11, 12, 9);
|
||||
m = GetBitInt(solar11, 4, 5);
|
||||
d = GetBitInt(solar11, 5, 0);
|
||||
offset = SolarToInt(solar_year, solar_month, solar_date) - SolarToInt(y, m, d);
|
||||
|
||||
days = lunar_month_days[year_index];
|
||||
leap = GetBitInt(days, 4, 13);
|
||||
|
||||
lunarY = year_index + solar_1_1[0];
|
||||
lunarM = 1;
|
||||
offset += 1;
|
||||
for (i = 0; i < 13; i++)
|
||||
{
|
||||
if (GetBitInt(days, 1, 12 - i) == 1)
|
||||
{
|
||||
dm = 30;
|
||||
}
|
||||
else
|
||||
{
|
||||
dm = 29;
|
||||
}
|
||||
if (offset > dm)
|
||||
{
|
||||
lunarM += 1;
|
||||
offset -= dm;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
lunar->IsLeap = 0;
|
||||
if (leap != 0 && lunarM > leap)
|
||||
{
|
||||
if (lunarM == leap + 1)
|
||||
{
|
||||
lunar->IsLeap = 1;
|
||||
}
|
||||
lunarM -= 1;
|
||||
}
|
||||
lunar->Month = lunarM;
|
||||
lunar->Date = offset;
|
||||
lunar->Year = lunarY;
|
||||
}
|
||||
|
||||
uint8_t LUNAR_GetZodiac(const struct Lunar_Date *lunar)
|
||||
{
|
||||
return lunar->Year % 12;
|
||||
}
|
||||
|
||||
uint8_t LUNAR_GetStem(const struct Lunar_Date *lunar)
|
||||
{
|
||||
return lunar->Year % 10;
|
||||
}
|
||||
|
||||
uint8_t LUNAR_GetBranch(const struct Lunar_Date *lunar)
|
||||
{
|
||||
return lunar->Year % 12;
|
||||
}
|
||||
|
||||
/*********************************************************************************************************
|
||||
** 以下为24节气计算相关程序
|
||||
**------------------------------------------------------------------------------------------------------
|
||||
********************************************************************************************************/
|
||||
|
||||
/*
|
||||
每年24节气标志表
|
||||
有兴趣的朋友可按照上面给的原理添加其它年份的表格
|
||||
不是很清楚的朋友可给我发EMAIL
|
||||
*/
|
||||
static const uint8_t YearMonthBit[160] =
|
||||
{
|
||||
0x4E, 0xA6, 0x99, // 2000
|
||||
0x9C, 0xA2, 0x98, // 2001
|
||||
0x80, 0x00, 0x18, // 2002
|
||||
0x00, 0x10, 0x24, // 2003
|
||||
0x4E, 0xA6, 0x99, // 2004
|
||||
0x9C, 0xA2, 0x98, // 2005
|
||||
0x80, 0x82, 0x18, // 2006
|
||||
0x00, 0x10, 0x24, // 2007
|
||||
0x4E, 0xA6, 0xD9, // 2008
|
||||
0x9E, 0xA2, 0x98, // 2009
|
||||
|
||||
0x80, 0x82, 0x18, // 2010
|
||||
0x00, 0x10, 0x04, // 2011
|
||||
0x4E, 0xE6, 0xD9, // 2012
|
||||
0x9E, 0xA6, 0xA8, // 2013
|
||||
0x80, 0x82, 0x18, // 2014
|
||||
0x00, 0x10, 0x00, // 2015
|
||||
0x0F, 0xE6, 0xD9, // 2016
|
||||
0xBE, 0xA6, 0x98, // 2017
|
||||
0x88, 0x82, 0x18, // 2018
|
||||
0x80, 0x00, 0x00, // 2019
|
||||
|
||||
0x0F, 0xEF, 0xD9, // 2020
|
||||
0xBE, 0xA6, 0x99, // 2021
|
||||
0x8C, 0x82, 0x98, // 2022
|
||||
0x80, 0x00, 0x00, // 2023
|
||||
0x0F, 0xEF, 0xDB, // 2024
|
||||
0xBE, 0xA6, 0x99, // 2025
|
||||
0x9C, 0xA2, 0x98, // 2026
|
||||
0x80, 0x00, 0x18, // 2027
|
||||
0x0F, 0xEF, 0xDB, // 2028
|
||||
0xBE, 0xA6, 0x99, // 2029
|
||||
|
||||
0x9C, 0xA2, 0x98, // 2030
|
||||
0x80, 0x00, 0x18, // 2031
|
||||
0x0F, 0xEF, 0xDB, // 2032
|
||||
0xBE, 0xA2, 0x99, // 2033
|
||||
0x8C, 0xA0, 0x98, // 2034
|
||||
0x80, 0x82, 0x18, // 2035
|
||||
0x0B, 0xEF, 0xDB, // 2036
|
||||
0xBE, 0xA6, 0x99, // 2037
|
||||
0x8C, 0xA2, 0x98, // 2038
|
||||
0x80, 0x82, 0x18, // 2039
|
||||
|
||||
0x0F, 0xEF, 0xDB, // 2040
|
||||
0xBE, 0xE6, 0xD9, // 2041
|
||||
0x9E, 0xA2, 0x98, // 2042
|
||||
0x80, 0x82, 0x18, // 2043
|
||||
0x0F, 0xEF, 0xFB, // 2044
|
||||
0xBF, 0xE6, 0xD9, // 2045
|
||||
0x9E, 0xA6, 0x98, // 2046
|
||||
0x80, 0x82, 0x18, // 2047
|
||||
0x0F, 0xFF, 0xFF, // 2048
|
||||
0xFC, 0xEF, 0xD9, // 2049
|
||||
0xBE, 0xA6, 0x18, // 2050
|
||||
};
|
||||
static const uint8_t days[24] =
|
||||
{
|
||||
6, 20, 4, 19, 6, 21, // 一月到三月 的节气基本日期
|
||||
5, 20, 6, 21, 6, 21, // 四月到六月 的节气基本日期
|
||||
7, 23, 8, 23, 8, 23, // 七月到九月 的节气基本日期
|
||||
8, 24, 8, 22, 7, 22, // 十月到十二月的节气基本日期
|
||||
};
|
||||
/*立春、雨水、惊蛰、春分、清明、谷雨、立夏、小满、芒种、夏至、小暑、大暑、立秋、处暑、白露、秋分、寒露、霜降、立冬、小雪、大雪、冬至、小寒、大寒
|
||||
*
|
||||
*/
|
||||
const char JieQiStr[24][7] = {
|
||||
"小寒",
|
||||
"大寒",
|
||||
"立春",
|
||||
"雨水",
|
||||
"惊蛰",
|
||||
"春分",
|
||||
"清明",
|
||||
"谷雨",
|
||||
"立夏",
|
||||
"小满",
|
||||
"芒种",
|
||||
"夏至",
|
||||
"小暑",
|
||||
"大暑",
|
||||
"立秋",
|
||||
"处暑",
|
||||
"白露",
|
||||
"秋分",
|
||||
"寒露",
|
||||
"霜降",
|
||||
"立冬",
|
||||
"小雪",
|
||||
"大雪",
|
||||
"冬至",
|
||||
};
|
||||
const uint8_t MonthDayMax[12] = {
|
||||
31,
|
||||
28,
|
||||
31,
|
||||
30,
|
||||
31,
|
||||
30,
|
||||
31,
|
||||
31,
|
||||
30,
|
||||
31,
|
||||
30,
|
||||
31,
|
||||
};
|
||||
|
||||
/*********************************************************************************************************
|
||||
** 函数名称:GetJieQi
|
||||
** 功能描述:输入公历日期得到本月24节气日期 day<15返回上半月节气,反之返回下半月
|
||||
** 如:GetJieQiStr(2007,02,08,str) 返回str[0]=4
|
||||
** 输 入: year 公历年
|
||||
** month 公历月
|
||||
** day 公历日
|
||||
** str 储存对应本月节气日期地址 1Byte
|
||||
** 输 出: 1 成功
|
||||
** 0 失败
|
||||
** 作 者: 赖皮 ★〓个人原创〓★
|
||||
** 日 期: 2007年02月08日
|
||||
**-------------------------------------------------------------------------------------------------------
|
||||
** 修改人:
|
||||
** 日 期:
|
||||
**------------------------------------------------------------------------------------------------------
|
||||
********************************************************************************************************/
|
||||
uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *JQdate)
|
||||
{
|
||||
uint8_t bak1, value, JQ;
|
||||
|
||||
if ((myear < 2000) || (myear > 2050))
|
||||
return 0;
|
||||
if ((mmonth == 0) || (mmonth > 12))
|
||||
return 0;
|
||||
JQ = (mmonth - 1) * 2; // 获得节气顺序标号(0~23
|
||||
if (mday >= 15)
|
||||
JQ++; // 判断是否是上半月
|
||||
|
||||
bak1 = YearMonthBit[(myear - 2000) * 3 + JQ / 8]; // 获得节气日期相对值所在字节
|
||||
value = ((bak1 << (JQ % 8)) & 0x80); // 获得节气日期相对值状态
|
||||
|
||||
*JQdate = days[JQ];
|
||||
if (value != 0)
|
||||
{
|
||||
// 判断年份,以决定节气相对值1代表1,还是-1。
|
||||
if ((JQ == 1 || JQ == 11 || JQ == 18 || JQ == 21) && myear < 2044)
|
||||
(*JQdate)++;
|
||||
else
|
||||
(*JQdate)--;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*********************************************************************************************************
|
||||
** 函数名称:GetJieQiStr位置
|
||||
** 如:GetJieQiStr(2007,02,08,day) 返回str="离雨水还有11天" day式距离几天
|
||||
** 输 入: year 公历年
|
||||
** month 公历月
|
||||
** day 公历日
|
||||
** str 储存24节气字符串地址 15Byte
|
||||
** 输 出: 1 成功
|
||||
** 0xFF 失败
|
||||
** 作 者: 赖皮 ★〓个人原创〓★
|
||||
** 日 期: 2007年02月08日
|
||||
**-------------------------------------------------------------------------------------------------------
|
||||
** 修改人:
|
||||
** 日 期:
|
||||
**------------------------------------------------------------------------------------------------------
|
||||
********************************************************************************************************/
|
||||
uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day)
|
||||
{
|
||||
uint8_t JQdate, JQ, MaxDay;
|
||||
|
||||
if (GetJieQi(myear, mmonth, mday, &JQdate) == 0)
|
||||
return 0xFF;
|
||||
|
||||
JQ = (mmonth - 1) * 2; // 获得节气顺序标号(0~23
|
||||
|
||||
if (mday >= 15)
|
||||
JQ++; // 判断是否是上半月
|
||||
|
||||
if (mday == JQdate) // 今天正是一个节气日
|
||||
{
|
||||
*day = 0;
|
||||
return JQ;
|
||||
}
|
||||
// 今天不是一个节气日
|
||||
// StrCopy(str, (uint8_t *)"离小寒还有??天", 15);
|
||||
|
||||
if (mday < JQdate) // 如果今天日期小于本月的节气日期
|
||||
{
|
||||
|
||||
mday = JQdate - mday;
|
||||
}
|
||||
else // 如果今天日期大于本月的节气日期
|
||||
{
|
||||
JQ++;
|
||||
|
||||
if (mday < 15)
|
||||
{
|
||||
GetJieQi(myear, mmonth, 15, &JQdate);
|
||||
mday = JQdate - mday;
|
||||
}
|
||||
else // 翻月
|
||||
{
|
||||
MaxDay = MonthDayMax[mmonth - 1];
|
||||
if (mmonth == 2) // 润月问题
|
||||
{
|
||||
if ((myear % 4 == 0) && ((myear % 100 != 0) || (myear % 400 == 0)))
|
||||
MaxDay++;
|
||||
}
|
||||
if (++mmonth == 13)
|
||||
mmonth = 1;
|
||||
GetJieQi(myear, mmonth, 1, &JQdate);
|
||||
mday = MaxDay - mday + JQdate;
|
||||
}
|
||||
}
|
||||
*day = mday;
|
||||
return JQ;
|
||||
}
|
||||
|
||||
uint32_t SEC_PER_YR[2] = {31536000, 31622400}; // 闰年和非闰年的秒数
|
||||
uint32_t SEC_PER_MT[2][12] = {
|
||||
{2678400, 2419200, 2678400, 2592000, 2678400, 2592000,
|
||||
2678400, 2678400, 2592000, 2678400, 2592000, 2678400},
|
||||
{2678400, 2505600, 2678400, 2592000, 2678400, 2592000,
|
||||
2678400, 2678400, 2592000, 2678400, 2592000, 2678400},
|
||||
};
|
||||
#define SECOND_OF_DAY 86400 // 一天多少秒
|
||||
|
||||
/**
|
||||
* @Name : static int is_leap(int yr)
|
||||
* @Description: 判断是否为闰年
|
||||
* "非整百年份:能被4整除的是闰年。"
|
||||
* "整百年份:能被400整除的是闰年。"
|
||||
* @In : 待机算的年份
|
||||
* @Out : 1:是闰年 0:非闰年
|
||||
* @Author : Denis
|
||||
*/
|
||||
int is_leap(int yr)
|
||||
{
|
||||
if (0 == (yr % 100))
|
||||
return (yr % 400 == 0) ? 1 : 0;
|
||||
else
|
||||
return (yr % 4 == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Name : static unsigned char day_of_week_get(unsigned char month, unsigned char day,
|
||||
unsigned short year)
|
||||
* @Description: 根据输入的年月日计算当天为星期几
|
||||
* @In : 年、月、日
|
||||
* @Out : 星期几
|
||||
* @Author : Denis
|
||||
*/
|
||||
unsigned char day_of_week_get(unsigned char month, unsigned char day,
|
||||
unsigned short year)
|
||||
{
|
||||
/* Month should be a number 0 to 11, Day should be a number 1 to 31 */
|
||||
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
|
||||
year -= (uint8_t)(month < 3);
|
||||
return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
|
||||
}
|
||||
|
||||
void transformTime(uint32_t unix_time, struct devtm *result)
|
||||
{
|
||||
int leapyr = 0;
|
||||
uint32_t ltime = unix_time;
|
||||
|
||||
memset(result, 0, sizeof(struct devtm));
|
||||
result->tm_year = EPOCH_YR;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (ltime < SEC_PER_YR[is_leap(result->tm_year)])
|
||||
{
|
||||
break;
|
||||
}
|
||||
ltime -= SEC_PER_YR[is_leap(result->tm_year)];
|
||||
++(result->tm_year);
|
||||
}
|
||||
|
||||
leapyr = is_leap(result->tm_year);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (ltime < SEC_PER_MT[leapyr][result->tm_mon])
|
||||
break;
|
||||
ltime -= SEC_PER_MT[leapyr][result->tm_mon];
|
||||
++(result->tm_mon);
|
||||
}
|
||||
|
||||
result->tm_mday = ltime / SEC_PER_DY;
|
||||
++(result->tm_mday);
|
||||
ltime = ltime % SEC_PER_DY;
|
||||
|
||||
result->tm_hour = ltime / SEC_PER_HR;
|
||||
ltime = ltime % SEC_PER_HR;
|
||||
|
||||
result->tm_min = ltime / 60;
|
||||
result->tm_sec = ltime % 60;
|
||||
|
||||
result->tm_wday =
|
||||
day_of_week_get(result->tm_mon + 1, result->tm_mday,
|
||||
result->tm_year);
|
||||
|
||||
/*
|
||||
* The number of years since YEAR0"
|
||||
*/
|
||||
result->tm_year -= YEAR0;
|
||||
}
|
||||
|
||||
uint8_t map[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
/*
|
||||
获取一个月最后一天值
|
||||
*/
|
||||
uint8_t get_last_day(uint16_t year, uint8_t month)
|
||||
{
|
||||
if (month % 12 == 1)
|
||||
{
|
||||
return map[month % 12] + is_leap(year);
|
||||
}
|
||||
return map[month % 12];
|
||||
}
|
||||
|
||||
/*
|
||||
获取一个月第一天星期值
|
||||
*/
|
||||
uint8_t get_first_day_week(uint16_t year, uint8_t month)
|
||||
{
|
||||
return day_of_week_get(month, 1, year);
|
||||
}
|
||||
|
||||
// 时间结构体转时间戳
|
||||
uint32_t transformTimeStruct(struct devtm *result)
|
||||
{
|
||||
uint32_t Cyear = 0;
|
||||
for (uint16_t i = 1970; i < result->tm_year; i++)
|
||||
{
|
||||
if (is_leap(i) == 1)
|
||||
Cyear++;
|
||||
}
|
||||
|
||||
uint32_t CountDay = Cyear * (uint32_t)366 + (uint32_t)(result->tm_year - 1970 - Cyear) * (uint32_t)365 + result->tm_mday - 1;
|
||||
for (uint8_t i = 0; i < result->tm_mon - 1; i++)
|
||||
{
|
||||
CountDay += get_last_day(result->tm_year, i);
|
||||
}
|
||||
|
||||
return (CountDay * SECOND_OF_DAY + (uint32_t)result->tm_sec + (uint32_t)result->tm_min * 60 + (uint32_t)result->tm_hour * 3600);
|
||||
}
|
||||
|
||||
uint8_t thisMonthMaxDays(uint8_t year, uint8_t month)
|
||||
{
|
||||
if (year % 4 == 0 && month == 2)
|
||||
return MonthDayMax[month - 1] + 1;
|
||||
else
|
||||
return MonthDayMax[month - 1];
|
||||
}
|
||||
53
GUI/Lunar.h
Normal file
53
GUI/Lunar.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef _LUNAR_H_
|
||||
#define _LUNAR_H_
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define YEAR0 (1900) /* The first year */
|
||||
#define EPOCH_YR (1970) /* EPOCH = Jan 1 1970 00:00:00 */
|
||||
#define SEC_PER_DY (86400) // 一天的秒数
|
||||
#define SEC_PER_HR (3600) // 一小时的秒数
|
||||
|
||||
typedef struct devtm
|
||||
{
|
||||
uint16_t tm_year;
|
||||
uint8_t tm_mon;
|
||||
uint8_t tm_mday;
|
||||
uint8_t tm_hour;
|
||||
uint8_t tm_min;
|
||||
uint8_t tm_sec;
|
||||
uint8_t tm_wday;
|
||||
} tm_t;
|
||||
|
||||
struct Lunar_Date
|
||||
{
|
||||
uint8_t IsLeap;
|
||||
uint8_t Date;
|
||||
uint8_t Month;
|
||||
uint16_t Year;
|
||||
};
|
||||
|
||||
extern const char Lunar_MonthString[13][7];
|
||||
extern const char Lunar_MonthLeapString[2][4];
|
||||
extern const char Lunar_DateString[31][7];
|
||||
extern const char Lunar_DayString[7][4];
|
||||
extern const char Lunar_ZodiacString[12][4];
|
||||
extern const char Lunar_StemStrig[10][4];
|
||||
extern const char Lunar_BranchStrig[12][4];
|
||||
extern const char JieQiStr[24][7];
|
||||
|
||||
void LUNAR_SolarToLunar(struct Lunar_Date *lunar, uint16_t solar_year, uint8_t solar_month, uint8_t solar_date);
|
||||
uint8_t LUNAR_GetZodiac(const struct Lunar_Date *lunar);
|
||||
uint8_t LUNAR_GetStem(const struct Lunar_Date *lunar);
|
||||
uint8_t LUNAR_GetBranch(const struct Lunar_Date *lunar);
|
||||
uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day);
|
||||
uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *JQdate);
|
||||
|
||||
void transformTime(uint32_t unix_time, struct devtm *result);
|
||||
uint32_t transformTimeStruct(struct devtm *result);
|
||||
uint8_t get_first_day_week(uint16_t year, uint8_t month);
|
||||
uint8_t get_last_day(uint16_t year, uint8_t month);
|
||||
unsigned char day_of_week_get(unsigned char month, unsigned char day, unsigned short year);
|
||||
uint8_t thisMonthMaxDays(uint8_t year, uint8_t month);
|
||||
|
||||
#endif
|
||||
135
GUI/fonts.c
Normal file
135
GUI/fonts.c
Normal file
@@ -0,0 +1,135 @@
|
||||
#include "fonts.h"
|
||||
|
||||
/*
|
||||
Fontname: -wenquanyi-wenquanyi bitmap song-medium-r-normal--12-120-75-75-P-119-ISO10646-1
|
||||
Copyright: (null)
|
||||
Glyphs: 96/30503
|
||||
BBX Build Mode: 0
|
||||
*/
|
||||
const uint8_t u8g2_font_wqy9_t_lunar[3235] U8G2_FONT_SECTION("u8g2_font_wqy9_t_lunar") =
|
||||
"\266\0\3\2\4\4\3\4\5\13\15\0\376\10\376\12\377\1a\2\317\4\30 \5\0L\13!\7\221F"
|
||||
"\213S\0\42\7\64}\213\310\24#\16\226\304\233\250eX\242^\206%j\1$\17\245<\253l\251("
|
||||
"\231\250%Je\213\0%\20\226<\233(\351\242%a\232DI\27-\1&\16\205D\253,\211\222\254"
|
||||
"\62%Q\244\4'\6\61\376\212\1(\13\263=\253$J\242nQ\26)\14\263=\213,\312\242.Q"
|
||||
"\22\1*\14uD\253J\345\240,M\21\0+\13wD\274\270\66\14Y\134\3,\7\62>\13E\1"
|
||||
"-\6\25d\213A.\6!\306\12\1/\14\304<\273\246\254\224\225\262\32\0\60\12\205D\233%\363-"
|
||||
"Y\0\61\11\205D\213\261O\203\0\62\13\205D\233%\13km\203\0\63\14\205D\213!\15\223\65\14"
|
||||
"\7\5\64\16\206\304;-\211\272d\311\60\246\11\0\65\15\205D\213!\11\303!\15\303A\1\66\15\205"
|
||||
"D\233%\14\207$\263%\13\0\67\13\205D\213A\254\205YX\2\70\15\205D\233%\323\222%\263%"
|
||||
"\13\0\71\15\205D\233%\263%C\250%\13\0:\6aD\11I;\11\202>\213!V\24\0<\10"
|
||||
"\225D\313\254k\7=\10\65\134\213A\35\4>\11\225D\213\264[G\0\77\15\225D\233%\323\302H"
|
||||
"\313\241\60\2@\24\247<\254\255\222HZ\42)JE\251H\211\222e\23\0A\16\207D\274\70M\302"
|
||||
"$+\15J\252\6B\15\206\304\213A\11\305a\11\215\303\2C\14\206\304\233!\11\325\216\311\220\0D"
|
||||
"\15\207D\214A\12\223\324c\62H\0E\12\205D\213c\70\214\305AF\13\205D\213c\70$a#"
|
||||
"\0G\15\206\304\233!\11\325\332(&\203\0H\13\206\304\213\320\70\14\242c\0I\10\203D\212%\352"
|
||||
"eJ\10\243\64\252\376\264\0K\15\205D\213LJJ\232\226D\225,L\11\205D\213\260\217\203\0M"
|
||||
"\20\207D\14m\310\226\212R\221\42)R\325\0N\15\206\304\213pS\42)\321Fc\0O\14\207D"
|
||||
"\254\255\222\272&Y\66\1P\14\205D\213!\311l\203\22\26\1Q\16\227<\254\255\222\272&Y\266\3"
|
||||
"\11\0R\20\206\304\213!\312\222,\311\222!jK\302\0S\14\205D\233AL\327\60\34\24\0T\11"
|
||||
"\207D\214C\26\367\15U\12\206\304\213\320\217\311\220\0V\17\207D\214TM\262(\253\204I\32g\0"
|
||||
"W\21\211D\215,\323\62\255\322)iJ\332\212Y\4X\15\206\304\213PL\242L\213ZB\61Y\13"
|
||||
"\207D\214\64\311*i\334\15Z\12\207D\214C\332\347a\10[\11\263>\213!\352O\3\134\14\245<"
|
||||
"\213\60\15\323\60\15\323\60]\11\263=\213\251\77\15\1^\10\65t\253,\251\5_\6\25<\213A`"
|
||||
"\7\62\375\212$\12a\14eD\233%K\6MK\206\0b\14\205D\213\60\34\222\314mP\0c\10"
|
||||
"d\304\232!k\34d\13\205D\313\312\240\271%C\0e\13eD\233%\33\206\60\35\2f\11\203D"
|
||||
"\232i\210:\1g\14\205\64\233AsK\206\60Y\0h\13\205D\213\60\34\222\314[\0i\7\201D"
|
||||
"\211d\30j\10\242\264\231,\351ek\15\205D\213\260\224\224\264$\252d\1l\7\201D\211\203\0m"
|
||||
"\16gD\214E\211\42)\222\42)\222\12n\11eD\213!\311\274\5o\12eD\233%sK\26\0"
|
||||
"p\14\205\64\213!\311\334\6%\14\1q\13\205\64\233AsK\206\260\0r\10cD\212!\352\4s"
|
||||
"\14eD\233%K\324$K\26\0t\12\203D\212(\32\242\66\1u\11eD\213\314[\62\4v\14"
|
||||
"eD\213LKJI\26F\0w\16gD\214(\222\42\245\242t\213\262\4x\13eD\213,\251U"
|
||||
"jZ\0y\15\205\64\213LKJI\26fa\6z\12eD\213A\314\332\6\1{\13\243<\252$"
|
||||
"\252dQ[\0|\7\261\276\212\7\1}\13\243<\212,\252%QK\4~\7&\334\33\311\2\200\17"
|
||||
"\225D+\251\222\15Q\66Da\24)\0\0\0\0\4\377\377N\0\12+d~(\31\16\2N\1\25"
|
||||
"\252=\216\207\64\207r(\207r(\207r(\207r`\4N\3\26\272=\316\34\312\241\34\312\304!\32"
|
||||
"t(\207r(l\35\4N\11\17\253<\236\341\316\313\60\344|\34\16\2N\21\27\253<\236a\220\263"
|
||||
"\70\213\263l\30\324\60\15\323\60\15\243\341 N\31\32\273<\216\7\65\307\342\341\224\225\62\251K\224\244"
|
||||
"Q\16D\71\20\245\13\0NY\30\272=\216w$Gr$Gr$Gr$GrDG\222\341\0"
|
||||
"N]\27\272=\276\34\312\241x\30\342(\216\342(\315\322,J\302H\36N\214\14\213D\236\341\316\77"
|
||||
"\16\7\1N\224\26\253<\236\341\234c\71\226\3\207\70\213\263\70\213\263h\70\10N\245\27\272=\316\34"
|
||||
"\13\207C\226#Y\70Hi\24J\231Y\212V\1QT\32\273<\276\34\33\324,\35.\245,\33\6"
|
||||
"\71\207\222r\322\26e\211\70\4Qk\30\253D\356\34\210r \312\201(\7\262\70K\213i\226\3I"
|
||||
"\16\5Qm\24\273<\316\34\314I\303Ag\314\342\260\34\345\210\16\5Q\234\33\273<\336x\70$Y"
|
||||
"\250ia\224\3QMJ\262$+%Q*jq\0Q\254\30\273<\276\34\33T-\214\222\34\312\21"
|
||||
"\333\24\315\71\240\203\71\30\2R\6\30\273<\276r\226\26\323,\7\222d\30\222\60\213\263\64\254F\242"
|
||||
"\6R\35\33\273<\236\34\214\206\203T+\25\243D\211\42E\213*Q[\251\30%\231\2SA\27\273"
|
||||
"<\336\34\313\261\34K\207\203\232c\71\226c\71\226c)\0SH\27\272=\256\34\32\206(\13\353P"
|
||||
"\70\34\322\34\312\241\34\312\241\20So\33\272=\276x\32\306LJ\62)\311\244$S\224l\351\226D"
|
||||
"Y\24j!\0S\206\32\273<\256\341\224c\345,N\206!\312JY\251\230da\22\245R\250\0V"
|
||||
"\333\30\251=\216\207(\211\244$\222\222HJ\42%\32f\35x\320\201\0X\354\30\273<~ \207\266"
|
||||
"A\307r\254\62\34\324\34\313\261\34\213\262\341\2Y\4\32\273<\256\60\15\323!I\243D\253\364\324\22"
|
||||
"\305Y\232Da&\306C\0Y\17\31\273<\216\7\65G\206\65L\247\64\31\322\60\34\206,\252\205\362"
|
||||
"\64\4Y'\30\273<\336\34\313\261t\70\250\71\226CI\216\324\201,-\351\200\0[P\30\273<\256"
|
||||
"a\310\241\34\312\241\34K\207\203\232c\71\226#u(\6[\305\31\273<\336tx\207\224aH\322\34"
|
||||
"\70\204Qq\30\302\250\70\14\321:[\322\33\273<\336tx\213\42e\30\222\60\312\206\203\30\305I\24"
|
||||
"m\212\250\203\32\0\134\17\30\273<\336\34\313\261\34\210\212Q\26e\245,\24\253\71R\207b\0]\362"
|
||||
"\26\252=\216\203\16\345P\71\32\6)\207rDGt$\31\16]\363\30\272=\216\203\24Gq\24G"
|
||||
"\303 \345P\16\345\210\216\350H\62\34^t\27\273<\256\34\33.a\65\36\6\255\234\205\303A\316\261"
|
||||
"\34\13\1^\232\33\273<\356x\70eq\62l\245l\70eQ\226\14[\224\204Q\26%\252\0^\377"
|
||||
"\30\273<\276\60\15\323\60\32\16Z\230\206i\230\206i\230\16k\30\1`\312\36\273<\256\60M\206A"
|
||||
"\321\201$\31\226R\226\224\6-L\243\244\226D%\245T\13\1b\12\31\273<\356$G\242l\70e"
|
||||
"q\26e\245,\24KI\230\264e\223\32b\14\33\273<\356$G\242l\70eq\26e\203\224U\302"
|
||||
"j&%Y\224H\242\0e\345\15\247>\216\203j\35\256\326\341\32e\366\34\273<~$\32\302(\32"
|
||||
"NaT\211\242!J\242\226\250\30\25\243!\314\221\11f\16\31\273<\356\341\224I\65)\32N\231T"
|
||||
"\223\242\341\224\245a-\211\324\4f\37\33\273<\256a\10\323p\30\302\64\34\206\60\212\207K\230\3\207"
|
||||
"\34H\207\203\0f%\32\273<\336x\70\244\71pP\343\341 \211\212\62%Y\62\244a:L\0f"
|
||||
"\221\33\273<\256a\10\323p\30\302\64\33\316I\66\34\304,\34\206H\11\323a\2g\10\31\271=\256"
|
||||
"a\210\322(\215\206!J\243\64\32\206(\215\322$L\344\4g\37 \273<\236(\32\16I\224D-"
|
||||
"C\64$Q\313\20U\242h\70$Q\16DIT\22%\1g*\27\273<\336\34\213\207s:\34\324"
|
||||
"\34\332\201\244\32\225\264LM\1kc\32\253<\216\7\65\307r \312\201h\320\242\34\210r \312\201"
|
||||
"(\35\16\2l\64\30\273<\336\34\313\261\312\220(iRN\252Q\61\252\265DIX\6n\5\36\273"
|
||||
"<\236\264\62\14\71\220E\311 %Y\232\14CTK\264%\312\222)+e\221\2n\341 \273<\236"
|
||||
"\60\11\223a\310\242$\212\206A\11\223\60\31\206(i\231\222NJ\242D-Q(r[\27\272=\336"
|
||||
"\70\212\243t\30\224\60\207\302\341\220\346P\16\345P\10r\327\35\273<\216\250\232Dq\64,\215\222\262"
|
||||
"DR\322)I\244h\311\342\244\226di\4s* \273<\216,\252T\206$\12\223(I\206!\312"
|
||||
"RiP*\232\244\14Z\224%\245A\312\12s\64 \273<\216\244\62D\305\244\62\14\321\22'\311\240"
|
||||
"\230*\265\60\31\206(\311\242\244\224D\225,u\62\26\271=\216\207,\323\262\341\240eZ\66\34\264b"
|
||||
"\216\344H\10u\63\26\271=\316\34\11\207C\226\15\7-\323\262\341\240\25s$\4vx\32\273<\236"
|
||||
"a\211\243\226(\11[\206$\312B\61\36\16i\222\3Y\266\12v}\20\270>\276\70\35\316\362p\210"
|
||||
"\315\303!\16w\345\33\273<\256\34\313\241A\31\244,\312J\303)+e\245JT\311\222A\307\0y"
|
||||
"\313\35\273<>)\33\323\60I\206\245\26%\332RT\242,\311\222\60K\302(\253\244\1y\315\33\273"
|
||||
"<>)\33\323hx\211Z\242H)%\312\60(a\32\246a\32f\0y\322\33\273<\276\332\230F"
|
||||
"IeHJ-Q\262\24\225(R\342,\15\63\65Q\1z\313\30\273<\336\34L\207CN\10\323\60"
|
||||
"\216r \312\201$\307\302\341 \177\212\27\273<\256\264\26\16\347\34\313\201C\16\344X:\34\324\34K"
|
||||
"\1\201J#\273<\236)\311\222(\311\222d\220\246$K\206A\251#\7)\251EI\62(Q\222%"
|
||||
"\211\62(\0\201\363\27\273<\236\341\232CYZ\33\316\71\226\3\207\34\310\261t\70\10\202\222\30\273<"
|
||||
"\276\332p\320\352H\16\206\303A\312\261\34\313\261\34\33\6\5\206N\34\273<\336A\216\207C\22\205\321"
|
||||
"\60hQ\232D\303\220\344X\64\204QI\21\7\206\307\32\273<\256\60-F\303\243\322\230\64%\203\62"
|
||||
"fqR\213\226l\212\206\0\206\360\36\273<\256\60\33\222A\13\223d\210\224\254\42Ia\64\14Z\224"
|
||||
"e\303 g\311p\11\214\67\32\273<\316(\16KY\224ia\24\207\341\60(J\230da:\254a"
|
||||
"\4\217\233\27\273<\336x\270\245\251\224\3I\70\34\324x\70\347X\216\245\0\217\260\34\273<\256\341\224"
|
||||
"c\311\260\345\330pJ\312I)K\42-\312JI\224db\0\221I\33\273<\216\7\61\311\221\352p"
|
||||
"\252D-Q\264M\71\20\15\247\34\210\206\13\0\225\360\33\273<\256h\30\242X\207\244A\22C\61\224"
|
||||
"\6I\14\305P\31\206D\7\6\226M\36\273<\216!\12\243hX\42)Q\245$\222\246\254\224\14\203"
|
||||
"\322\226$\303 gq\6\226\350\30\273<\216\7\65\307\342\341\224\225\222N\221\247J\247\254\224E\12\0"
|
||||
"\226\352\31\273<\236\341\234\16\217\241\242$J\216\16w,\33\6\35\213\206\13\0\227\34\35\273<\236\341"
|
||||
"\234\16OI\251\66$\203\22e\331\220I%%\31\222NY\66$\0\227\62\36\273<\236\341\234\16O"
|
||||
"Ii\220\206$J\244d\310\304HZ\16I-J\206hH\0\232l\30\273<\236a\320\261\64L\263"
|
||||
"\64L\207;\226c\303)\307rD\1\236!\35\273<~ \33\222AL\262$J\232\222nQ\61\32"
|
||||
"\226r\22\15\212\16\345\210\2\237 \36\272=\216!\31\222\34H\206dHr \31\356\240\244DIE"
|
||||
"\262$J\313\240L\1\237\231\32\273<\316(\7\262\70\36\16b\222#\245\60J\322H\315*\231I\32"
|
||||
"\2\0";
|
||||
|
||||
/*
|
||||
Fontname: -wenquanyi-wenquanyi bitmap song-bold-r-normal--16-160-75-75-P-80-iso10646-1
|
||||
Copyright: (null)
|
||||
Glyphs: 21/29889
|
||||
BBX Build Mode: 0
|
||||
*/
|
||||
const uint8_t u8g2_font_wqy12b_t_lunar[491] U8G2_FONT_SECTION("u8g2_font_wqy12b_t_lunar") =
|
||||
"\25\0\4\3\5\5\3\4\6\20\20\0\376\13\375\14\374\0\0\0\0\0\253\60\16g\25S\231\221P\303"
|
||||
"o$\324\214\0\61\13f\25S\221\31!\322O\14\62\15g\25\323\250\220\241\221R\244W\7\63\21h"
|
||||
"\21\323(\221\221\23\223\222\241SF#R\2\64\25h\21\323\222\32\242\221\20Q!#!#q\20%"
|
||||
"\246\2\0\65\21h\21S\270\20Sf\62\42'&F#R\2\66\24h\21S\241\21\221\20\23\63\31"
|
||||
"\221\20b$!\42C\2\67\21h\21S\70\10\223\22\223\22\223\22S%&\4\70\23h\21S\241\21"
|
||||
"\321\33\32\21\11!F\22\42\62$\0\71\24h\21S\241\21\221\20b$!\62b\246BD\206\4\0"
|
||||
"\0\0\0\4\377\377N\0\10\60\320cx N\11\20\220\21\343\70\270\307\335A=\336\35\34\10N\214"
|
||||
"\15P\61c\71\250\307\237\36\34\10N\224\36\320\361\342\70\270\23\327\364\200PHPHPHPHN"
|
||||
"JNJNJ\346\340@\0Qm \360\361b\223\7\220\7\20\227\207;\70\220G'\42*#(%"
|
||||
"'&%'$)\42*\1V\333\37\256\365bx \242\204D\11\211\22\22%$J(dD(\204"
|
||||
"\16\4+I\17\16H\5^t\37\20\322\342\21\27\77\250\21\22\24\222\223\222<\240\222\221\224\221\224\21"
|
||||
";\70\20\24\327\31\0e\345\20\352\335b\70(\343\331\301\31\237\35\234\11f\37\36\316\365b\71\30\22"
|
||||
"\23:\30\22\23:\30T\42x@\42#&$x\60(,vpg\10&\15\332\342\71\230\21\223\21"
|
||||
"\223\21\223\21\223\71\230\21\223\21\223\21\223\71\230\21\223\21\23\221\23\221\223\20\63\224\0g\37.\17\322"
|
||||
"bQ)\42aq\60\242\205\210\26\42\42\26&*D\264\20\21\261\20\321\302D\205\310\201\211\224\204\214"
|
||||
"\210\10\215\204\220\210\221\12\0\0";
|
||||
37
GUI/fonts.h
Normal file
37
GUI/fonts.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef _FONTS_H
|
||||
#define _FONTS_H
|
||||
|
||||
#include "u8g2_font.h"
|
||||
|
||||
/**
|
||||
* 文字列表:
|
||||
所有 ASCII 字符 (32-128)
|
||||
|
||||
未知
|
||||
农历
|
||||
正月二月三月四月五月六月七月八月九月十月
|
||||
冬月腊月
|
||||
闰
|
||||
初一初二初三初四初五初六初七初八初九初十
|
||||
十一十二十三十四十五十六十七十八十九二十
|
||||
廿一廿二廿三廿四廿五廿六廿七廿八廿九三十
|
||||
日
|
||||
一二三四五六
|
||||
猴鸡狗猪鼠牛虎兔龙蛇马羊
|
||||
庚辛壬癸甲乙丙丁戊已
|
||||
申酉戌亥子丑寅卯辰巳午未
|
||||
小寒大寒立春雨水惊蛰春分清明谷雨立夏小满芒种夏至小暑大暑立秋处暑白露秋分寒露霜降立冬小雪大雪冬至
|
||||
年月日时分秒
|
||||
星期
|
||||
*/
|
||||
extern const uint8_t u8g2_font_wqy9_t_lunar[] U8G2_FONT_SECTION("u8g2_font_wqy9_t_lunar");
|
||||
/**
|
||||
* 文字列表:
|
||||
0123456789
|
||||
年月日
|
||||
星期
|
||||
一二三四五六
|
||||
*/
|
||||
extern const uint8_t u8g2_font_wqy12b_t_lunar[] U8G2_FONT_SECTION("u8g2_font_wqy12b_t_lunar");
|
||||
|
||||
#endif
|
||||
573
GUI/u8g2_font.c
Normal file
573
GUI/u8g2_font.c
Normal file
@@ -0,0 +1,573 @@
|
||||
/*
|
||||
|
||||
U8g2_for_Adafruit_GFX.cpp
|
||||
|
||||
Add unicode support and U8g2 fonts to Adafruit GFX libraries.
|
||||
|
||||
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
|
||||
|
||||
Copyright (c) 2018, olikraus@gmail.com
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "u8g2_font.h"
|
||||
|
||||
static uint8_t u8g2_font_get_byte(const uint8_t *font, uint8_t offset)
|
||||
{
|
||||
font += offset;
|
||||
return u8x8_pgm_read( font );
|
||||
}
|
||||
|
||||
static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset) U8X8_NOINLINE;
|
||||
static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset)
|
||||
{
|
||||
uint16_t pos;
|
||||
font += offset;
|
||||
pos = u8x8_pgm_read( font );
|
||||
font++;
|
||||
pos <<= 8;
|
||||
pos += u8x8_pgm_read( font);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* new font format */
|
||||
void u8g2_read_font_info(u8g2_font_info_t *font_info, const uint8_t *font)
|
||||
{
|
||||
/* offset 0 */
|
||||
font_info->glyph_cnt = u8g2_font_get_byte(font, 0);
|
||||
font_info->bbx_mode = u8g2_font_get_byte(font, 1);
|
||||
font_info->bits_per_0 = u8g2_font_get_byte(font, 2);
|
||||
font_info->bits_per_1 = u8g2_font_get_byte(font, 3);
|
||||
|
||||
/* offset 4 */
|
||||
font_info->bits_per_char_width = u8g2_font_get_byte(font, 4);
|
||||
font_info->bits_per_char_height = u8g2_font_get_byte(font, 5);
|
||||
font_info->bits_per_char_x = u8g2_font_get_byte(font, 6);
|
||||
font_info->bits_per_char_y = u8g2_font_get_byte(font, 7);
|
||||
font_info->bits_per_delta_x = u8g2_font_get_byte(font, 8);
|
||||
|
||||
/* offset 9 */
|
||||
font_info->max_char_width = u8g2_font_get_byte(font, 9);
|
||||
font_info->max_char_height = u8g2_font_get_byte(font, 10);
|
||||
font_info->x_offset = u8g2_font_get_byte(font, 11);
|
||||
font_info->y_offset = u8g2_font_get_byte(font, 12);
|
||||
|
||||
/* offset 13 */
|
||||
font_info->ascent_A = u8g2_font_get_byte(font, 13);
|
||||
font_info->descent_g = u8g2_font_get_byte(font, 14);
|
||||
font_info->ascent_para = u8g2_font_get_byte(font, 15);
|
||||
font_info->descent_para = u8g2_font_get_byte(font, 16);
|
||||
|
||||
/* offset 17 */
|
||||
font_info->start_pos_upper_A = u8g2_font_get_word(font, 17);
|
||||
font_info->start_pos_lower_a = u8g2_font_get_word(font, 19);
|
||||
|
||||
/* offset 21 */
|
||||
font_info->start_pos_unicode = u8g2_font_get_word(font, 21);
|
||||
}
|
||||
|
||||
uint8_t u8g2_GetFontBBXWidth(u8g2_font_t *u8g2)
|
||||
{
|
||||
return u8g2->font_info.max_char_width; /* new font info structure */
|
||||
}
|
||||
|
||||
uint8_t u8g2_GetFontBBXHeight(u8g2_font_t *u8g2)
|
||||
{
|
||||
return u8g2->font_info.max_char_height; /* new font info structure */
|
||||
}
|
||||
|
||||
int8_t u8g2_GetFontBBXOffX(u8g2_font_t *u8g2)
|
||||
{
|
||||
return u8g2->font_info.x_offset; /* new font info structure */
|
||||
}
|
||||
|
||||
int8_t u8g2_GetFontBBXOffY(u8g2_font_t *u8g2)
|
||||
{
|
||||
return u8g2->font_info.y_offset; /* new font info structure */
|
||||
}
|
||||
|
||||
uint8_t u8g2_GetFontCapitalAHeight(u8g2_font_t *u8g2)
|
||||
{
|
||||
return u8g2->font_info.ascent_A; /* new font info structure */
|
||||
}
|
||||
|
||||
static uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t *f, uint8_t cnt) U8X8_NOINLINE;
|
||||
static uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t *f, uint8_t cnt)
|
||||
{
|
||||
uint8_t val;
|
||||
uint8_t bit_pos = f->decode_bit_pos;
|
||||
uint8_t bit_pos_plus_cnt;
|
||||
|
||||
//val = *(f->decode_ptr);
|
||||
val = u8x8_pgm_read( f->decode_ptr );
|
||||
|
||||
val >>= bit_pos;
|
||||
bit_pos_plus_cnt = bit_pos;
|
||||
bit_pos_plus_cnt += cnt;
|
||||
if ( bit_pos_plus_cnt >= 8 )
|
||||
{
|
||||
uint8_t s = 8;
|
||||
s -= bit_pos;
|
||||
f->decode_ptr++;
|
||||
//val |= *(f->decode_ptr) << (8-bit_pos);
|
||||
val |= u8x8_pgm_read( f->decode_ptr ) << (s);
|
||||
//bit_pos -= 8;
|
||||
bit_pos_plus_cnt -= 8;
|
||||
}
|
||||
val &= (1U<<cnt)-1;
|
||||
//bit_pos += cnt;
|
||||
|
||||
f->decode_bit_pos = bit_pos_plus_cnt;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
2 bit --> cnt = 2
|
||||
-2,-1,0. 1
|
||||
|
||||
3 bit --> cnt = 3
|
||||
-2,-1,0. 1
|
||||
-4,-3,-2,-1,0,1,2,3
|
||||
|
||||
if ( x < 0 )
|
||||
r = bits(x-1)+1;
|
||||
else
|
||||
r = bits(x)+1;
|
||||
|
||||
*/
|
||||
/* optimized */
|
||||
static int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cnt) U8X8_NOINLINE;
|
||||
static int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cnt)
|
||||
{
|
||||
int8_t v, d;
|
||||
v = (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt);
|
||||
d = 1;
|
||||
cnt--;
|
||||
d <<= cnt;
|
||||
v -= d;
|
||||
return v;
|
||||
//return (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt) - ((1<<cnt)>>1);
|
||||
}
|
||||
|
||||
|
||||
static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir) U8X8_NOINLINE;
|
||||
static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir)
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
case 0:
|
||||
dy += y;
|
||||
break;
|
||||
case 1:
|
||||
dy += x;
|
||||
break;
|
||||
case 2:
|
||||
dy -= y;
|
||||
break;
|
||||
default:
|
||||
dy -= x;
|
||||
break;
|
||||
}
|
||||
return dy;
|
||||
}
|
||||
|
||||
static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir) U8X8_NOINLINE;
|
||||
static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir)
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
case 0:
|
||||
dx += x;
|
||||
break;
|
||||
case 1:
|
||||
dx -= y;
|
||||
break;
|
||||
case 2:
|
||||
dx -= x;
|
||||
break;
|
||||
default:
|
||||
dx += y;
|
||||
break;
|
||||
}
|
||||
return dx;
|
||||
}
|
||||
|
||||
/*
|
||||
Description:
|
||||
Draw a run-length area of the glyph. "len" can have any size and the line
|
||||
length has to be wrapped at the glyph border.
|
||||
Args:
|
||||
len: Length of the line
|
||||
is_foreground foreground/background?
|
||||
u8g2->font_decode.target_x X position
|
||||
u8g2->font_decode.target_y Y position
|
||||
u8g2->font_decode.is_transparent Transparent mode
|
||||
Return:
|
||||
-
|
||||
Calls:
|
||||
u8g2_Draw90Line()
|
||||
Called by:
|
||||
u8g2_font_decode_glyph()
|
||||
*/
|
||||
/* optimized */
|
||||
static void u8g2_font_decode_len(u8g2_font_t *u8g2, uint8_t len, uint8_t is_foreground)
|
||||
{
|
||||
uint8_t cnt; /* total number of remaining pixels, which have to be drawn */
|
||||
uint8_t rem; /* remaining pixel to the right edge of the glyph */
|
||||
uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */
|
||||
/* current is either equal to cnt or equal to rem */
|
||||
|
||||
/* local coordinates of the glyph */
|
||||
uint8_t lx,ly;
|
||||
|
||||
/* target position on the screen */
|
||||
int16_t x, y;
|
||||
|
||||
u8g2_font_decode_t *decode = &(u8g2->font_decode);
|
||||
|
||||
cnt = len;
|
||||
|
||||
/* get the local position */
|
||||
lx = decode->x;
|
||||
ly = decode->y;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
/* calculate the number of pixel to the right edge of the glyph */
|
||||
rem = decode->glyph_width;
|
||||
rem -= lx;
|
||||
|
||||
/* calculate how many pixel to draw. This is either to the right edge */
|
||||
/* or lesser, if not enough pixel are left */
|
||||
current = rem;
|
||||
if ( cnt < rem )
|
||||
current = cnt;
|
||||
|
||||
|
||||
/* now draw the line, but apply the rotation around the glyph target position */
|
||||
//u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
|
||||
|
||||
/* get target position */
|
||||
x = decode->target_x;
|
||||
y = decode->target_y;
|
||||
|
||||
/* apply rotation */
|
||||
x = u8g2_add_vector_x(x, lx, ly, decode->dir);
|
||||
y = u8g2_add_vector_y(y, lx, ly, decode->dir);
|
||||
|
||||
/* draw foreground and background (if required) */
|
||||
if ( current > 0 ) /* avoid drawing zero length lines, issue #4 */
|
||||
{
|
||||
if ( is_foreground )
|
||||
{
|
||||
u8g2->draw_hv_line(x, y, current, decode->dir, decode->fg_color, u8g2->draw_hv_line_arg);
|
||||
}
|
||||
else if ( decode->is_transparent == 0 )
|
||||
{
|
||||
u8g2->draw_hv_line(x, y, current, decode->dir, decode->bg_color, u8g2->draw_hv_line_arg);
|
||||
}
|
||||
}
|
||||
|
||||
/* check, whether the end of the run length code has been reached */
|
||||
if ( cnt < rem )
|
||||
break;
|
||||
cnt -= rem;
|
||||
lx = 0;
|
||||
ly++;
|
||||
}
|
||||
lx += cnt;
|
||||
|
||||
decode->x = lx;
|
||||
decode->y = ly;
|
||||
|
||||
}
|
||||
|
||||
static void u8g2_font_setup_decode(u8g2_font_t *u8g2, const uint8_t *glyph_data)
|
||||
{
|
||||
u8g2_font_decode_t *decode = &(u8g2->font_decode);
|
||||
decode->decode_ptr = glyph_data;
|
||||
decode->decode_bit_pos = 0;
|
||||
|
||||
/* 8 Nov 2015, this is already done in the glyph data search procedure */
|
||||
/*
|
||||
decode->decode_ptr += 1;
|
||||
decode->decode_ptr += 1;
|
||||
*/
|
||||
|
||||
decode->glyph_width = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_char_width);
|
||||
decode->glyph_height = u8g2_font_decode_get_unsigned_bits(decode,u8g2->font_info.bits_per_char_height);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Description:
|
||||
Decode and draw a glyph.
|
||||
Args:
|
||||
glyph_data: Pointer to the compressed glyph data of the font
|
||||
u8g2->font_decode.target_x X position
|
||||
u8g2->font_decode.target_y Y position
|
||||
u8g2->font_decode.is_transparent Transparent mode
|
||||
Return:
|
||||
Width (delta x advance) of the glyph.
|
||||
Calls:
|
||||
u8g2_font_decode_len()
|
||||
*/
|
||||
/* optimized */
|
||||
static int8_t u8g2_font_decode_glyph(u8g2_font_t *u8g2, const uint8_t *glyph_data)
|
||||
{
|
||||
uint8_t a, b;
|
||||
int8_t x, y;
|
||||
int8_t d;
|
||||
int8_t h;
|
||||
u8g2_font_decode_t *decode = &(u8g2->font_decode);
|
||||
|
||||
u8g2_font_setup_decode(u8g2, glyph_data);
|
||||
h = u8g2->font_decode.glyph_height;
|
||||
|
||||
x = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_x);
|
||||
y = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_y);
|
||||
d = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_delta_x);
|
||||
|
||||
|
||||
if ( decode->glyph_width > 0 )
|
||||
{
|
||||
decode->target_x = u8g2_add_vector_x(decode->target_x, x, -(h+y), decode->dir);
|
||||
decode->target_y = u8g2_add_vector_y(decode->target_y, x, -(h+y), decode->dir);
|
||||
//u8g2_add_vector(&(decode->target_x), &(decode->target_y), x, -(h+y), decode->dir);
|
||||
|
||||
|
||||
/* reset local x/y position */
|
||||
decode->x = 0;
|
||||
decode->y = 0;
|
||||
|
||||
/* decode glyph */
|
||||
for(;;)
|
||||
{
|
||||
a = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_0);
|
||||
b = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_1);
|
||||
do
|
||||
{
|
||||
u8g2_font_decode_len(u8g2, a, 0);
|
||||
u8g2_font_decode_len(u8g2, b, 1);
|
||||
} while( u8g2_font_decode_get_unsigned_bits(decode, 1) != 0 );
|
||||
|
||||
if ( decode->y >= h )
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
Description:
|
||||
Find the starting point of the glyph data.
|
||||
Args:
|
||||
encoding: Encoding (ASCII or Unicode) of the glyph
|
||||
Return:
|
||||
Address of the glyph data or NULL, if the encoding is not avialable in the font.
|
||||
*/
|
||||
const uint8_t *u8g2_font_get_glyph_data(u8g2_font_t *u8g2, uint16_t encoding)
|
||||
{
|
||||
const uint8_t *font = u8g2->font;
|
||||
font += 23;
|
||||
|
||||
|
||||
if ( encoding <= 255 )
|
||||
{
|
||||
if ( encoding >= 'a' )
|
||||
{
|
||||
font += u8g2->font_info.start_pos_lower_a;
|
||||
}
|
||||
else if ( encoding >= 'A' )
|
||||
{
|
||||
font += u8g2->font_info.start_pos_upper_A;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if ( u8x8_pgm_read( font + 1 ) == 0 )
|
||||
break;
|
||||
if ( u8x8_pgm_read( font ) == encoding )
|
||||
{
|
||||
return font+2; /* skip encoding and glyph size */
|
||||
}
|
||||
font += u8x8_pgm_read( font + 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t e;
|
||||
const uint8_t *unicode_lookup_table;
|
||||
/* support for the new unicode lookup table */
|
||||
|
||||
font += u8g2->font_info.start_pos_unicode;
|
||||
unicode_lookup_table = font;
|
||||
|
||||
/* u8g2 issue 596: search for the glyph start in the unicode lookup table */
|
||||
do
|
||||
{
|
||||
font += u8g2_font_get_word(unicode_lookup_table, 0);
|
||||
e = u8g2_font_get_word(unicode_lookup_table, 2);
|
||||
unicode_lookup_table+=4;
|
||||
} while( e < encoding );
|
||||
|
||||
/* variable "font" is now updated according to the lookup table */
|
||||
|
||||
for(;;)
|
||||
{
|
||||
e = u8x8_pgm_read( font );
|
||||
e <<= 8;
|
||||
e |= u8x8_pgm_read( font + 1 );
|
||||
if ( e == 0 )
|
||||
break;
|
||||
if ( e == encoding )
|
||||
{
|
||||
return font+3; /* skip encoding and glyph size */
|
||||
}
|
||||
font += u8x8_pgm_read( font + 2 );
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int16_t u8g2_font_draw_glyph(u8g2_font_t *u8g2, int16_t x, int16_t y, uint16_t encoding)
|
||||
{
|
||||
int16_t dx = 0;
|
||||
u8g2->font_decode.target_x = x;
|
||||
u8g2->font_decode.target_y = y;
|
||||
//u8g2->font_decode.is_transparent = is_transparent; this is already set
|
||||
//u8g2->font_decode.dir = dir;
|
||||
const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, encoding);
|
||||
if ( glyph_data != NULL )
|
||||
{
|
||||
dx = u8g2_font_decode_glyph(u8g2, glyph_data);
|
||||
}
|
||||
return dx;
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
|
||||
uint8_t u8g2_IsGlyph(u8g2_font_t *u8g2, uint16_t requested_encoding)
|
||||
{
|
||||
/* updated to new code */
|
||||
if ( u8g2_font_get_glyph_data(u8g2, requested_encoding) != NULL )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* side effect: updates u8g2->font_decode and u8g2->glyph_x_offset */
|
||||
/* actually u8g2_GetGlyphWidth returns the glyph delta x and glyph width itself is set as side effect */
|
||||
int8_t u8g2_GetGlyphWidth(u8g2_font_t *u8g2, uint16_t requested_encoding)
|
||||
{
|
||||
const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, requested_encoding);
|
||||
if ( glyph_data == NULL )
|
||||
return 0;
|
||||
|
||||
u8g2_font_setup_decode(u8g2, glyph_data);
|
||||
u8g2->glyph_x_offset = u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_x);
|
||||
u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_y);
|
||||
|
||||
/* glyph width is here: u8g2->font_decode.glyph_width */
|
||||
return u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_delta_x);
|
||||
}
|
||||
|
||||
|
||||
void u8g2_SetFontMode(u8g2_font_t *u8g2, uint8_t is_transparent)
|
||||
{
|
||||
u8g2->font_decode.is_transparent = is_transparent; // new font procedures
|
||||
}
|
||||
|
||||
void u8g2_SetFontDirection(u8g2_font_t *u8g2, uint8_t dir)
|
||||
{
|
||||
u8g2->font_decode.dir = dir;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int16_t u8g2_DrawGlyph(u8g2_font_t *u8g2, int16_t x, int16_t y, uint16_t encoding)
|
||||
{
|
||||
return u8g2_font_draw_glyph(u8g2, x, y, encoding);
|
||||
}
|
||||
|
||||
int16_t u8g2_DrawStr(u8g2_font_t *u8g2, int16_t x, int16_t y, const char *s)
|
||||
{
|
||||
int16_t sum, delta;
|
||||
sum = 0;
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
delta = u8g2_DrawGlyph(u8g2, x, y, *s);
|
||||
switch(u8g2->font_decode.dir)
|
||||
{
|
||||
case 0:
|
||||
x += delta;
|
||||
break;
|
||||
case 1:
|
||||
y += delta;
|
||||
break;
|
||||
case 2:
|
||||
x -= delta;
|
||||
break;
|
||||
case 3:
|
||||
y -= delta;
|
||||
break;
|
||||
}
|
||||
sum += delta;
|
||||
s++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void u8g2_SetFont(u8g2_font_t *u8g2, const uint8_t *font)
|
||||
{
|
||||
if ( u8g2->font != font )
|
||||
{
|
||||
u8g2->font = font;
|
||||
u8g2->font_decode.is_transparent = 0;
|
||||
|
||||
u8g2_read_font_info(&(u8g2->font_info), font);
|
||||
}
|
||||
}
|
||||
|
||||
void u8g2_SetForegroundColor(u8g2_font_t *u8g2, uint16_t fg)
|
||||
{
|
||||
u8g2->font_decode.fg_color = fg;
|
||||
}
|
||||
|
||||
void u8g2_SetBackgroundColor(u8g2_font_t *u8g2, uint16_t bg)
|
||||
{
|
||||
u8g2->font_decode.bg_color = bg;
|
||||
}
|
||||
157
GUI/u8g2_font.h
Normal file
157
GUI/u8g2_font.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
|
||||
U8g2_for_Adafruit_GFX.h
|
||||
|
||||
Add unicode support and U8g2 fonts to Adafruit GFX libraries.
|
||||
|
||||
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
|
||||
|
||||
Copyright (c) 2018, olikraus@gmail.com
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __U8G2_H
|
||||
#define __U8G2_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define U8X8_NOINLINE __attribute__((noinline))
|
||||
# define U8X8_SECTION(name) __attribute__ ((section (name)))
|
||||
# define U8X8_UNUSED __attribute__((unused))
|
||||
#else
|
||||
# define U8X8_SECTION(name)
|
||||
# define U8X8_NOINLINE
|
||||
# define U8X8_UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(__AVR__)
|
||||
# define U8X8_FONT_SECTION(name) U8X8_SECTION(".progmem." name)
|
||||
# define u8x8_pgm_read(adr) pgm_read_byte_near(adr)
|
||||
# define U8X8_PROGMEM PROGMEM
|
||||
#endif
|
||||
|
||||
#ifndef U8X8_FONT_SECTION
|
||||
# define U8X8_FONT_SECTION(name)
|
||||
#endif
|
||||
|
||||
#ifndef u8x8_pgm_read
|
||||
# define u8x8_pgm_read(adr) (*(const uint8_t *)(adr))
|
||||
#endif
|
||||
|
||||
#ifndef U8X8_PROGMEM
|
||||
# define U8X8_PROGMEM
|
||||
#endif
|
||||
|
||||
#define U8G2_FONT_SECTION(name) U8X8_FONT_SECTION(name)
|
||||
|
||||
/* the macro U8G2_USE_LARGE_FONTS enables large fonts (>32K) */
|
||||
/* it can be enabled for those uC supporting larger arrays */
|
||||
#if defined(unix) || defined(__arm__) || defined(__arc__) || defined(ESP8266) || defined(ESP_PLATFORM)
|
||||
#ifndef U8G2_USE_LARGE_FONTS
|
||||
#define U8G2_USE_LARGE_FONTS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct _u8g2_font_info_t
|
||||
{
|
||||
/* offset 0 */
|
||||
uint8_t glyph_cnt;
|
||||
uint8_t bbx_mode;
|
||||
uint8_t bits_per_0;
|
||||
uint8_t bits_per_1;
|
||||
|
||||
/* offset 4 */
|
||||
uint8_t bits_per_char_width;
|
||||
uint8_t bits_per_char_height;
|
||||
uint8_t bits_per_char_x;
|
||||
uint8_t bits_per_char_y;
|
||||
uint8_t bits_per_delta_x;
|
||||
|
||||
/* offset 9 */
|
||||
int8_t max_char_width;
|
||||
int8_t max_char_height; /* overall height, NOT ascent. Instead ascent = max_char_height + y_offset */
|
||||
int8_t x_offset;
|
||||
int8_t y_offset;
|
||||
|
||||
/* offset 13 */
|
||||
int8_t ascent_A;
|
||||
int8_t descent_g; /* usually a negative value */
|
||||
int8_t ascent_para;
|
||||
int8_t descent_para;
|
||||
|
||||
/* offset 17 */
|
||||
uint16_t start_pos_upper_A;
|
||||
uint16_t start_pos_lower_a;
|
||||
|
||||
/* offset 21 */
|
||||
uint16_t start_pos_unicode;
|
||||
} u8g2_font_info_t;
|
||||
|
||||
typedef struct _u8g2_font_decode_t
|
||||
{
|
||||
const uint8_t *decode_ptr; /* pointer to the compressed data */
|
||||
|
||||
int16_t target_x;
|
||||
int16_t target_y;
|
||||
uint16_t fg_color;
|
||||
uint16_t bg_color;
|
||||
|
||||
int8_t x; /* local coordinates, (0,0) is upper left */
|
||||
int8_t y;
|
||||
int8_t glyph_width;
|
||||
int8_t glyph_height;
|
||||
|
||||
uint8_t decode_bit_pos; /* bitpos inside a byte of the compressed data */
|
||||
uint8_t is_transparent;
|
||||
uint8_t dir; /* direction */
|
||||
} u8g2_font_decode_t;
|
||||
|
||||
typedef struct _u8g2_font_t
|
||||
{
|
||||
const uint8_t *font; /* current font for all text procedures */
|
||||
|
||||
u8g2_font_decode_t font_decode; /* new font decode structure */
|
||||
u8g2_font_info_t font_info; /* new font info structure */
|
||||
|
||||
int8_t glyph_x_offset; /* set by u8g2_GetGlyphWidth as a side effect */
|
||||
|
||||
void *draw_hv_line_arg;
|
||||
void (*draw_hv_line)(int16_t x, int16_t y, int16_t len, uint8_t dir, uint16_t color, void *arg);
|
||||
} u8g2_font_t;
|
||||
|
||||
uint8_t u8g2_IsGlyph(u8g2_font_t *u8g2, uint16_t requested_encoding);
|
||||
int8_t u8g2_GetGlyphWidth(u8g2_font_t *u8g2, uint16_t requested_encoding);
|
||||
void u8g2_SetFontMode(u8g2_font_t *u8g2, uint8_t is_transparent);
|
||||
void u8g2_SetFontDirection(u8g2_font_t *u8g2, uint8_t dir);
|
||||
int16_t u8g2_DrawGlyph(u8g2_font_t *u8g2, int16_t x, int16_t y, uint16_t encoding);
|
||||
int16_t u8g2_DrawStr(u8g2_font_t *u8g2, int16_t x, int16_t y, const char *s);
|
||||
void u8g2_SetFont(u8g2_font_t *u8g2, const uint8_t *font);
|
||||
void u8g2_SetForegroundColor(u8g2_font_t *u8g2, uint16_t fg);
|
||||
void u8g2_SetBackgroundColor(u8g2_font_t *u8g2, uint16_t bg);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user