Skip to content

Releases: Mustry-Solutions/ignition-designer-dark-mode-module

Release list

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 13:06
330d843

A defect-fixing release. Ten dark-mode defects found by a Designer QA sweep
and fixed, each root-caused to a mechanism rather than patched by eye, and each
confirmed in a real Designer on 8.3.6. The theming passes gained failure
isolation, and the test harness gained two instruments it was missing:
component-level state diffing, and a check that everything this module reaches
by name still exists.

Added

  • A test for everything the module reaches by name
    (#53).
    This module works by reaching into Ignition, JIDE and JFreeChart internals as
    strings — a class called InlineTipLabel, a field called COLOR, a method
    called setLineHighlightColor — none of which the compiler checks, and every
    pass that uses one is deliberately guarded so a failure costs a surface rather
    than the Designer. Together that means an IA rename stops a pass working
    silently. ReflectiveSurfaceTest enumerates the whole surface (about 40
    names) and asserts each still resolves, and CI now runs the harness at both
    the 8.3.0 support floor and the current release. It cannot tell you a class
    still behaves the same — that is what the QA checklist is for — but it turns
    a silent regression into a red build.

  • When updateComponentTreeUI fails on a window, the module now says what
    broke and how much of the tree went unrefreshed

    (#12).
    The failure was already survivable and already logged with its stack, but a
    stack names the UI delegate that threw — not the component, and not the
    subtree the aborted update never reached, which is the part that actually
    matters. The report names components with no font at all and the path to each,
    any UIManager font key resolving to null, and every component left holding a
    delegate from the wrong look and feel. Runs only on the failure path, so it is
    not gated on the debug flag: that is precisely the moment nobody has verbose
    logging on.

  • The harness pins that no FlatLaf scaling listener is left registered
    (#12).
    With FlatLaf user scaling on, UIScale registers a listener on all three
    defaults tables that is still there after the stock theme is back, reacting to
    another look and feel's font changes. The module's only defence is one
    ordering-sensitive line setting flatlaf.uiScale.enabled=false before FlatLaf
    loads, and nothing guarded it. Measured both ways: as shipped no such listener
    appears anywhere; flip the property and all three tables carry one after a
    restore.

  • A headless look-and-feel harness (./gradlew :designer:lafHarness,
    #32).
    It drives the real switch sequence against the real Synthetica, JIDE and
    FlatLaf jars — no gateway, no Designer, no screenshots — and diffs every
    resolvable UIManager default across a light→dark→light cycle. The unit
    tests only ever saw stub look and feels, so every bug this module has had
    (#14, #17, #19, #22, #23) had to be found by deploying and looking. Four
    invariants are now pinned instead: a full cycle restores every default, the
    FlatLaf overrides are cleared while FlatLaf is still installed (the ordering
    #23 got wrong), repeated cycles converge, and JIDE's Theme.painter map
    comes back to its stock entries, the standard Swing colours actually go dark,
    and no UIManager key naming a background stays light under dark mode —
    which is #22
    turned from a manual dump into an assertion over 174 keys. It runs in CI.

    Its blind spots are mapped and documented rather than assumed: state outside
    UIManager (the IA colour tokens, the Synthetica singleton) is invisible to
    it, the dark half is weakly covered because JIDE derives dark colours
    correctly with no Designer present, and it cannot see pixels. A Designer
    still settles "does this look right".

  • A partly-applied theme now says so, in the Designer's status bar: which
    passes failed, out of how many, and where to read the stack traces. Every
    pass after the look-and-feel swap is isolated, so one that fails leaves a
    Designer that works and is visibly wrong somewhere; the only record used to
    be a log file nobody knows to look for.

  • The Designer's status bar stays readable under dark mode. StatusBar .setMessage re-asserts Color.black on the message label on every call, so
    its own messages were black on a dark bar.

  • docs/QA-CHECKLIST.md — a sweep of Designer
    surfaces with a pass/fail per surface, so coverage gaps are found before a
    release rather than reported as bugs
    (#5).
    The surface list is drawn from the catalogue in the MIT-licensed
    Exchange dark-mode script;
    its 8.1 class names have shifted on 8.3, its UI locations have not.

  • LookAndFeelDefaultsTableTest (./gradlew :designer:lafHarness) pins the
    gap between the developer defaults table and the look-and-feel table: 109
    colour keys resolve through UIManager but not through
    getLookAndFeelDefaults() under the stock look and feel, and the restore
    leaves that set exactly as it found it. Ignition code reading a colour
    that way gets null in a stock Designer and a real colour under dark mode,
    which is the opposite of the intuitive direction and has already caused
    one stack trace to be misread.

Changed

  • The headless harness runs against the current Ignition, not the support
    floor
    (#53).
    sdk_version stays at 8.3.0 — it is what the module compiles against and what
    module.xml claims as the minimum — but the harness now resolves
    harness_sdk_version (8.3.8 by default, -Pharness.sdk=8.3.6 to pin). The
    module reaches Ignition and JIDE internals by name, and none of that is
    compile-checked, so testing it against jars nobody runs was the weakest part
    of the setup. The full suite passes against 8.3.8.

  • Inline tip banners are readable under dark mode again
    (#47).
    InlineTipLabel.paintComponent fills with a literal #D6E4ED, so no
    look-and-feel swap reaches it — while its text is IA's Base900 token, which
    this module lightens. The result was light-on-pale: not merely wrong but
    illegible, in eleven places including Help → Diagnostics, the permissions
    configurator and the UDT multi-instance wizard. The fill now darkens with the
    other class constants and restores with them.

  • SQL and expression editors are themed
    (#48).
    "The script editor" is two components: the Python editors are
    RSyntaxTextArea and were already covered, while JIDE's CodeEditor — the
    Database Query Browser and every expression editor in the Designer, 46
    classes' worth — was not. Under dark mode it kept a cream #FFFFD7 band
    across the current line, a black caret on dark chrome, and syntax tokens
    at #000000, #000080, #650099. A new CodeEditorTheme lifts each syntax
    colour to a readable luminance while keeping its hue, so a keyword still reads
    as a keyword, and restores every value on the way back to light.

  • The Tag Browser's Value header and the Perspective property editor's
    filter now come back when dark mode is switched off

    (#45). Two different
    mechanisms, both invisible to the defaults diff — every UIManager key was
    already coming back correct.

    The header is painted by a cell renderer, which is not in the component
    hierarchy. JTableHeader.updateUI() reaches its default renderer anyway, but
    only while that renderer is a Component: on the way into dark mode it is, so
    Swing calls DefaultTableCellRenderer.updateUI() — literally super.updateUI(); setForeground(null); setBackground(null); — and destroys the colours
    SimpleTreeTable$SimpleHeaderRenderer sets in its constructor and never sets
    again. On the way back the renderer is wrapped in ours, which is not a
    Component, so Swing skips it and the header keeps null colours and a FlatLaf
    delegate for the rest of the session. The colours are now snapshotted before
    the switch can wipe them, and the delegate is put back explicitly.

    The filter is JIDE's LabeledTextField, whose updateUI() ends in
    setEnabled(), which does setBackground(getTextField().getBackground()).
    updateComponentTreeUI walks parent first, so on the restore the wrapper
    copies the inner field's still-dark #46494B onto itself a moment before that
    field goes light. A second pass now re-runs updateUI() child-first on
    anything left holding a dark UIResource background.

    Measured on the real components: a light→dark→light cycle over a
    SimpleTreeTable and a QuickFilterField rendered 15,462 pixels different
    from stock before the fix and 0 after.

  • The tree-update diagnostic now reports null backgrounds and foregrounds,
    not only fonts. It was written against the description in
    #12,
    which named a Font.getFamily() NPE. The failure actually caught in the wild
    was Color.getAlpha() on a null background, so the instrument was looking at
    the wrong property and would have reported no font at all: 0 while saying
    nothing about the cause. Its UIManager s...

Read more

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 27 Aug 23:12
605fc44

What's Changed

  • Darken JIDE toolbar button states by @sdonche in #10
  • Theme the code editors; isolate window updates on restore by @sdonche in #11
  • Recolour console output styles for dark mode by @sdonche in #13
  • Repoint ThemePainter references JIDE cached before the switch by @sdonche in #16
  • Measure startup readiness in dock frames, not trees by @sdonche in #18
  • Darken borders drawn in the Base000 token; widen the inspector by @sdonche in #20
  • Darken JIDE defaults that stayed light; add a light-defaults diagnostic by @sdonche in #22
  • Re-assert the JIDE painter map on every rescan by @sdonche in #19
  • Retake the screenshots against the current build by @sdonche in #24
  • Assert design tokens restore to their exact stock value by @sdonche in #25
  • Reconcile the docs with what the code actually does by @sdonche in #26
  • Drop the DCO requirement rather than leave it unenforced by @sdonche in #28
  • fix: clear the UIManager overrides before the light restore (#23) by @sdonche in #27
  • docs: cut the 0.1.0 changelog section by @sdonche in #30

New Contributors

Full Changelog: https://github.com/Mustry-Solutions/ignition-designer-dark-mode-module/commits/v0.1.0