emoji icons in menu
authorKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 2 Nov 2019 19:39:41 +0000 (14:39 -0500)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 2 Nov 2019 19:39:41 +0000 (14:39 -0500)
src/jexer/backend/GlyphMaker.java
src/jexer/menu/TMenu.java
src/jexer/menu/TMenuItem.java

index 0da2918def6c8d9d0f57d7a77506828039994d69..84316b71992e1f63f1eb888ad7ebfa1c928b564e 100644 (file)
@@ -139,7 +139,7 @@ class GlyphMakerFont {
 
         if (filename.length() == 0) {
             // Fallback font
-            font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize);
+            font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize - 2);
             return;
         }
 
@@ -148,16 +148,16 @@ class GlyphMakerFont {
             ClassLoader loader = Thread.currentThread().getContextClassLoader();
             InputStream in = loader.getResourceAsStream(filename);
             fontRoot = Font.createFont(Font.TRUETYPE_FONT, in);
-            font = fontRoot.deriveFont(Font.PLAIN, fontSize);
+            font = fontRoot.deriveFont(Font.PLAIN, fontSize - 2);
         } catch (java.awt.FontFormatException e) {
             // Ideally we would report an error here, either via System.err
             // or TExceptionDialog.  However, I do not want GlyphMaker to
             // know about available backends, so we quietly fallback to
             // whatever is available as MONO.
-            font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize);
+            font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize - 2);
         } catch (java.io.IOException e) {
             // See comment above.
-            font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize);
+            font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize - 2);
         }
     }
 
index 6d746df0c42ebc3f6da6ede018a33ff439233235..a44de72ea321eb13bcfd79b0c9386371f5e94a7e 100644 (file)
@@ -152,6 +152,11 @@ public class TMenu extends TWindow {
      */
     private MnemonicString mnemonic;
 
+    /**
+     * If true, draw icons with menu items.  Note package private access.
+     */
+    boolean useIcons = false;
+
     // ------------------------------------------------------------------------
     // Constructors -----------------------------------------------------------
     // ------------------------------------------------------------------------
@@ -182,6 +187,11 @@ public class TMenu extends TWindow {
         setHeight(2);
 
         setActive(false);
+
+        if (System.getProperty("jexer.menuIcons", "false").equals("true")) {
+            useIcons = true;
+        }
+
     }
 
     // ------------------------------------------------------------------------
@@ -446,7 +456,7 @@ public class TMenu extends TWindow {
         final boolean enabled) {
 
         assert (id >= 1024);
-        return addItemInternal(id, label, null, enabled);
+        return addItemInternal(id, label, null, enabled, -1);
     }
 
     /**
@@ -492,7 +502,7 @@ public class TMenu extends TWindow {
     private TMenuItem addItemInternal(final int id, final String label,
         final TKeypress key) {
 
-        return addItemInternal(id, label, key, true);
+        return addItemInternal(id, label, key, true, -1);
     }
 
     /**
@@ -502,15 +512,16 @@ public class TMenu extends TWindow {
      * @param label menu item label
      * @param key global keyboard accelerator
      * @param enabled default state for enabled
+     * @param icon icon picture/emoji
      * @return the new menu item
      */
     private TMenuItem addItemInternal(final int id, final String label,
-        final TKeypress key, final boolean enabled) {
+        final TKeypress key, final boolean enabled, final int icon) {
 
         int newY = getChildren().size() + 1;
         assert (newY < getHeight());
 
-        TMenuItem menuItem = new TMenuItem(this, id, 1, newY, label);
+        TMenuItem menuItem = new TMenuItem(this, id, 1, newY, label, icon);
         menuItem.setKey(key);
         menuItem.setEnabled(enabled);
         setHeight(getHeight() + 1);
@@ -551,6 +562,7 @@ public class TMenu extends TWindow {
 
         String label;
         TKeypress key = null;
+        int icon = -1;
         boolean checkable = false;
         boolean checked = false;
 
@@ -558,6 +570,7 @@ public class TMenu extends TWindow {
 
         case MID_REPAINT:
             label = i18n.getString("menuRepaintDesktop");
+            icon = 0x1F3A8;
             break;
 
         case MID_VIEW_IMAGE:
@@ -570,41 +583,48 @@ public class TMenu extends TWindow {
 
         case MID_NEW:
             label = i18n.getString("menuNew");
+            icon = 0x1F5CE;
             break;
 
         case MID_EXIT:
             label = i18n.getString("menuExit");
             key = kbAltX;
+            icon = 0x1F5D9;
             break;
 
         case MID_SHELL:
             label = i18n.getString("menuShell");
+            icon = 0x1F5AE;
             break;
 
         case MID_OPEN_FILE:
             label = i18n.getString("menuOpen");
             key = kbF3;
+            icon = 0x1F5C1;
             break;
 
         case MID_CUT:
             label = i18n.getString("menuCut");
             key = kbCtrlX;
+            icon = 0x1F5F6;
             break;
         case MID_COPY:
             label = i18n.getString("menuCopy");
             key = kbCtrlC;
+            icon = 0x1F5D0;
             break;
         case MID_PASTE:
             label = i18n.getString("menuPaste");
             key = kbCtrlV;
+            icon = 0x1F4CB;
             break;
         case MID_CLEAR:
             label = i18n.getString("menuClear");
-            // key = kbDel;
             break;
 
         case MID_FIND:
             label = i18n.getString("menuFind");
+            icon = 0x1F50D;
             break;
         case MID_REPLACE:
             label = i18n.getString("menuReplace");
@@ -622,6 +642,7 @@ public class TMenu extends TWindow {
             break;
         case MID_CASCADE:
             label = i18n.getString("menuWindowCascade");
+            icon = 0x1F5D7;
             break;
         case MID_CLOSE_ALL:
             label = i18n.getString("menuWindowCloseAll");
@@ -629,18 +650,22 @@ public class TMenu extends TWindow {
         case MID_WINDOW_MOVE:
             label = i18n.getString("menuWindowMove");
             key = kbCtrlF5;
+            icon = 0x263C;
             break;
         case MID_WINDOW_ZOOM:
             label = i18n.getString("menuWindowZoom");
             key = kbF5;
+            icon = 0x2195;
             break;
         case MID_WINDOW_NEXT:
             label = i18n.getString("menuWindowNext");
             key = kbF6;
+            icon = 0x2192;
             break;
         case MID_WINDOW_PREVIOUS:
             label = i18n.getString("menuWindowPrevious");
             key = kbShiftF6;
+            icon = 0x2190;
             break;
         case MID_WINDOW_CLOSE:
             label = i18n.getString("menuWindowClose");
@@ -775,7 +800,7 @@ public class TMenu extends TWindow {
             throw new IllegalArgumentException("Invalid menu ID: " + id);
         }
 
-        TMenuItem item = addItemInternal(id, label, key, enabled);
+        TMenuItem item = addItemInternal(id, label, key, enabled, icon);
         item.setCheckable(checkable);
         return item;
     }
index d9dfc2ac5482b64123713f45e8b58f7f9abf3e3d..b478059c077d17916dffff4b6b864f22874cbaf6 100644 (file)
@@ -80,6 +80,11 @@ public class TMenuItem extends TWidget {
      */
     private MnemonicString mnemonic;
 
+    /**
+     * An optional 2-cell-wide picture/icon for this item.
+     */
+    private int icon = -1;
+
     // ------------------------------------------------------------------------
     // Constructors -----------------------------------------------------------
     // ------------------------------------------------------------------------
@@ -96,6 +101,22 @@ public class TMenuItem extends TWidget {
     TMenuItem(final TMenu parent, final int id, final int x, final int y,
         final String label) {
 
+        this(parent, id, x, y, label, -1);
+    }
+
+    /**
+     * Package private constructor.
+     *
+     * @param parent parent widget
+     * @param id menu id
+     * @param x column relative to parent
+     * @param y row relative to parent
+     * @param label menu item title
+     * @param icon icon picture/emoji
+     */
+    TMenuItem(final TMenu parent, final int id, final int x, final int y,
+        final String label, final int icon) {
+
         // Set parent and window
         super(parent);
 
@@ -105,8 +126,13 @@ public class TMenuItem extends TWidget {
         setY(y);
         setHeight(1);
         this.label = mnemonic.getRawLabel();
-        setWidth(StringUtils.width(label) + 4);
+        if (parent.useIcons) {
+            setWidth(StringUtils.width(label) + 6);
+        } else {
+            setWidth(StringUtils.width(label) + 4);
+        }
         this.id = id;
+        this.icon = icon;
 
         // Default state for some known menu items
         switch (id) {
@@ -220,26 +246,31 @@ public class TMenuItem extends TWidget {
             }
         }
 
+        boolean useIcons = ((TMenu) getParent()).useIcons;
+
         char cVSide = GraphicsChars.WINDOW_SIDE;
         vLineXY(0, 0, 1, cVSide, background);
         vLineXY(getWidth() - 1, 0, 1, cVSide, background);
 
         hLineXY(1, 0, getWidth() - 2, ' ', menuColor);
-        putStringXY(2, 0, mnemonic.getRawLabel(), menuColor);
+        putStringXY(2 + (useIcons ? 2 : 0), 0, mnemonic.getRawLabel(),
+            menuColor);
         if (key != null) {
             String keyLabel = key.toString();
             putStringXY((getWidth() - StringUtils.width(keyLabel) - 2), 0,
                 keyLabel, menuColor);
         }
         if (mnemonic.getScreenShortcutIdx() >= 0) {
-            putCharXY(2 + mnemonic.getScreenShortcutIdx(), 0,
-                mnemonic.getShortcut(), menuMnemonicColor);
+            putCharXY(2 + (useIcons ? 2 : 0) + mnemonic.getScreenShortcutIdx(),
+                0, mnemonic.getShortcut(), menuMnemonicColor);
         }
         if (checked) {
             assert (checkable);
             putCharXY(1, 0, GraphicsChars.CHECK, menuColor);
         }
-
+        if ((useIcons == true) && (icon != -1)) {
+            putCharXY(2, 0, icon, menuColor);
+        }
     }
 
     // ------------------------------------------------------------------------
@@ -318,12 +349,34 @@ public class TMenuItem extends TWidget {
         if (key != null) {
             int newWidth = (StringUtils.width(label) + 4 +
                 StringUtils.width(key.toString()) + 2);
+            if (((TMenu) getParent()).useIcons) {
+                newWidth += 2;
+            }
             if (newWidth > getWidth()) {
                 setWidth(newWidth);
             }
         }
     }
 
+    /**
+     * Get a picture/emoji icon for this menu item.
+     *
+     * @return the codepoint, or -1 if no icon is specified for this menu
+     * item
+     */
+    public final int getIcon() {
+        return icon;
+    }
+
+    /**
+     * Set a picture/emoji icon for this menu item.
+     *
+     * @param icon a codepoint, or -1 to unset the icon
+     */
+    public final void setIcon(final int icon) {
+        this.icon = icon;
+    }
+
     /**
      * Dispatch event(s) due to selection or click.
      */