diff --git a/app/src/processing/app/EditorTab.java b/app/src/processing/app/EditorTab.java index c706e711352..04b21bf58ff 100644 --- a/app/src/processing/app/EditorTab.java +++ b/app/src/processing/app/EditorTab.java @@ -58,6 +58,7 @@ import java.nio.file.Path; import java.io.File; +import org.apache.commons.lang3.StringUtils; import org.fife.ui.autocomplete.AutoCompletion; import org.fife.ui.autocomplete.DefaultCompletionProvider; import org.fife.ui.rsyntaxtextarea.RSyntaxDocument; @@ -345,6 +346,20 @@ public void applyPreferences() { } // apply changes to the font size for the editor Font editorFont = scale(PreferencesData.getFont("editor.font")); + + // check whether a theme-defined editor font is available + Font themeFont = Theme.getFont("editor.font"); + if (themeFont != null) + { + // Apply theme font if the editor font has *not* been changed by the user, + // This allows themes to specify an editor font which will only be applied + // if the user hasn't already changed their editor font via preferences.txt + String defaultFontName = StringUtils.defaultIfEmpty(PreferencesData.getDefault("editor.font"), "").split(",")[0]; + if (defaultFontName.equals(editorFont.getName())) { + editorFont = new Font(themeFont.getName(), themeFont.getStyle(), editorFont.getSize()); + } + } + textarea.setFont(editorFont); scrollPane.getGutter().setLineNumberFont(editorFont); } diff --git a/app/src/processing/app/Theme.java b/app/src/processing/app/Theme.java index bfa39349888..1a09ad1b559 100644 --- a/app/src/processing/app/Theme.java +++ b/app/src/processing/app/Theme.java @@ -61,6 +61,8 @@ * and to make way for future ability to customize. */ public class Theme { + + static final String THEME_DIR = "theme/"; /** * Copy of the defaults in case the user mangles a preference. @@ -73,7 +75,8 @@ public class Theme { static protected void init() { try { - table.load(new File(BaseNoGui.getContentFile("lib"), "theme/theme.txt")); + table.load(new File(BaseNoGui.getContentFile("lib"), THEME_DIR + "theme.txt")); + table.load(getThemeFile(THEME_DIR + "theme.txt")); } catch (Exception te) { Base.showError(null, tr("Could not read color theme settings.\n" + "You'll need to reinstall Arduino."), @@ -177,6 +180,9 @@ static public Font getFont(String attr) { String value = getDefault(attr); set(attr, value); font = PreferencesHelper.getFont(table, attr); + if (font == null) { + return null; + } } return font.deriveFont((float) scale(font.getSize())); } @@ -245,11 +251,10 @@ public static Map getStyledFont(String what, Font font) { */ static public Image getLibImage(String filename, Component who, int width, int height) { - File libFolder = BaseNoGui.getContentFile("lib"); Image image = null; // Use vector image when available - File vectorFile = new File(libFolder, filename + ".svg"); + File vectorFile = getThemeFile(filename + ".svg"); if (vectorFile.exists()) { try { image = imageFromSVG(vectorFile.toURI().toURL(), width, height); @@ -259,13 +264,16 @@ static public Image getLibImage(String filename, Component who, int width, } } - // Otherwise fall-back to PNG bitmaps - if (image == null) { - File bitmapFile = new File(libFolder, filename + ".png"); - File bitmap2xFile = new File(libFolder, filename + "@2x.png"); + File bitmapFile = getThemeFile(filename + ".png"); + + // Otherwise fall-back to PNG bitmaps, allowing user-defined bitmaps to + // override built-in svgs + if (image == null || (!isUserThemeFile(vectorFile) && isUserThemeFile(bitmapFile))) { + File bitmap2xFile = getThemeFile(filename + "@2x.png"); File imageFile; - if ((getScale() > 125 && bitmap2xFile.exists()) || !bitmapFile.exists()) { + if (((getScale() > 125 && bitmap2xFile.exists()) || !bitmapFile.exists()) + && isUserThemeFile(bitmapFile) == isUserThemeFile(bitmap2xFile)) { imageFile = bitmap2xFile; } else { imageFile = bitmapFile; @@ -298,7 +306,7 @@ static public Image getLibImage(String filename, Component who, int width, */ static public Image getThemeImage(String name, Component who, int width, int height) { - return getLibImage("theme/" + name, who, width, height); + return getLibImage(THEME_DIR + name, who, width, height); } private static Image imageFromSVG(URL url, int width, int height) @@ -324,5 +332,33 @@ static public Graphics2D setupGraphics2D(Graphics graphics) { } return g; } + + /** + * Check whether the specified file is a user-defined theme file + */ + static public boolean isUserThemeFile(File file) { + return file.exists() && file.getAbsolutePath().startsWith(BaseNoGui.getSketchbookFolder().getAbsolutePath()); + } + /** + * @param name + * @return + */ + static public File getThemeFile(String name) { + File sketchBookThemeFolder = new File(BaseNoGui.getSketchbookFolder(), THEME_DIR); + + File themeFile = new File(sketchBookThemeFolder, name); + if (themeFile.exists()) { + return themeFile; + } + + if (name.startsWith(THEME_DIR)) { + themeFile = new File(sketchBookThemeFolder, name.substring(THEME_DIR.length())); + if (themeFile.exists()) { + return themeFile; + } + } + + return new File(BaseNoGui.getContentFile("lib"), name); + } } diff --git a/app/src/processing/app/forms/PasswordAuthorizationDialog.java b/app/src/processing/app/forms/PasswordAuthorizationDialog.java index d050a8ce2ff..1d464fbfcf9 100644 --- a/app/src/processing/app/forms/PasswordAuthorizationDialog.java +++ b/app/src/processing/app/forms/PasswordAuthorizationDialog.java @@ -1,12 +1,12 @@ package processing.app.forms; import processing.app.Base; +import processing.app.Theme; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.WindowEvent; -import java.io.File; import static processing.app.I18n.tr; @@ -34,7 +34,7 @@ public PasswordAuthorizationDialog(Frame parent, String dialogText) { typePasswordLabel.setText(dialogText); - icon.setIcon(new ImageIcon(new File(Base.getContentFile("lib"), "theme/lock.png").getAbsolutePath())); + icon.setIcon(new ImageIcon(Theme.getThemeFile("theme/lock.png").getAbsolutePath())); passwordLabel.setText(tr("Password:")); diff --git a/app/src/processing/app/syntax/SketchTextArea.java b/app/src/processing/app/syntax/SketchTextArea.java index 64133ba23cd..9ae605a1f93 100644 --- a/app/src/processing/app/syntax/SketchTextArea.java +++ b/app/src/processing/app/syntax/SketchTextArea.java @@ -110,7 +110,7 @@ private void installFeatures() throws IOException { private void setTheme(String name) throws IOException { FileInputStream defaultXmlInputStream = null; try { - defaultXmlInputStream = new FileInputStream(new File(BaseNoGui.getContentFile("lib"), "theme/syntax/" + name + ".xml")); + defaultXmlInputStream = new FileInputStream(processing.app.Theme.getThemeFile("theme/syntax/" + name + ".xml")); Theme theme = Theme.load(defaultXmlInputStream); theme.apply(this); } finally {