changeset 509:a11cd7ea3a37

core: doxygenize action
author David Demelier <markand@malikania.fr>
date Sat, 04 Mar 2023 08:52:57 +0100
parents 7f7602bae0bd
children 21d2c66f3521
files CMakeLists.txt doc/CMakeLists.txt doc/Doxyfile doc/doxygen-awesome.css examples/example-action/example-action.c libmlk-core/mlk/core/action-script.c libmlk-core/mlk/core/action-script.h libmlk-core/mlk/core/action-stack.c libmlk-core/mlk/core/action-stack.h libmlk-core/mlk/core/action.c libmlk-core/mlk/core/action.h libmlk-core/mlk/core/alloc.c libmlk-core/mlk/core/alloc.h tests/test-action-script.c
diffstat 14 files changed, 2611 insertions(+), 186 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Fri Mar 03 19:45:00 2023 +0100
+++ b/CMakeLists.txt	Sat Mar 04 08:52:57 2023 +0100
@@ -17,7 +17,13 @@
 #
 
 cmake_minimum_required(VERSION 3.20)
-project(molko C)
+project(
+	molko
+	VERSION "0.1.0"
+	DESCRIPTION "Molko's Engine"
+	HOMEPAGE_URL "http://hg.malikania.fr/molko"
+	LANGUAGES "C"
+)
 
 set_property(GLOBAL PROPERTY USE_FOLDERS On)
 
@@ -39,7 +45,7 @@
 	set(CMAKE_C_FLAGS "/D_CRT_SECURE_NO_WARNINGS ${CMAKE_C_FLAGS}")
 endif ()
 
-option(MLK_WITH_DOC "Enable mkdocs documentation" On)
+option(MLK_WITH_DOXYGEN "Enable doxygen documentation" On)
 option(MLK_WITH_EXAMPLES "Enable examples" Off)
 option(MLK_WITH_NLS "Enable NLS support" On)
 option(MLK_WITH_TESTS "Enable unit tests" Off)
@@ -69,7 +75,7 @@
 add_subdirectory(extern/libsqlite)
 add_subdirectory(extern/libdt)
 
-if (MLK_WITH_DOC)
+if (MLK_WITH_DOXYGEN)
 	add_subdirectory(doc)
 endif ()
 
--- a/doc/CMakeLists.txt	Fri Mar 03 19:45:00 2023 +0100
+++ b/doc/CMakeLists.txt	Sat Mar 04 08:52:57 2023 +0100
@@ -20,70 +20,19 @@
 
 set(
 	SOURCES
-	${doc_SOURCE_DIR}/CMakeLists.txt
-	${doc_SOURCE_DIR}/mkdocs.yml
-	${doc_SOURCE_DIR}/docs
-	${doc_SOURCE_DIR}/docs/tools
-	${doc_SOURCE_DIR}/docs/tools/map.md
-	${doc_SOURCE_DIR}/docs/tools/bcc.md
-	${doc_SOURCE_DIR}/docs/tools/tileset.md
-	${doc_SOURCE_DIR}/docs/specs
-	${doc_SOURCE_DIR}/docs/specs/map.md
-	${doc_SOURCE_DIR}/docs/specs/tileset.md
-	${doc_SOURCE_DIR}/docs/install.md
-	${doc_SOURCE_DIR}/docs/index.md
-	${doc_SOURCE_DIR}/docs/dev
-	${doc_SOURCE_DIR}/docs/dev/faq.md
-	${doc_SOURCE_DIR}/docs/dev/error.md
-	${doc_SOURCE_DIR}/docs/dev/ownership.md
-	${doc_SOURCE_DIR}/docs/dev/api
-	${doc_SOURCE_DIR}/docs/dev/api/core
-	${doc_SOURCE_DIR}/docs/dev/api/core/texture.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/mouse.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/inhibit.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/sprite.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/animation.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/music.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/image.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/zfile.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/alloc.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/sys.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/state.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/maths.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/script.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/error.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/color.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/window.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/sound.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/save.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/translate.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/event.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/trace.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/core.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/action.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/font.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/panic.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/key.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/painter.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/game.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/util.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/clock.md
-	${doc_SOURCE_DIR}/docs/dev/api/core/drawable.md
-	${doc_SOURCE_DIR}/docs/dev/howto
-	${doc_SOURCE_DIR}/docs/dev/howto/01-init.md
-	${doc_SOURCE_DIR}/docs/about.md
+	${doc_SOURE_DIR}/Doxyfile
 )
 
-add_custom_target(
-	doc
-	SOURCES ${SOURCES}
-)
+find_package(Doxygen REQUIRED)
 
 add_custom_target(
-	doc-serve
-	SOURCES ${SOURCES}
-	COMMAND mkdocs serve
-	WORKING_DIRECTORY ${doc_SOURCE_DIR}
+	doxygen
+	SOURCES ${doc_SOURCE_DIR}/Doxyfile
+	COMMAND Doxygen::doxygen ${doc_BINARY_DIR}/Doxyfile
+	WORKING_DIRECTORY ${molko_SOURCE_DIR}
 )
 
-source_group(TREE ${doc_SOURCE_DIR} FILES ${SOURCES})
+configure_file(
+	${doc_SOURCE_DIR}/Doxyfile
+	${doc_BINARY_DIR}/Doxyfile
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/Doxyfile	Sat Mar 04 08:52:57 2023 +0100
@@ -0,0 +1,45 @@
+DOXYFILE_ENCODING      = UTF-8
+
+PROJECT_NAME           = "Molko's Engine"
+PROJECT_NUMBER         = "@molko_VERSION@"
+PROJECT_BRIEF          = "@molko_DESCRIPTION@"
+
+OUTPUT_DIRECTORY       = "@doc_BINARY_DIR@"
+
+TAB_SIZE               = 8
+OPTIMIZE_OUTPUT_FOR_C  = YES
+MARKDOWN_SUPPORT       = YES
+AUTOLINK_SUPPORT       = YES
+MAX_INITIALIZER_LINES  = 0
+
+HIDE_UNDOC_MEMBERS     = YES
+HIDE_UNDOC_CLASSES     = YES
+
+SHOW_INCLUDE_FILES     = NO
+QUIET                  = YES
+
+GENERATE_TREEVIEW      = YES
+HTML_EXTRA_STYLESHEET  = "@doc_SOURCE_DIR@/doxygen-awesome.css"
+
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = NO
+
+INPUT                  = libmlk-util \
+                         libmlk-core \
+                         libmlk-ui \
+                         libmlk-rpg
+
+FILE_PATTERNS          = *.c *.h
+RECURSIVE              = YES
+
+GENERATE_HTML          = YES
+GENERATE_LATEX         = NO
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+
+HAVE_DOT               = YES
+
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = YES
+PREDEFINED             = MLK_CORE_BEGIN_DECLS MLK_CORE_END_DECLS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/doxygen-awesome.css	Sat Mar 04 08:52:57 2023 +0100
@@ -0,0 +1,2008 @@
+/**
+
+Doxygen Awesome
+https://github.com/jothepro/doxygen-awesome-css
+
+MIT License
+
+Copyright (c) 2021 - 2022 jothepro
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+html {
+    /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */
+    --primary-color: #1779c4;
+    --primary-dark-color: #335c80;
+    --primary-light-color: #70b1e9;
+
+    /* page base colors */
+    --page-background-color: white;
+    --page-foreground-color: #2f4153;
+    --page-secondary-foreground-color: #637485;
+
+    /* color for all separators on the website: hr, borders, ... */
+    --separator-color: #dedede;
+
+    /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */
+    --border-radius-large: 8px;
+    --border-radius-small: 4px;
+    --border-radius-medium: 6px;
+
+    /* default spacings. Most compontest reference these values for spacing, to provide uniform spacing on the page. */
+    --spacing-small: 5px;
+    --spacing-medium: 10px;
+    --spacing-large: 16px;
+
+    /* default box shadow used for raising an element above the normal content. Used in dropdowns, Searchresult, ... */
+    --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075);
+
+    --odd-color: rgba(0,0,0,.028);
+
+    /* font-families. will affect all text on the website
+     * font-family: the normal font for text, headlines, menus
+     * font-family-monospace: used for preformatted text in memtitle, code, fragments
+     */
+    --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
+    --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
+
+    /* font sizes */
+    --page-font-size: 15.6px;
+    --navigation-font-size: 14.4px;
+    --code-font-size: 14px; /* affects code, fragment */
+    --title-font-size: 22px;
+
+    /* content text properties. These only affect the page content, not the navigation or any other ui elements */
+    --content-line-height: 27px;
+    /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/
+    --content-maxwidth: 1000px;
+
+    /* colors for various content boxes: @warning, @note, @deprecated @bug */
+    --warning-color: #f8d1cc;
+    --warning-color-dark: #b61825;
+    --warning-color-darker: #75070f;
+    --note-color: #faf3d8;
+    --note-color-dark: #f3a600;
+    --note-color-darker: #5f4204;
+    --todo-color: #e4f3ff;
+    --todo-color-dark: #1879C4;
+    --todo-color-darker: #274a5c;
+    --deprecated-color: #ecf0f3;
+    --deprecated-color-dark: #5b6269;
+    --deprecated-color-darker: #43454a;
+    --bug-color: #e4dafd;
+    --bug-color-dark: #5b2bdd;
+    --bug-color-darker: #2a0d72;
+    --invariant-color: #d8f1e3;
+    --invariant-color-dark: #44b86f;
+    --invariant-color-darker: #265532;
+
+    /* blockquote colors */
+    --blockquote-background: #f8f9fa;
+    --blockquote-foreground: #636568;
+
+    /* table colors */
+    --tablehead-background: #f1f1f1;
+    --tablehead-foreground: var(--page-foreground-color);
+
+    /* menu-display: block | none
+     * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible.
+     * `GENERATE_TREEVIEW` MUST be enabled!
+     */
+    --menu-display: block;
+
+    --menu-focus-foreground: var(--page-background-color);
+    --menu-focus-background: var(--primary-color);
+    --menu-selected-background: rgba(0,0,0,.05);
+
+
+    --header-background: var(--page-background-color);
+    --header-foreground: var(--page-foreground-color);
+
+    /* searchbar colors */
+    --searchbar-background: var(--side-nav-background);
+    --searchbar-foreground: var(--page-foreground-color);
+
+    /* searchbar size
+     * (`searchbar-width` is only applied on screens >= 768px.
+     * on smaller screens the searchbar will always fill the entire screen width) */
+    --searchbar-height: 33px;
+    --searchbar-width: 210px;
+    --searchbar-border-radius: var(--searchbar-height);
+
+    /* code block colors */
+    --code-background: #f5f5f5;
+    --code-foreground: var(--page-foreground-color);
+
+    /* fragment colors */
+    --fragment-background: #F8F9FA;
+    --fragment-foreground: #37474F;
+    --fragment-keyword: #bb6bb2;
+    --fragment-keywordtype: #8258b3;
+    --fragment-keywordflow: #d67c3b;
+    --fragment-token: #438a59;
+    --fragment-comment: #969696;
+    --fragment-link: #5383d6;
+    --fragment-preprocessor: #46aaa5;
+    --fragment-linenumber-color: #797979;
+    --fragment-linenumber-background: #f4f4f5;
+    --fragment-linenumber-border: #e3e5e7;
+    --fragment-lineheight: 20px;
+
+    /* sidebar navigation (treeview) colors */
+    --side-nav-background: #fbfbfb;
+    --side-nav-foreground: var(--page-foreground-color);
+    --side-nav-arrow-opacity: 0;
+    --side-nav-arrow-hover-opacity: 0.9;
+
+    --toc-background: var(--side-nav-background);
+    --toc-foreground: var(--side-nav-foreground);
+
+    /* height of an item in any tree / collapsable table */
+    --tree-item-height: 30px;
+
+    --memname-font-size: var(--code-font-size);
+    --memtitle-font-size: 18px;
+
+    --webkit-scrollbar-size: 7px;
+    --webkit-scrollbar-padding: 4px;
+    --webkit-scrollbar-color: var(--separator-color);
+}
+
+@media screen and (max-width: 767px) {
+    html {
+        --page-font-size: 16px;
+        --navigation-font-size: 16px;
+        --code-font-size: 15px; /* affects code, fragment */
+        --title-font-size: 22px;
+    }
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) {
+        color-scheme: dark;
+
+        --primary-color: #1982d2;
+        --primary-dark-color: #86a9c4;
+        --primary-light-color: #4779ac;
+
+        --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35);
+
+        --odd-color: rgba(100,100,100,.06);
+
+        --menu-selected-background: rgba(0,0,0,.4);
+
+        --page-background-color: #1C1D1F;
+        --page-foreground-color: #d2dbde;
+        --page-secondary-foreground-color: #859399;
+        --separator-color: #38393b;
+        --side-nav-background: #252628;
+
+        --code-background: #2a2c2f;
+
+        --tablehead-background: #2a2c2f;
+    
+        --blockquote-background: #222325;
+        --blockquote-foreground: #7e8c92;
+
+        --warning-color: #2e1917;
+        --warning-color-dark: #ad2617;
+        --warning-color-darker: #f5b1aa;
+        --note-color: #3b2e04;
+        --note-color-dark: #f1b602;
+        --note-color-darker: #ceb670;
+        --todo-color: #163750;
+        --todo-color-dark: #1982D2;
+        --todo-color-darker: #dcf0fa;
+        --deprecated-color: #2e323b;
+        --deprecated-color-dark: #738396;
+        --deprecated-color-darker: #abb0bd;
+        --bug-color: #2a2536;
+        --bug-color-dark: #7661b3;
+        --bug-color-darker: #ae9ed6;
+        --invariant-color: #303a35;
+        --invariant-color-dark: #76ce96;
+        --invariant-color-darker: #cceed5;
+
+        --fragment-background: #282c34;
+        --fragment-foreground: #dbe4eb;
+        --fragment-keyword: #cc99cd;
+        --fragment-keywordtype: #ab99cd;
+        --fragment-keywordflow: #e08000;
+        --fragment-token: #7ec699;
+        --fragment-comment: #999999;
+        --fragment-link: #98c0e3;
+        --fragment-preprocessor: #65cabe;
+        --fragment-linenumber-color: #cccccc;
+        --fragment-linenumber-background: #35393c;
+        --fragment-linenumber-border: #1f1f1f;
+    }
+}
+
+/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */
+html.dark-mode {
+    color-scheme: dark;
+
+    --primary-color: #1982d2;
+    --primary-dark-color: #86a9c4;
+    --primary-light-color: #4779ac;
+
+    --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30);
+
+    --odd-color: rgba(100,100,100,.06);
+
+    --menu-selected-background: rgba(0,0,0,.4);
+
+    --page-background-color: #1C1D1F;
+    --page-foreground-color: #d2dbde;
+    --page-secondary-foreground-color: #859399;
+    --separator-color: #38393b;
+    --side-nav-background: #252628;
+
+    --code-background: #2a2c2f;
+
+    --tablehead-background: #2a2c2f;
+
+    --blockquote-background: #222325;
+    --blockquote-foreground: #7e8c92;
+
+    --warning-color: #2e1917;
+    --warning-color-dark: #ad2617;
+    --warning-color-darker: #f5b1aa;
+    --note-color: #3b2e04;
+    --note-color-dark: #f1b602;
+    --note-color-darker: #ceb670;
+    --todo-color: #163750;
+    --todo-color-dark: #1982D2;
+    --todo-color-darker: #dcf0fa;
+    --deprecated-color: #2e323b;
+    --deprecated-color-dark: #738396;
+    --deprecated-color-darker: #abb0bd;
+    --bug-color: #2a2536;
+    --bug-color-dark: #7661b3;
+    --bug-color-darker: #ae9ed6;
+    --invariant-color: #303a35;
+    --invariant-color-dark: #76ce96;
+    --invariant-color-darker: #cceed5;
+
+    --fragment-background: #282c34;
+    --fragment-foreground: #dbe4eb;
+    --fragment-keyword: #cc99cd;
+    --fragment-keywordtype: #ab99cd;
+    --fragment-keywordflow: #e08000;
+    --fragment-token: #7ec699;
+    --fragment-comment: #999999;
+    --fragment-link: #98c0e3;
+    --fragment-preprocessor: #65cabe;
+    --fragment-linenumber-color: #cccccc;
+    --fragment-linenumber-background: #35393c;
+    --fragment-linenumber-border: #1f1f1f;
+}
+
+body {
+    color: var(--page-foreground-color);
+    background-color: var(--page-background-color);
+    font-size: var(--page-font-size);
+}
+
+body, table, div, p, dl, #nav-tree .label, .title, .sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, .SelectItem, #MSearchField, .navpath li.navelem a, .navpath li.navelem a:hover {
+    font-family: var(--font-family);
+}
+
+h1, h2, h3, h4, h5 {
+    margin-top: .9em;
+    font-weight: 600;
+    line-height: initial;
+}
+
+p, div, table, dl {
+    font-size: var(--page-font-size);
+}
+
+a:link, a:visited, a:hover, a:focus, a:active {
+    color: var(--primary-color) !important;
+    font-weight: 500;
+}
+
+a.anchor {
+    scroll-margin-top: var(--spacing-large);
+}
+
+/*
+ Title and top navigation
+ */
+
+#top {
+    background: var(--header-background);
+    border-bottom: 1px solid var(--separator-color);
+}
+
+@media screen and (min-width: 768px) {
+    #top {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+        align-items: center;
+    }
+}
+
+#main-nav {
+    flex-grow: 5;
+    padding: var(--spacing-small) var(--spacing-medium);
+}
+
+#titlearea {
+    width: auto;
+    padding: var(--spacing-medium) var(--spacing-large);
+    background: none;
+    color: var(--header-foreground);
+    border-bottom: none;
+}
+
+@media screen and (max-width: 767px) {
+    #titlearea {
+        padding-bottom: var(--spacing-small);
+    }
+}
+
+#titlearea table tbody tr {
+    height: auto !important;
+}
+
+#projectname {
+    font-size: var(--title-font-size);
+    font-weight: 600;
+}
+
+#projectnumber {
+    font-family: inherit;
+    font-size: 60%;
+}
+
+#projectbrief {
+    font-family: inherit;
+    font-size: 80%;
+}
+
+#projectlogo {
+    vertical-align: middle;
+}
+
+#projectlogo img {
+    max-height: calc(var(--title-font-size) * 2);
+    margin-right: var(--spacing-small);
+}
+
+.sm-dox, .tabs, .tabs2, .tabs3 {
+    background: none;
+    padding: 0;
+}
+
+.tabs, .tabs2, .tabs3 {
+    border-bottom: 1px solid var(--separator-color);
+    margin-bottom: -1px;
+}
+
+@media screen and (max-width: 767px) {
+    .sm-dox a span.sub-arrow {
+        background: var(--code-background);
+    }
+
+    #main-menu a.has-submenu span.sub-arrow {
+        color: var(--page-secondary-foreground-color);
+        border-radius: var(--border-radius-medium);
+    }
+
+    #main-menu a.has-submenu:hover span.sub-arrow {
+        color: var(--page-foreground-color);
+    }
+}
+
+@media screen and (min-width: 768px) {
+    .sm-dox li, .tablist li {
+        display: var(--menu-display);
+    }
+
+    .sm-dox a span.sub-arrow {
+        border-color: var(--header-foreground) transparent transparent transparent;
+    }
+
+    .sm-dox a:hover span.sub-arrow {
+        border-color: var(--menu-focus-foreground) transparent transparent transparent;
+    }
+
+    .sm-dox ul a span.sub-arrow {
+        border-color: transparent transparent transparent var(--page-foreground-color);
+    }
+
+    .sm-dox ul a:hover span.sub-arrow {
+        border-color: transparent transparent transparent var(--menu-focus-foreground);
+    }
+}
+
+.sm-dox ul {
+    background: var(--page-background-color);
+    box-shadow: var(--box-shadow);
+    border: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-medium) !important;
+    padding: var(--spacing-small);
+    animation: ease-out 150ms slideInMenu;
+}
+
+@keyframes slideInMenu {
+    from {
+        opacity: 0;
+        transform: translate(0px, -2px);
+    }
+
+    to {
+        opacity: 1;
+        transform: translate(0px, 0px);
+    }
+}
+
+.sm-dox ul a {
+    color: var(--page-foreground-color) !important;
+    background: var(--page-background-color);
+    font-size: var(--navigation-font-size);
+}
+
+.sm-dox>li>ul:after {
+    border-bottom-color: var(--page-background-color) !important;
+}
+
+.sm-dox>li>ul:before {
+    border-bottom-color: var(--separator-color) !important;
+}
+
+.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus {
+    font-size: var(--navigation-font-size) !important;
+    color: var(--menu-focus-foreground) !important;
+    text-shadow: none;
+    background-color: var(--menu-focus-background);
+    border-radius: var(--border-radius-small) !important;
+}
+
+.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a {
+    text-shadow: none;
+    background: transparent;
+    background-image: none !important;
+    color: var(--header-foreground) !important;
+    font-weight: normal;
+    font-size: var(--navigation-font-size);
+    border-radius: var(--border-radius-small) !important;
+}
+
+.sm-dox a:focus {
+    outline: auto;
+}
+
+.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover {
+    text-shadow: none;
+    font-weight: normal;
+    background: var(--menu-focus-background);
+    color: var(--menu-focus-foreground) !important;
+    border-radius: var(--border-radius-small) !important;
+    font-size: var(--navigation-font-size);
+}
+
+.tablist li.current {
+    border-radius: var(--border-radius-small);
+    background: var(--menu-selected-background);
+}
+
+.tablist li {
+    margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small);
+}
+
+.tablist a {
+    padding: 0 var(--spacing-large);
+}
+
+
+/*
+ Search box
+ */
+
+#MSearchBox {
+    height: var(--searchbar-height);
+    background: var(--searchbar-background);
+    border-radius: var(--searchbar-border-radius);
+    border: 1px solid var(--separator-color);
+    overflow: hidden;
+    width: var(--searchbar-width);
+    position: relative;
+    box-shadow: none;
+    display: block;
+    margin-top: 0;
+}
+
+.left #MSearchSelect {
+    left: 0;
+    user-select: none;
+}
+
+.SelectionMark {
+    user-select: none;
+}
+
+.tabs .left #MSearchSelect {
+    padding-left: 0;
+}
+
+.tabs #MSearchBox {
+    position: absolute;
+    right: var(--spacing-medium);
+}
+
+@media screen and (max-width: 767px) {
+    .tabs #MSearchBox {
+        position: relative;
+        right: 0;
+        margin-left: var(--spacing-medium);
+        margin-top: 0;
+    }
+}
+
+#MSearchSelectWindow, #MSearchResultsWindow {
+    z-index: 9999;
+}
+
+#MSearchBox.MSearchBoxActive {
+    border-color: var(--primary-color);
+    box-shadow: inset 0 0 0 1px var(--primary-color);
+}
+
+#main-menu > li:last-child {
+    margin-right: 0;
+}
+
+@media screen and (max-width: 767px) {
+    #main-menu > li:last-child {
+        height: 50px;
+    }
+}
+
+#MSearchField {
+    font-size: var(--navigation-font-size);
+    height: calc(var(--searchbar-height) - 2px);
+    background: transparent;
+    width: calc(var(--searchbar-width) - 64px);
+}
+
+.MSearchBoxActive #MSearchField {
+    color: var(--searchbar-foreground);
+}
+
+#MSearchSelect {
+    top: calc(calc(var(--searchbar-height) / 2) - 11px);
+}
+
+.left #MSearchSelect {
+    padding-left: 8px;
+}
+
+#MSearchBox span.left, #MSearchBox span.right {
+    background: none;
+}
+
+#MSearchBox span.right {
+    padding-top: calc(calc(var(--searchbar-height) / 2) - 12px);
+    position: absolute;
+    right: var(--spacing-small);
+}
+
+.tabs #MSearchBox span.right {
+    top: calc(calc(var(--searchbar-height) / 2) - 12px);
+}
+
+@keyframes slideInSearchResults {
+    from {
+        opacity: 0;
+        transform: translate(0, 15px);
+    }
+
+    to {
+        opacity: 1;
+        transform: translate(0, 20px);
+    }
+}
+
+#MSearchResultsWindow {
+    left: auto !important;
+    right: var(--spacing-medium);
+    border-radius: var(--border-radius-large);
+    border: 1px solid var(--separator-color);
+    transform: translate(0, 20px);
+    box-shadow: var(--box-shadow);
+    animation: ease-out 280ms slideInSearchResults;
+    background: var(--page-background-color);
+}
+
+iframe#MSearchResults {
+    margin: 4px;
+}
+
+iframe {
+    color-scheme: normal;
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) iframe#MSearchResults {
+        filter: invert() hue-rotate(180deg);
+    }
+}
+
+html.dark-mode iframe#MSearchResults {
+    filter: invert() hue-rotate(180deg);
+}
+
+#MSearchSelectWindow {
+    border: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-medium);
+    box-shadow: var(--box-shadow);
+    background: var(--page-background-color);
+    padding-top: var(--spacing-small);
+    padding-bottom: var(--spacing-small);
+}
+
+#MSearchSelectWindow a.SelectItem {
+    font-size: var(--navigation-font-size);
+    line-height: var(--content-line-height);
+    margin: 0 var(--spacing-small);
+    border-radius: var(--border-radius-small);
+    color: var(--page-foreground-color) !important;
+    font-weight: normal;
+}
+
+#MSearchSelectWindow a.SelectItem:hover {
+    background: var(--menu-focus-background);
+    color: var(--menu-focus-foreground) !important;
+}
+
+@media screen and (max-width: 767px) {
+    #MSearchBox {
+        margin-top: var(--spacing-medium);
+        margin-bottom: var(--spacing-medium);
+        width: calc(100vw - 30px);
+    }
+
+    #main-menu > li:last-child {
+        float: none !important;
+    }
+
+    #MSearchField {
+        width: calc(100vw - 110px);
+    }
+
+    @keyframes slideInSearchResultsMobile {
+        from {
+            opacity: 0;
+            transform: translate(0, 15px);
+        }
+
+        to {
+            opacity: 1;
+            transform: translate(0, 20px);
+        }
+    }
+
+    #MSearchResultsWindow {
+        left: var(--spacing-medium) !important;
+        right: var(--spacing-medium);
+        overflow: auto;
+        transform: translate(0, 20px);
+        animation: ease-out 280ms slideInSearchResultsMobile;
+    }
+
+    /*
+     * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2
+     */
+    label.main-menu-btn ~ #searchBoxPos1 {
+        top: 3px !important;
+        right: 6px !important;
+        left: 45px;
+        display: flex;
+    }
+
+    label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox {
+        margin-top: 0;
+        margin-bottom: 0;
+        flex-grow: 2;
+        float: left;
+    }
+}
+
+/*
+ Tree view
+ */
+
+#side-nav {
+    padding: 0 !important;
+    background: var(--side-nav-background);
+}
+
+@media screen and (max-width: 767px) {
+    #side-nav {
+        display: none;
+    }
+
+    #doc-content {
+        margin-left: 0 !important;
+    }
+}
+
+#nav-tree {
+    background: transparent;
+}
+
+#nav-tree .label {
+    font-size: var(--navigation-font-size);
+}
+
+#nav-tree .item {
+    height: var(--tree-item-height);
+    line-height: var(--tree-item-height);
+}
+
+#nav-sync {
+    bottom: 12px;
+    right: 12px;
+    top: auto !important;
+    user-select: none;
+}
+
+#nav-tree .selected {
+    text-shadow: none;
+    background-image: none;
+    background-color: transparent;
+    box-shadow: inset 4px 0 0 0 var(--primary-color);
+}
+
+#nav-tree a {
+    color: var(--side-nav-foreground) !important;
+    font-weight: normal;
+}
+
+#nav-tree a:focus {
+    outline-style: auto;
+}
+
+#nav-tree .arrow {
+    opacity: var(--side-nav-arrow-opacity);
+}
+
+.arrow {
+    color: inherit;
+    cursor: pointer;
+    font-size: 45%;
+    vertical-align: middle;
+    margin-right: 2px;
+    font-family: serif;
+    height: auto;
+    text-align: right;
+}
+
+#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow {
+    opacity: var(--side-nav-arrow-hover-opacity);
+}
+
+#nav-tree .selected a {
+    color: var(--primary-color) !important;
+    font-weight: bolder;
+    font-weight: 600;
+}
+
+.ui-resizable-e {
+    background: var(--separator-color);
+    width: 1px;
+}
+
+/*
+ Contents
+ */
+
+div.header {
+    border-bottom: 1px solid var(--separator-color);
+    background-color: var(--page-background-color);
+    background-image: none;
+}
+
+div.contents, div.header .title, div.header .summary {
+    max-width: var(--content-maxwidth);
+}
+
+div.contents, div.header .title  {
+    line-height: initial;
+    margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto;
+}
+
+div.header .summary {
+    margin: var(--spacing-medium) auto 0 auto;
+}
+
+div.headertitle {
+    padding: 0;
+}
+
+div.header .title {
+    font-weight: 600;
+    font-size: 210%;
+    padding: var(--spacing-medium) var(--spacing-large);
+    word-break: break-word;
+}
+
+div.header .summary {
+    width: auto;
+    display: block;
+    float: none;
+    padding: 0 var(--spacing-large);
+}
+
+td.memSeparator {
+    border-color: var(--separator-color);
+}
+
+.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+    background: var(--code-background);
+}
+
+span.mlabel {
+    background: var(--primary-color);
+    border: none;
+    padding: 4px 9px;
+    border-radius: 12px;
+    margin-right: var(--spacing-medium);
+}
+
+span.mlabel:last-of-type {
+    margin-right: 2px;
+}
+
+div.contents {
+    padding: 0 var(--spacing-large);
+}
+
+div.contents p, div.contents li {
+    line-height: var(--content-line-height);
+}
+
+div.contents div.dyncontent {
+    margin: var(--spacing-medium) 0;
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) div.contents div.dyncontent img,
+    html:not(.light-mode) div.contents center img,
+    html:not(.light-mode) div.contents table img,
+    html:not(.light-mode) div.contents div.dyncontent iframe,
+    html:not(.light-mode) div.contents center iframe,
+    html:not(.light-mode) div.contents table iframe {
+        filter: hue-rotate(180deg) invert();
+    }
+}
+
+html.dark-mode div.contents div.dyncontent img,
+html.dark-mode div.contents center img,
+html.dark-mode div.contents table img,
+html.dark-mode div.contents div.dyncontent iframe,
+html.dark-mode div.contents center iframe,
+html.dark-mode div.contents table iframe {
+    filter: hue-rotate(180deg) invert();
+}
+
+h2.groupheader {
+    border-bottom: 0px;
+    color: var(--page-foreground-color);
+    box-shadow: 
+        100px 0 var(--page-background-color), 
+        -100px 0 var(--page-background-color),
+        100px 1px var(--separator-color),
+        -100px 1px var(--separator-color),
+        500px 0 var(--page-background-color), 
+        -500px 0 var(--page-background-color),
+        500px 1px var(--separator-color),
+        -500px 1px var(--separator-color),
+        1500px 0 var(--page-background-color), 
+        1500px 1px var(--separator-color),
+        var(--content-maxwidth) 0 var(--page-background-color),
+        calc(0px - var(--content-maxwidth)) 0 var(--page-background-color),
+        var(--content-maxwidth) 1px var(--separator-color),
+        calc(0px - var(--content-maxwidth)) 1px var(--separator-color),
+        calc(2 * var(--content-maxwidth)) 0 var(--page-background-color),
+        calc(0px - 2 * var(--content-maxwidth)) 0 var(--page-background-color),
+        calc(2 * var(--content-maxwidth)) 1px var(--separator-color),
+        calc(0px - 2 * var(--content-maxwidth)) 1px var(--separator-color);
+}
+
+blockquote {
+    margin: 0 var(--spacing-medium) 0 var(--spacing-medium);
+    padding: var(--spacing-small) var(--spacing-large);
+    background: var(--blockquote-background);
+    color: var(--blockquote-foreground);
+    border-left: 0;
+    overflow: visible;
+    border-radius: var(--border-radius-medium);
+    overflow: visible;
+    position: relative;
+}
+
+blockquote::before, blockquote::after {
+    font-weight: bold;
+    font-family: serif;
+    font-size: 360%;
+    opacity: .15;
+    position: absolute;
+}
+
+blockquote::before {
+    content: "“";
+    left: -10px;
+    top: 4px;
+}
+
+blockquote::after {
+    content: "”";
+    right: -8px;
+    bottom: -25px;
+}
+
+blockquote p {
+    margin: var(--spacing-small) 0 var(--spacing-medium) 0;
+}
+.paramname {
+    font-weight: 600;
+    color: var(--primary-dark-color);
+}
+
+.paramname > code {
+    border: 0;
+}
+
+table.params .paramname {
+    font-weight: 600;
+    font-family: var(--font-family-monospace);
+    font-size: var(--code-font-size);
+    padding-right: var(--spacing-small);
+}
+
+.glow {
+    text-shadow: 0 0 15px var(--primary-light-color) !important;
+}
+
+.alphachar a {
+    color: var(--page-foreground-color);
+}
+
+/*
+ Table of Contents
+ */
+
+div.toc {
+    z-index: 10;
+    position: relative;
+    background-color: var(--toc-background);
+    border: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-medium);
+    box-shadow: var(--box-shadow);
+    padding: 0 var(--spacing-large);
+    margin: 0 0 var(--spacing-medium) var(--spacing-medium);
+}
+
+div.toc h3 {
+    color: var(--toc-foreground);
+    font-size: var(--navigation-font-size);
+    margin: var(--spacing-large) 0;
+}
+
+div.toc li {
+    font-size: var(--navigation-font-size);
+    padding: 0;
+    background: none;
+}
+
+div.toc li:before {
+    content: '↓';
+    font-weight: 800;
+    font-family: var(--font-family);
+    margin-right: var(--spacing-small);
+    color: var(--toc-foreground);
+    opacity: .4;
+}
+
+div.toc ul li.level1 {
+    margin: 0;
+}
+
+div.toc ul li.level2, div.toc ul li.level3 {
+    margin-top: 0;
+}
+
+
+@media screen and (max-width: 767px) {
+    div.toc {
+        float: none;
+        width: auto;
+        margin: 0 0 var(--spacing-medium) 0;
+    }
+}
+
+/*
+ Code & Fragments
+ */
+
+code, div.fragment, pre.fragment {
+    border-radius: var(--border-radius-small);
+    border: 1px solid var(--separator-color);
+    overflow: hidden;
+}
+
+code {
+    display: inline;
+    background: var(--code-background);
+    color: var(--code-foreground);
+    padding: 2px 6px;
+    word-break: break-word;
+}
+
+div.fragment, pre.fragment {
+    margin: var(--spacing-medium) 0;
+    padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large);
+    background: var(--fragment-background);
+    color: var(--fragment-foreground);
+    overflow-x: auto;
+}
+
+@media screen and (max-width: 767px) {
+    div.fragment, pre.fragment {
+        border-top-right-radius: 0;
+        border-bottom-right-radius: 0;
+        border-right: 0;
+    }
+
+    .contents > div.fragment,
+    .textblock > div.fragment,
+    .textblock > pre.fragment,
+    .contents > .doxygen-awesome-fragment-wrapper > div.fragment,
+    .textblock > .doxygen-awesome-fragment-wrapper > div.fragment,
+    .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-large));
+        border-radius: 0;
+        border-left: 0;
+    }
+
+    .textblock li > .fragment,
+    .textblock li > .doxygen-awesome-fragment-wrapper > .fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-large));
+    }
+
+    .memdoc li > .fragment,
+    .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-medium));
+    }
+
+    .textblock ul, .memdoc ul {
+        overflow: initial;
+    }
+
+    .memdoc > div.fragment,
+    .memdoc > pre.fragment,
+    dl dd > div.fragment,
+    dl dd pre.fragment,
+    .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment,
+    .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment,
+    dl dd > .doxygen-awesome-fragment-wrapper > div.fragment,
+    dl dd .doxygen-awesome-fragment-wrapper > pre.fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-medium));
+        border-radius: 0;
+        border-left: 0;
+    }
+}
+
+code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span {
+    font-family: var(--font-family-monospace);
+    font-size: var(--code-font-size) !important;
+}
+
+div.line:after {
+    margin-right: var(--spacing-medium);
+}
+
+div.fragment .line, pre.fragment {
+    white-space: pre;
+    word-wrap: initial;
+    line-height: var(--fragment-lineheight);
+}
+
+div.fragment span.keyword {
+    color: var(--fragment-keyword);
+}
+
+div.fragment span.keywordtype {
+    color: var(--fragment-keywordtype);
+}
+
+div.fragment span.keywordflow {
+    color: var(--fragment-keywordflow);
+}
+
+div.fragment span.stringliteral {
+    color: var(--fragment-token)
+}
+
+div.fragment span.comment {
+    color: var(--fragment-comment);
+}
+
+div.fragment a.code {
+    color: var(--fragment-link) !important;
+}
+
+div.fragment span.preprocessor {
+    color: var(--fragment-preprocessor);
+}
+
+div.fragment span.lineno {
+    display: inline-block;
+    width: 27px;
+    border-right: none;
+    background: var(--fragment-linenumber-background);
+    color: var(--fragment-linenumber-color);
+}
+
+div.fragment span.lineno a {
+    background: none;
+    color: var(--fragment-link) !important;
+}
+
+div.fragment .line:first-child .lineno {
+    box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border);
+}
+
+/*
+ dl warning, attention, note, deprecated, bug, ...
+ */
+
+dl.bug dt a, dl.deprecated dt a, dl.todo dt a {
+    font-weight: bold !important;
+}
+
+dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.todo, dl.remark {
+    padding: var(--spacing-medium);
+    margin: var(--spacing-medium) 0;
+    color: var(--page-background-color);
+    overflow: hidden;
+    margin-left: 0;
+    border-radius: var(--border-radius-small);
+}
+
+dl.section dd {
+    margin-bottom: 2px;
+}
+
+dl.warning, dl.attention {
+    background: var(--warning-color);
+    border-left: 8px solid var(--warning-color-dark);
+    color: var(--warning-color-darker);
+}
+
+dl.warning dt, dl.attention dt {
+    color: var(--warning-color-dark);
+}
+
+dl.note, dl.remark {
+    background: var(--note-color);
+    border-left: 8px solid var(--note-color-dark);
+    color: var(--note-color-darker);
+}
+
+dl.note dt, dl.remark dt {
+    color: var(--note-color-dark);
+}
+
+dl.todo {
+    background: var(--todo-color);
+    border-left: 8px solid var(--todo-color-dark);
+    color: var(--todo-color-darker);
+}
+
+dl.todo dt {
+    color: var(--todo-color-dark);
+}
+
+dl.bug dt a {
+    color: var(--todo-color-dark) !important;
+}
+
+dl.bug {
+    background: var(--bug-color);
+    border-left: 8px solid var(--bug-color-dark);
+    color: var(--bug-color-darker);
+}
+
+dl.bug dt a {
+    color: var(--bug-color-dark) !important;
+}
+
+dl.deprecated {
+    background: var(--deprecated-color);
+    border-left: 8px solid var(--deprecated-color-dark);
+    color: var(--deprecated-color-darker);
+}
+
+dl.deprecated dt a {
+    color: var(--deprecated-color-dark) !important;
+}
+
+dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd {
+    margin-inline-start: 0px;
+}
+
+dl.invariant, dl.pre {
+    background: var(--invariant-color);
+    border-left: 8px solid var(--invariant-color-dark);
+    color: var(--invariant-color-darker);
+}
+
+dl.invariant dt, dl.pre dt {
+    color: var(--invariant-color-dark);
+}
+
+/*
+ memitem
+ */
+
+div.memdoc, div.memproto, h2.memtitle {
+    box-shadow: none;
+    background-image: none;
+    border: none;
+}
+
+div.memdoc {
+    padding: 0 var(--spacing-medium);
+    background: var(--page-background-color);
+}
+
+h2.memtitle, div.memitem {
+    border: 1px solid var(--separator-color);
+    box-shadow: var(--box-shadow);
+}
+
+h2.memtitle {
+    box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow);
+}
+
+div.memitem {
+    transition: none;
+}
+
+div.memproto, h2.memtitle {
+    background: var(--fragment-background);
+    text-shadow: none;
+}
+
+h2.memtitle {
+    font-weight: 500;
+    font-size: var(--memtitle-font-size);
+    font-family: var(--font-family-monospace);
+    border-bottom: none;
+    border-top-left-radius: var(--border-radius-medium);
+    border-top-right-radius: var(--border-radius-medium);
+    word-break: break-all;
+    position: relative;
+}
+
+h2.memtitle:after {
+    content: "";
+    display: block;
+    background: var(--fragment-background);
+    height: var(--spacing-medium);
+    bottom: calc(0px - var(--spacing-medium));
+    left: 0;
+    right: -14px;
+    position: absolute;
+    border-top-right-radius: var(--border-radius-medium);
+}
+
+h2.memtitle > span.permalink {
+    font-size: inherit;
+}
+
+h2.memtitle > span.permalink > a {
+    text-decoration: none;
+    padding-left: 3px;
+    margin-right: -4px;
+    user-select: none;
+    display: inline-block;
+    margin-top: -6px;
+}
+
+h2.memtitle > span.permalink > a:hover {
+    color: var(--primary-dark-color) !important;
+}
+
+a:target + h2.memtitle, a:target + h2.memtitle + div.memitem {
+    border-color: var(--primary-light-color);
+}
+
+div.memitem {
+    border-top-right-radius: var(--border-radius-medium);
+    border-bottom-right-radius: var(--border-radius-medium);
+    border-bottom-left-radius: var(--border-radius-medium);
+    overflow: hidden;
+    display: block !important;
+}
+
+div.memdoc {
+    border-radius: 0;
+}
+
+div.memproto {
+    border-radius: 0 var(--border-radius-small) 0 0;
+    overflow: auto;
+    border-bottom: 1px solid var(--separator-color);
+    padding: var(--spacing-medium);
+    margin-bottom: -1px;
+}
+
+div.memtitle {
+    border-top-right-radius: var(--border-radius-medium);
+    border-top-left-radius: var(--border-radius-medium);
+}
+
+div.memproto table.memname {
+    font-family: var(--font-family-monospace);
+    color: var(--page-foreground-color);
+    font-size: var(--memname-font-size);
+}
+
+table.mlabels, table.mlabels > tbody {
+    display: block;
+}
+
+td.mlabels-left {
+    width: auto;
+}
+
+td.mlabels-right {
+    margin-top: 3px;
+    position: sticky;
+    left: 0;
+}
+
+table.mlabels > tbody > tr:first-child {
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+}
+
+.memname, .memitem span.mlabels {
+    margin: 0
+}
+
+/*
+ reflist
+ */
+
+dl.reflist {
+    box-shadow: var(--box-shadow);
+    border-radius: var(--border-radius-medium);
+    border: 1px solid var(--separator-color);
+    overflow: hidden;
+    padding: 0;
+}
+
+
+dl.reflist dt, dl.reflist dd {
+    box-shadow: none;
+    text-shadow: none;
+    background-image: none;
+    border: none;
+    padding: 12px;
+}
+
+
+dl.reflist dt {
+    font-weight: 500;
+    border-radius: 0;
+    background: var(--code-background);
+    border-bottom: 1px solid var(--separator-color);
+    color: var(--page-foreground-color)
+}
+
+
+dl.reflist dd {
+    background: none;
+}
+
+/*
+ Table
+ */
+
+table.markdownTable, table.fieldtable {
+    width: 100%;
+    border: none;
+    margin: var(--spacing-medium) 0;
+    box-shadow: 0 0 0 1px var(--separator-color);
+    border-radius: var(--border-radius-small);
+}
+
+th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone {
+    background: var(--tablehead-background);
+    color: var(--tablehead-foreground);
+    font-weight: 600;
+    font-size: var(--page-font-size);
+}
+
+th.markdownTableHeadLeft:first-child, th.markdownTableHeadRight:first-child, th.markdownTableHeadCenter:first-child, th.markdownTableHeadNone:first-child {
+    border-top-left-radius: var(--border-radius-small);
+}
+
+th.markdownTableHeadLeft:last-child, th.markdownTableHeadRight:last-child, th.markdownTableHeadCenter:last-child, th.markdownTableHeadNone:last-child {
+    border-top-right-radius: var(--border-radius-small);
+}
+
+table.markdownTable td, table.markdownTable th, table.fieldtable dt {
+    border: none;
+    border-right: 1px solid var(--separator-color);
+    padding: var(--spacing-small) var(--spacing-medium);
+}
+
+table.markdownTable td:last-child, table.markdownTable th:last-child, table.fieldtable dt:last-child {
+    border: none;
+}
+
+table.markdownTable tr, table.markdownTable tr {
+    border-bottom: 1px solid var(--separator-color);
+}
+
+table.markdownTable tr:last-child, table.markdownTable tr:last-child {
+    border-bottom: none;
+}
+
+table.fieldtable th {
+    font-size: var(--page-font-size);
+    font-weight: 600;
+    background-image: none;
+    background-color: var(--tablehead-background);
+    color: var(--tablehead-foreground);
+    border-bottom: 1px solid var(--separator-color);
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+    border-bottom: 1px solid var(--separator-color);
+    border-right: 1px solid var(--separator-color);
+}
+
+.fieldtable td.fielddoc {
+    border-bottom: 1px solid var(--separator-color);
+}
+
+.memberdecls td.glow, .fieldtable tr.glow {
+    background-color: var(--primary-light-color);
+    box-shadow: 0 0 15px var(--primary-light-color);
+}
+
+table.memberdecls {
+    display: block;
+}
+
+table.memberdecls tr[class^='memitem'] {
+    font-family: var(--font-family-monospace);
+    font-size: var(--code-font-size);
+}
+
+table.memberdecls .memItemLeft, table.memberdecls .memItemRight {
+    transition: none;
+    padding-top: var(--spacing-small);
+    padding-bottom: var(--spacing-small);
+    border-top: 1px solid var(--separator-color);
+    border-bottom: 1px solid var(--separator-color);
+    background-color: var(--fragment-background);
+}
+
+table.memberdecls .memItemLeft {
+    border-radius: var(--border-radius-small) 0 0 var(--border-radius-small);
+    border-left: 1px solid var(--separator-color);
+    padding-left: var(--spacing-medium);
+    padding-right: 0;
+}
+
+table.memberdecls .memItemRight {
+    border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0;
+    border-right: 1px solid var(--separator-color);
+    padding-right: var(--spacing-medium);
+    padding-left: 0;
+
+}
+
+table.memberdecls .mdescLeft, table.memberdecls .mdescRight {
+    background: none;
+    color: var(--page-foreground-color);
+    padding: var(--spacing-small) 0;
+}
+
+table.memberdecls .memSeparator {
+    background: var(--page-background-color);
+    height: var(--spacing-large);
+    border: 0;
+    transition: none;
+}
+
+table.memberdecls .groupheader {
+    margin-bottom: var(--spacing-large);
+}
+
+table.memberdecls .inherit_header td {
+    padding: 0 0 var(--spacing-medium) 0;
+    text-indent: -12px;
+    line-height: 1.5em;
+    color: var(--page-secondary-foreground-color);
+}
+
+@media screen and (max-width: 767px) {
+
+    table.memberdecls .memItemLeft, table.memberdecls .memItemRight, table.memberdecls .mdescLeft, table.memberdecls .mdescRight {
+        display: block;
+        text-align: left;
+        padding-left: var(--spacing-large);
+        margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large));
+        border-right: none;
+        border-left: none;
+        border-radius: 0;
+    }
+
+    table.memberdecls .memItemLeft, table.memberdecls .mdescLeft {
+        border-bottom: 0;
+        padding-bottom: 0;
+    }
+
+    table.memberdecls .mdescLeft {
+        margin-top: calc(0px - var(--page-font-size));
+    }
+
+    table.memberdecls .memItemRight, table.memberdecls .mdescRight {
+        border-top: 0;
+        padding-top: 0;
+        padding-right: var(--spacing-large);
+    }
+
+    table.memberdecls tr[class^='memitem']:not(.inherit) {
+        display: block;
+        width: calc(100vw - 2 * var(--spacing-large));
+    }
+
+    table.memberdecls .mdescRight {
+        color: var(--page-foreground-color);
+    }
+
+    table.memberdecls tr.inherit {
+        visibility: hidden;
+    }
+
+    table.memberdecls tr[style="display: table-row;"] {
+        display: block !important;
+        visibility: visible;
+        width: calc(100vw - 2 * var(--spacing-large));
+        animation: fade .5s;
+    }
+
+    @keyframes fade {
+        0% {
+            opacity: 0;
+            max-height: 0;
+        }
+
+        100% {
+            opacity: 1;
+            max-height: 200px;
+        }
+    }
+}
+
+
+/*
+ Horizontal Rule
+ */
+
+hr {
+    margin-top: var(--spacing-large);
+    margin-bottom: var(--spacing-large);
+    border-top:1px solid var(--separator-color);
+}
+
+.contents hr {
+    box-shadow: 100px 0 0 0 var(--separator-color),
+                -100px 0 0 0 var(--separator-color),
+                var(--content-maxwidth) 0 0 0 var(--separator-color),
+                calc(0px - var(--content-maxwidth)) 0 0 0 var(--separator-color),
+                calc(2 * var(--content-maxwidth)) 0 0 0 var(--separator-color),
+                calc(0px - 2* var(--content-maxwidth)) 0 0 0 var(--separator-color);
+}
+
+.contents img, .contents .center, .contents center, .contents div.image object {
+    max-width: 100%;
+    overflow: auto;
+}
+
+/*
+ Directories
+ */
+div.directory {
+    border-top: 1px solid var(--separator-color);
+    border-bottom: 1px solid var(--separator-color);
+    width: auto;
+}
+
+table.directory {
+    font-family: var(--font-family);
+    font-size: var(--page-font-size);
+    font-weight: normal;
+}
+
+.directory td.entry {
+    padding: var(--spacing-small);
+}
+
+.directory tr.even {
+    background-color: var(--odd-color);
+}
+
+.icona {
+    width: auto;
+    height: auto;
+    margin: 0 var(--spacing-small);
+}
+
+.icon {
+    background: var(--primary-color);
+    width: 18px;
+    height: 18px;
+    line-height: 18px;
+}
+
+.iconfopen, .icondoc, .iconfclosed {
+    background-position: center;
+    margin-bottom: 0;
+}
+
+.icondoc {
+    filter: saturate(0.2);
+}
+
+@media screen and (max-width: 767px) {
+    div.directory {
+        margin-left: calc(0px - var(--spacing-medium));
+        margin-right: calc(0px - var(--spacing-medium));
+    }
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed {
+        filter: hue-rotate(180deg) invert();
+    }
+}
+
+html.dark-mode .iconfopen, html.dark-mode .iconfclosed {
+    filter: hue-rotate(180deg) invert();
+}
+
+/*
+ Class list
+ */
+
+.classindex dl.odd {
+    background: var(--odd-color);
+    border-radius: var(--border-radius-small);
+}
+
+@media screen and (max-width: 767px) {
+    .classindex {
+        margin: 0 calc(0px - var(--spacing-small));
+    }
+}
+
+/* 
+ Class Index Doxygen 1.8 
+*/
+
+table.classindex table div.ah {
+    background-image: none;
+    background-color: initial;
+    border-color: var(--separator-color);
+    color: var(--page-foreground-color);
+    box-shadow: var(--box-shadow);
+    border-radius: var(--border-radius-large);
+    padding: var(--spacing-small);
+}
+
+div.qindex {
+    background-color: var(--odd-color);
+    border-radius: var(--border-radius-small);
+    border: 1px solid var(--separator-color);
+    padding: var(--spacing-small) 0;
+}
+
+/*
+  Footer and nav-path
+ */
+
+#nav-path {
+    margin-bottom: -1px;
+    width: 100%;
+}
+
+#nav-path ul {
+    background-image: none;
+    background: var(--page-background-color);
+    border: none;
+    border-top: 1px solid var(--separator-color);
+    border-bottom: 1px solid var(--separator-color);
+    font-size: var(--navigation-font-size);
+}
+
+img.footer {
+    width: 60px;
+}
+
+.navpath li.footer {
+    color: var(--page-secondary-foreground-color);
+}
+
+address.footer {
+    margin-bottom: var(--spacing-large);
+}
+
+#nav-path li.navelem {
+    background-image: none;
+    display: flex;
+    align-items: center;
+}
+
+.navpath li.navelem a {
+    text-shadow: none;
+    display: inline-block;
+    color: var(--primary-color) !important;
+}
+
+.navpath li.navelem b {
+    color: var(--primary-dark-color);
+    font-weight: 500;
+}
+
+li.navelem {
+    padding: 0;
+    margin-left: -8px;
+}
+
+li.navelem:first-child {
+    margin-left: var(--spacing-large);
+}
+
+li.navelem:first-child:before {
+    display: none;
+}
+
+#nav-path li.navelem:after {
+    content: '';
+    border: 5px solid var(--page-background-color);
+    border-bottom-color: transparent;
+    border-right-color: transparent;
+    border-top-color: transparent;
+    transform: scaleY(4.2);
+    z-index: 10;
+    margin-left: 6px;
+}
+
+#nav-path li.navelem:before {
+    content: '';
+    border: 5px solid var(--separator-color);
+    border-bottom-color: transparent;
+    border-right-color: transparent;
+    border-top-color: transparent;
+    transform: scaleY(3.2);
+    margin-right: var(--spacing-small);
+}
+
+.navpath li.navelem a:hover {
+    color: var(--primary-color);
+}
+
+/*
+ Scrollbars for Webkit
+*/
+
+#nav-tree::-webkit-scrollbar,
+div.fragment::-webkit-scrollbar,
+pre.fragment::-webkit-scrollbar,
+div.memproto::-webkit-scrollbar,
+.contents center::-webkit-scrollbar {
+    width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding));
+    height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding));
+}
+
+#nav-tree::-webkit-scrollbar-thumb,
+div.fragment::-webkit-scrollbar-thumb,
+pre.fragment::-webkit-scrollbar-thumb,
+div.memproto::-webkit-scrollbar-thumb,
+.contents center::-webkit-scrollbar-thumb {
+    background-color: transparent;
+    border: var(--webkit-scrollbar-padding) solid transparent;
+    border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding));
+    background-clip: padding-box;  
+}
+
+#nav-tree:hover::-webkit-scrollbar-thumb,
+div.fragment:hover::-webkit-scrollbar-thumb,
+pre.fragment:hover::-webkit-scrollbar-thumb,
+div.memproto:hover::-webkit-scrollbar-thumb,
+.contents center:hover::-webkit-scrollbar-thumb {
+    background-color: var(--webkit-scrollbar-color);
+}
+
+#nav-tree::-webkit-scrollbar-track,
+div.fragment::-webkit-scrollbar-track,
+pre.fragment::-webkit-scrollbar-track,
+div.memproto::-webkit-scrollbar-track,
+.contents center::-webkit-scrollbar-track {
+    background: transparent;
+}
+
+#nav-tree, div.fragment, pre.fragment, div.memproto, .contents center {
+    overflow-x: overlay;
+}
+
+/*
+ Scrollbars for Firefox
+*/
+
+#nav-tree, div.fragment, pre.fragment, div.memproto, .contents center {
+    scrollbar-width: thin;
+}
+
+/*
+  Optional Dark mode toggle button
+*/
+
+doxygen-awesome-dark-mode-toggle {
+    display: inline-block;
+    margin: 0 0 0 var(--spacing-small);
+    padding: 0;
+    width: var(--searchbar-height);
+    height: var(--searchbar-height);
+    background: none;
+    border: none;
+    border-radius: var(--searchbar-height);
+    vertical-align: middle;
+    text-align: center;
+    line-height: var(--searchbar-height);
+    font-size: 22px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    user-select: none;
+    cursor: pointer;
+}
+
+doxygen-awesome-dark-mode-toggle > svg {
+    transition: transform .1s ease-in-out;
+}
+
+doxygen-awesome-dark-mode-toggle:active > svg {
+    transform: scale(.5);
+}
+
+doxygen-awesome-dark-mode-toggle:hover {
+    background-color: rgba(0,0,0,.03);
+}
+
+html.dark-mode doxygen-awesome-dark-mode-toggle:hover {
+    background-color: rgba(0,0,0,.18);
+}
+
+/*
+ Optional fragment copy button
+*/
+.doxygen-awesome-fragment-wrapper {
+    position: relative;
+}
+
+doxygen-awesome-fragment-copy-button {
+    opacity: 0;
+    background: var(--fragment-background);
+    width: 28px;
+    height: 28px;
+    position: absolute;
+    right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5));
+    top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5));
+    border: 1px solid var(--fragment-foreground);
+    cursor: pointer;
+    border-radius: var(--border-radius-small);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success {
+    opacity: .28;
+}
+
+doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success {
+    opacity: 1 !important;
+}
+
+doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg {
+    transform: scale(.91);
+}
+
+doxygen-awesome-fragment-copy-button svg {
+    fill: var(--fragment-foreground);
+    width: 18px;
+    height: 18px;
+}
+
+doxygen-awesome-fragment-copy-button.success svg {
+    fill: rgb(14, 168, 14);
+}
+
+doxygen-awesome-fragment-copy-button.success {
+    border-color: rgb(14, 168, 14);
+}
+
+@media screen and (max-width: 767px) {
+    .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button,
+    .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button,
+    .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button,
+    .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button,
+    dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button {
+        right: 0;
+    }
+}
+
+/*
+ Optional paragraph link button
+*/
+
+a.anchorlink {
+    font-size: 90%;
+    margin-left: var(--spacing-small);
+    color: var(--page-foreground-color) !important;
+    text-decoration: none;
+    opacity: .15;
+    display: none;
+    transition: opacity .1s ease-in-out, color .1s ease-in-out;
+}
+
+a.anchorlink svg {
+    fill: var(--page-foreground-color);
+}
+
+h3 a.anchorlink svg, h4 a.anchorlink svg {
+    margin-bottom: -3px;
+    margin-top: -4px;
+}
+
+a.anchorlink:hover {
+    opacity: .45;
+}
+
+h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink  {
+    display: inline-block;
+}
--- a/examples/example-action/example-action.c	Fri Mar 03 19:45:00 2023 +0100
+++ b/examples/example-action/example-action.c	Sat Mar 04 08:52:57 2023 +0100
@@ -187,7 +187,10 @@
  * depending on which chest the player clicks.
  */
 static struct mlk_action *script_actions[16];
-static struct mlk_action_script script;
+static struct mlk_action_script script = {
+	.actions = script_actions,
+	.actionsz = MLK_UTIL_SIZE(script_actions)
+};
 
 static void
 script_left_response(struct dialog *dlg, unsigned int index)
@@ -211,7 +214,7 @@
 	int err;
 	struct mlk_action *action;
 
-	mlk_action_script_init(&script, script_actions, MLK_UTIL_SIZE(script_actions));
+	mlk_action_script_init(&script);
 
 	for (size_t i = 0; i < msgsz; ++i) {
 		action = dialog_init(&msgs[i]);
--- a/libmlk-core/mlk/core/action-script.c	Fri Mar 03 19:45:00 2023 +0100
+++ b/libmlk-core/mlk/core/action-script.c	Sat Mar 04 08:52:57 2023 +0100
@@ -1,5 +1,5 @@
 /*
- * script.c -- convenient sequence of actions
+ * action-script.c -- convenient sequence of actions
  *
  * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr>
  *
@@ -27,23 +27,33 @@
 static inline struct mlk_action *
 current(struct mlk_action_script *s)
 {
-	if (s->cur >= s->len)
+	if (s->current >= s->length)
 		return NULL;
 
-	return s->actions[s->cur];
+	return s->actions[s->current];
 }
 
 void
-mlk_action_script_init(struct mlk_action_script *s, struct mlk_action **actions, size_t cap)
+mlk_action_script_init(struct mlk_action_script *s)
 {
 	assert(s);
 
-	s->actions = actions;
-	s->cap = cap;
-	s->len = s->cur = 0;
+	for (size_t i = 0; i < s->actionsz; ++i)
+		s->actions[i] = NULL;
+}
 
-	for (size_t i = 0; i < s->cap; ++i)
-		s->actions[i] = NULL;
+int
+mlk_action_script_append(struct mlk_action_script *s, struct mlk_action *a)
+{
+	assert(s);
+	assert(a);
+
+	if (s->length >= s->actionsz)
+		return MLK_ERR_NO_MEM;
+
+	s->actions[s->length++] = a;
+
+	return 0;
 }
 
 void
@@ -57,20 +67,6 @@
 		mlk_action_start(a);
 }
 
-int
-mlk_action_script_append(struct mlk_action_script *s, struct mlk_action *a)
-{
-	assert(s);
-	assert(a);
-
-	if (s->len >= s->cap)
-		return MLK_ERR_NO_MEM;
-
-	s->actions[s->len++] = a;
-
-	return 0;
-}
-
 void
 mlk_action_script_handle(struct mlk_action_script *s, const union mlk_event *ev)
 {
@@ -96,14 +92,14 @@
 
 	if (mlk_action_update(a, ticks)) {
 		mlk_action_end(a);
-		s->cur++;
+		s->current++;
 
 		/* Start this action now. */
 		if ((a = current(s)))
 			mlk_action_start(a);
 	}
 
-	return s->cur >= s->len;
+	return s->current >= s->length;
 }
 
 void
@@ -122,7 +118,7 @@
 {
 	assert(s);
 
-	return s->cur >= s->len;
+	return s->current >= s->length;
 }
 
 void
@@ -130,8 +126,12 @@
 {
 	assert(s);
 
-	for (size_t i = 0; i < s->len; ++i)
-		mlk_action_finish(s->actions[i]);
+	for (size_t i = 0; i < s->actionsz; ++i) {
+		if (i < s->length)
+			mlk_action_finish(s->actions[i]);
 
-	memset(s, 0, sizeof (*s));
+		s->actions[i] = NULL;
+	}
+
+	s->length = s->current = 0;
 }
--- a/libmlk-core/mlk/core/action-script.h	Fri Mar 03 19:45:00 2023 +0100
+++ b/libmlk-core/mlk/core/action-script.h	Sat Mar 04 08:52:57 2023 +0100
@@ -1,5 +1,5 @@
 /*
- * script.h -- convenient sequence of actions
+ * action-script.h -- convenient sequence of actions module
  *
  * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr>
  *
@@ -19,6 +19,30 @@
 #ifndef MLK_CORE_ACTION_SCRIPT_H
 #define MLK_CORE_ACTION_SCRIPT_H
 
+/**
+ * \file mlk/core/action-script.h
+ * \brief Convenient sequence of actions module.
+ *
+ * Module to create sequence of actions (see mlk/core/action.h)
+ *
+ * Those routines wrap individual actions into a sequence of actions into an action
+ * itself.
+ *
+ * This is convenient for scenarios where you need to specify several sequential
+ * actions that neet to waid the previous before continuing.
+ *
+ * In a nutshell, to write a scenario you should:
+ *
+ * 1. Declare a ::mlk_action array with your own size limits.
+ * 2. Declare a ::mlk_action_script and populate ::mlk_action_script::actions
+ *    and ::mlk_action_script::actionsz accordingly to the array.
+ * 3. Invoke ::mlk_action_script_init.
+ * 4. Add as many as actions you with with ::mlk_action_script_append.
+ * 5. Call ::mlk_action_script_start if you need (optional).
+ * 6. Invoke ::mlk_action_script_handle, ::mlk_action_script_update and
+ *    ::mlk_action_script_draw in your game loop until it completes.
+ */
+
 #include <stddef.h>
 
 #include "core.h"
@@ -27,38 +51,138 @@
 
 union mlk_event;
 
+/**
+ * \struct mlk_action_script
+ * \brief Actions script sequence
+ *
+ * This structure holds references to actions to be executed sequentially.
+ */
 struct mlk_action_script {
+	/**
+	 * (read-write, borrowed)
+	 *
+	 * Array of non-owning actions to run in order.
+	 */
 	struct mlk_action **actions;
-	size_t cap;
-	size_t len;
-	size_t cur;
+
+	/**
+	 * (read-write)
+	 *
+	 * Number of actions in array ::mlk_action_script::actions
+	 *
+	 * \warning changing this value must be kept in sync with the array
+	 *          dimension.
+	 */
+	size_t actionsz;
+
+	/**
+	 * (read-only)
+	 *
+	 * Number of actions inside of the array.
+	 */
+	size_t length;
+
+	/**
+	 * (read-only)
+	 *
+	 * Index of current action.
+	 */
+	size_t current;
 };
 
 MLK_CORE_BEGIN_DECLS
 
+/**
+ * Initialize the action sequence structure.
+ *
+ * This function will effectively reset the length, current and set all actions
+ * to NULL.
+ *
+ * \pre script != NULL
+ * \param script the action script structure
+ */
 void
-mlk_action_script_init(struct mlk_action_script *, struct mlk_action **, size_t);
-
-void
-mlk_action_script_start(struct mlk_action_script *);
+mlk_action_script_init(struct mlk_action_script *script);
 
+/**
+ * Try to append a new action into the script.
+ *
+ * The action is inserted as-is and ownership is left to the caller.
+ *
+ * \pre script != NULL
+ * \param script the action script structure
+ * \param action the action to append
+ * \return 0 on success or ::MLK_ERR_NO_MEM if full.
+ */
 int
-mlk_action_script_append(struct mlk_action_script *, struct mlk_action *);
+mlk_action_script_append(struct mlk_action_script *script,
+                         struct mlk_action *action);
 
-void
-mlk_action_script_handle(struct mlk_action_script *, const union mlk_event *);
+/**
+ * Tells if the sequence is complete.
+ *
+ * \pre script != NULL
+ * \param script the action script structure
+ * \return non-zero if completed
+ */
+int
+mlk_action_script_completed(const struct mlk_action_script *script);
 
-int
-mlk_action_script_update(struct mlk_action_script *, unsigned int);
+/**
+ * Invoke ::mlk_action_start on the current action.
+ *
+ * This function should be called only once because when the action completes
+ * the next one will be automatically started.
+ *
+ * \pre script != NULL
+ * \param script the action script structure
+ */
+void
+mlk_action_script_start(struct mlk_action_script *script);
 
+/**
+ * Invoke ::mlk_action_handle on the current action.
+ *
+ * \pre script != NULL
+ * \param script the action script structure
+ * \param event the event
+ */
 void
-mlk_action_script_draw(struct mlk_action_script *);
+mlk_action_script_handle(struct mlk_action_script *script,
+                         const union mlk_event *event);
 
+/**
+ * Invoke ::mlk_action_update on the current action.
+ *
+ * \pre script != NULL
+ * \param script the action script structure
+ * \param ticks frame ticks
+ */
 int
-mlk_action_script_completed(const struct mlk_action_script *);
+mlk_action_script_update(struct mlk_action_script *script, unsigned int ticks);
 
+/**
+ * Invoke ::mlk_action_draw on the current action.
+ *
+ * \pre script != NULL
+ * \param script the action script structure
+ */
 void
-mlk_action_script_finish(struct mlk_action_script *);
+mlk_action_script_draw(struct mlk_action_script *script);
+
+/**
+ * Invoke ::mlk_action_finish on all actions.
+ *
+ * After this call, the script array of actions is kept and can be reused if
+ * ::mlk_action_script_init is called again.
+ *
+ * \note If the sequence wasn't completed, the remaining actions are finalized
+ *       using ::mlk_action_finish but not terminated through ::mlk_action_end.
+ * \pre script != NULL
+ * \param script the action script structure
+ */
+void
+mlk_action_script_finish(struct mlk_action_script *script);
 
 MLK_CORE_END_DECLS
 
--- a/libmlk-core/mlk/core/action-stack.c	Fri Mar 03 19:45:00 2023 +0100
+++ b/libmlk-core/mlk/core/action-stack.c	Sat Mar 04 08:52:57 2023 +0100
@@ -66,6 +66,20 @@
 			mlk_action_start(act);
 }
 
+int
+mlk_action_stack_completed(const struct mlk_action_stack *st)
+{
+	assert(st);
+
+	struct mlk_action *act;
+
+	FOREACH(st, act)
+		if (act)
+			return 0;
+
+	return 1;
+}
+
 void
 mlk_action_stack_handle(struct mlk_action_stack *st, const union mlk_event *ev)
 {
@@ -115,20 +129,6 @@
 			mlk_action_draw(act);
 }
 
-int
-mlk_action_stack_completed(const struct mlk_action_stack *st)
-{
-	assert(st);
-
-	struct mlk_action *act;
-
-	FOREACH(st, act)
-		if (act)
-			return 0;
-
-	return 1;
-}
-
 void
 mlk_action_stack_finish(struct mlk_action_stack *st)
 {
--- a/libmlk-core/mlk/core/action-stack.h	Fri Mar 03 19:45:00 2023 +0100
+++ b/libmlk-core/mlk/core/action-stack.h	Sat Mar 04 08:52:57 2023 +0100
@@ -19,6 +19,17 @@
 #ifndef MLK_CORE_ACTION_STACK_H
 #define MLK_CORE_ACTION_STACK_H
 
+/**
+ * \file mlk/core/action-stack.h
+ * \brief Convenient stack of actions.
+ *
+ * Stack of actions.
+ *
+ * The purpose of this module is to help managing several actions at once.
+ * Actions are automatically removed from the stack if the corresponding update
+ * member function returns non-zero after completion.
+ */
+
 #include <stddef.h>
 
 #include "core.h"
@@ -27,36 +38,118 @@
 
 union mlk_event;
 
+/**
+ * \struct mlk_action_stack
+ * \brief Action stack structure
+ *
+ * This structure holds references to actions to be executed.
+ */
 struct mlk_action_stack {
+	/**
+	 * (read-write, borrowed)
+	 *
+	 * Array of non-owning actions to run.
+	 */
 	struct mlk_action **actions;
+
+	/**
+	 * (read-write)
+	 *
+	 * Number of actions in array ::mlk_action_script::actions
+	 *
+	 * \warning changing this value must be kept in sync with the array
+	 *          dimension.
+	 */
 	size_t actionsz;
 };
 
 MLK_CORE_BEGIN_DECLS
 
+/**
+ * Initialize the action sequence structure.
+ *
+ * This function will set all pointers in the ::mlk_action_stack::actions to
+ * NULL.
+ *
+ * \pre stack != NULL
+ * \param stack the action stack
+ */
 void
-mlk_action_stack_init(struct mlk_action_stack *, struct mlk_action **, size_t);
-
-int
-mlk_action_stack_add(struct mlk_action_stack *, struct mlk_action *);
+mlk_action_stack_init(struct mlk_action_stack *stack);
 
-void
-mlk_action_stack_start(struct mlk_action_stack *);
+/**
+ * Try to append a new action into the stack if one slot in the
+ * ::mlk_action_stack::actions is NULL
+ *
+ * The action is inserted as-is and ownership is left to the caller.
+ *
+ * \pre stack != NULL
+ * \param stack the action stack
+ * \param action the action to append
+ * \return 0 on success or ::MLK_ERR_NO_MEM if full.
+ */
+int
+mlk_action_stack_add(struct mlk_action_stack *stack,
+                     struct mlk_action *action);
 
-void
-mlk_action_stack_handle(struct mlk_action_stack *, const union mlk_event *);
+/**
+ * Tells if there are still at least one action in the stack.
+ *
+ * \pre stack != NULL
+ * \param stack the action stack
+ * \return non-zero if completed
+ */
+int
+mlk_action_stack_completed(const struct mlk_action_stack *stack);
+
 
-int
-mlk_action_stack_update(struct mlk_action_stack *, unsigned int);
+/**
+ * Invoke ::mlk_action_start on all actions.
+ *
+ * \pre stack != NULL
+ * \param stack the action stack
+ */
+void
+mlk_action_stack_start(struct mlk_action_stack *stack);
 
+/**
+ * Invoke ::mlk_action_handle on all actions.
+ *
+ * \pre stack != NULL
+ * \param stack the action stack
+ * \param event the event
+ */
 void
-mlk_action_stack_draw(const struct mlk_action_stack *);
+mlk_action_stack_handle(struct mlk_action_stack *stack,
+                        const union mlk_event *event);
 
+/**
+ * Invoke ::mlk_action_update on all actions.
+ *
+ * \pre stack != NULL
+ * \param stack the action stack
+ * \param ticks frame ticks
+ */
 int
-mlk_action_stack_completed(const struct mlk_action_stack *);
+mlk_action_stack_update(struct mlk_action_stack *stack,
+                        unsigned int ticks);
 
+/**
+ * Invoke ::mlk_action_draw on all actions.
+ *
+ * \pre stack != NULL
+ * \param stack the action stack
+ */
 void
-mlk_action_stack_finish(struct mlk_action_stack *);
+mlk_action_stack_draw(const struct mlk_action_stack *stack);
+
+/**
+ *
+ * \pre stack != NULL
+ * \param stack the action stack
+ */
+void
+mlk_action_stack_finish(struct mlk_action_stack *stack);
 
 MLK_CORE_END_DECLS
 
--- a/libmlk-core/mlk/core/action.c	Fri Mar 03 19:45:00 2023 +0100
+++ b/libmlk-core/mlk/core/action.c	Sat Mar 04 08:52:57 2023 +0100
@@ -1,5 +1,5 @@
 /*
- * action.c -- action states
+ * action.c -- generic in game actions
  *
  * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr>
  *
--- a/libmlk-core/mlk/core/action.h	Fri Mar 03 19:45:00 2023 +0100
+++ b/libmlk-core/mlk/core/action.h	Sat Mar 04 08:52:57 2023 +0100
@@ -1,5 +1,5 @@
 /*
- * action.h -- action states
+ * action.h -- generic in game actions
  *
  * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr>
  *
@@ -19,39 +19,162 @@
 #ifndef MLK_CORE_ACTION_H
 #define MLK_CORE_ACTION_H
 
+/**
+ * \file mlk/core/action.h
+ * \brief Generic in game actions.
+ *
+ * This module help creating user interaction within the gameplay by adding
+ * actions. They have the following properties:
+ *
+ * - Can handle user input and events,
+ * - Can be updated through the game loop,
+ * - Can be drawn.
+ *
+ * Most more high level objects can handle actions to add flexibility (like in
+ * battles, maps, etc).
+ */
+
 #include "core.h"
 
 union mlk_event;
 
+/**
+ * \struct mlk_action
+ * \brief Action structure
+ *
+ * Use this structure to create an action that may handle input, be updated and
+ * drawn.
+ */
 struct mlk_action {
+	/**
+	 * (read-write, borrowed, optional)
+	 *
+	 * Arbitrary user data.
+	 */
 	void *data;
-	void (*start)(struct mlk_action *);
-	void (*handle)(struct mlk_action *, const union mlk_event *);
-	int (*update)(struct mlk_action *, unsigned int);
-	void (*draw)(struct mlk_action *);
-	void (*end)(struct mlk_action *);
+
+	/**
+	 * (optional)
+	 *
+	 * Start the action.
+	 *
+	 * Use this function when the action should start.
+	 *
+	 * \param self this action
+	 */
+	void (*start)(struct mlk_action *self);
+
+	/**
+	 * (optional)
+	 *
+	 * Handle an event.
+	 *
+	 * \param self this action
+	 * \param event the event
+	 */
+	void (*handle)(struct mlk_action *self, const union mlk_event *event);
+
+	/**
+	 * (optional)
+	 *
+	 * Update the action with the given ticks since last frame.
+	 *
+	 * The callback should return non-zero if it is considered complete.
+	 *
+	 * \param self this action
+	 * \param ticks frame ticks
+	 * \return non-zero if complete
+	 */
+	int (*update)(struct mlk_action *self, unsigned int ticks);
+
+	/**
+	 * (optional)
+	 *
+	 * Draw the action.
+	 *
+	 * \param self this action
+	 */
+	void (*draw)(struct mlk_action *self);
+
+	/**
+	 * (optional)
+	 *
+	 * Terminate the action.
+	 *
+	 * In contrast to finish, this function should be called after the
+	 * action was considered complete.
+	 *
+	 * \param self this action
+	 */
+	void (*end)(struct mlk_action *self);
+
+	/**
+	 * (optional)
+	 *
+	 * Dispose resources allocated by/for the action.
+	 *
+	 * \param self this action
+	 */
 	void (*finish)(struct mlk_action *);
 };
 
 MLK_CORE_BEGIN_DECLS
 
-void
-mlk_action_start(struct mlk_action *);
-
+/**
+ * Invoke ::mlk_action::start function if not null.
+ *
+ * \pre action != NULL
+ * \param action the action
+ */
 void
-mlk_action_handle(struct mlk_action *, const union mlk_event *);
+mlk_action_start(struct mlk_action *action);
 
-int
-mlk_action_update(struct mlk_action *, unsigned int);
+/**
+ * Invoke ::mlk_action::handle function if not null.
+ *
+ * \pre action != NULL
+ * \param action the action
+ * \param event the event
+ */
+void
+mlk_action_handle(struct mlk_action *action, const union mlk_event *event);
 
-void
-mlk_action_draw(struct mlk_action *);
+/**
+ * Invoke ::mlk_action::update function if not null.
+ *
+ * \pre action != NULL
+ * \param action the action
+ * \param ticks frame ticks
+ */
+int
+mlk_action_update(struct mlk_action *action, unsigned int ticks);
 
+/**
+ * Invoke ::mlk_action::draw function if not null.
+ *
+ * \pre action != NULL
+ * \param action the action
+ */
 void
-mlk_action_end(struct mlk_action *);
+mlk_action_draw(struct mlk_action *action);
 
+/**
+ * Invoke ::mlk_action::end function if not null.
+ *
+ * \pre action != NULL
+ * \param action the action
+ */
 void
-mlk_action_finish(struct mlk_action *);
+mlk_action_end(struct mlk_action *action);
+
+/**
+ * Invoke ::mlk_action::finish function if not null.
+ *
+ * \pre action != NULL
+ * \param action the action
+ */
+void
+mlk_action_finish(struct mlk_action *action);
 
 MLK_CORE_END_DECLS
 
--- a/libmlk-core/mlk/core/alloc.c	Fri Mar 03 19:45:00 2023 +0100
+++ b/libmlk-core/mlk/core/alloc.c	Sat Mar 04 08:52:57 2023 +0100
@@ -1,5 +1,5 @@
 /*
- * alloc.h -- custom allocators
+ * alloc.c -- memory allocators
  *
  * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr>
  *
--- a/libmlk-core/mlk/core/alloc.h	Fri Mar 03 19:45:00 2023 +0100
+++ b/libmlk-core/mlk/core/alloc.h	Sat Mar 04 08:52:57 2023 +0100
@@ -1,5 +1,5 @@
 /*
- * alloc.h -- custom allocators
+ * alloc.h -- memory allocators
  *
  * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr>
  *
@@ -19,18 +19,62 @@
 #ifndef MLK_CORE_ALLOC_H
 #define MLK_CORE_ALLOC_H
 
+/**
+ * \file mlk/core/alloc.h
+ * \brief Memory allocators.
+ *
+ * This module provides function to dynamically allocate data on the heap.
+ *
+ * ## Synopsis
+ *
+ * Most of the Molko's Engine API does not allocate data except in very few
+ * cases, otherwise this module is used each time it is required.
+ *
+ * ## Pointer block
+ *
+ * Data allocated by this module isn't a simple pointer to the region data but
+ * a custom block data that holds the size of the element and the number of it.
+ * This has been designed in the sense that reallocating data is easier for the
+ * caller as it is not required to pass the data length along.
+ *
+ * An allocated blocks looks like this:
+ *
+ * | Type              | Description                 |
+ * |-------------------|-----------------------------|
+ * | `size_t`          | Number of items allocated   |
+ * | `size_t`          | Size of individual elements |
+ * | `unsigned char *` | User data                   |
+ *
+ * The structure is allocated using the [flexible array member][fam] to avoid
+ * allocating data twice.
+ *
+ * Example:
+ *
+ * Allocating three ints with `int *ptr = mlk_alloc_new(3, sizeof (int))` will
+ * create a block as following:
+ *
+ * | Type                      | Description                 |
+ * |---------------------------|-----------------------------|
+ * | `size_t` = 3              | Number of items allocated   |
+ * | `size_t` = `sizeof (int)` | Size of individual elements |
+ * | `unsigned char *`         | `int[3]`                    |
+ *
+ * Finally, calling `mlk_alloc_renew(ptr, 6)` will extend the memory for three
+ * more ints.
+ *
+ * [fam]: https://en.wikipedia.org/wiki/Flexible_array_member
+ */
+
 #include <stddef.h>
 
 #include "core.h"
 
-/* Custom allocator. */
 struct mlk_alloc_funcs {
 	void *(*alloc)(size_t);
 	void *(*realloc)(void *, size_t);
 	void (*free)(void *);
 };
 
-/* Minimalist growable array for loading data. */
 struct mlk_alloc_pool {
 	void *data;
 	size_t elemsize;
@@ -41,7 +85,6 @@
 
 MLK_CORE_BEGIN_DECLS
 
-/* allocator functions. */
 void
 mlk_alloc_set(const struct mlk_alloc_funcs *);
 
--- a/tests/test-action-script.c	Fri Mar 03 19:45:00 2023 +0100
+++ b/tests/test-action-script.c	Sat Mar 04 08:52:57 2023 +0100
@@ -16,10 +16,11 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <mlk/core/action-script.h>
 #include <mlk/core/action.h>
 #include <mlk/core/err.h>
 #include <mlk/core/event.h>
-#include <mlk/core/action-script.h>
+#include <mlk/core/util.h>
 
 #include <dt.h>
 
@@ -97,14 +98,24 @@
 static void
 test_basics_init(void)
 {
-	struct mlk_action_script sc;
 	struct mlk_action *actions[10];
+	struct mlk_action_script sc = {
+		.actions = actions,
+		.actionsz = MLK_UTIL_SIZE(actions)
+	};
+
+	mlk_action_script_init(&sc);
 
-	mlk_action_script_init(&sc, actions, 10);
+	DT_EQ_SIZE(sc.actionsz, 10U);
+	DT_EQ_SIZE(sc.length, 0U);
+	DT_EQ_SIZE(sc.current, 0U);
 
-	DT_EQ_SIZE(sc.len, 0U);
-	DT_EQ_SIZE(sc.cap, 10U);
-	DT_EQ_SIZE(sc.cur, 0U);
+	mlk_action_script_finish(&sc);
+
+	DT_EQ_PTR(sc.actions, actions);
+	DT_EQ_SIZE(sc.actionsz, 10U);
+	DT_EQ_SIZE(sc.length, 0U);
+	DT_EQ_SIZE(sc.current, 0U);
 }
 
 static void
@@ -112,27 +123,30 @@
 {
 	struct mlk_action actions[4] = {0};
 	struct mlk_action *array[3] = {0};
-	struct mlk_action_script sc = {0};
+	struct mlk_action_script sc = {
+		.actions = array,
+		.actionsz = MLK_UTIL_SIZE(array)
+	};
 
-	mlk_action_script_init(&sc, array, 3);
+	mlk_action_script_init(&sc);
 
 	DT_ASSERT(mlk_action_script_append(&sc, &actions[0]) == 0);
-	DT_EQ_SIZE(sc.len, 1U);
-	DT_EQ_SIZE(sc.cap, 3U);
-	DT_EQ_SIZE(sc.cur, 0U);
+	DT_EQ_SIZE(sc.actionsz, 3U);
+	DT_EQ_SIZE(sc.length, 1U);
+	DT_EQ_SIZE(sc.current, 0U);
 	DT_EQ_PTR(sc.actions[0], &actions[0]);
 
 	DT_ASSERT(mlk_action_script_append(&sc, &actions[1]) == 0);
-	DT_EQ_SIZE(sc.len, 2U);
-	DT_EQ_SIZE(sc.cap, 3U);
-	DT_EQ_SIZE(sc.cur, 0U);
+	DT_EQ_SIZE(sc.actionsz, 3U);
+	DT_EQ_SIZE(sc.length, 2U);
+	DT_EQ_SIZE(sc.current, 0U);
 	DT_EQ_PTR(sc.actions[0], &actions[0]);
 	DT_EQ_PTR(sc.actions[1], &actions[1]);
 
 	DT_ASSERT(mlk_action_script_append(&sc, &actions[2]) == 0);
-	DT_EQ_SIZE(sc.len, 3U);
-	DT_EQ_SIZE(sc.cap, 3U);
-	DT_EQ_SIZE(sc.cur, 0U);
+	DT_EQ_SIZE(sc.actionsz, 3U);
+	DT_EQ_SIZE(sc.length, 3U);
+	DT_EQ_SIZE(sc.current, 0U);
 	DT_EQ_PTR(sc.actions[0], &actions[0]);
 	DT_EQ_PTR(sc.actions[1], &actions[1]);
 	DT_EQ_PTR(sc.actions[2], &actions[2]);
@@ -141,6 +155,11 @@
 	DT_ASSERT(mlk_action_script_append(&sc, &actions[3]) == MLK_ERR_NO_MEM);
 
 	mlk_action_script_finish(&sc);
+
+	DT_EQ_PTR(sc.actions, array);
+	DT_EQ_SIZE(sc.actionsz, 3U);
+	DT_EQ_SIZE(sc.length, 0U);
+	DT_EQ_SIZE(sc.current, 0U);
 }
 
 static void
@@ -156,16 +175,19 @@
 	};
 
 	struct mlk_action *array[3] = {0};
-	struct mlk_action_script sc = {0};
+	struct mlk_action_script sc = {
+		.actions = array,
+		.actionsz = MLK_UTIL_SIZE(array)
+	};
 
-	mlk_action_script_init(&sc, array, 3);
+	mlk_action_script_init(&sc);
 
 	DT_ASSERT(mlk_action_script_append(&sc, &table[0].act) == 0);
 	DT_ASSERT(mlk_action_script_append(&sc, &table[1].act) == 0);
 	DT_ASSERT(mlk_action_script_append(&sc, &table[2].act) == 0);
 
 	/* [0] */
-	mlk_action_script_handle(&sc, &(union mlk_event){0});
+	mlk_action_script_handle(&sc, &(const union mlk_event){0});
 	DT_EQ_INT(table[0].inv.handle, 1);
 	DT_EQ_INT(table[0].inv.update, 0);
 	DT_EQ_INT(table[0].inv.draw, 0);
@@ -238,9 +260,12 @@
 	};
 
 	struct mlk_action *array[3];
-	struct mlk_action_script sc = {0};
+	struct mlk_action_script sc = {
+		.actions = array,
+		.actionsz = MLK_UTIL_SIZE(array)
+	};
 
-	mlk_action_script_init(&sc, array, 3);
+	mlk_action_script_init(&sc);
 
 	DT_ASSERT(mlk_action_script_append(&sc, &table[0].act) == 0);
 	DT_ASSERT(mlk_action_script_append(&sc, &table[1].act) == 0);
@@ -351,9 +376,12 @@
 	};
 
 	struct mlk_action *array[3];
-	struct mlk_action_script sc = {0};
+	struct mlk_action_script sc = {
+		.actions = array,
+		.actionsz = MLK_UTIL_SIZE(array)
+	};
 
-	mlk_action_script_init(&sc, array, 3);
+	mlk_action_script_init(&sc);
 
 	DT_ASSERT(mlk_action_script_append(&sc, &table[0].act) == 0);
 	DT_ASSERT(mlk_action_script_append(&sc, &table[1].act) == 0);
@@ -431,9 +459,12 @@
 	};
 
 	struct mlk_action *array[3];
-	struct mlk_action_script sc = {0};
+	struct mlk_action_script sc = {
+		.actions = array,
+		.actionsz = MLK_UTIL_SIZE(array)
+	};
 
-	mlk_action_script_init(&sc, array, 3);
+	mlk_action_script_init(&sc);
 
 	DT_ASSERT(mlk_action_script_append(&sc, &table[0].act) == 0);
 	DT_ASSERT(mlk_action_script_append(&sc, &table[1].act) == 0);