summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2025-06-01 13:27:50 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2025-06-01 13:27:50 (GMT)
commit07333983ff99b22994a79c8a7cbf4fad0b80158f (patch)
treeea38a27b114212b662f31feadfe2db1347a53148
parentbde358e3a0b8333fd796c89a3be998d8ad5b1826 (diff)
Build a static image for the About dialog box background.gtk4
-rw-r--r--.gitignore5
-rw-r--r--configure.ac2
-rw-r--r--pixmaps/Makefile.am18
-rw-r--r--pixmaps/chrysalide-full.pngbin28830 -> 0 bytes
-rw-r--r--pixmaps/chrysalide_text.pngbin11432 -> 0 bytes
-rw-r--r--pixmaps/revision.pngbin601 -> 0 bytes
-rw-r--r--pixmaps/revision_0.pngbin760 -> 0 bytes
-rw-r--r--pixmaps/revision_1.pngbin545 -> 0 bytes
-rw-r--r--pixmaps/revision_2.pngbin727 -> 0 bytes
-rw-r--r--pixmaps/revision_3.pngbin719 -> 0 bytes
-rw-r--r--pixmaps/revision_4.pngbin691 -> 0 bytes
-rw-r--r--pixmaps/revision_5.pngbin746 -> 0 bytes
-rw-r--r--pixmaps/revision_6.pngbin775 -> 0 bytes
-rw-r--r--pixmaps/revision_7.pngbin585 -> 0 bytes
-rw-r--r--pixmaps/revision_8.pngbin802 -> 0 bytes
-rw-r--r--pixmaps/revision_9.pngbin791 -> 0 bytes
-rw-r--r--src/data/images/Makefile.am1
-rw-r--r--src/data/images/gresource.xml3
-rw-r--r--src/gui/dialogs/Makefile.am2
-rw-r--r--src/gui/dialogs/about-int.h14
-rw-r--r--src/gui/dialogs/about.c57
-rw-r--r--src/gui/dialogs/about.css9
-rw-r--r--src/gui/dialogs/about.ui80
-rw-r--r--src/gui/dialogs/gresource.xml16
-rw-r--r--src/gui/style.css6
-rw-r--r--tools/about/build.py120
-rw-r--r--tools/about/courier-10-pitch-bold_EQ97V.zipbin0 -> 21114 bytes
-rw-r--r--tools/about/courier10point.zipbin0 -> 61784 bytes
-rwxr-xr-xtools/about/gen.sh52
-rw-r--r--tools/about/logo.pngbin0 -> 633982 bytes
-rw-r--r--tools/about/noise.pngbin0 -> 136944 bytes
-rw-r--r--tools/about/ttf.py111
32 files changed, 322 insertions, 174 deletions
diff --git a/.gitignore b/.gitignore
index bb8db02..ae3f2cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,9 @@ tools/d2c/d2c
tools/fuzzing/rost/fast-rost
tools/yara2rost/yara2rost
+# Images générées
+src/data/images/about-bg.png
+
# Schemas
src/schemas/gschemas.compiled
src/schemas/*.valid
@@ -84,6 +87,8 @@ src/schemas/*.valid
# Misc
plugins/python/androperms/androperms.db
system/pkgconfig/chrysalide.pc
+tools/about/bg.png
+tools/about/cour10p_b.ttf
tools/fuzzing/rost/rost.dict
# Themes
diff --git a/configure.ac b/configure.ac
index 693e9f8..8429ae6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -744,6 +744,8 @@ AC_CONFIG_FILES([stamp-h po/Makefile.in], [echo timestamp > stamp-h])
AC_CONFIG_COMMANDS([marshal], [echo -e "VOID:UINT64\nVOID:INT,UINT64,INT\nVOID:OBJECT,OBJECT\nVOID:ENUM,OBJECT\nVOID:ENUM,ENUM\nVOID:BOOLEAN,UINT64\nVOID:BOOLEAN,ULONG,ULONG\nVOID:INT,INT\nVOID:OBJECT,BOOLEAN\nVOID:ULONG,BOOLEAN\nVOID:DOUBLE,DOUBLE" > src/glibext/chrysamarshal.list])
+AC_CONFIG_COMMANDS([about], [./tools/about/gen.sh $version], [version=r$PACKAGE_VERSION])
+
AC_CONFIG_FILES([Makefile
doc/Makefile
pixmaps/Makefile
diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am
index d1dff31..da3de19 100644
--- a/pixmaps/Makefile.am
+++ b/pixmaps/Makefile.am
@@ -4,19 +4,6 @@ APP_ICONS = \
chrysalide-64.png \
chrysalide-128.png
-REVISION_PIX = \
- revision_0.png \
- revision_1.png \
- revision_2.png \
- revision_3.png \
- revision_4.png \
- revision_5.png \
- revision_6.png \
- revision_7.png \
- revision_8.png \
- revision_9.png \
- revision.png
-
TOOLBAR_BUTTONS = \
tbutton_collapse.png \
tbutton_expand.png \
@@ -41,8 +28,6 @@ OTHER_ICONS = \
breakpoint_normal.png
MISC = \
- chrysalide-full.png \
- chrysalide_text.png \
welcome.png
CORE = \
@@ -57,13 +42,12 @@ EXTRA_DIST = \
openida_text.xcf \
before-after.png \
$(APP_ICONS) \
- $(REVISION_PIX) \
$(TOOLBAR_BUTTONS) \
$(LIST_ICONS) \
$(ERROR_ICONS) \
$(MISC) \
$(CORE)
-pix_DATA = $(APP_ICONS) $(REVISION_PIX) $(TOOLBAR_BUTTONS) $(LIST_ICONS) $(ERROR_ICONS) $(OTHER_ICONS) $(MISC)
+pix_DATA = $(APP_ICONS) $(TOOLBAR_BUTTONS) $(LIST_ICONS) $(ERROR_ICONS) $(OTHER_ICONS) $(MISC)
pixdir = $(pixmapsdir)
diff --git a/pixmaps/chrysalide-full.png b/pixmaps/chrysalide-full.png
deleted file mode 100644
index a153353..0000000
--- a/pixmaps/chrysalide-full.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/chrysalide_text.png b/pixmaps/chrysalide_text.png
deleted file mode 100644
index b4d8c78..0000000
--- a/pixmaps/chrysalide_text.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision.png b/pixmaps/revision.png
deleted file mode 100644
index 330e108..0000000
--- a/pixmaps/revision.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_0.png b/pixmaps/revision_0.png
deleted file mode 100644
index 0a468de..0000000
--- a/pixmaps/revision_0.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_1.png b/pixmaps/revision_1.png
deleted file mode 100644
index 738a881..0000000
--- a/pixmaps/revision_1.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_2.png b/pixmaps/revision_2.png
deleted file mode 100644
index b567b80..0000000
--- a/pixmaps/revision_2.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_3.png b/pixmaps/revision_3.png
deleted file mode 100644
index 7f5e3fc..0000000
--- a/pixmaps/revision_3.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_4.png b/pixmaps/revision_4.png
deleted file mode 100644
index a21ccbb..0000000
--- a/pixmaps/revision_4.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_5.png b/pixmaps/revision_5.png
deleted file mode 100644
index a9130d9..0000000
--- a/pixmaps/revision_5.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_6.png b/pixmaps/revision_6.png
deleted file mode 100644
index 291febd..0000000
--- a/pixmaps/revision_6.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_7.png b/pixmaps/revision_7.png
deleted file mode 100644
index ccd4d4e..0000000
--- a/pixmaps/revision_7.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_8.png b/pixmaps/revision_8.png
deleted file mode 100644
index 054c250..0000000
--- a/pixmaps/revision_8.png
+++ /dev/null
Binary files differ
diff --git a/pixmaps/revision_9.png b/pixmaps/revision_9.png
deleted file mode 100644
index 1123669..0000000
--- a/pixmaps/revision_9.png
+++ /dev/null
Binary files differ
diff --git a/src/data/images/Makefile.am b/src/data/images/Makefile.am
index 068e43f..d5ec84f 100644
--- a/src/data/images/Makefile.am
+++ b/src/data/images/Makefile.am
@@ -4,6 +4,7 @@ BUILT_SOURCES = resources.h resources.c
noinst_LTLIBRARIES = libdataimages.la
RES_FILES = \
+ about-bg.png \
dock-station-left-symbolic.svg \
dock-station-right-symbolic.svg \
dock-station-bottom-symbolic.svg \
diff --git a/src/data/images/gresource.xml b/src/data/images/gresource.xml
index 7659da3..25c8274 100644
--- a/src/data/images/gresource.xml
+++ b/src/data/images/gresource.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
+ <gresource prefix="/re/chrysalide/framework/gui/dialogs/about">
+ <file compressed="true" alias="bg.png">about-bg.png</file>
+ </gresource>
<gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions">
<file compressed="true">dock-station-left-symbolic.svg</file>
<file compressed="true">dock-station-right-symbolic.svg</file>
diff --git a/src/gui/dialogs/Makefile.am b/src/gui/dialogs/Makefile.am
index e910c96..3492f63 100644
--- a/src/gui/dialogs/Makefile.am
+++ b/src/gui/dialogs/Makefile.am
@@ -3,7 +3,9 @@ BUILT_SOURCES = resources.h resources.c
noinst_LTLIBRARIES = libguidialogs.la
+
UI_FILES = \
+ about.css \
about.ui \
preferences.ui
# bookmark.ui \
diff --git a/src/gui/dialogs/about-int.h b/src/gui/dialogs/about-int.h
index 616c73f..96a470e 100644
--- a/src/gui/dialogs/about-int.h
+++ b/src/gui/dialogs/about-int.h
@@ -37,20 +37,6 @@ struct _GtkAppAboutDialog
{
GtkWindow parent; /* A laisser en premier */
- union
- {
- struct
- {
- GtkPicture *revision_0; /* Numéro #0 */
- GtkPicture *revision_1; /* Numéro #1 */
- GtkPicture *revision_2; /* Numéro #2 */
- GtkPicture *revision_3; /* Numéro #3 */
- GtkPicture *revision_4; /* Numéro #4 */
- GtkPicture *revision_5; /* Numéro #5 */
- };
- GtkPicture *revisions[6]; /* Tous les numéros d'un coup */
- };
-
};
/* Boîte "A propos de" dédiée à l'application (classe) */
diff --git a/src/gui/dialogs/about.c b/src/gui/dialogs/about.c
index 956918b..1dca752 100644
--- a/src/gui/dialogs/about.c
+++ b/src/gui/dialogs/about.c
@@ -44,10 +44,10 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *);
static void gtk_app_about_dialog_init(GtkAppAboutDialog *);
/* Supprime toutes les références externes. */
-static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *);
+static void gtk_app_about_dialog_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_app_about_dialog_finalize(GtkAppAboutDialog *);
+static void gtk_app_about_dialog_finalize(GObject *);
@@ -74,22 +74,17 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *class)
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_app_about_dialog_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_app_about_dialog_finalize;
+ object->dispose = gtk_app_about_dialog_dispose;
+ object->finalize = gtk_app_about_dialog_finalize;
widget = GTK_WIDGET_CLASS(class);
+ gtk_widget_class_set_css_name(widget, "aboutdialog");
+
gtk_widget_class_add_binding_action(widget, GDK_KEY_Escape, 0, "window.close", NULL);
gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/about.ui");
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_0);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_1);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_2);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_3);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_4);
- gtk_widget_class_bind_template_child(widget, GtkAppAboutDialog, revision_5);
-
}
@@ -107,40 +102,14 @@ static void gtk_app_about_dialog_class_init(GtkAppAboutDialogClass *class)
static void gtk_app_about_dialog_init(GtkAppAboutDialog *dialog)
{
- unsigned int revision; /* Numéro de révision */
- unsigned int max; /* Nbre. de boucles à effectuer*/
- unsigned int i; /* Boucle de parcours */
- unsigned int level; /* Unité la plus importante */
- char buffer[64]; /* Nom d'image à forger */
-
gtk_widget_init_template(GTK_WIDGET(dialog));
- revision = REVISION;
- max = log(revision) / log(10);
-
- assert(max <= 6);
-
- for (i = 0; i <= max; i++)
- {
- level = pow(10, max - i);
-
- snprintf(buffer, 64, "/org/chrysalide/gui/dialogs/about/revision_%u.png", revision / level);
-
- gtk_picture_set_resource(dialog->revisions[i], buffer);
-
- revision %= level;
-
- }
-
- for (; i < 6; i++)
- gtk_widget_set_visible(GTK_WIDGET(dialog->revisions[i]), FALSE);
-
}
/******************************************************************************
* *
-* Paramètres : dialog = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -150,18 +119,18 @@ static void gtk_app_about_dialog_init(GtkAppAboutDialog *dialog)
* *
******************************************************************************/
-static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *dialog)
+static void gtk_app_about_dialog_dispose(GObject *object)
{
- gtk_widget_dispose_template(GTK_WIDGET(dialog), GTK_TYPE_APP_ABOUT_DIALOG);
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_APP_ABOUT_DIALOG);
- G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->dispose(G_OBJECT(dialog));
+ G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : dialog = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -171,9 +140,9 @@ static void gtk_app_about_dialog_dispose(GtkAppAboutDialog *dialog)
* *
******************************************************************************/
-static void gtk_app_about_dialog_finalize(GtkAppAboutDialog *dialog)
+static void gtk_app_about_dialog_finalize(GObject *object)
{
- G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->finalize(G_OBJECT(dialog));
+ G_OBJECT_CLASS(gtk_app_about_dialog_parent_class)->finalize(object);
}
diff --git a/src/gui/dialogs/about.css b/src/gui/dialogs/about.css
new file mode 100644
index 0000000..af3fa97
--- /dev/null
+++ b/src/gui/dialogs/about.css
@@ -0,0 +1,9 @@
+
+aboutdialog > box {
+
+ background-color: black;
+
+ background-image: url('resource:///re/chrysalide/framework/gui/dialogs/about/bg.png');
+ background-repeat: no-repeat;
+
+}
diff --git a/src/gui/dialogs/about.ui b/src/gui/dialogs/about.ui
index 989e53b..7b519d2 100644
--- a/src/gui/dialogs/about.ui
+++ b/src/gui/dialogs/about.ui
@@ -8,91 +8,13 @@
<property name="modal">true</property>
<property name="resizable">false</property>
- <style>
- <class name="black-bg"/>
- </style>
-
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
- <child>
- <object class="GtkPicture" id="logo">
- <property name="margin-top">10</property>
- <property name="file">resource://org/chrysalide/gui/dialogs/about/chrysalide-full.png</property>
- </object>
- </child>
-
- <!--
- Etage intermédiaire pour ne pas que l'image se voie allouer la largeur entière
- de la fenêtre. Sinon des marges sont placées autour du rendu lors que l'image
- n'est pas étendue pour couvrir cette largeur entière.
- -->
- <child>
- <object class="GtkBox">
- <property name="orientation">horizontal</property>
- <property name="halign">center</property>
- <property name="margin-top">14</property>
- <child>
- <object class="GtkPicture" id="text">
- <property name="width-request">253</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/chrysalide_text.png</property>
- </object>
- </child>
- </object>
- </child>
-
- <child>
- <object class="GtkBox">
- <property name="orientation">horizontal</property>
- <property name="margin-start">149</property>
- <child>
- <object class="GtkPicture" id="revision">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_0">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_1">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_2">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_3">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_4">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- <child>
- <object class="GtkPicture" id="revision_5">
- <property name="width-request">14</property>
- <property name="file">resource:///org/chrysalide/gui/dialogs/about/revision.png</property>
- </object>
- </child>
- </object>
- </child>
<child>
<object class="GtkLabel">
- <property name="margin-top">22</property>
+ <property name="margin-top">368</property>
<property name="margin-bottom">10</property>
<property name="label" translatable="yes">&lt;span fgcolor='white'&gt;Copyright (C) 2008-2025 Cyrille Bagard&lt;/span&gt;</property>
<property name="use-markup">True</property>
diff --git a/src/gui/dialogs/gresource.xml b/src/gui/dialogs/gresource.xml
index 169f440..966d9c8 100644
--- a/src/gui/dialogs/gresource.xml
+++ b/src/gui/dialogs/gresource.xml
@@ -1,22 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/re/chrysalide/framework/gui/dialogs">
+ <file compressed="true">about.css</file>
<file compressed="true">about.ui</file>
<file compressed="true">preferences.ui</file>
</gresource>
- <gresource prefix="/org/chrysalide/gui/dialogs/about">
- <file compressed="true" alias="chrysalide-full.png">../../../pixmaps/chrysalide-full.png</file>
- <file compressed="true" alias="chrysalide_text.png">../../../pixmaps/chrysalide_text.png</file>
- <file compressed="true" alias="revision.png">../../../pixmaps/revision.png</file>
- <file compressed="true" alias="revision_0.png">../../../pixmaps/revision_0.png</file>
- <file compressed="true" alias="revision_1.png">../../../pixmaps/revision_1.png</file>
- <file compressed="true" alias="revision_2.png">../../../pixmaps/revision_2.png</file>
- <file compressed="true" alias="revision_3.png">../../../pixmaps/revision_3.png</file>
- <file compressed="true" alias="revision_4.png">../../../pixmaps/revision_4.png</file>
- <file compressed="true" alias="revision_5.png">../../../pixmaps/revision_5.png</file>
- <file compressed="true" alias="revision_6.png">../../../pixmaps/revision_6.png</file>
- <file compressed="true" alias="revision_7.png">../../../pixmaps/revision_7.png</file>
- <file compressed="true" alias="revision_8.png">../../../pixmaps/revision_8.png</file>
- <file compressed="true" alias="revision_9.png">../../../pixmaps/revision_9.png</file>
- </gresource>
</gresources>
diff --git a/src/gui/style.css b/src/gui/style.css
index e21d931..dce41fa 100644
--- a/src/gui/style.css
+++ b/src/gui/style.css
@@ -36,11 +36,7 @@ list.boxed-list, list.boxed-list > row:last-child {
/* about.css */
-.black-bg {
-
- background-color: black;
-
-}
+@import url('resource:///re/chrysalide/framework/gui/dialogs/about.css');
/* welcome.css */
diff --git a/tools/about/build.py b/tools/about/build.py
new file mode 100644
index 0000000..2267492
--- /dev/null
+++ b/tools/about/build.py
@@ -0,0 +1,120 @@
+
+# apt install libcairo2-dev pkg-config python3-dev
+# pip install pycairo
+
+import cairo
+import math
+import sys
+
+from enum import IntEnum
+
+from ttf import create_cairo_font_face_for_file
+
+
+WIDTH = 350
+HEIGHT = 430
+
+
+def deg2rad(degrees):
+ return degrees * (math.pi / 180)
+
+
+class TextAlignment(IntEnum):
+ LEFT = 1
+ CENTER = 2
+ RIGHT = 3
+
+
+def draw_text(ctx, text, pos, fsize, noise, theta = 0.0, align = TextAlignment.CENTER):
+ """Dessine un texte en respectant des propriétées."""
+
+ ctx.save()
+
+ ctx.set_font_size(fsize)
+
+ fascent, fdescent, fheight, fxadvance, fyadvance = ctx.font_extents()
+ x_off, y_off, tw, th = ctx.text_extents(text)[:4]
+
+ if align == TextAlignment.LEFT:
+ nx = 0
+ elif align == TextAlignment.RIGHT:
+ nx = -tw
+ else:
+ nx = -tw / 2.0
+
+ ny = fheight / 2
+
+ ctx.translate(pos[0], pos[1])
+ ctx.rotate(theta)
+ ctx.translate(nx, ny)
+ ctx.move_to(0,0)
+
+ ctx.text_path(text)
+ ctx.set_source_surface(noise, 0, -fheight)
+ ctx.fill_preserve()
+ ctx.set_source_rgb(1.0, 1.0, 1.0)
+ ctx.set_line_width(1)
+ ctx.stroke()
+
+ ctx.restore()
+
+
+if __name__ == '__main__':
+ """Point d'entrée du script."""
+
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
+
+ cr = cairo.Context(surface)
+
+ face = create_cairo_font_face_for_file('cour10p_b.ttf')
+ cr.set_font_face(face)
+
+ noise = cairo.ImageSurface.create_from_png('noise.png')
+
+ # Type d'édition
+
+ if len(sys.argv) > 2:
+
+ draw_text(cr, sys.argv[2], [ 300, 25 ], 32, noise,
+ theta = deg2rad(270), align = TextAlignment.RIGHT)
+
+ cr.set_source_rgb(0, 0, 0)
+ cr.paint_with_alpha(0.4)
+
+ # Numéro de version
+
+ draw_text(cr, sys.argv[1], [ 149, 10 + 259 + 14 + 42 + 2 ], 23, noise, align=TextAlignment.LEFT)
+
+ cr.set_source_rgb(0, 0, 0)
+ cr.paint_with_alpha(0.5)
+
+ # Logo
+
+ logo = cairo.ImageSurface.create_from_png('logo.png')
+
+ scale_y = 259 / logo.get_height()
+
+ cr.save()
+
+ cr.translate((WIDTH - (logo.get_width() * scale_y)) / 2, 12)
+
+ cr.scale(scale_y, scale_y)
+
+ cr.set_source_surface(logo, 0, 0)
+ cr.paint()
+
+ cr.restore()
+
+ # Titre
+
+ draw_text(cr, 'Chrysalide', [ WIDTH / 2, 10 + 259 + 14 + 4 ], 42, noise)
+
+ # cr.rectangle(265, 30, 10, 10)
+ # cr.set_source_rgb(1, 0, 0)
+ # cr.fill()
+
+ # cr.rectangle(265, 255, 10, 10)
+ # cr.set_source_rgb(1, 0, 0)
+ # cr.fill()
+
+ surface.write_to_png('bg.png')
diff --git a/tools/about/courier-10-pitch-bold_EQ97V.zip b/tools/about/courier-10-pitch-bold_EQ97V.zip
new file mode 100644
index 0000000..0585fe6
--- /dev/null
+++ b/tools/about/courier-10-pitch-bold_EQ97V.zip
Binary files differ
diff --git a/tools/about/courier10point.zip b/tools/about/courier10point.zip
new file mode 100644
index 0000000..82cd0de
--- /dev/null
+++ b/tools/about/courier10point.zip
Binary files differ
diff --git a/tools/about/gen.sh b/tools/about/gen.sh
new file mode 100755
index 0000000..c22ec59
--- /dev/null
+++ b/tools/about/gen.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+
+# Cf. https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script/246128#246128
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+pushd $SCRIPT_DIR > /dev/null
+
+
+# Obtention de la police Courier-10-Pitch-Bold
+# --------------------------------------------
+
+# https://fontsgeek.com/fonts/Courier-10-Pitch-Bold
+# https://fontsgeek.com/terms-and-conditions
+
+# => courier-10-pitch-bold_EQ97V.zip
+
+
+# Courier 10 Pitch font missing after upgrade to 17.04?
+# https://askubuntu.com/questions/914352/courier-10-pitch-font-missing-after-upgrade-to-17-04
+
+# https://groups.google.com/g/trelby/c/CGkpcMBXW9U
+# -> http://www.trelby.org/files/release/font/courier10point.zip
+# --> https://web.archive.org/web/20140326080337/http://www.trelby.org/files/release/font/courier10point.zip
+
+# https://news.ycombinator.com/item?id=18802628
+# -> https://www.trelby.org/assets/courier10point.zip
+
+# => courier10point.zip
+
+if [ ! -f cour10p_b.ttf ]; then
+
+ unzip -p courier10point.zip courier10point/cour10p_b.ttf > cour10p_b.ttf
+
+fi
+
+
+# Construction de l'image de fond
+#--------------------------------
+
+if [ $# -lt 1 -o $# -gt 2 ]; then
+
+ echo "Usage: $0 <version> <edition>"
+ exit 123
+
+fi
+
+python3 ./build.py $*
+
+cp bg.png ../../src/data/images/about-bg.png
+
+popd > /dev/null
diff --git a/tools/about/logo.png b/tools/about/logo.png
new file mode 100644
index 0000000..9bf9969
--- /dev/null
+++ b/tools/about/logo.png
Binary files differ
diff --git a/tools/about/noise.png b/tools/about/noise.png
new file mode 100644
index 0000000..b5d6b91
--- /dev/null
+++ b/tools/about/noise.png
Binary files differ
diff --git a/tools/about/ttf.py b/tools/about/ttf.py
new file mode 100644
index 0000000..eb6c027
--- /dev/null
+++ b/tools/about/ttf.py
@@ -0,0 +1,111 @@
+
+# Source: https://www.cairographics.org/cookbook/freetypepython/
+
+import ctypes as ct
+import cairo
+
+_initialized = False
+def create_cairo_font_face_for_file (filename, faceindex=0, loadoptions=0):
+ "given the name of a font file, and optional faceindex to pass to FT_New_Face" \
+ " and loadoptions to pass to cairo_ft_font_face_create_for_ft_face, creates" \
+ " a cairo.FontFace object that may be used to render text with that font."
+ global _initialized
+ global _freetype_so
+ global _cairo_so
+ global _ft_lib
+ global _ft_destroy_key
+ global _surface
+
+ CAIRO_STATUS_SUCCESS = 0
+ FT_Err_Ok = 0
+
+ if not _initialized:
+ # find shared objects
+ _freetype_so = ct.CDLL("libfreetype.so.6")
+ _cairo_so = ct.CDLL("libcairo.so.2")
+ _cairo_so.cairo_ft_font_face_create_for_ft_face.restype = ct.c_void_p
+ _cairo_so.cairo_ft_font_face_create_for_ft_face.argtypes = [ ct.c_void_p, ct.c_int ]
+ _cairo_so.cairo_font_face_get_user_data.restype = ct.c_void_p
+ _cairo_so.cairo_font_face_get_user_data.argtypes = (ct.c_void_p, ct.c_void_p)
+ _cairo_so.cairo_font_face_set_user_data.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
+ _cairo_so.cairo_set_font_face.argtypes = [ ct.c_void_p, ct.c_void_p ]
+ _cairo_so.cairo_font_face_status.argtypes = [ ct.c_void_p ]
+ _cairo_so.cairo_font_face_destroy.argtypes = (ct.c_void_p,)
+ _cairo_so.cairo_status.argtypes = [ ct.c_void_p ]
+ # initialize freetype
+ _ft_lib = ct.c_void_p()
+ status = _freetype_so.FT_Init_FreeType(ct.byref(_ft_lib))
+ if status != FT_Err_Ok :
+ raise RuntimeError("Error %d initializing FreeType library." % status)
+ #end if
+
+ class PycairoContext(ct.Structure):
+ _fields_ = \
+ [
+ ("PyObject_HEAD", ct.c_byte * object.__basicsize__),
+ ("ctx", ct.c_void_p),
+ ("base", ct.c_void_p),
+ ]
+ #end PycairoContext
+
+ _surface = cairo.ImageSurface(cairo.FORMAT_A8, 0, 0)
+ _ft_destroy_key = ct.c_int() # dummy address
+ _initialized = True
+ #end if
+
+ ft_face = ct.c_void_p()
+ cr_face = None
+ try :
+ # load FreeType face
+ status = _freetype_so.FT_New_Face(_ft_lib, filename.encode("utf-8"), faceindex, ct.byref(ft_face))
+ if status != FT_Err_Ok :
+ raise RuntimeError("Error %d creating FreeType font face for %s" % (status, filename))
+ #end if
+
+ # create Cairo font face for freetype face
+ cr_face = _cairo_so.cairo_ft_font_face_create_for_ft_face(ft_face, loadoptions)
+ status = _cairo_so.cairo_font_face_status(cr_face)
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename))
+ #end if
+ # Problem: Cairo doesn't know to call FT_Done_Face when its font_face object is
+ # destroyed, so we have to do that for it, by attaching a cleanup callback to
+ # the font_face. This only needs to be done once for each font face, while
+ # cairo_ft_font_face_create_for_ft_face will return the same font_face if called
+ # twice with the same FT Face.
+ # The following check for whether the cleanup has been attached or not is
+ # actually unnecessary in our situation, because each call to FT_New_Face
+ # will return a new FT Face, but we include it here to show how to handle the
+ # general case.
+ if _cairo_so.cairo_font_face_get_user_data(cr_face, ct.byref(_ft_destroy_key)) == None :
+ status = _cairo_so.cairo_font_face_set_user_data \
+ (
+ cr_face,
+ ct.byref(_ft_destroy_key),
+ ft_face,
+ _freetype_so.FT_Done_Face
+ )
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d doing user_data dance for %s" % (status, filename))
+ #end if
+ ft_face = None # Cairo has stolen my reference
+ #end if
+
+ # set Cairo font face into Cairo context
+ cairo_ctx = cairo.Context(_surface)
+ cairo_t = PycairoContext.from_address(id(cairo_ctx)).ctx
+ _cairo_so.cairo_set_font_face(cairo_t, cr_face)
+ status = _cairo_so.cairo_font_face_status(cairo_t)
+ if status != CAIRO_STATUS_SUCCESS :
+ raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename))
+ #end if
+
+ finally :
+ _cairo_so.cairo_font_face_destroy(cr_face)
+ _freetype_so.FT_Done_Face(ft_face)
+ #end try
+
+ # get back Cairo font face as a Python object
+ face = cairo_ctx.get_font_face()
+ return face
+#end create_cairo_font_face_for_file