/*************************************************************************/ /* script_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 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 "script_editor_plugin.h" #include "tools/editor/editor_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/keyboard.h" #include "os/os.h" #include "tools/editor/editor_node.h" #include "tools/editor/script_editor_debugger.h" #include "globals.h" #include "os/file_access.h" #include "scene/main/viewport.h" #include "os/keyboard.h" #include "os/input.h" /*** SCRIPT EDITOR ****/ void ScriptEditorBase::_bind_methods() { ADD_SIGNAL(MethodInfo("name_changed")); ADD_SIGNAL(MethodInfo("request_help_search",PropertyInfo(Variant::STRING,"topic"))); ADD_SIGNAL(MethodInfo("request_open_script_at_line",PropertyInfo(Variant::OBJECT,"script"),PropertyInfo(Variant::INT,"line"))); ADD_SIGNAL(MethodInfo("request_save_history")); ADD_SIGNAL(MethodInfo("go_to_help",PropertyInfo(Variant::STRING,"what"))); } static bool _can_open_in_editor(Script* p_script) { String path = p_script->get_path(); if (path.find("::")!=-1) { //refuse handling this if it can't be edited bool valid=false; for(int i=0;iget_editor_data().get_edited_scene_count();i++) { if (path.begins_with(EditorNode::get_singleton()->get_editor_data().get_scene_path(i))) { valid=true; break; } } return valid; } return true; } class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache { struct Cache { uint64_t time_loaded; RES cache; }; Map cached; public: uint64_t max_time_cache; int max_cache_size; void cleanup() { List< Map::Element * > to_clean; Map::Element *I=cached.front(); while(I) { if ((OS::get_singleton()->get_ticks_msec()-I->get().time_loaded)>max_time_cache) { to_clean.push_back(I); } I=I->next(); } while(to_clean.front()) { cached.erase(to_clean.front()->get()); to_clean.pop_front(); } } RES get_cached_resource(const String& p_path) { Map::Element *E=cached.find(p_path); if (!E) { Cache c; c.cache=ResourceLoader::load(p_path); E=cached.insert(p_path,c); } E->get().time_loaded=OS::get_singleton()->get_ticks_msec(); if (cached.size()>max_cache_size) { uint64_t older; Map::Element *O=cached.front(); older=O->get().time_loaded; Map::Element *I=O; while(I) { if (I->get().time_loadedget().time_loaded; O=I; } I=I->next(); } if (O!=E) {//should never heppane.. cached.erase(O); } } return E->get().cache; } EditorScriptCodeCompletionCache() { max_cache_size=128; max_time_cache=5*60*1000; //minutes, five } }; #define SORT_SCRIPT_LIST void ScriptEditorQuickOpen::popup(const Vector& p_functions, bool p_dontclear) { popup_centered_ratio(0.6); if (p_dontclear) search_box->select_all(); else search_box->clear(); search_box->grab_focus(); functions=p_functions; _update_search(); } void ScriptEditorQuickOpen::_text_changed(const String& p_newtext) { _update_search(); } void ScriptEditorQuickOpen::_sbox_input(const InputEvent& p_ie) { if (p_ie.type==InputEvent::KEY && ( p_ie.key.scancode == KEY_UP || p_ie.key.scancode == KEY_DOWN || p_ie.key.scancode == KEY_PAGEUP || p_ie.key.scancode == KEY_PAGEDOWN ) ) { search_options->call("_input_event",p_ie); search_box->accept_event(); } } void ScriptEditorQuickOpen::_update_search() { search_options->clear(); TreeItem *root = search_options->create_item(); for(int i=0;iget_text()=="" || file.findn(search_box->get_text())!=-1)) { TreeItem *ti = search_options->create_item(root); ti->set_text(0,file); if (root->get_children()==ti) ti->select(0); } } get_ok()->set_disabled(root->get_children()==NULL); } void ScriptEditorQuickOpen::_confirmed() { TreeItem *ti = search_options->get_selected(); if (!ti) return; int line = ti->get_text(0).get_slice(":",1).to_int(); emit_signal("goto_line",line-1); hide(); } void ScriptEditorQuickOpen::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { connect("confirmed",this,"_confirmed"); } } void ScriptEditorQuickOpen::_bind_methods() { ObjectTypeDB::bind_method(_MD("_text_changed"),&ScriptEditorQuickOpen::_text_changed); ObjectTypeDB::bind_method(_MD("_confirmed"),&ScriptEditorQuickOpen::_confirmed); ObjectTypeDB::bind_method(_MD("_sbox_input"),&ScriptEditorQuickOpen::_sbox_input); ADD_SIGNAL(MethodInfo("goto_line",PropertyInfo(Variant::INT,"line"))); } ScriptEditorQuickOpen::ScriptEditorQuickOpen() { VBoxContainer *vbc = memnew( VBoxContainer ); add_child(vbc); set_child_rect(vbc); search_box = memnew( LineEdit ); vbc->add_margin_child(TTR("Search:"),search_box); search_box->connect("text_changed",this,"_text_changed"); search_box->connect("input_event",this,"_sbox_input"); search_options = memnew( Tree ); vbc->add_margin_child(TTR("Matches:"),search_options,true); get_ok()->set_text(TTR("Open")); get_ok()->set_disabled(true); register_text_enter(search_box); set_hide_on_ok(false); search_options->connect("item_activated",this,"_confirmed"); search_options->set_hide_root(true); } ///////////////////////////////// ScriptEditor *ScriptEditor::script_editor=NULL; /*** SCRIPT EDITOR ******/ String ScriptEditor::_get_debug_tooltip(const String&p_text,Node *_se) { // ScriptEditorBase *se=_se->cast_to(); String val = debugger->get_var_value(p_text); if (val!=String()) { return p_text+": "+val; } else { return String(); } } void ScriptEditor::_breaked(bool p_breaked,bool p_can_debug) { debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_NEXT), !(p_breaked && p_can_debug)); debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_STEP), !(p_breaked && p_can_debug) ); debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), p_breaked ); debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), !p_breaked ); for(int i=0;iget_child_count();i++) { ScriptEditorBase *se = tab_container->get_child(i)->cast_to(); if (!se) { continue; } se->set_debugger_active(p_breaked); } } void ScriptEditor::_show_debugger(bool p_show) { // debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW), p_show); } void ScriptEditor::_script_created(Ref