diff --git a/bootloader/bootloader-display.c b/bootloader/bootloader-display.c
index 1fe0cae0ffee19dcf226db64248af754e3c87ac7..e4a19ab9345b592c782c6fa39c43da2e3bdf909b 100644
--- a/bootloader/bootloader-display.c
+++ b/bootloader/bootloader-display.c
@@ -2,7 +2,7 @@
 /* Autogenerated */
 #include "splash-screen.h"
 
-#include "GUI_Paint.h"
+#include "gfx.h"
 #include "display.h"
 
 /*
@@ -17,18 +17,20 @@ static void bootloader_display_splash(void)
 	int idx = 0;
 
 	for (int i = 0; i < sizeof(splash); i++) {
-		uint16_t color = (splash[i] & 0x80) ? 0xffff : 0x0000;
+		Color white = gfx_color(&display_screen, WHITE);
+		Color black = gfx_color(&display_screen, BLACK);
+		Color color = (splash[i] & 0x80) ? white : black;
 		uint8_t length = splash[i] & 0x7f;
 
 		for (int j = 0; j < length; j++) {
 			uint16_t x = idx % 160;
 			uint16_t y = idx / 160;
-			Paint_SetPixel(x, y, color);
+			gfx_setpixel(&display_screen, x, y, color);
 			idx++;
 		}
 	}
 
-	LCD_Update();
+	gfx_update(&display_screen);
 }
 
 /*
@@ -44,10 +46,8 @@ void bootloader_display_init(void)
  */
 void bootloader_display_header(void)
 {
-	Paint_Clear(0x0000);
-	Paint_DrawString_EN(0, 16 * 0, "Bootloader", &Font16, 0x0000, 0xffff);
-	Paint_DrawString_EN(0, 16 * 1, __DATE__, &Font16, 0x0000, 0xffff);
-	LCD_Update();
+	txt_puts(&display_textb, "Bootloader\n");
+	txt_puts(&display_textb, __DATE__ "\n");
 }
 
 /*
@@ -55,6 +55,8 @@ void bootloader_display_header(void)
  */
 void bootloader_display_line(int line, char *string, uint16_t color)
 {
-	Paint_DrawString_EN(0, 16 * line, string, &Font16, 0x0000, color);
-	LCD_Update();
+	Color white = gfx_color(&display_screen, WHITE);
+	Color black = gfx_color(&display_screen, BLACK);
+	gfx_puts(&Font16, &display_screen, 0, 16 * line, string, white, black);
+	gfx_update(&display_screen);
 }
diff --git a/epicardium/main.c b/epicardium/main.c
index c90d008248e0562c184701099be9ff59d7639b60..b32cf12a4ff0af6189a12ab600b240bbd110f7bd 100644
--- a/epicardium/main.c
+++ b/epicardium/main.c
@@ -17,12 +17,13 @@
 #include "modules/stream.h"
 #include "api/interrupt-sender.h"
 
-#include <Heart.h>
-#include "GUI_Paint.h"
-
 #include "FreeRTOS.h"
 #include "task.h"
 
+#include <Heart.h>
+#include "gfx.h"
+#include "display.h"
+
 TaskHandle_t dispatcher_task_id;
 
 /*
@@ -47,8 +48,8 @@ int main(void)
 	card10_init();
 	card10_diag();
 
-	Paint_DrawImage(Heart, 0, 0, 160, 80);
-	LCD_Update();
+	gfx_copy_raw(&display_screen, (const void *)(Heart), sizeof(Heart));
+	gfx_update(&display_screen);
 
 	/* TODO: Move this to its own function */
 	SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
diff --git a/epicardium/modules/display.c b/epicardium/modules/display.c
index 1f50acae5cb60a5c199b9864194ffdcd62954e5e..ed82df00724ccc134af27ec5a60131119ec8308e 100644
--- a/epicardium/modules/display.c
+++ b/epicardium/modules/display.c
@@ -1,11 +1,13 @@
 #include "epicardium.h"
 #include "tmr_utils.h"
 #include "gpio.h"
-#include "GUI_DEV/GUI_Paint.h"
 #include "Fonts/fonts.h"
 #include "tmr.h"
 #include "FreeRTOS.h"
 #include "task.h"
+#include "gfx.h"
+#include "display.h"
+#include "LCD_Driver.h"
 
 static TaskHandle_t lock = NULL;
 
@@ -30,7 +32,7 @@ int epic_disp_print(
 	if (cl < 0) {
 		return cl;
 	} else {
-		Paint_DrawString_EN(posx, posy, pString, &Font20, bg, fg);
+		gfx_puts(&Font20, &display_screen, posx, posy, pString, fg, bg);
 		return 0;
 	}
 }
@@ -41,7 +43,7 @@ int epic_disp_clear(uint16_t color)
 	if (cl < 0) {
 		return cl;
 	} else {
-		LCD_Clear(color);
+		gfx_clear_to_color(&display_screen, color);
 		return 0;
 	}
 }
@@ -52,7 +54,7 @@ int epic_disp_pixel(uint16_t x, uint16_t y, uint16_t color)
 	if (cl < 0) {
 		return cl;
 	} else {
-		Paint_SetPixel(x, y, color);
+		gfx_setpixel(&display_screen, x, y, color);
 		return 0;
 	}
 }
@@ -70,9 +72,8 @@ int epic_disp_line(
 	if (cl < 0) {
 		return cl;
 	} else {
-		Paint_DrawLine(
-			xstart, ystart, xend, yend, color, linestyle, pixelsize
-		);
+		gfx_thick_line(&display_screen, xstart, ystart, xend, yend,
+			 				 pixelsize, color);
 		return 0;
 	}
 }
@@ -87,14 +88,20 @@ int epic_disp_rect(
 	uint16_t pixelsize
 ) {
 	int cl = check_lock();
-	if (cl < 0) {
+	if (cl < 0)
 		return cl;
-	} else {
-		Paint_DrawRectangle(
-			xstart, ystart, xend, yend, color, fillstyle, pixelsize
-		);
-		return 0;
+
+	switch (fillstyle) {
+	case FILLSTYLE_EMPTY:
+		gfx_rectangle(&display_screen, xstart, ystart, xend - xstart,
+					    yend - ystart, pixelsize, color);
+		break;
+	case FILLSTYLE_FILLED:
+		gfx_rectangle_fill(&display_screen, xstart, ystart,
+		   	      xend - xstart, yend - ystart, color);
+		break;
 	}
+	return 0;
 }
 
 int epic_disp_circ(
@@ -106,12 +113,19 @@ int epic_disp_circ(
 	uint16_t pixelsize
 ) {
 	int cl = check_lock();
-	if (cl < 0) {
+	if (cl < 0)
 		return cl;
-	} else {
-		Paint_DrawCircle(x, y, rad, color, fillstyle, pixelsize);
-		return 0;
+
+	switch (fillstyle) {
+	case FILLSTYLE_EMPTY:
+		gfx_circle(&display_screen, x, y, rad, pixelsize, color);
+		break;
+	case FILLSTYLE_FILLED:
+		gfx_circle_fill(&display_screen, x, y, rad, color);
+		break;
 	}
+
+	return 0;
 }
 
 int epic_disp_update()
@@ -121,7 +135,7 @@ int epic_disp_update()
 		return cl;
 	}
 
-	LCD_Update();
+	gfx_update(&display_screen);
 	return 0;
 }
 
diff --git a/hw-tests/bmetest/main.c b/hw-tests/bmetest/main.c
index 0c44012965e3c0528f1d6ecf998a5015bb74a559..2c1bc80b62a72d86410c32abf411419a7c414c50 100644
--- a/hw-tests/bmetest/main.c
+++ b/hw-tests/bmetest/main.c
@@ -11,7 +11,9 @@
 #include "gpio.h"
 #include "bme680.h"
 #include "bosch.h"
-#include "GUI_DEV/GUI_Paint.h"
+#include "gfx.h"
+#include "framebuffer.h"
+#include "display.h"
 #include "Fonts/fonts.h"
 
 #include "card10.h"
@@ -72,7 +74,8 @@ int main(void)
     /* Set the power mode */
     rslt = bme680_set_sensor_mode(&gas_sensor);
 
-
+    Color white = gfx_color(&display_screen, WHITE);
+    Color black = gfx_color(&display_screen, BLACK);
     while (1) {
         TMR_Delay(MXC_TMR0, MSEC(1000), 0);
 
@@ -84,13 +87,13 @@ int main(void)
 
         char buf[128];
         sprintf(buf, "T: %.2Lf degC", data.temperature / 100.0l);
-        Paint_DrawString_EN(0, 0, buf, &Font16, 0x0000, 0xffff);
+        gfx_puts(&Font16, &display_screen, 0, 0, buf, white, black);
 
         sprintf(buf, "P: %.2Lf hPa", data.pressure / 100.0l);
-        Paint_DrawString_EN(0, 16, buf, &Font16, 0x0000, 0xffff);
+        gfx_puts(&Font16, &display_screen, 0, 16, buf, white, black);
 
         sprintf(buf, "H: %.2Lf %%rH", data.humidity / 1000.0l);
-        Paint_DrawString_EN(0, 32, buf, &Font16, 0x0000, 0xffff);
+        gfx_puts(&Font16, &display_screen, 0, 32, buf, white, black);
 
         //printf("%.2f,%.2f,%.2f\n", data.temperature / 100.0f,
         //    data.pressure / 100.0f, data.humidity / 1000.0f );
@@ -98,10 +101,10 @@ int main(void)
         if(data.status & BME680_GASM_VALID_MSK) {
             printf(", G: %ld ohms", data.gas_resistance);
             sprintf(buf, "G: %ld ohms", data.gas_resistance);
-            Paint_DrawString_EN(0, 48, buf, &Font16, 0x0000, 0xffff);
+            gfx_puts(&Font16, &display_screen, 0, 48, buf, white, black);
         }
 
-        LCD_Update();
+        gfx_update(&display_screen);
 
         printf("\n");
 
diff --git a/hw-tests/bootloader-update/main.c b/hw-tests/bootloader-update/main.c
index 684890d231f1e299b3bf1501f66c9de70586fd6d..b740866539c4a5cc758946cae94398d346c58028 100644
--- a/hw-tests/bootloader-update/main.c
+++ b/hw-tests/bootloader-update/main.c
@@ -6,7 +6,7 @@
 #include "card10.h"
 #include "bootloader-9251ea6.h"
 #include "display.h"
-#include "GUI_Paint.h"
+#include "gfx.h"
 #include "pmic.h"
 
 
@@ -45,37 +45,32 @@ int main(void)
     pmic_set_button_callback(pmic_button);
 
     printf("Erasing bootloader.\n");
-    Paint_DrawString_EN(0, 16*0, "Erasing bootloader", &Font16, 0x0000, 0xffff);
-    LCD_Update();
+    txt_puts(&display_textb, "Erasing bootloader.\n");
 
     ICC_Disable();
 
     int ret = FLC_MultiPageErase(0x10000000, 0x10000000 + 1024*64-1);
     if(ret != E_NO_ERROR) {
         printf("FLC_MultiPageErase failed with %d\n", ret);
-        Paint_DrawString_EN(0, 16*1, "Fail.", &Font16, 0x0000, 0xffff);
-        LCD_Update();
+    	txt_puts(&display_textb, "Fail.\n");
         while(1);
     }
 
 
     printf("Writing bootloader.\n");
-    Paint_DrawString_EN(0, 16*0, "Writing bootloader ", &Font16, 0x0000, 0xffff);
-    LCD_Update();
+    txt_puts(&display_textb, "Writing bootloader.\n");
 
     ret = FLC_Write(0x10000000, sizeof(bootloader_data), (uint32_t *)bootloader_data);
     if(ret != E_NO_ERROR) {
         printf("FLC_Write failed with %d\n", ret);
-        Paint_DrawString_EN(0, 16*1, "Fail.", &Font16, 0x0000, 0xffff);
-        LCD_Update();
+    	txt_puts(&display_textb, "Fail.\n");
         while(1);
     }
     ICC_Enable();
 
     printf("Done.\n");
-    Paint_DrawString_EN(0, 16*1, "Done.", &Font16, 0x0000, 0xffff);
-    Paint_DrawString_EN(0, 16*2, "Please restart", &Font16, 0x0000, 0xffff);
-    LCD_Update();
+    txt_puts(&display_textb, "Done.\n");
+    txt_puts(&display_textb, "Please restart.\n");
 
     while (1) {
         card10_poll();
diff --git a/hw-tests/dual-core/main.c b/hw-tests/dual-core/main.c
index ca91f9d63161412f52271c7797e172c5e7be20be..533ade07569fda60648cd80b64d03ad0e8033f82 100644
--- a/hw-tests/dual-core/main.c
+++ b/hw-tests/dual-core/main.c
@@ -7,7 +7,8 @@
 #include "leds.h"
 #include "card10.h"
 
-#include "GUI_Paint.h"
+#include "gfx.h"
+#include "display.h"
 
 #include "tmr_utils.h"
 
@@ -21,8 +22,8 @@ int main(void)
 	card10_init();
 	card10_diag();
 
-	Paint_DrawImage(Heart, 0, 0, 160, 80);
-	LCD_Update();
+	gfx_copy_raw(&display_screen, (const void *)(Heart), sizeof(Heart));
+	gfx_update(&display_screen);
 
 	for (int i = 0; i < 11; i++) {
 		leds_set_dim(i, 1);
diff --git a/hw-tests/ecgtest/main.c b/hw-tests/ecgtest/main.c
index da01840f84f7673eb3af1c2ec94272138faec7c4..a1cf8ea97419e97605a22ad0e4d05210456bc238 100644
--- a/hw-tests/ecgtest/main.c
+++ b/hw-tests/ecgtest/main.c
@@ -16,7 +16,9 @@
 #include "spi.h"
 #include "pb.h"
 #include "MAX30003.h"
-#include "GUI_DEV/GUI_Paint.h"
+#include "gfx.h"
+#include "LCD_Driver.h"
+#include "display.h"
 #include "pmic.h"
 #include "card10.h"
 #include <stdbool.h>
@@ -149,7 +151,7 @@ static uint8_t prev;
 
 static void clear(void)
 {
-    Paint_Clear(BLACK);
+    gfx_clear(&display_screen);
     prev = Y_OFFSET;
 }
 
@@ -172,7 +174,7 @@ static void set(uint8_t index, int8_t val)
     }
 
     for(int i = min; i < max + 1; i++) {
-        LCD_SetUWORD(SIZE_X - index - 1, i, RED);
+        LCD_SetUWORD(SIZE_X - index - 1, i, 0xf800);
     }
 
     prev = pos;
@@ -194,7 +196,9 @@ void update(void)
 
     char buf[128];
     sprintf(buf, "Switch: %d  Pull: %d Scale: %d", ecg_switch, internal_pull, scale);
-    Paint_DrawString_EN(0, 0, buf, &Font8, 0x0000, 0xffff);
+    gfx_puts(&Font8, &display_screen, 0, 0, buf,
+	      gfx_color(&display_screen, WHITE),
+	      gfx_color(&display_screen, BLACK));
 
 
     for(int i=0; i<SIZE_X; i++) {
diff --git a/hw-tests/hello-world/main.c b/hw-tests/hello-world/main.c
index 6581b97c4809d5b66a33c9c1ee9fbfbe3375aa2c..76cb380dd129a35f0570ee81124923b81a3c129e 100644
--- a/hw-tests/hello-world/main.c
+++ b/hw-tests/hello-world/main.c
@@ -7,7 +7,8 @@
 #include "leds.h"
 #include "card10.h"
 
-#include "GUI_Paint.h"
+#include "gfx.h"
+#include "display.h"
 
 #include "tmr_utils.h"
 
@@ -28,8 +29,8 @@ int main(void)
     card10_init();
     card10_diag();
 
-    Paint_DrawImage(Heart, 0, 0, 160, 80);
-    LCD_Update();
+    gfx_copy_raw(&display_screen, (const void *)(Heart), sizeof(Heart));
+    gfx_update(&display_screen);
 
     for(int i=0; i<11; i++) {
         leds_set_dim(i, 1);
diff --git a/hw-tests/imutest/main.c b/hw-tests/imutest/main.c
index 8b5f1ec4f23693f2c5fabfa922157bd8f3ecdb4f..055e4ef22b2e634fa1aac5f3160a8c593c598d66 100644
--- a/hw-tests/imutest/main.c
+++ b/hw-tests/imutest/main.c
@@ -13,7 +13,8 @@
 #include "gpio.h"
 #include "bhy_uc_driver.h"
 #include "pmic.h"
-#include "GUI_DEV/GUI_Paint.h"
+#include "gfx.h"
+#include "display.h"
 
 #include "card10.h"
 
@@ -48,7 +49,7 @@ void draw_arrow(int angle, int color)
     int x2 = x1 - sin * 30;
     int y2 = y1 - cos * 30;
 
-    Paint_DrawLine(x1, y1, x2, y2, color, LINE_STYLE_SOLID, DOT_PIXEL_2X2);
+    gfx_thick_line(&display_screen, x1, y1, x2, y2, 2, color);
 
     sin = sinf((angle - 140) * 2 * M_PI / 360.);
     cos = cosf((angle - 140) * 2 * M_PI / 360.);
@@ -56,7 +57,7 @@ void draw_arrow(int angle, int color)
     int x3 = x2 - sin * 10;
     int y3 = y2 - cos * 10;
 
-    Paint_DrawLine(x2, y2, x3, y3, color, LINE_STYLE_SOLID, DOT_PIXEL_2X2);
+    gfx_thick_line(&display_screen, x2, y2, x3, y3, 2, color);
 
     sin = sinf((angle + 140) * 2 * M_PI / 360.);
     cos = cosf((angle + 140) * 2 * M_PI / 360.);
@@ -64,7 +65,7 @@ void draw_arrow(int angle, int color)
     int x4 = x2 - sin * 10;
     int y4 = y2 - cos * 10;
 
-    Paint_DrawLine(x2, y2, x4, y4, color, LINE_STYLE_SOLID, DOT_PIXEL_2X2);
+    gfx_thick_line(&display_screen, x2, y2, x4, y4, 2, color);
 }
 
 /***** Functions *****/
@@ -81,8 +82,14 @@ static void sensors_callback_orientation(bhy_data_generic_t * sensor_data, bhy_v
     int angle = sensor_data->data_vector.x * 360 / 32768;
 
     if(angle != prev) {
-        Paint_Clear(BLACK);
-        int colors[] = {RED, YELLOW, YELLOW, GREEN};
+	gfx_clear(&display_screen);
+
+        int colors[] = {
+		gfx_color(&display_screen, RED),
+		gfx_color(&display_screen, YELLOW),
+		gfx_color(&display_screen, YELLOW),
+		gfx_color(&display_screen, GREEN)
+	};
         int color = colors[sensor_data->data_vector.status];
         draw_arrow(sensor_data->data_vector.x * 360 / 32768, color);
 
@@ -91,11 +98,11 @@ static void sensors_callback_orientation(bhy_data_generic_t * sensor_data, bhy_v
         //Paint_DrawString_EN(0, 0, buf, &Font12, BLACK, color);
 
         sprintf(buf, "%3d", angle);
-        Paint_DrawString_EN(0, 30, buf, &Font24, BLACK, color);
-        Paint_DrawCircle(57,35, 4, color, DRAW_FILL_EMPTY, DOT_PIXEL_1X1);
+	gfx_puts(&Font24, &display_screen, 0, 30, buf, color,
+			  gfx_color(&display_screen, BLACK));
+	gfx_circle(&display_screen, 57, 35, 4, 2, color);
 
-
-        LCD_Update();
+	gfx_update(&display_screen);
         prev = angle;
     }
 }
diff --git a/hw-tests/ips/main.c b/hw-tests/ips/main.c
index e47610b75994251fa6aba6d68e3dbf805f8182af..cb24d36733ae8f9b8b0303e2b679e2afbf1b0b59 100644
--- a/hw-tests/ips/main.c
+++ b/hw-tests/ips/main.c
@@ -5,10 +5,12 @@
 /***** Includes *****/
 #include "tmr_utils.h"
 #include "gpio.h"
-#include "GUI_DEV/GUI_Paint.h"
+#include "gfx.h"
+#include "display.h"
 #include "Fonts/fonts.h"
 #include "image/image.h"
 #include "tmr.h"
+#include "DEV_Config.h"
 
 #include "card10.h"
 
@@ -25,17 +27,23 @@ int main(void)
     card10_init();
     card10_diag();
 
-    Paint_DrawString_EN(0, 0, "123", &Font24, 0x000f, 0xfff0);
-    Paint_DrawString_EN(0, 23, "ABC", &Font24, BLUE, CYAN);
-    Paint_DrawString_CN(20,42, "΢ѩµç×Ó",  &Font24CN, WHITE, RED);
-    Paint_DrawRectangle(70, 10, 100, 40, RED,DRAW_FILL_EMPTY, DOT_PIXEL_2X2 );
-    Paint_DrawLine(70, 10, 100, 40, MAGENTA, LINE_STYLE_SOLID, DOT_PIXEL_2X2);
-    Paint_DrawLine(100, 10, 70, 40, MAGENTA, LINE_STYLE_SOLID, DOT_PIXEL_2X2);
-    Paint_DrawCircle(85,25, 22, GREEN, DRAW_FILL_EMPTY, DOT_PIXEL_2X2);
-
-    Paint_DrawImage(gImage_40X40,120, 0,40, 40);
-    Paint_DrawImage(gImage_160X80,0, 0, 160, 80);
-    LCD_Update();
+    Color red = gfx_color(&display_screen, RED);
+    Color green = gfx_color(&display_screen, GREEN);
+    Color yellow = gfx_color(&display_screen, YELLOW);
+
+    gfx_puts(&Font24, &display_screen, 0, 0, "123", 0x000f, 0xfff8);
+    gfx_puts(&Font24, &display_screen, 23, 0, "ABC", 0x000f, 0xfff8);
+    gfx_rectangle(&display_screen, 70, 10, 100, 40, 2, red);
+    gfx_thick_line(&display_screen, 70, 10, 100, 40, 2, green);
+    gfx_thick_line(&display_screen, 100, 10, 70, 40, 2, yellow);
+    gfx_circle(&display_screen, 85, 25, 22, 2, green);
+
+    gfx_copy_region_raw(&display_screen, 120, 0, 40, 40, 2,
+		      	     (const void *)(gImage_40X40));
+    gfx_copy_region_raw(&display_screen, 0, 0, 160, 80, 2,
+		    	   (const void *)(gImage_160X80));
+    gfx_update(&display_screen);
+
     DEV_Delay_ms(3000);
 
     while (1) {
diff --git a/lib/card10/display.c b/lib/card10/display.c
index e1d66276646f480cde27c063f162d7bd85dd6138..2756ccb7b1a78a2993ad4b96715ad4d846c77475 100644
--- a/lib/card10/display.c
+++ b/lib/card10/display.c
@@ -1,5 +1,7 @@
 #include "LCD/LCD_Driver.h"
-#include "GUI_DEV/GUI_Paint.h"
+#include "framebuffer.h"
+#include "gfx.h"
+#include "textbuffer.h"
 
 #include "gpio.h"
 #include "tmr.h"
@@ -11,6 +13,9 @@
 /***** Globals *****/
 const gpio_cfg_t DEV_DC_PIN = { PORT_1, PIN_6, GPIO_FUNC_OUT, GPIO_PAD_NONE };
 
+struct gfx_region display_screen;
+struct txt_buffer display_textb;
+
 // Parameters for PWM output
 #define PORT_PWM PORT_0 // port
 #define PIN_PWM PIN_28  // pin
@@ -93,10 +98,8 @@ void display_init(void)
 	PWM_Output();
 	LCD_SetBacklight(500);
 	LCD_Init();
-	LCD_Clear(BLACK);
-
-	Paint_NewImage(LCD_WIDTH, LCD_HEIGHT, 0, WHITE);
 
-	Paint_Clear(BLACK);
-	Paint_SetRotate(180);
+	display_screen = gfx_screen(LCD_framebuffer());
+	txt_init(&display_textb, &display_screen, &Font12);
+	gfx_clear(&display_screen);
 }
diff --git a/lib/card10/display.h b/lib/card10/display.h
index e4244b58a672eed1706ea4c81e4e268fee4147b8..47f82a37f275babff016ab5b32299b0e2e23a475 100644
--- a/lib/card10/display.h
+++ b/lib/card10/display.h
@@ -1,4 +1,9 @@
 #ifndef DISPLAY_H
+#include "framebuffer.h"
+#include "textbuffer.h"
+
+extern struct gfx_region display_screen;
+extern struct txt_buffer display_textb;
 
 void display_init(void);
 
diff --git a/lib/gfx/GUI_DEV/GUI_Paint.c b/lib/gfx/GUI_DEV/GUI_Paint.c
deleted file mode 100644
index 13cbba25f907ac0056d5dc17d0b7830714f6fc6d..0000000000000000000000000000000000000000
--- a/lib/gfx/GUI_DEV/GUI_Paint.c
+++ /dev/null
@@ -1,683 +0,0 @@
-/*****************************************************************************
-* | File      	:   GUI_Paint.c
-* | Author      :   Waveshare team
-* | Function    :	Achieve drawing: draw points, lines, boxes, circles and
-*                   their size, solid dotted line, solid rectangle hollow
-*                   rectangle, solid circle hollow circle.
-* | Info        :
-*   Achieve display characters: Display a single character, string, number
-*   Achieve time display: adaptive size display time minutes and seconds
-*----------------
-* |	This version:   V2.0
-* | Date        :   2018-11-15
-* | Info        :
-* 1.add: Paint_NewImage()
-*    Create an image's properties
-* 2.add: Paint_SelectImage()
-*    Select the picture to be drawn
-* 3.add: Paint_SetRotate()
-*    Set the direction of the cache    
-* 4.add: Paint_RotateImage() 
-*    Can flip the picture, Support 0-360 degrees, 
-*    but only 90.180.270 rotation is better
-* 4.add: Paint_SetMirroring() 
-*    Can Mirroring the picture, horizontal, vertical, origin
-* 5.add: Paint_DrawString_CN() 
-*    Can display Chinese(GB1312)    
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documnetation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to  whom the Software is
-* furished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-*
-******************************************************************************/
-#include "GUI_Paint.h"
-#include "DEV_Config.h"
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h> //memset()
-#include <math.h>
-
-volatile PAINT Paint;
-
-/******************************************************************************
-function:	Create Image
-parameter:
-    image   :   Pointer to the image cache
-    width   :   The width of the picture
-    Height  :   The height of the picture
-    Color   :   Whether the picture is inverted
-******************************************************************************/
-void Paint_NewImage(UWORD Width, UWORD Height, UWORD Rotate, UWORD Color)
-{
-    Paint.WidthMemory = Width;
-    Paint.HeightMemory = Height;
-    Paint.Color = Color;    
-    Paint.WidthByte = Width;
-    Paint.HeightByte = Height;    
-    printf("WidthByte = %d, HeightByte = %d\r\n", Paint.WidthByte, Paint.HeightByte);
-    printf(" EPD_WIDTH / 8 = %d\r\n",  122 / 8);
-   
-    Paint.Rotate = Rotate;
-    Paint.Mirror = MIRROR_NONE;
-    
-    if(Rotate == ROTATE_0 || Rotate == ROTATE_180) {
-        Paint.Width = Width;
-        Paint.Height = Height;
-    } else {
-        Paint.Width = Height;
-        Paint.Height = Width;
-    }
-}
-
-/******************************************************************************
-function:	Select Image Rotate
-parameter:
-    Rotate   :   0,90,180,270
-******************************************************************************/
-void Paint_SetRotate(UWORD Rotate)
-{
-    if(Rotate == ROTATE_0 || Rotate == ROTATE_90 || Rotate == ROTATE_180 || Rotate == ROTATE_270) {
-        Debug("Set image Rotate %d\r\n", Rotate);
-        Paint.Rotate = Rotate;
-    } else {
-        Debug("rotate = 0, 90, 180, 270\r\n");
-      //  exit(0);
-    }
-}
-
-/******************************************************************************
-function:	Select Image mirror
-parameter:
-    mirror   :       Not mirror,Horizontal mirror,Vertical mirror,Origin mirror
-******************************************************************************/
-void Paint_SetMirroring(UBYTE mirror)
-{
-    if(mirror == MIRROR_NONE || mirror == MIRROR_HORIZONTAL || 
-        mirror == MIRROR_VERTICAL || mirror == MIRROR_ORIGIN) {
-        Debug("mirror image x:%s, y:%s\r\n",(mirror & 0x01)? "mirror":"none", ((mirror >> 1) & 0x01)? "mirror":"none");
-        Paint.Mirror = mirror;
-    } else {
-        Debug("mirror should be MIRROR_NONE, MIRROR_HORIZONTAL, \
-        MIRROR_VERTICAL or MIRROR_ORIGIN\r\n");
-//exit(0);
-    }    
-}
-
-/******************************************************************************
-function:	Draw Pixels
-parameter:
-    Xpoint  :   At point X
-    Ypoint  :   At point Y
-    Color   :   Painted colors
-******************************************************************************/
-void Paint_SetPixel(UWORD Xpoint, UWORD Ypoint, UWORD Color)
-{
-    if(Xpoint > Paint.Width || Ypoint > Paint.Height){
-        Debug("Exceeding display boundaries\r\n");
-        return;
-    }      
-    UWORD X, Y;
-
-    switch(Paint.Rotate) {
-    case 0:
-        X = Xpoint;
-        Y = Ypoint;  
-        break;
-    case 90:
-        X = Paint.WidthMemory - Ypoint - 1;
-        Y = Xpoint;
-        break;
-    case 180:
-        X = Paint.WidthMemory - Xpoint - 1;
-        Y = Paint.HeightMemory - Ypoint - 1;
-        break;
-    case 270:
-        X = Ypoint;
-        Y = Paint.HeightMemory - Xpoint - 1;
-        break;
-
-    default:
-        return;
-    }
-    
-    switch(Paint.Mirror) {
-    case MIRROR_NONE:
-        break;
-    case MIRROR_HORIZONTAL:
-        X = Paint.WidthMemory - X - 1;
-        break;
-    case MIRROR_VERTICAL:
-        Y = Paint.HeightMemory - Y - 1;
-        break;
-    case MIRROR_ORIGIN:
-        X = Paint.WidthMemory - X - 1;
-        Y = Paint.HeightMemory - Y - 1;
-        break;
-    default:
-        return;
-    }
-
-    // printf("x = %d, y = %d\r\n", X, Y);
-    if(X > Paint.WidthMemory || Y > Paint.HeightMemory){
-        Debug("Exceeding display boundaries\r\n");
-        return;
-    }
-    
-   // UDOUBLE Addr = X / 8 + Y * Paint.WidthByte;
-		LCD_SetUWORD(X,Y, Color);
-}
-
-/******************************************************************************
-function:	Clear the color of the picture
-parameter:
-    Color   :   Painted colors
-******************************************************************************/
-void Paint_Clear(UWORD Color)
-{	
-	LCD_Clear(Color);
-}
-
-/******************************************************************************
-function:	Clear the color of a window
-parameter:
-    Xstart :   x starting point
-    Ystart :   Y starting point
-    Xend   :   x end point
-    Yend   :   y end point
-******************************************************************************/
-void Paint_ClearWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color)
-{
-    UWORD X, Y;
-    for (Y = Ystart; Y < Yend; Y++) {
-        for (X = Xstart; X < Xend; X++) {//8 pixel =  1 byte
-            Paint_SetPixel(X, Y, Color);
-        }
-    }
-}
-
-/******************************************************************************
-function:	Draw Point(Xpoint, Ypoint) Fill the color
-parameter:
-    Xpoint		:   The Xpoint coordinate of the point
-    Ypoint		:   The Ypoint coordinate of the point
-    Color		:   Set color
-    Dot_Pixel	:	point size
-******************************************************************************/
-void Paint_DrawPoint(UWORD Xpoint, UWORD Ypoint, UWORD Color,
-                     DOT_PIXEL Dot_Pixel, DOT_STYLE DOT_STYLE)
-{
-    if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
-        // Debug("Paint_DrawPoint Input exceeds the normal display range\r\n");
-        return;
-    }
-
-    int16_t XDir_Num , YDir_Num;
-    if (DOT_STYLE == DOT_FILL_AROUND) {
-        for (XDir_Num = 0; XDir_Num < 2*Dot_Pixel - 1; XDir_Num++) {
-            for (YDir_Num = 0; YDir_Num < 2 * Dot_Pixel - 1; YDir_Num++) {
-                if(Xpoint + XDir_Num - Dot_Pixel < 0 || Ypoint + YDir_Num - Dot_Pixel < 0)
-                    break;
-                // printf("x = %d, y = %d\r\n", Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel);
-                Paint_SetPixel(Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel, Color);
-            }
-        }
-    } else {
-        for (XDir_Num = 0; XDir_Num <  Dot_Pixel; XDir_Num++) {
-            for (YDir_Num = 0; YDir_Num <  Dot_Pixel; YDir_Num++) {
-                Paint_SetPixel(Xpoint + XDir_Num - 1, Ypoint + YDir_Num - 1, Color);
-            }
-        }
-    }
-}
-
-/******************************************************************************
-function:	Draw a line of arbitrary slope
-parameter:
-    Xstart :Starting Xpoint point coordinates
-    Ystart :Starting Xpoint point coordinates
-    Xend   :End point Xpoint coordinate
-    Yend   :End point Ypoint coordinate
-    Color  :The color of the line segment
-******************************************************************************/
-void Paint_DrawLine(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend,
-                    UWORD Color, LINE_STYLE Line_Style, DOT_PIXEL Dot_Pixel)
-{
-    if (Xstart > Paint.Width || Ystart > Paint.Height ||
-        Xend > Paint.Width || Yend > Paint.Height) {
-        Debug("Paint_DrawLine Input exceeds the normal display range\r\n");
-        return;
-    }
-
-    UWORD Xpoint = Xstart;
-    UWORD Ypoint = Ystart;
-    int dx = (int)Xend - (int)Xstart >= 0 ? Xend - Xstart : Xstart - Xend;
-    int dy = (int)Yend - (int)Ystart <= 0 ? Yend - Ystart : Ystart - Yend;
-
-    // Increment direction, 1 is positive, -1 is counter;
-    int XAddway = Xstart < Xend ? 1 : -1;
-    int YAddway = Ystart < Yend ? 1 : -1;
-
-    //Cumulative error
-    int Esp = dx + dy;
-    char Dotted_Len = 0;
-
-    for (;;) {
-        Dotted_Len++;
-        //Painted dotted line, 2 point is really virtual
-        if (Line_Style == LINE_STYLE_DOTTED && Dotted_Len % 3 == 0) {
-            //Debug("LINE_DOTTED\r\n");
-            Paint_DrawPoint(Xpoint, Ypoint, IMAGE_BACKGROUND, Dot_Pixel, DOT_STYLE_DFT);
-            Dotted_Len = 0;
-        } else {
-            Paint_DrawPoint(Xpoint, Ypoint, Color, Dot_Pixel, DOT_STYLE_DFT);
-        }
-        if (2 * Esp >= dy) {
-            if (Xpoint == Xend)
-                break;
-            Esp += dy;
-            Xpoint += XAddway;
-        }
-        if (2 * Esp <= dx) {
-            if (Ypoint == Yend)
-                break;
-            Esp += dx;
-            Ypoint += YAddway;
-        }
-    }
-}
-
-/******************************************************************************
-function:	Draw a rectangle
-parameter:
-    Xstart :Rectangular  Starting Xpoint point coordinates
-    Ystart :Rectangular  Starting Xpoint point coordinates
-    Xend   :Rectangular  End point Xpoint coordinate
-    Yend   :Rectangular  End point Ypoint coordinate
-    Color  :The color of the Rectangular segment
-    Filled : Whether it is filled--- 1 solid 0:empty
-******************************************************************************/
-void Paint_DrawRectangle(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend,
-                         UWORD Color, DRAW_FILL Filled, DOT_PIXEL Dot_Pixel)
-{
-    if (Xstart > Paint.Width || Ystart > Paint.Height ||
-        Xend > Paint.Width || Yend > Paint.Height) {
-        Debug("Input exceeds the normal display range\r\n");
-        return;
-    }
-
-    if (Filled ) {
-        UWORD Ypoint;
-        for(Ypoint = Ystart; Ypoint < Yend; Ypoint++) {
-            Paint_DrawLine(Xstart, Ypoint, Xend, Ypoint, Color , LINE_STYLE_SOLID, Dot_Pixel);
-        }
-    } else {
-        Paint_DrawLine(Xstart, Ystart, Xend, Ystart, Color , LINE_STYLE_SOLID, Dot_Pixel);
-        Paint_DrawLine(Xstart, Ystart, Xstart, Yend, Color , LINE_STYLE_SOLID, Dot_Pixel);
-        Paint_DrawLine(Xend, Yend, Xend, Ystart, Color , LINE_STYLE_SOLID, Dot_Pixel);
-        Paint_DrawLine(Xend, Yend, Xstart, Yend, Color , LINE_STYLE_SOLID, Dot_Pixel);
-    }
-}
-
-/******************************************************************************
-function:	Use the 8-point method to draw a circle of the
-            specified size at the specified position->
-parameter:
-    X_Center  :Center X coordinate
-    Y_Center  :Center Y coordinate
-    Radius    :circle Radius
-    Color     :The color of the :circle segment
-    Filled    : Whether it is filled: 1 filling 0:Do not
-******************************************************************************/
-void Paint_DrawCircle(UWORD X_Center, UWORD Y_Center, UWORD Radius,
-                      UWORD Color, DRAW_FILL  Draw_Fill , DOT_PIXEL Dot_Pixel)
-{
-    if (X_Center > Paint.Width || Y_Center >= Paint.Height) {
-        Debug("Paint_DrawCircle Input exceeds the normal display range\r\n");
-        return;
-    }
-
-    //Draw a circle from(0, R) as a starting point
-    int16_t XCurrent, YCurrent;
-    XCurrent = 0;
-    YCurrent = Radius;
-
-    //Cumulative error,judge the next point of the logo
-    int16_t Esp = 3 - (Radius << 1 );
-
-    int16_t sCountY;
-    if (Draw_Fill == DRAW_FILL_FULL) {
-        while (XCurrent <= YCurrent ) { //Realistic circles
-            for (sCountY = XCurrent; sCountY <= YCurrent; sCountY ++ ) {
-                Paint_DrawPoint(X_Center + XCurrent, Y_Center + sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//1
-                Paint_DrawPoint(X_Center - XCurrent, Y_Center + sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//2
-                Paint_DrawPoint(X_Center - sCountY, Y_Center + XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//3
-                Paint_DrawPoint(X_Center - sCountY, Y_Center - XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//4
-                Paint_DrawPoint(X_Center - XCurrent, Y_Center - sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//5
-                Paint_DrawPoint(X_Center + XCurrent, Y_Center - sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//6
-                Paint_DrawPoint(X_Center + sCountY, Y_Center - XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//7
-                Paint_DrawPoint(X_Center + sCountY, Y_Center + XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-            }
-            if (Esp < 0 )
-                Esp += 4 * XCurrent + 6;
-            else {
-                Esp += 10 + 4 * (XCurrent - YCurrent );
-                YCurrent --;
-            }
-            XCurrent ++;
-        }
-    } else { //Draw a hollow circle
-        while (XCurrent <= YCurrent ) {
-            Paint_DrawPoint(X_Center + XCurrent, Y_Center + YCurrent, Color, Dot_Pixel, DOT_STYLE_DFT);//1
-            Paint_DrawPoint(X_Center - XCurrent, Y_Center + YCurrent, Color, Dot_Pixel, DOT_STYLE_DFT);//2
-            Paint_DrawPoint(X_Center - YCurrent, Y_Center + XCurrent, Color, Dot_Pixel, DOT_STYLE_DFT);//3
-            Paint_DrawPoint(X_Center - YCurrent, Y_Center - XCurrent, Color, Dot_Pixel, DOT_STYLE_DFT);//4
-            Paint_DrawPoint(X_Center - XCurrent, Y_Center - YCurrent, Color, Dot_Pixel, DOT_STYLE_DFT);//5
-            Paint_DrawPoint(X_Center + XCurrent, Y_Center - YCurrent, Color, Dot_Pixel, DOT_STYLE_DFT);//6
-            Paint_DrawPoint(X_Center + YCurrent, Y_Center - XCurrent, Color, Dot_Pixel, DOT_STYLE_DFT);//7
-            Paint_DrawPoint(X_Center + YCurrent, Y_Center + XCurrent, Color, Dot_Pixel, DOT_STYLE_DFT);//0
-
-            if (Esp < 0 )
-                Esp += 4 * XCurrent + 6;
-            else {
-                Esp += 10 + 4 * (XCurrent - YCurrent );
-                YCurrent --;
-            }
-            XCurrent ++;
-        }
-    }
-}
-
-/******************************************************************************
-function:	Show English characters
-parameter:
-    Xpoint           :X coordinate
-    Ypoint           :Y coordinate
-    Acsii_Char       :To display the English characters
-    Font             :A structure pointer that displays a character size
-    Color_Background : Select the background color of the English character
-    Color_Foreground : Select the foreground color of the English character
-******************************************************************************/
-void Paint_DrawChar(UWORD Xpoint, UWORD Ypoint, const char Acsii_Char,
-                    sFONT* Font, UWORD Color_Background, UWORD Color_Foreground)
-{
-    UWORD Page, Column;
-
-    if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
-        Debug("Paint_DrawChar Input exceeds the normal display range\r\n");
-        return;
-    }
-
-    uint32_t Char_Offset = (Acsii_Char - ' ') * Font->Height * (Font->Width / 8 + (Font->Width % 8 ? 1 : 0));
-    const unsigned char *ptr = &Font->table[Char_Offset];
-
-    for (Page = 0; Page < Font->Height; Page ++ ) {
-        for (Column = 0; Column < Font->Width; Column ++ ) {
-
-            //To determine whether the font background color and screen background color is consistent
-            if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
-                if (*ptr & (0x80 >> (Column % 8)))
-                    Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
-                    // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-            } else {
-                if (*ptr & (0x80 >> (Column % 8))) {
-                    Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
-                    // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-                } else {
-                    Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Background);
-                    // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-                }
-            }
-            //One pixel is 8 bits
-            if (Column % 8 == 7)
-                ptr++;
-        }// Write a line
-        if (Font->Width % 8 != 0)
-            ptr++;
-    }// Write all
-}
-
-/******************************************************************************
-function:	Display the string
-parameter:
-    Xstart           :X coordinate
-    Ystart           :Y coordinate
-    pString          :The first address of the English string to be displayed
-    Font             :A structure pointer that displays a character size
-    Color_Background : Select the background color of the English character
-    Color_Foreground : Select the foreground color of the English character
-******************************************************************************/
-void Paint_DrawString_EN(UWORD Xstart, UWORD Ystart, const char * pString,
-                         sFONT* Font, UWORD Color_Background, UWORD Color_Foreground )
-{
-    UWORD Xpoint = Xstart;
-    UWORD Ypoint = Ystart;
-
-    if (Xstart > Paint.Width || Ystart > Paint.Height) {
-        Debug("Paint_DrawString_EN Input exceeds the normal display range\r\n");
-        return;
-    }
-
-    while (* pString != '\0') {
-        //if X direction filled , reposition to(Xstart,Ypoint),Ypoint is Y direction plus the Height of the character
-        if ((Xpoint + Font->Width ) > Paint.Width ) {
-            Xpoint = Xstart;
-            Ypoint += Font->Height;
-        }
-
-        // If the Y direction is full, reposition to(Xstart, Ystart)
-        if ((Ypoint  + Font->Height ) > Paint.Height ) {
-            Xpoint = Xstart;
-            Ypoint = Ystart;
-        }
-        Paint_DrawChar(Xpoint, Ypoint, * pString, Font, Color_Background, Color_Foreground);
-
-        //The next character of the address
-        pString ++;
-
-        //The next word of the abscissa increases the font of the broadband
-        Xpoint += Font->Width;
-    }
-}
-
-
-/******************************************************************************
-function:	Display the string
-parameter:
-    Xstart           :X coordinate
-    Ystart           :Y coordinate
-    pString          :The first address of the Chinese string and English
-                        string to be displayed
-    Font             :A structure pointer that displays a character size
-    Color_Background : Select the background color of the English character
-    Color_Foreground : Select the foreground color of the English character
-******************************************************************************/
-void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font, UWORD Color_Background, UWORD Color_Foreground)
-{
-    const char* p_text = pString;
-    int x = Xstart, y = Ystart;
-    int i, j,Num;
-
-    /* Send the string character by character on EPD */
-    while (*p_text != 0) {
-        if(*p_text <= 0x7F) {  //ASCII < 126
-            for(Num = 0; Num < font->size; Num++) {
-                if(*p_text== font->table[Num].index[0]) {
-                    const char* ptr = &font->table[Num].matrix[0];
-
-                    for (j = 0; j < font->Height; j++) {
-                        for (i = 0; i < font->Width; i++) {
-                            if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
-                                if (*ptr & (0x80 >> (i % 8))) {
-                                    Paint_SetPixel(x + i, y + j, Color_Foreground);
-                                    // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-                                }
-                            } else {
-                                if (*ptr & (0x80 >> (i % 8))) {
-                                    Paint_SetPixel(x + i, y + j, Color_Foreground);
-                                    // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-                                } else {
-                                    Paint_SetPixel(x + i, y + j, Color_Background);
-                                    // Paint_DrawPoint(x + i, y + j, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-                                }
-                            }
-                            if (i % 8 == 7) {
-                                ptr++;
-                            }
-                        }
-                        if (font->Width % 8 != 0) {
-                            ptr++;
-                        }
-                    }
-                    break;
-                }
-            }
-            /* Point on the next character */
-            p_text += 1;
-            /* Decrement the column position by 16 */
-            x += font->ASCII_Width;
-        } else {        //Chinese
-            for(Num = 0; Num < font->size; Num++) {
-                if((*p_text== font->table[Num].index[0]) && (*(p_text+1) == font->table[Num].index[1])) {
-                    const char* ptr = &font->table[Num].matrix[0];
-
-                    for (j = 0; j < font->Height; j++) {
-                        for (i = 0; i < font->Width; i++) {
-                            if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
-                                if (*ptr & (0x80 >> (i % 8))) {
-                                    Paint_SetPixel(x + i, y + j, Color_Foreground);
-                                    // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-                                }
-                            } else {
-                                if (*ptr & (0x80 >> (i % 8))) {
-                                    Paint_SetPixel(x + i, y + j, Color_Foreground);
-                                    // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-                                } else {
-                                    Paint_SetPixel(x + i, y + j, Color_Background);
-                                    // Paint_DrawPoint(x + i, y + j, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
-                                }
-                            }
-                            if (i % 8 == 7) {
-                                ptr++;
-                            }
-                        }
-                        if (font->Width % 8 != 0) {
-                            ptr++;
-                        }
-                    }
-                    break;
-                }
-            }
-            /* Point on the next character */
-            p_text += 2;
-            /* Decrement the column position by 16 */
-            x += font->Width;
-        }
-    }
-}
-
-/******************************************************************************
-function:	Display nummber
-parameter:
-    Xstart           :X coordinate
-    Ystart           : Y coordinate
-    Nummber          : The number displayed
-    Font             :A structure pointer that displays a character size
-    Color_Background : Select the background color of the English character
-    Color_Foreground : Select the foreground color of the English character
-******************************************************************************/
-#define  ARRAY_LEN 255
-void Paint_DrawNum(UWORD Xpoint, UWORD Ypoint, int32_t Nummber,
-                   sFONT* Font, UWORD Color_Background, UWORD Color_Foreground )
-{
-
-    int16_t Num_Bit = 0, Str_Bit = 0;
-    uint8_t Str_Array[ARRAY_LEN] = {0}, Num_Array[ARRAY_LEN] = {0};
-    uint8_t *pStr = Str_Array;
-
-    if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
-        Debug("Paint_DisNum Input exceeds the normal display range\r\n");
-        return;
-    }
-
-    //Converts a number to a string
-    while (Nummber) {
-        Num_Array[Num_Bit] = Nummber % 10 + '0';
-        Num_Bit++;
-        Nummber /= 10;
-    }
-
-    //The string is inverted
-    while (Num_Bit > 0) {
-        Str_Array[Str_Bit] = Num_Array[Num_Bit - 1];
-        Str_Bit ++;
-        Num_Bit --;
-    }
-
-    //show
-    Paint_DrawString_EN(Xpoint, Ypoint, (const char*)pStr, Font, Color_Background, Color_Foreground);
-}
-
-/******************************************************************************
-function:	Display time
-parameter:
-    Xstart           :X coordinate
-    Ystart           : Y coordinate
-    pTime            : Time-related structures
-    Font             :A structure pointer that displays a character size
-    Color            : Select the background color of the English character
-******************************************************************************/
-void Paint_DrawTime(UWORD Xstart, UWORD Ystart, PAINT_TIME *pTime, sFONT* Font,
-                    UWORD Color_Background, UWORD Color_Foreground)
-{
-    uint8_t value[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
-
-    UWORD Dx = Font->Width;
-
-    //Write data into the cache
-    Paint_DrawChar(Xstart                           , Ystart, value[pTime->Hour / 10], Font, Color_Background, Color_Foreground);
-    Paint_DrawChar(Xstart + Dx                      , Ystart, value[pTime->Hour % 10], Font, Color_Background, Color_Foreground);
-    Paint_DrawChar(Xstart + Dx  + Dx / 4 + Dx / 2   , Ystart, ':'                    , Font, Color_Background, Color_Foreground);
-    Paint_DrawChar(Xstart + Dx * 2 + Dx / 2         , Ystart, value[pTime->Min / 10] , Font, Color_Background, Color_Foreground);
-    Paint_DrawChar(Xstart + Dx * 3 + Dx / 2         , Ystart, value[pTime->Min % 10] , Font, Color_Background, Color_Foreground);
-    Paint_DrawChar(Xstart + Dx * 4 + Dx / 2 - Dx / 4, Ystart, ':'                    , Font, Color_Background, Color_Foreground);
-    Paint_DrawChar(Xstart + Dx * 5                  , Ystart, value[pTime->Sec / 10] , Font, Color_Background, Color_Foreground);
-    Paint_DrawChar(Xstart + Dx * 6                  , Ystart, value[pTime->Sec % 10] , Font, Color_Background, Color_Foreground);
-}
-
-/******************************************************************************
-function:	Display image
-parameter:
-    image            :Image start address
-    xStart           : X starting coordinates
-    yStart           : Y starting coordinates
-    xEnd             :Image width
-    yEnd             : Image height
-******************************************************************************/
-void Paint_DrawImage(const unsigned char *image, UWORD xStart, UWORD yStart, UWORD W_Image, UWORD H_Image) 
-{
-    int i,j; 
-		for(j = 0; j < H_Image; j++){
-			for(i = 0; i < W_Image; i++){
-				if(xStart+i < LCD_WIDTH  &&  yStart+j < LCD_HEIGHT)//Exceeded part does not display
-					Paint_SetPixel(xStart + i, yStart + j, (*(image + j*W_Image*2 + i*2+1))<<8 | (*(image + j*W_Image*2 + i*2)));
-				//Using arrays is a property of sequential storage, accessing the original array by algorithm
-				//j*W_Image*2 			   Y offset
-				//i*2              	   X offset
-			}
-		}
-      
-}
diff --git a/lib/gfx/GUI_DEV/GUI_Paint.h b/lib/gfx/GUI_DEV/GUI_Paint.h
deleted file mode 100644
index 187c9631470cef6b9e8e5b4da8450602923571dd..0000000000000000000000000000000000000000
--- a/lib/gfx/GUI_DEV/GUI_Paint.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*****************************************************************************
-* | File      	:   GUI_Paint.h
-* | Author      :   Waveshare team
-* | Function    :	Achieve drawing: draw points, lines, boxes, circles and
-*                   their size, solid dotted line, solid rectangle hollow
-*                   rectangle, solid circle hollow circle.
-* | Info        :
-*   Achieve display characters: Display a single character, string, number
-*   Achieve time display: adaptive size display time minutes and seconds
-*----------------
-* |	This version:   V2.0
-* | Date        :   2018-11-15
-* | Info        :
-* 1.add: Paint_NewImage()
-*    Create an image's properties
-* 2.add: Paint_SelectImage()
-*    Select the picture to be drawn
-* 3.add: Paint_SetRotate()
-*    Set the direction of the cache    
-* 4.add: Paint_RotateImage() 
-*    Can flip the picture, Support 0-360 degrees, 
-*    but only 90.180.270 rotation is better
-* 4.add: Paint_SetMirroring() 
-*    Can Mirroring the picture, horizontal, vertical, origin
-* 5.add: Paint_DrawString_CN() 
-*    Can display Chinese(GB1312)    
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documnetation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to  whom the Software is
-* furished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-*
-******************************************************************************/
-#ifndef __GUI_PAINT_H
-#define __GUI_PAINT_H
-
-#include "DEV_Config.h"
-#include "LCD_Driver.h"
-#include "fonts.h"
-#include "Debug.h"
-
-/**
- * Image attributes
-**/
-typedef struct {
-    UBYTE *Image;
-    UWORD Width;
-    UWORD Height;
-    UWORD WidthMemory;
-    UWORD HeightMemory;
-    UWORD Color;
-    UWORD Rotate;
-    UWORD Mirror;
-    UWORD WidthByte;
-    UWORD HeightByte;
-} PAINT;
-extern volatile PAINT Paint;
-
-/**
- * Display rotate
-**/
-#define ROTATE_0            0
-#define ROTATE_90           90
-#define ROTATE_180          180
-#define ROTATE_270          270
-
-/**
- * Display Flip
-**/
-typedef enum {
-    MIRROR_NONE  = 0x00,
-    MIRROR_HORIZONTAL = 0x01,
-    MIRROR_VERTICAL = 0x02,
-    MIRROR_ORIGIN = 0x03,
-} MIRROR_IMAGE;
-#define MIRROR_IMAGE_DFT MIRROR_NONE
-
-/**
- * image color
-**/
-
-#define WHITE					0xFFFF
-#define BLACK					0x0000	  
-#define BLUE 					0x001F  
-#define BRED 					0XF81F
-#define GRED 					0XFFE0
-#define GBLUE					0X07FF
-#define RED  					0xF800
-#define MAGENTA				0xF81F
-#define GREEN					0x07E0
-#define CYAN 					0x7FFF
-#define YELLOW				0xFFE0
-#define BROWN					0XBC40 
-#define BRRED					0XFC07 
-#define GRAY 					0X8430 
-#define DARKBLUE			0X01CF	
-#define LIGHTBLUE			0X7D7C	 
-#define GRAYBLUE      0X5458 
-#define LIGHTGREEN    0X841F 
-#define LGRAY 			  0XC618 
-#define LGRAYBLUE     0XA651
-#define LBBLUE        0X2B12 
-
-
-#define IMAGE_BACKGROUND    WHITE
-#define FONT_FOREGROUND     BLACK
-#define FONT_BACKGROUND     WHITE
-
-/**
- * The size of the point
-**/
-typedef enum {
-    DOT_PIXEL_1X1  = 1,		// 1 x 1
-    DOT_PIXEL_2X2  , 		// 2 X 2
-    DOT_PIXEL_3X3  ,		// 3 X 3
-    DOT_PIXEL_4X4  ,		// 4 X 4
-    DOT_PIXEL_5X5  , 		// 5 X 5
-    DOT_PIXEL_6X6  , 		// 6 X 6
-    DOT_PIXEL_7X7  , 		// 7 X 7
-    DOT_PIXEL_8X8  , 		// 8 X 8
-} DOT_PIXEL;
-#define DOT_PIXEL_DFT  DOT_PIXEL_1X1  //Default dot pilex
-
-/**
- * Point size fill style
-**/
-typedef enum {
-    DOT_FILL_AROUND  = 1,		// dot pixel 1 x 1
-    DOT_FILL_RIGHTUP  , 		// dot pixel 2 X 2
-} DOT_STYLE;
-#define DOT_STYLE_DFT  DOT_FILL_AROUND  //Default dot pilex
-
-/**
- * Line style, solid or dashed
-**/
-typedef enum {
-    LINE_STYLE_SOLID = 0,
-    LINE_STYLE_DOTTED,
-} LINE_STYLE;
-
-/**
- * Whether the graphic is filled
-**/
-typedef enum {
-    DRAW_FILL_EMPTY = 0,
-    DRAW_FILL_FULL,
-} DRAW_FILL;
-
-/**
- * Custom structure of a time attribute
-**/
-typedef struct {
-    UWORD Year;  //0000
-    UBYTE  Month; //1 - 12
-    UBYTE  Day;   //1 - 30
-    UBYTE  Hour;  //0 - 23
-    UBYTE  Min;   //0 - 59
-    UBYTE  Sec;   //0 - 59
-} PAINT_TIME;
-extern PAINT_TIME sPaint_time;
-
-//init and Clear
-void Paint_NewImage(UWORD Width, UWORD Height, UWORD Rotate, UWORD Color);
-void Paint_SelectImage(UBYTE *image);
-void Paint_SetRotate(UWORD Rotate);
-void Paint_SetMirroring(UBYTE mirror);
-void Paint_SetPixel(UWORD Xpoint, UWORD Ypoint, UWORD Color);
-
-void Paint_Clear(UWORD Color);
-void Paint_ClearWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color);
-
-//Drawing
-void Paint_DrawPoint(UWORD Xpoint, UWORD Ypoint, UWORD Color, DOT_PIXEL Dot_Pixel, DOT_STYLE Dot_FillWay);
-void Paint_DrawLine(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color, LINE_STYLE Line_Style, DOT_PIXEL Dot_Pixel);
-void Paint_DrawRectangle(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color, DRAW_FILL Filled , DOT_PIXEL Dot_Pixel);
-void Paint_DrawCircle(UWORD X_Center, UWORD Y_Center, UWORD Radius, UWORD Color, DRAW_FILL Draw_Fill , DOT_PIXEL Dot_Pixel);
-
-//Display string
-void Paint_DrawChar(UWORD Xstart, UWORD Ystart, const char Acsii_Char, sFONT* Font, UWORD Color_Background, UWORD Color_Foreground);
-void Paint_DrawString_EN(UWORD Xstart, UWORD Ystart, const char * pString, sFONT* Font, UWORD Color_Background, UWORD Color_Foreground);
-void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font, UWORD Color_Background, UWORD Color_Foreground);
-void Paint_DrawNum(UWORD Xpoint, UWORD Ypoint, int32_t Nummber, sFONT* Font, UWORD Color_Background, UWORD Color_Foreground);
-void Paint_DrawTime(UWORD Xstart, UWORD Ystart, PAINT_TIME *pTime, sFONT* Font, UWORD Color_Background, UWORD Color_Foreground);
-
-//pic
-void Paint_DrawImage(const unsigned char *image,UWORD Startx, UWORD Starty,UWORD Endx, UWORD Endy); 
-
-
-#endif
-
-
-
-
-
diff --git a/lib/gfx/LCD/LCD_Driver.c b/lib/gfx/LCD/LCD_Driver.c
index af5d50e37f886dc6fa212cdca62b60e4594c6f22..b06fe1990cebdbf0c0597d164642b40c6baa3fbc 100644
--- a/lib/gfx/LCD/LCD_Driver.c
+++ b/lib/gfx/LCD/LCD_Driver.c
@@ -28,6 +28,8 @@
 #
 ******************************************************************************/
 #include "LCD_Driver.h"
+#include "framebuffer.h"
+
 static uint8_t screen[LCD_HEIGHT][LCD_WIDTH][2];
 
 /*******************************************************************************
@@ -319,3 +321,40 @@ void LCD_Update(void)
 {
 	LCD_Set((uint8_t *)screen, sizeof(screen));
 }
+
+static Color lcd_fb_encode_color_rgb_f(struct framebuffer *fb, float r,
+	 					    float g, float b) {
+	// RGB_565
+	const int r_max = (1 << 5) - 1;
+	const int g_max = (1 << 6) - 1;
+	const int b_max = (1 << 5) - 1;
+
+	int r_ = r * r_max;
+	int g_ = g * g_max;
+	int b_ = b * b_max;
+
+	Color o = 0;	
+	o |= (r_ << 11) & 0xf800;
+	o |= (g_ << 5) & 0x07e0;
+	o |= b_ & 0x001f;
+	return o;
+}
+
+static void lcd_fb_update(struct framebuffer *fb) {
+	LCD_Update();
+}
+
+static struct framebuffer framebuffer = {
+	.data = screen,
+	.width = LCD_WIDTH,
+	.height = LCD_HEIGHT,
+	.stride = LCD_WIDTH * LCD_HEIGHT * 2,
+	.orientation = FB_O_180,
+
+	.encode_color_rgb_f = lcd_fb_encode_color_rgb_f,
+	.update = lcd_fb_update,
+};
+
+struct framebuffer *LCD_framebuffer(void) {
+	return &framebuffer;
+}
diff --git a/lib/gfx/LCD/LCD_Driver.h b/lib/gfx/LCD/LCD_Driver.h
index 597956b2f7620dce0ab7f9034cc1ccdea953ab83..49358115beea4ac4a7f8ec30b2b827149c6dfdad 100644
--- a/lib/gfx/LCD/LCD_Driver.h
+++ b/lib/gfx/LCD/LCD_Driver.h
@@ -31,6 +31,7 @@
 #define __LCD_DRIVER_H
 
 #include "DEV_Config.h"
+#include "framebuffer.h"
 
 #define LCD_WIDTH   160 //LCD width
 #define LCD_HEIGHT  80 //LCD height
@@ -52,4 +53,6 @@ uint8_t *LCD_Framebuffer(void);
 void LCD_Set(uint8_t *data, int len);
 void LCD_Update(void);
 
+struct framebuffer *LCD_framebuffer(void);
+
 #endif
diff --git a/lib/gfx/framebuffer.c b/lib/gfx/framebuffer.c
new file mode 100644
index 0000000000000000000000000000000000000000..e72b8c1a0710ac975eecf47f1e07b924dddc49cd
--- /dev/null
+++ b/lib/gfx/framebuffer.c
@@ -0,0 +1,36 @@
+#include "framebuffer.h"
+
+void fb_clear_to_color(struct framebuffer *fb, Color c) {
+	for (int y = 0; y < fb->height; y++) {
+		for (int x = 0; x < fb->width; x++)
+			fb_setpixel(fb, x, y, c);
+	}
+}
+
+void fb_clear(struct framebuffer *fb) {
+	Color c = fb->encode_color_rgb_f(fb, .0f, .0f, .0f);
+	fb_clear_to_color(fb, c);
+}
+
+Color fb_encode_color_rgb(struct framebuffer *fb, int r, int g, int b) {
+	float r_ = (float)(r) / 255.0f;
+	float g_ = (float)(g) / 255.0f;
+	float b_ = (float)(b) / 255.0f;
+
+	return fb->encode_color_rgb_f(fb, r_, g_, b_);
+}
+
+Color fb_encode_color_rgb_f(struct framebuffer *fb, float r, float g,
+							   float b) {
+	return fb->encode_color_rgb_f(fb, r, g, b);
+}
+
+void fb_copy_raw(struct framebuffer *fb, const void *data,
+					    size_t size) {
+	size_t to_copy = size < fb->stride ? size : fb->stride;
+	memcpy(fb->data, data, to_copy);
+}
+
+void fb_update(struct framebuffer *fb) {
+	fb->update(fb);
+}
diff --git a/lib/gfx/framebuffer.h b/lib/gfx/framebuffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..9aa761caabfee17b9b9d8857694cc6d371bbd731
--- /dev/null
+++ b/lib/gfx/framebuffer.h
@@ -0,0 +1,96 @@
+#ifndef FRAMEBUFFER_H
+#define FRAMEBUFFER_H
+#include <stdint.h>
+#include <string.h>
+
+#define __FB_ALWAYS_INLINE __attribute__((always_inline))
+
+typedef unsigned int Color;
+
+enum orientation {
+	FB_O_0,
+	FB_O_90,
+	FB_O_180,
+	FB_O_270,
+};
+
+struct framebuffer {
+	void *data;
+	size_t width;
+	size_t height;
+	size_t stride;
+	int orientation;
+
+	Color (*encode_color_rgb_f)(struct framebuffer *fb, float r, float g,
+								    float b);
+	void (*update)(struct framebuffer *fb);
+};
+
+__FB_ALWAYS_INLINE
+inline size_t fb_bytes_per_pixel(const struct framebuffer *fb) {
+	const int pixels = fb->height * fb->width;
+	return fb->stride / pixels;
+}
+
+__FB_ALWAYS_INLINE
+inline void *fb_pixel(struct framebuffer *fb, int x, int y) {
+	int xo;
+	int yo;
+
+	switch (fb->orientation) {
+	case FB_O_0:
+		xo = x;
+		yo = y;
+		break;	
+	case FB_O_90:
+		xo = fb->width - y - 1;
+		yo = x;
+		break;
+	case FB_O_180:
+		xo = fb->width - x - 1;
+		yo = fb->height - y - 1;
+		break;
+	case FB_O_270:
+		xo = y;
+		yo = fb->height - x - 1;
+		break;
+	default:
+		return NULL;
+	}
+
+	if (xo < 0 || yo < 0)
+		return NULL;
+	if (xo >= fb->width || yo >= fb->height)
+		return NULL;
+
+	const size_t bpp = fb_bytes_per_pixel(fb);
+	return (void *)(fb->data) + yo * fb->width * bpp + xo * bpp;
+}
+
+__FB_ALWAYS_INLINE
+inline void fb_setpixel(struct framebuffer *fb, int x, int y, Color c) {
+	uint8_t *pixel = fb_pixel(fb, x, y);
+	if (pixel == NULL)
+		return;
+
+	const uint8_t *color = (const uint8_t *)(&c);
+	const size_t bpp = fb_bytes_per_pixel(fb);
+	switch (bpp) {
+	default:
+	case 2:
+		pixel[1] = color[0];
+		pixel[0] = color[1];
+	}
+}
+
+void fb_clear_to_color(struct framebuffer *fb, Color c);
+void fb_clear(struct framebuffer *fb);
+Color fb_encode_color_rgb(struct framebuffer *fb, int r, int g, int b);
+Color fb_encode_color_rgb_f(struct framebuffer *fb, float r, float g,
+							    float b);
+void fb_copy_raw(struct framebuffer *fb, const void *data,
+					     size_t size);
+void fb_update(struct framebuffer *fb);
+
+#undef __FB_ALWAYS_INLINE 
+#endif
diff --git a/lib/gfx/gfx.c b/lib/gfx/gfx.c
new file mode 100644
index 0000000000000000000000000000000000000000..085fe9153eb5e13da2f9f029ebf176dc8571ae34
--- /dev/null
+++ b/lib/gfx/gfx.c
@@ -0,0 +1,215 @@
+#include "gfx.h"
+#include "framebuffer.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <math.h>
+
+struct gfx_region gfx_screen(struct framebuffer *fb) {
+	struct gfx_region r = {
+		.fb = fb,
+		.x = 0,
+		.y = 0,
+		.width = fb->width,
+		.height = fb->height
+	};
+	return r;
+}
+
+static inline int letter_bit(sFONT *font, char c, int x, int y) {
+	if (x < 0 || y < 0)
+		return 0;
+	if (x >= font->Width || y >= font->Height)
+		return 0;
+	if (c < ' ' || c > '~')
+		return 0;
+
+	size_t bytes_per_row = font->Width / 8 + 1;
+	size_t bytes_per_letter = bytes_per_row * font->Height;
+	int letter = c - ' ';
+	const uint8_t *letter_ptr = font->table + bytes_per_letter * letter;
+	int horz_byte = x / 8;
+	int horz_bit = 7 - x % 8;
+
+	return (*(letter_ptr + y * bytes_per_row + horz_byte) >> horz_bit) & 1;
+}
+
+void gfx_putchar(sFONT *font, struct gfx_region *r, int x, int y, char ch,
+						     Color fg, Color bg) {
+	for (int yo = 0; yo < font->Height; yo++) {
+		for (int xo = 0; xo < font->Width; xo++) {
+			int lb = letter_bit(font, ch, xo, yo);
+
+			if (fg != bg) {
+				Color c = lb ? fg : bg;
+				gfx_setpixel(r, x + xo, y + yo, c);
+			} else {
+				if (lb) {
+					gfx_setpixel(r, x + xo, y + yo, fg);
+				}
+			}
+		}
+	}
+}
+
+void gfx_puts(sFONT *font, struct gfx_region *r, int x, int y, const char *str,
+						    	  Color fg, Color bg) {
+	while (*str) {
+		x += font->Width;
+		if (x >= r->width) {
+			x = 0;
+			y += font->Height;
+		}
+		if (y >= r->height) {
+			y = 0;
+			x = 0;
+		}
+		gfx_putchar(font, r, x, y, *str, fg, bg);
+		str++;
+	}
+}
+
+Color gfx_color_rgb_f(struct gfx_region *reg, float r, float g, float b) {
+	return fb_encode_color_rgb_f(reg->fb, r, g, b); 
+}
+
+Color gfx_color_rgb(struct gfx_region *reg, uint8_t r, uint8_t g, uint8_t b) {
+	return fb_encode_color_rgb(reg->fb, r, g, b);
+}
+
+void gfx_update(struct gfx_region *reg) {
+	reg->fb->update(reg->fb);
+}
+
+void gfx_clear_to_color(struct gfx_region *reg, Color c) {
+	fb_clear_to_color(reg->fb, c);	
+}
+
+void gfx_clear(struct gfx_region *reg) {
+	gfx_clear_to_color(reg, gfx_color(reg, BLACK));
+}
+
+void gfx_circle(struct gfx_region *reg, int x, int y, int r, int t, Color c) {
+	for (int y_ = y - r; y_ <= y + r; y_++) {
+		for (int x_ = x - r; x_ <= x + r; x_++) {
+			int dx = (x_ - x) * (x_ - x);
+			int dy = (y_ - y) * (y_ - y);
+			int outer = (r + t) * (r + t);
+			int inner = r * r;
+			int edge = ((dx + dy) >= inner) && ((dx + dy) <= outer);
+			if (edge)
+				gfx_setpixel(reg, x_, y_, c);
+		}
+	}
+}
+
+void gfx_circle_fill(struct gfx_region *reg, int x, int y, int r, Color c) {
+	for (int y_ = y - r; y_ <= y + r; y_++) {
+		for (int x_ = x - r; x_ <= x + r; x_++) {
+			int dx = (x_ - x) * (x_ - x);
+			int dy = (y_ - y) * (y_ - y);
+			int edge = r * r;
+			int fill = (dx + dy) <= edge;
+			if (fill)
+				gfx_setpixel(reg, x_, y_, c);
+		}
+	}
+}
+
+void gfx_rectangle(struct gfx_region *reg, int x, int y, int w, int h,
+						     int t, Color c) {
+	if (t > 1) {
+		gfx_thick_line(reg, x, y, x + w, y, t, c);
+		gfx_thick_line(reg, x, y + h, x + w, y + h, t, c);
+		gfx_thick_line(reg, x, y, x, y + h, t, c);
+		gfx_thick_line(reg, x + w, y, x + w, y + h, t, c);
+	} else {
+		gfx_line(reg, x, y, x + w, y, c);
+		gfx_line(reg, x, y + h, x + w, y + h, c);
+		gfx_line(reg, x, y, x, y + h, c);
+		gfx_line(reg, x + w, y, x + w, y + h, c);
+	}
+}
+
+void gfx_rectangle_fill(struct gfx_region *reg, int x, int y, int w, int h,
+								 Color c) {
+	for (int y_ = y; y_ < y + h; y_++) {
+		for (int x_ = x; x_ < x + w; x_++)
+			gfx_setpixel(reg, x_, y_, c);
+	}
+}
+
+void gfx_line(struct gfx_region *reg, int x1, int y1, int x2, int y2, Color c) {
+	float dx = x2 - x1;
+	float dy = y2 - y1;
+	float de = fabs(dy / dx);
+	float e = .0f;
+	int y = y1;
+	for (int x = x1; x < x2; x++) {
+		gfx_setpixel(reg, x, y, c);
+		e += de;
+		if (e >= .5f) {
+			y += dy >= .0f ? 1 : -1;
+			e -= 1.0f;
+		}
+	}
+}
+
+void gfx_thick_line(struct gfx_region *reg, int x1, int y1, int x2, int y2,
+							  int t, Color c) {
+	float dx = x2 - x1;
+	float dy = y2 - y1;
+	float de = fabs(dy / dx);
+	float e = .0f;
+	int y = y1;
+	for (int x = x1; x < x2; x++) {
+		gfx_circle_fill(reg, x, y, t, c);
+		e += de;
+		if (e >= .5f) {
+			y += dy >= .0f ? 1 : -1;
+			e -= 1.0f;
+		}
+	}
+}
+
+Color gfx_color(struct gfx_region *reg, enum gfx_color color) {
+	switch (color) {
+	case WHITE:
+		return gfx_color_rgb_f(reg, 1.0f, 1.0f, 1.0f);
+	case BLACK:
+		return gfx_color_rgb_f(reg, .0f, .0f, .0f);
+	case RED:
+		return gfx_color_rgb_f(reg, 1.0f, .0f, .0f);
+	case GREEN:
+		return gfx_color_rgb_f(reg, .0f, 1.0f, .0f);
+	case BLUE:
+		return gfx_color_rgb_f(reg, .0f, .0f, 1.0f);
+	case YELLOW:
+		return gfx_color_rgb_f(reg, 1.0f, 1.0f, .0f);
+	default:
+		break;
+	}
+	return gfx_color_rgb_f(reg, .0f, .0f, .0f);
+}
+
+void gfx_copy_region_raw(struct gfx_region *reg, int x, int y, int w, int h,
+					 	size_t bpp, const void *p) {
+	for (int y_ = 0; y_ < h; y_++) {
+		for (int x_ = 0; x_ < w; x_++) {
+			Color c;
+
+			switch (bpp) {
+			default:
+			case 2:
+				c = *(const uint16_t *)(p);
+				break;
+			}
+
+			gfx_setpixel(reg, x + x_, y + y_, c);
+			p += bpp;
+		}
+	}
+}
+
+void gfx_copy_raw(struct gfx_region *reg, const void *p, size_t size) {
+	fb_copy_raw(reg->fb, p, size);
+}
diff --git a/lib/gfx/gfx.h b/lib/gfx/gfx.h
new file mode 100644
index 0000000000000000000000000000000000000000..bdf36dae7eb8d4e3f85bf6bbae1646672f36373a
--- /dev/null
+++ b/lib/gfx/gfx.h
@@ -0,0 +1,62 @@
+#ifndef GFX_H
+#define GFX_H
+#include <stddef.h>
+#include "fonts.h"
+#include "framebuffer.h"
+
+#define __GFX_ALWAYS_INLINE __attribute__((always_inline))
+
+struct gfx_region {
+	struct framebuffer *fb;
+	size_t x;
+	size_t y;
+	size_t width;
+	size_t height;
+};
+
+__GFX_ALWAYS_INLINE
+inline void gfx_setpixel(struct gfx_region *r, int x, int y, Color c) {
+	if (x < 0 || y < 0)
+		return;
+	if (x >= r->width || y >= r->height)
+		return;
+
+	fb_setpixel(r->fb, r->x + x, r->y + y, c);
+}
+
+struct gfx_region gfx_screen(struct framebuffer *fb);
+void gfx_putchar(sFONT *font, struct gfx_region *reg, int x, int y, char ch,
+						        Color fg, Color bg);
+void gfx_puts(sFONT *font, struct gfx_region *reg, int x, int y,
+			   const char *str, Color fg, Color bg);
+Color gfx_color_rgb_f(struct gfx_region *reg, float r, float g, float b);
+Color gfx_color_rgb(struct gfx_region *reg, uint8_t r, uint8_t g, uint8_t b);
+void gfx_clear_to_color(struct gfx_region *reg, Color c);
+void gfx_clear(struct gfx_region *reg);
+void gfx_circle(struct gfx_region *reg, int x, int y, int r, int t, Color c);
+void gfx_circle_fill(struct gfx_region *reg, int x, int y, int r, Color c);
+void gfx_rectangle(struct gfx_region *reg, int x, int y, int w, int h,
+						      int t, Color c);
+void gfx_rectangle_fill(struct gfx_region *reg, int x, int y, int w, int h,
+								  Color c);
+void gfx_line(struct gfx_region *reg, int x1, int y1, int x2, int y2, Color c);
+void gfx_thick_line(struct gfx_region *reg, int x1, int y1, int x2, int y2,
+							   int t, Color c);
+void gfx_update(struct gfx_region *reg);
+
+enum gfx_color {
+	WHITE,
+	BLACK,
+	RED,
+	GREEN,
+	BLUE,
+	YELLOW
+};
+Color gfx_color(struct gfx_region *reg, enum gfx_color color);
+
+void gfx_copy_region_raw(struct gfx_region *reg, int x, int y, int w, int h,
+					         size_t bpp, const void *p);
+void gfx_copy_raw(struct gfx_region *reg, const void *p, size_t size);
+
+#undef __GFX_ALWAYS_INLINE
+#endif
diff --git a/lib/gfx/meson.build b/lib/gfx/meson.build
index 41b377b1fbe12469e8411b23f597b2af51f40e5c..37b90e436950b8e2b164dcb0bede57373281d4ce 100644
--- a/lib/gfx/meson.build
+++ b/lib/gfx/meson.build
@@ -7,7 +7,6 @@ includes = include_directories(
 
 sources = files(
   './GUI_DEV/DEV_Config.c',
-  './GUI_DEV/GUI_Paint.c',
   './LCD/LCD_Driver.c',
   './Fonts/font8.c',
   './Fonts/font12.c',
@@ -16,6 +15,9 @@ sources = files(
   './Fonts/font20.c',
   './Fonts/font24.c',
   './Fonts/font24CN.c',
+  'framebuffer.c',
+  'gfx.c',
+  'textbuffer.c'
 )
 
 lib = static_library(
diff --git a/lib/gfx/textbuffer.c b/lib/gfx/textbuffer.c
new file mode 100644
index 0000000000000000000000000000000000000000..533b2316da44dc5e02bc65bced6b5c9e61868057
--- /dev/null
+++ b/lib/gfx/textbuffer.c
@@ -0,0 +1,224 @@
+#include "textbuffer.h"
+#include "gfx.h"
+#include <string.h>
+
+void txt_init(struct txt_buffer *txtb, struct gfx_region *reg, sFONT *f) {
+	txtb->reg = reg;
+	txtb->font = f;
+	txtb->cursor_column = 0;
+	txtb->cursor_row = 0;
+	txtb->fg_color = gfx_color_rgb_f(reg, 1.0f, 1.0f, 1.0f);
+	txtb->bg_color = gfx_color_rgb_f(reg, .0f, .0f, .0f);
+	txtb->draw_cursor = 1;
+	txtb->auto_update = 1;
+
+	txt_clear(txtb);
+}
+
+static inline size_t width_(struct txt_buffer *tm) {
+	return tm->reg->width / tm->font->Width;
+}
+
+static inline size_t height_(struct txt_buffer *tm) {
+	return tm->reg->height / tm->font->Height;
+}
+
+size_t txt_width(struct txt_buffer *tm) {
+	return width_(tm);
+}
+
+size_t txt_height(struct txt_buffer *tm) {
+	return height_(tm);
+}
+
+static void scrollup(struct txt_buffer *tm) {
+	const int last_row = height_(tm) - 1;
+	const size_t line_size = width_(tm) * sizeof(struct txt_glyph);
+
+	for (int row = 0; row < last_row; row++)
+		memcpy(&tm->text[row][0], &tm->text[row + 1][0], line_size);
+	for (int col = 0; col < width_(tm); col++) {
+		struct txt_glyph *g = &tm->text[last_row][col];
+		g->ch = ' ';
+		g->fg_color = tm->fg_color;
+		g->bg_color = tm->bg_color;
+	}
+}
+
+static void newline(struct txt_buffer *tm) {
+	const int last_row = height_(tm) - 1;
+
+	scrollup(tm);
+	tm->cursor_row = last_row;
+	tm->cursor_column = 0;
+}
+
+static inline void advance_cursor(struct txt_buffer *tm) {
+	const int last_row = height_(tm) - 1;
+
+	tm->cursor_column++;
+	if (tm->cursor_column >= width_(tm)) {
+		tm->cursor_column = 0;
+		tm->cursor_row++;
+		if (tm->cursor_row > last_row)
+			newline(tm);
+	}
+}
+
+static void tab(struct txt_buffer *tm) {
+	while(tm->cursor_column % 5)
+		txt_putchar(tm, ' ');
+}
+
+static inline struct txt_glyph *getchar_(struct txt_buffer *tm, int x,
+							      int y) {
+	if (x < 0 || x >= TEXTBUFFER_MAX_WIDTH)
+		return NULL;
+	if (y < 0 || y >= TEXTBUFFER_MAX_HEIGHT)
+		return NULL;
+	return &tm->text[y][x];
+}
+
+void txt_clear(struct txt_buffer *tm) {
+	int w = width_(tm);
+	int h = height_(tm);
+	for (int r = 0; r < h; r++) {
+		for (int c = 0; c < w; c++) {
+			struct txt_glyph *g = getchar_(tm, c, r);
+			if (g == NULL)
+				continue;
+
+			g->ch = ' ';
+			g->fg_color = tm->fg_color;
+			g->bg_color = tm->bg_color;
+		}
+	}
+
+	tm->cursor_column = 0;
+	tm->cursor_row = 0;
+
+	if (tm->auto_update)
+		txt_update(tm);
+}
+
+void txt_putchar(struct txt_buffer *tm, char ch) {
+	struct txt_glyph *g = getchar_(tm, tm->cursor_column, tm->cursor_row);
+	if (g == NULL)
+		return;
+
+	switch (ch) {
+	case '\n':
+		newline(tm);
+		break;
+	case '\t':
+		tab(tm);
+		break;
+	default:
+		g->ch = ch;
+		g->fg_color = tm->fg_color;
+		g->bg_color = tm->bg_color;
+		advance_cursor(tm);
+	}
+
+	if (tm->auto_update)
+		txt_update(tm);
+}
+
+void txt_puts(struct txt_buffer *tm, const char *str) {
+	while (*str) {
+		txt_putchar(tm, *str);
+		str++;
+	}
+}
+
+static inline int cursor_px_column(struct txt_buffer *tm) {
+	return tm->font->Width * tm->cursor_column;
+}
+
+static inline int cursor_px_row(struct txt_buffer *tm) {
+	return tm->font->Height * tm->cursor_row;
+}
+
+static void draw_cursor_(struct txt_buffer *tm) {
+	const int x = cursor_px_column(tm);
+	const int y = cursor_px_row(tm);
+	const int w = tm->font->Width;
+	const int h = tm->font->Height;
+	gfx_rectangle_fill(tm->reg, x, y, w, h, tm->fg_color);
+}
+
+void txt_draw(struct txt_buffer *tm) {
+	const int w = width_(tm);
+	const int h = height_(tm);
+	int px_column = 0;
+	int px_row = 0;
+
+	for (int r = 0; r < h; r++) {
+		px_column = 0;
+		for (int c = 0; c < w; c++) {
+			struct txt_glyph *g = getchar_(tm, c, r);
+			if (g == NULL)
+				continue;
+
+			gfx_putchar(tm->font, tm->reg, px_column, px_row,
+					g->ch, g->fg_color, g->bg_color);
+			px_column += tm->font->Width;
+		}
+
+		px_row += tm->font->Height;
+	}
+
+	if (tm->draw_cursor)
+		draw_cursor_(tm);
+}
+
+void txt_set_color_f(struct txt_buffer *tm, enum txt_color sw, float r, float g,
+							    	    float b) {
+	Color c = gfx_color_rgb_f(tm->reg, r, g, b);
+
+	switch (c) {
+	case TEXT_FOREGROUND:
+		tm->fg_color = c;
+		break;
+	case TEXT_BACKGROUND:
+		tm->bg_color = c;
+		break;
+	}
+}
+
+void txt_set_color(struct txt_buffer *tm, enum txt_color sw, int r, int g,
+							        int b) {
+	Color c = gfx_color_rgb(tm->reg, r, g, b);
+
+	switch (c) {
+	case TEXT_FOREGROUND:
+		tm->fg_color = c;
+		break;
+	case TEXT_BACKGROUND:
+		tm->bg_color = c;
+		break;
+	}
+}
+
+void txt_set_cursor(struct txt_buffer *tm, int x, int y, int draw_cursor) {
+	tm->draw_cursor = draw_cursor;
+
+	if (x < 0 || x >= width_(tm))
+		return;
+	if (y < 0 || y >= height_(tm))
+		return;
+
+	tm->cursor_column = x;
+	tm->cursor_row = y;
+
+	if (tm->auto_update)
+		txt_update(tm);
+}
+
+void txt_set_transparent(struct txt_buffer *tm) {
+	tm->bg_color = tm->fg_color;
+}
+
+void txt_update(struct txt_buffer *tm) {
+	gfx_update(tm->reg);
+}
diff --git a/lib/gfx/textbuffer.h b/lib/gfx/textbuffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..bec52bbeaad535dcb749de568236f91e200be929
--- /dev/null
+++ b/lib/gfx/textbuffer.h
@@ -0,0 +1,49 @@
+#ifndef TEXTBUFFER_H
+#define TEXTBUFFER_H
+#include "gfx.h"
+#include "fonts.h"
+#include <stdint.h>
+
+#define TEXTBUFFER_MAX_WIDTH 40
+#define TEXTBUFFER_MAX_HEIGHT 20
+
+struct txt_glyph {
+	char ch;
+	Color fg_color;
+	Color bg_color;
+};
+
+struct txt_buffer {
+	struct gfx_region *reg;
+	sFONT *font;
+	int cursor_column;
+	int cursor_row;
+	Color fg_color;
+	Color bg_color;
+	int draw_cursor;
+	int auto_update;
+
+	struct txt_glyph text[TEXTBUFFER_MAX_HEIGHT][TEXTBUFFER_MAX_WIDTH];
+};
+
+enum txt_color {
+	TEXT_FOREGROUND,
+	TEXT_BACKGROUND
+};
+
+void txt_init(struct txt_buffer *txtb, struct gfx_region *reg, sFONT *f);
+size_t txt_width(struct txt_buffer *tm);
+size_t txt_height(struct txt_buffer *tm);
+void txt_clear(struct txt_buffer *tm);
+void txt_putchar(struct txt_buffer *tm, char ch);
+void txt_puts(struct txt_buffer *tm, const char *str);
+void txt_draw(struct txt_buffer *tm);
+void txt_set_color_f(struct txt_buffer *tm, enum txt_color sw, float r, float g,
+								     float b);
+void txt_set_color(struct txt_buffer *tm, enum txt_color sw, int r, int g,
+								 int b);
+void txt_set_transparent(struct txt_buffer *tm);
+void txt_set_cursor(struct txt_buffer *tm, int x, int y, int draw_cursor);
+void txt_update(struct txt_buffer *tm);
+
+#endif