summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp8
-rw-r--r--editor/editor_about.cpp1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp315
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h8
-rw-r--r--modules/gdscript/gd_parser.cpp83
-rw-r--r--modules/gdscript/gd_tokenizer.cpp318
-rw-r--r--modules/gdscript/gd_tokenizer.h3
-rw-r--r--platform/android/detect.py2
-rw-r--r--platform/x11/os_x11.cpp16
-rw-r--r--scene/gui/label.cpp23
-rwxr-xr-xscene/main/node.cpp5
-rw-r--r--scene/resources/font.cpp2
-rw-r--r--servers/physics_2d/space_2d_sw.cpp2
13 files changed, 410 insertions, 376 deletions
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 263b0cc641..76df57d410 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -6082,15 +6082,11 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, rt->buffers.effect, 0);
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- printf("err status: %x\n", status);
- _render_target_clear(rt);
- ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
- }
-
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("err status: %x\n", status);
_render_target_clear(rt);
ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
}
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 2328a42a07..fd90c766fd 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -137,7 +137,6 @@ EditorAbout::EditorAbout() {
tc->add_child(license_thirdparty);
Label *tpl_label = memnew(Label);
- tpl_label->set_custom_minimum_size(Size2(0, 64 * EDSCALE));
tpl_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
tpl_label->set_autowrap(true);
tpl_label->set_text(TTR("Godot Engine relies on a number of thirdparty free and open source libraries, all compatible with the terms of its MIT license. The following is an exhaustive list of all such thirdparty components with their respective copyright statements and license terms."));
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 4f07fdba2b..4c4cd88dfb 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -35,10 +35,10 @@
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/script_editor_debugger.h"
-#include "project_settings.h"
#include "os/input.h"
#include "os/keyboard.h"
#include "print_string.h"
+#include "project_settings.h"
#include "scene/2d/light_2d.h"
#include "scene/2d/particles_2d.h"
#include "scene/2d/polygon_2d.h"
@@ -241,7 +241,6 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
} else if (!Input::get_singleton()->is_mouse_button_pressed(0)) {
List<Node *> &selection = editor_selection->get_selected_node_list();
-
Vector2 mouse_pos = viewport->get_local_mouse_pos();
if (selection.size() && viewport->get_rect().has_point(mouse_pos)) {
//just in case, make it work if over viewport
@@ -258,7 +257,6 @@ void CanvasItemEditor::_tool_select(int p_index) {
ToolButton *tb[TOOL_MAX] = { select_button, list_select_button, move_button, rotate_button, pivot_button, pan_button };
for (int i = 0; i < TOOL_MAX; i++) {
-
tb[i]->set_pressed(i == p_index);
}
@@ -449,44 +447,7 @@ bool CanvasItemEditor::_is_part_of_subscene(CanvasItem *p_item) {
return item_owner && item_owner != scene_node && p_item != scene_node && item_owner->get_filename() != "";
}
-// slow but modern computers should have no problem
-CanvasItem *CanvasItemEditor::_select_canvas_item_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
-
- if (!p_node)
- return NULL;
- if (p_node->cast_to<Viewport>())
- return NULL;
-
- CanvasItem *c = p_node->cast_to<CanvasItem>();
-
- for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
-
- CanvasItem *r = NULL;
-
- if (c && !c->is_set_as_toplevel())
- r = _select_canvas_item_at_pos(p_pos, p_node->get_child(i), p_parent_xform * c->get_transform(), p_canvas_xform);
- else {
- CanvasLayer *cl = p_node->cast_to<CanvasLayer>();
- r = _select_canvas_item_at_pos(p_pos, p_node->get_child(i), transform, cl ? cl->get_transform() : p_canvas_xform); //use base transform
- }
-
- if (r)
- return r;
- }
-
- if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !_is_part_of_subscene(c) && !c->cast_to<CanvasLayer>()) {
-
- Rect2 rect = c->get_item_rect();
- Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos);
-
- if (rect.has_point(local_pos))
- return c;
- }
-
- return NULL;
-}
-
-void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items) {
+void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items, unsigned int limit) {
if (!p_node)
return;
if (p_node->cast_to<Viewport>())
@@ -502,6 +463,9 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
CanvasLayer *cl = p_node->cast_to<CanvasLayer>();
_find_canvas_items_at_pos(p_pos, p_node->get_child(i), transform, cl ? cl->get_transform() : p_canvas_xform, r_items); //use base transform
}
+
+ if (limit != 0 && r_items.size() >= limit)
+ return;
}
if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !c->cast_to<CanvasLayer>()) {
@@ -565,72 +529,50 @@ void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_n
}
}
-bool CanvasItemEditor::_select(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag) {
-
- if (p_append) {
- //additive selection
-
- if (!item) {
-
- if (p_drag) {
- drag_from = transform.affine_inverse().xform(p_click_pos);
-
- box_selecting = true;
- box_selecting_to = drag_from;
- }
+void CanvasItemEditor::_select_click_on_empty_area(Point2 p_click_pos, bool p_append, bool p_box_selection) {
+ if (!p_append) {
+ editor_selection->clear();
+ viewport->update();
+ };
- return false; //nothing to add
- }
+ if (p_box_selection) {
+ // Start a box selection
+ drag_from = transform.affine_inverse().xform(p_click_pos);
+ box_selecting = true;
+ box_selecting_to = drag_from;
+ }
+}
+bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag) {
+ bool still_selected = true;
+ if (p_append) {
if (editor_selection->is_selected(item)) {
- //already in here, erase it
+ // Already in the selection, remove it from the selected nodes
editor_selection->remove_node(item);
- //_remove_canvas_item(c);
-
- viewport->update();
- return false;
+ still_selected = false;
+ } else {
+ // Add the item to the selection
+ _append_canvas_item(item);
}
- _append_canvas_item(item);
- viewport->update();
-
- return true;
-
} else {
- //regular selection
-
- if (!item) {
- //clear because nothing clicked
- editor_selection->clear();
-
- if (p_drag) {
- drag_from = transform.affine_inverse().xform(p_click_pos);
-
- box_selecting = true;
- box_selecting_to = drag_from;
- }
-
- viewport->update();
- return false;
- }
-
if (!editor_selection->is_selected(item)) {
- //select a new one and clear previous selection
+ // Select a new one and clear previous selection
editor_selection->clear();
editor_selection->add_node(item);
- //reselect
+ // Reselect
if (get_tree()->is_editor_hint()) {
editor->call("edit_node", item);
}
}
+ }
- if (p_drag) {
- _prepare_drag(p_click_pos);
- }
-
- viewport->update();
-
- return true;
+ if (still_selected && p_drag) {
+ // Drag the node(s) if requested
+ _prepare_drag(p_click_pos);
}
+
+ viewport->update();
+ return still_selected;
}
void CanvasItemEditor::_key_move(const Vector2 &p_dir, bool p_snap, KeyMoveMODE p_move_mode) {
@@ -766,7 +708,7 @@ CanvasItem *CanvasItemEditor::get_single_item() {
return single_item;
}
-CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D &p_xform, const Rect2 &p_local_rect, const Point2 &p_click, Vector2 &r_point) {
+CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Point2 &p_click, Vector2 &r_point) {
CanvasItem *canvas_item = get_single_item();
@@ -805,8 +747,6 @@ CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D &
float radius = (select_handle->get_size().width / 2) * 1.5;
- //try draggers
-
for (int i = 0; i < 4; i++) {
int prev = (i + 3) % 4;
@@ -831,14 +771,6 @@ CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D &
return dragger[i * 2 + 1];
}
- /*
- if (rect.has_point(xform.affine_inverse().xform(p_click))) {
- r_point=_find_topleftmost_point();
- return DRAG_ALL;
- }*/
-
- //try draggers
-
return DRAG_NONE;
}
@@ -966,7 +898,7 @@ void CanvasItemEditor::_selection_result_pressed(int p_result) {
CanvasItem *item = selection_results[p_result].item;
if (item)
- _select(item, Point2(), additive_selection, false);
+ _select_click_on_item(item, Point2(), additive_selection, false);
}
void CanvasItemEditor::_selection_menu_hide() {
@@ -1006,7 +938,8 @@ void CanvasItemEditor::_list_select(const Ref<InputEventMouseButton> &b) {
selection_results.clear();
additive_selection = b->get_shift();
- if (!_select(item, click, additive_selection, false))
+
+ if (!_select_click_on_item(item, click, additive_selection, false))
return;
} else if (!selection_results.empty()) {
@@ -1048,7 +981,6 @@ void CanvasItemEditor::_list_select(const Ref<InputEventMouseButton> &b) {
void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
{
-
EditorNode *en = editor;
EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
@@ -1062,11 +994,11 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> b = p_event;
-
if (b.is_valid()) {
+ // Button event
if (b->get_button_index() == BUTTON_WHEEL_DOWN) {
-
+ // Scroll or pan down
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
v_scroll->set_value(v_scroll->get_value() + int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor());
@@ -1092,7 +1024,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
}
if (b->get_button_index() == BUTTON_WHEEL_UP) {
-
+ // Scroll or pan up
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
v_scroll->set_value(v_scroll->get_value() - int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor());
@@ -1116,7 +1048,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
}
if (b->get_button_index() == BUTTON_WHEEL_LEFT) {
-
+ // Pan left
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
h_scroll->set_value(h_scroll->get_value() - int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor());
@@ -1124,7 +1056,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
}
if (b->get_button_index() == BUTTON_WHEEL_RIGHT) {
-
+ // Pan right
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
h_scroll->set_value(h_scroll->get_value() + int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor());
@@ -1134,29 +1066,24 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
if (b->get_button_index() == BUTTON_RIGHT) {
if (b->is_pressed() && (tool == TOOL_SELECT && b->get_alt())) {
-
+ // Open the selection list
_list_select(b);
return;
}
if (get_item_count() > 0 && drag != DRAG_NONE) {
- //cancel drag
-
+ // Cancel a drag
if (bone_ik_list.size()) {
-
for (List<BoneIK>::Element *E = bone_ik_list.back(); E; E = E->prev()) {
-
E->get().node->edit_set_state(E->get().orig_state);
}
bone_ik_list.clear();
} else {
-
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 || !canvas_item->is_visible_in_tree())
continue;
@@ -1180,33 +1107,23 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
can_move_pivot = false;
} else if (box_selecting) {
+ // Cancel box selection
box_selecting = false;
viewport->update();
- } else if (b->is_pressed()) {
-#if 0
- ref_item = NULL;
- Node* scene = get_scene()->get_root_node()->cast_to<EditorNode>()->get_edited_scene();
- if ( scene ) ref_item =_select_canvas_item_at_pos( Point2( b.x, b.y ), scene, transform );
-#endif
- //popup->set_position(Point2(b.x,b.y));
- //popup->popup();
}
return;
}
- /*
- if (!canvas_items.size())
- return;
- */
if (b->get_button_index() == BUTTON_LEFT && tool == TOOL_LIST_SELECT) {
if (b->is_pressed())
+ // Open the selection list
_list_select(b);
return;
}
if (b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) {
if (b->is_pressed()) {
-
+ // Set the pivot point
Point2 mouse_pos = b->get_position();
mouse_pos = transform.affine_inverse().xform(mouse_pos);
mouse_pos = snap_point(mouse_pos);
@@ -1216,16 +1133,18 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
}
if (tool == TOOL_PAN || b->get_button_index() != BUTTON_LEFT || Input::get_singleton()->is_key_pressed(KEY_SPACE))
+ // Pan the view
return;
+ // -- From now we consider that the button is BUTTON_LEFT --
+
if (!b->is_pressed()) {
if (drag != DRAG_NONE) {
-
+ // Stop dragging
if (undo_redo) {
if (bone_ik_list.size()) {
-
undo_redo->create_action(TTR("Edit IK Chain"));
for (List<BoneIK>::Element *E = bone_ik_list.back(); E; E = E->prev()) {
@@ -1241,7 +1160,6 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->commit_action();
} else {
-
undo_redo->create_action(TTR("Edit CanvasItem"));
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -1285,11 +1203,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
}
if (box_selecting) {
-#if 0
- if ( ! b->get_shift() ) _clear_canvas_items();
- if ( box_selection_end() ) return;
-#endif
-
+ // Stop box selection
Node *scene = editor->get_edited_scene();
if (scene) {
@@ -1316,6 +1230,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
return;
}
+ // -- From now we consider that the button is BUTTON_LEFT and that it is pressed --
+
Map<ObjectID, BoneList>::Element *Cbone = NULL; //closest
{
@@ -1390,19 +1306,16 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
}
}
- CanvasItem *single_item = get_single_item();
-
- if (single_item) {
- //try single canvas_item edit
-
- CanvasItem *canvas_item = single_item;
+ // Single selected item
+ CanvasItem *canvas_item = get_single_item();
+ if (canvas_item) {
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
ERR_FAIL_COND(!se);
Point2 click = b->get_position();
+ // Rotation
if ((b->get_control() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
-
drag = DRAG_ROTATE;
drag_from = transform.affine_inverse().xform(click);
se->undo_state = canvas_item->edit_get_state();
@@ -1413,72 +1326,59 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
- Rect2 rect = canvas_item->get_item_rect();
- //float handle_radius = handle_len * 1.4144; //magic number, guess what it means!
-
if (tool == TOOL_SELECT) {
- drag = _find_drag_type(xform, rect, click, drag_point_from);
-
+ // Open a sub-scene on double-click
if (b->is_doubleclick()) {
-
if (canvas_item->get_filename() != "" && canvas_item != editor->get_edited_scene()) {
-
editor->open_request(canvas_item->get_filename());
return;
}
}
- if (drag != DRAG_NONE && (!Cbone || drag != DRAG_ALL)) {
+ // Drag
+ drag = _find_drag_type(click, drag_point_from);
+ if (drag != DRAG_NONE) {
drag_from = transform.affine_inverse().xform(click);
se->undo_state = canvas_item->edit_get_state();
if (canvas_item->cast_to<Node2D>())
se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot();
if (canvas_item->cast_to<Control>())
se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset();
-
return;
}
- } else {
-
- drag = DRAG_NONE;
}
}
- //multi canvas_item edit
-
+ // Multiple selected items
Point2 click = b->get_position();
if ((b->get_alt() || tool == TOOL_MOVE) && get_item_count()) {
+ // Drag the nodes
_prepare_drag(click);
viewport->update();
return;
}
- Node *scene = editor->get_edited_scene();
- if (!scene)
- return;
-
- /*
- if (current_window) {
- //no window.... ?
- click-=current_window->get_scroll();
- }*/
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();
}
+
+ Node *scene = editor->get_edited_scene();
+ if (!scene)
+ return;
+ // Find the item to select
if (!c) {
- c = _select_canvas_item_at_pos(click, scene, transform, Transform2D());
+ Vector<_SelectResult> selection;
+ _find_canvas_items_at_pos(click, scene, transform, Transform2D(), selection, 1);
+ if (!selection.empty())
+ c = selection[0].item;
CanvasItem *cn = c;
-
while (cn) {
if (cn->has_meta("_edit_group_")) {
c = cn;
@@ -1488,28 +1388,29 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
}
Node *n = c;
-
while ((n && n != scene && n->get_owner() != scene) || (n && !n->is_class("CanvasItem"))) {
n = n->get_parent();
};
c = n->cast_to<CanvasItem>();
-#if 0
- if ( b->is_pressed() ) box_selection_start( click );
-#endif
+ // Select the item
additive_selection = b->get_shift();
- if (!_select(c, click, additive_selection))
+ if (!c) {
+ _select_click_on_empty_area(click, additive_selection, true);
+ } else if (!_select_click_on_item(c, click, additive_selection, true)) {
return;
+ }
}
Ref<InputEventMouseMotion> m = p_event;
if (m.is_valid()) {
+ // Mouse motion event
if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
viewport->call_deferred("grab_focus");
if (box_selecting) {
-
+ // Update box selection
box_selecting_to = transform.affine_inverse().xform(m->get_position());
viewport->update();
return;
@@ -1618,8 +1519,21 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
Vector2 minsize = canvas_item->edit_get_minimum_size();
if (uniform) {
+ // Keep the height/width ratio of the item
float aspect = local_rect.size.aspect();
switch (drag) {
+ case DRAG_LEFT: {
+ drag_vector.y = -drag_vector.x / aspect;
+ } break;
+ case DRAG_RIGHT: {
+ drag_vector.y = drag_vector.x / aspect;
+ } break;
+ case DRAG_TOP: {
+ drag_vector.x = -drag_vector.y * aspect;
+ } break;
+ case DRAG_BOTTOM: {
+ drag_vector.x = drag_vector.y * aspect;
+ } break;
case DRAG_BOTTOM_LEFT:
case DRAG_TOP_RIGHT: {
if (aspect > 1.0) { // width > height, take x as reference
@@ -1636,7 +1550,17 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
drag_vector.x = drag_vector.y * aspect;
}
} break;
- default: {}
+ }
+ } else {
+ switch (drag) {
+ case DRAG_RIGHT:
+ case DRAG_LEFT: {
+ drag_vector.y = 0;
+ } break;
+ case DRAG_TOP:
+ case DRAG_BOTTOM: {
+ drag_vector.x = 0;
+ } break;
}
}
@@ -1645,44 +1569,25 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) {
begin += drag_vector;
end += drag_vector;
} break;
- case DRAG_RIGHT: {
-
- incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric);
-
- } break;
- case DRAG_BOTTOM: {
-
- incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric);
-
- } break;
+ case DRAG_RIGHT:
+ case DRAG_BOTTOM:
case DRAG_BOTTOM_RIGHT: {
-
incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric);
incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric);
} break;
- case DRAG_TOP_LEFT: {
+ case DRAG_TOP_LEFT: {
incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric);
incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric);
} break;
- case DRAG_TOP: {
- incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric);
-
- } break;
- case DRAG_LEFT: {
-
- incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric);
-
- } break;
+ case DRAG_TOP:
case DRAG_TOP_RIGHT: {
-
incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric);
incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric);
-
} break;
+ case DRAG_LEFT:
case DRAG_BOTTOM_LEFT: {
-
incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric);
incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric);
} break;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index f40a7cbc4a..4383be251c 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -303,11 +303,11 @@ class CanvasItemEditor : public VBoxContainer {
int handle_len;
bool _is_part_of_subscene(CanvasItem *p_item);
- CanvasItem *_select_canvas_item_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform);
- void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items);
+ void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items, unsigned int limit = 0);
void _find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, List<CanvasItem *> *r_items);
- bool _select(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag = true);
+ void _select_click_on_empty_area(Point2 p_click_pos, bool p_append, bool p_box_selection);
+ bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag);
ConfirmationDialog *snap_dialog;
@@ -325,7 +325,7 @@ class CanvasItemEditor : public VBoxContainer {
void _key_move(const Vector2 &p_dir, bool p_snap, KeyMoveMODE p_move_mode);
void _list_select(const Ref<InputEventMouseButton> &b);
- DragType _find_drag_type(const Transform2D &p_xform, const Rect2 &p_local_rect, const Point2 &p_click, Vector2 &r_point);
+ DragType _find_drag_type(const Point2 &p_click, Vector2 &r_point);
void _prepare_drag(const Point2 &p_click_pos);
void _popup_callback(int p_op);
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 75029a020b..6e873c9197 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -185,8 +185,8 @@ void GDParser::_make_completable_call(int p_arg) {
bool GDParser::_get_completable_identifier(CompletionType p_type, StringName &identifier) {
identifier = StringName();
- if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) {
- identifier = tokenizer->get_token_identifier();
+ if (tokenizer->is_token_literal()) {
+ identifier = tokenizer->get_token_literal();
tokenizer->advance();
}
if (tokenizer->get_token() == GDTokenizer::TK_CURSOR) {
@@ -201,8 +201,8 @@ bool GDParser::_get_completable_identifier(CompletionType p_type, StringName &id
completion_ident_is_call = false;
tokenizer->advance();
- if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) {
- identifier = identifier.operator String() + tokenizer->get_token_identifier().operator String();
+ if (tokenizer->is_token_literal()) {
+ identifier = identifier.operator String() + tokenizer->get_token_literal().operator String();
tokenizer->advance();
}
@@ -296,17 +296,6 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool
need_identifier = false;
} break;
- case GDTokenizer::TK_IDENTIFIER: {
- if (!need_identifier) {
- done = true;
- break;
- }
-
- path += String(tokenizer->get_token_identifier());
- tokenizer->advance();
- need_identifier = false;
-
- } break;
case GDTokenizer::TK_OP_DIV: {
if (need_identifier) {
@@ -320,6 +309,13 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool
} break;
default: {
+ // Instead of checking for TK_IDENTIFIER, we check with is_token_literal, as this allows us to use match/sync/etc. as a name
+ if (need_identifier && tokenizer->is_token_literal()) {
+ path += String(tokenizer->get_token_literal());
+ tokenizer->advance();
+ need_identifier = false;
+ }
+
done = true;
break;
}
@@ -585,7 +581,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool
cn->value = Variant::get_numeric_constant_value(bi_type, identifier);
expr = cn;
- } else if (tokenizer->get_token(1) == GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token() == GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER || tokenizer->get_token() == GDTokenizer::TK_BUILT_IN_FUNC)) {
+ } else if (tokenizer->get_token(1) == GDTokenizer::TK_PARENTHESIS_OPEN && tokenizer->is_token_literal()) {
+ // We check with is_token_literal, as this allows us to use match/sync/etc. as a name
//function or constructor
OperatorNode *op = alloc_node<OperatorNode>();
@@ -627,7 +624,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool
expr = op;
- } else if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) {
+ } else if (tokenizer->is_token_literal(0, true)) {
+ // We check with is_token_literal, as this allows us to use match/sync/etc. as a name
//identifier (reference)
const ClassNode *cln = current_class;
@@ -827,10 +825,11 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool
if (expecting == DICT_EXPECT_KEY) {
- if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1) == GDTokenizer::TK_OP_ASSIGN) {
+ if (tokenizer->is_token_literal() && tokenizer->get_token(1) == GDTokenizer::TK_OP_ASSIGN) {
+ // We check with is_token_literal, as this allows us to use match/sync/etc. as a name
//lua style identifier, easier to write
ConstantNode *cn = alloc_node<ConstantNode>();
- cn->value = tokenizer->get_token_identifier();
+ cn->value = tokenizer->get_token_literal();
key = cn;
tokenizer->advance(2);
expecting = DICT_EXPECT_VALUE;
@@ -870,7 +869,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool
expr = dict;
- } else if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && (tokenizer->get_token(1) == GDTokenizer::TK_IDENTIFIER || tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) {
+ } else if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && (tokenizer->is_token_literal(1) || tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) {
+ // We check with is_token_literal, as this allows us to use match/sync/etc. as a name
// parent call
tokenizer->advance(); //goto identifier
@@ -922,7 +922,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool
//indexing using "."
- if (tokenizer->get_token(1) != GDTokenizer::TK_CURSOR && tokenizer->get_token(1) != GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1) != GDTokenizer::TK_BUILT_IN_FUNC) {
+ if (tokenizer->get_token(1) != GDTokenizer::TK_CURSOR && !tokenizer->is_token_literal(1)) {
+ // We check with is_token_literal, as this allows us to use match/sync/etc. as a name
_set_error("Expected identifier as member");
return NULL;
} else if (tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) {
@@ -2341,12 +2342,12 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) {
//variale declaration and (eventual) initialization
tokenizer->advance();
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ if (!tokenizer->is_token_literal(0, true)) {
_set_error("Expected identifier for local variable name.");
return;
}
- StringName n = tokenizer->get_token_identifier();
+ StringName n = tokenizer->get_token_literal();
tokenizer->advance();
if (current_function) {
for (int i = 0; i < current_function->arguments.size(); i++) {
@@ -2571,7 +2572,7 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) {
tokenizer->advance();
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ if (!tokenizer->is_token_literal(0, true)) {
_set_error("identifier expected after 'for'");
}
@@ -3108,7 +3109,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
tokenizer->advance(); //var before the identifier is allowed
}
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ if (!tokenizer->is_token_literal(0, true)) {
_set_error("Expected identifier for argument.");
return;
@@ -3260,7 +3261,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
case GDTokenizer::TK_PR_SIGNAL: {
tokenizer->advance();
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ if (!tokenizer->is_token_literal()) {
_set_error("Expected identifier after 'signal'.");
return;
}
@@ -3282,7 +3283,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
break;
}
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ if (tokenizer->is_token_literal(0, true)) {
_set_error("Expected identifier in signal argument.");
return;
}
@@ -3847,13 +3848,13 @@ void GDParser::_parse_class(ClassNode *p_class) {
bool onready = tokenizer->get_token(-1) == GDTokenizer::TK_PR_ONREADY;
tokenizer->advance();
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ if (!tokenizer->is_token_literal(0, true)) {
_set_error("Expected identifier for member variable name.");
return;
}
- member.identifier = tokenizer->get_token_identifier();
+ member.identifier = tokenizer->get_token_literal();
member.expression = NULL;
member._export.name = member.identifier;
member.line = tokenizer->get_token_line();
@@ -3979,11 +3980,11 @@ void GDParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token() != GDTokenizer::TK_COMMA) {
//just comma means using only getter
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
- _set_error("Expected identifier for setter function after 'notify'.");
+ if (!tokenizer->is_token_literal()) {
+ _set_error("Expected identifier for setter function after 'setget'.");
}
- member.setter = tokenizer->get_token_identifier();
+ member.setter = tokenizer->get_token_literal();
tokenizer->advance();
}
@@ -3992,11 +3993,11 @@ void GDParser::_parse_class(ClassNode *p_class) {
//there is a getter
tokenizer->advance();
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ if (!tokenizer->is_token_literal()) {
_set_error("Expected identifier for getter function after ','.");
}
- member.getter = tokenizer->get_token_identifier();
+ member.getter = tokenizer->get_token_literal();
tokenizer->advance();
}
}
@@ -4014,13 +4015,13 @@ void GDParser::_parse_class(ClassNode *p_class) {
ClassNode::Constant constant;
tokenizer->advance();
- if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ if (!tokenizer->is_token_literal(0, true)) {
_set_error("Expected name (identifier) for constant.");
return;
}
- constant.identifier = tokenizer->get_token_identifier();
+ constant.identifier = tokenizer->get_token_literal();
tokenizer->advance();
if (tokenizer->get_token() != GDTokenizer::TK_OP_ASSIGN) {
@@ -4061,8 +4062,8 @@ void GDParser::_parse_class(ClassNode *p_class) {
Dictionary enum_dict;
tokenizer->advance();
- if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) {
- enum_name = tokenizer->get_token_identifier();
+ if (tokenizer->is_token_literal(0, true)) {
+ enum_name = tokenizer->get_token_literal();
tokenizer->advance();
}
if (tokenizer->get_token() != GDTokenizer::TK_CURLY_BRACKET_OPEN) {
@@ -4079,7 +4080,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
tokenizer->advance();
break; // End of enum
- } else if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) {
+ } else if (!tokenizer->is_token_literal(0, true)) {
if (tokenizer->get_token() == GDTokenizer::TK_EOF) {
_set_error("Unexpected end of file.");
@@ -4088,10 +4089,10 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
return;
- } else { // tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER
+ } else { // tokenizer->is_token_literal(0, true)
ClassNode::Constant constant;
- constant.identifier = tokenizer->get_token_identifier();
+ constant.identifier = tokenizer->get_token_literal();
tokenizer->advance();
diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp
index f4e0cc8e29..95774cb6d6 100644
--- a/modules/gdscript/gd_tokenizer.cpp
+++ b/modules/gdscript/gd_tokenizer.cpp
@@ -130,12 +130,222 @@ const char *GDTokenizer::token_names[TK_MAX] = {
"Cursor"
};
+struct _bit {
+ Variant::Type type;
+ const char *text;
+};
+//built in types
+
+static const _bit _type_list[] = {
+ //types
+ { Variant::BOOL, "bool" },
+ { Variant::INT, "int" },
+ { Variant::REAL, "float" },
+ { Variant::STRING, "String" },
+ { Variant::VECTOR2, "Vector2" },
+ { Variant::RECT2, "Rect2" },
+ { Variant::TRANSFORM2D, "Transform2D" },
+ { Variant::VECTOR3, "Vector3" },
+ { Variant::RECT3, "Rect3" },
+ { Variant::PLANE, "Plane" },
+ { Variant::QUAT, "Quat" },
+ { Variant::BASIS, "Basis" },
+ { Variant::TRANSFORM, "Transform" },
+ { Variant::COLOR, "Color" },
+ { Variant::_RID, "RID" },
+ { Variant::OBJECT, "Object" },
+ { Variant::NODE_PATH, "NodePath" },
+ { Variant::DICTIONARY, "Dictionary" },
+ { Variant::ARRAY, "Array" },
+ { Variant::POOL_BYTE_ARRAY, "PoolByteArray" },
+ { Variant::POOL_INT_ARRAY, "PoolIntArray" },
+ { Variant::POOL_REAL_ARRAY, "PoolFloatArray" },
+ { Variant::POOL_STRING_ARRAY, "PoolStringArray" },
+ { Variant::POOL_VECTOR2_ARRAY, "PoolVector2Array" },
+ { Variant::POOL_VECTOR3_ARRAY, "PoolVector3Array" },
+ { Variant::POOL_COLOR_ARRAY, "PoolColorArray" },
+ { Variant::VARIANT_MAX, NULL },
+};
+
+struct _kws {
+ GDTokenizer::Token token;
+ const char *text;
+};
+
+static const _kws _keyword_list[] = {
+ //ops
+ { GDTokenizer::TK_OP_IN, "in" },
+ { GDTokenizer::TK_OP_NOT, "not" },
+ { GDTokenizer::TK_OP_OR, "or" },
+ { GDTokenizer::TK_OP_AND, "and" },
+ //func
+ { GDTokenizer::TK_PR_FUNCTION, "func" },
+ { GDTokenizer::TK_PR_CLASS, "class" },
+ { GDTokenizer::TK_PR_EXTENDS, "extends" },
+ { GDTokenizer::TK_PR_IS, "is" },
+ { GDTokenizer::TK_PR_ONREADY, "onready" },
+ { GDTokenizer::TK_PR_TOOL, "tool" },
+ { GDTokenizer::TK_PR_STATIC, "static" },
+ { GDTokenizer::TK_PR_EXPORT, "export" },
+ { GDTokenizer::TK_PR_SETGET, "setget" },
+ { GDTokenizer::TK_PR_VAR, "var" },
+ { GDTokenizer::TK_PR_PRELOAD, "preload" },
+ { GDTokenizer::TK_PR_ASSERT, "assert" },
+ { GDTokenizer::TK_PR_YIELD, "yield" },
+ { GDTokenizer::TK_PR_SIGNAL, "signal" },
+ { GDTokenizer::TK_PR_BREAKPOINT, "breakpoint" },
+ { GDTokenizer::TK_PR_REMOTE, "remote" },
+ { GDTokenizer::TK_PR_MASTER, "master" },
+ { GDTokenizer::TK_PR_SLAVE, "slave" },
+ { GDTokenizer::TK_PR_SYNC, "sync" },
+ { GDTokenizer::TK_PR_CONST, "const" },
+ { GDTokenizer::TK_PR_ENUM, "enum" },
+ //controlflow
+ { GDTokenizer::TK_CF_IF, "if" },
+ { GDTokenizer::TK_CF_ELIF, "elif" },
+ { GDTokenizer::TK_CF_ELSE, "else" },
+ { GDTokenizer::TK_CF_FOR, "for" },
+ { GDTokenizer::TK_CF_WHILE, "while" },
+ { GDTokenizer::TK_CF_DO, "do" },
+ { GDTokenizer::TK_CF_SWITCH, "switch" },
+ { GDTokenizer::TK_CF_CASE, "case" },
+ { GDTokenizer::TK_CF_BREAK, "break" },
+ { GDTokenizer::TK_CF_CONTINUE, "continue" },
+ { GDTokenizer::TK_CF_RETURN, "return" },
+ { GDTokenizer::TK_CF_MATCH, "match" },
+ { GDTokenizer::TK_CF_PASS, "pass" },
+ { GDTokenizer::TK_SELF, "self" },
+ { GDTokenizer::TK_CONST_PI, "PI" },
+ { GDTokenizer::TK_WILDCARD, "_" },
+ { GDTokenizer::TK_CONST_INF, "INF" },
+ { GDTokenizer::TK_CONST_NAN, "NAN" },
+ { GDTokenizer::TK_ERROR, NULL }
+};
+
const char *GDTokenizer::get_token_name(Token p_token) {
ERR_FAIL_INDEX_V(p_token, TK_MAX, "<error>");
return token_names[p_token];
}
+bool GDTokenizer::is_token_literal(int p_offset, bool variable_safe) const {
+ switch (get_token(p_offset)) {
+ // Can always be literal:
+ case TK_IDENTIFIER:
+
+ case TK_PR_ONREADY:
+ case TK_PR_TOOL:
+ case TK_PR_STATIC:
+ case TK_PR_EXPORT:
+ case TK_PR_SETGET:
+ case TK_PR_SIGNAL:
+ case TK_PR_REMOTE:
+ case TK_PR_MASTER:
+ case TK_PR_SLAVE:
+ case TK_PR_SYNC:
+ return true;
+
+ // Literal for non-variables only:
+ case TK_BUILT_IN_TYPE:
+ case TK_BUILT_IN_FUNC:
+
+ case TK_OP_IN:
+ case TK_OP_NOT:
+ //case TK_OP_OR:
+ //case TK_OP_AND:
+
+ case TK_PR_CLASS:
+ case TK_PR_CONST:
+ case TK_PR_ENUM:
+ case TK_PR_PRELOAD:
+ case TK_PR_FUNCTION:
+ case TK_PR_EXTENDS:
+ case TK_PR_ASSERT:
+ case TK_PR_YIELD:
+ case TK_PR_VAR:
+
+ case TK_CF_IF:
+ case TK_CF_ELIF:
+ case TK_CF_ELSE:
+ case TK_CF_FOR:
+ case TK_CF_WHILE:
+ case TK_CF_DO:
+ case TK_CF_SWITCH:
+ case TK_CF_CASE:
+ case TK_CF_BREAK:
+ case TK_CF_CONTINUE:
+ case TK_CF_RETURN:
+ case TK_CF_MATCH:
+ case TK_CF_PASS:
+ case TK_SELF:
+ case TK_CONST_PI:
+ case TK_WILDCARD:
+ case TK_CONST_INF:
+ case TK_CONST_NAN:
+ case TK_ERROR:
+ return !variable_safe;
+
+ case TK_CONSTANT: {
+ switch (get_token_constant(p_offset).get_type()) {
+ case Variant::NIL:
+ case Variant::BOOL:
+ return true;
+ default:
+ return false;
+ }
+ }
+ default:
+ return false;
+ }
+}
+
+StringName GDTokenizer::get_token_literal(int p_offset) const {
+ Token token = get_token(p_offset);
+ switch (token) {
+ case TK_IDENTIFIER:
+ return get_token_identifier(p_offset);
+ case TK_BUILT_IN_TYPE: {
+ Variant::Type type = get_token_type(p_offset);
+ int idx = 0;
+
+ while (_type_list[idx].text) {
+ if (type == _type_list[idx].type) {
+ return _type_list[idx].text;
+ }
+ idx++;
+ }
+ } break; // Shouldn't get here, stuff happens
+ case TK_BUILT_IN_FUNC:
+ return GDFunctions::get_func_name(get_token_built_in_func(p_offset));
+ case TK_CONSTANT: {
+ const Variant value = get_token_constant(p_offset);
+
+ switch (value.get_type()) {
+ case Variant::NIL:
+ return "null";
+ case Variant::BOOL:
+ return value ? "true" : "false";
+ default: {}
+ }
+ }
+ case TK_OP_AND:
+ case TK_OP_OR:
+ break; // Don't get into default, since they can be non-literal
+ default: {
+ int idx = 0;
+
+ while (_keyword_list[idx].text) {
+ if (token == _keyword_list[idx].token) {
+ return _keyword_list[idx].text;
+ }
+ idx++;
+ }
+ }
+ }
+ ERR_EXPLAIN("Failed to get token literal");
+ ERR_FAIL_V("");
+}
+
static bool _is_text_char(CharType c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
@@ -779,51 +989,14 @@ void GDTokenizerText::_advance() {
bool found = false;
- struct _bit {
- Variant::Type type;
- const char *text;
- };
- //built in types
-
- static const _bit type_list[] = {
- //types
- { Variant::BOOL, "bool" },
- { Variant::INT, "int" },
- { Variant::REAL, "float" },
- { Variant::STRING, "String" },
- { Variant::VECTOR2, "Vector2" },
- { Variant::RECT2, "Rect2" },
- { Variant::TRANSFORM2D, "Transform2D" },
- { Variant::VECTOR3, "Vector3" },
- { Variant::RECT3, "Rect3" },
- { Variant::PLANE, "Plane" },
- { Variant::QUAT, "Quat" },
- { Variant::BASIS, "Basis" },
- { Variant::TRANSFORM, "Transform" },
- { Variant::COLOR, "Color" },
- { Variant::_RID, "RID" },
- { Variant::OBJECT, "Object" },
- { Variant::NODE_PATH, "NodePath" },
- { Variant::DICTIONARY, "Dictionary" },
- { Variant::ARRAY, "Array" },
- { Variant::POOL_BYTE_ARRAY, "PoolByteArray" },
- { Variant::POOL_INT_ARRAY, "PoolIntArray" },
- { Variant::POOL_REAL_ARRAY, "PoolFloatArray" },
- { Variant::POOL_STRING_ARRAY, "PoolStringArray" },
- { Variant::POOL_VECTOR2_ARRAY, "PoolVector2Array" },
- { Variant::POOL_VECTOR3_ARRAY, "PoolVector3Array" },
- { Variant::POOL_COLOR_ARRAY, "PoolColorArray" },
- { Variant::VARIANT_MAX, NULL },
- };
-
{
int idx = 0;
- while (type_list[idx].text) {
+ while (_type_list[idx].text) {
- if (str == type_list[idx].text) {
- _make_type(type_list[idx].type);
+ if (str == _type_list[idx].text) {
+ _make_type(_type_list[idx].type);
found = true;
break;
}
@@ -844,74 +1017,18 @@ void GDTokenizerText::_advance() {
break;
}
}
-
- //keywor
}
if (!found) {
-
- struct _kws {
- Token token;
- const char *text;
- };
-
- static const _kws keyword_list[] = {
- //ops
- { TK_OP_IN, "in" },
- { TK_OP_NOT, "not" },
- { TK_OP_OR, "or" },
- { TK_OP_AND, "and" },
- //func
- { TK_PR_FUNCTION, "func" },
- { TK_PR_CLASS, "class" },
- { TK_PR_EXTENDS, "extends" },
- { TK_PR_IS, "is" },
- { TK_PR_ONREADY, "onready" },
- { TK_PR_TOOL, "tool" },
- { TK_PR_STATIC, "static" },
- { TK_PR_EXPORT, "export" },
- { TK_PR_SETGET, "setget" },
- { TK_PR_VAR, "var" },
- { TK_PR_PRELOAD, "preload" },
- { TK_PR_ASSERT, "assert" },
- { TK_PR_YIELD, "yield" },
- { TK_PR_SIGNAL, "signal" },
- { TK_PR_BREAKPOINT, "breakpoint" },
- { TK_PR_REMOTE, "remote" },
- { TK_PR_MASTER, "master" },
- { TK_PR_SLAVE, "slave" },
- { TK_PR_SYNC, "sync" },
- { TK_PR_CONST, "const" },
- { TK_PR_ENUM, "enum" },
- //controlflow
- { TK_CF_IF, "if" },
- { TK_CF_ELIF, "elif" },
- { TK_CF_ELSE, "else" },
- { TK_CF_FOR, "for" },
- { TK_CF_WHILE, "while" },
- { TK_CF_DO, "do" },
- { TK_CF_SWITCH, "switch" },
- { TK_CF_CASE, "case" },
- { TK_CF_BREAK, "break" },
- { TK_CF_CONTINUE, "continue" },
- { TK_CF_RETURN, "return" },
- { TK_CF_MATCH, "match" },
- { TK_CF_PASS, "pass" },
- { TK_SELF, "self" },
- { TK_CONST_PI, "PI" },
- { TK_WILDCARD, "_" },
- { TK_CONST_INF, "INF" },
- { TK_CONST_NAN, "NAN" },
- { TK_ERROR, NULL }
- };
+ //keyword
int idx = 0;
found = false;
- while (keyword_list[idx].text) {
+ while (_keyword_list[idx].text) {
- if (str == keyword_list[idx].text) {
- _make_token(keyword_list[idx].token);
+ if (str == _keyword_list[idx].text) {
+ _make_token(_keyword_list[idx].token);
found = true;
break;
}
@@ -992,6 +1109,7 @@ const Variant &GDTokenizerText::get_token_constant(int p_offset) const {
ERR_FAIL_COND_V(tk_rb[ofs].type != TK_CONSTANT, tk_rb[0].constant);
return tk_rb[ofs].constant;
}
+
StringName GDTokenizerText::get_token_identifier(int p_offset) const {
ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, StringName());
diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h
index c051176097..4e868301a3 100644
--- a/modules/gdscript/gd_tokenizer.h
+++ b/modules/gdscript/gd_tokenizer.h
@@ -149,6 +149,9 @@ protected:
public:
static const char *get_token_name(Token p_token);
+ bool is_token_literal(int p_offset = 0, bool variable_safe = false) const;
+ StringName get_token_literal(int p_offset = 0) const;
+
virtual const Variant &get_token_constant(int p_offset = 0) const = 0;
virtual Token get_token(int p_offset = 0) const = 0;
virtual StringName get_token_identifier(int p_offset = 0) const = 0;
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 55b7052393..fae1df3f27 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -178,7 +178,7 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"])
env.Append(CPPFLAGS=string.split('-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'))
- env.Append(CPPFLAGS=string.split('-DANDROID -DNO_STATVFS -DGLES2_ENABLED'))
+ env.Append(CPPFLAGS=string.split('-DNO_STATVFS -DGLES2_ENABLED'))
env['neon_enabled'] = False
if env['android_arch'] == 'x86':
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 3143f30f77..5bfe31b8c2 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -1858,7 +1858,7 @@ void OS_X11::set_clipboard(const String &p_text) {
XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, CurrentTime);
};
-static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) {
+static String _get_clipboard_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) {
String ret;
@@ -1875,7 +1875,7 @@ static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_di
};
if (Sown != None) {
- XConvertSelection(x11_display, p_source, XA_STRING, selection,
+ XConvertSelection(x11_display, p_source, target, selection,
x11_window, CurrentTime);
XFlush(x11_display);
while (true) {
@@ -1915,6 +1915,18 @@ static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_di
return ret;
}
+static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) {
+ String ret;
+ Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
+ if (utf8_atom != None) {
+ ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom);
+ }
+ if (ret == "") {
+ ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING);
+ }
+ return ret;
+}
+
String OS_X11::get_clipboard() const {
String ret;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 159d81eb09..874156821e 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -28,15 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "label.h"
-#include "project_settings.h"
#include "print_string.h"
+#include "project_settings.h"
#include "translation.h"
void Label::set_autowrap(bool p_autowrap) {
autowrap = p_autowrap;
word_cache_dirty = true;
- minimum_size_changed();
update();
}
bool Label::has_autowrap() const {
@@ -48,7 +47,6 @@ void Label::set_uppercase(bool p_uppercase) {
uppercase = p_uppercase;
word_cache_dirty = true;
- minimum_size_changed();
update();
}
bool Label::is_uppercase() const {
@@ -71,7 +69,6 @@ void Label::_notification(int p_what) {
xl_text = new_text;
regenerate_word_cache();
- minimum_size_changed();
update();
}
@@ -292,7 +289,7 @@ void Label::_notification(int p_what) {
Size2 Label::get_minimum_size() const {
if (autowrap)
- return Size2(1, 1);
+ return Size2(1, clip ? 1 : minsize.height);
else {
// don't want to mutable everything
@@ -487,15 +484,16 @@ void Label::regenerate_word_cache() {
}
}
- if (!autowrap) {
+ if (!autowrap)
minsize.width = width;
- if (max_lines_visible > 0 && line_count > max_lines_visible) {
- minsize.height = (font->get_height() * max_lines_visible) + (line_spacing * (max_lines_visible - 1));
- } else {
- minsize.height = (font->get_height() * line_count) + (line_spacing * (line_count - 1));
- }
+
+ if (max_lines_visible > 0 && line_count > max_lines_visible) {
+ minsize.height = (font->get_height() * max_lines_visible) + (line_spacing * (max_lines_visible - 1));
+ } else {
+ minsize.height = (font->get_height() * line_count) + (line_spacing * (line_count - 1));
}
+ minimum_size_changed();
word_cache_dirty = false;
}
@@ -533,9 +531,6 @@ void Label::set_text(const String &p_string) {
if (percent_visible < 1)
visible_chars = get_total_character_count() * percent_visible;
update();
- if (!autowrap) {
- minimum_size_changed();
- }
}
void Label::set_clip_text(bool p_clip) {
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 26d1deadf9..c3849f79df 100755
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -311,6 +311,11 @@ void Node::move_child(Node *p_child, int p_pos) {
ERR_FAIL_COND(data.blocked > 0);
}
+ // Specifying one place beyond the end
+ // means the same as moving to the last position
+ if (p_pos == data.children.size())
+ p_pos--;
+
if (p_child->data.pos == p_pos)
return; //do nothing
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 3668dda604..a6a70d775f 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -506,7 +506,7 @@ float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_c
cpos.y += c->v_align;
ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0);
if (c->texture_idx != -1)
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate);
+ VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, RID(), false);
return get_char_size(p_char, p_next).width;
}
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index c407a17bc6..a17d1f6a12 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -553,7 +553,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
const CollisionObject2DSW *col_obj = intersection_query_results[i];
int shape_idx = intersection_query_subindex_results[i];
- if (col_obj->is_shape_set_as_one_way_collision(j)) {
+ if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
cbk.valid_dir = body_shape_xform.get_axis(1).normalized();
cbk.valid_depth = p_margin; //only valid depth is the collision margin