diff options
37 files changed, 649 insertions, 139 deletions
diff --git a/core/ustring.cpp b/core/ustring.cpp index 21696e2a55..3f5e198281 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -2150,7 +2150,7 @@ int64_t String::to_int(const CharType *p_str, int p_len) { if (integer > INT32_MAX / 10) { String number(""); str = p_str; - while (str != limit) { + while (*str && str != limit) { number += *(str++); } ERR_FAIL_V_MSG(sign == 1 ? INT32_MAX : INT32_MIN, "Cannot represent " + number + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 56b4b21525..04deae6bf5 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -136,6 +136,15 @@ Returns the column's icon's maximum width. </description> </method> + <method name="get_icon_modulate" qualifiers="const"> + <return type="Color"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <description> + Returns the [Color] modulating the column's icon. + </description> + </method> <method name="get_icon_region" qualifiers="const"> <return type="Rect2"> </return> @@ -464,6 +473,17 @@ Sets the given column's icon's maximum width. </description> </method> + <method name="set_icon_modulate"> + <return type="void"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <argument index="1" name="modulate" type="Color"> + </argument> + <description> + Modulates the given column's icon with [code]modulate[/code]. + </description> + </method> <method name="set_icon_region"> <return type="void"> </return> diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 8e026b96ce..5c02d8096d 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -1570,7 +1570,7 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]); + pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); } } break; diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 40574d8c77..ab0ee7c24f 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -804,6 +804,15 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += "else\n"; code += _dump_node_code(cf_node->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } + } else if (cf_node->flow_op == SL::FLOW_OP_SWITCH) { + code += _mktab(p_level) + "switch (" + _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cf_node->flow_op == SL::FLOW_OP_CASE) { + code += _mktab(p_level) + "case " + _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ":\n"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cf_node->flow_op == SL::FLOW_OP_DEFAULT) { + code += _mktab(p_level) + "default:\n"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } else if (cf_node->flow_op == SL::FLOW_OP_DO) { code += _mktab(p_level); code += "do"; @@ -957,6 +966,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_CANVAS_ITEM].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["round"] = "#define ROUND_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["inverse"] = "#define INVERSE_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["isinf"] = "#define IS_INF_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["isnan"] = "#define IS_NAN_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["trunc"] = "#define TRUNC_USED\n"; @@ -1066,6 +1076,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; actions[VS::SHADER_SPATIAL].usage_defines["round"] = "#define ROUND_USED\n"; actions[VS::SHADER_SPATIAL].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["inverse"] = "#define INVERSE_USED\n"; actions[VS::SHADER_SPATIAL].usage_defines["isinf"] = "#define IS_INF_USED\n"; actions[VS::SHADER_SPATIAL].usage_defines["isnan"] = "#define IS_NAN_USED\n"; actions[VS::SHADER_SPATIAL].usage_defines["trunc"] = "#define TRUNC_USED\n"; diff --git a/drivers/gles2/shaders/stdlib.glsl b/drivers/gles2/shaders/stdlib.glsl index 96421fcb4a..9c74418743 100644 --- a/drivers/gles2/shaders/stdlib.glsl +++ b/drivers/gles2/shaders/stdlib.glsl @@ -299,6 +299,81 @@ highp float determinant(highp mat4 m) { #endif +#if defined(INVERSE_USED) + +highp mat2 inverse(highp mat2 m) { + highp float d = 1.0 / (m[0].x * m[1].y - m[1].x * m[0].y); + return mat2( + vec2(m[1].y * d, -m[0].y * d), + vec2(-m[1].x * d, m[0].x * d)); +} + +highp mat3 inverse(highp mat3 m) { + highp float d = 1.0 / (m[0].x * (m[1].y * m[2].z - m[2].y * m[1].z) - m[1].x * (m[0].y * m[2].z - m[2].y * m[0].z) + m[2].x * (m[0].y * m[1].z - m[1].y * m[0].z)); + return mat3( + vec3((m[1].y * m[2].z - m[2].y * m[1].z), -(m[1].x * m[2].z - m[2].x * m[1].z), (m[1].x * m[2].y - m[2].x * m[1].y)) * d, + vec3(-(m[0].y * m[2].z - m[2].y * m[0].z), (m[0].x * m[2].z - m[2].x * m[0].z), -(m[0].x * m[2].y - m[2].x * m[0].y)) * d, + vec3((m[0].y * m[1].z - m[1].y * m[0].z), -(m[0].x * m[1].z - m[1].x * m[0].z), (m[0].x * m[1].y - m[1].x * m[0].y)) * d); +} + +highp mat4 inverse(highp mat4 m) { + highp float c00 = m[2].z * m[3].w - m[3].z * m[2].w; + highp float c02 = m[1].z * m[3].w - m[3].z * m[1].w; + highp float c03 = m[1].z * m[2].w - m[2].z * m[1].w; + + highp float c04 = m[2].y * m[3].w - m[3].y * m[2].w; + highp float c06 = m[1].y * m[3].w - m[3].y * m[1].w; + highp float c07 = m[1].y * m[2].w - m[2].y * m[1].w; + + highp float c08 = m[2].y * m[3].z - m[3].y * m[2].z; + highp float c10 = m[1].y * m[3].z - m[3].y * m[1].z; + highp float c11 = m[1].y * m[2].z - m[2].y * m[1].z; + + highp float c12 = m[2].x * m[3].w - m[3].x * m[2].w; + highp float c14 = m[1].x * m[3].w - m[3].x * m[1].w; + highp float c15 = m[1].x * m[2].w - m[2].x * m[1].w; + + highp float c16 = m[2].x * m[3].z - m[3].x * m[2].z; + highp float c18 = m[1].x * m[3].z - m[3].x * m[1].z; + highp float c19 = m[1].x * m[2].z - m[2].x * m[1].z; + + highp float c20 = m[2].x * m[3].y - m[3].x * m[2].y; + highp float c22 = m[1].x * m[3].y - m[3].x * m[1].y; + highp float c23 = m[1].x * m[2].y - m[2].x * m[1].y; + + vec4 f0 = vec4(c00, c00, c02, c03); + vec4 f1 = vec4(c04, c04, c06, c07); + vec4 f2 = vec4(c08, c08, c10, c11); + vec4 f3 = vec4(c12, c12, c14, c15); + vec4 f4 = vec4(c16, c16, c18, c19); + vec4 f5 = vec4(c20, c20, c22, c23); + + vec4 v0 = vec4(m[1].x, m[0].x, m[0].x, m[0].x); + vec4 v1 = vec4(m[1].y, m[0].y, m[0].y, m[0].y); + vec4 v2 = vec4(m[1].z, m[0].z, m[0].z, m[0].z); + vec4 v3 = vec4(m[1].w, m[0].w, m[0].w, m[0].w); + + vec4 inv0 = vec4(v1 * f0 - v2 * f1 + v3 * f2); + vec4 inv1 = vec4(v0 * f0 - v2 * f3 + v3 * f4); + vec4 inv2 = vec4(v0 * f1 - v1 * f3 + v3 * f5); + vec4 inv3 = vec4(v0 * f2 - v1 * f4 + v2 * f5); + + vec4 sa = vec4(+1, -1, +1, -1); + vec4 sb = vec4(-1, +1, -1, +1); + + mat4 inv = mat4(inv0 * sa, inv1 * sb, inv2 * sa, inv3 * sb); + + vec4 r0 = vec4(inv[0].x, inv[1].x, inv[2].x, inv[3].x); + vec4 d0 = vec4(m[0] * r0); + + highp float d1 = (d0.x + d0.y) + (d0.z + d0.w); + highp float d = 1.0 / d1; + + return inv * d; +} + +#endif + #ifndef USE_GLES_OVER_GL #if defined(TRANSPOSE_USED) diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index a54064e4c8..5f4acbc2de 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2247,7 +2247,7 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn pi.type = Variant::INT; if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]); + pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); } } break; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 85ace4b4f0..0121d88f4d 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -801,6 +801,15 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener code += _mktab(p_level) + "else\n"; code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } + } else if (cfnode->flow_op == SL::FLOW_OP_SWITCH) { + code += _mktab(p_level) + "switch (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n"; + code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cfnode->flow_op == SL::FLOW_OP_CASE) { + code += _mktab(p_level) + "case " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ":\n"; + code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cfnode->flow_op == SL::FLOW_OP_DEFAULT) { + code += _mktab(p_level) + "default:\n"; + code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } else if (cfnode->flow_op == SL::FLOW_OP_DO) { code += _mktab(p_level) + "do"; code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 84631f3e38..a729befe8e 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -63,7 +63,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory subdirectory_item->set_text(0, dname); subdirectory_item->set_icon(0, get_icon("Folder", "EditorIcons")); - subdirectory_item->set_icon_color(0, get_color("folder_icon_modulate", "FileDialog")); + subdirectory_item->set_icon_modulate(0, get_color("folder_icon_modulate", "FileDialog")); subdirectory_item->set_selectable(0, true); String lpath = p_dir->get_path(); subdirectory_item->set_metadata(0, lpath); @@ -214,7 +214,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo TreeItem *ti = tree->create_item(favorites); ti->set_text(0, text); ti->set_icon(0, icon); - ti->set_icon_color(0, color); + ti->set_icon_modulate(0, color); ti->set_tooltip(0, fave); ti->set_selectable(0, true); ti->set_metadata(0, fave); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 132bf3973e..3eea888950 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -600,33 +600,15 @@ void EditorAssetLibrary::_notification(int p_what) { case NOTIFICATION_PROCESS: { HTTPClient::Status s = request->get_http_client_status(); - bool visible = s != HTTPClient::STATUS_DISCONNECTED; + const bool loading = s != HTTPClient::STATUS_DISCONNECTED; - if (visible != load_status->is_visible()) { - load_status->set_visible(visible); - } - - if (visible) { - switch (s) { - - case HTTPClient::STATUS_RESOLVING: { - load_status->set_value(0.1); - } break; - case HTTPClient::STATUS_CONNECTING: { - load_status->set_value(0.2); - } break; - case HTTPClient::STATUS_REQUESTING: { - load_status->set_value(0.3); - } break; - case HTTPClient::STATUS_BODY: { - load_status->set_value(0.4); - } break; - default: { - } - } + if (loading) { + library_scroll->set_modulate(Color(1, 1, 1, 0.5)); + } else { + library_scroll->set_modulate(Color(1, 1, 1, 1)); } - bool no_downloads = downloads_hb->get_child_count() == 0; + const bool no_downloads = downloads_hb->get_child_count() == 0; if (no_downloads == downloads_scroll->is_visible()) { downloads_scroll->set_visible(!no_downloads); } @@ -1157,6 +1139,10 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const _search(); } break; case REQUESTING_SEARCH: { + + // The loading text only needs to be displayed before the first page is loaded + library_loading->hide(); + if (asset_items) { memdelete(asset_items); } @@ -1472,6 +1458,10 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { library_vb_border->add_child(library_vb); + library_loading = memnew(Label(TTR("Loading..."))); + library_loading->set_align(Label::ALIGN_CENTER); + library_vb->add_child(library_loading); + asset_top_page = memnew(HBoxContainer); library_vb->add_child(asset_top_page); @@ -1494,12 +1484,6 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { library_vb->add_constant_override("separation", 20 * EDSCALE); - load_status = memnew(ProgressBar); - load_status->set_min(0); - load_status->set_max(1); - load_status->set_step(0.001); - library_main->add_child(load_status); - error_hb = memnew(HBoxContainer); library_main->add_child(error_hb); error_label = memnew(Label); diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index 81288ae831..d81606c284 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -186,13 +186,13 @@ class EditorAssetLibrary : public PanelContainer { PanelContainer *library_scroll_bg; ScrollContainer *library_scroll; VBoxContainer *library_vb; + Label *library_loading; LineEdit *filter; OptionButton *categories; OptionButton *repository; OptionButton *sort; ToolButton *reverse; Button *search; - ProgressBar *load_status; HBoxContainer *error_hb; TextureRect *error_tr; Label *error_label; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 785a1c107a..2daee70474 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4429,6 +4429,27 @@ void CanvasItemEditor::_popup_callback(int p_op) { } } break; + case CLEAR_GUIDES: { + + if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_") || EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) { + undo_redo->create_action(TTR("Clear Guides")); + if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) { + Array hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_"); + + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", Array()); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); + } + if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) { + Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_"); + + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", Array()); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); + } + undo_redo->add_undo_method(viewport, "update"); + undo_redo->commit_action(); + } + + } break; case VIEW_CENTER_TO_SELECTION: case VIEW_FRAME_TO_SELECTION: { @@ -5159,6 +5180,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION); + p->add_shortcut(ED_SHORTCUT("canvas_item_editor/clear_guides", TTR("Clear Guides")), CLEAR_GUIDES); p->add_separator(); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_P), PREVIEW_CANVAS_SCALE); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index a16d07599a..ac7d612292 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -178,6 +178,7 @@ private: ANIM_COPY_POSE, ANIM_PASTE_POSE, ANIM_CLEAR_POSE, + CLEAR_GUIDES, VIEW_CENTER_TO_SELECTION, VIEW_FRAME_TO_SELECTION, PREVIEW_CANVAS_SCALE, diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index c1e85788f8..9096a0e0be 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -176,6 +176,86 @@ Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bo return OK; } +Variant TileSetEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { + + return false; +} + +bool TileSetEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { + + Dictionary d = p_data; + + if (!d.has("type")) + return false; + + if (d.has("from") && (Object *)(d["from"]) == texture_list) + return false; + + if (String(d["type"]) == "resource" && d.has("resource")) { + RES r = d["resource"]; + + Ref<Texture> texture = r; + + if (texture.is_valid()) { + + return true; + } + } + + if (String(d["type"]) == "files") { + + Vector<String> files = d["files"]; + + if (files.size() == 0) + return false; + + for (int i = 0; i < files.size(); i++) { + String file = files[i]; + String ftype = EditorFileSystem::get_singleton()->get_file_type(file); + + if (!ClassDB::is_parent_class(ftype, "Texture")) { + return false; + } + } + + return true; + } + return false; +} + +void TileSetEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { + + if (!can_drop_data_fw(p_point, p_data, p_from)) + return; + + Dictionary d = p_data; + + if (!d.has("type")) + return; + + if (String(d["type"]) == "resource" && d.has("resource")) { + RES r = d["resource"]; + + Ref<Texture> texture = r; + + if (texture.is_valid()) + add_texture(texture); + + if (texture_list->get_item_count() > 0) { + update_texture_list_icon(); + texture_list->select(texture_list->get_item_count() - 1); + _on_texture_list_selected(texture_list->get_item_count() - 1); + } + } + + if (String(d["type"]) == "files") { + + PoolVector<String> files = d["files"]; + + _on_textures_added(files); + } +} + void TileSetEditor::_bind_methods() { ClassDB::bind_method("_undo_redo_import_scene", &TileSetEditor::_undo_redo_import_scene); @@ -203,6 +283,10 @@ void TileSetEditor::_bind_methods() { ClassDB::bind_method("_select_edited_shape_coord", &TileSetEditor::_select_edited_shape_coord); ClassDB::bind_method("_sort_tiles", &TileSetEditor::_sort_tiles); + ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &TileSetEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &TileSetEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("drop_data_fw"), &TileSetEditor::drop_data_fw); + ClassDB::bind_method("edit", &TileSetEditor::edit); ClassDB::bind_method("add_texture", &TileSetEditor::add_texture); ClassDB::bind_method("remove_texture", &TileSetEditor::remove_texture); @@ -274,6 +358,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { texture_list->set_v_size_flags(SIZE_EXPAND_FILL); texture_list->set_custom_minimum_size(Size2(200, 0)); texture_list->connect("item_selected", this, "_on_texture_list_selected"); + texture_list->set_drag_forwarding(this); HBoxContainer *tileset_toolbar_container = memnew(HBoxContainer); left_container->add_child(tileset_toolbar_container); diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 69ad8205a4..fff9ef7731 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -173,6 +173,12 @@ class TileSetEditor : public HSplitContainer { static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge); void _undo_redo_import_scene(Node *p_scene, bool p_merge); + bool _is_drop_valid(const Dictionary &p_drag_data, const Dictionary &p_item_data) const; + Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); + bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; + void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + void _file_load_request(const PoolVector<String> &p_path, int p_at_pos = -1); + protected: static void _bind_methods(); void _notification(int p_what); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 589964f620..66fbc32b1c 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -41,6 +41,7 @@ #include "scene/gui/panel.h" #include "scene/main/viewport.h" #include "scene/resources/visual_shader_nodes.h" +#include "servers/visual/shader_types.h" Control *VisualShaderNodePlugin::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) { @@ -229,6 +230,14 @@ void VisualShaderEditor::_update_custom_nodes() { } } +String VisualShaderEditor::_get_description(int p_idx) { + if (add_options[p_idx].highend) { + return TTR("(GLES3 only)") + " " + add_options[p_idx].description; // TODO: change it to (Vulkan Only) when its ready + } else { + return add_options[p_idx].description; + } +} + void VisualShaderEditor::_update_options_menu() { node_desc->set_text(""); @@ -332,11 +341,10 @@ void VisualShaderEditor::_update_options_menu() { else if (add_options[i].highend) item->set_custom_color(0, supported_color); item->set_text(0, add_options[i].name); - if (p_category == sub_category) { - if (is_first_item) { - item->select(0); - is_first_item = false; - } + if (is_first_item && use_filter) { + item->select(0); + node_desc->set_text(_get_description(i)); + is_first_item = false; } switch (add_options[i].return_type) { case VisualShaderNode::PORT_TYPE_SCALAR: @@ -1598,6 +1606,9 @@ void VisualShaderEditor::_notification(int p_what) { preview_text->add_color_override("symbol_color", symbol_color); preview_text->add_color_region("/*", "*/", comment_color, false); preview_text->add_color_region("//", "", comment_color, false); + + error_text->add_font_override("font", get_font("status_source", "EditorFonts")); + error_text->add_color_override("font_color", get_color("error_color", "Editor")); } tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Tools", "EditorIcons")); @@ -1926,11 +1937,7 @@ void VisualShaderEditor::_member_selected() { if (item != NULL && item->has_meta("id")) { members_dialog->get_ok()->set_disabled(false); - if (add_options[item->get_meta("id")].highend) { - node_desc->set_text(TTR("(GLES3 only)") + " " + add_options[item->get_meta("id")].description); // TODO: change it to (Vulkan Only) when its ready - } else { - node_desc->set_text(add_options[item->get_meta("id")].description); - } + node_desc->set_text(_get_description(item->get_meta("id"))); } else { members_dialog->get_ok()->set_disabled(true); node_desc->set_text(""); @@ -2052,11 +2059,44 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da void VisualShaderEditor::_show_preview_text() { preview_showed = !preview_showed; - preview_text->set_visible(preview_showed); + preview_vbox->set_visible(preview_showed); + if (preview_showed) { + if (pending_update_preview) { + _update_preview(); + pending_update_preview = false; + } + } } void VisualShaderEditor::_update_preview() { - preview_text->set_text(visual_shader->get_code()); + + if (!preview_showed) { + pending_update_preview = true; + return; + } + + String code = visual_shader->get_code(); + + preview_text->set_text(code); + + ShaderLanguage sl; + + Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_types()); + + for (int i = 0; i < preview_text->get_line_count(); i++) { + preview_text->set_line_as_marked(i, false); + } + if (err != OK) { + preview_text->set_line_as_marked(sl.get_error_line() - 1, true); + error_text->set_visible(true); + + String text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text(); + error_text->set_text(text); + shader_error = true; + } else { + error_text->set_visible(false); + shader_error = false; + } } void VisualShaderEditor::_bind_methods() { @@ -2127,6 +2167,8 @@ VisualShaderEditor::VisualShaderEditor() { ShaderLanguage::get_keyword_list(&keyword_list); preview_showed = false; + pending_update_preview = false; + shader_error = false; to_node = -1; to_slot = -1; @@ -2201,15 +2243,22 @@ VisualShaderEditor::VisualShaderEditor() { // PREVIEW PANEL /////////////////////////////////////// + preview_vbox = memnew(VBoxContainer); + preview_vbox->set_visible(preview_showed); + main_box->add_child(preview_vbox); preview_text = memnew(TextEdit); - main_box->add_child(preview_text); + preview_vbox->add_child(preview_text); preview_text->set_h_size_flags(SIZE_EXPAND_FILL); preview_text->set_v_size_flags(SIZE_EXPAND_FILL); - preview_text->set_visible(preview_showed); preview_text->set_custom_minimum_size(Size2(400 * EDSCALE, 0)); preview_text->set_syntax_coloring(true); + preview_text->set_show_line_numbers(true); preview_text->set_readonly(true); + error_text = memnew(Label); + preview_vbox->add_child(error_text); + error_text->set_visible(false); + /////////////////////////////////////// // SHADER NODES TREE /////////////////////////////////////// @@ -2520,7 +2569,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("TransformDecompose", "Transform", "Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors."))); add_options.push_back(AddOption("Determinant", "Transform", "Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), VisualShaderNodeTransformFunc::FUNC_INVERSE, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, -1, -1, true)); + add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), VisualShaderNodeTransformFunc::FUNC_INVERSE, VisualShaderNode::PORT_TYPE_TRANSFORM)); add_options.push_back(AddOption("Transpose", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), VisualShaderNodeTransformFunc::FUNC_TRANSPOSE, VisualShaderNode::PORT_TYPE_TRANSFORM)); add_options.push_back(AddOption("TransformMult", "Transform", "Operators", "VisualShaderNodeTransformMult", TTR("Multiplies transform by transform."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM)); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 1556c7cd43..cd5efc366b 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -70,7 +70,11 @@ class VisualShaderEditor : public VBoxContainer { PanelContainer *error_panel; Label *error_label; + bool pending_update_preview; + bool shader_error; + VBoxContainer *preview_vbox; TextEdit *preview_text; + Label *error_text; UndoRedo *undo_redo; Point2 saved_node_pos; @@ -154,6 +158,7 @@ class VisualShaderEditor : public VBoxContainer { void _show_preview_text(); void _update_preview(); + String _get_description(int p_idx); static VisualShaderEditor *singleton; diff --git a/main/main.cpp b/main/main.cpp index 582df4e866..8def4bd1ec 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -598,6 +598,14 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph auto_build_solutions = true; editor = true; +#ifdef DEBUG_METHODS_ENABLED + } else if (I->get() == "--gdnative-generate-json-api") { + // Register as an editor instance to use the GLES2 fallback automatically on hardware that doesn't support the GLES3 backend + editor = true; + + // We still pass it to the main arguments since the argument handling itself is not done in this function + main_args.push_back(I->get()); +#endif } else if (I->get() == "--export" || I->get() == "--export-debug") { // Export project editor = true; diff --git a/modules/mono/SCsub b/modules/mono/SCsub index cc60e64a11..a9afa7ccf6 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -8,13 +8,7 @@ Import('env_modules') env_mono = env_modules.Clone() -env_mono.add_source_files(env.modules_sources, '*.cpp') -env_mono.add_source_files(env.modules_sources, 'glue/*.cpp') -env_mono.add_source_files(env.modules_sources, 'mono_gd/*.cpp') -env_mono.add_source_files(env.modules_sources, 'utils/*.cpp') - if env['tools']: - env_mono.add_source_files(env.modules_sources, 'editor/*.cpp') # NOTE: It is safe to generate this file here, since this is still executed serially import build_scripts.make_cs_compressed_header as make_cs_compressed_header make_cs_compressed_header.generate_header( @@ -62,3 +56,13 @@ if env_mono['tools']: # GodotTools.ProjectEditor which doesn't depend on the Godot API solution and # is required by the bindings generator in order to be able to generated it. godot_tools_build.build_project_editor_only(env_mono) + +# Add sources + +env_mono.add_source_files(env.modules_sources, '*.cpp') +env_mono.add_source_files(env.modules_sources, 'glue/*.cpp') +env_mono.add_source_files(env.modules_sources, 'mono_gd/*.cpp') +env_mono.add_source_files(env.modules_sources, 'utils/*.cpp') + +if env['tools']: + env_mono.add_source_files(env.modules_sources, 'editor/*.cpp') diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py index cd9210897d..8cad204d7b 100644 --- a/modules/mono/build_scripts/make_android_mono_config.py +++ b/modules/mono/build_scripts/make_android_mono_config.py @@ -3,23 +3,6 @@ def generate_compressed_config(config_src, output_dir): import os.path from compat import byte_to_str - # Header file - with open(os.path.join(output_dir, 'android_mono_config.gen.h'), 'w') as header: - header.write('''/* THIS FILE IS GENERATED DO NOT EDIT */ -#ifndef ANDROID_MONO_CONFIG_GEN_H -#define ANDROID_MONO_CONFIG_GEN_H - -#ifdef ANDROID_ENABLED - -#include "core/ustring.h" - -String get_godot_android_mono_config(); - -#endif // ANDROID_ENABLED - -#endif // ANDROID_MONO_CONFIG_GEN_H -''') - # Source file with open(os.path.join(output_dir, 'android_mono_config.gen.cpp'), 'w') as cpp: with open(config_src, 'rb') as f: @@ -36,7 +19,7 @@ String get_godot_android_mono_config(); bytes_seq_str += byte_to_str(buf[buf_idx]) cpp.write('''/* THIS FILE IS GENERATED DO NOT EDIT */ -#include "android_mono_config.gen.h" +#include "android_mono_config.h" #ifdef ANDROID_ENABLED diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj index f3ac353c0f..dcfdd83831 100644 --- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj @@ -11,6 +11,7 @@ <AssemblyName>GodotTools.BuildLogger</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> + <LangVersion>7</LangVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj index f36b40f87c..24c7cb1573 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj @@ -8,6 +8,7 @@ <RootNamespace>GodotTools.Core</RootNamespace> <AssemblyName>GodotTools.Core</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <LangVersion>7</LangVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeConnection/GodotTools.IdeConnection.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeConnection/GodotTools.IdeConnection.csproj index 84c08251ab..94e525715b 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeConnection/GodotTools.IdeConnection.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.IdeConnection/GodotTools.IdeConnection.csproj @@ -11,6 +11,7 @@ <AssemblyName>GodotTools.IdeConnection</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> + <LangVersion>7</LangVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj index 08b8ba3946..c745fe321b 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj @@ -9,6 +9,7 @@ <AssemblyName>GodotTools.ProjectEditor</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <BaseIntermediateOutputPath>obj</BaseIntermediateOutputPath> + <LangVersion>7</LangVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 099c7fcb56..7da7cff933 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -359,7 +359,7 @@ namespace GodotTools aboutLabel.Text = "C# support in Godot Engine is in late alpha stage and, while already usable, " + "it is not meant for use in production.\n\n" + - "Projects can be exported to Linux, macOS and Windows, but not yet to mobile or web platforms. " + + "Projects can be exported to Linux, macOS, Windows and Android, but not yet to iOS, HTML5 or UWP. " + "Bugs and usability issues will be addressed gradually over future releases, " + "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" + "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" + diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index e2d576caef..3c57900873 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -10,6 +10,7 @@ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath> <GodotApiConfiguration>Debug</GodotApiConfiguration> + <LangVersion>7</LangVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/NotifyAwaiter.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/NotifyAwaiter.cs index a3490fa89f..700b786752 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/NotifyAwaiter.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/NotifyAwaiter.cs @@ -51,7 +51,7 @@ namespace GodotTools.Utils { continuation = null; exception = null; - result = default; + result = default(T); IsCompleted = false; return this; } diff --git a/modules/mono/glue/Managed/Managed.csproj b/modules/mono/glue/Managed/Managed.csproj index ad55fe9539..c8eca71199 100644 --- a/modules/mono/glue/Managed/Managed.csproj +++ b/modules/mono/glue/Managed/Managed.csproj @@ -8,6 +8,7 @@ <RootNamespace>Managed</RootNamespace> <AssemblyName>Managed</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <LangVersion>7</LangVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <DebugSymbols>true</DebugSymbols> diff --git a/modules/mono/mono_gd/android_mono_config.h b/modules/mono/mono_gd/android_mono_config.h new file mode 100644 index 0000000000..78d3fdec98 --- /dev/null +++ b/modules/mono/mono_gd/android_mono_config.h @@ -0,0 +1,13 @@ +#ifndef ANDROID_MONO_CONFIG_H +#define ANDROID_MONO_CONFIG_H + +#ifdef ANDROID_ENABLED + +#include "core/ustring.h" + +// This function is defined in an auto-generated source file +String get_godot_android_mono_config(); + +#endif // ANDROID_ENABLED + +#endif // ANDROID_MONO_CONFIG_H diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index eed8812305..aa69803a58 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -56,7 +56,7 @@ #endif #ifdef ANDROID_ENABLED -#include "android_mono_config.gen.h" +#include "android_mono_config.h" #endif GDMono *GDMono::singleton = NULL; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 0c096f0d97..9bc593ea3b 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -430,7 +430,7 @@ void FileDialog::update_file_list() { TreeItem *ti = tree->create_item(root); ti->set_text(0, dir_name); ti->set_icon(0, folder); - ti->set_icon_color(0, folder_color); + ti->set_icon_modulate(0, folder_color); Dictionary d; d["name"] = dir_name; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index f8c31121be..7d1895a67a 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -559,7 +559,7 @@ void TextEdit::_update_selection_mode_line() { click_select_held->start(); } -void TextEdit::_update_minimap_scroll() { +void TextEdit::_update_minimap_click() { Point2 mp = get_local_mouse_position(); int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT); @@ -573,6 +573,13 @@ void TextEdit::_update_minimap_scroll() { int row; _get_minimap_mouse_row(Point2i(mp.x, mp.y), row); + if (row >= get_first_visible_line() && (row < get_last_visible_line() || row >= (text.size() - 1))) { + minimap_scroll_ratio = v_scroll->get_as_ratio(); + minimap_scroll_click_pos = mp.y; + can_drag_minimap = true; + return; + } + int wi; int first_line = row - num_lines_from_rows(row, 0, -get_visible_rows() / 2, wi) + 1; double delta = get_scroll_pos_for_line(first_line, wi) - get_v_scroll(); @@ -583,6 +590,17 @@ void TextEdit::_update_minimap_scroll() { } } +void TextEdit::_update_minimap_drag() { + + if (!can_drag_minimap) { + return; + } + + Point2 mp = get_local_mouse_position(); + double diff = (mp.y - minimap_scroll_click_pos) / _get_control_height(); + v_scroll->set_as_ratio(minimap_scroll_ratio + diff); +} + void TextEdit::_notification(int p_what) { switch (p_what) { @@ -899,12 +917,7 @@ void TextEdit::_notification(int p_what) { // calculate viewport size and y offset int viewport_height = (draw_amount - 1) * minimap_line_height; - int control_height = size.height; - control_height -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) { - control_height -= h_scroll->get_size().height; - } - control_height -= viewport_height; + int control_height = _get_control_height() - viewport_height; int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount)); // calculate the first line. @@ -918,8 +931,7 @@ void TextEdit::_notification(int p_what) { int minimap_draw_amount = minimap_visible_lines + times_line_wraps(minimap_line + 1); // draw the minimap - Color viewport_color = cache.current_line_color; - viewport_color.a /= 2; + Color viewport_color = (cache.background_color.get_v() < 0.5) ? Color(1, 1, 1, 0.1) : Color(0, 0, 0, 0.1); VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, cache.minimap_width, viewport_height), viewport_color); for (int i = 0; i < minimap_draw_amount; i++) { @@ -2071,12 +2083,7 @@ void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const // calculate viewport size and y offset int viewport_height = (draw_amount - 1) * minimap_line_height; - int control_height = get_size().height; - control_height -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) { - control_height -= h_scroll->get_size().height; - } - control_height -= viewport_height; + int control_height = _get_control_height() - viewport_height; int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount)); // calculate the first line. @@ -2240,7 +2247,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { // minimap if (draw_minimap) { - _update_minimap_scroll(); + _update_minimap_click(); if (dragging_minimap) { return; } @@ -2363,6 +2370,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == BUTTON_LEFT) { dragging_minimap = false; dragging_selection = false; + can_drag_minimap = false; click_select_held->stop(); } @@ -2411,7 +2419,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _reset_caret_blink_timer(); if (draw_minimap && !dragging_selection) { - _update_minimap_scroll(); + _update_minimap_drag(); } if (!dragging_minimap) { @@ -3506,6 +3514,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } break; case KEY_Z: { + if (readonly) { + break; + } + if (!k->get_command()) { scancode_handled = false; break; @@ -3518,6 +3530,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } break; case KEY_Y: { + if (readonly) { + break; + } + if (!k->get_command()) { scancode_handled = false; break; @@ -3992,7 +4008,7 @@ void TextEdit::_line_edited_from(int p_line) { if (syntax_highlighting_cache.size() > 0) { cache_size = syntax_highlighting_cache.back()->key(); - for (int i = p_line - 1; i < cache_size; i++) { + for (int i = p_line - 1; i <= cache_size; i++) { if (syntax_highlighting_cache.has(i)) { syntax_highlighting_cache.erase(i); } @@ -4019,23 +4035,21 @@ Size2 TextEdit::get_minimum_size() const { return cache.style_normal->get_minimum_size(); } -int TextEdit::get_visible_rows() const { +int TextEdit::_get_control_height() const { + int control_height = get_size().height; + control_height -= cache.style_normal->get_minimum_size().height; + if (h_scroll->is_visible_in_tree()) { + control_height -= h_scroll->get_size().height; + } + return control_height; +} - int total = get_size().height; - total -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) - total -= h_scroll->get_size().height; - total /= get_row_height(); - return total; +int TextEdit::get_visible_rows() const { + return _get_control_height() / get_row_height(); } int TextEdit::_get_minimap_visible_rows() const { - int total = get_size().height; - total -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) - total -= h_scroll->get_size().height; - total /= (minimap_char_size.y + minimap_line_spacing); - return total; + return _get_control_height() / (minimap_char_size.y + minimap_line_spacing); } int TextEdit::get_total_visible_rows() const { @@ -6126,10 +6140,7 @@ int TextEdit::get_last_visible_line_wrap_index() const { double TextEdit::get_visible_rows_offset() const { - double total = get_size().height; - total -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) - total -= h_scroll->get_size().height; + double total = _get_control_height(); total /= (double)get_row_height(); total = total - floor(total); total = -CLAMP(total, 0.001, 1) + 1; @@ -6539,9 +6550,21 @@ void TextEdit::set_line(int line, String new_text) { } void TextEdit::insert_at(const String &p_text, int at) { - cursor_set_column(0); - cursor_set_line(at, false, true); _insert_text(at, 0, p_text + "\n"); + if (cursor.line >= at) { + // offset cursor when located after inserted line + ++cursor.line; + } + if (is_selection_active()) { + if (selection.from_line >= at) { + // offset selection when located after inserted line + ++selection.from_line; + ++selection.to_line; + } else if (selection.to_line >= at) { + // extend selection that includes inserted line + ++selection.to_line; + } + } } void TextEdit::set_show_line_numbers(bool p_show) { @@ -7019,6 +7042,9 @@ TextEdit::TextEdit() { scrolling = false; minimap_clicked = false; dragging_minimap = false; + can_drag_minimap = false; + minimap_scroll_ratio = 0; + minimap_scroll_click_pos = 0; dragging_selection = false; target_v_scroll = 0; v_scroll_speed = 80; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 889be3eaa5..9c568acd93 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -334,7 +334,10 @@ private: bool scrolling; bool dragging_selection; bool dragging_minimap; + bool can_drag_minimap; bool minimap_clicked; + double minimap_scroll_ratio; + double minimap_scroll_click_pos; float target_v_scroll; float v_scroll_speed; @@ -406,7 +409,8 @@ private: void _update_selection_mode_word(); void _update_selection_mode_line(); - void _update_minimap_scroll(); + void _update_minimap_click(); + void _update_minimap_drag(); void _scroll_up(real_t p_delta); void _scroll_down(real_t p_delta); @@ -418,6 +422,7 @@ private: //void mouse_motion(const Point& p_pos, const Point& p_rel, int p_button_mask); Size2 get_minimum_size() const; + int _get_control_height() const; int get_row_height() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 6c8aa35e3c..b7451faad3 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -224,14 +224,14 @@ Rect2 TreeItem::get_icon_region(int p_column) const { return cells[p_column].icon_region; } -void TreeItem::set_icon_color(int p_column, const Color &p_icon_color) { +void TreeItem::set_icon_modulate(int p_column, const Color &p_modulate) { ERR_FAIL_INDEX(p_column, cells.size()); - cells.write[p_column].icon_color = p_icon_color; + cells.write[p_column].icon_color = p_modulate; _changed_notify(p_column); } -Color TreeItem::get_icon_color(int p_column) const { +Color TreeItem::get_icon_modulate(int p_column) const { ERR_FAIL_INDEX_V(p_column, cells.size(), Color()); return cells[p_column].icon_color; @@ -744,6 +744,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_icon_max_width", "column", "width"), &TreeItem::set_icon_max_width); ClassDB::bind_method(D_METHOD("get_icon_max_width", "column"), &TreeItem::get_icon_max_width); + ClassDB::bind_method(D_METHOD("set_icon_modulate", "column", "modulate"), &TreeItem::set_icon_modulate); + ClassDB::bind_method(D_METHOD("get_icon_modulate", "column"), &TreeItem::get_icon_modulate); + ClassDB::bind_method(D_METHOD("set_range", "column", "value"), &TreeItem::set_range); ClassDB::bind_method(D_METHOD("get_range", "column"), &TreeItem::get_range); ClassDB::bind_method(D_METHOD("set_range_config", "column", "min", "max", "step", "expr"), &TreeItem::set_range_config, DEFVAL(false)); @@ -1259,10 +1262,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 check_ofs.y += Math::floor((real_t)(item_rect.size.y - checked->get_height()) / 2); if (p_item->cells[i].checked) { - - checked->draw(ci, check_ofs, icon_col); + checked->draw(ci, check_ofs); } else { - unchecked->draw(ci, check_ofs, icon_col); + unchecked->draw(ci, check_ofs); } int check_w = checked->get_width() + cache.hseparation; @@ -1274,8 +1276,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 draw_item_rect(p_item->cells[i], item_rect, col, icon_col); - //font->draw( ci, text_pos, p_item->cells[i].text, col,item_rect.size.x-check_w ); - } break; case TreeItem::CELL_MODE_RANGE: { if (p_item->cells[i].text != "") { @@ -1305,18 +1305,16 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 font->draw(ci, text_pos, s, col, item_rect.size.x - downarrow->get_width()); - //? Point2i arrow_pos = item_rect.position; arrow_pos.x += item_rect.size.x - downarrow->get_width(); arrow_pos.y += Math::floor(((item_rect.size.y - downarrow->get_height())) / 2.0); - downarrow->draw(ci, arrow_pos, icon_col); + downarrow->draw(ci, arrow_pos); } else { Ref<Texture> updown = cache.updown; String valtext = String::num(p_item->cells[i].val, Math::range_step_decimals(p_item->cells[i].step)); - //String valtext = rtos( p_item->cells[i].val ); if (p_item->cells[i].suffix != String()) valtext += " " + p_item->cells[i].suffix; @@ -1330,7 +1328,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 updown_pos.x += item_rect.size.x - updown->get_width(); updown_pos.y += Math::floor(((item_rect.size.y - updown->get_height())) / 2.0); - updown->draw(ci, updown_pos, icon_col); + updown->draw(ci, updown_pos); } } break; @@ -1348,13 +1346,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 icon_ofs += item_rect.position; draw_texture_rect(p_item->cells[i].icon, Rect2(icon_ofs, icon_size), false, icon_col); - //p_item->cells[i].icon->draw(ci, icon_ofs); } break; case TreeItem::CELL_MODE_CUSTOM: { - //int option = (int)p_item->cells[i].val; - if (p_item->cells[i].custom_draw_obj) { Object *cdo = ObjectDB::get_instance(p_item->cells[i].custom_draw_obj); @@ -1429,10 +1424,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 arrow->draw(ci, p_pos + p_draw_ofs + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset); } - //separator - //get_painter()->draw_fill_rect( Point2i(0,pos.y),Size2i(get_size().width,1),color( COLOR_TREE_GRID) ); - - //pos=p_pos; //reset pos } Point2 children_pos = p_pos; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index b57923e24b..fdc6da5055 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -193,8 +193,8 @@ public: void set_icon_region(int p_column, const Rect2 &p_icon_region); Rect2 get_icon_region(int p_column) const; - void set_icon_color(int p_column, const Color &p_icon_color); - Color get_icon_color(int p_column) const; + void set_icon_modulate(int p_column, const Color &p_modulate); + Color get_icon_modulate(int p_column) const; void set_icon_max_width(int p_column, int p_max); int get_icon_max_width(int p_column) const; diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index 60fb3a3a95..6ba159ca0a 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -671,6 +671,7 @@ Body2DSW::Body2DSW() : angular_velocity = 0; biased_angular_velocity = 0; mass = 1; + inertia = 0; user_inertia = false; _inv_inertia = 0; _inv_mass = 1; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 1dd6699851..e9d85c7eb0 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -283,6 +283,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_CF_DO, "do" }, { TK_CF_SWITCH, "switch" }, { TK_CF_CASE, "case" }, + { TK_CF_DEFAULT, "default" }, { TK_CF_BREAK, "break" }, { TK_CF_CONTINUE, "continue" }, { TK_CF_RETURN, "return" }, @@ -3778,6 +3779,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui TkPos pos = _get_tkpos(); Token tk = _get_token(); + + if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_SWITCH) { + if (tk.type != TK_CF_CASE && tk.type != TK_CF_DEFAULT && tk.type != TK_CURLY_BRACKET_CLOSE) { + _set_error("Switch may contains only case and default blocks"); + return ERR_PARSE_ERROR; + } + } + if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block if (p_just_one) { _set_error("Unexpected '}'"); @@ -4132,6 +4141,183 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } else { _set_tkpos(pos); //rollback } + } else if (tk.type == TK_CF_SWITCH) { + // switch() {} + tk = _get_token(); + if (tk.type != TK_PARENTHESIS_OPEN) { + _set_error("Expected '(' after switch"); + return ERR_PARSE_ERROR; + } + ControlFlowNode *cf = alloc_node<ControlFlowNode>(); + cf->flow_op = FLOW_OP_SWITCH; + Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); + if (!n) + return ERR_PARSE_ERROR; + if (n->get_datatype() != TYPE_INT) { + _set_error("Expected integer expression"); + return ERR_PARSE_ERROR; + } + tk = _get_token(); + if (tk.type != TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')' after expression"); + return ERR_PARSE_ERROR; + } + tk = _get_token(); + if (tk.type != TK_CURLY_BRACKET_OPEN) { + _set_error("Expected '{' after switch statement"); + return ERR_PARSE_ERROR; + } + BlockNode *switch_block = alloc_node<BlockNode>(); + switch_block->block_type = BlockNode::BLOCK_TYPE_SWITCH; + switch_block->parent_block = p_block; + cf->expressions.push_back(n); + cf->blocks.push_back(switch_block); + p_block->statements.push_back(cf); + + int prev_type = TK_CF_CASE; + while (true) { // Go-through multiple cases. + + if (_parse_block(switch_block, p_builtin_types, true, true, false) != OK) { + return ERR_PARSE_ERROR; + } + pos = _get_tkpos(); + tk = _get_token(); + if (tk.type == TK_CF_CASE || tk.type == TK_CF_DEFAULT) { + if (prev_type == TK_CF_DEFAULT) { + if (tk.type == TK_CF_CASE) { + _set_error("Cases must be defined before default case."); + return ERR_PARSE_ERROR; + } else if (prev_type == TK_CF_DEFAULT) { + _set_error("Default case must be defined only once."); + return ERR_PARSE_ERROR; + } + } + prev_type = tk.type; + _set_tkpos(pos); + continue; + } else { + Set<int> constants; + for (int i = 0; i < switch_block->statements.size(); i++) { // Checks for duplicates. + ControlFlowNode *flow = (ControlFlowNode *)switch_block->statements[i]; + if (flow) { + if (flow->flow_op == FLOW_OP_CASE) { + ConstantNode *n2 = static_cast<ConstantNode *>(flow->expressions[0]); + if (!n2) { + return ERR_PARSE_ERROR; + } + if (n2->values.empty()) { + return ERR_PARSE_ERROR; + } + if (constants.has(n2->values[0].sint)) { + _set_error("Duplicated case label: '" + itos(n2->values[0].sint) + "'"); + return ERR_PARSE_ERROR; + } + constants.insert(n2->values[0].sint); + } else if (flow->flow_op == FLOW_OP_DEFAULT) { + continue; + } else { + return ERR_PARSE_ERROR; + } + } else { + return ERR_PARSE_ERROR; + } + } + break; + } + } + + } else if (tk.type == TK_CF_CASE) { + // case x : break; | return; + + if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_CASE) { + _set_tkpos(pos); + return OK; + } + + if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) { + _set_error("case must be placed within switch block"); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + + int sign = 1; + + if (tk.type == TK_OP_SUB) { + sign = -1; + tk = _get_token(); + } + + if (tk.type != TK_INT_CONSTANT) { + _set_error("Expected integer constant"); + return ERR_PARSE_ERROR; + } + + int constant = (int)tk.constant * sign; + + tk = _get_token(); + + if (tk.type != TK_COLON) { + _set_error("Expected ':'"); + return ERR_PARSE_ERROR; + } + + ControlFlowNode *cf = alloc_node<ControlFlowNode>(); + cf->flow_op = FLOW_OP_CASE; + + ConstantNode *n = alloc_node<ConstantNode>(); + ConstantNode::Value v; + v.sint = constant; + n->values.push_back(v); + n->datatype = TYPE_INT; + + BlockNode *case_block = alloc_node<BlockNode>(); + case_block->block_type = BlockNode::BLOCK_TYPE_CASE; + case_block->parent_block = p_block; + cf->expressions.push_back(n); + cf->blocks.push_back(case_block); + p_block->statements.push_back(cf); + + Error err = _parse_block(case_block, p_builtin_types, false, true, false); + if (err) + return err; + + return OK; + + } else if (tk.type == TK_CF_DEFAULT) { + + if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_CASE) { + _set_tkpos(pos); + return OK; + } + + if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) { + _set_error("default must be placed within switch block"); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + + if (tk.type != TK_COLON) { + _set_error("Expected ':'"); + return ERR_PARSE_ERROR; + } + + ControlFlowNode *cf = alloc_node<ControlFlowNode>(); + cf->flow_op = FLOW_OP_DEFAULT; + + BlockNode *default_block = alloc_node<BlockNode>(); + default_block->block_type = BlockNode::BLOCK_TYPE_DEFAULT; + default_block->parent_block = p_block; + cf->blocks.push_back(default_block); + p_block->statements.push_back(cf); + + Error err = _parse_block(default_block, p_builtin_types, false, true, false); + if (err) + return err; + + return OK; + } else if (tk.type == TK_CF_DO || tk.type == TK_CF_WHILE) { // do {} while() // while() {} @@ -4299,6 +4485,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } p_block->statements.push_back(flow); + if (p_block->block_type == BlockNode::BLOCK_TYPE_CASE || p_block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) { + return OK; + } } else if (tk.type == TK_CF_DISCARD) { //check return type @@ -4345,9 +4534,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } p_block->statements.push_back(flow); + if (p_block->block_type == BlockNode::BLOCK_TYPE_CASE || p_block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) { + return OK; + } + } else if (tk.type == TK_CF_CONTINUE) { - if (!p_can_break) { + if (!p_can_continue) { //all is good _set_error("Continuing is not allowed here"); } diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 36c691c3ae..b71788513e 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -125,6 +125,7 @@ public: TK_CF_DO, TK_CF_SWITCH, TK_CF_CASE, + TK_CF_DEFAULT, TK_CF_BREAK, TK_CF_CONTINUE, TK_CF_RETURN, @@ -266,6 +267,8 @@ public: FLOW_OP_DO, FLOW_OP_BREAK, FLOW_OP_SWITCH, + FLOW_OP_CASE, + FLOW_OP_DEFAULT, FLOW_OP_CONTINUE, FLOW_OP_DISCARD }; @@ -420,6 +423,15 @@ public: FunctionNode *parent_function; BlockNode *parent_block; + enum BlockType { + BLOCK_TYPE_STANDART, + BLOCK_TYPE_SWITCH, + BLOCK_TYPE_CASE, + BLOCK_TYPE_DEFAULT, + }; + + int block_type; + struct Variable { DataType type; DataPrecision precision; @@ -436,6 +448,7 @@ public: Node(TYPE_BLOCK), parent_function(NULL), parent_block(NULL), + block_type(BLOCK_TYPE_STANDART), single_statement(false) {} }; |