fix(splash): skip runtime title/version draw and use mantle background
Some checks failed
Build and Test / build (pull_request) Failing after 19m15s

The splash PNG already has the title and version baked in by
generate-splash.py, but SplashScreen::splashImage() was drawing them
again at position (6,75) which fell outside the rounded background
rectangle (starts at 30,30). Skip runtime text rendering for Kindred
Create while keeping the dev build warning.

Also switch the splash background from Catppuccin Mocha base (#1e1e2e)
to mantle (#181825) for a darker appearance and regenerate assets.
This commit is contained in:
2026-02-12 10:08:23 -06:00
parent 70118201b0
commit f71decca08
4 changed files with 69 additions and 52 deletions

View File

@@ -34,53 +34,67 @@ except ImportError:
# Catppuccin Mocha colors
COLORS = {
'base': '#1e1e2e',
'surface0': '#313244',
'text': '#cdd6f4',
'subtext0': '#a6adc8',
'blue': '#89b4fa',
'lavender': '#b4befe',
"mantle": "#181825",
"base": "#1e1e2e",
"surface0": "#313244",
"text": "#cdd6f4",
"subtext0": "#a6adc8",
"blue": "#89b4fa",
"lavender": "#b4befe",
}
def hex_to_rgb(hex_color):
"""Convert hex color to RGB tuple."""
hex_color = hex_color.lstrip('#')
hex_color = hex_color.lstrip("#")
return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
def create_rounded_rectangle(draw, bbox, radius, fill):
"""Draw a rounded rectangle."""
x1, y1, x2, y2 = bbox
draw.rounded_rectangle(bbox, radius=radius, fill=fill)
def load_svg_as_image(svg_path, width, height):
"""Load an SVG file and convert to PIL Image at specified size."""
if cairosvg:
import io
png_data = cairosvg.svg2png(url=str(svg_path), output_width=width, output_height=height)
return Image.open(io.BytesIO(png_data)).convert('RGBA')
return Image.open(io.BytesIO(png_data)).convert("RGBA")
else:
# Fallback: try using inkscape command line
import subprocess
import tempfile
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
tmp_path = tmp.name
try:
subprocess.run([
'inkscape', '-w', str(width), '-h', str(height),
str(svg_path), '-o', tmp_path
], check=True, capture_output=True)
img = Image.open(tmp_path).convert('RGBA')
subprocess.run(
["inkscape", "-w", str(width), "-h", str(height), str(svg_path), "-o", tmp_path],
check=True,
capture_output=True,
)
img = Image.open(tmp_path).convert("RGBA")
return img
finally:
if os.path.exists(tmp_path):
os.unlink(tmp_path)
def get_font(size, bold=False):
"""Get a font, falling back to default if not available."""
font_names = [
'/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf' if bold else '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
'/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf' if bold else '/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf',
'/usr/share/fonts/TTF/DejaVuSans-Bold.ttf' if bold else '/usr/share/fonts/TTF/DejaVuSans.ttf',
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
if bold
else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf"
if bold
else "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
"/usr/share/fonts/TTF/DejaVuSans-Bold.ttf"
if bold
else "/usr/share/fonts/TTF/DejaVuSans.ttf",
]
for font_name in font_names:
if os.path.exists(font_name):
@@ -88,6 +102,7 @@ def get_font(size, bold=False):
# Fallback to default
return ImageFont.load_default()
def create_splash(output_path, logo_path, width, height, version, freecad_version, scale=1):
"""Create a splash screen image."""
# Scale dimensions
@@ -97,11 +112,11 @@ def create_splash(output_path, logo_path, width, height, version, freecad_versio
padding = int(30 * scale)
# Create image with transparent background
img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
img = Image.new("RGBA", (w, h), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Draw rounded rectangle background
bg_color = hex_to_rgb(COLORS['base'])
bg_color = hex_to_rgb(COLORS["mantle"])
create_rounded_rectangle(draw, (padding, padding, w - padding, h - padding), radius, bg_color)
# Load and place logo
@@ -125,7 +140,7 @@ def create_splash(output_path, logo_path, width, height, version, freecad_versio
title_width = title_bbox[2] - title_bbox[0]
title_x = (w - title_width) // 2
title_y = int(250 * scale)
draw.text((title_x, title_y), title, fill=hex_to_rgb(COLORS['text']), font=title_font)
draw.text((title_x, title_y), title, fill=hex_to_rgb(COLORS["text"]), font=title_font)
# Draw version string
version_font = get_font(int(12 * scale))
@@ -134,12 +149,15 @@ def create_splash(output_path, logo_path, width, height, version, freecad_versio
version_width = version_bbox[2] - version_bbox[0]
version_x = (w - version_width) // 2
version_y = title_y + int(35 * scale)
draw.text((version_x, version_y), version_str, fill=hex_to_rgb(COLORS['subtext0']), font=version_font)
draw.text(
(version_x, version_y), version_str, fill=hex_to_rgb(COLORS["subtext0"]), font=version_font
)
# Save
img.save(output_path, 'PNG')
img.save(output_path, "PNG")
print(f"Created: {output_path}")
def create_about(output_path, logo_path, width, height, scale=1):
"""Create an about dialog image."""
# Scale dimensions
@@ -147,7 +165,7 @@ def create_about(output_path, logo_path, width, height, scale=1):
h = int(height * scale)
# Create image
img = Image.new('RGBA', (w, h), hex_to_rgb(COLORS['base']) + (255,))
img = Image.new("RGBA", (w, h), hex_to_rgb(COLORS["base"]) + (255,))
draw = ImageDraw.Draw(img)
# Load and place logo
@@ -163,18 +181,19 @@ def create_about(output_path, logo_path, width, height, scale=1):
print(f"Warning: Could not load logo: {e}")
# Save
img.save(output_path, 'PNG')
img.save(output_path, "PNG")
print(f"Created: {output_path}")
def main():
parser = argparse.ArgumentParser(description='Generate Kindred Create splash screens')
parser.add_argument('--version', default='0.1.0', help='Kindred Create version')
parser.add_argument('--freecad-version', default='1.0.0', help='FreeCAD version')
parser = argparse.ArgumentParser(description="Generate Kindred Create splash screens")
parser.add_argument("--version", default="0.1.0", help="Kindred Create version")
parser.add_argument("--freecad-version", default="1.0.0", help="FreeCAD version")
args = parser.parse_args()
script_dir = Path(__file__).parent
logo_path = script_dir / 'kindred-logo.svg'
icons_dir = script_dir.parent.parent / 'src' / 'Gui' / 'Icons'
logo_path = script_dir / "kindred-logo.svg"
icons_dir = script_dir.parent.parent / "src" / "Gui" / "Icons"
if not logo_path.exists():
print(f"Error: Logo not found at {logo_path}")
@@ -182,33 +201,31 @@ def main():
# Create splash screens (600x400 as per spec)
create_splash(
icons_dir / 'kindredcreatesplash.png',
icons_dir / "kindredcreatesplash.png",
logo_path,
600, 400,
600,
400,
args.version,
args.freecad_version,
scale=1
scale=1,
)
# Create 2x version for HiDPI
create_splash(
icons_dir / 'kindredcreatesplash_2x.png',
icons_dir / "kindredcreatesplash_2x.png",
logo_path,
600, 400,
600,
400,
args.version,
args.freecad_version,
scale=2
scale=2,
)
# Create about image
create_about(
icons_dir / 'kindredcreateabout.png',
logo_path,
400, 200,
scale=1
)
create_about(icons_dir / "kindredcreateabout.png", logo_path, 400, 200, scale=1)
print("\nSplash screen generation complete!")
if __name__ == '__main__':
if __name__ == "__main__":
main()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -360,9 +360,6 @@ QPixmap SplashScreen::splashImage()
fontExe.setPointSizeF(20.0);
QFontMetrics metricExe(fontExe);
int l = QtTools::horizontalAdvance(metricExe, title);
if (title == QLatin1String("Kindred Create")) {
// For Kindred Create splash, we draw the title as part of the dynamic rendering
}
int w = splash_image.width();
int h = splash_image.height();
@@ -386,6 +383,8 @@ QPixmap SplashScreen::splashImage()
QColor color(QString::fromStdString(tc->second));
if (color.isValid()) {
painter.setPen(color);
if (title != QLatin1String("Kindred Create")) {
// Kindred Create's splash PNG already contains the title and version
painter.setFont(fontExe);
if (title != QLatin1String("FreeCAD")) {
// FreeCAD's Splashscreen already contains the EXE name, no need to draw it
@@ -393,6 +392,7 @@ QPixmap SplashScreen::splashImage()
}
painter.setFont(fontVer);
painter.drawText(x + (l + 235), y - 7, version);
}
QColor warningColor(QString::fromStdString(wc->second));
if (suffix == QLatin1String("dev") && warningColor.isValid()) {
fontVer.setPointSizeF(14.0);