From bc3b191de9eaa830c61a608b6765a61928cbaa60 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 13:18:45 -0400 Subject: [PATCH] working on font options and prefs --- app/src/processing/app/EditorConsole.java | 1 + app/src/processing/app/Preferences.java | 103 +++++++++++++++---- app/src/processing/app/Toolkit.java | 46 +++++++++ app/src/processing/app/tools/CreateFont.java | 4 +- build/build.xml | 7 ++ todo.txt | 2 + 6 files changed, 142 insertions(+), 21 deletions(-) diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java index dd822c7d0..18b582cc4 100644 --- a/app/src/processing/app/EditorConsole.java +++ b/app/src/processing/app/EditorConsole.java @@ -176,6 +176,7 @@ public class EditorConsole extends JScrollPane { consoleDoc.setParagraphAttributes(0, 0, standard, true); Font font = Preferences.getFont("console.font"); + //Font font = Toolkit.getMonoFont(size, style); // build styles for different types of console output Color bgColor = mode.getColor("console.color"); diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index ba391e47e..0699ffd3b 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -26,6 +26,7 @@ import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; +import java.util.List; import javax.swing.*; @@ -116,15 +117,18 @@ public class Preferences { JTextField fontSizeField; JCheckBox inputMethodBox; JCheckBox autoAssociateBox; + //JRadioButton bitsThirtyTwoButton; //JRadioButton bitsSixtyFourButton; + JComboBox displaySelectionBox; - int displayCount; + + //List monoFontList; + Font[] monoFontList; + JComboBox fontSelectionBox; - // the calling editor, so updates can be applied - -// Editor editor; + /** Base object so that updates can be applied to the list of editors. */ Base base; @@ -294,6 +298,39 @@ public class Preferences { top += vmax + GUI_BETWEEN; + // Editor and console font [ Source Code Pro ] + + // Nevermind on this for now.. Java doesn't seem to have a method for + // enumerating only the fixed-width (monospaced) fonts. To do this + // properly, we'd need to list the fonts, and compare the metrics of + // i and M for each. When they're identical (and not degenerate), + // we'd call that font fixed width. That's all a very expensive set of + // operations, so it should also probably be cached between runs and + // updated in the background. + + Container fontBox = Box.createHorizontalBox(); + JLabel fontLabel = new JLabel("Editor and Console font "); + final String fontTip = "" + + "Select the font used in the Editor and the Console.
" + + "Only monospaced (fixed-width) fonts may be used,
" + + "though the list may be imperfect."; + fontLabel.setToolTipText(fontTip); + fontBox.add(fontLabel); + // needs to happen here for getPreferredSize() + fontSelectionBox = new JComboBox(new Object[] { Toolkit.getMonoFontName() }); + fontSelectionBox.setToolTipText(fontTip); +// fontSelectionBox.addItem(Toolkit.getMonoFont(size, style)); + //updateDisplayList(); + fontSelectionBox.setEnabled(false); // don't enable until fonts are loaded + fontBox.add(fontSelectionBox); +// fontBox.add(Box.createHorizontalGlue()); + pain.add(fontBox); + d = fontBox.getPreferredSize(); + fontBox.setBounds(left, top, d.width + 150, d.height); +// fontBox.setBounds(left, top, dialog.getWidth() - left*2, d.height); + top += d.height + GUI_BETWEEN; + + // Editor font size [ ] Container box = Box.createHorizontalBox(); @@ -310,23 +347,7 @@ public class Preferences { fontSizeField.setText(String.valueOf(editorFont.getSize())); top += d.height + GUI_BETWEEN; - - // Nevermind on this for now.. Java doesn't seem to have a method for - // enumerating only the fixed-width (monospaced) fonts. To do this - // properly, we'd need to list the fonts, and compare the metrics of - // i and M for each. When they're identical (and not degenerate), - // we'd call that font fixed width. That's all a very expensive set of - // operations, so it should also probably be cached between runs and - // updated in the background. -// // Editor font -// -// GraphicsEnvironment ge = -// GraphicsEnvironment.getLocalGraphicsEnvironment(); -// Font fonts[] = ge.getAllFonts(); -// ArrayList monoFonts = new ArrayList(); - - // [ ] Use smooth text in editor window editorAntialiasBox = @@ -754,6 +775,15 @@ public class Preferences { // System.out.println("setting num to " + displayNum); displaySelectionBox.setSelectedIndex(displayNum); } + + new Thread(new Runnable() { + public void run() { + initFontList(); +// while (monoFontList == null) { +// System.out.println("Waiting for font list to finish loading..."); +// } + } + }).start(); memoryOverrideBox. setSelected(getBoolean("run.options.memory")); //$NON-NLS-1$ @@ -785,6 +815,39 @@ public class Preferences { } + /** + * I have some ideas on how we could make Swing even more obtuse for the + * most basic usage scenarios. Is there someone on the team I can contact? + * Oracle, are you listening? + */ + class FontNamer extends JLabel implements ListCellRenderer { + public Component getListCellRendererComponent(JList list, + Font value, int index, + boolean isSelected, + boolean cellHasFocus) { + setText(value.getName()); + return this; + } + } + + + void initFontList() { + if (monoFontList == null) { + Font[] list = Toolkit.getMonoFontList().toArray(new Font[0]); + fontSelectionBox.setModel(new DefaultComboBoxModel(list)); + fontSelectionBox.setRenderer(new FontNamer()); + // Preferred size just makes it extend to the container + //fontSelectionBox.setSize(fontSelectionBox.getPreferredSize()); + // Minimum size is better, but cuts things off (on OS X), so we add 20 + //Dimension minSize = fontSelectionBox.getMinimumSize(); + //Dimension minSize = fontSelectionBox.getPreferredSize(); + //fontSelectionBox.setSize(minSize.width + 20, minSize.height); + fontSelectionBox.setEnabled(true); + monoFontList = list; // signal that we're finished + } + } + + void updateDisplayList() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); displayCount = ge.getScreenDevices().length; diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index a22ca11b9..3d9fd488e 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -36,12 +36,14 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.List; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; @@ -320,12 +322,56 @@ public class Toolkit { // } + static public List getMonoFontList() { + GraphicsEnvironment ge = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + Font[] fonts = ge.getAllFonts(); + ArrayList outgoing = new ArrayList(); + // Using AffineTransform.getScaleInstance(100, 100) doesn't change sizes + FontRenderContext frc = + new FontRenderContext(new AffineTransform(), + Preferences.getBoolean("editor.antialias"), + true); // use fractional metrics + for (Font font : fonts) { + if (font.canDisplay('i') && font.canDisplay('M') && + font.canDisplay(' ') && font.canDisplay('.')) { + + // The old method just returns 1 or 0, and using deriveFont(size) + // is overkill. It also causes deprecation warnings +// @SuppressWarnings("deprecation") +// FontMetrics fm = awtToolkit.getFontMetrics(font); + //FontMetrics fm = awtToolkit.getFontMetrics(font.deriveFont(24)); +// System.out.println(fm.charWidth('i') + " " + fm.charWidth('M')); +// if (fm.charWidth('i') == fm.charWidth('M') && +// fm.charWidth('M') == fm.charWidth(' ') && +// fm.charWidth(' ') == fm.charWidth('.')) { + double w = font.getStringBounds(" ", frc).getWidth(); + if (w == font.getStringBounds("i", frc).getWidth() && + w == font.getStringBounds("M", frc).getWidth() && + w == font.getStringBounds(".", frc).getWidth()) { + outgoing.add(font); +// System.out.println(" good " + w); + } + } + } + return outgoing; + } + + static Font monoFont; static Font monoBoldFont; static Font sansFont; static Font sansBoldFont; + static public String getMonoFontName() { + if (monoFont == null) { + getMonoFont(12, Font.PLAIN); // load a dummy version + } + return monoFont.getName(); + } + + static public Font getMonoFont(int size, int style) { if (monoFont == null) { try { diff --git a/app/src/processing/app/tools/CreateFont.java b/app/src/processing/app/tools/CreateFont.java index 217af0bfa..17d6cbc73 100644 --- a/app/src/processing/app/tools/CreateFont.java +++ b/app/src/processing/app/tools/CreateFont.java @@ -112,9 +112,11 @@ public class CreateFont extends JFrame implements Tool { // also ignore dialog, dialoginput, monospaced, serif, sansserif // getFontList is deprecated in 1.4, so this has to be used + //long t = System.currentTimeMillis(); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - Font fonts[] = ge.getAllFonts(); + Font[] fonts = ge.getAllFonts(); + //System.out.println("font startup took " + (System.currentTimeMillis() - t) + " ms"); if (false) { ArrayList fontList = new ArrayList(); diff --git a/build/build.xml b/build/build.xml index 025e2772a..c54ad2d68 100755 --- a/build/build.xml +++ b/build/build.xml @@ -592,6 +592,13 @@ + + diff --git a/todo.txt b/todo.txt index 91a9f51be..6c810e637 100644 --- a/todo.txt +++ b/todo.txt @@ -71,6 +71,8 @@ _ dialog box icon is fuzzy on OS X retina machines _ https://github.com/processing/processing/issues/2117 _ solution might be our own dialog boxes (see 'dialogs' section) +_ console font in EditorConsole +_ Font font = Preferences.getFont("console.font"); _ fix console font on Windows and Linux with 7u40 _ the message area text also looks ugly.. can we fix? _ add pref to select PDE font (so that CJKV languages work better)