Browse Source

Allow exporting enums from GDScript

Use as `export(E) ...`
Closes #12392
Bojidar Marinov 7 năm trước cách đây
mục cha
commit
e4a36d0eda
3 tập tin đã thay đổi với 100 bổ sung16 xóa
  1. 5 1
      editor/property_editor.cpp
  2. 69 9
      modules/gdscript/gdscript_parser.cpp
  3. 26 6
      scene/gui/tree.cpp

+ 5 - 1
editor/property_editor.cpp

@@ -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();

+ 69 - 9
modules/gdscript/gdscript_parser.cpp

@@ -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) {

+ 26 - 6
scene/gui/tree.cpp

@@ -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));