ADR: EditorColor Registry Consistency

Status

Proposed (Date: 2026-08-02)

Context

org.omegat.util.gui.Styles.EditorColor is the registry that mediates between Theme, application code, and Preferences for every segment marker colour (see the mechanism reference in 84.ThemeColorAndPresentation.md). An audit of the enum, done while reviewing ADR 2026003, found that its ~50 entries are declared through three different constructors, each with a different default-resolution behaviour:

  1. Two-argument, theme-backed (the majority of entries): the default is UIManager.getColor("OmegaT.xxx"), i.e. whatever the active theme defines. Example: COLOR_ACTIVE_SOURCE(displayName, UIManager.getColor("OmegaT.activeSource")).

  2. Three-argument, hardcoded fallback (3 entries — the Source Files progress colours): the default is UIManager.getColor(uiManagerKey) if present, otherwise a literal hex colour compiled into Styles.java:

    COLOR_PROJECT_FILES_PROGRESS_LOW(displayName, "OmegaT.projectFilesProgressLow", "#f0b8b4"),
    COLOR_PROJECT_FILES_PROGRESS_HIGH(displayName, "OmegaT.projectFilesProgressHigh", "#b7d7b7"),
    COLOR_PROJECT_FILES_PROGRESS_COMPLETE(displayName, "OmegaT.projectFilesProgressComplete", "#b8ccf0"),
    

    Neither DefaultFlatLightTheme nor DefaultFlatDarkTheme defines these three OmegaT.* keys, so the hardcoded literal is not a rare fallback — it is the value every user of the two bundled themes actually gets today.

  3. One-argument, no theme default (roughly 15 entries): defaultColor is null at construction, and the resolved colour stays null unless a Preferences value has been set. No OmegaT.* UIDefaults key exists for these at all, in either bundled theme. Example: COLOR_ACTIVE_TARGET(displayName), and similarly COLOR_ACTIVE_SOURCE_FG, COLOR_ACTIVE_TARGET_FG, COLOR_SEGMENT_MARKER_FG, COLOR_SEGMENT_MARKER_BG, COLOR_SOURCE_FG, COLOR_NOTED_FG, COLOR_UNTRANSLATED_FG, COLOR_TRANSLATED_FG, COLOR_NON_UNIQUE_BG, COLOR_MOD_INFO, COLOR_MOD_INFO_FG, COLOR_GLOSSARY_SOURCE, COLOR_GLOSSARY_TARGET, COLOR_GLOSSARY_NOTE, COLOR_MATCHES_DEL_ACTIVE, COLOR_MATCHES_DEL_INACTIVE. Consumers such as EditorSettings.getAttributeSet() call .getColor() on these directly and pass the (possibly null) result straight into Styles.createAttributeSet(); there is no null-handling fallback at the call site either.

Pattern (2) means a theme author has no reliable way to make the Source Files progress colours part of their palette without also relying on undocumented code-level defaults. Pattern (3) means a theme author — including a hypothetical high-contrast/accessibility theme, one of the options raised in the persona review behind 2026003 — cannot control those ~15 markers via the Theme layer at all; the only way to set them is per-user Preferences, which is not something a theme can ship.

This is directly relevant to 2026003. That ADR’s decision is to extend the theme-to-registry- to-preference chain to additional presentation channels (formatting, audio, accessibility labels) uniformly across markers. Doing that on top of the current registry means propagating three inconsistent default-resolution patterns across N new channels instead of one. It is cheaper to unify the registry first.

Decision

Decision A. Every EditorColor entry will have a real, theme-resolvable default, reached via the standard two-argument, theme-backed constructor:

  • The three Source Files progress colours gain corresponding OmegaT.* keys in both DefaultFlatLightTheme and DefaultFlatDarkTheme, and move off the three-argument constructor.

  • The ~15 theme-less entries gain corresponding OmegaT.* keys in both bundled themes as well, and move off the one-argument constructor.

This is an architecture decision, not a design decision: it is about where each default lives (theme-backed key vs. hardcoded literal vs. absent), not about what the colour values should be. Selecting the actual colour values is an implementation detail left to the PR that carries out this change, not decided here. In particular, no visual change is intended as a result of this ADR: for the three progress-colour entries a value already exists (the current hardcoded literal) and the expectation is that it carries over unchanged; this ADR does not mandate that expectation, it simply is not proposing a redesign.

Decision B. Once Decision A is complete, remove the one-argument and three-argument EditorColor constructors entirely, leaving a single canonical two-argument, theme-backed constructor. This is a deliberate constraint on the enum’s API surface so that a future contributor — including whoever implements 2026003’s additional channels — cannot reintroduce a theme-less or hardcoded-fallback entry.

The existing ColorScheme_{dark,light}.properties fallback in UIDesignManager (used only when a third-party theme omits OmegaT.* keys entirely) is unaffected by this decision; it remains the safety net for incomplete external themes, which is a different concern from the two bundled themes carrying inconsistent defaults internally.

Consequences

Positive

  • Every marker becomes fully definable by a theme, which is required groundwork for a high-contrast or otherwise accessibility-oriented theme, one of the resolutions proposed in 2026003 for the persona review’s contrast-audit item.

  • 2026003’s planned extension of the registry to formatting/audio/accessibility-label channels can follow one constructor pattern instead of reconciling three.

  • Removes a currently silent behaviour (the hardcoded progress-colour fallback applies to the bundled themes today, not just hypothetical incomplete ones) that no theme author can override short of also touching Preferences.

Negative

  • Requires adding ~18 new keys to both DefaultFlatLightTheme and DefaultFlatDarkTheme. Colour value selection for this is out of scope of this ADR and left to the implementation PR; it is not a purely mechanical change for the ~15 entries that have never had a theme-backed value before, since there is nothing existing to carry over for those.

  • Any third-party theme plugin, or a user relying on the current “null means inherit component default” behaviour for one of the fifteen theme-less markers, may see a visible colour change once a real default is introduced there. This risk does not apply to the three progress-colour entries, where the existing hardcoded literal is expected to carry over unchanged.

  • Removing the one- and three-argument constructors is a breaking change to Styles.java’s internal API surface (not a public/plugin API, but touches every affected enum literal in one changeset).