Browse Source

Lulzbot ExtUI Western language support (#15208)

Fix #15134
Marcio Teixeira 5 years ago
parent
commit
47d19bab40

+ 6 - 0
Marlin/Configuration_adv.h

@@ -1205,6 +1205,12 @@
   //#define TOUCH_UI_PORTRAIT
   //#define TOUCH_UI_MIRRORED
 
+  // Enable UTF8 rendering capabilities.
+  //#define TOUCH_UI_USE_UTF8
+  #if ENABLED(TOUCH_UI_USE_UTF8)
+    #define TOUCH_UI_UTF8_WESTERN_CHARSET
+  #endif
+
   // Use a numeric passcode for "Screen lock" keypad.
   // (recommended for smaller displays)
   //#define TOUCH_UI_PASSCODE

+ 7 - 1
Marlin/src/lcd/extensible_ui/lib/lulzbot/config.h

@@ -76,6 +76,12 @@
 //#define TOUCH_UI_PORTRAIT
 //#define TOUCH_UI_MIRRORED
 
+// Enable UTF8 rendering capabilities.
+//#define TOUCH_UI_USE_UTF8
+#ifdef  TOUCH_UI_USE_UTF8
+  #define TOUCH_UI_UTF8_WESTERN_CHARSET
+#endif
+
 // Use a numeric passcode for "Parental lock".
 // This is a recommended for smaller displays.
 //#define TOUCH_UI_PASSCODE
@@ -90,7 +96,7 @@
 //#define DEVELOPER_SCREENS
 
 // Maximum feed rate for manual extrusion (mm/s)
-//#define MAX_MANUAL_FEEDRATE 240
+#define MAX_MANUAL_FEEDRATE {50*60, 50*60, 4*60, 60}
 
 // Sets the SPI speed in Hz
 

+ 1 - 0
Marlin/src/lcd/extensible_ui/lib/lulzbot/ftdi_eve_lib/basic/commands.h

@@ -159,6 +159,7 @@ class CLCD::FontMetrics {
     uint32_t  height;
     uint32_t  ptr;
 
+    FontMetrics() {}
     FontMetrics(uint8_t font) {load(font);}
 
     void load(uint8_t font);

+ 35 - 23
Marlin/src/lcd/extensible_ui/lib/lulzbot/ftdi_eve_lib/extended/command_processor.h

@@ -67,14 +67,14 @@ class CommandProcessor : public CLCD::CommandFifo {
     }
 
     FORCEDINLINE void linear_widget_box(int16_t &x, int16_t &y, int16_t &w, int16_t &h, bool tracker = false) {
-      const uint16_t th = widget_thickness()/2;
+      const uint16_t th = widget_thickness() / 2;
       if (w > h) {
         x += tracker ? th * 2.5 : th;
-        y += h/2  - th/2;
+        y += (h - th) / 2;
         w -= tracker ? th * 5.0 : th * 2;
         h  = th;
       } else {
-        x += w/2  - th/2;
+        x += (w - th) / 2;
         y += tracker ? th * 2.5 : th;
         w  = th;
         h -= tracker ? th * 5.0 : th * 2;
@@ -82,9 +82,9 @@ class CommandProcessor : public CLCD::CommandFifo {
     }
 
     FORCEDINLINE uint16_t circular_widget_box(int16_t &x, int16_t &y, int16_t &w, int16_t &h) {
-      const uint16_t r = min(w,h)/2;
-      x += w/2;
-      y += h/2;
+      const uint16_t r = min(w,h) / 2;
+      x += w / 2;
+      y += h / 2;
       w  = 1;
       h  = 1;
       return r;
@@ -200,22 +200,22 @@ class CommandProcessor : public CLCD::CommandFifo {
     inline CommandProcessor& rectangle(int16_t x, int16_t y, int16_t w, int16_t h) {
       using namespace FTDI;
       CLCD::CommandFifo::cmd(BEGIN(RECTS));
-      CLCD::CommandFifo::cmd(VERTEX2F(x*16,y*16));
-      CLCD::CommandFifo::cmd(VERTEX2F((x+w)*16,(y+h)*16));
+      CLCD::CommandFifo::cmd(VERTEX2F(x * 16, y * 16));
+      CLCD::CommandFifo::cmd(VERTEX2F((x + w) * 16, (y + h) * 16));
       return *this;
     }
 
     template<typename T>
     FORCEDINLINE CommandProcessor& toggle(int16_t x, int16_t y, int16_t w, int16_t h, T text, bool state, uint16_t options = FTDI::OPT_3D) {
       CLCD::FontMetrics fm(_font);
-      const int16_t widget_h = fm.height * 20.0/16;
+      const int16_t widget_h = fm.height * 20.0 / 16;
       //const int16_t outer_bar_r = widget_h / 2;
       //const int16_t knob_r      = outer_bar_r - 1.5;
       // The y coordinate of the toggle is the baseline of the text,
       // so we must introduce a fudge factor based on the line height to
       // actually center the control.
-      const int16_t fudge_y = fm.height*5/16;
-      CLCD::CommandFifo::toggle(x + h/2, y + h/2 - widget_h/2 + fudge_y, w - h, _font, options, state);
+      const int16_t fudge_y = fm.height * 5 / 16;
+      CLCD::CommandFifo::toggle(x + h / 2, y + (h - widget_h) / 2 + fudge_y, w - h, _font, options, state);
       CLCD::CommandFifo::str(text);
       return *this;
     }
@@ -286,23 +286,29 @@ class CommandProcessor : public CLCD::CommandFifo {
       return *this;
     }
 
+    void apply_text_alignment(int16_t &x, int16_t &y, int16_t w, int16_t h, uint16_t options) {
+      using namespace FTDI;
+      x += ((options & OPT_CENTERX) ? w / 2 : ((options & OPT_RIGHTX) ? w : 0));
+      y += ((options & OPT_CENTERY) ? h / 2 : h);
+    }
+
     CommandProcessor& number(int16_t x, int16_t y, int16_t w, int16_t h, int32_t n, uint16_t options = FTDI::OPT_CENTER) {
       using namespace FTDI;
-      CLCD::CommandFifo::number(
-        x + ((options & OPT_CENTERX) ? w/2 : ((options & OPT_RIGHTX) ? w : 0)),
-        y + ((options & OPT_CENTERY) ? h/2 : h),
-        _font, options, n);
+      apply_text_alignment(x, y, w, h, options);
+      CLCD::CommandFifo::number(x, y, _font, options, n);
       return *this;
     }
 
     template<typename T> FORCEDINLINE
     CommandProcessor& text(int16_t x, int16_t y, int16_t w, int16_t h, T text, uint16_t options = FTDI::OPT_CENTER) {
       using namespace FTDI;
-      CLCD::CommandFifo::text(
-        x + ((options & OPT_CENTERX) ? w/2 : ((options & OPT_RIGHTX) ? w : 0)),
-        y + ((options & OPT_CENTERY) ? h/2 : h),
-        _font, options);
-      CLCD::CommandFifo::str(text);
+      apply_text_alignment(x, y, w, h, options);
+      #ifdef TOUCH_UI_USE_UTF8
+        draw_utf8_text(*this, x, y, text, font_size_t::from_romfont(_font), options);
+      #else
+        CLCD::CommandFifo::text(x, y, _font, options);
+        CLCD::CommandFifo::str(text);
+      #endif
       return *this;
     }
 
@@ -313,8 +319,8 @@ class CommandProcessor : public CLCD::CommandFifo {
         cmd(BITMAP_TRANSFORM_A(uint32_t(float(256)/scale)));
         cmd(BITMAP_TRANSFORM_E(uint32_t(float(256)/scale)));
       }
-      cmd(BITMAP_SIZE(info.filter, info.wrapx, info.wrapy, info.width*scale, info.height*scale));
-      cmd(VERTEX2F((x + w/2 - info.width*scale/2)*16, (y + h/2 - info.height*scale/2)*16));
+      cmd(BITMAP_SIZE(info.filter, info.wrapx, info.wrapy, info.width * scale, info.height * scale));
+      cmd(VERTEX2F((x + w / 2 - info.width * scale / 2) * 16, (y + h / 2 - info.height * scale / 2) * 16));
       if (scale != 1) {
         cmd(BITMAP_TRANSFORM_A(256));
         cmd(BITMAP_TRANSFORM_E(256));
@@ -328,7 +334,13 @@ class CommandProcessor : public CLCD::CommandFifo {
       bool styleModified = false;
       if (_btn_style_callback) styleModified = _btn_style_callback(*this, _tag, _style, options, false);
       CLCD::CommandFifo::button(x, y, w, h, _font, options);
-      CLCD::CommandFifo::str(text);
+      #ifdef TOUCH_UI_USE_UTF8
+        apply_text_alignment(x, y, w, h, OPT_CENTER);
+        CLCD::CommandFifo::str(F(""));
+        draw_utf8_text(*this, x, y, text, font_size_t::from_romfont(_font), OPT_CENTER);
+      #else
+        CLCD::CommandFifo::str(text);
+      #endif
       if (_btn_style_callback && styleModified) _btn_style_callback(*this, _tag, _style, options, true);
       return *this;
     }

+ 6 - 1
Marlin/src/lcd/extensible_ui/lib/lulzbot/ftdi_eve_lib/extended/ftdi_extended.h

@@ -30,14 +30,19 @@
 #endif
 
 #ifdef FTDI_EXTENDED
+  #include "unicode/font_size_t.h"
+  #include "unicode/unicode.h"
+  #include "unicode/standard_char_set.h"
+  #include "unicode/western_char_set.h"
+  #include "unicode/font_bitmaps.h"
   #include "rgb_t.h"
   #include "bitmap_info.h"
   #include "tiny_timer.h"
   #include "grid_layout.h"
   #include "dl_cache.h"
-  #include "screen_types.h"
   #include "event_loop.h"
   #include "command_processor.h"
+  #include "screen_types.h"
   #include "sound_player.h"
   #include "sound_list.h"
   #include "polygon.h"

+ 13 - 5
Marlin/src/lcd/extensible_ui/lib/lulzbot/ftdi_eve_lib/extended/screen_types.h

@@ -156,8 +156,11 @@ class UncachedScreen {
   public:
     static void onRefresh() {
       using namespace FTDI;
-      CLCD::CommandFifo cmd;
+      CommandProcessor cmd;
       cmd.cmd(CMD_DLSTART);
+      #ifdef TOUCH_UI_USE_UTF8
+        load_utf8_bitmaps(cmd);
+      #endif
 
       current_screen.onRedraw(BOTH);
 
@@ -183,9 +186,12 @@ class CachedScreen {
     static void repaintBackground() {
       using namespace FTDI;
       DLCache dlcache(DL_SLOT);
-      CLCD::CommandFifo cmd;
+      CommandProcessor cmd;
 
       cmd.cmd(CMD_DLSTART);
+      #ifdef TOUCH_UI_USE_UTF8
+        load_utf8_bitmaps(cmd);
+      #endif
       current_screen.onRedraw(BACKGROUND);
 
       dlcache.store(DL_SIZE);
@@ -195,14 +201,16 @@ class CachedScreen {
     static void onRefresh() {
       using namespace FTDI;
       DLCache dlcache(DL_SLOT);
-      CLCD::CommandFifo cmd;
+      CommandProcessor cmd;
 
       cmd.cmd(CMD_DLSTART);
 
       if (dlcache.has_data()) {
         dlcache.append();
-      }
-      else {
+      } else {
+        #ifdef TOUCH_UI_USE_UTF8
+          load_utf8_bitmaps(cmd);
+        #endif
         current_screen.onRedraw(BACKGROUND);
         dlcache.store(DL_SIZE);
       }

+ 28 - 31
Marlin/src/lcd/extensible_ui/lib/lulzbot/ftdi_eve_lib/extended/text_box.cpp

@@ -29,41 +29,33 @@ namespace FTDI {
    * be broken so that the display width is less than w. The line will also
    * be broken after a '\n'. Returns the display width of the line.
    */
-  static uint16_t find_line_break(const CLCD::FontMetrics &fm, uint16_t w, const char *str, const char *&end) {
+  static uint16_t find_line_break(const FontMetrics &fm, uint16_t w, const char *str, const char *&end) {
+    w -= fm.get_char_width(' ');
     const char *p = str;
-    end = str + strlen(str);
-    uint16_t width = fm.get_text_width(str);
+    end = str;
+    uint16_t lw = 0, result = 0;
     for(;;) {
-      // Find next tentative line break.
-      char delim = *(p);
-      while (delim && delim != ' ' && delim != '\n') {
-        delim = *(++p);
-      }
-      // Check to see whether to break the line.
-      const uint16_t margin = fm.get_text_width("  ");
-      const uint16_t lw = p > str ? fm.get_text_width(str, p - str) + margin : 0;
-      if (lw < w) {
-        width = lw;
-        switch (delim) {
-          case '\0':
-            end = p;
-            break;
-          case '\n':
-            end = ++p;
-            break;
-          case ' ':
-            end = ++p;
-            continue;
+      utf8_char_t c = get_utf8_char_and_inc(p);
+      if (c == ' ' || c == '\n' || c == '\0') {
+        if (lw < w || end == str) {
+          end   = (c == '\0') ? p-1 : p;
+          result = lw;
         }
+        if (c == '\0' || c == '\n') break;
       }
-      return width;
+      lw += fm.get_char_width(c);
+    }
+    if (end == str) {
+      end   = p-1;
+      result = lw;
     }
+    return result;
   }
 
   /**
    * This function returns a measurements of the word-wrapped text box.
    */
-  static void measure_text_box(const CLCD::FontMetrics &fm, const char *str, uint16_t &width, uint16_t &height) {
+  static void measure_text_box(const FontMetrics &fm, const char *str, uint16_t &width, uint16_t &height) {
     const char *line_start = (const char*)str;
     const char *line_end;
     const uint16_t wrap_width = width;
@@ -72,7 +64,7 @@ namespace FTDI {
       uint16_t line_width = find_line_break(fm, wrap_width, line_start, line_end);
       if (line_end == line_start) break;
       width  = max(width, line_width);
-      height += fm.height;
+      height += fm.get_height();
       line_start = line_end;
     }
   }
@@ -81,10 +73,11 @@ namespace FTDI {
    * This function draws text inside a bounding box, doing word wrapping and using the largest font that will fit.
    */
   void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options, uint8_t font) {
-    CLCD::FontMetrics fm(font);
-
     uint16_t box_width, box_height;
 
+    FontMetrics fm(font);
+
+    // Shrink the font until we find a font that fits
     for(;;) {
       box_width = w;
       measure_text_box(fm, str, box_width, box_height);
@@ -110,10 +103,14 @@ namespace FTDI {
         if (line[line_len - 1] == '\n' || line[line_len - 1] == ' ')
           line[line_len - 1] = 0;
 
-        cmd.CLCD::CommandFifo::text(x + dx, y + dy, font, options & ~OPT_CENTERY);
-        cmd.CLCD::CommandFifo::str(line);
+        #ifdef TOUCH_UI_USE_UTF8
+          draw_utf8_text(cmd, x + dx, y + dy, line, fm.fs, options & ~OPT_CENTERY);
+        #else
+          cmd.CLCD::CommandFifo::text(x + dx, y + dy, font, options & ~OPT_CENTERY);
+          cmd.CLCD::CommandFifo::str(line);
+        #endif
       }
-      y += fm.height;
+      y += fm.get_height();
 
       line_start = line_end;
     }

+ 40 - 0
Marlin/src/lcd/extensible_ui/lib/lulzbot/ftdi_eve_lib/extended/unicode/README.txt

@@ -0,0 +1,40 @@
+
+FTDI EVE Unicode Rendering
+--------------------------
+
+The FTDI EVE chips have several fonts in ROM, but these fonts only contain a
+subset of ASCII characters. Notably, this excludes diacritics and accents
+used in most Western languages.
+
+While the FTDI EVE has the capability for user-defined fonts, such fonts only
+support 127 character positions, making them as limiting as the built-in fonts.
+
+As a further complication, high resolution TFT displays require high resolution
+fonts. It is not feasible to put a complete international font into the limited
+flash memory of most microprocessors.
+
+To work around these limitations, this library uses a custom font renderer with
+the following characteristics:
+
+  1) Rather than providing bitmaps for different font sizes, it uses a single
+     bitmap for the largest font size (romfont 31) and emulates other sizes by
+     scaling the bitmaps using BITMAP_TRANSFORM.
+
+  2) Rather than loading an entire font, it combines symbols from romfont 31
+     with a limited number of symbols from a custom font. For accented letters,
+     the rendering code combine basic letter shapes from romfont 31 with
+     bitmaps containing only the accent themselves.
+
+  3) The custom bitmap is RLE compressed into PROGMEM. For accents, which have
+     a fairly small number of non-white pixels, the savings are significant.
+
+These characteristics enable an alphabet for Western languages to be
+synthesized from only a few dozen custom symbols and modest PROGMEM use (~10k)
+
+The text layout is done by the code in "unicode.cpp" with the help of one of
+more character renderers (e.g. "western_char_set.cpp"). Each character render
+is responsible for loading the necessary bitmap data into RAMG and drawing
+characters as requested.
+
+To add symbols for other languages, it will only be necessary to make a bitmap
+and implement a corresponding character renderer.

+ 55 - 0
Marlin/src/lcd/extensible_ui/lib/lulzbot/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp

@@ -0,0 +1,55 @@
+/*******************
+ * font_bitmap.cpp *
+ *******************/
+
+/****************************************************************************
+ *   Written By Marcio Teixeira 2019 - Aleph Objects, Inc.                  *
+ *                                                                          *
+ *   This program is free software: you can redistribute it and/or modify   *
+ *   it under the terms of the GNU General Public License as published by   *
+ *   the Free Software Foundation, either version 3 of the License, or      *
+ *   (at your option) any later version.                                    *
+ *                                                                          *
+ *   This program is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *   GNU General Public License for more details.                           *
+ *                                                                          *
+ *   To view a copy of the GNU General Public License, go to the following  *
+ *   location: <http://www.gnu.org/licenses/>.                              *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#ifdef FTDI_EXTENDED
+
+namespace FTDI {
+
+  void write_rle_data(uint16_t addr, const uint8_t *data, size_t n) {
+    for (; n > 2; n -= 2) {
+      uint8_t count = pgm_read_byte(data++);
+      uint8_t value = pgm_read_byte(data++);
+      while (count--) CLCD::mem_write_8(addr++, value);
+    }
+  }
+
+  void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle) {
+    cmd.cmd(BITMAP_HANDLE(handle));
+    cmd.cmd(BITMAP_SOURCE(fm.ptr));
+    cmd.bitmap_layout(fm.format, fm.stride, fm.height);
+    cmd.bitmap_size(BILINEAR, BORDER, BORDER, fm.width, fm.height);
+  }
+
+  void ext_vertex2ii(CommandProcessor &cmd, int x, int y, uint8_t handle, uint8_t cell) {
+    if (x < 0 || y < 0 || x > 511 || y > 511) {
+      cmd.cmd(BITMAP_HANDLE(handle));
+      cmd.cmd(CELL(cell));
+      cmd.cmd(VERTEX2F(x * 16, y * 16));
+    } else {
+      cmd.cmd(VERTEX2II(x, y, handle, cell));
+    }
+  }
+
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED

+ 30 - 0
Marlin/src/lcd/extensible_ui/lib/lulzbot/ftdi_eve_lib/extended/unicode/font_bitmaps.h

@@ -0,0 +1,30 @@
+/******************
+ * font_bitmaps.h *
+ ******************/
+
+/****************************************************************************
+ *   Written By Marcio Teixeira 2019 - Aleph Objects, Inc.                  *
+ *                                                                          *
+ *   This program is free software: you can redistribute it and/or modify   *
+ *   it under the terms of the GNU General Public License as published by   *
+ *   the Free Software Foundation, either version 3 of the License, or      *
+ *   (at your option) any later version.                                    *
+ *                                                                          *
+ *   This program is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *   GNU General Public License for more details.                           *
+ *                                                                          *
+ *   To view a copy of the GNU General Public License, go to the following  *
+ *   location: <http://www.gnu.org/licenses/>.                              *
+ ****************************************************************************/
+
+#pragma once
+
+class CommandProcessor;
+
+namespace FTDI {
+  void write_rle_data(uint16_t addr, const uint8_t *data, size_t n);
+  void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle);
+  void ext_vertex2ii(CommandProcessor &cmd, int x, int y, uint8_t handle, uint8_t cell);
+}

Some files were not shown because too many files changed in this diff