174 lines
5.5 KiB
Java
174 lines
5.5 KiB
Java
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<MainWindow> 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
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// 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 };
|
|
|
|
// Eyes
|
|
static final int LEFT = 0;
|
|
static final int RIGHT = 1;
|
|
static final int CHR = 2;
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Constructors //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Default constructor
|
|
public App(boolean useNative) {
|
|
|
|
// Configure instance fields
|
|
localizer = new Localizer();
|
|
windows = new ArrayList<MainWindow>();
|
|
|
|
// 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 };
|
|
|
|
// 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<String, Localizer.Locale>();
|
|
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);
|
|
}
|
|
|
|
}
|