Skip to content

Commit 3317e84

Browse files
authored
Merge pull request #7115 from Mumfrey/feature/user-defined-themes
[IDE] Add support for user-defined theme in sketchbook folder
2 parents 13d6b25 + f113a76 commit 3317e84

File tree

4 files changed

+63
-12
lines changed

4 files changed

+63
-12
lines changed

Diff for: app/src/processing/app/EditorTab.java

+15
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import java.nio.file.Path;
5959
import java.io.File;
6060

61+
import org.apache.commons.lang3.StringUtils;
6162
import org.fife.ui.autocomplete.AutoCompletion;
6263
import org.fife.ui.autocomplete.DefaultCompletionProvider;
6364
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
@@ -345,6 +346,20 @@ public void applyPreferences() {
345346
}
346347
// apply changes to the font size for the editor
347348
Font editorFont = scale(PreferencesData.getFont("editor.font"));
349+
350+
// check whether a theme-defined editor font is available
351+
Font themeFont = Theme.getFont("editor.font");
352+
if (themeFont != null)
353+
{
354+
// Apply theme font if the editor font has *not* been changed by the user,
355+
// This allows themes to specify an editor font which will only be applied
356+
// if the user hasn't already changed their editor font via preferences.txt
357+
String defaultFontName = StringUtils.defaultIfEmpty(PreferencesData.getDefault("editor.font"), "").split(",")[0];
358+
if (defaultFontName.equals(editorFont.getName())) {
359+
editorFont = new Font(themeFont.getName(), themeFont.getStyle(), editorFont.getSize());
360+
}
361+
}
362+
348363
textarea.setFont(editorFont);
349364
scrollPane.getGutter().setLineNumberFont(editorFont);
350365
}

Diff for: app/src/processing/app/Theme.java

+45-9
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
* and to make way for future ability to customize.
6262
*/
6363
public class Theme {
64+
65+
static final String THEME_DIR = "theme/";
6466

6567
/**
6668
* Copy of the defaults in case the user mangles a preference.
@@ -73,7 +75,8 @@ public class Theme {
7375

7476
static protected void init() {
7577
try {
76-
table.load(new File(BaseNoGui.getContentFile("lib"), "theme/theme.txt"));
78+
table.load(new File(BaseNoGui.getContentFile("lib"), THEME_DIR + "theme.txt"));
79+
table.load(getThemeFile(THEME_DIR + "theme.txt"));
7780
} catch (Exception te) {
7881
Base.showError(null, tr("Could not read color theme settings.\n"
7982
+ "You'll need to reinstall Arduino."),
@@ -177,6 +180,9 @@ static public Font getFont(String attr) {
177180
String value = getDefault(attr);
178181
set(attr, value);
179182
font = PreferencesHelper.getFont(table, attr);
183+
if (font == null) {
184+
return null;
185+
}
180186
}
181187
return font.deriveFont((float) scale(font.getSize()));
182188
}
@@ -245,11 +251,10 @@ public static Map<String, Object> getStyledFont(String what, Font font) {
245251
*/
246252
static public Image getLibImage(String filename, Component who, int width,
247253
int height) {
248-
File libFolder = BaseNoGui.getContentFile("lib");
249254
Image image = null;
250255

251256
// Use vector image when available
252-
File vectorFile = new File(libFolder, filename + ".svg");
257+
File vectorFile = getThemeFile(filename + ".svg");
253258
if (vectorFile.exists()) {
254259
try {
255260
image = imageFromSVG(vectorFile.toURI().toURL(), width, height);
@@ -259,13 +264,16 @@ static public Image getLibImage(String filename, Component who, int width,
259264
}
260265
}
261266

262-
// Otherwise fall-back to PNG bitmaps
263-
if (image == null) {
264-
File bitmapFile = new File(libFolder, filename + ".png");
265-
File bitmap2xFile = new File(libFolder, filename + "@2x.png");
267+
File bitmapFile = getThemeFile(filename + ".png");
268+
269+
// Otherwise fall-back to PNG bitmaps, allowing user-defined bitmaps to
270+
// override built-in svgs
271+
if (image == null || (!isUserThemeFile(vectorFile) && isUserThemeFile(bitmapFile))) {
272+
File bitmap2xFile = getThemeFile(filename + "@2x.png");
266273

267274
File imageFile;
268-
if ((getScale() > 125 && bitmap2xFile.exists()) || !bitmapFile.exists()) {
275+
if (((getScale() > 125 && bitmap2xFile.exists()) || !bitmapFile.exists())
276+
&& isUserThemeFile(bitmapFile) == isUserThemeFile(bitmap2xFile)) {
269277
imageFile = bitmap2xFile;
270278
} else {
271279
imageFile = bitmapFile;
@@ -298,7 +306,7 @@ static public Image getLibImage(String filename, Component who, int width,
298306
*/
299307
static public Image getThemeImage(String name, Component who, int width,
300308
int height) {
301-
return getLibImage("theme/" + name, who, width, height);
309+
return getLibImage(THEME_DIR + name, who, width, height);
302310
}
303311

304312
private static Image imageFromSVG(URL url, int width, int height)
@@ -324,5 +332,33 @@ static public Graphics2D setupGraphics2D(Graphics graphics) {
324332
}
325333
return g;
326334
}
335+
336+
/**
337+
* Check whether the specified file is a user-defined theme file
338+
*/
339+
static public boolean isUserThemeFile(File file) {
340+
return file.exists() && file.getAbsolutePath().startsWith(BaseNoGui.getSketchbookFolder().getAbsolutePath());
341+
}
327342

343+
/**
344+
* @param name
345+
* @return
346+
*/
347+
static public File getThemeFile(String name) {
348+
File sketchBookThemeFolder = new File(BaseNoGui.getSketchbookFolder(), THEME_DIR);
349+
350+
File themeFile = new File(sketchBookThemeFolder, name);
351+
if (themeFile.exists()) {
352+
return themeFile;
353+
}
354+
355+
if (name.startsWith(THEME_DIR)) {
356+
themeFile = new File(sketchBookThemeFolder, name.substring(THEME_DIR.length()));
357+
if (themeFile.exists()) {
358+
return themeFile;
359+
}
360+
}
361+
362+
return new File(BaseNoGui.getContentFile("lib"), name);
363+
}
328364
}

Diff for: app/src/processing/app/forms/PasswordAuthorizationDialog.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package processing.app.forms;
22

33
import processing.app.Base;
4+
import processing.app.Theme;
45

56
import javax.swing.*;
67
import java.awt.*;
78
import java.awt.event.ActionEvent;
89
import java.awt.event.WindowEvent;
9-
import java.io.File;
1010

1111
import static processing.app.I18n.tr;
1212

@@ -34,7 +34,7 @@ public PasswordAuthorizationDialog(Frame parent, String dialogText) {
3434

3535
typePasswordLabel.setText(dialogText);
3636

37-
icon.setIcon(new ImageIcon(new File(Base.getContentFile("lib"), "theme/lock.png").getAbsolutePath()));
37+
icon.setIcon(new ImageIcon(Theme.getThemeFile("theme/lock.png").getAbsolutePath()));
3838

3939
passwordLabel.setText(tr("Password:"));
4040

Diff for: app/src/processing/app/syntax/SketchTextArea.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ private void installFeatures() throws IOException {
110110
private void setTheme(String name) throws IOException {
111111
FileInputStream defaultXmlInputStream = null;
112112
try {
113-
defaultXmlInputStream = new FileInputStream(new File(BaseNoGui.getContentFile("lib"), "theme/syntax/" + name + ".xml"));
113+
defaultXmlInputStream = new FileInputStream(processing.app.Theme.getThemeFile("theme/syntax/" + name + ".xml"));
114114
Theme theme = Theme.load(defaultXmlInputStream);
115115
theme.apply(this);
116116
} finally {

0 commit comments

Comments
 (0)