cjk support wip
authorKevin Lamonte <kevin.lamonte@gmail.com>
Thu, 8 Aug 2019 23:01:52 +0000 (18:01 -0500)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Thu, 8 Aug 2019 23:01:52 +0000 (18:01 -0500)
12 files changed:
src/jexer/TCheckBox.java
src/jexer/TLabel.java
src/jexer/TList.java
src/jexer/TRadioButton.java
src/jexer/TRadioGroup.java
src/jexer/TStatusBar.java
src/jexer/backend/ECMA48Terminal.java
src/jexer/backend/SwingTerminal.java
src/jexer/bits/MnemonicString.java
src/jexer/menu/TMenu.java
src/jexer/menu/TMenuItem.java
src/jexer/ttree/TTreeItem.java

index 9cdb303989a1bc53f547277055f8745b6e7f37e1..1e86470a4f36a1b850f9f9fe5df0f4341eb87498 100644 (file)
@@ -34,6 +34,7 @@ import static jexer.TKeypress.kbSpace;
 import jexer.bits.CellAttributes;
 import jexer.bits.GraphicsChars;
 import jexer.bits.MnemonicString;
+import jexer.bits.StringUtils;
 import jexer.event.TKeypressEvent;
 import jexer.event.TMouseEvent;
 
@@ -78,7 +79,7 @@ public class TCheckBox extends TWidget {
         final String label, final boolean checked) {
 
         // Set parent and window
-        super(parent, x, y, label.length() + 4, 1);
+        super(parent, x, y, StringUtils.width(label) + 4, 1);
 
         mnemonic = new MnemonicString(label);
         this.checked = checked;
index c34aee16f32aa699009835b119e95442b8915c7c..1d65976bba16f3947a3c47498cf552dcdda4f849 100644 (file)
@@ -30,6 +30,7 @@ package jexer;
 
 import jexer.bits.CellAttributes;
 import jexer.bits.MnemonicString;
+import jexer.bits.StringUtils;
 
 /**
  * TLabel implements a simple label, with an optional mnemonic hotkey action
@@ -157,7 +158,7 @@ public class TLabel extends TWidget {
         final TAction action) {
 
         // Set parent and window
-        super(parent, false, x, y, text.length(), 1);
+        super(parent, false, x, y, StringUtils.width(text), 1);
 
         mnemonic = new MnemonicString(text);
         this.colorKey = colorKey;
index f9e721621eda3a76c69f47d33c0132ca37f54722..a962f7cfe9eeee9b3ed579657964765add8bc772 100644 (file)
@@ -32,6 +32,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import jexer.bits.CellAttributes;
+import jexer.bits.StringUtils;
 import jexer.event.TKeypressEvent;
 import jexer.event.TMouseEvent;
 import static jexer.TKeypress.*;
@@ -338,8 +339,9 @@ public class TList extends TScrollableWidget {
 
         for (int i = 0; i < strings.size(); i++) {
             String line = strings.get(i);
-            if (line.length() > maxLineWidth) {
-                maxLineWidth = line.length();
+            int lineLength = StringUtils.width(line);
+            if (lineLength > maxLineWidth) {
+                maxLineWidth = lineLength;
             }
         }
 
index e3d98a985329a52dfbd18769212045e8561b68d8..2d602fa3abc1218b8612061c97743176b12ef0c6 100644 (file)
@@ -31,6 +31,7 @@ package jexer;
 import jexer.bits.CellAttributes;
 import jexer.bits.GraphicsChars;
 import jexer.bits.MnemonicString;
+import jexer.bits.StringUtils;
 import jexer.event.TKeypressEvent;
 import jexer.event.TMouseEvent;
 import static jexer.TKeypress.*;
@@ -81,7 +82,7 @@ public class TRadioButton extends TWidget {
         final String label, final int id) {
 
         // Set parent and window
-        super(parent, x, y, label.length() + 4, 1);
+        super(parent, x, y, StringUtils.width(label) + 4, 1);
 
         mnemonic = new MnemonicString(label);
         this.id = id;
@@ -179,8 +180,8 @@ public class TRadioButton extends TWidget {
         }
         putCharXY(2, 0, ')', radioButtonColor);
         putStringXY(4, 0, mnemonic.getRawLabel(), radioButtonColor);
-        if (mnemonic.getShortcutIdx() >= 0) {
-            putCharXY(4 + mnemonic.getShortcutIdx(), 0,
+        if (mnemonic.getScreenShortcutIdx() >= 0) {
+            putCharXY(4 + mnemonic.getScreenShortcutIdx(), 0,
                 mnemonic.getShortcut(), mnemonicColor);
         }
     }
index 0f84e71904fc7fef1b00fbacbb21d5fc3843e98c..7460de413b653a2d3c2898a6d8a73a8a2ad172fd 100644 (file)
@@ -29,6 +29,7 @@
 package jexer;
 
 import jexer.bits.CellAttributes;
+import jexer.bits.StringUtils;
 
 /**
  * TRadioGroup is a collection of TRadioButtons with a box and label.
@@ -71,7 +72,7 @@ public class TRadioGroup extends TWidget {
         final String label) {
 
         // Set parent and window
-        super(parent, x, y, label.length() + 4, 2);
+        super(parent, x, y, StringUtils.width(label) + 4, 2);
 
         this.label = label;
     }
@@ -96,7 +97,7 @@ public class TRadioGroup extends TWidget {
         drawBox(0, 0, getWidth(), getHeight(), radioGroupColor, radioGroupColor,
             3, false);
 
-        hLineXY(1, 0, label.length() + 2, ' ', radioGroupColor);
+        hLineXY(1, 0, StringUtils.width(label) + 2, ' ', radioGroupColor);
         putStringXY(2, 0, label, radioGroupColor);
     }
 
@@ -161,8 +162,8 @@ public class TRadioGroup extends TWidget {
     public TRadioButton addRadioButton(final String label) {
         int buttonX = 1;
         int buttonY = getChildren().size() + 1;
-        if (label.length() + 4 > getWidth()) {
-            setWidth(label.length() + 7);
+        if (StringUtils.width(label) + 4 > getWidth()) {
+            setWidth(StringUtils.width(label) + 7);
         }
         setHeight(getChildren().size() + 3);
         TRadioButton button = new TRadioButton(this, buttonX, buttonY, label,
index 98565d0f8c8c7d50c29ea86218156dbaa991049b..fbd79da850c320f0fa3a7a54696d7da4ed31b857 100644 (file)
@@ -33,6 +33,7 @@ import java.util.List;
 
 import jexer.bits.CellAttributes;
 import jexer.bits.GraphicsChars;
+import jexer.bits.StringUtils;
 import jexer.event.TCommandEvent;
 import jexer.event.TKeypressEvent;
 import jexer.event.TMouseEvent;
@@ -97,7 +98,8 @@ public class TStatusBar extends TWidget {
          * @return the number of columns this takes when drawn
          */
         public int width() {
-            return this.label.length() + this.key.toString().length() + 3;
+            return StringUtils.width(this.label) +
+                StringUtils.width(this.key.toString()) + 3;
         }
 
         /**
@@ -132,7 +134,7 @@ public class TStatusBar extends TWidget {
 
         // TStatusBar is a parentless widget, because TApplication handles
         // its drawing and event routing directly.
-        super(null, false, 0, 0, text.length(), 1);
+        super(null, false, 0, 0, StringUtils.width(text), 1);
 
         this.text = text;
         setWindow(window);
@@ -269,17 +271,17 @@ public class TStatusBar extends TWidget {
             if (key.selected) {
                 putCharXY(col++, row, ' ', selectedColor);
                 putStringXY(col, row, keyStr, selectedColor);
-                col += keyStr.length();
+                col += StringUtils.width(keyStr);
                 putCharXY(col++, row, ' ', selectedColor);
                 putStringXY(col, row, key.label, selectedColor);
-                col += key.label.length();
+                col += StringUtils.width(key.label);
                 putCharXY(col++, row, ' ', selectedColor);
             } else {
                 putCharXY(col++, row, ' ', barColor);
                 putStringXY(col, row, keyStr, keyColor);
-                col += keyStr.length() + 1;
+                col += StringUtils.width(keyStr) + 1;
                 putStringXY(col, row, key.label, barColor);
-                col += key.label.length();
+                col += StringUtils.width(key.label);
                 putCharXY(col++, row, ' ', barColor);
             }
         }
index 252e80c4123a85d94af54a15e734ac8ade3c12ea..ca1d499594734c75275a53f90a7f5fb8aa9f9a56 100644 (file)
@@ -1002,7 +1002,8 @@ public class ECMA48Terminal extends LogicalScreen
     // ------------------------------------------------------------------------
 
     /**
-     * Constructor sets up state for getEvent().
+     * Constructor sets up state for getEvent().  If either windowWidth or
+     * windowHeight are less than 1, the terminal is not resized.
      *
      * @param listener the object this backend needs to wake up when new
      * input comes in
@@ -1026,10 +1027,12 @@ public class ECMA48Terminal extends LogicalScreen
 
         // Send dtterm/xterm sequences, which will probably not work because
         // allowWindowOps is defaulted to false.
-        String resizeString = String.format("\033[8;%d;%dt", windowHeight,
-            windowWidth);
-        this.output.write(resizeString);
-        this.output.flush();
+        if ((windowWidth > 0) && (windowHeight > 0)) {
+            String resizeString = String.format("\033[8;%d;%dt", windowHeight,
+                windowWidth);
+            this.output.write(resizeString);
+            this.output.flush();
+        }
     }
 
     /**
index 58b8f799cf7f1e1153f2ef60f2af486ba96d03da..bd1ba87ce2d3c442ce5254f358254586cae0227e 100644 (file)
@@ -1265,18 +1265,31 @@ public class SwingTerminal extends LogicalScreen
             int xPixel = cursorX * textWidth + left;
             int yPixel = cursorY * textHeight + top;
             Cell lCell = logical[cursorX][cursorY];
+            int cursorWidth = textWidth;
+            switch (lCell.getWidth()) {
+            case SINGLE:
+                // NOP
+                break;
+            case LEFT:
+                cursorWidth *= 2;
+                break;
+            case RIGHT:
+                cursorWidth *= 2;
+                xPixel -= textWidth;
+                break;
+            }
             gr.setColor(attrToForegroundColor(lCell));
             switch (cursorStyle) {
             default:
                 // Fall through...
             case UNDERLINE:
-                gr.fillRect(xPixel, yPixel + textHeight - 2, textWidth, 2);
+                gr.fillRect(xPixel, yPixel + textHeight - 2, cursorWidth, 2);
                 break;
             case BLOCK:
-                gr.fillRect(xPixel, yPixel, textWidth, textHeight);
+                gr.fillRect(xPixel, yPixel, cursorWidth, textHeight);
                 break;
             case OUTLINE:
-                gr.drawRect(xPixel, yPixel, textWidth - 1, textHeight - 1);
+                gr.drawRect(xPixel, yPixel, cursorWidth - 1, textHeight - 1);
                 break;
             }
         }
index 5977ed56c71064262d19f0fed0afc15686ffd59e..2d5dbc8cd2533ebb8697b247a744ea2b82aa3202 100644 (file)
@@ -50,6 +50,12 @@ public class MnemonicString {
      */
     private int shortcutIdx = -1;
 
+    /**
+     * Screen location of the highlighted character (number of text cells
+     * required to display from the beginning to shortcutIdx).
+     */
+    private int screenShortcutIdx = -1;
+
     /**
      * The raw (uncolored) string.
      */
@@ -72,12 +78,14 @@ public class MnemonicString {
         boolean foundAmp = false;
         boolean foundShortcut = false;
         int scanShortcutIdx = 0;
+        int scanScreenShortcutIdx = 0;
         for (int i = 0; i < label.length(); i++) {
             char c = label.charAt(i);
             if (c == '&') {
                 if (foundAmp) {
                     newLabel += '&';
                     scanShortcutIdx++;
+                    scanScreenShortcutIdx++;
                 } else {
                     foundAmp = true;
                 }
@@ -89,9 +97,11 @@ public class MnemonicString {
                         foundAmp = false;
                         foundShortcut = true;
                         shortcutIdx = scanShortcutIdx;
+                        screenShortcutIdx = scanScreenShortcutIdx;
                     }
                 } else {
                     scanShortcutIdx++;
+                    scanScreenShortcutIdx += StringUtils.width(c);
                 }
             }
         }
@@ -120,6 +130,16 @@ public class MnemonicString {
         return shortcutIdx;
     }
 
+    /**
+     * Get the screen location of the highlighted character.
+     *
+     * @return the number of text cells required to display from the
+     * beginning of the label to shortcutIdx
+     */
+    public int getScreenShortcutIdx() {
+        return screenShortcutIdx;
+    }
+
     /**
      * Get the raw (uncolored) string.
      *
index 1d6a6ad34179c7325d7ed4d457e828059de4b09b..58228f9900d1c311bf947be32410da6f0ea50427 100644 (file)
@@ -37,6 +37,7 @@ import jexer.TWindow;
 import jexer.bits.CellAttributes;
 import jexer.bits.GraphicsChars;
 import jexer.bits.MnemonicString;
+import jexer.bits.StringUtils;
 import jexer.event.TKeypressEvent;
 import jexer.event.TMouseEvent;
 import static jexer.TKeypress.*;
@@ -177,7 +178,7 @@ public class TMenu extends TWindow {
         assert (mnemonic.getShortcutIdx() >= 0);
 
         // Recompute width and height to reflect an empty menu
-        setWidth(getTitle().length() + 4);
+        setWidth(StringUtils.width(getTitle()) + 4);
         setHeight(2);
 
         setActive(false);
index bd149abb08b4ae8e6c65943b249832e954c4e78d..eafa9e5bcc9fbdadd11c763c91dbd32c7bdd0df0 100644 (file)
@@ -33,6 +33,7 @@ import jexer.TWidget;
 import jexer.bits.CellAttributes;
 import jexer.bits.GraphicsChars;
 import jexer.bits.MnemonicString;
+import jexer.bits.StringUtils;
 import jexer.event.TKeypressEvent;
 import jexer.event.TMouseEvent;
 import jexer.event.TMenuEvent;
@@ -104,7 +105,7 @@ public class TMenuItem extends TWidget {
         setY(y);
         setHeight(1);
         this.label = mnemonic.getRawLabel();
-        setWidth(label.length() + 4);
+        setWidth(StringUtils.width(label) + 4);
         this.id = id;
 
         // Default state for some known menu items
@@ -227,8 +228,8 @@ public class TMenuItem extends TWidget {
         putStringXY(2, 0, mnemonic.getRawLabel(), menuColor);
         if (key != null) {
             String keyLabel = key.toString();
-            putStringXY((getWidth() - keyLabel.length() - 2), 0, keyLabel,
-                menuColor);
+            putStringXY((getWidth() - StringUtils.width(keyLabel) - 2), 0,
+                keyLabel, menuColor);
         }
         if (mnemonic.getShortcutIdx() >= 0) {
             putCharXY(2 + mnemonic.getShortcutIdx(), 0, mnemonic.getShortcut(),
@@ -315,7 +316,8 @@ public class TMenuItem extends TWidget {
         this.key = key;
 
         if (key != null) {
-            int newWidth = (label.length() + 4 + key.toString().length() + 2);
+            int newWidth = (StringUtils.width(label) + 4 +
+                StringUtils.width(key.toString()) + 2);
             if (newWidth > getWidth()) {
                 setWidth(newWidth);
             }
index 759bfb7a857ff3878c7986c63a26adafb1468f3f..44c408b2bd3f6095bd8a27d758d76b0b233e3964 100644 (file)
@@ -34,6 +34,7 @@ import java.util.List;
 import jexer.TWidget;
 import jexer.bits.CellAttributes;
 import jexer.bits.GraphicsChars;
+import jexer.bits.StringUtils;
 import jexer.event.TKeypressEvent;
 import jexer.event.TMouseEvent;
 import static jexer.TKeypress.*;
@@ -266,9 +267,9 @@ public class TTreeItem extends TWidget {
         }
         putStringXY(offset, 0, line, color);
         if (selected) {
-            putStringXY(offset + line.length(), 0, text, selectedColor);
+            putStringXY(offset + StringUtils.width(line), 0, text, selectedColor);
         } else {
-            putStringXY(offset + line.length(), 0, text, textColor);
+            putStringXY(offset + StringUtils.width(line), 0, text, textColor);
         }
         if ((level > 0) && (expandable)) {
             if (expanded) {
@@ -402,10 +403,10 @@ public class TTreeItem extends TWidget {
      * @return the maximum number of columns for this item or its children
      */
     public int getMaximumColumn() {
-        int max = prefix.length() + 4 + text.length();
+        int max = prefix.length() + 4 + StringUtils.width(text);
         for (TWidget widget: getChildren()) {
             TTreeItem item = (TTreeItem) widget;
-            int n = item.prefix.length() + 4 + item.text.length();
+            int n = item.prefix.length() + 4 + StringUtils.width(item.text);
             if (n > max) {
                 max = n;
             }