diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 0ae3b24578b..f491deb350e 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -417,7 +417,8 @@ MODULE_GROUPING = { BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8') # '2.83.0 Beta' or '2.83.0' or '2.83.1' -BLENDER_VERSION_DOTS = bpy.app.version_string +BLENDER_VERSION_STRING = bpy.app.version_string +BLENDER_VERSION_DOTS = "%d.%d" % (bpy.app.version[0], bpy.app.version[1]) if BLENDER_REVISION != "Unknown": # SHA1 Git hash @@ -1724,11 +1725,11 @@ def write_sphinx_conf_py(basepath): fw("import sys, os\n\n") fw("extensions = ['sphinx.ext.intersphinx']\n\n") fw("intersphinx_mapping = {'blender_manual': ('https://docs.blender.org/manual/en/dev/', None)}\n\n") - fw("project = 'Blender %s Python API'\n" % BLENDER_VERSION_DOTS) + fw("project = 'Blender %s Python API'\n" % BLENDER_VERSION_STRING) fw("master_doc = 'index'\n") fw("copyright = u'Blender Foundation'\n") - fw("version = '%s'\n" % BLENDER_VERSION_HASH) - fw("release = '%s'\n" % BLENDER_VERSION_HASH) + fw("version = '%s'\n" % BLENDER_VERSION_DOTS) + fw("release = '%s'\n" % BLENDER_VERSION_DOTS) # Quiet file not in table-of-contents warnings. fw("exclude_patterns = [\n") @@ -1749,6 +1750,7 @@ except ModuleNotFoundError: fw("if html_theme == 'sphinx_rtd_theme':\n") fw(" html_theme_options = {\n") + fw(" 'display_version': False\n") # fw(" 'analytics_id': '',\n") # fw(" 'collapse_navigation': True,\n") fw(" 'sticky_navigation': False,\n") @@ -1765,10 +1767,15 @@ except ModuleNotFoundError: fw("html_show_search_summary = True\n") fw("html_split_index = True\n") fw("html_static_path = ['static']\n") + fw("templates_path = ['templates']\n") + fw("html_context = {'commit': '%s'}\n" % BLENDER_VERSION_HASH) fw("html_extra_path = ['static/favicon.ico', 'static/blender_logo.svg']\n") fw("html_favicon = 'static/favicon.ico'\n") fw("html_logo = 'static/blender_logo.svg'\n") fw("html_last_updated_fmt = '%m/%d/%Y'\n\n") + fw("if html_theme == 'sphinx_rtd_theme':\n") + fw(" html_css_files = ['css/version_switch.css']\n") + fw(" html_js_files = ['js/version_switch.js']\n") # needed for latex, pdf gen fw("latex_elements = {\n") @@ -2125,6 +2132,9 @@ def copy_theme_assets(basepath): shutil.copytree(os.path.join(SCRIPT_DIR, "static"), os.path.join(basepath, "static"), copy_function=shutil.copy) + shutil.copytree(os.path.join(SCRIPT_DIR, "templates"), + os.path.join(basepath, "templates"), + copy_function=shutil.copy) def rna2sphinx(basepath): diff --git a/doc/python_api/static/css/version_switch.css b/doc/python_api/static/css/version_switch.css new file mode 100644 index 00000000000..360ff2eea0e --- /dev/null +++ b/doc/python_api/static/css/version_switch.css @@ -0,0 +1,127 @@ +/* Override RTD theme */ +.rst-versions { + border-top: 0px; + overflow: visible; +} +.version-btn.vdeact { + cursor: default; + color: dimgray; +} + +.version-btn.vdeact::after { + content: ""; +} +#versionwrap { + display: flex; + padding-top: 2px; + font-size: 90%; + justify-content: center; + flex-wrap: wrap; +} +.version-btn { + display: inline-block; + background-color: #272525; + width: 140px; + text-align: center; + padding: 3px 10px; + margin: 0px 5px 4px; + vertical-align: middle; + color: #27AE60; + border: solid 1px #444444; + border-radius: 3px; + cursor: pointer; + z-index: 400; + transition: border-color 0.4s; +} +.version-btn::after { + content:"\f0d8"; + display: inline; + font: normal normal normal 16px/1 FontAwesome; + color: #8d8c8c; + vertical-align: top; + padding-left: 0.5em; +} +.version-btn-open::after { + color: gray; +} +.version-btn:hover, .version-btn:focus { + border-color: #525252; +} +.version-btn-open { + color: gray; + border: solid 1px gray; +} +.version-btn.wait { + cursor: wait; +} +.version-btn.disabled { + cursor: not-allowed; + color: dimgray; +} +.version-dialog { + display: none; + position: absolute; + bottom: 28px; + width: 140px; + margin: 0 5px; + padding-bottom: 4px; + background-color: #0003; + border-radius: 3px; + box-shadow: 0 0 6px #000C; + z-index: 999; + max-height: calc(100vh - 30px); + overflow-y: auto; + cursor: default; +} +.version-title { + padding: 5px; + color: black; + text-align: center; + font-size: 102%; + background-color: #27ae60; + border-bottom: solid 1.5px #444; +} +.version-list { + margin-bottom: 4px; + text-align: center; + background-color: #000C; + border: solid 1px gray; + border-radius: 0px 0px 3px 3px; +} +.version-list a, .version-list span, .version-list li { + position: relative; + display: block; + font-size: 98%; + line-height: 1.15; + width: 100%; + margin: 0; + padding: 4px 0px; + color: #404040; +} +.version-list li { + background-color: #ede9e9; + color: #404040; + padding: 1px; +} +.version-list li:hover, .version-list li a:focus { + background-color: #b9cfda; +} +.version-list li.selected, .version-list li.selected:hover { + background-color: #8d8c8c; +} +.version-list li.selected span { + cursor: default; + outline-color: red; +} +.version-arrow { + position: absolute; + width: 8px; + height: 8px; + left: 50%; + bottom: 4px; + margin-left: -4px; + transform: rotate(225deg); + background: #ede9e9; + border: 1px solid gray; + border-width: 1px 0 0 1px; +} diff --git a/doc/python_api/static/js/version_switch.js b/doc/python_api/static/js/version_switch.js new file mode 100644 index 00000000000..88468b163e4 --- /dev/null +++ b/doc/python_api/static/js/version_switch.js @@ -0,0 +1,323 @@ +(function() { // switch: v1.2 +"use strict"; + +var versionsFileUrl = "https://docs.blender.org/versions.json" + +var all_versions; + +var Popover = function() { + function Popover(id) + { + this.isOpen = false; + this.type = (id === "version-popover"); + this.$btn = $('#' + id); + this.$dialog = this.$btn.next(); + this.$list = this.$dialog.children("ul"); + this.sel = null; + this.beforeInit(); + } + + Popover.prototype = { + beforeInit : function() { + var that = this; + this.$btn.on("click", function(e) { + that.init(); + e.preventDefault(); + e.stopPropagation(); + }); + this.$btn.on("keydown", function(e) { + if (that.btnKeyFilter(e)) { + that.init(); + e.preventDefault(); + e.stopPropagation(); + } + }); + }, + init : function() { + this.$btn.off("click"); + this.$btn.off("keydown"); + + if (all_versions === undefined) { + this.$btn.addClass("wait"); + this.loadVL(this); + } + else { + this.afterLoad(); + } + }, + loadVL : function(that) { + $.getJSON(versionsFileUrl, function(data) { + all_versions = data; + that.afterLoad(); + return true; + }).fail(function() { + console.log("Version Switch Error: versions.json could not be loaded."); + that.$btn.addClass("disabled"); + return false; + }); + }, + afterLoad : function() { + var release = DOCUMENTATION_OPTIONS.VERSION; + const m = release.match(/\d\.\d+/g); + if (m) { + release = m[0]; + } + + this.warnOld(release, all_versions); + + var version = this.getNamed(release); + var list = this.buildList(version); + + this.$list.children(":first-child").remove(); + this.$list.append(list); + var that = this; + this.$list.on("keydown", function(e) { + that.keyMove(e); + }); + + this.$btn.removeClass("wait"); + this.btnOpenHandler(); + this.$btn.on("mousedown", function(e) { + that.btnOpenHandler(); + e.preventDefault() + }); + this.$btn.on("keydown", function(e) { + if (that.btnKeyFilter(e)) { + that.btnOpenHandler(); + } + }); + }, + warnOld : function(release, all_versions) { + // Note this is effectively disabled now, two issues must fixed: + // * versions.js does not contain a current entry, because that leads to + // duplicate version numbers in the menu. These need to be deduplicated. + // * It only shows the warning after opening the menu to switch version + // when versions.js is loaded. This is too late to be useful. + var current = all_versions.current + if (!current) + { + // console.log("Version Switch Error: no 'current' in version.json."); + return; + } + const m = current.match(/\d\.\d+/g); + if (m) { + current = parseFloat(m[0]); + } + if (release < current) { + var currentURL = window.location.pathname.replace(release, current); + var warning = $('
Note
' + + '' + + 'You are not using the most up to date version of the documentation. ' + + ' is the newest version.' + + '
' + + '