Graphics: You can now do g.fillRect({x,y,x2,y2,r}) for rounded rectangles

This commit is contained in:
Gordon Williams 2022-02-11 11:01:27 +00:00
parent 3064ca5653
commit 9c5e5f2355
4 changed files with 65 additions and 16 deletions

View File

@ -17,6 +17,7 @@
g.wrapString now splits long words if they are too long for a line
Add Storage.getStats to get more fine-grained info about Storage
Add Bangle.midnight event that can be used for housekeeping tasks
Graphics: You can now do `g.fillRect({x,y,x2,y2,r})` for rounded rectangles
2v12 : nRF52840: Flow control XOFF is now sent at only 3/8th full - delays in BLE mean we can sometimes fill our 1k input buffer otherwise
__FILE__ is now set correctly for apps (fixes 2v11 regression)

View File

@ -425,7 +425,7 @@ static void graphicsSetPixelDeviceBlended(JsGraphics *gfx, int x, int y, int amt
graphicsSetPixelDevice(gfx, x, y, col);
}
static void graphicsFillRectDevice(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col) {
void graphicsFillRectDevice(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col) {
if (x1>x2) {
int t = x1;
x1 = x2;

View File

@ -206,6 +206,7 @@ unsigned int graphicsGetPixel(JsGraphics *gfx, int x, int y);
void graphicsClear(JsGraphics *gfx);
void graphicsFillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col);
void graphicsFallbackFillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col); // Simple fillrect - doesn't call device-specific FR
void graphicsFillRectDevice(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col); // fillrect using device coordinates
void graphicsFallbackScroll(JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2);
void graphicsDrawRect(JsGraphics *gfx, int x1, int y1, int x2, int y2);
void graphicsDrawEllipse(JsGraphics *gfx, int x, int y, int x2, int y2);

View File

@ -901,7 +901,8 @@ JsVar *jswrap_graphics_clear(JsVar *parent, bool resetState) {
return jsvLockAgain(parent);
}
void _jswrap_graphics_getRect(JsVar *opt, int *x1, int *y1, int *x2, int *y2) {
void _jswrap_graphics_getRect(JsVar *opt, int *x1, int *y1, int *x2, int *y2, int *r) {
*r = 0;
if (jsvIsObject(opt)) {
int w = -1,h = -1;
jsvConfigObject configs[] = {
@ -913,6 +914,7 @@ void _jswrap_graphics_getRect(JsVar *opt, int *x1, int *y1, int *x2, int *y2) {
{"y2", JSV_INTEGER, y2},
{"w", JSV_INTEGER, &w},
{"h", JSV_INTEGER, &h},
{"r", JSV_INTEGER, r}
};
jsvReadConfigObject(opt, configs, sizeof(configs) / sizeof(jsvConfigObject));
if (w>=0) *x2 = *x1 + w;
@ -921,6 +923,53 @@ void _jswrap_graphics_getRect(JsVar *opt, int *x1, int *y1, int *x2, int *y2) {
*x1 = jsvGetInteger(opt);
}
JsVar *_jswrap_graphics_fillRect_col(JsVar *parent, JsVar *opt, int y1, int x2, int y2, bool isFgCol) {
int x1, r;
_jswrap_graphics_getRect(opt, &x1, &y1, &x2, &y2, &r);
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
uint32_t col = isFgCol ? gfx.data.fgColor : gfx.data.bgColor;
#ifndef SAVE_ON_FLASH
if (r>0) {
// rounded rects
graphicsToDeviceCoordinates(&gfx, &x1, &y1);
graphicsToDeviceCoordinates(&gfx, &x2, &y2);
int x,y;
if (x1 > x2) { x = x1; x1 = x2; x2 = x; }
if (y1 > y2) { y = y1; y1 = y2; y2 = y; }
// clip if radius too big
x = (x2-x1)/2;
y = (y2-y1)/2;
if (x<r) r=x;
if (y<r) r=y;
// rect in middle
int cx1 = x1+r, cx2 = x2-r;
int cy1 = y1+r, cy2 = y2-r;
graphicsFillRectDevice(&gfx, x1, cy1, x2, cy2, col);
// draw rounded top and bottom
int dx = 0;
int dy = r;
int r2 = r*r;
int err = r2-(2*r-1)*r2;
int e2;
bool changed = false;
do {
changed = false;
e2 = 2*err;
if (e2 < (2*dx+1)*r2) { dx++; err += (2*dx+1)*r2; changed=true; }
if (e2 > -(2*dy-1)*r2) {
// draw only just before we change Y, to avoid a bunch of overdraw
graphicsFillRectDevice(&gfx, cx1-dx,cy2+dy, cx2+dx,cy2+dy, col);
graphicsFillRectDevice(&gfx, cx1-dx,cy1-dy, cx2+dx,cy1-dy, col);
dy--; err -= (2*dy-1)*r2; changed=true;
}
} while (changed && dy >= 0);
} else
#endif
graphicsFillRect(&gfx, x1,y1,x2,y2,col);
graphicsSetVar(&gfx); // gfx data changed because modified area
return jsvLockAgain(parent);
}
/*JSON{
"type" : "method",
"class" : "Graphics",
@ -936,16 +985,16 @@ void _jswrap_graphics_getRect(JsVar *opt, int *x1, int *y1, int *x2, int *y2) {
"return_object" : "Graphics"
}
Fill a rectangular area in the Foreground Color
On devices with enough memory, you can specify `{x,y,x2,y2,r}` as the first
argument, which allows you to draw a rounded rectangle.
*/
JsVar *jswrap_graphics_fillRect(JsVar *parent, JsVar *opt, int y1, int x2, int y2) {
int x1;
_jswrap_graphics_getRect(opt, &x1, &y1, &x2, &y2);
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
graphicsFillRect(&gfx, x1,y1,x2,y2,gfx.data.fgColor);
graphicsSetVar(&gfx); // gfx data changed because modified area
return jsvLockAgain(parent);
return _jswrap_graphics_fillRect_col(parent,opt,y1,x2,y2,true);
}
/*JSON{
"type" : "method",
"class" : "Graphics",
@ -962,14 +1011,12 @@ JsVar *jswrap_graphics_fillRect(JsVar *parent, JsVar *opt, int y1, int x2, int y
"return_object" : "Graphics"
}
Fill a rectangular area in the Background Color
On devices with enough memory, you can specify `{x,y,x2,y2,r}` as the first
argument, which allows you to draw a rounded rectangle.
*/
JsVar *jswrap_graphics_clearRect(JsVar *parent, JsVar *opt, int y1, int x2, int y2) {
int x1;
_jswrap_graphics_getRect(opt, &x1, &y1, &x2, &y2);
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
graphicsFillRect(&gfx, x1,y1,x2,y2,gfx.data.bgColor);
graphicsSetVar(&gfx); // gfx data changed because modified area
return jsvLockAgain(parent);
return _jswrap_graphics_fillRect_col(parent,opt,y1,x2,y2,false);
}
/*JSON{
@ -989,8 +1036,8 @@ JsVar *jswrap_graphics_clearRect(JsVar *parent, JsVar *opt, int y1, int x2, int
Draw an unfilled rectangle 1px wide in the Foreground Color
*/
JsVar *jswrap_graphics_drawRect(JsVar *parent, JsVar *opt, int y1, int x2, int y2) {
int x1;
_jswrap_graphics_getRect(opt, &x1, &y1, &x2, &y2);
int x1, r;
_jswrap_graphics_getRect(opt, &x1, &y1, &x2, &y2, &r);
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
graphicsDrawRect(&gfx, x1,y1,x2,y2);
graphicsSetVar(&gfx); // gfx data changed because modified area