Add type variations to Theme

This commit is contained in:
Yuri Sizov
2021-07-04 23:42:23 +03:00
parent 30d4732623
commit 4ee0e6ddf5
18 changed files with 757 additions and 199 deletions

View File

@ -263,6 +263,21 @@ Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const {
return Vector<String>();
}
Vector<String> Theme::_get_type_variation_list(const StringName &p_theme_type) const {
Vector<String> ilret;
List<StringName> il;
get_type_variation_list(p_theme_type, &il);
ilret.resize(il.size());
int i = 0;
String *w = ilret.ptrw();
for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
w[i] = E->get();
}
return ilret;
}
Vector<String> Theme::_get_type_list() const {
Vector<String> ilret;
List<StringName> il;
@ -292,10 +307,14 @@ bool Theme::_set(const StringName &p_name, const Variant &p_value) {
set_stylebox(name, theme_type, p_value);
} else if (type == "fonts") {
set_font(name, theme_type, p_value);
} else if (type == "font_sizes") {
set_font_size(name, theme_type, p_value);
} else if (type == "colors") {
set_color(name, theme_type, p_value);
} else if (type == "constants") {
set_constant(name, theme_type, p_value);
} else if (type == "base_type") {
set_type_variation(theme_type, p_value);
} else {
return false;
}
@ -332,10 +351,14 @@ bool Theme::_get(const StringName &p_name, Variant &r_ret) const {
} else {
r_ret = get_font(name, theme_type);
}
} else if (type == "font_sizes") {
r_ret = get_font_size(name, theme_type);
} else if (type == "colors") {
r_ret = get_color(name, theme_type);
} else if (type == "constants") {
r_ret = get_constant(name, theme_type);
} else if (type == "base_type") {
r_ret = get_type_variation_base(theme_type);
} else {
return false;
}
@ -351,6 +374,14 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
const StringName *key = nullptr;
// Type variations.
while ((key = variation_map.next(key))) {
list.push_back(PropertyInfo(Variant::STRING_NAME, String() + *key + "/base_type"));
}
key = nullptr;
// Icons.
while ((key = icon_map.next(key))) {
const StringName *key2 = nullptr;
@ -361,6 +392,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
key = nullptr;
// Styles.
while ((key = style_map.next(key))) {
const StringName *key2 = nullptr;
@ -371,6 +403,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
key = nullptr;
// Fonts.
while ((key = font_map.next(key))) {
const StringName *key2 = nullptr;
@ -381,6 +414,18 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
key = nullptr;
// Font sizes.
while ((key = font_size_map.next(key))) {
const StringName *key2 = nullptr;
while ((key2 = font_size_map[*key].next(key2))) {
list.push_back(PropertyInfo(Variant::INT, String() + *key + "/font_sizes/" + *key2));
}
}
key = nullptr;
// Colors.
while ((key = color_map.next(key))) {
const StringName *key2 = nullptr;
@ -391,6 +436,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
key = nullptr;
// Constants.
while ((key = constant_map.next(key))) {
const StringName *key2 = nullptr;
@ -399,6 +445,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
// Sort and store properties.
list.sort();
for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) {
p_list->push_back(E->get());
@ -1183,6 +1230,63 @@ void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_l
}
}
void Theme::set_type_variation(const StringName &p_theme_type, const StringName &p_base_type) {
ERR_FAIL_COND_MSG(p_theme_type == StringName(), "An empty theme type cannot be marked as a variation of another type.");
ERR_FAIL_COND_MSG(ClassDB::class_exists(p_theme_type), "A type associated with a built-in class cannot be marked as a variation of another type.");
ERR_FAIL_COND_MSG(p_base_type == StringName(), "An empty theme type cannot be the base type of a variation. Use clear_type_variation() instead if you want to unmark '" + String(p_theme_type) + "' as a variation.");
if (variation_map.has(p_theme_type)) {
StringName old_base = variation_map[p_theme_type];
variation_base_map[old_base].erase(p_theme_type);
}
variation_map[p_theme_type] = p_base_type;
variation_base_map[p_base_type].push_back(p_theme_type);
_emit_theme_changed();
}
bool Theme::is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const {
return (variation_map.has(p_theme_type) && variation_map[p_theme_type] == p_base_type);
}
void Theme::clear_type_variation(const StringName &p_theme_type) {
ERR_FAIL_COND_MSG(!variation_map.has(p_theme_type), "Cannot clear the type variation '" + String(p_theme_type) + "' because it does not exist.");
StringName base_type = variation_map[p_theme_type];
variation_base_map[base_type].erase(p_theme_type);
variation_map.erase(p_theme_type);
_emit_theme_changed();
}
StringName Theme::get_type_variation_base(const StringName &p_theme_type) const {
if (!variation_map.has(p_theme_type)) {
return StringName();
}
return variation_map[p_theme_type];
}
void Theme::get_type_variation_list(const StringName &p_base_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
if (!variation_base_map.has(p_base_type)) {
return;
}
for (const List<StringName>::Element *E = variation_base_map[p_base_type].front(); E; E = E->next()) {
// Prevent infinite loops if variants were set to be cross-dependent (that's still invalid usage, but handling for stability sake).
if (p_list->find(E->get())) {
continue;
}
p_list->push_back(E->get());
// Continue looking for sub-variations.
get_type_variation_list(E->get(), p_list);
}
}
void Theme::_freeze_change_propagation() {
no_change_propagation = true;
}
@ -1236,9 +1340,13 @@ void Theme::clear() {
icon_map.clear();
style_map.clear();
font_map.clear();
font_size_map.clear();
color_map.clear();
constant_map.clear();
variation_map.clear();
variation_base_map.clear();
_emit_theme_changed();
}
@ -1291,6 +1399,9 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
color_map = p_other->color_map;
constant_map = p_other->constant_map;
variation_map = p_other->variation_map;
variation_base_map = p_other->variation_base_map;
_unfreeze_and_propagate_changes();
}
@ -1300,30 +1411,42 @@ void Theme::get_type_list(List<StringName> *p_list) const {
Set<StringName> types;
const StringName *key = nullptr;
// Icons.
while ((key = icon_map.next(key))) {
types.insert(*key);
}
key = nullptr;
// StyleBoxes.
while ((key = style_map.next(key))) {
types.insert(*key);
}
key = nullptr;
// Fonts.
while ((key = font_map.next(key))) {
types.insert(*key);
}
key = nullptr;
// Font sizes.
while ((key = font_size_map.next(key))) {
types.insert(*key);
}
key = nullptr;
// Colors.
while ((key = color_map.next(key))) {
types.insert(*key);
}
key = nullptr;
// Constants.
while ((key = constant_map.next(key))) {
types.insert(*key);
}
@ -1333,10 +1456,25 @@ void Theme::get_type_list(List<StringName> *p_list) const {
}
}
void Theme::get_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) {
void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) {
ERR_FAIL_NULL(p_list);
StringName class_name = p_theme_type;
// Build the dependency chain for type variations.
if (p_type_variation != StringName()) {
StringName variation_name = p_type_variation;
while (variation_name != StringName()) {
p_list->push_back(variation_name);
variation_name = get_type_variation_base(variation_name);
// If we have reached the base type dependency, it's safe to stop (assuming no funny business was done to the Theme).
if (variation_name == p_base_type) {
break;
}
}
}
// Continue building the chain using native class hierarchy.
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);
@ -1346,6 +1484,7 @@ void Theme::get_type_dependencies(const StringName &p_theme_type, List<StringNam
void Theme::reset_state() {
clear();
}
void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_icon", "name", "theme_type", "texture"), &Theme::set_icon);
ClassDB::bind_method(D_METHOD("get_icon", "name", "theme_type"), &Theme::get_icon);
@ -1411,6 +1550,12 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_theme_item_list", "data_type", "theme_type"), &Theme::_get_theme_item_list);
ClassDB::bind_method(D_METHOD("get_theme_item_type_list", "data_type"), &Theme::_get_theme_item_type_list);
ClassDB::bind_method(D_METHOD("set_type_variation", "theme_type", "base_type"), &Theme::set_type_variation);
ClassDB::bind_method(D_METHOD("is_type_variation", "theme_type", "base_type"), &Theme::is_type_variation);
ClassDB::bind_method(D_METHOD("clear_type_variation", "theme_type"), &Theme::clear_type_variation);
ClassDB::bind_method(D_METHOD("get_type_variation_base", "theme_type"), &Theme::get_type_variation_base);
ClassDB::bind_method(D_METHOD("get_type_variation_list", "base_type"), &Theme::_get_type_variation_list);
ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list);
ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme);