1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-06 12:20:30 +00:00

2D Animation Improvements

-=-=-=-=-=-=-=-=-=--=-=-=

-Ability to set 2D nodes as bones
-Abity to set 2D nodes as IK chains
-2D IK Solver
-Improvements in the UI for adding keyframes (separate loc,rot,scale buttons)
This commit is contained in:
Juan Linietsky
2014-07-06 11:49:27 -03:00
parent cd80d442a2
commit 3d68949a1c
22 changed files with 1725 additions and 388 deletions

View File

@@ -35,7 +35,7 @@
#include "scene/2d/node_2d.h"
#include "globals.h"
#include "os/input.h"
#include "tools/editor/editor_settings.h"
void CanvasItemEditor::_unhandled_key_input(const InputEvent& p_ev) {
if (!is_visible())
@@ -180,9 +180,9 @@ void CanvasItemEditor::_node_removed(Node *p_node) {
void CanvasItemEditor::_keying_changed(bool p_changed) {
if (p_changed)
animation_menu->show();
animation_hb->show();
else
animation_menu->hide();
animation_hb->hide();
}
// slow but modern computers should have no problem
@@ -639,30 +639,48 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
if (b.button_index==BUTTON_RIGHT) {
if (get_item_count() > 0 && drag!=DRAG_NONE) {
//cancel drag
if (bone_ik_list.size()) {
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<BoneIK>::Element *E=bone_ik_list.back();E;E=E->prev()) {
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
E->get().node->edit_set_state(E->get().orig_state);
}
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
if (!canvas_item)
continue;
if (!canvas_item->is_visible())
continue;
bone_ik_list.clear();
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
continue;
} else {
canvas_item->edit_set_state(se->undo_state);
if (canvas_item->cast_to<Node2D>())
canvas_item->cast_to<Node2D>()->edit_set_pivot(se->undo_pivot);
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
if (!canvas_item)
continue;
if (!canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
continue;
canvas_item->edit_set_state(se->undo_state);
if (canvas_item->cast_to<Node2D>())
canvas_item->cast_to<Node2D>()->edit_set_pivot(se->undo_pivot);
}
}
drag=DRAG_NONE;
viewport->update();
can_move_pivot=false;
} else if (box_selecting) {
box_selecting=false;
viewport->update();
@@ -689,34 +707,55 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
if (undo_redo) {
undo_redo->create_action("Edit CanvasItem");
if (bone_ik_list.size()) {
List<Node*> &selection = editor_selection->get_selected_node_list();
undo_redo->create_action("Edit IK Chain");
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
for(List<BoneIK>::Element *E=bone_ik_list.back();E;E=E->prev()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
if (!canvas_item)
continue;
if (!canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
continue;
undo_redo->add_do_method(E->get().node,"edit_set_state",E->get().node->edit_get_state());
undo_redo->add_undo_method(E->get().node,"edit_set_state",E->get().orig_state);
}
Variant state=canvas_item->edit_get_state();
undo_redo->add_do_method(canvas_item,"edit_set_state",state);
undo_redo->add_undo_method(canvas_item,"edit_set_state",se->undo_state);
if (canvas_item->cast_to<Node2D>()) {
Node2D *pvt = canvas_item->cast_to<Node2D>();
if (pvt->edit_has_pivot()) {
undo_redo->add_do_method(canvas_item,"edit_set_pivot",pvt->edit_get_pivot());
undo_redo->add_undo_method(canvas_item,"edit_set_pivot",se->undo_pivot);
undo_redo->add_do_method(viewport,"update");
undo_redo->add_undo_method(viewport,"update");
bone_ik_list.clear();
undo_redo->commit_action();
} else {
undo_redo->create_action("Edit CanvasItem");
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
if (!canvas_item)
continue;
if (!canvas_item->is_visible())
continue;
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
continue;
Variant state=canvas_item->edit_get_state();
undo_redo->add_do_method(canvas_item,"edit_set_state",state);
undo_redo->add_undo_method(canvas_item,"edit_set_state",se->undo_state);
if (canvas_item->cast_to<Node2D>()) {
Node2D *pvt = canvas_item->cast_to<Node2D>();
if (pvt->edit_has_pivot()) {
undo_redo->add_do_method(canvas_item,"edit_set_pivot",pvt->edit_get_pivot());
undo_redo->add_undo_method(canvas_item,"edit_set_pivot",se->undo_pivot);
}
}
}
undo_redo->commit_action();
}
undo_redo->commit_action();
}
drag=DRAG_NONE;
@@ -759,6 +798,86 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
return;
}
List<BoneList>::Element *Cbone=NULL; //closest
{
bone_ik_list.clear();
float closest_dist=1e20;
int bone_width = EditorSettings::get_singleton()->get("2d_editor/bone_width");
for(List<BoneList>::Element *E=bone_list.front();E;E=E->next()) {
if (E->get().from == E->get().to)
continue;
Vector2 s[2]={
E->get().from,
E->get().to
};
Vector2 p = Geometry::get_closest_point_to_segment_2d(Vector2(b.x,b.y),s);
float d = p.distance_to(Vector2(b.x,b.y));
if (d<bone_width && d<closest_dist) {
Cbone=E;
closest_dist=d;
}
}
if (Cbone) {
Node2D *b=NULL;
Object* obj=ObjectDB::get_instance(Cbone->get().bone);
if (obj)
b=obj->cast_to<Node2D>();
if (b) {
bool ik_found=false;
bool first=true;
while(b) {
CanvasItem *pi=b->get_parent_item();
if (!pi)
break;
float len=pi->get_global_transform().get_origin().distance_to(b->get_global_pos());
b=pi->cast_to<Node2D>();
if (!b)
break;
if (first) {
bone_orig_xform=b->get_global_transform();
first=false;
}
BoneIK bik;
bik.node=b;
bik.len=len;
bik.orig_state=b->edit_get_state();
bone_ik_list.push_back(bik);
if (b->has_meta("_edit_ik_")) {
ik_found=bone_ik_list.size()>1;
break;
}
if (!pi->has_meta("_edit_bone_"))
break;
}
if (!ik_found)
bone_ik_list.clear();
}
}
}
CanvasItem *single_item = get_single_item();
if (single_item) {
@@ -797,7 +916,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
}
}
if (drag!=DRAG_NONE) {
if (drag!=DRAG_NONE && (!Cbone || drag!=DRAG_ALL)) {
drag_from=transform.affine_inverse().xform(click);
se->undo_state=canvas_item->edit_get_state();
if (canvas_item->cast_to<Node2D>())
@@ -856,16 +975,30 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
//no window.... ?
click-=current_window->get_scroll();
}*/
CanvasItem *c=_select_canvas_item_at_pos(click, scene,transform,Matrix32());
CanvasItem *c=NULL;
if (Cbone) {
Object* obj=ObjectDB::get_instance(Cbone->get().bone);
if (obj)
c=obj->cast_to<CanvasItem>();
if (c)
c=c->get_parent_item();
CanvasItem* cn = c;
}
if (!c) {
c =_select_canvas_item_at_pos(click, scene,transform,Matrix32());
while(cn) {
if (cn->has_meta("_edit_group_")) {
c=cn;
CanvasItem* cn = c;
while(cn) {
if (cn->has_meta("_edit_group_")) {
c=cn;
}
cn=cn->get_parent_item();
}
cn=cn->get_parent_item();
}
Node* n = c;
@@ -989,6 +1122,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
@@ -1000,9 +1134,14 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
if (!se)
continue;
canvas_item->edit_set_state(se->undo_state); //reset state and reapply
if (canvas_item->cast_to<Node2D>())
canvas_item->cast_to<Node2D>()->edit_set_pivot(se->undo_pivot);
bool dragging_bone = drag==DRAG_ALL && selection.size()==1 && bone_ik_list.size();
if (!dragging_bone) {
canvas_item->edit_set_state(se->undo_state); //reset state and reapply
if (canvas_item->cast_to<Node2D>())
canvas_item->cast_to<Node2D>()->edit_set_pivot(se->undo_pivot);
}
Vector2 dfrom = drag_from;
@@ -1153,10 +1292,145 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
}
local_rect.pos=begin;
local_rect.size=end-begin;
canvas_item->edit_set_rect(local_rect);
if (!dragging_bone) {
local_rect.pos=begin;
local_rect.size=end-begin;
canvas_item->edit_set_rect(local_rect);
} else {
//ok, all that had to be done was done, now solve IK
Node2D *n2d = canvas_item->cast_to<Node2D>();
Matrix32 final_xform = bone_orig_xform;
if (n2d) {
float total_len = 0;
for (List<BoneIK>::Element *E=bone_ik_list.front();E;E=E->next()) {
if (E->prev())
total_len+=E->get().len;
E->get().pos = E->get().node->get_global_transform().get_origin();
}
{
final_xform.elements[2]+=dto-dfrom;//final_xform.affine_inverse().basis_xform_inv(drag_vector);
//n2d->set_global_transform(final_xform);
}
CanvasItem *last = bone_ik_list.back()->get().node;
if (!last)
break;
Vector2 root_pos = last->get_global_transform().get_origin();
Vector2 leaf_pos = final_xform.get_origin();
if ((leaf_pos.distance_to(root_pos)) > total_len) {
//oops dude you went too far
//print_line("TOO FAR!");
Vector2 rel = leaf_pos - root_pos;
rel = rel.normalized() * total_len;
leaf_pos=root_pos+rel;
}
bone_ik_list.front()->get().pos=leaf_pos;
//print_line("BONE IK LIST "+itos(bone_ik_list.size()));
if (bone_ik_list.size()>2) {
int solver_iterations=64;
float solver_k=0.3;
for(int i=0;i<solver_iterations;i++) {
for (List<BoneIK>::Element *E=bone_ik_list.front();E;E=E->next()) {
if (E==bone_ik_list.back()) {
break;
}
float len = E->next()->get().len;
if (E->next()==bone_ik_list.back()) {
//print_line("back");
Vector2 rel = E->get().pos - E->next()->get().pos;
//print_line("PREV "+E->get().pos);
Vector2 desired = E->next()->get().pos+rel.normalized()*len;
//print_line("DESIRED "+desired);
E->get().pos=E->get().pos.linear_interpolate(desired,solver_k);
//print_line("POST "+E->get().pos);
} else if (E==bone_ik_list.front()) {
//only adjust parent
//print_line("front");
Vector2 rel = E->next()->get().pos - E->get().pos;
//print_line("PREV "+E->next()->get().pos);
Vector2 desired = E->get().pos+rel.normalized()*len;
//print_line("DESIRED "+desired);
E->next()->get().pos=E->next()->get().pos.linear_interpolate(desired,solver_k);
//print_line("POST "+E->next()->get().pos);
} else {
Vector2 rel = E->next()->get().pos - E->get().pos;
Vector2 cen = (E->next()->get().pos + E->get().pos)*0.5;
rel=rel.linear_interpolate(rel.normalized()*len,solver_k);
rel*=0.5;
E->next()->get().pos=cen+rel;
E->get().pos=cen-rel;
//print_line("mid");
}
}
}
}
}
for (List<BoneIK>::Element *E=bone_ik_list.back();E;E=E->prev()) {
Node2D *n = E->get().node;
if (!E->prev()) {
//last goes to what it was
final_xform.set_origin(n->get_global_pos());
n->set_global_transform(final_xform);
} else {
Vector2 rel = (E->prev()->get().node->get_global_pos() - n->get_global_pos()).normalized();
Vector2 rel2 = (E->prev()->get().pos - E->get().pos).normalized();
float rot = rel.angle_to(rel2);
if (n->get_global_transform().basis_determinant()<0) {
//mirrored, rotate the other way
rot=-rot;
}
n->rotate(rot);
}
}
break;
}
}
}
@@ -1393,7 +1667,77 @@ void CanvasItemEditor::_viewport_draw() {
}
int bone_width = EditorSettings::get_singleton()->get("2d_editor/bone_width");
Color bone_color1 = EditorSettings::get_singleton()->get("2d_editor/bone_color1");
Color bone_color2 = EditorSettings::get_singleton()->get("2d_editor/bone_color2");
Color bone_ik_color = EditorSettings::get_singleton()->get("2d_editor/bone_ik_color");
Color bone_selected_color = EditorSettings::get_singleton()->get("2d_editor/bone_selected_color");
for(List<BoneList>::Element*E=bone_list.front();E;E=E->next()) {
E->get().from=Vector2();
E->get().to=Vector2();
Object *obj = ObjectDB::get_instance(E->get().bone);
if (!obj)
continue;
Node2D* n2d = obj->cast_to<Node2D>();
if (!n2d)
continue;
if (!n2d->get_parent())
continue;
CanvasItem *pi = n2d->get_parent_item();
Node2D* pn2d=n2d->get_parent()->cast_to<Node2D>();
if (!pn2d)
continue;
Vector2 from = transform.xform(pn2d->get_global_pos());
Vector2 to = transform.xform(n2d->get_global_pos());
E->get().from=from;
E->get().to=to;
Vector2 rel = to-from;
Vector2 relt = rel.tangent().normalized()*bone_width;
Vector<Vector2> bone_shape;
bone_shape.push_back(from);
bone_shape.push_back(from+rel*0.2+relt);
bone_shape.push_back(to);
bone_shape.push_back(from+rel*0.2-relt);
Vector<Color> colors;
if (pi->has_meta("_edit_ik_")) {
colors.push_back(bone_ik_color);
colors.push_back(bone_ik_color);
colors.push_back(bone_ik_color);
colors.push_back(bone_ik_color);
} else {
colors.push_back(bone_color1);
colors.push_back(bone_color2);
colors.push_back(bone_color1);
colors.push_back(bone_color2);
}
VisualServer::get_singleton()->canvas_item_add_primitive(ci,bone_shape,colors,Vector<Vector2>(),RID());
if (editor_selection->is_selected(pi)) {
for(int i=0;i<bone_shape.size();i++) {
VisualServer::get_singleton()->canvas_item_add_line(ci,bone_shape[i],bone_shape[(i+1)%bone_shape.size()],bone_selected_color,2);
}
}
}
}
void CanvasItemEditor::_notification(int p_what) {
@@ -1445,6 +1789,7 @@ void CanvasItemEditor::_notification(int p_what) {
unlock_button->set_icon(get_icon("Unlock","EditorIcons"));
group_button->set_icon(get_icon("Group","EditorIcons"));
ungroup_button->set_icon(get_icon("Ungroup","EditorIcons"));
key_insert_button->set_icon(get_icon("Key","EditorIcons"));
}
@@ -1509,6 +1854,13 @@ void CanvasItemEditor::_find_canvas_items_span(Node *p_node, Rect2& r_rect, cons
lock_list.push_back(lock);
}
if (c->has_meta("_edit_bone_")) {
BoneList bone;
bone.bone=c->get_instance_ID();
bone_list.push_back(bone);
}
r_rect.expand_to( xform.xform(rect.pos) );
r_rect.expand_to( xform.xform(rect.pos+Point2(rect.size.x,0)) );
r_rect.expand_to( xform.xform(rect.pos+Point2(0,rect.size.y)) );
@@ -1541,6 +1893,7 @@ void CanvasItemEditor::_update_scrollbars() {
Rect2 canvas_item_rect=Rect2(Point2(),screen_rect);
lock_list.clear();;
bone_list.clear();;
if (editor->get_edited_scene())
_find_canvas_items_span(editor->get_edited_scene(),canvas_item_rect,Matrix32());
@@ -1878,6 +2231,44 @@ void CanvasItemEditor::_popup_callback(int p_op) {
editor->get_animation_editor()->insert_node_value_key(n2d,"transform/rot",Math::rad2deg(n2d->get_rot()),existing);
if (key_scale)
editor->get_animation_editor()->insert_node_value_key(n2d,"transform/scale",n2d->get_scale(),existing);
if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) {
//look for an IK chain
List<Node2D*> ik_chain;
Node2D *n = n2d->get_parent_item()->cast_to<Node2D>();
bool has_chain=false;
while(n) {
ik_chain.push_back(n);
if (n->has_meta("_edit_ik_")) {
has_chain=true;
break;
}
if (!n->get_parent_item())
break;
n=n->get_parent_item()->cast_to<Node2D>();
}
if (has_chain && ik_chain.size()) {
for(List<Node2D*>::Element *F=ik_chain.front();F;F=F->next()) {
if (key_pos)
editor->get_animation_editor()->insert_node_value_key(F->get(),"transform/pos",F->get()->get_pos(),existing);
if (key_rot)
editor->get_animation_editor()->insert_node_value_key(F->get(),"transform/rot",Math::rad2deg(F->get()->get_rot()),existing);
if (key_scale)
editor->get_animation_editor()->insert_node_value_key(F->get(),"transform/scale",F->get()->get_scale(),existing);
}
}
}
} else if (canvas_item->cast_to<Control>()) {
Control *ctrl = canvas_item->cast_to<Control>();
@@ -1891,10 +2282,20 @@ void CanvasItemEditor::_popup_callback(int p_op) {
}
} break;
case ANIM_INSERT_POS:
case ANIM_INSERT_ROT:
case ANIM_INSERT_SCALE:
case ANIM_INSERT_POS_ROT:
case ANIM_INSERT_POS: {
key_pos = key_loc_button->is_pressed();
} break;
case ANIM_INSERT_ROT: {
key_pos = key_rot_button->is_pressed();
} break;
case ANIM_INSERT_SCALE: {
key_scale = key_scale_button->is_pressed();
} break;
/*
case ANIM_INSERT_POS_ROT
case ANIM_INSERT_POS_SCALE:
case ANIM_INSERT_ROT_SCALE:
case ANIM_INSERT_POS_ROT_SCALE: {
@@ -1917,7 +2318,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
animation_menu->get_popup()->set_item_checked(idx,i==p_op);
}
} break;
} break;*/
case ANIM_COPY_POSE: {
pose_clipboard.clear();;
@@ -2061,6 +2462,85 @@ void CanvasItemEditor::_popup_callback(int p_op) {
}
} break;
case SKELETON_MAKE_BONES: {
Map<Node*,Object*> &selection = editor_selection->get_selection();
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
Node2D *n2d = E->key()->cast_to<Node2D>();
if (!n2d)
continue;
if (!n2d->is_visible())
continue;
if (!n2d->get_parent_item())
continue;
n2d->set_meta("_edit_bone_",true);
}
viewport->update();
} break;
case SKELETON_CLEAR_BONES: {
Map<Node*,Object*> &selection = editor_selection->get_selection();
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
Node2D *n2d = E->key()->cast_to<Node2D>();
if (!n2d)
continue;
if (!n2d->is_visible())
continue;
n2d->set_meta("_edit_bone_",Variant());
}
viewport->update();
} break;
case SKELETON_SET_IK_CHAIN: {
List<Node*> &selection = editor_selection->get_selected_node_list();
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
if (!canvas_item)
continue;
if (!canvas_item->is_visible())
continue;
canvas_item->set_meta("_edit_ik_",true);
}
viewport->update();
} break;
case SKELETON_CLEAR_IK_CHAIN: {
Map<Node*,Object*> &selection = editor_selection->get_selection();
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *n2d = E->key()->cast_to<CanvasItem>();
if (!n2d)
continue;
if (!n2d->is_visible())
continue;
n2d->set_meta("_edit_ik_",Variant());
}
viewport->update();
} break;
}
}
#if 0
@@ -2296,6 +2776,18 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_check_item("Use Pixel Snap",SNAP_USE_PIXEL);
p->add_separator();
p->add_item("Expand to Parent",EXPAND_TO_PARENT,KEY_MASK_CMD|KEY_P);
p->add_separator();
p->add_submenu_item("Skeleton..","skeleton");
PopupMenu *p2 = memnew(PopupMenu);
p->add_child(p2);
p2->set_name("skeleton");
p2->add_item("Make Bones",SKELETON_MAKE_BONES,KEY_MASK_CMD|KEY_SHIFT|KEY_B);
p2->add_item("Clear Bones",SKELETON_CLEAR_BONES);
p2->add_separator();
p2->add_item("Make IK Chain",SKELETON_SET_IK_CHAIN);
p2->add_item("Clear IK Chain",SKELETON_CLEAR_IK_CHAIN);
p2->connect("item_pressed", this,"_popup_callback");
/*
p->add_item("Align Horizontal",ALIGN_HORIZONTAL);
@@ -2314,12 +2806,50 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_item("Zoom Out",ZOOM_OUT);
p->add_item("Zoom Reset",ZOOM_RESET);
p->add_item("Zoom Set..",ZOOM_SET);
p->add_separator();
p->add_item("Center Selection", VIEW_CENTER_TO_SELECTION, KEY_F);
p->add_item("Frame Selection", VIEW_FRAME_TO_SELECTION, KEY_MASK_CMD|KEY_F);
animation_hb = memnew( HBoxContainer );
hb->add_child(animation_hb);
animation_hb->add_child( memnew( VSeparator ));
animation_hb->hide();
key_loc_button = memnew( Button("loc"));
key_loc_button->set_toggle_mode(true);
key_loc_button->set_pressed(true);
key_loc_button->set_focus_mode(FOCUS_NONE);
key_loc_button->add_color_override("font_color",Color(1,0.6,0.6));
key_loc_button->add_color_override("font_color_pressed",Color(0.6,1,0.6));
key_loc_button->connect("pressed",this,"_popup_callback",varray(ANIM_INSERT_POS));
animation_hb->add_child(key_loc_button);
key_rot_button = memnew( Button("rot"));
key_rot_button->set_toggle_mode(true);
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
key_rot_button->add_color_override("font_color",Color(1,0.6,0.6));
key_rot_button->add_color_override("font_color_pressed",Color(0.6,1,0.6));
key_rot_button->connect("pressed",this,"_popup_callback",varray(ANIM_INSERT_ROT));
animation_hb->add_child(key_rot_button);
key_scale_button = memnew( Button("scl"));
key_scale_button->set_toggle_mode(true);
key_scale_button->set_focus_mode(FOCUS_NONE);
key_scale_button->add_color_override("font_color",Color(1,0.6,0.6));
key_scale_button->add_color_override("font_color_pressed",Color(0.6,1,0.6));
key_scale_button->connect("pressed",this,"_popup_callback",varray(ANIM_INSERT_SCALE));
animation_hb->add_child(key_scale_button);
key_insert_button = memnew( Button );
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed",this,"_popup_callback",varray(ANIM_INSERT_KEY));
key_insert_button->set_tooltip("Insert Keys (Insert)");
animation_hb->add_child(key_insert_button);
animation_menu = memnew( MenuButton );
animation_menu->set_text("Animation");
hb->add_child(animation_menu);
animation_hb->add_child(animation_menu);
animation_menu->get_popup()->connect("item_pressed", this,"_popup_callback");
p = animation_menu->get_popup();
@@ -2327,22 +2857,10 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_item("Insert Key",ANIM_INSERT_KEY,KEY_INSERT);
p->add_item("Insert Key (Existing Tracks)",ANIM_INSERT_KEY_EXISTING,KEY_MASK_CMD+KEY_INSERT);
p->add_separator();
p->add_check_item("Pos",ANIM_INSERT_POS);
p->add_check_item("Rot",ANIM_INSERT_ROT);
p->add_check_item("Scale",ANIM_INSERT_SCALE);
p->add_check_item("Pos+Rot",ANIM_INSERT_POS_ROT);
p->set_item_checked(p->get_item_index(ANIM_INSERT_POS_ROT),true);
p->add_check_item("Pos+Scale",ANIM_INSERT_POS_SCALE);
p->add_check_item("Rot+Scale",ANIM_INSERT_ROT_SCALE);
p->add_check_item("Loc+Rot+Scale",ANIM_INSERT_POS_ROT_SCALE);
p->add_separator();
p->add_item("Copy Pose",ANIM_COPY_POSE);
p->add_item("Paste Pose",ANIM_PASTE_POSE);
p->add_item("Clear Pose",ANIM_CLEAR_POSE,KEY_MASK_ALT|KEY_K);
animation_menu->hide();
value_dialog = memnew( AcceptDialog );
value_dialog->set_title("Set a Value");
value_dialog->get_ok()->set_text("Close");