/*************************************************************************/ /* property_editor.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 "property_editor.h" #include "scene/gui/label.h" #include "io/resource_loader.h" #include "io/image_loader.h" #include "os/input.h" #include "os/keyboard.h" #include "class_db.h" #include "print_string.h" #include "global_config.h" #include "scene/resources/font.h" #include "pair.h" #include "scene/scene_string_names.h" #include "editor_settings.h" #include "editor_export.h" #include "editor_node.h" #include "multi_node_edit.h" #include "array_property_edit.h" #include "editor_help.h" #include "scene/resources/packed_scene.h" #include "scene/main/viewport.h" #include "editor_file_system.h" #include "create_dialog.h" #include "property_selector.h" #include "global_config.h" void CustomPropertyEditor::_notification(int p_what) { if (p_what==NOTIFICATION_DRAW) { RID ci = get_canvas_item(); get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size())); /* if (v.get_type()==Variant::COLOR) { VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2( 10,10,60, get_size().height-20 ), v ); }*/ } } void CustomPropertyEditor::_menu_option(int p_which) { switch(type) { case Variant::INT: { if (hint==PROPERTY_HINT_FLAGS) { int val = v; if (val&(1<set_mode(EditorFileDialog::MODE_OPEN_FILE); String type=(hint==PROPERTY_HINT_RESOURCE_TYPE)?hint_text:String(); List extensions; for (int i=0;i valid_extensions; for (List::Element *E=extensions.front();E;E=E->next()) { print_line("found: "+E->get()); valid_extensions.insert(E->get()); } file->clear_filters(); for (Set::Element *E=valid_extensions.front();E;E=E->next()) { file->add_filter("*."+E->get()+" ; "+E->get().to_upper() ); } file->popup_centered_ratio(); } break; case OBJ_MENU_EDIT: { RefPtr RefPtr=v; if (!RefPtr.is_null()) { emit_signal("resource_edit_request"); hide(); } } break; case OBJ_MENU_CLEAR: { v=Variant(); emit_signal("variant_changed"); hide(); } break; case OBJ_MENU_MAKE_UNIQUE: { RefPtr RefPtr=v; Ref res_orig = RefPtr; if (res_orig.is_null()) return; List property_list; res_orig->get_property_list(&property_list); List< Pair > propvalues; for(List::Element *E=property_list.front();E;E=E->next()) { Pair p; PropertyInfo &pi = E->get(); if (pi.usage&PROPERTY_USAGE_STORAGE) { p.first=pi.name; p.second=res_orig->get(pi.name); } propvalues.push_back(p); } String orig_type = res_orig->get_class(); Object *inst = ClassDB::instance( orig_type ); Ref res = Ref( inst->cast_to() ); ERR_FAIL_COND(res.is_null()); for(List< Pair >::Element *E=propvalues.front();E;E=E->next()) { Pair &p=E->get(); res->set(p.first,p.second); } v=res.get_ref_ptr(); emit_signal("variant_changed"); hide(); } break; case OBJ_MENU_COPY: { EditorSettings::get_singleton()->set_resource_clipboard(v); } break; case OBJ_MENU_PASTE: { v=EditorSettings::get_singleton()->get_resource_clipboard(); emit_signal("variant_changed"); } break; case OBJ_MENU_REIMPORT: { RES r=v; /* if (r.is_valid() && r->get_import_metadata().is_valid()) { Ref rimd = r->get_import_metadata(); Ref eip = EditorImportExport::get_singleton()->get_import_plugin_by_name(rimd->get_editor()); if (eip.is_valid()) { eip->import_dialog(r->get_path()); } }*/ } break; case OBJ_MENU_NEW_SCRIPT: { if (owner->cast_to()) EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(owner->cast_to()); } break; case OBJ_MENU_SHOW_IN_FILE_SYSTEM: { RES r=v; FileSystemDock *file_system_dock=EditorNode::get_singleton()->get_filesystem_dock(); file_system_dock->navigate_to_path(r->get_path()); // Ensure that the FileSystem dock is visible. TabContainer* tab_container=(TabContainer*)file_system_dock->get_parent_control(); tab_container->set_current_tab(file_system_dock->get_position_in_parent()); } break; default: { ERR_FAIL_COND( inheritors_array.empty() ); String intype=inheritors_array[p_which-TYPE_BASE_ID]; if (intype=="ViewportTexture") { scene_tree->set_title(TTR("Pick a Viewport")); scene_tree->popup_centered_ratio(); picking_viewport=true; return; } Object *obj = ClassDB::instance(intype); ERR_BREAK( !obj ); Resource *res=obj->cast_to(); ERR_BREAK( !res ); if (owner && hint==PROPERTY_HINT_RESOURCE_TYPE && hint_text=="Script") { //make visual script the right type res->call("set_instance_base_type",owner->get_class()); } v=Ref(res).get_ref_ptr(); emit_signal("variant_changed"); } break; } } break; default:{} } } void CustomPropertyEditor::hide_menu() { menu->hide(); } Variant CustomPropertyEditor::get_variant() const { return v; } String CustomPropertyEditor::get_name() const { return name; } bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Type p_type, const Variant& p_variant,int p_hint,String p_hint_text) { owner=p_owner; updating=true; name=p_name; v=p_variant; field_names.clear(); hint=p_hint; hint_text=p_hint_text; type_button->hide(); if (color_picker) color_picker->hide(); texture_preview->hide(); inheritors_array.clear(); text_edit->hide(); easing_draw->hide(); spinbox->hide(); slider->hide(); for (int i=0;ihide(); value_label[i]->hide(); if (i<4) scroll[i]->hide(); } for (int i=0;ihide(); } checks20gc->hide(); for(int i=0;i<20;i++) checks20[i]->hide(); type = (p_variant.get_type()!=Variant::NIL && p_variant.get_type()!=Variant::_RID && p_type!=Variant::OBJECT)? p_variant.get_type() : p_type; switch(type) { case Variant::BOOL: { checks20gc->show(); CheckBox *c=checks20[0]; c->set_text("True"); checks20gc->set_pos(Vector2(4,4)); c->set_pressed(v); c->show(); checks20gc->set_size(checks20gc->get_minimum_size()); set_size(checks20gc->get_pos()+checks20gc->get_size()+Vector2(4,4)*EDSCALE); } break; case Variant::INT: case Variant::REAL: { if (hint==PROPERTY_HINT_RANGE) { int c = hint_text.get_slice_count(","); float min=0,max=100,step=1; if (c>=1) { if (!hint_text.get_slice(",",0).empty()) min=hint_text.get_slice(",",0).to_double(); } if (c>=2) { if (!hint_text.get_slice(",",1).empty()) max=hint_text.get_slice(",",1).to_double(); } if (c>=3) { if (!hint_text.get_slice(",",2).empty()) step= hint_text.get_slice(",",2).to_double(); } if (c>=4 && hint_text.get_slice(",",3)=="slider") { slider->set_min(min); slider->set_max(max); slider->set_step(step); slider->set_value(v); slider->show(); set_size(Size2(110,30)*EDSCALE); } else { spinbox->set_min(min); spinbox->set_max(max); spinbox->set_step(step); spinbox->set_value(v); spinbox->show(); set_size(Size2(70,35)*EDSCALE); } } else if (hint==PROPERTY_HINT_ENUM) { menu->clear(); Vector options = hint_text.split(","); for(int i=0;iadd_item(options[i],i); } menu->set_pos(get_pos()); menu->popup(); hide(); updating=false; return false; } else if (hint==PROPERTY_HINT_LAYERS_2D_PHYSICS || hint==PROPERTY_HINT_LAYERS_2D_RENDER || hint==PROPERTY_HINT_LAYERS_3D_PHYSICS || hint==PROPERTY_HINT_LAYERS_3D_RENDER) { String title; String basename; switch (hint) { case PROPERTY_HINT_LAYERS_2D_RENDER: basename="layer_names/2d_render"; title="2D Render Layers"; break; case PROPERTY_HINT_LAYERS_2D_PHYSICS: basename="layer_names/2d_physics"; title="2D Physics Layers"; break; case PROPERTY_HINT_LAYERS_3D_RENDER: basename="layer_names/3d_render"; title="3D Render Layers"; break; case PROPERTY_HINT_LAYERS_3D_PHYSICS: basename="layer_names/3d_physics";title="3D Physics Layers"; break; } checks20gc->show(); uint32_t flgs = v; for(int i=0;i<2;i++) { Point2 ofs(4,4); ofs.y+=22*i; for(int j=0;j<10;j++) { int idx = i*10+j; CheckBox *c=checks20[idx]; c->set_text(GlobalConfig::get_singleton()->get(basename+"/layer_"+itos(idx+1))); c->set_pressed( flgs & (1<<(i*10+j)) ); c->show(); } } show(); value_label[0]->set_text(title); value_label[0]->show(); value_label[0]->set_pos(Vector2(4,4)*EDSCALE); checks20gc->set_pos(Vector2(4,4)*EDSCALE+Vector2(0,value_label[0]->get_size().height+4*EDSCALE)); checks20gc->set_size(checks20gc->get_minimum_size()); set_size(Vector2(4,4)*EDSCALE+checks20gc->get_pos()+checks20gc->get_size()); } else if (hint==PROPERTY_HINT_EXP_EASING) { easing_draw->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,5); easing_draw->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,5); easing_draw->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,5); easing_draw->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,30); type_button->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,3); type_button->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,3); type_button->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,25); type_button->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,7); type_button->set_text(TTR("Preset..")); type_button->get_popup()->clear(); type_button->get_popup()->add_item(TTR("Linear"),EASING_LINEAR); type_button->get_popup()->add_item(TTR("Ease In"),EASING_EASE_IN); type_button->get_popup()->add_item(TTR("Ease Out"),EASING_EASE_OUT); if (hint_text!="attenuation") { type_button->get_popup()->add_item(TTR("Zero"),EASING_ZERO); type_button->get_popup()->add_item(TTR("Easing In-Out"),EASING_IN_OUT); type_button->get_popup()->add_item(TTR("Easing Out-In"),EASING_OUT_IN); } type_button->show(); easing_draw->show(); set_size(Size2(200,150)*EDSCALE); } else if (hint==PROPERTY_HINT_FLAGS) { menu->clear(); Vector flags = hint_text.split(","); for(int i=0;iadd_check_item(flag,i); int f = v; if (f&(1<set_item_checked(menu->get_item_index(i),true); } menu->set_pos(get_pos()); menu->popup(); hide(); updating=false; return false; } else { List names; names.push_back("value:"); config_value_editors(1,1,50,names); value_editor[0]->set_text( String::num(v) ); } } break; case Variant::STRING: { if (hint==PROPERTY_HINT_FILE || hint==PROPERTY_HINT_GLOBAL_FILE) { List names; names.push_back(TTR("File..")); names.push_back(TTR("Clear")); config_action_buttons(names); } else if (hint==PROPERTY_HINT_DIR || hint==PROPERTY_HINT_GLOBAL_DIR) { List names; names.push_back(TTR("Dir..")); names.push_back(TTR("Clear")); config_action_buttons(names); } else if (hint==PROPERTY_HINT_ENUM) { menu->clear(); Vector options = hint_text.split(","); for(int i=0;iadd_item(options[i],i); } menu->set_pos(get_pos()); menu->popup(); hide(); updating=false; return false; } else if (hint==PROPERTY_HINT_MULTILINE_TEXT) { text_edit->show(); text_edit->set_text(v); //action_buttons[0]; int button_margin = get_constant("button_margin","Dialogs"); int margin = get_constant("margin","Dialogs"); action_buttons[0]->set_anchor( MARGIN_LEFT, ANCHOR_END ); action_buttons[0]->set_anchor( MARGIN_TOP, ANCHOR_END ); action_buttons[0]->set_anchor( MARGIN_RIGHT, ANCHOR_END ); action_buttons[0]->set_anchor( MARGIN_BOTTOM, ANCHOR_END ); action_buttons[0]->set_begin( Point2( 70, button_margin-5 ) ); action_buttons[0]->set_end( Point2( margin, margin ) ); action_buttons[0]->set_text(TTR("Close")); action_buttons[0]->show(); } else if (hint==PROPERTY_HINT_TYPE_STRING) { /* FIXME: This is repeated twice, with slightly different behavior! Which one? Check line 644 */ if (!create_dialog) { create_dialog = memnew( CreateDialog ); create_dialog->connect("create",this,"_create_dialog_callback"); add_child(create_dialog); } if (hint_text!=String()) { create_dialog->set_base_type(hint_text); } else { create_dialog->set_base_type("Object"); } create_dialog->popup(false); hide(); updating=false; return false; } else if (hint==PROPERTY_HINT_METHOD_OF_VARIANT_TYPE) { #define MAKE_PROPSELECT if (!property_select) { property_select = memnew(PropertySelector); property_select->connect("selected",this,"_create_selected_property"); add_child(property_select); } hide(); MAKE_PROPSELECT; Variant::Type type=Variant::NIL; for(int i=0;iselect_method_from_basic_type(type,v); updating=false; return false; } else if (hint==PROPERTY_HINT_METHOD_OF_BASE_TYPE) { MAKE_PROPSELECT property_select->select_method_from_base_type(hint_text,v); updating=false; return false; } else if (hint==PROPERTY_HINT_METHOD_OF_INSTANCE) { MAKE_PROPSELECT Object *instance = ObjectDB::get_instance(hint_text.to_int64()); if (instance) property_select->select_method_from_instance(instance,v); updating=false; return false; } else if (hint==PROPERTY_HINT_METHOD_OF_SCRIPT) { MAKE_PROPSELECT Object *obj = ObjectDB::get_instance(hint_text.to_int64()); if (obj && obj->cast_to