package app; // Java imports import java.awt.*; import java.util.*; import javax.swing.*; // Project imports import util.*; import vue.*; // Top-level software state manager public class App { // Instance fields private boolean useNative; // Produce native core contexts private Localizer.Locale[] locales; // Language translations private ArrayList windows; // Application windows // Configuration fields Util.Font fntDialog; // Dialog font Util.Font fntMono; // Monospaced font int hexDigitWidth; // Width in pixels of one hex digit Localizer localizer; // UI localization manager int[][] rgbBase; // Base anaglyph filter colors int rgbClear; // Transparent pixel color /////////////////////////////////////////////////////////////////////////// // Constants // /////////////////////////////////////////////////////////////////////////// // Anaglyph presets static final int[] RED = { 0xFF, 0x00, 0x00 }; static final int[] CYAN = { 0x00, 0xC6, 0xF0 }; static final int[] GREEN = { 0x00, 0xB4, 0x00 }; static final int[] MAGENTA = { 0xC8, 0x00, 0xFF }; /////////////////////////////////////////////////////////////////////////// // Constructors // /////////////////////////////////////////////////////////////////////////// // Default constructor public App(boolean useNative) { // Configure instance fields localizer = new Localizer(); windows = new ArrayList(); // Configure config fields fntDialog = new Util.Font(new JLabel().getFont()); fntMono = new Util.Font(new Font(Util.fontFamily(new String[] { "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14)); hexDigitWidth = hexDigitWidth(); rgbBase = new int[][] { GREEN, MAGENTA, RED }; rgbClear = 0x003050; // Additional processing setUseNative(useNative); initLocales(); addWindow(); } /////////////////////////////////////////////////////////////////////////// // Package Methods // /////////////////////////////////////////////////////////////////////////// // Add a new program window void addWindow() { windows.add(new MainWindow(this)); windowsChanged(); } // Determine whether the native module is in use boolean getUseNative() { return useNative; } // Retrieve a list of registered locales Localizer.Locale[] listLocales() { var ret = new Localizer.Locale[locales.length]; System.arraycopy(locales, 0, ret, 0, locales.length); return ret; } // Determine the number of a window in the collection int numberOf(MainWindow window) { return windows.indexOf(window) + 1; } // Remove a program window void removeWindow(MainWindow window) { windows.remove(window); windowsChanged(); } // Specify whether using the native module boolean setUseNative(boolean useNative) { return this.useNative = useNative && Vue.getNativeID() != null; } /////////////////////////////////////////////////////////////////////////// // Private Methods // /////////////////////////////////////////////////////////////////////////// // Calculate the maximum hexadecimal digit width private int hexDigitWidth() { int width = 0; for (var digit : "0123456789ABCDEFabcdef".toCharArray()) width = Math.max(width, fntMono.metrics.charWidth(digit)); return width; } // Load and parse all locale translations private void initLocales() { // Process all locale files var locales = new HashMap(); for (String file : Util.listFiles("locale")) { // Process the file try { var locale = Localizer.parse(Util.textRead("locale/" + file)); String key = locale.id.toLowerCase(); // Register the locale if (locales.containsKey(key)) throw new RuntimeException( "Locale with ID '" + locale.id + "' already registered"); locales.put(key, locale); // The locale matches the one in the config if (key.equals("en-us")) localizer.setLocale(locale); } // Could not process the file catch (Exception e) { System.err.println("Error parsing locale " + file + ": " + e.getMessage()); } } // Produce the list of registered locales this.locales = locales.values().toArray( new Localizer.Locale[locales.size()]); Arrays.sort(this.locales); // Select a default locale if (localizer.getLocale() != null || this.locales.length == 0) return; var locale = locales.get("en-us"); localizer.setLocale(locale != null ? locale : this.locales[0]); } // A window has been added to or removed from the program state private void windowsChanged() { int count = windows.size(); for (int x = 0; x < count; x++) windows.get(x).windowsChanged(x + 1, count == 1); } }