Add math/script expression evaluation in editor (#3620)

Rebase of #453
This commit is contained in:
Franco Eusébio Garcia 2016-05-01 05:33:32 -03:00 committed by Rémi Verschelde
parent ff40dcd83f
commit a735573327
5 changed files with 252 additions and 40 deletions

View File

@ -0,0 +1,43 @@
/*************************************************************************/
/* value_evaluator.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2014 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. */
/*************************************************************************/
#ifndef VALUE_EVALUATOR_H
#define VALUE_EVALUATOR_H
#include "core/object.h"
class ValueEvaluator : public Object {
OBJ_TYPE(ValueEvaluator, Object);
public:
virtual double eval(const String& p_text) {
return p_text.to_double();
}
};
#endif // VALUE_EVALUATOR_H

View File

@ -154,7 +154,7 @@ void TreeItem::set_text(int p_column,String p_text) {
ERR_FAIL_INDEX( p_column, cells.size() );
cells[p_column].text=p_text;
if (cells[p_column].mode==TreeItem::CELL_MODE_RANGE) {
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(",");
@ -704,6 +704,7 @@ void TreeItem::_bind_methods() {
BIND_CONSTANT( CELL_MODE_STRING );
BIND_CONSTANT( CELL_MODE_CHECK );
BIND_CONSTANT( CELL_MODE_RANGE );
BIND_CONSTANT( CELL_MODE_RANGE_EXPRESSION );
BIND_CONSTANT( CELL_MODE_ICON );
BIND_CONSTANT( CELL_MODE_CUSTOM );
@ -1127,7 +1128,8 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
//font->draw( ci, text_pos, p_item->cells[i].text, col,item_rect.size.x-check_w );
} break;
case TreeItem::CELL_MODE_RANGE: {
case TreeItem::CELL_MODE_RANGE:
case TreeItem::CELL_MODE_RANGE_EXPRESSION: {
if (p_item->cells[i].text!="") {
@ -1594,7 +1596,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
}
} break;
case TreeItem::CELL_MODE_RANGE: {
case TreeItem::CELL_MODE_RANGE:
case TreeItem::CELL_MODE_RANGE_EXPRESSION: {
if (c.text!="") {
@ -1794,6 +1797,13 @@ void Tree::text_editor_enter(String p_text) {
//popup_edited_item->edited_signal.call( popup_edited_item_col );
} break;
case TreeItem::CELL_MODE_RANGE_EXPRESSION: {
if(evaluator)
c.val=evaluator->eval(p_text);
else
c.val=p_text.to_double();
} break;
default: { ERR_FAIL(); }
}
@ -2372,7 +2382,7 @@ bool Tree::edit_selected() {
item_edited(col,s);
return true;
} else if (c.mode==TreeItem::CELL_MODE_RANGE && c.text!="") {
} else if ((c.mode==TreeItem::CELL_MODE_RANGE||c.mode==TreeItem::CELL_MODE_RANGE_EXPRESSION) && c.text!="") {
popup_menu->clear();
for (int i=0;i<c.text.get_slice_count(",");i++) {
@ -2389,7 +2399,7 @@ bool Tree::edit_selected() {
popup_edited_item_col=col;
return true;
} else if (c.mode==TreeItem::CELL_MODE_STRING || c.mode==TreeItem::CELL_MODE_RANGE) {
} else if (c.mode==TreeItem::CELL_MODE_STRING || c.mode==TreeItem::CELL_MODE_RANGE || c.mode==TreeItem::CELL_MODE_RANGE_EXPRESSION ) {
Point2i textedpos=get_global_pos() + rect.pos;
text_editor->set_pos( textedpos );
@ -2398,7 +2408,7 @@ bool Tree::edit_selected() {
text_editor->set_text( c.mode==TreeItem::CELL_MODE_STRING?c.text:rtos(c.val) );
text_editor->select_all();
if (c.mode==TreeItem::CELL_MODE_RANGE) {
if (c.mode==TreeItem::CELL_MODE_RANGE || c.mode==TreeItem::CELL_MODE_RANGE_EXPRESSION ) {
value_editor->set_pos(textedpos + Point2i(0,text_editor->get_size().height) );
value_editor->set_size( Size2(rect.size.width,1));
@ -3227,6 +3237,9 @@ bool Tree::is_folding_hidden() const {
return hide_folding;
}
void Tree::set_value_evaluator(ValueEvaluator *p_evaluator) {
evaluator = p_evaluator;
}
void Tree::_bind_methods() {
@ -3367,6 +3380,7 @@ Tree::Tree() {
hide_folding=false;
evaluator=NULL;
}

View File

@ -34,6 +34,7 @@
#include "scene/gui/line_edit.h"
#include "scene/gui/scroll_bar.h"
#include "scene/gui/slider.h"
#include "core/helper/value_evaluator.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
@ -52,6 +53,7 @@ public:
CELL_MODE_STRING, ///< just a string
CELL_MODE_CHECK, ///< string + check
CELL_MODE_RANGE, ///< Contains a range
CELL_MODE_RANGE_EXPRESSION, ///< Contains a range
CELL_MODE_ICON, ///< Contains a icon, not editable
CELL_MODE_CUSTOM, ///< Contains a custom value, show a string, and an edit button
};
@ -422,6 +424,8 @@ friend class TreeItem;
bool hide_folding;
ValueEvaluator *evaluator;
protected:
static void _bind_methods();
@ -482,7 +486,7 @@ public:
void set_hide_folding(bool p_hide);
bool is_folding_hidden() const;
void set_value_evaluator(ValueEvaluator *p_evaluator);
Tree();
~Tree();

View File

@ -1313,6 +1313,9 @@ void CustomPropertyEditor::_modified(String p_string) {
case Variant::REAL: {
if (hint!=PROPERTY_HINT_EXP_EASING) {
if (evaluator)
evaluator->eval(value_editor[0]->get_text());
else
v=value_editor[0]->get_text().to_double();
emit_signal("variant_changed");
@ -1327,8 +1330,13 @@ void CustomPropertyEditor::_modified(String p_string) {
case Variant::VECTOR2: {
Vector2 vec;
if (evaluator) {
vec.x=evaluator->eval(value_editor[0]->get_text());
vec.y=evaluator->eval(value_editor[1]->get_text());
} else {
vec.x=value_editor[0]->get_text().to_double();
vec.y=value_editor[1]->get_text().to_double();
}
v=vec;
emit_signal("variant_changed");
@ -1336,10 +1344,17 @@ void CustomPropertyEditor::_modified(String p_string) {
case Variant::RECT2: {
Rect2 r2;
if (evaluator) {
r2.pos.x=evaluator->eval(value_editor[0]->get_text());
r2.pos.y=evaluator->eval(value_editor[1]->get_text());
r2.size.x=evaluator->eval(value_editor[2]->get_text());
r2.size.y=evaluator->eval(value_editor[3]->get_text());
} else {
r2.pos.x=value_editor[0]->get_text().to_double();
r2.pos.y=value_editor[1]->get_text().to_double();
r2.size.x=value_editor[2]->get_text().to_double();
r2.size.y=value_editor[3]->get_text().to_double();
}
v=r2;
emit_signal("variant_changed");
@ -1348,9 +1363,15 @@ void CustomPropertyEditor::_modified(String p_string) {
case Variant::VECTOR3: {
Vector3 vec;
if (evaluator) {
vec.x=evaluator->eval(value_editor[0]->get_text());
vec.y=evaluator->eval(value_editor[1]->get_text());
vec.z=evaluator->eval(value_editor[2]->get_text());
} else {
vec.x=value_editor[0]->get_text().to_double();
vec.y=value_editor[1]->get_text().to_double();
vec.z=value_editor[2]->get_text().to_double();
}
v=vec;
emit_signal("variant_changed");
@ -1358,10 +1379,17 @@ void CustomPropertyEditor::_modified(String p_string) {
case Variant::PLANE: {
Plane pl;
if (evaluator) {
pl.normal.x=evaluator->eval(value_editor[0]->get_text());
pl.normal.y=evaluator->eval(value_editor[1]->get_text());
pl.normal.z=evaluator->eval(value_editor[2]->get_text());
pl.d=evaluator->eval(value_editor[3]->get_text());
} else {
pl.normal.x=value_editor[0]->get_text().to_double();
pl.normal.y=value_editor[1]->get_text().to_double();
pl.normal.z=value_editor[2]->get_text().to_double();
pl.d=value_editor[3]->get_text().to_double();
}
v=pl;
emit_signal("variant_changed");
@ -1369,10 +1397,17 @@ void CustomPropertyEditor::_modified(String p_string) {
case Variant::QUAT: {
Quat q;
if (evaluator) {
q.x=evaluator->eval(value_editor[0]->get_text());
q.y=evaluator->eval(value_editor[1]->get_text());
q.z=evaluator->eval(value_editor[2]->get_text());
q.w=evaluator->eval(value_editor[3]->get_text());
} else {
q.x=value_editor[0]->get_text().to_double();
q.y=value_editor[1]->get_text().to_double();
q.z=value_editor[2]->get_text().to_double();
q.w=value_editor[3]->get_text().to_double();
}
v=q;
emit_signal("variant_changed");
@ -1380,14 +1415,23 @@ void CustomPropertyEditor::_modified(String p_string) {
case Variant::_AABB: {
Vector3 pos;
Vector3 size;
if (evaluator) {
pos.x=evaluator->eval(value_editor[0]->get_text());
pos.y=evaluator->eval(value_editor[1]->get_text());
pos.z=evaluator->eval(value_editor[2]->get_text());
size.x=evaluator->eval(value_editor[3]->get_text());
size.y=evaluator->eval(value_editor[4]->get_text());
size.z=evaluator->eval(value_editor[5]->get_text());
} else {
pos.x=value_editor[0]->get_text().to_double();
pos.y=value_editor[1]->get_text().to_double();
pos.z=value_editor[2]->get_text().to_double();
Vector3 size;
size.x=value_editor[3]->get_text().to_double();
size.y=value_editor[4]->get_text().to_double();
size.z=value_editor[5]->get_text().to_double();
}
v=AABB(pos,size);
emit_signal("variant_changed");
@ -1396,9 +1440,12 @@ void CustomPropertyEditor::_modified(String p_string) {
Matrix32 m;
for(int i=0;i<6;i++) {
if (evaluator) {
m.elements[i/2][i%2]=evaluator->eval(value_editor[i]->get_text());
} else {
m.elements[i/2][i%2]=value_editor[i]->get_text().to_double();
}
}
v=m;
emit_signal("variant_changed");
@ -1409,8 +1456,12 @@ void CustomPropertyEditor::_modified(String p_string) {
Matrix3 m;
for(int i=0;i<9;i++) {
if (evaluator) {
m.elements[i/3][i%3]=evaluator->eval(value_editor[i]->get_text());
} else {
m.elements[i/3][i%3]=value_editor[i]->get_text().to_double();
}
}
v=m;
emit_signal("variant_changed");
@ -1421,13 +1472,24 @@ void CustomPropertyEditor::_modified(String p_string) {
Matrix3 basis;
for(int i=0;i<9;i++) {
if (evaluator) {
basis.elements[i/3][i%3]=evaluator->eval(value_editor[(i/3)*4+i%3]->get_text());
} else {
basis.elements[i/3][i%3]=value_editor[(i/3)*4+i%3]->get_text().to_double();
}
}
Vector3 origin;
if (evaluator) {
origin.x=evaluator->eval(value_editor[3]->get_text());
origin.y=evaluator->eval(value_editor[7]->get_text());
origin.z=evaluator->eval(value_editor[11]->get_text());
} else {
origin.x=value_editor[3]->get_text().to_double();
origin.y=value_editor[7]->get_text().to_double();
origin.z=value_editor[11]->get_text().to_double();
}
v=Transform(basis,origin);
emit_signal("variant_changed");
@ -1736,6 +1798,8 @@ CustomPropertyEditor::CustomPropertyEditor() {
add_child(menu);
menu->connect("item_pressed",this,"_menu_option");
evaluator = NULL;
spinbox = memnew ( SpinBox );
add_child(spinbox);
spinbox->set_area_as_parent_rect(5);
@ -1750,7 +1814,7 @@ CustomPropertyEditor::CustomPropertyEditor() {
bool PropertyEditor::_might_be_in_instance() {
if (!obj)
return NULL;
return false;
Node *node = obj->cast_to<Node>();
@ -2695,8 +2759,11 @@ void PropertyEditor::update_tree() {
}
if (p.hint==PROPERTY_HINT_ENUM)
item->set_cell_mode( 1, TreeItem::CELL_MODE_RANGE );
else
item->set_cell_mode( 1, TreeItem::CELL_MODE_RANGE_EXPRESSION );
if (p.hint==PROPERTY_HINT_SPRITE_FRAME) {
item->set_range_config(1,0,99999,1);
@ -3390,6 +3457,9 @@ void PropertyEditor::edit(Object* p_object) {
}
obj=p_object;
evaluator->edit(p_object);
update_tree();
if (obj) {
@ -3719,6 +3789,10 @@ PropertyEditor::PropertyEditor() {
custom_editor->connect("resource_edit_request", this,"_resource_edit_request",make_binds(),CONNECT_DEFERRED);
tree->set_hide_folding(true);
evaluator = memnew (PropertyValueEvaluator);
tree->set_value_evaluator(evaluator);
custom_editor->set_value_evaluator(evaluator);
capitalize_paths=true;
autoclear=false;
tree->set_column_titles_visible(false);
@ -3737,6 +3811,7 @@ PropertyEditor::PropertyEditor() {
PropertyEditor::~PropertyEditor()
{
memdelete(evaluator);
}
@ -3975,3 +4050,51 @@ SectionedPropertyEditor::~SectionedPropertyEditor() {
memdelete(filter);
}
double PropertyValueEvaluator::eval(const String& p_text) {
if (!obj)
return _default_eval(p_text);
Ref<Script> script= Ref<Script>(script_language ->create_script());
script->set_source_code(_build_script(p_text));
Error err = script->reload();
if (err) {
print_line("[PropertyValueEvaluator] Error loading script for expression: " + p_text);
return _default_eval(p_text);
}
ScriptInstance *script_instance = script->instance_create(this);
Variant::CallError call_err;
script_instance->call("set_this",obj);
double result = script_instance->call("e", NULL, 0, call_err );
if (call_err.error == Variant::CallError::CALL_OK) {
return result;
}
print_line("[PropertyValueEvaluator]: Error eval! Error code: " + itos(call_err.error));
memdelete(script_instance);
return _default_eval(p_text);
}
void PropertyValueEvaluator::edit(Object *p_obj) {
obj = p_obj;
}
String PropertyValueEvaluator::_build_script(const String& p_text) {
String script_text = "tool\nvar this\nfunc set_this(p_this):\n\tthis=p_this\nfunc e():\n\treturn ";
script_text += p_text.strip_edges();
script_text += "\n";
return script_text;
}
PropertyValueEvaluator::PropertyValueEvaluator() {
script_language = ScriptServer::get_language(0); // todo: get script language from editor setting
}
PropertyValueEvaluator::~PropertyValueEvaluator() {
}

View File

@ -46,6 +46,8 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
class PropertyValueEvaluator;
class CustomPropertyEditor : public Popup {
OBJ_TYPE( CustomPropertyEditor, Popup );
@ -104,6 +106,8 @@ class CustomPropertyEditor : public Popup {
bool updating;
PropertyValueEvaluator *evaluator;
void _text_edit_changed();
void _file_selected(String p_file);
void _scroll_modified(double p_value);
@ -137,6 +141,8 @@ public:
void set_read_only(bool p_read_only) { read_only=p_read_only; }
void set_value_evaluator( PropertyValueEvaluator *p_evaluator) { evaluator=p_evaluator; }
bool edit(Object* p_owner,const String& p_name,Variant::Type p_type, const Variant& p_variant,int p_hint,String p_hint_text);
CustomPropertyEditor();
@ -151,6 +157,8 @@ class PropertyEditor : public Control {
//Object *object;
LineEdit *search_box;
PropertyValueEvaluator *evaluator;
Object* obj;
Array _prop_edited_name;
@ -283,4 +291,24 @@ public:
~SectionedPropertyEditor();
};
class PropertyValueEvaluator : public ValueEvaluator {
OBJ_TYPE( PropertyValueEvaluator, ValueEvaluator );
Object *obj;
ScriptLanguage *script_language;
String _build_script(const String& p_text);
_FORCE_INLINE_ double _default_eval(const String& p_text) {
return p_text.to_double();
}
public:
void edit(Object *p_obj);
double eval(const String& p_text);
PropertyValueEvaluator();
~PropertyValueEvaluator();
};
#endif