4242import java .awt .event .WindowAdapter ;
4343import java .awt .event .WindowEvent ;
4444import java .awt .font .GlyphVector ;
45+ import java .awt .geom .Rectangle2D ;
4546import java .awt .image .VolatileImage ;
4647import java .io .File ;
4748import java .io .FileInputStream ;
@@ -164,8 +165,11 @@ public class MegaMekGUI implements IPreferenceChangeListener {
164165 /** Family name of the spray-paint font the splash tag is drawn in. Ships in mm-data under data/fonts. */
165166 private static final String SPRAY_PAINT_FONT_FAMILY = "Rubik Spray Paint" ;
166167
167- /** Colour of the sprayed splash tag: a strong red, left see-through enough that the logo shows through it. */
168- private static final Color SPLASH_TAG_COLOR = new Color (198 , 26 , 26 , 232 );
168+ /** Colour the splash tag is sprayed in when it does not name one: a strong red. */
169+ private static final Color SPLASH_TAG_DEFAULT_COLOR = new Color (198 , 26 , 26 );
170+
171+ /** How solid the sprayed tag is, out of 255. Short of opaque, so the logo shows through the paint. */
172+ private static final int SPLASH_TAG_ALPHA = 232 ;
169173
170174 /** Colour outlining the sprayed tag, which lifts the red clear of the light wordmark underneath it. */
171175 private static final Color SPLASH_TAG_OUTLINE_COLOR = new Color (0 , 0 , 0 , 225 );
@@ -176,9 +180,6 @@ public class MegaMekGUI implements IPreferenceChangeListener {
176180 */
177181 private static final double SPLASH_TAG_OUTLINE_WIDTH_FRACTION = 0.085 ;
178182
179- /** How far off level the sprayed tag sits, in degrees, so it does not read as a tidy interface caption. */
180- private static final double SPLASH_TAG_TILT_DEGREES = -2.5 ;
181-
182183 /** Fraction of the logo's width the sprayed tag spans, leaving it a little narrower than the logo itself. */
183184 private static final double SPLASH_TAG_WIDTH_FRACTION_OF_LOGO = 0.92 ;
184185
@@ -218,6 +219,8 @@ public class MegaMekGUI implements IPreferenceChangeListener {
218219 private ManagedVolatileImage medalImage ;
219220 /** Font the splash tag is sprayed in, or {@code null} when this build has no tag to spray. */
220221 private Font splashTagFont ;
222+ /** Colour the splash tag is sprayed in, worked out once when the menu is built. */
223+ private Color splashTagColor = SPLASH_TAG_DEFAULT_COLOR ;
221224 private TipOfTheDay tipOfTheDay ;
222225 private AbstractRandomArmyDialog randomArmyDialog ;
223226 private NetworkInformationDialog networkInformationDialog ;
@@ -435,6 +438,7 @@ private void showMainMenu() {
435438 logoImage = new ManagedVolatileImage (getImage (FILENAME_LOGO ), Transparency .TRANSLUCENT );
436439 medalImage = new ManagedVolatileImage (getImage (FILENAME_MEDAL ), Transparency .TRANSLUCENT );
437440 splashTagFont = loadSplashTagFont ();
441+ splashTagColor = resolveSplashTagColor ();
438442 Dimension splashPanelPreferredSize = calculateSplashPanelPreferredSize (scaledMonitorSize , splashImage );
439443 // This is an empty panel that will contain the splash image
440444 // Draw background, border, and children first
@@ -540,7 +544,7 @@ private void showMainMenu() {
540544 * is why {@code Version.properties} asks for a short one.</p>
541545 *
542546 * @param graphics the graphics context the tag will be painted with, used to measure the lettering
543- * @param panelWidth the width in pixels of the splash artwork
547+ * @param logoBounds the area the logo occupies, which the tag is sized against
544548 *
545549 * @return the font to spray the tag in, already at the right size, or {@code null} when this build has no tag
546550 */
@@ -551,11 +555,14 @@ private void showMainMenu() {
551555
552556 String splashTag = Version .getSplashTag ();
553557
554- // Measure at a reference size and scale from there, which is one measurement instead of a search.
558+ // Measure at a reference size and scale from there, which is one measurement instead of a search. The
559+ // measurement is of the painted lettering itself rather than of the font's ascent and descent, because
560+ // those describe what the font could draw rather than what this particular tag does draw.
555561 Font referenceFont = splashTagFont .deriveFont (SPLASH_TAG_REFERENCE_FONT_SIZE );
556- FontMetrics referenceMetrics = graphics .getFontMetrics (referenceFont );
557- int referenceWidth = referenceMetrics .stringWidth (splashTag );
558- int referenceHeight = referenceMetrics .getAscent () - referenceMetrics .getDescent ();
562+ Rectangle2D referenceInk = referenceFont .createGlyphVector (graphics .getFontRenderContext (), splashTag )
563+ .getVisualBounds ();
564+ double referenceWidth = referenceInk .getWidth ();
565+ double referenceHeight = referenceInk .getHeight ();
559566 if ((referenceWidth <= 0 ) || (referenceHeight <= 0 )) {
560567 return null ;
561568 }
@@ -597,28 +604,30 @@ private void drawSplashTag(Graphics2D graphics, @Nullable Rectangle logoBounds)
597604 }
598605
599606 String splashTag = Version .getSplashTag ();
600- FontMetrics tagMetrics = graphics .getFontMetrics (sizedSplashTagFont );
601- int tagWidth = tagMetrics .stringWidth (splashTag );
602-
603- // Centred across the logo, and down it at the height the wordmark sits at
604- int tagX = logoBounds .x + ((logoBounds .width - tagWidth ) / 2 );
605- int lettersHeight = tagMetrics .getAscent () - tagMetrics .getDescent ();
606- int wordmarkCentreY = logoBounds .y + (int ) (logoBounds .height * LOGO_WORDMARK_CENTRE_FRACTION );
607- int tagY = wordmarkCentreY + (lettersHeight / 2 );
608607
609608 Graphics2D tagGraphics = (Graphics2D ) graphics .create ();
610609 try {
611610 tagGraphics .setRenderingHint (RenderingHints .KEY_ANTIALIASING , RenderingHints .VALUE_ANTIALIAS_ON );
612611 tagGraphics .setRenderingHint (RenderingHints .KEY_TEXT_ANTIALIASING ,
613612 RenderingHints .VALUE_TEXT_ANTIALIAS_ON );
614- tagGraphics .rotate (Math .toRadians (SPLASH_TAG_TILT_DEGREES ),
615- tagX + (tagWidth / 2.0 ),
616- tagY - (tagMetrics .getAscent () / 2.0 ));
617613
618- // The lettering is outlined in black and then filled in red, rather than simply drawn, so that it
619- // stands clear of the pale wordmark it is sprayed across .
614+ // Measure the painted lettering, so that centring it uses where the paint actually lands rather than
615+ // where the font says its tallest and lowest characters could reach .
620616 GlyphVector tagGlyphs = sizedSplashTagFont .createGlyphVector (tagGraphics .getFontRenderContext (),
621617 splashTag );
618+ Rectangle2D tagInk = tagGlyphs .getVisualBounds ();
619+
620+ // Centred across the logo, and down it at the height the wordmark sits at
621+ int tagX = logoBounds .x + (int ) ((logoBounds .width - tagInk .getWidth ()) / 2 - tagInk .getX ());
622+ int wordmarkCentreY = logoBounds .y + (int ) (logoBounds .height * LOGO_WORDMARK_CENTRE_FRACTION );
623+ int tagY = wordmarkCentreY - (int ) (tagInk .getY () + (tagInk .getHeight () / 2 ));
624+
625+ tagGraphics .rotate (Math .toRadians (Version .getSplashTagRotation ()),
626+ tagX + tagInk .getCenterX (),
627+ wordmarkCentreY );
628+
629+ // The lettering is outlined and then filled, rather than simply drawn, so that it stands clear of the
630+ // pale wordmark it is sprayed across.
622631 Shape tagOutline = tagGlyphs .getOutline (tagX , tagY );
623632
624633 float outlineWidth = (float ) Math .max (1.0 ,
@@ -627,13 +636,40 @@ private void drawSplashTag(Graphics2D graphics, @Nullable Rectangle logoBounds)
627636 tagGraphics .setColor (SPLASH_TAG_OUTLINE_COLOR );
628637 tagGraphics .draw (tagOutline );
629638
630- tagGraphics .setColor (SPLASH_TAG_COLOR );
639+ tagGraphics .setColor (splashTagColor );
631640 tagGraphics .fill (tagOutline );
632641 } finally {
633642 tagGraphics .dispose ();
634643 }
635644 }
636645
646+ /**
647+ * Works out what colour to spray the splash tag in, the same way the build note's colour is chosen: by the
648+ * plain colour name written in {@code Version.properties}.
649+ *
650+ * <p>A tag that names no colour, or names one that is not recognised, is sprayed in red. Whichever colour is
651+ * used is left slightly see-through so the logo shows through the paint.</p>
652+ *
653+ * @return the colour to spray the tag in, never {@code null}
654+ */
655+ private static Color resolveSplashTagColor () {
656+ String configuredColorName = Version .getSplashTagColorName ();
657+ if (configuredColorName == null ) {
658+ LOGGER .debug ("[SplashTag] No splashTagColor set - the tag is sprayed in red" );
659+ return UIUtil .addAlpha (SPLASH_TAG_DEFAULT_COLOR , SPLASH_TAG_ALPHA );
660+ }
661+
662+ Color namedColor = colorForName (configuredColorName );
663+ if (namedColor == null ) {
664+ LOGGER .warn ("[SplashTag] Version.properties sets splashTagColor to '{}', which is not a colour name "
665+ + "MegaMek knows. The tag will be sprayed in red instead." , configuredColorName );
666+ return UIUtil .addAlpha (SPLASH_TAG_DEFAULT_COLOR , SPLASH_TAG_ALPHA );
667+ }
668+
669+ LOGGER .debug ("[SplashTag] Splash tag colour set to {}" , configuredColorName );
670+ return UIUtil .addAlpha (namedColor , SPLASH_TAG_ALPHA );
671+ }
672+
637673 /**
638674 * Loads the font the splash tag is sprayed in, once, when the menu is built.
639675 *
0 commit comments