feat: godot-engine-source-4.3-stable
16
engine/scene/theme/SCsub
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
|
||||
import default_theme_builders
|
||||
|
||||
env.add_source_files(env.scene_sources, "*.cpp")
|
||||
|
||||
SConscript("icons/SCsub")
|
||||
|
||||
env.Depends("#scene/theme/default_font.gen.h", "#thirdparty/fonts/OpenSans_SemiBold.woff2")
|
||||
env.CommandNoCache(
|
||||
"#scene/theme/default_font.gen.h",
|
||||
"#thirdparty/fonts/OpenSans_SemiBold.woff2",
|
||||
env.Run(default_theme_builders.make_fonts_header),
|
||||
)
|
||||
1277
engine/scene/theme/default_theme.cpp
Normal file
39
engine/scene/theme/default_theme.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/**************************************************************************/
|
||||
/* default_theme.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DEFAULT_THEME_H
|
||||
#define DEFAULT_THEME_H
|
||||
|
||||
#include "scene/resources/theme.h"
|
||||
|
||||
void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale);
|
||||
void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, TextServer::FontAntialiasing p_font_antialiased = TextServer::FONT_ANTIALIASING_GRAY, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
|
||||
|
||||
#endif // DEFAULT_THEME_H
|
||||
30
engine/scene/theme/default_theme_builders.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"""Functions used to generate source files during build time"""
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
|
||||
def make_fonts_header(target, source, env):
|
||||
dst = str(target[0])
|
||||
|
||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
||||
g.write("#ifndef _DEFAULT_FONTS_H\n")
|
||||
g.write("#define _DEFAULT_FONTS_H\n")
|
||||
|
||||
# Saving uncompressed, since FreeType will reference from memory pointer.
|
||||
for i in range(len(source)):
|
||||
file = str(source[i])
|
||||
with open(file, "rb") as f:
|
||||
buf = f.read()
|
||||
|
||||
name = os.path.splitext(os.path.basename(file))[0]
|
||||
|
||||
g.write("static const int _font_" + name + "_size = " + str(len(buf)) + ";\n")
|
||||
g.write("static const unsigned char _font_" + name + "[] = {\n")
|
||||
for j in range(len(buf)):
|
||||
g.write("\t" + str(buf[j]) + ",\n")
|
||||
|
||||
g.write("};\n")
|
||||
|
||||
g.write("#endif")
|
||||
19
engine/scene/theme/icons/SCsub
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
|
||||
import default_theme_icons_builders
|
||||
|
||||
env["BUILDERS"]["MakeDefaultThemeIconsBuilder"] = Builder(
|
||||
action=env.Run(default_theme_icons_builders.make_default_theme_icons_action),
|
||||
suffix=".h",
|
||||
src_suffix=".svg",
|
||||
)
|
||||
|
||||
# Default theme icons
|
||||
icon_sources = Glob("*.svg")
|
||||
|
||||
env.Alias(
|
||||
"default_theme_icons",
|
||||
[env.MakeDefaultThemeIconsBuilder("#scene/theme/default_theme_icons.gen.h", icon_sources)],
|
||||
)
|
||||
1
engine/scene/theme/icons/add.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6z"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
1
engine/scene/theme/icons/arrow_down.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#b2b2b2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".45" stroke-width="2" d="m5 7 3 3 3-3"/></svg>
|
||||
|
After Width: | Height: | Size: 207 B |
1
engine/scene/theme/icons/arrow_left.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#b2b2b2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".45" stroke-width="2" d="m9 11-3-3 3-3"/></svg>
|
||||
|
After Width: | Height: | Size: 208 B |
1
engine/scene/theme/icons/arrow_right.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#b2b2b2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".45" stroke-width="2" d="m6 11 3-3-3-3"/></svg>
|
||||
|
After Width: | Height: | Size: 208 B |
1
engine/scene/theme/icons/bookmark.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#fefffe" fill-opacity=".85"><path d="M14.5 1.5h-13v13L8 9.25l6.5 5.25z"/><path stroke="#fefffe" stroke-linejoin="round" stroke-opacity=".85" d="M14.5 1.5h-13v13L8 9.25l6.5 5.25z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 262 B |
1
engine/scene/theme/icons/breakpoint.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="7" fill="#ff5d5d" fill-opacity=".5"/></svg>
|
||||
|
After Width: | Height: | Size: 131 B |
1
engine/scene/theme/icons/checked.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect width="14" height="14" x="1" y="1" fill="#fff" fill-opacity=".75" rx="2.333"/><path fill="#1a1a1a" d="m11.5 3.75-5.6 5.6-1.7-1.7-1.5 1.5 3.2 3.2 7.1-7.1z"/></svg>
|
||||
|
After Width: | Height: | Size: 231 B |
1
engine/scene/theme/icons/checked_disabled.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect width="14" height="14" x="1" y="1" fill="#fff" fill-opacity=".37" rx="2.333"/><path fill="#1a1a1a" fill-opacity=".5" d="m11.5 3.75-5.6 5.6-1.7-1.7-1.5 1.5 3.2 3.2 7.1-7.1z"/></svg>
|
||||
|
After Width: | Height: | Size: 249 B |
1
engine/scene/theme/icons/close.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" fill-opacity=".75" d="m1 3 2-2 5 5 5-5 2 2-5 5 5 5-2 2-5-5-5 5-2-2 5-5z"/></svg>
|
||||
|
After Width: | Height: | Size: 161 B |
1
engine/scene/theme/icons/close_hl.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" d="m1 3 2-2 5 5 5-5 2 2-5 5 5 5-2 2-5-5-5 5-2-2 5-5z"/></svg>
|
||||
|
After Width: | Height: | Size: 142 B |
1
engine/scene/theme/icons/color_picker_bar_arrow.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 20"><path fill="#b2b2b2" stroke="#b2b2b2" stroke-linejoin="round" d="m3.564 15.218h8.872l-4.436-4.436z"/></svg>
|
||||
|
After Width: | Height: | Size: 190 B |
1
engine/scene/theme/icons/color_picker_cursor.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="5.5" fill="none" stroke="#fff"/><circle cx="8" cy="8" r="4.5" fill="none" stroke="#000"/></svg>
|
||||
|
After Width: | Height: | Size: 183 B |
1
engine/scene/theme/icons/color_picker_overbright.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" stroke="#000003" d="m.5.5v10l10-10z"/></svg>
|
||||
|
After Width: | Height: | Size: 125 B |
1
engine/scene/theme/icons/color_picker_pipette.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" d="M10 3a1 1 0 0 0-4 0v2H5v2h1v5c0 .712.36 1.372 1 1.73V15h2v-1.27c.618-.36 1-1 1-1.73V7h1V5h-1V3zM7 7h2v5a1 1 0 0 1-2 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 214 B |
61
engine/scene/theme/icons/default_theme_icons_builders.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"""Functions used to generate source files during build time"""
|
||||
|
||||
import os
|
||||
from io import StringIO
|
||||
|
||||
|
||||
# See also `editor/icons/editor_icons_builders.py`.
|
||||
def make_default_theme_icons_action(target, source, env):
|
||||
dst = str(target[0])
|
||||
svg_icons = [str(x) for x in source]
|
||||
|
||||
with StringIO() as icons_string, StringIO() as s:
|
||||
for f in svg_icons:
|
||||
fname = str(f)
|
||||
|
||||
icons_string.write('\t"')
|
||||
|
||||
with open(fname, "rb") as svgf:
|
||||
b = svgf.read(1)
|
||||
while len(b) == 1:
|
||||
icons_string.write("\\" + str(hex(ord(b)))[1:])
|
||||
b = svgf.read(1)
|
||||
|
||||
icons_string.write('"')
|
||||
if fname != svg_icons[-1]:
|
||||
icons_string.write(",")
|
||||
icons_string.write("\n")
|
||||
|
||||
s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n\n")
|
||||
s.write('#include "modules/modules_enabled.gen.h"\n\n')
|
||||
s.write("#ifndef _DEFAULT_THEME_ICONS_H\n")
|
||||
s.write("#define _DEFAULT_THEME_ICONS_H\n")
|
||||
s.write("static const int default_theme_icons_count = {};\n\n".format(len(svg_icons)))
|
||||
s.write("#ifdef MODULE_SVG_ENABLED\n")
|
||||
s.write("static const char *default_theme_icons_sources[] = {\n")
|
||||
s.write(icons_string.getvalue())
|
||||
s.write("};\n")
|
||||
s.write("#endif // MODULE_SVG_ENABLED\n\n")
|
||||
s.write("static const char *default_theme_icons_names[] = {\n")
|
||||
|
||||
index = 0
|
||||
for f in svg_icons:
|
||||
fname = str(f)
|
||||
|
||||
# Trim the `.svg` extension from the string.
|
||||
icon_name = os.path.basename(fname)[:-4]
|
||||
|
||||
s.write('\t"{0}"'.format(icon_name))
|
||||
|
||||
if fname != svg_icons[-1]:
|
||||
s.write(",")
|
||||
s.write("\n")
|
||||
|
||||
index += 1
|
||||
|
||||
s.write("};\n")
|
||||
|
||||
s.write("#endif\n")
|
||||
|
||||
with open(dst, "w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(s.getvalue())
|
||||
1
engine/scene/theme/icons/error_icon.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#ff5d5d" d="M2 1v8.586l1.293-1.293a1 1 0 0 1 1.414 0L7 10.587l2.293-2.293a1 1 0 0 1 1.414 0L13 10.586l1-1V6H9V1H2zm8 0v4h4zm-6 9.414-2 2V15h12v-2.586l-.293.293a1 1 0 0 1-1.414 0L10 10.414l-2.293 2.293a1 1 0 0 1-1.414 0L4 10.414z"/></svg>
|
||||
|
After Width: | Height: | Size: 312 B |
1
engine/scene/theme/icons/file.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" d="M2 1v14h12V6H9V1zm8 0v4h4z"/></svg>
|
||||
|
After Width: | Height: | Size: 122 B |
1
engine/scene/theme/icons/folder.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" d="M2 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1h-4a1 1 0 0 1-1-1V3a1 1 0 0 0-1-1z"/></svg>
|
||||
|
After Width: | Height: | Size: 198 B |
1
engine/scene/theme/icons/folder_create.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" d="M2 3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8v-1H8v-4h2V8h4v2h1V7a1 1 0 0 0-1-1h-4a1 1 0 0 1-1-1V4a1 1 0 0 0-1-1Z"/><path fill="#fefffe" d="M13 13h2v-2h-2V9h-2v2H9v2h2v2h2z"/></svg>
|
||||
|
After Width: | Height: | Size: 260 B |
1
engine/scene/theme/icons/folder_up.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#b2b2b2" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 11V4m4 4L8 4 4 8"/></svg>
|
||||
|
After Width: | Height: | Size: 193 B |
1
engine/scene/theme/icons/graph_port.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><circle cx="5" cy="5" r="5" fill="#fff"/><circle cx="5" cy="5" r="3.667" fill="#b2b2b2" fill-opacity=".65"/></svg>
|
||||
|
After Width: | Height: | Size: 177 B |
1
engine/scene/theme/icons/grid_layout.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="none" stroke-width="1.3"><path stroke="#fefffe" stroke-linejoin="round" d="M1.87 6.541h2.917v2.917H1.87zm4.666 0h2.917v2.917H6.536zm4.666 0h2.917v2.917h-2.917z"/><path stroke="#e0e0e0" stroke-linecap="round" stroke-opacity=".65" d="m5.432 1.112-1.95 1.95 1.95 1.95m-1.95-1.95h9.386m-2.137 8.05 1.95 1.95-1.95 1.95m-7.437-1.95h9.387"/></g></svg>
|
||||
|
After Width: | Height: | Size: 416 B |
1
engine/scene/theme/icons/grid_minimap.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" stroke-linejoin="round" stroke-miterlimit="2"><path fill="#b2b2b2" fill-opacity=".65" d="M14 2.199v2.615l-2.625 1.313V3.512zM2 6.264l2.625 1.312v2.551L2 8.814zm12 0v2.55l-2.625 1.313V7.576zM6 7.719h4v2.64H6zm-4 2.56 2.625 1.313v2.521L2 12.801zm12 0v2.522l-2.625 1.312v-2.521zm-8 1.455h4v2.641H6zm4-8.109v2.734H5.844s-.749.647-.875.641c-.131-.007-1.51-1.456-1.51-1.456L2 4.814V2.199l.117.06s-.064-.775.424-1.216L1.279.441A.626.626 0 0 0 .375 1v12c0 .237.134.453.346.559l4 2a.626.626 0 0 0 .279.066h6a.626.626 0 0 0 .279-.066l4-2a.625.625 0 0 0 .346-.559V1a.625.625 0 0 0-.904-.559l-3.869 1.934H7.888s.084.624-.218 1.25z"/><path fill="#fefffe" d="M5 6.25c-4-3.5-2-6 0-6s4 2.5 0 6z"/></svg>
|
||||
|
After Width: | Height: | Size: 750 B |
1
engine/scene/theme/icons/grid_snap.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" fill-opacity=".65" d="M3 0v3H0v2h3v4H0v2h3v3h2V5h9V3h-3V0H9v3H5V0zm4 13v2h2v-2zm6 0v2h2v-2z"/><path fill="#fefffe" d="M7 11v2h2v-2a2 2 0 0 1 4 0v2h2v-2a4 4 0 0 0-8 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 259 B |
1
engine/scene/theme/icons/grid_toggle.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" fill-opacity=".65" d="M3 0v3H0v2h3v4H0v2h3v3h2V5h9V3h-3V0H9v3H5V0z"/><path fill="#e0e0e0" d="M11 6.62c-1.747 0-3.957 1.344-4.752 3.936a.683.69 0 00-.004.394C7.012 13.665 9.292 14.9 11 14.9c1.708 0 3.988-1.235 4.756-3.95a.683.69 0 000-.382C15.004 7.955 12.746 6.62 11 6.62zM11 8a2.733 2.76 0 012.733 2.76A2.733 2.76 0 0111 13.52a2.733 2.76 0 01-2.733-2.76A2.733 2.76 0 0111 8zm0 1.38a1.367 1.38 0 00-1.367 1.38A1.367 1.38 0 0011 12.14a1.367 1.38 0 001.367-1.38A1.367 1.38 0 0011 9.38z"/></svg>
|
||||
|
After Width: | Height: | Size: 576 B |
1
engine/scene/theme/icons/hslider_tick.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="4" height="16"><path fill="#fff" fill-opacity=".25" d="M1 0h2v16H1z"/></svg>
|
||||
|
After Width: | Height: | Size: 123 B |
1
engine/scene/theme/icons/hsplitter.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="48"><path fill="gray" fill-opacity=".65" d="M3.15 4v40h1.7V4z"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
1
engine/scene/theme/icons/indeterminate.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect width="14" height="14" x="1" y="1" fill="#fff" fill-opacity=".75" rx="2.333"/><path fill="#1a1a1a" d="m3 7h10v2h-10z"/></svg>
|
||||
|
After Width: | Height: | Size: 194 B |
1
engine/scene/theme/icons/indeterminate_disabled.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect width="14" height="14" x="1" y="1" fill="#fff" fill-opacity=".37" rx="2.333"/><path fill="#1a1a1a" fill-opacity=".5" d="m3 7h10v2h-10z"/></svg>
|
||||
|
After Width: | Height: | Size: 212 B |
1
engine/scene/theme/icons/line_edit_clear.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" fill-opacity=".75" d="m1 3 2-2 5 5 5-5 2 2-5 5 5 5-2 2-5-5-5 5-2-2 5-5z"/></svg>
|
||||
|
After Width: | Height: | Size: 161 B |
1
engine/scene/theme/icons/mini_checkerboard.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="gray" d="M0 0v8h8V0zm8 8v8h8V8z"/><path fill="#fff" d="M8 0v8h8V0zm0 8H0v8h8z"/></svg>
|
||||
|
After Width: | Height: | Size: 161 B |
1
engine/scene/theme/icons/option_button_arrow.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12"><path fill="none" stroke="#b2b2b2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".85" stroke-width="2" d="m2 4 4 4 4-4"/></svg>
|
||||
|
After Width: | Height: | Size: 207 B |
1
engine/scene/theme/icons/picker_shape_circle.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#eaeaea" d="M6.5 2.5a5.5 5.5 0 0 0 0 11 5.5 5.5 0 0 0 0-11m6.5 0h2v11h-2z"/></svg>
|
||||
|
After Width: | Height: | Size: 157 B |
1
engine/scene/theme/icons/picker_shape_rectangle.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#eaeaea" d="M.5 2.5h11v11H.5zm12 0h2v11h-2z"/></svg>
|
||||
|
After Width: | Height: | Size: 127 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="5.25" fill="none" stroke="#eaeaea" stroke-width="1.75"/><path fill="#eaeaea" d="M4.9 4.9h6.2v6.2H4.9z"/></svg>
|
||||
|
After Width: | Height: | Size: 198 B |
1
engine/scene/theme/icons/popup_menu_arrow_left.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="16"><path fill="none" stroke="#b2b2b2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".45" stroke-width="2" d="m5.5 11-3-3 3-3"/></svg>
|
||||
|
After Width: | Height: | Size: 209 B |
1
engine/scene/theme/icons/popup_menu_arrow_right.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="16"><path fill="none" stroke="#b2b2b2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".45" stroke-width="2" d="m2.5 11 3-3-3-3"/></svg>
|
||||
|
After Width: | Height: | Size: 209 B |
1
engine/scene/theme/icons/radio_checked.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="5.5" fill="#1a1a1a" stroke="#fff" stroke-opacity=".75" stroke-width="3"/></svg>
|
||||
|
After Width: | Height: | Size: 167 B |
1
engine/scene/theme/icons/radio_checked_disabled.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="7" fill="#fff" fill-opacity=".37"/><circle cx="8" cy="8" r="4" fill="#1a1a1a" fill-opacity=".5"/></svg>
|
||||
|
After Width: | Height: | Size: 191 B |
1
engine/scene/theme/icons/radio_unchecked.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="7" fill="#1a1a1a" fill-opacity=".5"/></svg>
|
||||
|
After Width: | Height: | Size: 131 B |
1
engine/scene/theme/icons/radio_unchecked_disabled.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="7" fill="#1a1a1a" fill-opacity=".25"/></svg>
|
||||
|
After Width: | Height: | Size: 132 B |
1
engine/scene/theme/icons/region_folded.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12"><path fill="#fff" d="M3 2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1zm2.75 7a1 1 0 0 1-1.414-1.414L5.922 6 4.336 4.414A1 1 0 0 1 5.75 3l2.293 2.293a1 1 0 0 1 0 1.414z"/></svg>
|
||||
|
After Width: | Height: | Size: 257 B |
1
engine/scene/theme/icons/region_unfolded.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12"><path fill="#fff" d="M10 3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1zM3 5.75a1 1 0 0 1 1.414-1.414L6 5.922l1.586-1.586A1 1 0 0 1 9 5.75L6.707 8.043a1 1 0 0 1-1.414 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 258 B |
1
engine/scene/theme/icons/reload.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" d="M5 8a4 4 0 1 1 4 4v2a6 6 0 1 0-6-6H1l3 4 3-4z"/></svg>
|
||||
|
After Width: | Height: | Size: 141 B |
1
engine/scene/theme/icons/resizer_nw.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#fefffe" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".65" stroke-width="2" d="M4 11V4h7"/><circle cx="7.5" cy="7.5" r="1.5" fill="#b2b2b2" fill-opacity=".65"/></svg>
|
||||
|
After Width: | Height: | Size: 273 B |
1
engine/scene/theme/icons/resizer_se.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#fefffe" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".65" stroke-width="2" d="M11 4v7H4"/><circle cx="7.5" cy="7.5" r="1.5" fill="#b2b2b2" fill-opacity=".65"/></svg>
|
||||
|
After Width: | Height: | Size: 273 B |
1
engine/scene/theme/icons/scroll_button_left.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="6" fill="#fefffe" fill-opacity=".75"/><path fill="none" stroke="#1a1a1a" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".65" stroke-width="2" d="m9 5-3 3 3 3"/></svg>
|
||||
|
After Width: | Height: | Size: 270 B |
1
engine/scene/theme/icons/scroll_button_left_hl.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="6" fill="#fefffe"/><path fill="none" stroke="#1a1a1a" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m9 5-3 3 3 3"/></svg>
|
||||
|
After Width: | Height: | Size: 230 B |
1
engine/scene/theme/icons/scroll_button_right.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="6" fill="#fefffe" fill-opacity=".75"/><path fill="none" stroke="#1a1a1a" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".65" stroke-width="2" d="m7 5 3 3-3 3"/></svg>
|
||||
|
After Width: | Height: | Size: 270 B |
1
engine/scene/theme/icons/scroll_button_right_hl.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="6" fill="#fefffe"/><path fill="none" stroke="#1a1a1a" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m7 5 3 3-3 3"/></svg>
|
||||
|
After Width: | Height: | Size: 230 B |
1
engine/scene/theme/icons/slider_grabber.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="7" fill="#fefefe" fill-opacity=".75"/></svg>
|
||||
|
After Width: | Height: | Size: 132 B |
1
engine/scene/theme/icons/slider_grabber_disabled.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="7" fill="#fefefe" fill-opacity=".37"/></svg>
|
||||
|
After Width: | Height: | Size: 132 B |
1
engine/scene/theme/icons/slider_grabber_hl.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="7" fill="#fefefe"/></svg>
|
||||
|
After Width: | Height: | Size: 113 B |
1
engine/scene/theme/icons/tabs_drop_mark.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="32"><path fill="#d3d3d3" d="m5 1h6v30h-6z"/></svg>
|
||||
|
After Width: | Height: | Size: 109 B |
1
engine/scene/theme/icons/tabs_menu.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" fill-opacity=".45" d="M8 0a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4z"/></svg>
|
||||
|
After Width: | Height: | Size: 214 B |
1
engine/scene/theme/icons/tabs_menu_hl.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" fill-opacity=".65" d="M8 0a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4z"/></svg>
|
||||
|
After Width: | Height: | Size: 214 B |
1
engine/scene/theme/icons/text_edit_ellipsis.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="8"><path fill="#fefffe" fill-opacity=".25" d="M4 0a4 4 0 0 0 0 8h6a4 4 0 0 0 0-8zM3 3a1 1 0 0 1 0 2 1 1 0 0 1 0-2zm4 0a1 1 0 0 1 0 2 1 1 0 0 1 0-2zm4 0a1 1 0 0 1 0 2 1 1 0 0 1 0-2z"/></svg>
|
||||
|
After Width: | Height: | Size: 248 B |
1
engine/scene/theme/icons/text_edit_space.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8"><circle cx="4" cy="4" r="1.5" fill="#b2b2b2" fill-opacity=".25"/></svg>
|
||||
|
After Width: | Height: | Size: 132 B |
1
engine/scene/theme/icons/text_edit_tab.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8"><path fill="#b2b2b2" fill-opacity=".25" d="M6 0v8h2V0zM1 0a1 1 0 0 0-.693 1.705L2.6 3.998.307 6.291A1 1 0 0 0 1.72 7.705l3-3a1 1 0 0 0 0-1.414l-3-3A1 1 0 0 0 1 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 232 B |
1
engine/scene/theme/icons/toggle_off.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16"><g fill-opacity=".5"><rect width="30" height="14" x="1" y="1" fill="#1a1a1a" rx="7"/><circle cx="8" cy="8" r="5" fill="#fff"/></g></svg>
|
||||
|
After Width: | Height: | Size: 199 B |
1
engine/scene/theme/icons/toggle_off_disabled.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16"><g fill-opacity=".25"><rect width="30" height="14" x="1" y="1" fill="#1a1a1a" rx="7"/><circle cx="8" cy="8" r="5" fill="#fff"/></g></svg>
|
||||
|
After Width: | Height: | Size: 200 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16"><g fill-opacity=".25"><rect width="30" height="14" x="1" y="1" fill="#1a1a1a" rx="7"/><circle cx="24" cy="8" r="5" fill="#fff"/></g></svg>
|
||||
|
After Width: | Height: | Size: 201 B |
1
engine/scene/theme/icons/toggle_off_mirrored.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16"><g fill-opacity=".5"><rect width="30" height="14" x="1" y="1" fill="#1a1a1a" rx="7"/><circle cx="24" cy="8" r="5" fill="#fff"/></g></svg>
|
||||
|
After Width: | Height: | Size: 200 B |
1
engine/scene/theme/icons/toggle_on.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16"><rect width="30" height="14" x="1" y="1" fill="#fff" fill-opacity=".75" rx="7"/><circle cx="24" cy="8" r="5" fill="#1a1a1a"/></svg>
|
||||
|
After Width: | Height: | Size: 194 B |
1
engine/scene/theme/icons/toggle_on_disabled.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16"><rect width="30" height="14" x="1" y="1" fill="#fff" fill-opacity=".37" rx="7"/><circle cx="24" cy="8" r="5" fill="#1a1a1a" fill-opacity=".5"/></svg>
|
||||
|
After Width: | Height: | Size: 212 B |
1
engine/scene/theme/icons/toggle_on_disabled_mirrored.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16"><rect width="30" height="14" x="1" y="1" fill="#fff" fill-opacity=".37" rx="7"/><circle cx="8" cy="8" r="5" fill="#1a1a1a" fill-opacity=".5"/></svg>
|
||||
|
After Width: | Height: | Size: 211 B |
1
engine/scene/theme/icons/toggle_on_mirrored.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16"><rect width="30" height="14" x="1" y="1" fill="#fff" fill-opacity=".75" rx="7"/><circle cx="8" cy="8" r="5" fill="#1a1a1a"/></svg>
|
||||
|
After Width: | Height: | Size: 193 B |
1
engine/scene/theme/icons/unchecked.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect width="14" height="14" x="1" y="1" fill="#1a1a1a" fill-opacity=".5" rx="2.333"/></svg>
|
||||
|
After Width: | Height: | Size: 155 B |
1
engine/scene/theme/icons/unchecked_disabled.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect width="14" height="14" x="1" y="1" fill="#1a1a1a" fill-opacity=".25" rx="2.333"/></svg>
|
||||
|
After Width: | Height: | Size: 156 B |
1
engine/scene/theme/icons/updown.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#fff" stroke-opacity=".75" stroke-width="2" d="m4 6 4-3.5L12 6m0 4-4 3.5L4 10"/></svg>
|
||||
|
After Width: | Height: | Size: 175 B |
1
engine/scene/theme/icons/visibility_visible.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b2b2b2" d="M8 2C5.443 2 2.209 3.948 1.045 7.705a1 1 0 0 0 0 .55C2.163 12.211 5.5 14 8 14s5.836-1.789 6.961-5.725a1 1 0 0 0 0-.55C13.861 3.935 10.554 2 8 2zm0 2a4 4 0 0 1 0 8 4 4 0 0 1 0-8zm0 2a2 2 0 0 0 0 4 2 2 0 0 0 0-4z"/></svg>
|
||||
|
After Width: | Height: | Size: 306 B |
1
engine/scene/theme/icons/vslider_tick.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="4"><path fill="#fff" fill-opacity=".25" d="M0 3V1h16v2z"/></svg>
|
||||
|
After Width: | Height: | Size: 123 B |
1
engine/scene/theme/icons/vsplitter.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="8"><path fill="none" stroke="gray" stroke-opacity=".65" stroke-width="1.7" d="M4 4h40"/></svg>
|
||||
|
After Width: | Height: | Size: 153 B |
1
engine/scene/theme/icons/zoom_less.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="8" fill="#b2b2b2" fill-opacity=".65"/><circle cx="8" cy="8" r="7" fill="#fefffe"/><path fill="#010001" d="M4 7h8v2H4z"/></svg>
|
||||
|
After Width: | Height: | Size: 214 B |
1
engine/scene/theme/icons/zoom_more.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="8" fill="#b2b2b2" fill-opacity=".65"/><circle cx="8" cy="8" r="7" fill="#fefffe"/><path fill="#010001" d="M7 4h2v3h3v2H9v3H7V9H4V7h3z"/></svg>
|
||||
|
After Width: | Height: | Size: 230 B |
1
engine/scene/theme/icons/zoom_reset.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="8" fill="#b2b2b2" fill-opacity=".65"/><circle cx="8" cy="8" r="7" fill="#fefffe"/><path fill="#010001" d="M8 4.166A1 1 0 0 1 9.526 5v7h-2V6.87l-1.445.962-1-1.6z"/></svg>
|
||||
|
After Width: | Height: | Size: 257 B |
512
engine/scene/theme/theme_db.cpp
Normal file
|
|
@ -0,0 +1,512 @@
|
|||
/**************************************************************************/
|
||||
/* theme_db.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "theme_db.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/main/node.h"
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/resources/font.h"
|
||||
#include "scene/resources/style_box.h"
|
||||
#include "scene/resources/texture.h"
|
||||
#include "scene/theme/default_theme.h"
|
||||
#include "servers/text_server.h"
|
||||
|
||||
// Default engine theme creation and configuration.
|
||||
|
||||
void ThemeDB::initialize_theme() {
|
||||
// Default theme-related project settings.
|
||||
|
||||
// Allow creating the default theme at a different scale to suit higher/lower base resolutions.
|
||||
float default_theme_scale = GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), 1.0);
|
||||
|
||||
String project_theme_path = GLOBAL_DEF_RST_BASIC(PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), "");
|
||||
String project_font_path = GLOBAL_DEF_RST_BASIC(PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.otf,*.ttf,*.woff,*.woff2,*.fnt,*.font,*.pfb,*.pfm", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), "");
|
||||
|
||||
TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), 1);
|
||||
TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), TextServer::HINTING_LIGHT);
|
||||
TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "gui/theme/default_font_subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), TextServer::SUBPIXEL_POSITIONING_AUTO);
|
||||
|
||||
const bool font_msdf = GLOBAL_DEF_RST("gui/theme/default_font_multichannel_signed_distance_field", false);
|
||||
const bool font_generate_mipmaps = GLOBAL_DEF_RST("gui/theme/default_font_generate_mipmaps", false);
|
||||
|
||||
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "gui/theme/lcd_subpixel_layout", PROPERTY_HINT_ENUM, "Disabled,Horizontal RGB,Horizontal BGR,Vertical RGB,Vertical BGR"), 1);
|
||||
ProjectSettings::get_singleton()->set_restart_if_changed("gui/theme/lcd_subpixel_layout", false);
|
||||
|
||||
// Attempt to load custom project theme and font.
|
||||
|
||||
if (!project_theme_path.is_empty()) {
|
||||
Ref<Theme> theme = ResourceLoader::load(project_theme_path);
|
||||
if (theme.is_valid()) {
|
||||
set_project_theme(theme);
|
||||
} else {
|
||||
ERR_PRINT("Error loading custom project theme '" + project_theme_path + "'");
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Font> project_font;
|
||||
if (!project_font_path.is_empty()) {
|
||||
project_font = ResourceLoader::load(project_font_path);
|
||||
if (project_font.is_valid()) {
|
||||
set_fallback_font(project_font);
|
||||
} else {
|
||||
ERR_PRINT("Error loading custom project font '" + project_font_path + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// Always generate the default theme to serve as a fallback for all required theme definitions.
|
||||
|
||||
if (RenderingServer::get_singleton()) {
|
||||
make_default_theme(default_theme_scale, project_font, font_subpixel_positioning, font_hinting, font_antialiasing, font_msdf, font_generate_mipmaps);
|
||||
}
|
||||
|
||||
_init_default_theme_context();
|
||||
}
|
||||
|
||||
void ThemeDB::initialize_theme_noproject() {
|
||||
if (RenderingServer::get_singleton()) {
|
||||
make_default_theme(1.0, Ref<Font>());
|
||||
}
|
||||
|
||||
_init_default_theme_context();
|
||||
}
|
||||
|
||||
void ThemeDB::finalize_theme() {
|
||||
if (!RenderingServer::get_singleton()) {
|
||||
WARN_PRINT("Finalizing theme when there is no RenderingServer is an error; check the order of operations.");
|
||||
}
|
||||
|
||||
_finalize_theme_contexts();
|
||||
default_theme.unref();
|
||||
|
||||
fallback_font.unref();
|
||||
fallback_icon.unref();
|
||||
fallback_stylebox.unref();
|
||||
}
|
||||
|
||||
// Global Theme resources.
|
||||
|
||||
void ThemeDB::set_default_theme(const Ref<Theme> &p_default) {
|
||||
default_theme = p_default;
|
||||
}
|
||||
|
||||
Ref<Theme> ThemeDB::get_default_theme() {
|
||||
return default_theme;
|
||||
}
|
||||
|
||||
void ThemeDB::set_project_theme(const Ref<Theme> &p_project_default) {
|
||||
project_theme = p_project_default;
|
||||
}
|
||||
|
||||
Ref<Theme> ThemeDB::get_project_theme() {
|
||||
return project_theme;
|
||||
}
|
||||
|
||||
// Universal fallback values for theme item types.
|
||||
|
||||
void ThemeDB::set_fallback_base_scale(float p_base_scale) {
|
||||
if (fallback_base_scale == p_base_scale) {
|
||||
return;
|
||||
}
|
||||
|
||||
fallback_base_scale = p_base_scale;
|
||||
emit_signal(SNAME("fallback_changed"));
|
||||
}
|
||||
|
||||
float ThemeDB::get_fallback_base_scale() {
|
||||
return fallback_base_scale;
|
||||
}
|
||||
|
||||
void ThemeDB::set_fallback_font(const Ref<Font> &p_font) {
|
||||
if (fallback_font == p_font) {
|
||||
return;
|
||||
}
|
||||
|
||||
fallback_font = p_font;
|
||||
emit_signal(SNAME("fallback_changed"));
|
||||
}
|
||||
|
||||
Ref<Font> ThemeDB::get_fallback_font() {
|
||||
return fallback_font;
|
||||
}
|
||||
|
||||
void ThemeDB::set_fallback_font_size(int p_font_size) {
|
||||
if (fallback_font_size == p_font_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
fallback_font_size = p_font_size;
|
||||
emit_signal(SNAME("fallback_changed"));
|
||||
}
|
||||
|
||||
int ThemeDB::get_fallback_font_size() {
|
||||
return fallback_font_size;
|
||||
}
|
||||
|
||||
void ThemeDB::set_fallback_icon(const Ref<Texture2D> &p_icon) {
|
||||
if (fallback_icon == p_icon) {
|
||||
return;
|
||||
}
|
||||
|
||||
fallback_icon = p_icon;
|
||||
emit_signal(SNAME("fallback_changed"));
|
||||
}
|
||||
|
||||
Ref<Texture2D> ThemeDB::get_fallback_icon() {
|
||||
return fallback_icon;
|
||||
}
|
||||
|
||||
void ThemeDB::set_fallback_stylebox(const Ref<StyleBox> &p_stylebox) {
|
||||
if (fallback_stylebox == p_stylebox) {
|
||||
return;
|
||||
}
|
||||
|
||||
fallback_stylebox = p_stylebox;
|
||||
emit_signal(SNAME("fallback_changed"));
|
||||
}
|
||||
|
||||
Ref<StyleBox> ThemeDB::get_fallback_stylebox() {
|
||||
return fallback_stylebox;
|
||||
}
|
||||
|
||||
void ThemeDB::get_native_type_dependencies(const StringName &p_base_type, List<StringName> *p_list) {
|
||||
ERR_FAIL_NULL(p_list);
|
||||
|
||||
// TODO: It may make sense to stop at Control/Window, because their parent classes cannot be used in
|
||||
// a meaningful way.
|
||||
StringName class_name = p_base_type;
|
||||
while (class_name != StringName()) {
|
||||
p_list->push_back(class_name);
|
||||
class_name = ClassDB::get_parent_class_nocheck(class_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Global theme contexts.
|
||||
|
||||
ThemeContext *ThemeDB::create_theme_context(Node *p_node, List<Ref<Theme>> &p_themes) {
|
||||
ERR_FAIL_COND_V(!p_node->is_inside_tree(), nullptr);
|
||||
ERR_FAIL_COND_V(theme_contexts.has(p_node), nullptr);
|
||||
ERR_FAIL_COND_V(p_themes.is_empty(), nullptr);
|
||||
|
||||
ThemeContext *context = memnew(ThemeContext);
|
||||
context->node = p_node;
|
||||
context->parent = get_nearest_theme_context(p_node);
|
||||
context->set_themes(p_themes);
|
||||
|
||||
theme_contexts[p_node] = context;
|
||||
_propagate_theme_context(p_node, context);
|
||||
|
||||
p_node->connect(SceneStringName(tree_exited), callable_mp(this, &ThemeDB::destroy_theme_context).bind(p_node));
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void ThemeDB::destroy_theme_context(Node *p_node) {
|
||||
ERR_FAIL_COND(!theme_contexts.has(p_node));
|
||||
|
||||
p_node->disconnect(SceneStringName(tree_exited), callable_mp(this, &ThemeDB::destroy_theme_context));
|
||||
|
||||
ThemeContext *context = theme_contexts[p_node];
|
||||
|
||||
theme_contexts.erase(p_node);
|
||||
_propagate_theme_context(p_node, context->parent);
|
||||
|
||||
memdelete(context);
|
||||
}
|
||||
|
||||
void ThemeDB::_propagate_theme_context(Node *p_from_node, ThemeContext *p_context) {
|
||||
Control *from_control = Object::cast_to<Control>(p_from_node);
|
||||
Window *from_window = from_control ? nullptr : Object::cast_to<Window>(p_from_node);
|
||||
|
||||
if (from_control) {
|
||||
from_control->set_theme_context(p_context);
|
||||
} else if (from_window) {
|
||||
from_window->set_theme_context(p_context);
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_from_node->get_child_count(); i++) {
|
||||
Node *child_node = p_from_node->get_child(i);
|
||||
|
||||
// If the child is the root of another global context, stop the propagation
|
||||
// in this branch.
|
||||
if (theme_contexts.has(child_node)) {
|
||||
theme_contexts[child_node]->parent = p_context;
|
||||
continue;
|
||||
}
|
||||
|
||||
_propagate_theme_context(child_node, p_context);
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeDB::_init_default_theme_context() {
|
||||
default_theme_context = memnew(ThemeContext);
|
||||
|
||||
List<Ref<Theme>> themes;
|
||||
|
||||
// Only add the project theme to the default context when running projects.
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||
themes.push_back(project_theme);
|
||||
}
|
||||
#else
|
||||
themes.push_back(project_theme);
|
||||
#endif
|
||||
|
||||
themes.push_back(default_theme);
|
||||
default_theme_context->set_themes(themes);
|
||||
}
|
||||
|
||||
void ThemeDB::_finalize_theme_contexts() {
|
||||
if (default_theme_context) {
|
||||
memdelete(default_theme_context);
|
||||
default_theme_context = nullptr;
|
||||
}
|
||||
while (theme_contexts.size()) {
|
||||
HashMap<Node *, ThemeContext *>::Iterator E = theme_contexts.begin();
|
||||
memdelete(E->value);
|
||||
theme_contexts.remove(E);
|
||||
}
|
||||
}
|
||||
|
||||
ThemeContext *ThemeDB::get_theme_context(Node *p_node) const {
|
||||
if (!theme_contexts.has(p_node)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return theme_contexts[p_node];
|
||||
}
|
||||
|
||||
ThemeContext *ThemeDB::get_default_theme_context() const {
|
||||
return default_theme_context;
|
||||
}
|
||||
|
||||
ThemeContext *ThemeDB::get_nearest_theme_context(Node *p_for_node) const {
|
||||
ERR_FAIL_COND_V(!p_for_node->is_inside_tree(), nullptr);
|
||||
|
||||
Node *parent_node = p_for_node->get_parent();
|
||||
while (parent_node) {
|
||||
if (theme_contexts.has(parent_node)) {
|
||||
return theme_contexts[parent_node];
|
||||
}
|
||||
|
||||
parent_node = parent_node->get_parent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Theme item binding.
|
||||
|
||||
void ThemeDB::bind_class_item(Theme::DataType p_data_type, const StringName &p_class_name, const StringName &p_prop_name, const StringName &p_item_name, ThemeItemSetter p_setter) {
|
||||
ERR_FAIL_COND_MSG(theme_item_binds[p_class_name].has(p_prop_name), vformat("Failed to bind theme item '%s' in class '%s': already bound", p_prop_name, p_class_name));
|
||||
|
||||
ThemeItemBind bind;
|
||||
bind.data_type = p_data_type;
|
||||
bind.class_name = p_class_name;
|
||||
bind.item_name = p_item_name;
|
||||
bind.setter = p_setter;
|
||||
|
||||
theme_item_binds[p_class_name][p_prop_name] = bind;
|
||||
theme_item_binds_list[p_class_name].push_back(bind);
|
||||
}
|
||||
|
||||
void ThemeDB::bind_class_external_item(Theme::DataType p_data_type, const StringName &p_class_name, const StringName &p_prop_name, const StringName &p_item_name, const StringName &p_type_name, ThemeItemSetter p_setter) {
|
||||
ERR_FAIL_COND_MSG(theme_item_binds[p_class_name].has(p_prop_name), vformat("Failed to bind theme item '%s' in class '%s': already bound", p_prop_name, p_class_name));
|
||||
|
||||
ThemeItemBind bind;
|
||||
bind.data_type = p_data_type;
|
||||
bind.class_name = p_class_name;
|
||||
bind.item_name = p_item_name;
|
||||
bind.type_name = p_type_name;
|
||||
bind.external = true;
|
||||
bind.setter = p_setter;
|
||||
|
||||
theme_item_binds[p_class_name][p_prop_name] = bind;
|
||||
theme_item_binds_list[p_class_name].push_back(bind);
|
||||
}
|
||||
|
||||
void ThemeDB::update_class_instance_items(Node *p_instance) {
|
||||
ERR_FAIL_NULL(p_instance);
|
||||
|
||||
// Use the hierarchy to initialize all inherited theme caches. Setters carry the necessary
|
||||
// context and will set the values appropriately.
|
||||
StringName class_name = p_instance->get_class();
|
||||
while (class_name != StringName()) {
|
||||
HashMap<StringName, HashMap<StringName, ThemeItemBind>>::Iterator E = theme_item_binds.find(class_name);
|
||||
if (E) {
|
||||
for (const KeyValue<StringName, ThemeItemBind> &F : E->value) {
|
||||
F.value.setter(p_instance);
|
||||
}
|
||||
}
|
||||
|
||||
class_name = ClassDB::get_parent_class_nocheck(class_name);
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeDB::get_class_items(const StringName &p_class_name, List<ThemeItemBind> *r_list, bool p_include_inherited, Theme::DataType p_filter_type) {
|
||||
List<StringName> class_hierarchy;
|
||||
StringName class_name = p_class_name;
|
||||
while (class_name != StringName()) {
|
||||
class_hierarchy.push_front(class_name); // Put parent classes in front.
|
||||
class_name = ClassDB::get_parent_class_nocheck(class_name);
|
||||
}
|
||||
|
||||
HashSet<StringName> inherited_props;
|
||||
for (const StringName &theme_type : class_hierarchy) {
|
||||
HashMap<StringName, List<ThemeItemBind>>::Iterator E = theme_item_binds_list.find(theme_type);
|
||||
if (E) {
|
||||
for (const ThemeItemBind &F : E->value) {
|
||||
if (p_filter_type != Theme::DATA_TYPE_MAX && F.data_type != p_filter_type) {
|
||||
continue;
|
||||
}
|
||||
if (inherited_props.has(F.item_name)) {
|
||||
continue; // Skip inherited properties.
|
||||
}
|
||||
if (F.external || F.class_name != p_class_name) {
|
||||
inherited_props.insert(F.item_name);
|
||||
|
||||
if (!p_include_inherited) {
|
||||
continue; // Track properties defined in parent classes, and skip them.
|
||||
}
|
||||
}
|
||||
|
||||
r_list->push_back(F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeDB::_sort_theme_items() {
|
||||
for (KeyValue<StringName, List<ThemeDB::ThemeItemBind>> &E : theme_item_binds_list) {
|
||||
E.value.sort_custom<ThemeItemBind::SortByType>();
|
||||
}
|
||||
}
|
||||
|
||||
// Object methods.
|
||||
|
||||
void ThemeDB::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_default_theme"), &ThemeDB::get_default_theme);
|
||||
ClassDB::bind_method(D_METHOD("get_project_theme"), &ThemeDB::get_project_theme);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_fallback_base_scale", "base_scale"), &ThemeDB::set_fallback_base_scale);
|
||||
ClassDB::bind_method(D_METHOD("get_fallback_base_scale"), &ThemeDB::get_fallback_base_scale);
|
||||
ClassDB::bind_method(D_METHOD("set_fallback_font", "font"), &ThemeDB::set_fallback_font);
|
||||
ClassDB::bind_method(D_METHOD("get_fallback_font"), &ThemeDB::get_fallback_font);
|
||||
ClassDB::bind_method(D_METHOD("set_fallback_font_size", "font_size"), &ThemeDB::set_fallback_font_size);
|
||||
ClassDB::bind_method(D_METHOD("get_fallback_font_size"), &ThemeDB::get_fallback_font_size);
|
||||
ClassDB::bind_method(D_METHOD("set_fallback_icon", "icon"), &ThemeDB::set_fallback_icon);
|
||||
ClassDB::bind_method(D_METHOD("get_fallback_icon"), &ThemeDB::get_fallback_icon);
|
||||
ClassDB::bind_method(D_METHOD("set_fallback_stylebox", "stylebox"), &ThemeDB::set_fallback_stylebox);
|
||||
ClassDB::bind_method(D_METHOD("get_fallback_stylebox"), &ThemeDB::get_fallback_stylebox);
|
||||
|
||||
ADD_GROUP("Fallback values", "fallback_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fallback_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_fallback_base_scale", "get_fallback_base_scale");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_font", PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_NONE), "set_fallback_font", "get_fallback_font");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "fallback_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater,suffix:px"), "set_fallback_font_size", "get_fallback_font_size");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NONE), "set_fallback_icon", "get_fallback_icon");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_stylebox", PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_NONE), "set_fallback_stylebox", "get_fallback_stylebox");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("fallback_changed"));
|
||||
}
|
||||
|
||||
// Memory management, reference, and initialization.
|
||||
|
||||
ThemeDB *ThemeDB::singleton = nullptr;
|
||||
|
||||
ThemeDB *ThemeDB::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
ThemeDB::ThemeDB() {
|
||||
singleton = this;
|
||||
if (MessageQueue::get_singleton()) { // May not exist in tests etc.
|
||||
callable_mp(this, &ThemeDB::_sort_theme_items).call_deferred();
|
||||
}
|
||||
}
|
||||
|
||||
ThemeDB::~ThemeDB() {
|
||||
// For technical reasons unit tests recreate and destroy the default
|
||||
// theme over and over again. Make sure that finalize_theme() also
|
||||
// frees any objects that can be recreated by initialize_theme*().
|
||||
|
||||
_finalize_theme_contexts();
|
||||
|
||||
default_theme.unref();
|
||||
project_theme.unref();
|
||||
|
||||
fallback_font.unref();
|
||||
fallback_icon.unref();
|
||||
fallback_stylebox.unref();
|
||||
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
void ThemeContext::_emit_changed() {
|
||||
emit_signal(CoreStringName(changed));
|
||||
}
|
||||
|
||||
void ThemeContext::set_themes(List<Ref<Theme>> &p_themes) {
|
||||
for (const Ref<Theme> &theme : themes) {
|
||||
theme->disconnect_changed(callable_mp(this, &ThemeContext::_emit_changed));
|
||||
}
|
||||
|
||||
themes.clear();
|
||||
|
||||
for (const Ref<Theme> &theme : p_themes) {
|
||||
if (theme.is_null()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
themes.push_back(theme);
|
||||
theme->connect_changed(callable_mp(this, &ThemeContext::_emit_changed));
|
||||
}
|
||||
|
||||
_emit_changed();
|
||||
}
|
||||
|
||||
List<Ref<Theme>> ThemeContext::get_themes() const {
|
||||
return themes;
|
||||
}
|
||||
|
||||
Ref<Theme> ThemeContext::get_fallback_theme() const {
|
||||
// We expect all contexts to be valid and non-empty, but just in case...
|
||||
if (themes.size() == 0) {
|
||||
return ThemeDB::get_singleton()->get_default_theme();
|
||||
}
|
||||
|
||||
return themes.back()->get();
|
||||
}
|
||||
|
||||
void ThemeContext::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("changed"));
|
||||
}
|
||||
207
engine/scene/theme/theme_db.h
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/**************************************************************************/
|
||||
/* theme_db.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef THEME_DB_H
|
||||
#define THEME_DB_H
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "scene/resources/theme.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
class Font;
|
||||
class Node;
|
||||
class StyleBox;
|
||||
class Texture2D;
|
||||
class ThemeContext;
|
||||
|
||||
// Macros for binding theme items of this class. This information is used for the documentation, theme
|
||||
// overrides, etc. This is also the basis for theme cache.
|
||||
|
||||
#define BIND_THEME_ITEM(m_data_type, m_class, m_prop) \
|
||||
ThemeDB::get_singleton()->bind_class_item(m_data_type, get_class_static(), #m_prop, #m_prop, [](Node *p_instance) { \
|
||||
m_class *p_cast = Object::cast_to<m_class>(p_instance); \
|
||||
p_cast->theme_cache.m_prop = p_cast->get_theme_item(m_data_type, _scs_create(#m_prop)); \
|
||||
})
|
||||
|
||||
#define BIND_THEME_ITEM_CUSTOM(m_data_type, m_class, m_prop, m_item_name) \
|
||||
ThemeDB::get_singleton()->bind_class_item(m_data_type, get_class_static(), #m_prop, m_item_name, [](Node *p_instance) { \
|
||||
m_class *p_cast = Object::cast_to<m_class>(p_instance); \
|
||||
p_cast->theme_cache.m_prop = p_cast->get_theme_item(m_data_type, _scs_create(m_item_name)); \
|
||||
})
|
||||
|
||||
// Macro for binding theme items used by this class, but defined/binded by other classes. This is primarily used for
|
||||
// the theme cache. Can also be used to list such items in documentation.
|
||||
|
||||
#define BIND_THEME_ITEM_EXT(m_data_type, m_class, m_prop, m_item_name, m_type_name) \
|
||||
ThemeDB::get_singleton()->bind_class_external_item(m_data_type, get_class_static(), #m_prop, m_item_name, m_type_name, [](Node *p_instance) { \
|
||||
m_class *p_cast = Object::cast_to<m_class>(p_instance); \
|
||||
p_cast->theme_cache.m_prop = p_cast->get_theme_item(m_data_type, _scs_create(m_item_name), _scs_create(m_type_name)); \
|
||||
})
|
||||
|
||||
class ThemeDB : public Object {
|
||||
GDCLASS(ThemeDB, Object);
|
||||
|
||||
static ThemeDB *singleton;
|
||||
|
||||
// Global Theme resources used by the default theme context.
|
||||
|
||||
Ref<Theme> default_theme;
|
||||
Ref<Theme> project_theme;
|
||||
|
||||
// Universal default values, final fallback for every theme.
|
||||
|
||||
float fallback_base_scale = 1.0;
|
||||
Ref<Font> fallback_font;
|
||||
int fallback_font_size = 16;
|
||||
Ref<Texture2D> fallback_icon;
|
||||
Ref<StyleBox> fallback_stylebox;
|
||||
|
||||
// Global theme contexts used to scope global Theme resources.
|
||||
|
||||
ThemeContext *default_theme_context = nullptr;
|
||||
HashMap<Node *, ThemeContext *> theme_contexts;
|
||||
|
||||
void _propagate_theme_context(Node *p_from_node, ThemeContext *p_context);
|
||||
void _init_default_theme_context();
|
||||
void _finalize_theme_contexts();
|
||||
|
||||
// Binding of theme items to Node classes.
|
||||
|
||||
public:
|
||||
typedef std::function<void(Node *)> ThemeItemSetter;
|
||||
|
||||
struct ThemeItemBind {
|
||||
Theme::DataType data_type;
|
||||
StringName class_name;
|
||||
StringName item_name;
|
||||
StringName type_name;
|
||||
bool external = false;
|
||||
|
||||
ThemeItemSetter setter;
|
||||
|
||||
struct SortByType {
|
||||
_FORCE_INLINE_ bool operator()(const ThemeItemBind &l, const ThemeItemBind &r) const {
|
||||
return l.data_type < r.data_type;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
private:
|
||||
HashMap<StringName, HashMap<StringName, ThemeItemBind>> theme_item_binds;
|
||||
HashMap<StringName, List<ThemeItemBind>> theme_item_binds_list; // Used for listing purposes.
|
||||
|
||||
void _sort_theme_items();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void initialize_theme();
|
||||
void initialize_theme_noproject();
|
||||
void finalize_theme();
|
||||
|
||||
// Global Theme resources.
|
||||
|
||||
void set_default_theme(const Ref<Theme> &p_default);
|
||||
Ref<Theme> get_default_theme();
|
||||
|
||||
void set_project_theme(const Ref<Theme> &p_project_default);
|
||||
Ref<Theme> get_project_theme();
|
||||
|
||||
// Universal fallback values.
|
||||
|
||||
void set_fallback_base_scale(float p_base_scale);
|
||||
float get_fallback_base_scale();
|
||||
|
||||
void set_fallback_font(const Ref<Font> &p_font);
|
||||
Ref<Font> get_fallback_font();
|
||||
|
||||
void set_fallback_font_size(int p_font_size);
|
||||
int get_fallback_font_size();
|
||||
|
||||
void set_fallback_icon(const Ref<Texture2D> &p_icon);
|
||||
Ref<Texture2D> get_fallback_icon();
|
||||
|
||||
void set_fallback_stylebox(const Ref<StyleBox> &p_stylebox);
|
||||
Ref<StyleBox> get_fallback_stylebox();
|
||||
|
||||
void get_native_type_dependencies(const StringName &p_base_type, List<StringName> *p_list);
|
||||
|
||||
// Global theme contexts.
|
||||
|
||||
ThemeContext *create_theme_context(Node *p_node, List<Ref<Theme>> &p_themes);
|
||||
void destroy_theme_context(Node *p_node);
|
||||
|
||||
ThemeContext *get_theme_context(Node *p_node) const;
|
||||
ThemeContext *get_default_theme_context() const;
|
||||
ThemeContext *get_nearest_theme_context(Node *p_for_node) const;
|
||||
|
||||
// Theme item binding.
|
||||
|
||||
void bind_class_item(Theme::DataType p_data_type, const StringName &p_class_name, const StringName &p_prop_name, const StringName &p_item_name, ThemeItemSetter p_setter);
|
||||
void bind_class_external_item(Theme::DataType p_data_type, const StringName &p_class_name, const StringName &p_prop_name, const StringName &p_item_name, const StringName &p_type_name, ThemeItemSetter p_setter);
|
||||
void update_class_instance_items(Node *p_instance);
|
||||
|
||||
void get_class_items(const StringName &p_class_name, List<ThemeItemBind> *r_list, bool p_include_inherited = false, Theme::DataType p_filter_type = Theme::DATA_TYPE_MAX);
|
||||
|
||||
// Memory management, reference, and initialization.
|
||||
|
||||
static ThemeDB *get_singleton();
|
||||
ThemeDB();
|
||||
~ThemeDB();
|
||||
};
|
||||
|
||||
class ThemeContext : public Object {
|
||||
GDCLASS(ThemeContext, Object);
|
||||
|
||||
friend class ThemeDB;
|
||||
|
||||
Node *node = nullptr;
|
||||
ThemeContext *parent = nullptr;
|
||||
|
||||
// Themes are stacked in the order of relevance, for easy iteration.
|
||||
// This means that the first theme is the one you should check first,
|
||||
// and the last theme is the fallback theme where every lookup ends.
|
||||
List<Ref<Theme>> themes;
|
||||
|
||||
void _emit_changed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_themes(List<Ref<Theme>> &p_themes);
|
||||
List<Ref<Theme>> get_themes() const;
|
||||
Ref<Theme> get_fallback_theme() const;
|
||||
};
|
||||
|
||||
#endif // THEME_DB_H
|
||||
442
engine/scene/theme/theme_owner.cpp
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
/**************************************************************************/
|
||||
/* theme_owner.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "theme_owner.h"
|
||||
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/theme/theme_db.h"
|
||||
|
||||
// Theme owner node.
|
||||
|
||||
void ThemeOwner::set_owner_node(Node *p_node) {
|
||||
owner_control = nullptr;
|
||||
owner_window = nullptr;
|
||||
|
||||
Control *c = Object::cast_to<Control>(p_node);
|
||||
if (c) {
|
||||
owner_control = c;
|
||||
return;
|
||||
}
|
||||
|
||||
Window *w = Object::cast_to<Window>(p_node);
|
||||
if (w) {
|
||||
owner_window = w;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Node *ThemeOwner::get_owner_node() const {
|
||||
if (owner_control) {
|
||||
return owner_control;
|
||||
} else if (owner_window) {
|
||||
return owner_window;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ThemeOwner::has_owner_node() const {
|
||||
return bool(owner_control || owner_window);
|
||||
}
|
||||
|
||||
void ThemeOwner::set_owner_context(ThemeContext *p_context, bool p_propagate) {
|
||||
ThemeContext *default_context = ThemeDB::get_singleton()->get_default_theme_context();
|
||||
|
||||
if (owner_context && owner_context->is_connected(CoreStringName(changed), callable_mp(this, &ThemeOwner::_owner_context_changed))) {
|
||||
owner_context->disconnect(CoreStringName(changed), callable_mp(this, &ThemeOwner::_owner_context_changed));
|
||||
} else if (default_context->is_connected(CoreStringName(changed), callable_mp(this, &ThemeOwner::_owner_context_changed))) {
|
||||
default_context->disconnect(CoreStringName(changed), callable_mp(this, &ThemeOwner::_owner_context_changed));
|
||||
}
|
||||
|
||||
owner_context = p_context;
|
||||
|
||||
if (owner_context) {
|
||||
owner_context->connect(CoreStringName(changed), callable_mp(this, &ThemeOwner::_owner_context_changed));
|
||||
} else {
|
||||
default_context->connect(CoreStringName(changed), callable_mp(this, &ThemeOwner::_owner_context_changed));
|
||||
}
|
||||
|
||||
if (p_propagate) {
|
||||
_owner_context_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeOwner::_owner_context_changed() {
|
||||
if (!holder->is_inside_tree()) {
|
||||
// We ignore theme changes outside of tree, because NOTIFICATION_ENTER_TREE covers everything.
|
||||
return;
|
||||
}
|
||||
|
||||
Control *c = Object::cast_to<Control>(holder);
|
||||
Window *w = c == nullptr ? Object::cast_to<Window>(holder) : nullptr;
|
||||
|
||||
if (c) {
|
||||
c->notification(Control::NOTIFICATION_THEME_CHANGED);
|
||||
} else if (w) {
|
||||
w->notification(Window::NOTIFICATION_THEME_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
ThemeContext *ThemeOwner::_get_active_owner_context() const {
|
||||
if (owner_context) {
|
||||
return owner_context;
|
||||
}
|
||||
|
||||
return ThemeDB::get_singleton()->get_default_theme_context();
|
||||
}
|
||||
|
||||
// Theme propagation.
|
||||
|
||||
void ThemeOwner::assign_theme_on_parented(Node *p_for_node) {
|
||||
// We check if there are any themes affecting the parent. If that's the case
|
||||
// its children also need to be affected.
|
||||
// We don't notify here because `NOTIFICATION_THEME_CHANGED` will be handled
|
||||
// a bit later by `NOTIFICATION_ENTER_TREE`.
|
||||
|
||||
Node *parent = p_for_node->get_parent();
|
||||
|
||||
Control *parent_c = Object::cast_to<Control>(parent);
|
||||
if (parent_c && parent_c->has_theme_owner_node()) {
|
||||
propagate_theme_changed(p_for_node, parent_c->get_theme_owner_node(), false, true);
|
||||
} else {
|
||||
Window *parent_w = Object::cast_to<Window>(parent);
|
||||
if (parent_w && parent_w->has_theme_owner_node()) {
|
||||
propagate_theme_changed(p_for_node, parent_w->get_theme_owner_node(), false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeOwner::clear_theme_on_unparented(Node *p_for_node) {
|
||||
// We check if there were any themes affecting the parent. If that's the case
|
||||
// its children need were also affected and need to be updated.
|
||||
// We don't notify because we're exiting the tree, and it's not important.
|
||||
|
||||
Node *parent = p_for_node->get_parent();
|
||||
|
||||
Control *parent_c = Object::cast_to<Control>(parent);
|
||||
if (parent_c && parent_c->has_theme_owner_node()) {
|
||||
propagate_theme_changed(p_for_node, nullptr, false, true);
|
||||
} else {
|
||||
Window *parent_w = Object::cast_to<Window>(parent);
|
||||
if (parent_w && parent_w->has_theme_owner_node()) {
|
||||
propagate_theme_changed(p_for_node, nullptr, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeOwner::propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign) {
|
||||
Control *c = Object::cast_to<Control>(p_to_node);
|
||||
Window *w = c == nullptr ? Object::cast_to<Window>(p_to_node) : nullptr;
|
||||
|
||||
if (!c && !w) {
|
||||
// Theme inheritance chains are broken by nodes that aren't Control or Window.
|
||||
return;
|
||||
}
|
||||
|
||||
bool assign = p_assign;
|
||||
if (c) {
|
||||
if (c != p_owner_node && c->get_theme().is_valid()) {
|
||||
// Has a theme, so we don't want to change the theme owner,
|
||||
// but we still want to propagate in case this child has theme items
|
||||
// it inherits from the theme this node uses.
|
||||
// See https://github.com/godotengine/godot/issues/62844.
|
||||
assign = false;
|
||||
}
|
||||
|
||||
if (assign) {
|
||||
c->set_theme_owner_node(p_owner_node);
|
||||
}
|
||||
|
||||
if (p_notify) {
|
||||
c->notification(Control::NOTIFICATION_THEME_CHANGED);
|
||||
}
|
||||
} else if (w) {
|
||||
if (w != p_owner_node && w->get_theme().is_valid()) {
|
||||
// Same as above.
|
||||
assign = false;
|
||||
}
|
||||
|
||||
if (assign) {
|
||||
w->set_theme_owner_node(p_owner_node);
|
||||
}
|
||||
|
||||
if (p_notify) {
|
||||
w->notification(Window::NOTIFICATION_THEME_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_to_node->get_child_count(); i++) {
|
||||
propagate_theme_changed(p_to_node->get_child(i), p_owner_node, p_notify, assign);
|
||||
}
|
||||
}
|
||||
|
||||
// Theme lookup.
|
||||
|
||||
void ThemeOwner::get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const {
|
||||
const Control *for_c = Object::cast_to<Control>(p_for_node);
|
||||
const Window *for_w = Object::cast_to<Window>(p_for_node);
|
||||
ERR_FAIL_COND_MSG(!for_c && !for_w, "Only Control and Window nodes and derivatives can be polled for theming.");
|
||||
|
||||
StringName type_name = p_for_node->get_class_name();
|
||||
StringName type_variation;
|
||||
if (for_c) {
|
||||
type_variation = for_c->get_theme_type_variation();
|
||||
} else if (for_w) {
|
||||
type_variation = for_w->get_theme_type_variation();
|
||||
}
|
||||
|
||||
// If we are looking for dependencies of the current class (or a variation of it), check relevant themes.
|
||||
if (p_theme_type == StringName() || p_theme_type == type_name || p_theme_type == type_variation) {
|
||||
// We need one theme that can give us a valid dependency chain. It must be complete
|
||||
// (i.e. variations can depend on other variations, but only within the same theme,
|
||||
// and eventually the chain must lead to native types).
|
||||
|
||||
// First, look through themes owned by nodes in the tree.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
|
||||
if (owner_theme.is_valid() && owner_theme->get_type_variation_base(type_variation) != StringName()) {
|
||||
owner_theme->get_type_dependencies(type_name, type_variation, r_list);
|
||||
return;
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Second, check global contexts.
|
||||
ThemeContext *global_context = _get_active_owner_context();
|
||||
for (const Ref<Theme> &theme : global_context->get_themes()) {
|
||||
if (theme.is_valid() && theme->get_type_variation_base(type_variation) != StringName()) {
|
||||
theme->get_type_dependencies(type_name, type_variation, r_list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing was found, get the native dependencies for the current class.
|
||||
ThemeDB::get_singleton()->get_native_type_dependencies(type_name, r_list);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, get the native dependencies for the provided theme type.
|
||||
ThemeDB::get_singleton()->get_native_type_dependencies(p_theme_type, r_list);
|
||||
}
|
||||
|
||||
Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types) {
|
||||
ERR_FAIL_COND_V_MSG(p_theme_types.is_empty(), Variant(), "At least one theme type must be specified.");
|
||||
|
||||
// First, look through each control or window node in the branch, until no valid parent can be found.
|
||||
// Only nodes with a theme resource attached are considered.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
// For each theme resource check the theme types provided and see if p_name exists with any of them.
|
||||
for (const StringName &E : p_theme_types) {
|
||||
Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
|
||||
return owner_theme->get_theme_item(p_data_type, p_name, E);
|
||||
}
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Second, check global themes from the appropriate context.
|
||||
ThemeContext *global_context = _get_active_owner_context();
|
||||
for (const Ref<Theme> &theme : global_context->get_themes()) {
|
||||
if (theme.is_valid()) {
|
||||
for (const StringName &E : p_theme_types) {
|
||||
if (theme->has_theme_item(p_data_type, p_name, E)) {
|
||||
return theme->get_theme_item(p_data_type, p_name, E);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, if no match exists, use any type to return the default/empty value.
|
||||
return global_context->get_fallback_theme()->get_theme_item(p_data_type, p_name, StringName());
|
||||
}
|
||||
|
||||
bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types) {
|
||||
ERR_FAIL_COND_V_MSG(p_theme_types.is_empty(), false, "At least one theme type must be specified.");
|
||||
|
||||
// First, look through each control or window node in the branch, until no valid parent can be found.
|
||||
// Only nodes with a theme resource attached are considered.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
// For each theme resource check the theme types provided and see if p_name exists with any of them.
|
||||
for (const StringName &E : p_theme_types) {
|
||||
Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Second, check global themes from the appropriate context.
|
||||
ThemeContext *global_context = _get_active_owner_context();
|
||||
for (const Ref<Theme> &theme : global_context->get_themes()) {
|
||||
if (theme.is_valid()) {
|
||||
for (const StringName &E : p_theme_types) {
|
||||
if (theme->has_theme_item(p_data_type, p_name, E)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, if no match exists, return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
float ThemeOwner::get_theme_default_base_scale() {
|
||||
// First, look through each control or window node in the branch, until no valid parent can be found.
|
||||
// Only nodes with a theme resource attached are considered.
|
||||
// For each theme resource see if their assigned theme has the default value defined and valid.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_default_base_scale()) {
|
||||
return owner_theme->get_default_base_scale();
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Second, check global themes from the appropriate context.
|
||||
ThemeContext *global_context = _get_active_owner_context();
|
||||
for (const Ref<Theme> &theme : global_context->get_themes()) {
|
||||
if (theme.is_valid()) {
|
||||
if (theme->has_default_base_scale()) {
|
||||
return theme->get_default_base_scale();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, if no match exists, return the universal default.
|
||||
return ThemeDB::get_singleton()->get_fallback_base_scale();
|
||||
}
|
||||
|
||||
Ref<Font> ThemeOwner::get_theme_default_font() {
|
||||
// First, look through each control or window node in the branch, until no valid parent can be found.
|
||||
// Only nodes with a theme resource attached are considered.
|
||||
// For each theme resource see if their assigned theme has the default value defined and valid.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_default_font()) {
|
||||
return owner_theme->get_default_font();
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Second, check global themes from the appropriate context.
|
||||
ThemeContext *global_context = _get_active_owner_context();
|
||||
for (const Ref<Theme> &theme : global_context->get_themes()) {
|
||||
if (theme.is_valid()) {
|
||||
if (theme->has_default_font()) {
|
||||
return theme->get_default_font();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, if no match exists, return the universal default.
|
||||
return ThemeDB::get_singleton()->get_fallback_font();
|
||||
}
|
||||
|
||||
int ThemeOwner::get_theme_default_font_size() {
|
||||
// First, look through each control or window node in the branch, until no valid parent can be found.
|
||||
// Only nodes with a theme resource attached are considered.
|
||||
// For each theme resource see if their assigned theme has the default value defined and valid.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
Ref<Theme> owner_theme = _get_owner_node_theme(owner_node);
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_default_font_size()) {
|
||||
return owner_theme->get_default_font_size();
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Second, check global themes from the appropriate context.
|
||||
ThemeContext *global_context = _get_active_owner_context();
|
||||
for (const Ref<Theme> &theme : global_context->get_themes()) {
|
||||
if (theme.is_valid()) {
|
||||
if (theme->has_default_font_size()) {
|
||||
return theme->get_default_font_size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, if no match exists, return the universal default.
|
||||
return ThemeDB::get_singleton()->get_fallback_font_size();
|
||||
}
|
||||
|
||||
Ref<Theme> ThemeOwner::_get_owner_node_theme(Node *p_owner_node) const {
|
||||
const Control *owner_c = Object::cast_to<Control>(p_owner_node);
|
||||
if (owner_c) {
|
||||
return owner_c->get_theme();
|
||||
}
|
||||
|
||||
const Window *owner_w = Object::cast_to<Window>(p_owner_node);
|
||||
if (owner_w) {
|
||||
return owner_w->get_theme();
|
||||
}
|
||||
|
||||
return Ref<Theme>();
|
||||
}
|
||||
|
||||
Node *ThemeOwner::_get_next_owner_node(Node *p_from_node) const {
|
||||
Node *parent = p_from_node->get_parent();
|
||||
|
||||
Control *parent_c = Object::cast_to<Control>(parent);
|
||||
if (parent_c) {
|
||||
return parent_c->get_theme_owner_node();
|
||||
} else {
|
||||
Window *parent_w = Object::cast_to<Window>(parent);
|
||||
if (parent_w) {
|
||||
return parent_w->get_theme_owner_node();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
85
engine/scene/theme/theme_owner.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/**************************************************************************/
|
||||
/* theme_owner.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef THEME_OWNER_H
|
||||
#define THEME_OWNER_H
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "scene/resources/theme.h"
|
||||
|
||||
class Control;
|
||||
class Node;
|
||||
class ThemeContext;
|
||||
class Window;
|
||||
|
||||
class ThemeOwner : public Object {
|
||||
Node *holder = nullptr;
|
||||
|
||||
Control *owner_control = nullptr;
|
||||
Window *owner_window = nullptr;
|
||||
ThemeContext *owner_context = nullptr;
|
||||
|
||||
void _owner_context_changed();
|
||||
ThemeContext *_get_active_owner_context() const;
|
||||
|
||||
Node *_get_next_owner_node(Node *p_from_node) const;
|
||||
Ref<Theme> _get_owner_node_theme(Node *p_owner_node) const;
|
||||
|
||||
public:
|
||||
// Theme owner node.
|
||||
|
||||
void set_owner_node(Node *p_node);
|
||||
Node *get_owner_node() const;
|
||||
bool has_owner_node() const;
|
||||
|
||||
void set_owner_context(ThemeContext *p_context, bool p_propagate = true);
|
||||
|
||||
// Theme propagation.
|
||||
|
||||
void assign_theme_on_parented(Node *p_for_node);
|
||||
void clear_theme_on_unparented(Node *p_for_node);
|
||||
void propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign);
|
||||
|
||||
// Theme lookup.
|
||||
|
||||
void get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const;
|
||||
|
||||
Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types);
|
||||
bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, const List<StringName> &p_theme_types);
|
||||
|
||||
float get_theme_default_base_scale();
|
||||
Ref<Font> get_theme_default_font();
|
||||
int get_theme_default_font_size();
|
||||
|
||||
ThemeOwner(Node *p_holder) { holder = p_holder; }
|
||||
~ThemeOwner() {}
|
||||
};
|
||||
|
||||
#endif // THEME_OWNER_H
|
||||