fix(splash): skip runtime title/version draw and use mantle background #179

Merged
forbes merged 2 commits from feat/editing-context-system into main 2026-02-12 16:11:10 +00:00
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('#')
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
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,13 +383,16 @@ QPixmap SplashScreen::splashImage()
QColor color(QString::fromStdString(tc->second));
if (color.isValid()) {
painter.setPen(color);
painter.setFont(fontExe);
if (title != QLatin1String("FreeCAD")) {
// FreeCAD's Splashscreen already contains the EXE name, no need to draw it
painter.drawText(x, y, title);
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
painter.drawText(x, y, title);
}
painter.setFont(fontVer);
painter.drawText(x + (l + 235), y - 7, version);
}
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);