mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: theme sync with OS (#82)
This commit is contained in:
433
src/main/java/app/termora/SwingUtils.java
Normal file
433
src/main/java/app/termora/SwingUtils.java
Normal file
@@ -0,0 +1,433 @@
|
|||||||
|
package app.termora;/*
|
||||||
|
* @(#)SwingUtils.java 1.02 11/15/08
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//package darrylbu.util;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of utility methods for Swing.
|
||||||
|
*
|
||||||
|
* @author Darryl Burke
|
||||||
|
*/
|
||||||
|
public final class SwingUtils {
|
||||||
|
|
||||||
|
private SwingUtils() {
|
||||||
|
throw new Error("SwingUtils is just a container for static methods");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for searching below <code>container</code> in the
|
||||||
|
* component hierarchy and return nested components that are instances of
|
||||||
|
* class <code>clazz</code> it finds. Returns an empty list if no such
|
||||||
|
* components exist in the container.
|
||||||
|
* <P>
|
||||||
|
* Invoking this method with a class parameter of JComponent.class
|
||||||
|
* will return all nested components.
|
||||||
|
* <P>
|
||||||
|
* This method invokes getDescendantsOfType(clazz, container, true)
|
||||||
|
*
|
||||||
|
* @param clazz the class of components whose instances are to be found.
|
||||||
|
* @param container the container at which to begin the search
|
||||||
|
* @return the List of components
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> List<T> getDescendantsOfType(
|
||||||
|
Class<T> clazz, Container container) {
|
||||||
|
return getDescendantsOfType(clazz, container, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for searching below <code>container</code> in the
|
||||||
|
* component hierarchy and return nested components that are instances of
|
||||||
|
* class <code>clazz</code> it finds. Returns an empty list if no such
|
||||||
|
* components exist in the container.
|
||||||
|
* <P>
|
||||||
|
* Invoking this method with a class parameter of JComponent.class
|
||||||
|
* will return all nested components.
|
||||||
|
*
|
||||||
|
* @param clazz the class of components whose instances are to be found.
|
||||||
|
* @param container the container at which to begin the search
|
||||||
|
* @param nested true to list components nested within another listed
|
||||||
|
* component, false otherwise
|
||||||
|
* @return the List of components
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> List<T> getDescendantsOfType(
|
||||||
|
Class<T> clazz, Container container, boolean nested) {
|
||||||
|
List<T> tList = new ArrayList<T>();
|
||||||
|
for (Component component : container.getComponents()) {
|
||||||
|
if (clazz.isAssignableFrom(component.getClass())) {
|
||||||
|
tList.add(clazz.cast(component));
|
||||||
|
}
|
||||||
|
if (nested || !clazz.isAssignableFrom(component.getClass())) {
|
||||||
|
tList.addAll(SwingUtils.<T>getDescendantsOfType(clazz,
|
||||||
|
(Container) component, nested));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method that searches below <code>container</code> in the
|
||||||
|
* component hierarchy and returns the first found component that is an
|
||||||
|
* instance of class <code>clazz</code> having the bound property value.
|
||||||
|
* Returns {@code null} if such component cannot be found.
|
||||||
|
* <P>
|
||||||
|
* This method invokes getDescendantOfType(clazz, container, property, value,
|
||||||
|
* true)
|
||||||
|
*
|
||||||
|
* @param clazz the class of component whose instance is to be found.
|
||||||
|
* @param container the container at which to begin the search
|
||||||
|
* @param property the className of the bound property, exactly as expressed in
|
||||||
|
* the accessor e.g. "Text" for getText(), "Value" for getValue().
|
||||||
|
* @param value the value of the bound property
|
||||||
|
* @return the component, or null if no such component exists in the
|
||||||
|
* container
|
||||||
|
* @throws java.lang.IllegalArgumentException if the bound property does
|
||||||
|
* not exist for the class or cannot be accessed
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> T getDescendantOfType(
|
||||||
|
Class<T> clazz, Container container, String property, Object value)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
return getDescendantOfType(clazz, container, property, value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method that searches below <code>container</code> in the
|
||||||
|
* component hierarchy and returns the first found component that is an
|
||||||
|
* instance of class <code>clazz</code> and has the bound property value.
|
||||||
|
* Returns {@code null} if such component cannot be found.
|
||||||
|
*
|
||||||
|
* @param clazz the class of component whose instance to be found.
|
||||||
|
* @param container the container at which to begin the search
|
||||||
|
* @param property the className of the bound property, exactly as expressed in
|
||||||
|
* the accessor e.g. "Text" for getText(), "Value" for getValue().
|
||||||
|
* @param value the value of the bound property
|
||||||
|
* @param nested true to list components nested within another component
|
||||||
|
* which is also an instance of <code>clazz</code>, false otherwise
|
||||||
|
* @return the component, or null if no such component exists in the
|
||||||
|
* container
|
||||||
|
* @throws java.lang.IllegalArgumentException if the bound property does
|
||||||
|
* not exist for the class or cannot be accessed
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> T getDescendantOfType(Class<T> clazz,
|
||||||
|
Container container, String property, Object value, boolean nested)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
List<T> list = getDescendantsOfType(clazz, container, nested);
|
||||||
|
return getComponentFromList(clazz, list, property, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for searching below <code>container</code> in the
|
||||||
|
* component hierarchy and return nested components of class
|
||||||
|
* <code>clazz</code> it finds. Returns an empty list if no such
|
||||||
|
* components exist in the container.
|
||||||
|
* <P>
|
||||||
|
* This method invokes getDescendantsOfClass(clazz, container, true)
|
||||||
|
*
|
||||||
|
* @param clazz the class of components to be found.
|
||||||
|
* @param container the container at which to begin the search
|
||||||
|
* @return the List of components
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> List<T> getDescendantsOfClass(
|
||||||
|
Class<T> clazz, Container container) {
|
||||||
|
return getDescendantsOfClass(clazz, container, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for searching below <code>container</code> in the
|
||||||
|
* component hierarchy and return nested components of class
|
||||||
|
* <code>clazz</code> it finds. Returns an empty list if no such
|
||||||
|
* components exist in the container.
|
||||||
|
*
|
||||||
|
* @param clazz the class of components to be found.
|
||||||
|
* @param container the container at which to begin the search
|
||||||
|
* @param nested true to list components nested within another listed
|
||||||
|
* component, false otherwise
|
||||||
|
* @return the List of components
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> List<T> getDescendantsOfClass(
|
||||||
|
Class<T> clazz, Container container, boolean nested) {
|
||||||
|
List<T> tList = new ArrayList<T>();
|
||||||
|
for (Component component : container.getComponents()) {
|
||||||
|
if (clazz.equals(component.getClass())) {
|
||||||
|
tList.add(clazz.cast(component));
|
||||||
|
}
|
||||||
|
if (nested || !clazz.equals(component.getClass())) {
|
||||||
|
tList.addAll(SwingUtils.<T>getDescendantsOfClass(clazz,
|
||||||
|
(Container) component, nested));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method that searches below <code>container</code> in the
|
||||||
|
* component hierarchy in a depth first manner and returns the first
|
||||||
|
* found component of class <code>clazz</code> having the bound property
|
||||||
|
* value.
|
||||||
|
* <P>
|
||||||
|
* Returns {@code null} if such component cannot be found.
|
||||||
|
* <P>
|
||||||
|
* This method invokes getDescendantOfClass(clazz, container, property,
|
||||||
|
* value, true)
|
||||||
|
*
|
||||||
|
* @param clazz the class of component to be found.
|
||||||
|
* @param container the container at which to begin the search
|
||||||
|
* @param property the className of the bound property, exactly as expressed in
|
||||||
|
* the accessor e.g. "Text" for getText(), "Value" for getValue().
|
||||||
|
* This parameter is case sensitive.
|
||||||
|
* @param value the value of the bound property
|
||||||
|
* @return the component, or null if no such component exists in the
|
||||||
|
* container's hierarchy.
|
||||||
|
* @throws java.lang.IllegalArgumentException if the bound property does
|
||||||
|
* not exist for the class or cannot be accessed
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> T getDescendantOfClass(Class<T> clazz,
|
||||||
|
Container container, String property, Object value)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
return getDescendantOfClass(clazz, container, property, value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method that searches below <code>container</code> in the
|
||||||
|
* component hierarchy in a depth first manner and returns the first
|
||||||
|
* found component of class <code>clazz</code> having the bound property
|
||||||
|
* value.
|
||||||
|
* <P>
|
||||||
|
* Returns {@code null} if such component cannot be found.
|
||||||
|
*
|
||||||
|
* @param clazz the class of component to be found.
|
||||||
|
* @param container the container at which to begin the search
|
||||||
|
* @param property the className of the bound property, exactly as expressed
|
||||||
|
* in the accessor e.g. "Text" for getText(), "Value" for getValue().
|
||||||
|
* This parameter is case sensitive.
|
||||||
|
* @param value the value of the bound property
|
||||||
|
* @param nested true to include components nested within another listed
|
||||||
|
* component, false otherwise
|
||||||
|
* @return the component, or null if no such component exists in the
|
||||||
|
* container's hierarchy
|
||||||
|
* @throws java.lang.IllegalArgumentException if the bound property does
|
||||||
|
* not exist for the class or cannot be accessed
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> T getDescendantOfClass(Class<T> clazz,
|
||||||
|
Container container, String property, Object value, boolean nested)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
List<T> list = getDescendantsOfClass(clazz, container, nested);
|
||||||
|
return getComponentFromList(clazz, list, property, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends JComponent> T getComponentFromList(Class<T> clazz,
|
||||||
|
List<T> list, String property, Object value)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
T retVal = null;
|
||||||
|
Method method = null;
|
||||||
|
try {
|
||||||
|
method = clazz.getMethod("get" + property);
|
||||||
|
} catch (NoSuchMethodException ex) {
|
||||||
|
try {
|
||||||
|
method = clazz.getMethod("is" + property);
|
||||||
|
} catch (NoSuchMethodException ex1) {
|
||||||
|
throw new IllegalArgumentException("Property " + property +
|
||||||
|
" not found in class " + clazz.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (T t : list) {
|
||||||
|
Object testVal = method.invoke(t);
|
||||||
|
if (equals(value, testVal)) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvocationTargetException ex) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Error accessing property " + property +
|
||||||
|
" in class " + clazz.getName());
|
||||||
|
} catch (IllegalAccessException ex) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Property " + property +
|
||||||
|
" cannot be accessed in class " + clazz.getName());
|
||||||
|
} catch (SecurityException ex) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Property " + property +
|
||||||
|
" cannot be accessed in class " + clazz.getName());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for determining whether two objects are either
|
||||||
|
* equal or both null.
|
||||||
|
*
|
||||||
|
* @param obj1 the first reference object to compare.
|
||||||
|
* @param obj2 the second reference object to compare.
|
||||||
|
* @return true if obj1 and obj2 are equal or if both are null,
|
||||||
|
* false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean equals(Object obj1, Object obj2) {
|
||||||
|
return obj1 == null ? obj2 == null : obj1.equals(obj2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for mapping a container in the hierarchy to its
|
||||||
|
* contained components. The keys are the containers, and the values
|
||||||
|
* are lists of contained components.
|
||||||
|
* <P>
|
||||||
|
* Implementation note: The returned value is a HashMap and the values
|
||||||
|
* are of type ArrayList. This is subject to change, so callers should
|
||||||
|
* code against the interfaces Map and List.
|
||||||
|
*
|
||||||
|
* @param container The JComponent to be mapped
|
||||||
|
* @param nested true to drill down to nested containers, false otherwise
|
||||||
|
* @return the Map of the UI
|
||||||
|
*/
|
||||||
|
public static Map<JComponent, List<JComponent>> getComponentMap(
|
||||||
|
JComponent container, boolean nested) {
|
||||||
|
HashMap<JComponent, List<JComponent>> retVal =
|
||||||
|
new HashMap<JComponent, List<JComponent>>();
|
||||||
|
for (JComponent component : getDescendantsOfType(JComponent.class,
|
||||||
|
container, false)) {
|
||||||
|
if (!retVal.containsKey(container)) {
|
||||||
|
retVal.put(container,
|
||||||
|
new ArrayList<JComponent>());
|
||||||
|
}
|
||||||
|
retVal.get(container).add(component);
|
||||||
|
if (nested) {
|
||||||
|
retVal.putAll(getComponentMap(component, nested));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for retrieving a subset of the UIDefaults pertaining
|
||||||
|
* to a particular class.
|
||||||
|
*
|
||||||
|
* @param clazz the class of interest
|
||||||
|
* @return the UIDefaults of the class
|
||||||
|
*/
|
||||||
|
public static UIDefaults getUIDefaultsOfClass(Class clazz) {
|
||||||
|
String name = clazz.getName();
|
||||||
|
name = name.substring(name.lastIndexOf(".") + 2);
|
||||||
|
return getUIDefaultsOfClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for retrieving a subset of the UIDefaults pertaining
|
||||||
|
* to a particular class.
|
||||||
|
*
|
||||||
|
* @param className fully qualified name of the class of interest
|
||||||
|
* @return the UIDefaults of the class named
|
||||||
|
*/
|
||||||
|
public static UIDefaults getUIDefaultsOfClass(String className) {
|
||||||
|
UIDefaults retVal = new UIDefaults();
|
||||||
|
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
|
||||||
|
List<?> listKeys = Collections.list(defaults.keys());
|
||||||
|
for (Object key : listKeys) {
|
||||||
|
if (key instanceof String && ((String) key).startsWith(className)) {
|
||||||
|
String stringKey = (String) key;
|
||||||
|
String property = stringKey;
|
||||||
|
if (stringKey.contains(".")) {
|
||||||
|
property = stringKey.substring(stringKey.indexOf(".") + 1);
|
||||||
|
}
|
||||||
|
retVal.put(property, defaults.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for retrieving the UIDefault for a single property
|
||||||
|
* of a particular class.
|
||||||
|
*
|
||||||
|
* @param clazz the class of interest
|
||||||
|
* @param property the property to query
|
||||||
|
* @return the UIDefault property, or null if not found
|
||||||
|
*/
|
||||||
|
public static Object getUIDefaultOfClass(Class clazz, String property) {
|
||||||
|
Object retVal = null;
|
||||||
|
UIDefaults defaults = getUIDefaultsOfClass(clazz);
|
||||||
|
List<Object> listKeys = Collections.list(defaults.keys());
|
||||||
|
for (Object key : listKeys) {
|
||||||
|
if (key.equals(property)) {
|
||||||
|
return defaults.get(key);
|
||||||
|
}
|
||||||
|
if (key.toString().equalsIgnoreCase(property)) {
|
||||||
|
retVal = defaults.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exclude methods that return values that are meaningless to the user
|
||||||
|
*/
|
||||||
|
static Set<String> setExclude = new HashSet<String>();
|
||||||
|
static {
|
||||||
|
setExclude.add("getFocusCycleRootAncestor");
|
||||||
|
setExclude.add("getAccessibleContext");
|
||||||
|
setExclude.add("getColorModel");
|
||||||
|
setExclude.add("getGraphics");
|
||||||
|
setExclude.add("getGraphicsConfiguration");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for obtaining most non-null human readable properties
|
||||||
|
* of a JComponent. Array properties are not included.
|
||||||
|
* <P>
|
||||||
|
* Implementation note: The returned value is a HashMap. This is subject
|
||||||
|
* to change, so callers should code against the interface Map.
|
||||||
|
*
|
||||||
|
* @param component the component whose proerties are to be determined
|
||||||
|
* @return the class and value of the properties
|
||||||
|
*/
|
||||||
|
public static Map<Object, Object> getProperties(JComponent component) {
|
||||||
|
Map<Object, Object> retVal = new HashMap<Object, Object>();
|
||||||
|
Class<?> clazz = component.getClass();
|
||||||
|
Method[] methods = clazz.getMethods();
|
||||||
|
Object value = null;
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (method.getName().matches("^(is|get).*") &&
|
||||||
|
method.getParameterTypes().length == 0) {
|
||||||
|
try {
|
||||||
|
Class returnType = method.getReturnType();
|
||||||
|
if (returnType != void.class &&
|
||||||
|
!returnType.getName().startsWith("[") &&
|
||||||
|
!setExclude.contains(method.getName())) {
|
||||||
|
String key = method.getName();
|
||||||
|
value = method.invoke(component);
|
||||||
|
if (value != null && !(value instanceof Component)) {
|
||||||
|
retVal.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ignore exceptions that arise if the property could not be accessed
|
||||||
|
} catch (IllegalAccessException ex) {
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
} catch (InvocationTargetException ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to obtain the Swing class from which this
|
||||||
|
* component was directly or indirectly derived.
|
||||||
|
*
|
||||||
|
* @param component The component whose Swing superclass is to be
|
||||||
|
* determined
|
||||||
|
* @return The nearest Swing class in the inheritance tree
|
||||||
|
*/
|
||||||
|
public static <T extends JComponent> Class getJClass(T component) {
|
||||||
|
Class<?> clazz = component.getClass();
|
||||||
|
while (!clazz.getName().matches("javax.swing.J[^.]*$")) {
|
||||||
|
clazz = clazz.getSuperclass();
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -129,14 +129,14 @@ class ApplicationRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val themeManager = ThemeManager.getInstance()
|
val themeManager = ThemeManager.getInstance()
|
||||||
val settings = Database.getDatabase()
|
val appearance = Database.getDatabase().appearance
|
||||||
var theme = settings.appearance.theme
|
var theme = appearance.theme
|
||||||
// 如果是跟随系统或者不存在样式,那么使用默认的
|
// 如果是跟随系统
|
||||||
if (settings.appearance.followSystem || !themeManager.themes.containsKey(theme)) {
|
if (appearance.followSystem) {
|
||||||
theme = if (OsThemeDetector.getDetector().isDark) {
|
theme = if (OsThemeDetector.getDetector().isDark) {
|
||||||
"Dark"
|
appearance.darkTheme
|
||||||
} else {
|
} else {
|
||||||
"Light"
|
appearance.lightTheme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -551,6 +551,8 @@ class Database private constructor(private val env: Environment) : Disposable {
|
|||||||
* 跟随系统
|
* 跟随系统
|
||||||
*/
|
*/
|
||||||
var followSystem by BooleanPropertyDelegate(true)
|
var followSystem by BooleanPropertyDelegate(true)
|
||||||
|
var darkTheme by StringPropertyDelegate("Dark")
|
||||||
|
var lightTheme by StringPropertyDelegate("Light")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语言
|
* 语言
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ import com.formdev.flatlaf.FlatClientProperties
|
|||||||
import com.formdev.flatlaf.FlatLaf
|
import com.formdev.flatlaf.FlatLaf
|
||||||
import com.formdev.flatlaf.util.SystemInfo
|
import com.formdev.flatlaf.util.SystemInfo
|
||||||
import com.jetbrains.JBR
|
import com.jetbrains.JBR
|
||||||
import java.awt.BorderLayout
|
import java.awt.*
|
||||||
import java.awt.Dimension
|
|
||||||
import java.awt.Window
|
|
||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
import java.awt.event.WindowAdapter
|
import java.awt.event.WindowAdapter
|
||||||
import java.awt.event.WindowEvent
|
import java.awt.event.WindowEvent
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
|
|
||||||
|
|
||||||
abstract class DialogWrapper(owner: Window?) : JDialog(owner) {
|
abstract class DialogWrapper(owner: Window?) : JDialog(owner) {
|
||||||
private val rootPanel = JPanel(BorderLayout())
|
private val rootPanel = JPanel(BorderLayout())
|
||||||
private val titleLabel = JLabel()
|
private val titleLabel = JLabel()
|
||||||
@@ -147,6 +146,31 @@ abstract class DialogWrapper(owner: Window?) : JDialog(owner) {
|
|||||||
|
|
||||||
rootPane.actionMap.put("close", object : AnAction() {
|
rootPane.actionMap.put("close", object : AnAction() {
|
||||||
override fun actionPerformed(evt: AnActionEvent) {
|
override fun actionPerformed(evt: AnActionEvent) {
|
||||||
|
val c = KeyboardFocusManager.getCurrentKeyboardFocusManager().focusOwner
|
||||||
|
val popups: List<JPopupMenu> = SwingUtils.getDescendantsOfType(
|
||||||
|
JPopupMenu::class.java,
|
||||||
|
c as Container, true
|
||||||
|
)
|
||||||
|
|
||||||
|
var openPopup = false
|
||||||
|
for (p in popups) {
|
||||||
|
p.isVisible = false
|
||||||
|
openPopup = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val window = SwingUtilities.windowForComponent(c)
|
||||||
|
val windows = window.ownedWindows
|
||||||
|
for (w in windows) {
|
||||||
|
if (w.isVisible && w.javaClass.getName().endsWith("HeavyWeightWindow")) {
|
||||||
|
openPopup = true
|
||||||
|
w.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openPopup) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
doCancelAction()
|
doCancelAction()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ import com.formdev.flatlaf.FlatPropertiesLaf
|
|||||||
import com.formdev.flatlaf.util.SystemInfo
|
import com.formdev.flatlaf.util.SystemInfo
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
interface LafTag
|
||||||
|
interface LightLafTag : LafTag
|
||||||
|
interface DarkLafTag : LafTag
|
||||||
|
|
||||||
class DraculaLaf : FlatPropertiesLaf("Dracula", Properties().apply {
|
class DraculaLaf : FlatPropertiesLaf("Dracula", Properties().apply {
|
||||||
putAll(
|
putAll(
|
||||||
mapOf(
|
mapOf(
|
||||||
@@ -16,7 +21,7 @@ class DraculaLaf : FlatPropertiesLaf("Dracula", Properties().apply {
|
|||||||
"@windowText" to "#eaeaea",
|
"@windowText" to "#eaeaea",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Basic.BACKGROUND -> 0x282935
|
TerminalColor.Basic.BACKGROUND -> 0x282935
|
||||||
@@ -54,7 +59,8 @@ class DraculaLaf : FlatPropertiesLaf("Dracula", Properties().apply {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class LightLaf : FlatLightLaf(), ColorTheme {
|
|
||||||
|
class LightLaf : FlatLightLaf(), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0
|
TerminalColor.Normal.BLACK -> 0
|
||||||
@@ -81,7 +87,7 @@ class LightLaf : FlatLightLaf(), ColorTheme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class DarkLaf : FlatDarkLaf(), ColorTheme {
|
class DarkLaf : FlatDarkLaf(), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0
|
TerminalColor.Normal.BLACK -> 0
|
||||||
@@ -110,7 +116,7 @@ class DarkLaf : FlatDarkLaf(), ColorTheme {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class iTerm2DarkLaf : FlatDarkLaf(), ColorTheme {
|
class iTerm2DarkLaf : FlatDarkLaf(), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
|
|
||||||
@@ -158,7 +164,7 @@ class TermiusLightLaf : FlatPropertiesLaf("Termius Light", Properties().apply {
|
|||||||
"@windowText" to "#32364a",
|
"@windowText" to "#32364a",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
|
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
|
|
||||||
@@ -201,7 +207,7 @@ class TermiusDarkLaf : FlatPropertiesLaf("Termius Dark", Properties().apply {
|
|||||||
"@windowText" to "#21b568",
|
"@windowText" to "#21b568",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
|
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
@@ -243,7 +249,7 @@ class NovelLaf : FlatPropertiesLaf("Novel", Properties().apply {
|
|||||||
"@windowText" to "#3b2322",
|
"@windowText" to "#3b2322",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -282,7 +288,7 @@ class AtomOneDarkLaf : FlatPropertiesLaf("Atom One Dark", Properties().apply {
|
|||||||
"@windowText" to "#abb2bf",
|
"@windowText" to "#abb2bf",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -320,7 +326,7 @@ class AtomOneLightLaf : FlatPropertiesLaf("Atom One Light", Properties().apply {
|
|||||||
"@windowText" to "#383a42",
|
"@windowText" to "#383a42",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -358,7 +364,7 @@ class EverforestDarkLaf : FlatPropertiesLaf("Everforest Dark", Properties().appl
|
|||||||
"@windowText" to "#d3c6aa",
|
"@windowText" to "#d3c6aa",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x42494e
|
TerminalColor.Normal.BLACK -> 0x42494e
|
||||||
@@ -395,7 +401,7 @@ class EverforestLightLaf : FlatPropertiesLaf("Everforest Light", Properties().ap
|
|||||||
"@windowText" to "#5c6a72",
|
"@windowText" to "#5c6a72",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x42494e
|
TerminalColor.Normal.BLACK -> 0x42494e
|
||||||
@@ -432,7 +438,7 @@ class NightOwlLaf : FlatPropertiesLaf("Night Owl", Properties().apply {
|
|||||||
"@windowText" to "#d6deeb",
|
"@windowText" to "#d6deeb",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x072945
|
TerminalColor.Normal.BLACK -> 0x072945
|
||||||
@@ -469,7 +475,7 @@ class LightOwlLaf : FlatPropertiesLaf("Light Owl", Properties().apply {
|
|||||||
"@windowText" to "#403f53",
|
"@windowText" to "#403f53",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x403f53
|
TerminalColor.Normal.BLACK -> 0x403f53
|
||||||
@@ -506,7 +512,7 @@ class AuraLaf : FlatPropertiesLaf("Aura", Properties().apply {
|
|||||||
"@windowText" to "#edecee",
|
"@windowText" to "#edecee",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x1c1b22
|
TerminalColor.Normal.BLACK -> 0x1c1b22
|
||||||
@@ -543,7 +549,7 @@ class Cobalt2Laf : FlatPropertiesLaf("Cobalt2", Properties().apply {
|
|||||||
"@windowText" to "#ffffff",
|
"@windowText" to "#ffffff",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -580,7 +586,7 @@ class OctocatDarkLaf : FlatPropertiesLaf("Octocat Dark", Properties().apply {
|
|||||||
"@windowText" to "#8b949e",
|
"@windowText" to "#8b949e",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -617,7 +623,7 @@ class OctocatLightLaf : FlatPropertiesLaf("Octocat Light", Properties().apply {
|
|||||||
"@windowText" to "#3e3e3e",
|
"@windowText" to "#3e3e3e",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -654,7 +660,7 @@ class AyuDarkLaf : FlatPropertiesLaf("Ayu Dark", Properties().apply {
|
|||||||
"@windowText" to "#e6e1cf",
|
"@windowText" to "#e6e1cf",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -691,7 +697,7 @@ class AyuLightLaf : FlatPropertiesLaf("Ayu Light", Properties().apply {
|
|||||||
"@windowText" to "#5c6773",
|
"@windowText" to "#5c6773",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -728,7 +734,7 @@ class HomebrewLaf : FlatPropertiesLaf("Homebrew", Properties().apply {
|
|||||||
"@windowText" to "#00ff00",
|
"@windowText" to "#00ff00",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x2e2e2e
|
TerminalColor.Normal.BLACK -> 0x2e2e2e
|
||||||
@@ -767,7 +773,7 @@ class ProLaf : FlatPropertiesLaf("Pro", Properties().apply {
|
|||||||
"@windowText" to "#f2f2f2",
|
"@windowText" to "#f2f2f2",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x2e2e2e
|
TerminalColor.Normal.BLACK -> 0x2e2e2e
|
||||||
@@ -806,7 +812,7 @@ class NordLightLaf : FlatPropertiesLaf("Nord Light", Properties().apply {
|
|||||||
"@windowText" to "#414858",
|
"@windowText" to "#414858",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x2c3344
|
TerminalColor.Normal.BLACK -> 0x2c3344
|
||||||
@@ -845,7 +851,7 @@ class NordDarkLaf : FlatPropertiesLaf("Nord Dark", Properties().apply {
|
|||||||
"@windowText" to "#d8dee9",
|
"@windowText" to "#d8dee9",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x3b4252
|
TerminalColor.Normal.BLACK -> 0x3b4252
|
||||||
@@ -885,7 +891,7 @@ class GitHubLightLaf : FlatPropertiesLaf("GitHub Light", Properties().apply {
|
|||||||
"@windowText" to "#3e3e3e",
|
"@windowText" to "#3e3e3e",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, LightLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x3e3e3e
|
TerminalColor.Normal.BLACK -> 0x3e3e3e
|
||||||
@@ -924,7 +930,7 @@ class GitHubDarkLaf : FlatPropertiesLaf("GitHub Dark", Properties().apply {
|
|||||||
"@windowText" to "#8b949e",
|
"@windowText" to "#8b949e",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x000000
|
TerminalColor.Normal.BLACK -> 0x000000
|
||||||
@@ -964,7 +970,7 @@ class ChalkLaf : FlatPropertiesLaf("Chalk", Properties().apply {
|
|||||||
"@windowText" to "#d2d8d9",
|
"@windowText" to "#d2d8d9",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}), ColorTheme {
|
}), ColorTheme, DarkLafTag {
|
||||||
override fun getColor(color: TerminalColor): Int {
|
override fun getColor(color: TerminalColor): Int {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
TerminalColor.Normal.BLACK -> 0x7d8b8f
|
TerminalColor.Normal.BLACK -> 0x7d8b8f
|
||||||
|
|||||||
@@ -17,11 +17,8 @@ import app.termora.terminal.CursorStyle
|
|||||||
import app.termora.terminal.DataKey
|
import app.termora.terminal.DataKey
|
||||||
import app.termora.terminal.panel.TerminalPanel
|
import app.termora.terminal.panel.TerminalPanel
|
||||||
import cash.z.ecc.android.bip39.Mnemonics
|
import cash.z.ecc.android.bip39.Mnemonics
|
||||||
import com.formdev.flatlaf.FlatLaf
|
|
||||||
import com.formdev.flatlaf.extras.FlatSVGIcon
|
import com.formdev.flatlaf.extras.FlatSVGIcon
|
||||||
import com.formdev.flatlaf.extras.components.FlatButton
|
import com.formdev.flatlaf.extras.components.*
|
||||||
import com.formdev.flatlaf.extras.components.FlatComboBox
|
|
||||||
import com.formdev.flatlaf.extras.components.FlatLabel
|
|
||||||
import com.formdev.flatlaf.util.SystemInfo
|
import com.formdev.flatlaf.util.SystemInfo
|
||||||
import com.jgoodies.forms.builder.FormBuilder
|
import com.jgoodies.forms.builder.FormBuilder
|
||||||
import com.jgoodies.forms.layout.FormLayout
|
import com.jgoodies.forms.layout.FormLayout
|
||||||
@@ -49,6 +46,8 @@ import java.nio.charset.StandardCharsets
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
import javax.swing.event.DocumentEvent
|
import javax.swing.event.DocumentEvent
|
||||||
|
import javax.swing.event.PopupMenuEvent
|
||||||
|
import javax.swing.event.PopupMenuListener
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
|
|
||||||
@@ -109,6 +108,7 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
val themeComboBox = FlatComboBox<String>()
|
val themeComboBox = FlatComboBox<String>()
|
||||||
val languageComboBox = FlatComboBox<String>()
|
val languageComboBox = FlatComboBox<String>()
|
||||||
val followSystemCheckBox = JCheckBox(I18n.getString("termora.settings.appearance.follow-system"))
|
val followSystemCheckBox = JCheckBox(I18n.getString("termora.settings.appearance.follow-system"))
|
||||||
|
val preferredThemeBtn = JButton(Icons.settings)
|
||||||
private val appearance get() = database.appearance
|
private val appearance get() = database.appearance
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -119,6 +119,7 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
private fun initView() {
|
private fun initView() {
|
||||||
|
|
||||||
followSystemCheckBox.isSelected = appearance.followSystem
|
followSystemCheckBox.isSelected = appearance.followSystem
|
||||||
|
preferredThemeBtn.isEnabled = followSystemCheckBox.isSelected
|
||||||
|
|
||||||
themeComboBox.isEnabled = !followSystemCheckBox.isSelected
|
themeComboBox.isEnabled = !followSystemCheckBox.isSelected
|
||||||
themeManager.themes.keys.forEach { themeComboBox.addItem(it) }
|
themeManager.themes.keys.forEach { themeComboBox.addItem(it) }
|
||||||
@@ -158,19 +159,17 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
followSystemCheckBox.addActionListener {
|
followSystemCheckBox.addActionListener {
|
||||||
appearance.followSystem = followSystemCheckBox.isSelected
|
appearance.followSystem = followSystemCheckBox.isSelected
|
||||||
themeComboBox.isEnabled = !followSystemCheckBox.isSelected
|
themeComboBox.isEnabled = !followSystemCheckBox.isSelected
|
||||||
|
preferredThemeBtn.isEnabled = followSystemCheckBox.isSelected
|
||||||
|
appearance.theme = themeComboBox.selectedItem as String
|
||||||
|
|
||||||
if (followSystemCheckBox.isSelected) {
|
if (followSystemCheckBox.isSelected) {
|
||||||
SwingUtilities.invokeLater {
|
SwingUtilities.invokeLater {
|
||||||
if (OsThemeDetector.getDetector().isDark) {
|
if (OsThemeDetector.getDetector().isDark) {
|
||||||
if (!FlatLaf.isLafDark()) {
|
themeManager.change(appearance.darkTheme)
|
||||||
themeManager.change("Dark")
|
themeComboBox.selectedItem = appearance.darkTheme
|
||||||
themeComboBox.selectedItem = "Dark"
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (FlatLaf.isLafDark()) {
|
themeManager.change(appearance.lightTheme)
|
||||||
themeManager.change("Light")
|
themeComboBox.selectedItem = appearance.lightTheme
|
||||||
themeComboBox.selectedItem = "Light"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,6 +188,8 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preferredThemeBtn.addActionListener { showPreferredThemeContextmenu() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getIcon(isSelected: Boolean): Icon {
|
override fun getIcon(isSelected: Boolean): Icon {
|
||||||
@@ -203,19 +204,74 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showPreferredThemeContextmenu() {
|
||||||
|
val popupMenu = FlatPopupMenu()
|
||||||
|
val dark = JMenu("For Dark OS")
|
||||||
|
val light = JMenu("For Light OS")
|
||||||
|
val darkTheme = appearance.darkTheme
|
||||||
|
val lightTheme = appearance.lightTheme
|
||||||
|
|
||||||
|
for (e in themeManager.themes) {
|
||||||
|
val clazz = Class.forName(e.value)
|
||||||
|
val item = JCheckBoxMenuItem(e.key)
|
||||||
|
item.isSelected = e.key == lightTheme || e.key == darkTheme
|
||||||
|
if (clazz.interfaces.contains(DarkLafTag::class.java)) {
|
||||||
|
dark.add(item).addActionListener {
|
||||||
|
if (e.key != darkTheme) {
|
||||||
|
appearance.darkTheme = e.key
|
||||||
|
if (OsThemeDetector.getDetector().isDark) {
|
||||||
|
themeComboBox.selectedItem = e.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (clazz.interfaces.contains(LightLafTag::class.java)) {
|
||||||
|
light.add(item).addActionListener {
|
||||||
|
if (e.key != lightTheme) {
|
||||||
|
appearance.lightTheme = e.key
|
||||||
|
if (!OsThemeDetector.getDetector().isDark) {
|
||||||
|
themeComboBox.selectedItem = e.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popupMenu.add(dark)
|
||||||
|
popupMenu.addSeparator()
|
||||||
|
popupMenu.add(light)
|
||||||
|
popupMenu.addPopupMenuListener(object : PopupMenuListener {
|
||||||
|
override fun popupMenuWillBecomeVisible(e: PopupMenuEvent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popupMenuWillBecomeInvisible(e: PopupMenuEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popupMenuCanceled(e: PopupMenuEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
popupMenu.show(preferredThemeBtn, 0, preferredThemeBtn.height + 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getFormPanel(): JPanel {
|
private fun getFormPanel(): JPanel {
|
||||||
val layout = FormLayout(
|
val layout = FormLayout(
|
||||||
"left:pref, $formMargin, default:grow, $formMargin, default, default:grow",
|
"left:pref, $formMargin, default:grow, $formMargin, default, default:grow",
|
||||||
"pref, $formMargin, pref, $formMargin"
|
"pref, $formMargin, pref, $formMargin"
|
||||||
)
|
)
|
||||||
|
val box = FlatToolBar()
|
||||||
|
box.add(followSystemCheckBox)
|
||||||
|
box.add(Box.createHorizontalStrut(2))
|
||||||
|
box.add(preferredThemeBtn)
|
||||||
|
|
||||||
var rows = 1
|
var rows = 1
|
||||||
val step = 2
|
val step = 2
|
||||||
return FormBuilder.create().layout(layout)
|
return FormBuilder.create().layout(layout)
|
||||||
.add("${I18n.getString("termora.settings.appearance.theme")}:").xy(1, rows)
|
.add("${I18n.getString("termora.settings.appearance.theme")}:").xy(1, rows)
|
||||||
.add(themeComboBox).xy(3, rows)
|
.add(themeComboBox).xy(3, rows)
|
||||||
.add(followSystemCheckBox).xy(5, rows).apply { rows += step }
|
.add(box).xy(5, rows).apply { rows += step }
|
||||||
.add("${I18n.getString("termora.settings.appearance.language")}:").xy(1, rows)
|
.add("${I18n.getString("termora.settings.appearance.language")}:").xy(1, rows)
|
||||||
.add(languageComboBox).xy(3, rows)
|
.add(languageComboBox).xy(3, rows)
|
||||||
.add(Hyperlink(object : AnAction(I18n.getString("termora.settings.appearance.i-want-to-translate")) {
|
.add(Hyperlink(object : AnAction(I18n.getString("termora.settings.appearance.i-want-to-translate")) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class ThemeManager private constructor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val appearance by lazy { Database.getDatabase().appearance }
|
||||||
val themes = mapOf(
|
val themes = mapOf(
|
||||||
"Light" to LightLaf::class.java.name,
|
"Light" to LightLaf::class.java.name,
|
||||||
"Dark" to DarkLaf::class.java.name,
|
"Dark" to DarkLaf::class.java.name,
|
||||||
@@ -79,18 +80,16 @@ class ThemeManager private constructor() {
|
|||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
OsThemeDetector.getDetector().registerListener(object : Consumer<Boolean> {
|
OsThemeDetector.getDetector().registerListener(object : Consumer<Boolean> {
|
||||||
override fun accept(isDark: Boolean) {
|
override fun accept(isDark: Boolean) {
|
||||||
if (!Database.getDatabase().appearance.followSystem) {
|
if (!appearance.followSystem) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FlatLaf.isLafDark() && isDark) {
|
SwingUtilities.invokeLater {
|
||||||
return
|
if (isDark) {
|
||||||
}
|
change(appearance.darkTheme)
|
||||||
|
} else {
|
||||||
if (isDark) {
|
change(appearance.lightTheme)
|
||||||
SwingUtilities.invokeLater { change("Dark") }
|
}
|
||||||
} else {
|
|
||||||
SwingUtilities.invokeLater { change("Light") }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user