Просмотр исходного кода

[FL-2524] Graphics cleanup and icon rotation (#2561)

* Canvas with rotation
* Full icon rotation, cleanup of unused resources
* F18 API update
* Bitmap draw cleanup
* More cleaning up
* Migrate recovery and DFU to canvas
* Make the internal draw function static
* Remove all calls to u8g2_DrawXBM

Co-authored-by: あく <alleteam@gmail.com>
Astra 2 лет назад
Родитель
Сommit
b4ceb55fd2

+ 4 - 4
applications/external/dap_link/gui/views/dap_main_view.c

@@ -51,10 +51,10 @@ static void dap_main_view_draw_callback(Canvas* canvas, void* _model) {
     canvas_set_color(canvas, ColorBlack);
     if(model->dap_active) {
         canvas_draw_icon(canvas, 14, 16, &I_ArrowUpFilled_12x18);
-        canvas_draw_icon(canvas, 28, 16, &I_ArrowDownFilled_12x18);
+        canvas_draw_icon_ex(canvas, 28, 16, &I_ArrowUpFilled_12x18, IconRotation180);
     } else {
         canvas_draw_icon(canvas, 14, 16, &I_ArrowUpEmpty_12x18);
-        canvas_draw_icon(canvas, 28, 16, &I_ArrowDownEmpty_12x18);
+        canvas_draw_icon_ex(canvas, 28, 16, &I_ArrowUpEmpty_12x18, IconRotation180);
     }
 
     switch(model->mode) {
@@ -76,9 +76,9 @@ static void dap_main_view_draw_callback(Canvas* canvas, void* _model) {
     }
 
     if(model->rx_active) {
-        canvas_draw_icon(canvas, 101, 16, &I_ArrowDownFilled_12x18);
+        canvas_draw_icon_ex(canvas, 101, 16, &I_ArrowUpFilled_12x18, IconRotation180);
     } else {
-        canvas_draw_icon(canvas, 101, 16, &I_ArrowDownEmpty_12x18);
+        canvas_draw_icon_ex(canvas, 101, 16, &I_ArrowUpEmpty_12x18, IconRotation180);
     }
 
     canvas_draw_str_aligned(canvas, 100, 38, AlignCenter, AlignTop, "UART");

BIN
applications/external/dap_link/icons/ArrowDownEmpty_12x18.png


BIN
applications/external/dap_link/icons/ArrowDownFilled_12x18.png


+ 2 - 2
applications/main/gpio/views/gpio_usb_uart.c

@@ -80,9 +80,9 @@ static void gpio_usb_uart_draw_callback(Canvas* canvas, void* _model) {
         canvas_draw_icon(canvas, 48, 14, &I_ArrowUpEmpty_14x15);
 
     if(model->rx_active)
-        canvas_draw_icon(canvas, 48, 34, &I_ArrowDownFilled_14x15);
+        canvas_draw_icon_ex(canvas, 48, 34, &I_ArrowUpFilled_14x15, IconRotation180);
     else
-        canvas_draw_icon(canvas, 48, 34, &I_ArrowDownEmpty_14x15);
+        canvas_draw_icon_ex(canvas, 48, 34, &I_ArrowUpEmpty_14x15, IconRotation180);
 }
 
 static bool gpio_usb_uart_input_callback(InputEvent* event, void* context) {

+ 2 - 2
applications/services/desktop/desktop.c

@@ -37,7 +37,7 @@ static void desktop_loader_callback(const void* message, void* context) {
 static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) {
     UNUSED(context);
     furi_assert(canvas);
-    canvas_draw_icon(canvas, 0, 0, &I_Lock_8x8);
+    canvas_draw_icon(canvas, 0, 0, &I_Lock_7x8);
 }
 
 static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) {
@@ -230,7 +230,7 @@ Desktop* desktop_alloc() {
 
     // Lock icon
     desktop->lock_icon_viewport = view_port_alloc();
-    view_port_set_width(desktop->lock_icon_viewport, icon_get_width(&I_Lock_8x8));
+    view_port_set_width(desktop->lock_icon_viewport, icon_get_width(&I_Lock_7x8));
     view_port_draw_callback_set(
         desktop->lock_icon_viewport, desktop_lock_icon_draw_callback, desktop);
     view_port_enabled_set(desktop->lock_icon_viewport, false);

+ 8 - 5
applications/services/desktop/views/desktop_view_pin_input.c

@@ -115,16 +115,18 @@ static void desktop_view_pin_input_draw_cells(Canvas* canvas, DesktopViewPinInpu
             } else {
                 switch(model->pin.data[i]) {
                 case InputKeyDown:
-                    canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_down_7x9);
+                    canvas_draw_icon_ex(
+                        canvas, x + 3, y + 2, &I_Pin_arrow_up_7x9, IconRotation180);
                     break;
                 case InputKeyUp:
-                    canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_up_7x9);
+                    canvas_draw_icon_ex(canvas, x + 3, y + 2, &I_Pin_arrow_up_7x9, IconRotation0);
                     break;
                 case InputKeyLeft:
-                    canvas_draw_icon(canvas, x + 2, y + 3, &I_Pin_arrow_left_9x7);
+                    canvas_draw_icon_ex(
+                        canvas, x + 2, y + 3, &I_Pin_arrow_up_7x9, IconRotation270);
                     break;
                 case InputKeyRight:
-                    canvas_draw_icon(canvas, x + 2, y + 3, &I_Pin_arrow_right_9x7);
+                    canvas_draw_icon_ex(canvas, x + 2, y + 3, &I_Pin_arrow_up_7x9, IconRotation90);
                     break;
                 default:
                     furi_assert(0);
@@ -147,7 +149,8 @@ static void desktop_view_pin_input_draw(Canvas* canvas, void* context) {
     desktop_view_pin_input_draw_cells(canvas, model);
 
     if((model->pin.length > 0) && !model->locked_input) {
-        canvas_draw_icon(canvas, 4, 53, &I_Pin_back_full_40x8);
+        canvas_draw_icon(canvas, 4, 53, &I_Pin_back_arrow_10x8);
+        canvas_draw_str(canvas, 16, 60, "= clear");
     }
 
     if(model->button_label && ((model->pin.length >= MIN_PIN_SIZE) || model->locked_input)) {

+ 131 - 5
applications/services/gui/canvas.c

@@ -221,7 +221,7 @@ void canvas_draw_bitmap(
     y += canvas->offset_y;
     uint8_t* bitmap_data = NULL;
     compress_icon_decode(canvas->compress_icon, compressed_bitmap_data, &bitmap_data);
-    u8g2_DrawXBM(&canvas->fb, x, y, width, height, bitmap_data);
+    canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap_data, IconRotation0);
 }
 
 void canvas_draw_icon_animation(
@@ -237,13 +237,138 @@ void canvas_draw_icon_animation(
     uint8_t* icon_data = NULL;
     compress_icon_decode(
         canvas->compress_icon, icon_animation_get_data(icon_animation), &icon_data);
-    u8g2_DrawXBM(
+    canvas_draw_u8g2_bitmap(
         &canvas->fb,
         x,
         y,
         icon_animation_get_width(icon_animation),
         icon_animation_get_height(icon_animation),
-        icon_data);
+        icon_data,
+        IconRotation0);
+}
+
+static void canvas_draw_u8g2_bitmap_int(
+    u8g2_t* u8g2,
+    u8g2_uint_t x,
+    u8g2_uint_t y,
+    u8g2_uint_t w,
+    u8g2_uint_t h,
+    bool mirror,
+    bool rotation,
+    const uint8_t* bitmap) {
+    u8g2_uint_t blen;
+    blen = w;
+    blen += 7;
+    blen >>= 3;
+
+    if(rotation && !mirror) {
+        x += w + 1;
+    } else if(mirror && !rotation) {
+        y += h - 1;
+    }
+
+    while(h > 0) {
+        const uint8_t* b = bitmap;
+        uint16_t len = w;
+        uint16_t x0 = x;
+        uint16_t y0 = y;
+        uint8_t mask;
+        uint8_t color = u8g2->draw_color;
+        uint8_t ncolor = (color == 0 ? 1 : 0);
+        mask = 1;
+
+        while(len > 0) {
+            if(u8x8_pgm_read(b) & mask) {
+                u8g2->draw_color = color;
+                u8g2_DrawHVLine(u8g2, x0, y0, 1, 0);
+            } else if(u8g2->bitmap_transparency == 0) {
+                u8g2->draw_color = ncolor;
+                u8g2_DrawHVLine(u8g2, x0, y0, 1, 0);
+            }
+
+            if(rotation) {
+                y0++;
+            } else {
+                x0++;
+            }
+
+            mask <<= 1;
+            if(mask == 0) {
+                mask = 1;
+                b++;
+            }
+            len--;
+        }
+
+        u8g2->draw_color = color;
+        bitmap += blen;
+
+        if(mirror) {
+            if(rotation) {
+                x++;
+            } else {
+                y--;
+            }
+        } else {
+            if(rotation) {
+                x--;
+            } else {
+                y++;
+            }
+        }
+        h--;
+    }
+}
+
+void canvas_draw_u8g2_bitmap(
+    u8g2_t* u8g2,
+    u8g2_uint_t x,
+    u8g2_uint_t y,
+    u8g2_uint_t w,
+    u8g2_uint_t h,
+    const uint8_t* bitmap,
+    IconRotation rotation) {
+    u8g2_uint_t blen;
+    blen = w;
+    blen += 7;
+    blen >>= 3;
+#ifdef U8G2_WITH_INTERSECTION
+    if(u8g2_IsIntersection(u8g2, x, y, x + w, y + h) == 0) return;
+#endif /* U8G2_WITH_INTERSECTION */
+
+    switch(rotation) {
+    case IconRotation0:
+        canvas_draw_u8g2_bitmap_int(u8g2, x, y, w, h, 0, 0, bitmap);
+        break;
+    case IconRotation90:
+        canvas_draw_u8g2_bitmap_int(u8g2, x, y, w, h, 0, 1, bitmap);
+        break;
+    case IconRotation180:
+        canvas_draw_u8g2_bitmap_int(u8g2, x, y, w, h, 1, 0, bitmap);
+        break;
+    case IconRotation270:
+        canvas_draw_u8g2_bitmap_int(u8g2, x, y, w, h, 1, 1, bitmap);
+        break;
+    default:
+        break;
+    }
+}
+
+void canvas_draw_icon_ex(
+    Canvas* canvas,
+    uint8_t x,
+    uint8_t y,
+    const Icon* icon,
+    IconRotation rotation) {
+    furi_assert(canvas);
+    furi_assert(icon);
+
+    x += canvas->offset_x;
+    y += canvas->offset_y;
+    uint8_t* icon_data = NULL;
+    compress_icon_decode(canvas->compress_icon, icon_get_data(icon), &icon_data);
+    canvas_draw_u8g2_bitmap(
+        &canvas->fb, x, y, icon_get_width(icon), icon_get_height(icon), icon_data, rotation);
 }
 
 void canvas_draw_icon(Canvas* canvas, uint8_t x, uint8_t y, const Icon* icon) {
@@ -254,7 +379,8 @@ void canvas_draw_icon(Canvas* canvas, uint8_t x, uint8_t y, const Icon* icon) {
     y += canvas->offset_y;
     uint8_t* icon_data = NULL;
     compress_icon_decode(canvas->compress_icon, icon_get_data(icon), &icon_data);
-    u8g2_DrawXBM(&canvas->fb, x, y, icon_get_width(icon), icon_get_height(icon), icon_data);
+    canvas_draw_u8g2_bitmap(
+        &canvas->fb, x, y, icon_get_width(icon), icon_get_height(icon), icon_data, IconRotation0);
 }
 
 void canvas_draw_dot(Canvas* canvas, uint8_t x, uint8_t y) {
@@ -364,7 +490,7 @@ void canvas_draw_xbm(
     furi_assert(canvas);
     x += canvas->offset_x;
     y += canvas->offset_y;
-    u8g2_DrawXBM(&canvas->fb, x, y, w, h, bitmap);
+    canvas_draw_u8g2_bitmap(&canvas->fb, x, y, w, h, bitmap, IconRotation0);
 }
 
 void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch) {

+ 32 - 0
applications/services/gui/canvas.h

@@ -64,6 +64,22 @@ typedef struct {
     uint8_t descender;
 } CanvasFontParameters;
 
+/** Icon flip */
+typedef enum {
+    IconFlipNone,
+    IconFlipHorizontal,
+    IconFlipVertical,
+    IconFlipBoth,
+} IconFlip;
+
+/** Icon rotation */
+typedef enum {
+    IconRotation0,
+    IconRotation90,
+    IconRotation180,
+    IconRotation270,
+} IconRotation;
+
 /** Canvas anonymous structure */
 typedef struct Canvas Canvas;
 
@@ -217,6 +233,22 @@ void canvas_draw_bitmap(
     uint8_t height,
     const uint8_t* compressed_bitmap_data);
 
+/** Draw icon at position defined by x,y with rotation and flip.
+ *
+ * @param      canvas   Canvas instance
+ * @param      x        x coordinate
+ * @param      y        y coordinate
+ * @param      icon     Icon instance
+ * @param      flip     IconFlip
+ * @param      rotation IconRotation
+ */
+void canvas_draw_icon_ex(
+    Canvas* canvas,
+    uint8_t x,
+    uint8_t y,
+    const Icon* icon,
+    IconRotation rotation);
+
 /** Draw animation at position defined by x,y.
  *
  * @param      canvas          Canvas instance

+ 19 - 0
applications/services/gui/canvas_i.h

@@ -78,3 +78,22 @@ void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation);
  * @return     CanvasOrientation
  */
 CanvasOrientation canvas_get_orientation(const Canvas* canvas);
+
+/** Draw a u8g2 bitmap
+ *
+ * @param      canvas   Canvas instance
+ * @param      x        x coordinate
+ * @param      y        y coordinate
+ * @param      width    width
+ * @param      height   height
+ * @param      bitmap   bitmap
+ * @param      rotation rotation
+ */
+void canvas_draw_u8g2_bitmap(
+    u8g2_t* u8g2,
+    uint8_t x,
+    uint8_t y,
+    uint8_t width,
+    uint8_t height,
+    const uint8_t* bitmap,
+    uint8_t rotation);

BIN
assets/icons/GPIO/ArrowDownEmpty_14x15.png


BIN
assets/icons/GPIO/ArrowDownFilled_14x15.png


BIN
assets/icons/PIN/Pin_arrow_down_7x9.png


BIN
assets/icons/PIN/Pin_arrow_left_9x7.png


BIN
assets/icons/PIN/Pin_arrow_right_9x7.png


BIN
assets/icons/PIN/Pin_back_full_40x8.png


BIN
assets/icons/StatusBar/Lock_8x8.png


+ 2 - 7
firmware/targets/f18/api_symbols.csv

@@ -1,5 +1,5 @@
 entry,status,name,type,params
-Version,+,20.0,,
+Version,+,20.1,,
 Header,+,applications/services/bt/bt_service/bt.h,,
 Header,+,applications/services/cli/cli.h,,
 Header,+,applications/services/cli/cli_vcp.h,,
@@ -539,6 +539,7 @@ Function,+,canvas_draw_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
 Function,+,canvas_draw_glyph,void,"Canvas*, uint8_t, uint8_t, uint16_t"
 Function,+,canvas_draw_icon,void,"Canvas*, uint8_t, uint8_t, const Icon*"
 Function,+,canvas_draw_icon_animation,void,"Canvas*, uint8_t, uint8_t, IconAnimation*"
+Function,+,canvas_draw_icon_ex,void,"Canvas*, uint8_t, uint8_t, const Icon*, IconRotation"
 Function,+,canvas_draw_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
 Function,+,canvas_draw_rbox,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t"
 Function,+,canvas_draw_rframe,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t"
@@ -875,12 +876,6 @@ Function,-,furi_hal_clock_resume_tick,void,
 Function,-,furi_hal_clock_suspend_tick,void,
 Function,-,furi_hal_clock_switch_to_hsi,void,
 Function,-,furi_hal_clock_switch_to_pll,void,
-Function,-,compress_alloc,Compress*,uint16_t
-Function,-,compress_decode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*"
-Function,-,compress_encode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*"
-Function,-,compress_free,void,Compress*
-Function,-,compress_icon_decode,void,"const uint8_t*, uint8_t**"
-Function,-,compress_icon_init,void,
 Function,+,furi_hal_console_disable,void,
 Function,+,furi_hal_console_enable,void,
 Function,+,furi_hal_console_init,void,

+ 2 - 1
firmware/targets/f7/api_symbols.csv

@@ -1,5 +1,5 @@
 entry,status,name,type,params
-Version,+,20.0,,
+Version,+,20.1,,
 Header,+,applications/services/bt/bt_service/bt.h,,
 Header,+,applications/services/cli/cli.h,,
 Header,+,applications/services/cli/cli_vcp.h,,
@@ -621,6 +621,7 @@ Function,+,canvas_draw_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
 Function,+,canvas_draw_glyph,void,"Canvas*, uint8_t, uint8_t, uint16_t"
 Function,+,canvas_draw_icon,void,"Canvas*, uint8_t, uint8_t, const Icon*"
 Function,+,canvas_draw_icon_animation,void,"Canvas*, uint8_t, uint8_t, IconAnimation*"
+Function,+,canvas_draw_icon_ex,void,"Canvas*, uint8_t, uint8_t, const Icon*, IconRotation"
 Function,+,canvas_draw_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
 Function,+,canvas_draw_rbox,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t"
 Function,+,canvas_draw_rframe,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t"

+ 13 - 18
firmware/targets/f7/src/dfu.c

@@ -2,29 +2,24 @@
 #include <furi_hal.h>
 #include <flipper.h>
 #include <alt_boot.h>
-#include <u8g2_glue.h>
 #include <assets_icons.h>
 #include <toolbox/compress.h>
+#include <gui/canvas.h>
+#include <gui/canvas_i.h>
 
 void flipper_boot_dfu_show_splash() {
     // Initialize
-    CompressIcon* compress_icon = compress_icon_alloc();
-
-    u8g2_t* fb = malloc(sizeof(u8g2_t));
-    memset(fb, 0, sizeof(u8g2_t));
-    u8g2_Setup_st756x_flipper(fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32);
-    u8g2_InitDisplay(fb);
-    u8g2_SetDrawColor(fb, 0x01);
-    uint8_t* splash_data = NULL;
-    compress_icon_decode(compress_icon, icon_get_data(&I_DFU_128x50), &splash_data);
-    u8g2_DrawXBM(fb, 0, 64 - 50, 128, 50, splash_data);
-    u8g2_SetFont(fb, u8g2_font_helvB08_tr);
-    u8g2_DrawStr(fb, 2, 8, "Update & Recovery Mode");
-    u8g2_DrawStr(fb, 2, 21, "DFU Started");
-    u8g2_SetPowerSave(fb, 0);
-    u8g2_SendBuffer(fb);
-
-    compress_icon_free(compress_icon);
+    Canvas* canvas = canvas_init();
+
+    canvas_set_color(canvas, ColorBlack);
+    canvas_set_font(canvas, FontPrimary);
+
+    canvas_draw_icon(canvas, 0, 64 - 50, &I_DFU_128x50);
+    canvas_draw_str(canvas, 2, 8, "Update & Recovery Mode");
+    canvas_draw_str(canvas, 2, 21, "DFU Started");
+    canvas_commit(canvas);
+
+    canvas_free(canvas);
 }
 
 void flipper_boot_dfu_exec() {

+ 22 - 23
firmware/targets/f7/src/recovery.c

@@ -2,44 +2,43 @@
 #include <furi_hal.h>
 #include <flipper.h>
 #include <alt_boot.h>
-#include <u8g2_glue.h>
 #include <assets_icons.h>
 #include <toolbox/compress.h>
+#include <gui/canvas.h>
+#include <gui/canvas_i.h>
 
 #define COUNTER_VALUE (136U)
 
-static void flipper_boot_recovery_draw_splash(u8g2_t* fb, size_t progress) {
+static void flipper_boot_recovery_draw_progress(Canvas* canvas, size_t progress) {
     if(progress < COUNTER_VALUE) {
         // Fill the progress bar while the progress is going down
-        u8g2_SetDrawColor(fb, 0x01);
-        u8g2_DrawRFrame(fb, 59, 41, 69, 8, 2);
+        canvas_draw_rframe(canvas, 59, 41, 69, 8, 2);
         size_t width = (COUNTER_VALUE - progress) * 68 / COUNTER_VALUE;
-        u8g2_DrawBox(fb, 60, 42, width, 6);
+        canvas_draw_box(canvas, 60, 42, width, 6);
     } else {
-        u8g2_SetDrawColor(fb, 0x00);
-        u8g2_DrawRBox(fb, 59, 41, 69, 8, 2);
+        canvas_draw_rframe(canvas, 59, 41, 69, 8, 2);
+        canvas_set_color(canvas, ColorWhite);
+        canvas_draw_box(canvas, 60, 42, 67, 6);
+        canvas_set_color(canvas, ColorBlack);
     }
 
-    u8g2_SendBuffer(fb);
+    canvas_commit(canvas);
 }
 
-void flipper_boot_recovery_exec() {
-    u8g2_t* fb = malloc(sizeof(u8g2_t));
-    u8g2_Setup_st756x_flipper(fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32);
-    u8g2_InitDisplay(fb);
+void flipper_boot_recovery_draw_splash(Canvas* canvas) {
+    canvas_set_color(canvas, ColorBlack);
+    canvas_set_font(canvas, FontPrimary);
+
+    canvas_draw_icon(canvas, 0, 0, &I_Erase_pin_128x64);
 
-    CompressIcon* compress_icon = compress_icon_alloc();
-    uint8_t* splash_data = NULL;
-    compress_icon_decode(compress_icon, icon_get_data(&I_Erase_pin_128x64), &splash_data);
+    canvas_commit(canvas);
+}
 
-    u8g2_ClearBuffer(fb);
-    u8g2_SetDrawColor(fb, 0x01);
+void flipper_boot_recovery_exec() {
+    Canvas* canvas = canvas_init();
 
-    // Draw the recovery picture
-    u8g2_DrawXBM(fb, 0, 0, 128, 64, splash_data);
-    u8g2_SendBuffer(fb);
-    u8g2_SetPowerSave(fb, 0);
-    compress_icon_free(compress_icon);
+    // Show recovery splashscreen
+    flipper_boot_recovery_draw_splash(canvas);
 
     size_t counter = COUNTER_VALUE;
     while(counter) {
@@ -53,7 +52,7 @@ void flipper_boot_recovery_exec() {
             counter = COUNTER_VALUE;
         }
 
-        flipper_boot_recovery_draw_splash(fb, counter);
+        flipper_boot_recovery_draw_progress(canvas, counter);
     }
 
     if(!counter) {