Setting up rounded rectangles support

This commit is contained in:
Clément Grennerat
2025-09-15 14:32:20 +02:00
parent 0017804193
commit 13c4e50264
11 changed files with 2046 additions and 882 deletions
+282 -64
View File
@@ -96,6 +96,7 @@ void LCD_Init(void) {
LCD_Write_Command(0x36);
LCD_Write_Data(0b00111100);
// Exit sleep
LCD_Write_Command(0x11);
HAL_Delay(150);
@@ -105,24 +106,24 @@ void LCD_Init(void) {
HAL_Delay(400);
// Fill white
LCD_Fill_Screen(WHITE);
// Draw colors columns
LCD_Set_Address(30, 30, LCD_WIDTH - 30, LCD_HEIGHT - 30);
uint32_t size = (LCD_WIDTH - 59) * 20;
LCD_Draw_Colour_Burst(BLACK, size);
LCD_Draw_Colour_Burst(WHITE, size);
LCD_Draw_Colour_Burst(BLUE, size);
LCD_Draw_Colour_Burst(GREEN, size);
LCD_Draw_Colour_Burst(RED, size);
LCD_Draw_Colour_Burst(BLACK, 4 * size);
// Draw rectangles in the angles
LCD_Draw_Rectangle(1, 1, 20, 20, RED);
LCD_Draw_Rectangle(LCD_WIDTH - 21, 1, 20, 20, GREEN);
LCD_Draw_Rectangle(LCD_WIDTH - 21, LCD_HEIGHT - 21, 20, 20,
BLACK);
LCD_Draw_Rectangle(1, LCD_HEIGHT - 21, 20, 20, BLUE);
// LCD_Fill_Screen(WHITE);
//
//// Draw colors columns
// LCD_Set_Address(30, 30, LCD_WIDTH - 30, LCD_HEIGHT - 30);
// uint32_t size = (LCD_WIDTH - 59) * 20;
// LCD_Draw_Colour_Burst(BLACK, size);
// LCD_Draw_Colour_Burst(WHITE, size);
// LCD_Draw_Colour_Burst(BLUE, size);
// LCD_Draw_Colour_Burst(GREEN, size);
// LCD_Draw_Colour_Burst(RED, size);
// LCD_Draw_Colour_Burst(BLACK, 4 * size);
//
//// Draw rectangles in the angles
// LCD_Draw_Rectangle(1, 1, 20, 20, RED);
// LCD_Draw_Rectangle(LCD_WIDTH - 21, 1, 20, 20, GREEN);
// LCD_Draw_Rectangle(LCD_WIDTH - 21, LCD_HEIGHT - 21, 20, 20,
// BLACK);
// LCD_Draw_Rectangle(1, LCD_HEIGHT - 21, 20, 20, BLUE);
}
@@ -140,8 +141,11 @@ void LCD_Draw_Colour_Burst(uint16_t color, uint32_t size) {
}
}
void LCD_Fill_Screen(uint16_t color) {
LCD_Draw_Rectangle(0, 0, LCD_WIDTH, LCD_HEIGHT, color);
void LCD_Fill_Screen(uint16_t color, uint8_t full_screen) {
uint16_t height = full_screen ? LCD_FULL_HEIGHT : LCD_HEIGHT;
LCD_Set_Address(0, 0, LCD_WIDTH - 1, height - 1);
LCD_Draw_Colour_Burst(color, LCD_WIDTH * height);
}
void LCD_Draw_Pixel(uint16_t x, uint16_t y, uint16_t color) {
@@ -263,49 +267,6 @@ void LCD_Draw_Filled_Circle(
//TODO: https://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles
}
void LCD_Draw_Hollow_Rectangle_Coord(
uint16_t X0,
uint16_t Y0,
uint16_t X1,
uint16_t Y1,
uint16_t Colour) {
uint16_t X_length = 0;
uint16_t Y_length = 0;
uint8_t Negative_X = 0;
uint8_t Negative_Y = 0;
float Calc_Negative = 0;
Calc_Negative = X1 - X0;
if (Calc_Negative < 0) Negative_X = 1;
Calc_Negative = 0;
Calc_Negative = Y1 - Y0;
if (Calc_Negative < 0) Negative_Y = 1;
//DRAW HORIZONTAL!
if (!Negative_X) {
X_length = X1 - X0;
} else {
X_length = X0 - X1;
}
LCD_Draw_Horizontal_Line(X0, Y0, X_length, Colour);
LCD_Draw_Horizontal_Line(X0, Y1, X_length, Colour);
//DRAW VERTICAL!
if (!Negative_Y) {
Y_length = Y1 - Y0;
} else {
Y_length = Y0 - Y1;
}
LCD_Draw_Vertical_Line(X0, Y0, Y_length, Colour);
LCD_Draw_Vertical_Line(X1, Y0, Y_length, Colour);
if ((X_length > 0) || (Y_length > 0)) {
LCD_Draw_Pixel(X1, Y1, Colour);
}
}
void LCD_Draw_Filled_Rectangle_Coord(
uint16_t X0,
uint16_t Y0,
@@ -330,7 +291,7 @@ void LCD_Draw_Filled_Rectangle_Coord(
//DRAW HORIZONTAL!
if (!Negative_X) {
X_length = X1 - X0;
X_length = X1 - X0 + 1;
X0_true = X0;
} else {
X_length = X0 - X1;
@@ -414,3 +375,260 @@ void LCD_Draw_Filled_Rectangle_Coord(
// while ((SPI3->SR & SPI_SR_BSY) != 0);//Attendre fin envoi trame
// CS_OFF;
//}
void LCD_DrawHollowRoundRect(
uint16_t x,
uint16_t y,
uint16_t w,
uint16_t h,
uint8_t radius_top,
uint8_t radius_bottom,
uint8_t border_width,
uint16_t color,
uint16_t fill_color,
uint8_t do_fill) {
uint8_t radius_top_lines = radius_top ? radius_top - 1 : 0;
uint8_t radius_bottom_lines = radius_bottom ? radius_bottom - 1 : 0;
// Fill interior if requested
if (do_fill) {
uint16_t x_inner, y_inner, w_inner, h_inner;
uint8_t radius_top_fill, radius_bottom_fill;
if (border_width == 0) {
// Full area fill (no border)
x_inner = x;
y_inner = y;
w_inner = w;
h_inner = h;
radius_top_fill = radius_top;
radius_bottom_fill = radius_bottom;
} else {
// Interior area (inside border)
x_inner = x + border_width;
y_inner = y + border_width;
w_inner = (w > 2 * border_width) ? w - 2 * border_width : 0;
h_inner = (h > 2 * border_width) ? h - 2 * border_width : 0;
radius_top_fill = (radius_top > border_width) ? radius_top - border_width : 0;
radius_bottom_fill = (radius_bottom > border_width) ? radius_bottom - border_width : 0;
}
// Draw filled interior (only if dimensions are valid)
if (w_inner > 0 && h_inner > 0) {
uint16_t x_central = x_inner + radius_top_fill;
uint16_t y_central = y;
uint16_t w_central = w_inner - 2*radius_top_fill;
uint16_t h_central = h;
LCD_Draw_Rectangle(x_central, y_central, w_central, h_central, fill_color);
uint16_t x_left = x;
uint16_t y_left = y_inner + radius_top_fill;
uint16_t w_left = x_inner + radius_top_fill + 1 - x;
uint16_t h_left = h_inner - radius_bottom_fill - radius_top_fill;
LCD_Draw_Rectangle(x_left, y_left, w_left, h_left, fill_color);
uint16_t x_right = x + w - w_left;
LCD_Draw_Rectangle(x_right, y_left, w_left, h_left, fill_color);
// Top-left rounded corner
if (radius_top_fill > 0) {
uint32_t r_sq = (uint32_t)radius_top_fill * radius_top_fill;
int16_t center_x = x_inner + radius_top_fill - 1;
int16_t center_y = y_inner + radius_top_fill - 1;
for (int16_t i = x_inner; i < x_inner + radius_top_fill; i++) {
for (int16_t j = y_inner; j < y_inner + radius_top_fill; j++) {
int16_t dx = center_x - i;
int16_t dy = center_y - j;
uint32_t dist_sq = (uint32_t)dx * dx + (uint32_t)dy * dy;
if (dist_sq <= r_sq) {
LCD_Draw_Pixel(i, j, fill_color);
}
}
}
}
// Top-right rounded corner
if (radius_top_fill > 0) {
uint32_t r_sq = (uint32_t)radius_top_fill * radius_top_fill;
int16_t center_x = x_inner + w_inner - radius_top_fill;
int16_t center_y = y_inner + radius_top_fill - 1;
for (int16_t i = x_inner + w_inner - radius_top_fill; i < x_inner + w_inner; i++) {
for (int16_t j = y_inner; j < y_inner + radius_top_fill; j++) {
int16_t dx = i - center_x;
int16_t dy = center_y - j;
uint32_t dist_sq = (uint32_t)dx * dx + (uint32_t)dy * dy;
if (dist_sq <= r_sq) {
LCD_Draw_Pixel(i, j, fill_color);
}
}
}
}
// Bottom-left rounded corner
if (radius_bottom_fill > 0) {
uint32_t r_sq = (uint32_t)radius_bottom_fill * radius_bottom_fill;
int16_t center_x = x_inner + radius_bottom_fill - 1;
int16_t center_y = y_inner + h_inner - radius_bottom_fill;
for (int16_t i = x_inner; i < x_inner + radius_bottom_fill; i++) {
for (int16_t j = y_inner + h_inner - radius_bottom_fill; j < y_inner + h_inner; j++) {
int16_t dx = center_x - i;
int16_t dy = j - center_y;
uint32_t dist_sq = (uint32_t)dx * dx + (uint32_t)dy * dy;
if (dist_sq <= r_sq) {
LCD_Draw_Pixel(i, j, fill_color);
}
}
}
}
// Bottom-right rounded corner
if (radius_bottom_fill > 0) {
uint32_t r_sq = (uint32_t)radius_bottom_fill * radius_bottom_fill;
int16_t center_x = x_inner + w_inner - radius_bottom_fill;
int16_t center_y = y_inner + h_inner - radius_bottom_fill;
for (int16_t i = x_inner + w_inner - radius_bottom_fill; i < x_inner + w_inner; i++) {
for (int16_t j = y_inner + h_inner - radius_bottom_fill; j < y_inner + h_inner; j++) {
int16_t dx = i - center_x;
int16_t dy = j - center_y;
uint32_t dist_sq = (uint32_t)dx * dx + (uint32_t)dy * dy;
if (dist_sq <= r_sq) {
LCD_Draw_Pixel(i, j, fill_color);
}
}
}
}
}
}
// Draw border only if requested (border_width > 0)
if (border_width > 0) {
// Top horizontal border segment
if (w > 2 * radius_top_lines) {
uint16_t x_top = x + radius_top_lines;
uint16_t y_top = y;
uint16_t w_top = w - 2 * radius_top_lines;
uint16_t h_top = border_width;
LCD_Draw_Rectangle(x_top, y_top, w_top, h_top, color);
}
// Bottom horizontal border segment
if (w > 2 * radius_bottom_lines) {
uint16_t x_bottom = x + radius_bottom_lines;
uint16_t y_bottom = y + h - border_width;
uint16_t w_bottom = w - 2 * radius_bottom_lines;
uint16_t h_bottom = border_width;
LCD_Draw_Rectangle(x_bottom, y_bottom, w_bottom, h_bottom, color);
}
// Left vertical border segment
if (h > radius_top_lines + radius_bottom_lines) {
uint16_t x_left = x;
uint16_t y_left = y + radius_top_lines;
uint16_t w_left = border_width;
uint16_t h_left = h - radius_top_lines - radius_bottom_lines;
LCD_Draw_Rectangle(x_left, y_left, w_left, h_left, color);
}
// Right vertical border segment
if (h > radius_top_lines + radius_bottom_lines) {
uint16_t x_right = x + w - border_width;
uint16_t y_right = y + radius_top_lines;
uint16_t w_right = border_width;
uint16_t h_right = h - radius_top_lines - radius_bottom_lines;
LCD_Draw_Rectangle(x_right, y_right, w_right, h_right, color);
}
// Top-left rounded corner
if (radius_top > 0) {
int16_t inner_radius = radius_top - border_width;
if (inner_radius < 0) inner_radius = 0;
uint32_t inner_sq = (uint32_t)inner_radius * inner_radius;
uint32_t outer_sq = (uint32_t)radius_top * radius_top;
int16_t center_x = x + radius_top - 1;
int16_t center_y = y + radius_top - 1;
for (int16_t i = x; i < x + radius_top; i++) {
for (int16_t j = y; j < y + radius_top; j++) {
int16_t dx = center_x - i;
int16_t dy = center_y - j;
uint32_t dist_sq = (uint32_t)dx * dx + (uint32_t)dy * dy;
if (dist_sq <= outer_sq && dist_sq > inner_sq) {
LCD_Draw_Pixel(i, j, color);
}
}
}
}
// Top-right rounded corner
if (radius_top > 0) {
int16_t inner_radius = radius_top - border_width;
if (inner_radius < 0) inner_radius = 0;
uint32_t inner_sq = (uint32_t)inner_radius * inner_radius;
uint32_t outer_sq = (uint32_t)radius_top * radius_top;
int16_t center_x = x + w - radius_top;
int16_t center_y = y + radius_top - 1;
for (int16_t i = x + w - radius_top; i < x + w; i++) {
for (int16_t j = y; j < y + radius_top; j++) {
int16_t dx = i - center_x;
int16_t dy = center_y - j;
uint32_t dist_sq = (uint32_t)dx * dx + (uint32_t)dy * dy;
if (dist_sq <= outer_sq && dist_sq > inner_sq) {
LCD_Draw_Pixel(i, j, color);
}
}
}
}
// Bottom-left rounded corner
if (radius_bottom > 0) {
int16_t inner_radius = radius_bottom - border_width;
if (inner_radius < 0) inner_radius = 0;
uint32_t inner_sq = (uint32_t)inner_radius * inner_radius;
uint32_t outer_sq = (uint32_t)radius_bottom * radius_bottom;
int16_t center_x = x + radius_bottom - 1;
int16_t center_y = y + h - radius_bottom;
for (int16_t i = x; i < x + radius_bottom; i++) {
for (int16_t j = y + h - radius_bottom; j < y + h; j++) {
int16_t dx = center_x - i;
int16_t dy = j - center_y;
uint32_t dist_sq = (uint32_t)dx * dx + (uint32_t)dy * dy;
if (dist_sq <= outer_sq && dist_sq > inner_sq) {
LCD_Draw_Pixel(i, j, color);
}
}
}
}
// Bottom-right rounded corner
if (radius_bottom > 0) {
int16_t inner_radius = radius_bottom - border_width;
if (inner_radius < 0) inner_radius = 0;
uint32_t inner_sq = (uint32_t)inner_radius * inner_radius;
uint32_t outer_sq = (uint32_t)radius_bottom * radius_bottom;
int16_t center_x = x + w - radius_bottom;
int16_t center_y = y + h - radius_bottom;
for (int16_t i = x + w - radius_bottom; i < x + w; i++) {
for (int16_t j = y + h - radius_bottom; j < y + h; j++) {
int16_t dx = i - center_x;
int16_t dy = j - center_y;
uint32_t dist_sq = (uint32_t)dx * dx + (uint32_t)dy * dy;
if (dist_sq <= outer_sq && dist_sq > inner_sq) {
LCD_Draw_Pixel(i, j, color);
}
}
}
}
}
}
+54 -22
View File
@@ -1,12 +1,14 @@
#include "dashboard.h"
#include "font.h"
#include "monomaniacone12pt.h"
#include "monomaniacone14pt.h"
#include "monomaniacone20pt.h"
#include "monomaniacone72pt.h"
void run_dashboard_loop() {
init();
while(1) {
while (1) {
}
@@ -14,31 +16,61 @@ void run_dashboard_loop() {
void init() {
LCD_Init();
// draw base
// Test drawing text
//char text[] = "test bro";
//LCD_Draw_Text(&text, 30, 100, WHITE, 20, RED);
GFX_DrawChar(40, 40, '!', &monomaniacone20pt, BLACK, WHITE);
GFX_DrawChar(60, 40, '2', &monomaniacone20pt, BLACK, WHITE);
GFX_DrawChar(80, 40, '3', &monomaniacone20pt, BLACK, WHITE);
GFX_DrawChar(100, 40, '4', &monomaniacone20pt, BLACK, WHITE);
GFX_DrawChar(120, 40, '5', &monomaniacone20pt, BLACK, WHITE);
GFX_DrawText(470/2, 150, "BONJOUR !", &monomaniacone20pt, RED, BLACK, 1);
GFX_DrawText(470/2, 250, "01234", &monomaniacone72pt, ORANGE, BLACK, 1);
draw_init();
}
void update_values() {
// UART send 0201 04 4084 03
// UART send 0201 04 4084 03
}
void update_values_setup() {
// UART send 0201 2F D58D 03
// UART send 0201 2F D58D 03
}
void update_adc() {
// UART send 0201 20 2462 03
// UART send 0201 20 2462 03
}
void LCD_DrawHollowRoundRect(
uint16_t x,
uint16_t y,
uint16_t w,
uint16_t h,
uint8_t radius_top,
uint8_t radius_bottom,
uint8_t border_width,
uint16_t color,
uint16_t fill_color,
uint8_t do_fill);
void draw_init() {
LCD_Fill_Screen(COLOR_OFF, 1);
LCD_Fill_Screen(COLOR_BG, 0);
GFX_DrawChar(40, 40, '!', &monomaniacone20pt, COLOR_PRIMARY, COLOR_BG);
GFX_DrawChar(60, 40, '2', &monomaniacone20pt, COLOR_PRIMARY, COLOR_BG);
GFX_DrawChar(80, 40, '3', &monomaniacone20pt, COLOR_SECONDARY, COLOR_BG);
GFX_DrawChar(100, 40, '4', &monomaniacone20pt, COLOR_SECONDARY, COLOR_BG);
GFX_DrawChar(120, 40, '5', &monomaniacone20pt, COLOR_ERROR, COLOR_BG);
GFX_DrawText(LCD_WIDTH / 2, 50, "Bonjour Monsieur !", &monomaniacone12pt,
COLOR_SECONDARY, COLOR_BG, 1, -2);
GFX_DrawText(LCD_WIDTH / 2, 70, "Bonjour Monsieur !", &monomaniacone14pt,
COLOR_SECONDARY, COLOR_BG, 1, -2);
GFX_DrawText(LCD_WIDTH / 2, 100, "Bonjour MONSieur !", &monomaniacone20pt,
COLOR_SUCCESS, COLOR_BG, 1, -2);
GFX_DrawText(LCD_WIDTH / 2, 26+95, "12", &monomaniacone72pt, COLOR_FG, COLOR_BG, 1, -5);
// Draw a rectangle with different top/bottom radii
LCD_DrawHollowRoundRect(10, 10, 100, 50, 10, 0, 4, BLACK, COLOR_PRIMARY, 1);
// Draw a pill-shaped rectangle (same radius for all corners)
LCD_DrawHollowRoundRect(20, 70, 80, 30, 15, 15, 2, COLOR_SUCCESS, 0, 0);
// Draw a square with rounded corners
LCD_DrawHollowRoundRect(50, 100, 60, 60, 10, 10, 6, COLOR_ERROR, 0, 0);
LCD_DrawHollowRoundRect(130, 100, 60, 60, 10, 10, 0, 0, COLOR_ERROR, 1);
LCD_DrawHollowRoundRect(136, 106, 48, 48, 4, 4, 0, 0, COLOR_PRIMARY, 1);
uint16_t bar_width = LCD_WIDTH - 12;
LCD_DrawHollowRoundRect(4, LCD_HEIGHT - 30, bar_width+4, 26, 8, 8, 2,
COLOR_FG, COLOR_SUCCESS, 0);
LCD_DrawHollowRoundRect(4+2, LCD_HEIGHT - 30 + 2, 0.75 * bar_width, 22, 6, 6, 0,
COLOR_FG, COLOR_SUCCESS, 1);
}
+59 -48
View File
@@ -22,7 +22,8 @@ void GFX_DrawChar(
if (startX + glyph->width <= 0 || startX >= LCD_WIDTH) return;
if (startY + glyph->height <= 0 || startY >= LCD_HEIGHT) return;
LCD_Set_Address(startX, startY, startX + glyph->width - 1, startY + glyph->height - 1);
LCD_Set_Address(startX, startY, startX + glyph->width - 1,
startY + glyph->height - 1);
uint16_t pendingPixelCount = 0;
uint8_t pendingPixelBit = 0;
@@ -33,11 +34,12 @@ void GFX_DrawChar(
uint8_t bitIndex = bitPos % 8;
uint8_t pixelBit = font->bitmaps[byteIndex] & (0x80 >> bitIndex);
if(pixelBit == pendingPixelBit) {
if (pixelBit == pendingPixelBit) {
pendingPixelCount++;
}else {
if(pendingPixelCount != 0) {
LCD_Draw_Colour_Burst(pendingPixelBit ? fg_color : bg_color, pendingPixelCount);
} else {
if (pendingPixelCount != 0) {
LCD_Draw_Colour_Burst(pendingPixelBit ? fg_color : bg_color,
pendingPixelCount);
pendingPixelCount = 1;
}
pendingPixelBit = pixelBit;
@@ -56,59 +58,68 @@ void GFX_DrawChar(
bitPos++;
}
}
if(pendingPixelCount != 0) {
LCD_Draw_Colour_Burst(pendingPixelBit ? fg_color : bg_color, pendingPixelCount);
if (pendingPixelCount != 0) {
LCD_Draw_Colour_Burst(pendingPixelBit ? fg_color : bg_color,
pendingPixelCount);
}
}
uint16_t GFX_GetTextWidth(const char *text, const GFXfont *font) {
uint16_t width = 0;
uint16_t GFX_GetTextWidth(const char *text, const GFXfont *font, int8_t letter_spacing) {
uint16_t width = 0;
while (*text != '\0') {
if (*text >= font->firstChar && *text <= font->lastChar) {
uint16_t glyphIndex = *text - font->firstChar;
width += font->glyphs[glyphIndex].advance;
} else {
// Default advance for unsupported characters
width += 10;
}
text++;
while (*text != '\0') {
if (*text >= font->firstChar && *text <= font->lastChar) {
uint16_t glyphIndex = *text - font->firstChar;
width += font->glyphs[glyphIndex].advance;
width += letter_spacing;
} else {
// Default advance for unsupported characters
width += 10;
}
text++;
}
return width;
return width;
}
void GFX_DrawText(
uint16_t x,
uint16_t y,
const char *text,
const GFXfont *font,
uint16_t fg_color,
uint16_t bg_color,
uint8_t alignment,
int8_t letter_spacing) {
void GFX_DrawText(uint16_t x, uint16_t y, const char *text, const GFXfont *font,
uint16_t fg_color, uint16_t bg_color, uint8_t alignment) {
// Adjust x position based on alignment
switch (alignment) {
case 1:// Center
x -= GFX_GetTextWidth(text, font, letter_spacing) / 2;
break;
case 2:// Right
x -= GFX_GetTextWidth(text, font, letter_spacing);
break;
// Default: Left alignment (no adjustment)
}
// Adjust x position based on alignment
switch (alignment) {
case 1: // Center
x -= GFX_GetTextWidth(text, font) / 2;
break;
case 2: // Right
x -= GFX_GetTextWidth(text, font);
break;
// Default: Left alignment (no adjustment)
// Draw each character
uint16_t cursorX = x;
uint16_t cursorY = y;
while (*text != '\0') {
GFX_DrawChar(cursorX, cursorY, *text, font, fg_color, bg_color);
// Move cursor by the glyph's advance width
if (*text >= font->firstChar && *text <= font->lastChar) {
uint16_t glyphIndex = *text - font->firstChar;
cursorX += font->glyphs[glyphIndex].advance;
cursorX += letter_spacing;
} else {
// Default advance for unsupported characters
cursorX += 10 + letter_spacing;
}
// Draw each character
uint16_t cursorX = x;
uint16_t cursorY = y;
while (*text != '\0') {
GFX_DrawChar(cursorX, cursorY, *text, font, fg_color, bg_color);
// Move cursor by the glyph's advance width
if (*text >= font->firstChar && *text <= font->lastChar) {
uint16_t glyphIndex = *text - font->firstChar;
cursorX += font->glyphs[glyphIndex].advance;
} else {
// Default advance for unsupported characters
cursorX += 10;
}
text++;
}
text++;
}
}