Allow exporting enums from GDScript

Use as `export(E) ...`
Closes #12392
This commit is contained in:
Bojidar Marinov 2017-11-15 20:50:37 +02:00
parent 64caa4733c
commit e4a36d0eda
No known key found for this signature in database
GPG Key ID: 4D546A8F1E091856
3 changed files with 100 additions and 16 deletions

View File

@ -415,7 +415,11 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
menu->clear();
Vector<String> options = hint_text.split(",");
for (int i = 0; i < options.size(); i++) {
menu->add_item(options[i], i);
if (options[i].find(":") != -1) {
menu->add_item(options[i].get_slicec(':', 0), options[i].get_slicec(':', 1).to_int());
} else {
menu->add_item(options[i], i);
}
}
menu->set_position(get_position());
menu->popup();

View File

@ -3758,22 +3758,82 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_export.hint = PROPERTY_HINT_NONE;
}
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER) {
} else {
String identifier = tokenizer->get_token_identifier();
if (!ClassDB::is_parent_class(identifier, "Resource")) {
parenthesis++;
Node *subexpr = _parse_and_reduce_expression(p_class, true, true);
if (!subexpr) {
if (_recover_from_completion()) {
break;
}
return;
}
parenthesis--;
if (subexpr->type != Node::TYPE_CONSTANT) {
current_export = PropertyInfo();
_set_error("Export hint not a type or resource.");
_set_error("Expected a constant expression.");
}
current_export.type = Variant::OBJECT;
current_export.hint = PROPERTY_HINT_RESOURCE_TYPE;
current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
Variant constant = static_cast<ConstantNode *>(subexpr)->value;
current_export.hint_string = identifier;
if (constant.get_type() == Variant::OBJECT) {
GDScriptNativeClass *native_class = Object::cast_to<GDScriptNativeClass>(constant);
tokenizer->advance();
if (native_class && ClassDB::is_parent_class(native_class->get_name(), "Resource")) {
current_export.type = Variant::OBJECT;
current_export.hint = PROPERTY_HINT_RESOURCE_TYPE;
current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
current_export.hint_string = native_class->get_name();
} else {
current_export = PropertyInfo();
_set_error("Export hint not a resource type.");
}
} else if (constant.get_type() == Variant::DICTIONARY) {
// Enumeration
bool is_flags = false;
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
tokenizer->advance();
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FLAGS") {
is_flags = true;
tokenizer->advance();
} else {
current_export = PropertyInfo();
_set_error("Expected 'FLAGS' after comma.");
}
}
current_export.type = Variant::INT;
current_export.hint = is_flags ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM;
Dictionary enum_values = constant;
List<Variant> keys;
enum_values.get_key_list(&keys);
bool first = true;
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
if (enum_values[E->get()].get_type() == Variant::INT) {
if (!first)
current_export.hint_string += ",";
else
first = false;
current_export.hint_string += E->get().operator String().camelcase_to_underscore(true).capitalize().xml_escape();
if (!is_flags) {
current_export.hint_string += ":";
current_export.hint_string += enum_values[E->get()].operator String().xml_escape();
}
}
}
} else {
current_export = PropertyInfo();
_set_error("Expected type for export.");
return;
}
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {

View File

@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "tree.h"
#include <limits.h>
#include "os/input.h"
#include "os/keyboard.h"
@ -154,8 +155,17 @@ void TreeItem::set_text(int p_column, String p_text) {
if (cells[p_column].mode == TreeItem::CELL_MODE_RANGE || cells[p_column].mode == TreeItem::CELL_MODE_RANGE_EXPRESSION) {
cells[p_column].min = 0;
cells[p_column].max = p_text.get_slice_count(",");
Vector<String> strings = p_text.split(",");
cells[p_column].min = INT_MAX;
cells[p_column].max = INT_MIN;
for (int i = 0; i < strings.size(); i++) {
int value = i;
if (!strings[i].get_slicec(':', 1).empty()) {
value = strings[i].get_slicec(':', 1).to_int();
}
cells[p_column].min = MIN(cells[p_column].min, value);
cells[p_column].max = MAX(cells[p_column].max, value);
}
cells[p_column].step = 0;
}
_changed_notify(p_column);
@ -1231,8 +1241,18 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int option = (int)p_item->cells[i].val;
String s = p_item->cells[i].text;
s = s.get_slicec(',', option);
String s = RTR("(Other)");
Vector<String> strings = p_item->cells[i].text.split(",");
for (int i = 0; i < strings.size(); i++) {
int value = i;
if (!strings[i].get_slicec(':', 1).empty()) {
value = strings[i].get_slicec(':', 1).to_int();
}
if (option == value) {
s = strings[i].get_slicec(':', 0);
break;
}
}
if (p_item->cells[i].suffix != String())
s += " " + p_item->cells[i].suffix;
@ -1776,7 +1796,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
for (int i = 0; i < c.text.get_slice_count(","); i++) {
String s = c.text.get_slicec(',', i);
popup_menu->add_item(s, i);
popup_menu->add_item(s.get_slicec(':', 0), s.get_slicec(':', 1).empty() ? i : s.get_slicec(':', 1).to_int());
}
popup_menu->set_size(Size2(col_width, 0));
@ -2634,7 +2654,7 @@ bool Tree::edit_selected() {
for (int i = 0; i < c.text.get_slice_count(","); i++) {
String s = c.text.get_slicec(',', i);
popup_menu->add_item(s, i);
popup_menu->add_item(s.get_slicec(':', 0), s.get_slicec(':', 1).empty() ? i : s.get_slicec(':', 1).to_int());
}
popup_menu->set_size(Size2(rect.size.width, 0));