summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/base_button.cpp21
-rw-r--r--scene/gui/base_button.h4
-rw-r--r--scene/gui/check_button.cpp13
-rw-r--r--scene/gui/color_picker.cpp70
-rw-r--r--scene/gui/color_picker.h11
-rw-r--r--scene/gui/control.cpp8
-rw-r--r--scene/gui/item_list.cpp1
-rw-r--r--scene/gui/line_edit.cpp32
-rw-r--r--scene/gui/menu_button.cpp4
-rw-r--r--scene/gui/option_button.cpp6
-rw-r--r--scene/gui/popup.cpp2
-rw-r--r--scene/gui/popup_menu.cpp71
-rw-r--r--scene/gui/tab_container.cpp13
-rw-r--r--scene/gui/tabs.cpp6
-rw-r--r--scene/gui/text_edit.cpp121
-rw-r--r--scene/gui/texture_button.cpp2
-rw-r--r--scene/gui/texture_rect.cpp2
17 files changed, 285 insertions, 102 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index d68cdd5f8d..e95781c181 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -282,10 +282,7 @@ void BaseButton::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
}
- if (p_what == NOTIFICATION_EXIT_TREE) {
- }
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED && !is_visible_in_tree()) {
+ if (p_what == NOTIFICATION_EXIT_TREE || (p_what == NOTIFICATION_VISIBILITY_CHANGED && !is_visible_in_tree())) {
if (!toggle_mode) {
status.pressed = false;
@@ -379,7 +376,7 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
bool pressing;
if (status.press_attempt) {
- pressing = status.pressing_inside;
+ pressing = (status.pressing_inside || keep_pressed_outside);
if (status.pressed)
pressing = !pressing;
} else {
@@ -449,6 +446,16 @@ Control::FocusMode BaseButton::get_enabled_focus_mode() const {
return enabled_focus_mode;
}
+void BaseButton::set_keep_pressed_outside(bool p_on) {
+
+ keep_pressed_outside = p_on;
+}
+
+bool BaseButton::is_keep_pressed_outside() const {
+
+ return keep_pressed_outside;
+}
+
void BaseButton::set_shortcut(const Ref<ShortCut> &p_shortcut) {
if (shortcut.is_null() == p_shortcut.is_null())
@@ -531,6 +538,8 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_draw_mode"), &BaseButton::get_draw_mode);
ClassDB::bind_method(D_METHOD("set_enabled_focus_mode", "mode"), &BaseButton::set_enabled_focus_mode);
ClassDB::bind_method(D_METHOD("get_enabled_focus_mode"), &BaseButton::get_enabled_focus_mode);
+ ClassDB::bind_method(D_METHOD("set_keep_pressed_outside", "enabled"), &BaseButton::set_keep_pressed_outside);
+ ClassDB::bind_method(D_METHOD("is_keep_pressed_outside"), &BaseButton::is_keep_pressed_outside);
ClassDB::bind_method(D_METHOD("set_shortcut", "shortcut"), &BaseButton::set_shortcut);
ClassDB::bind_method(D_METHOD("get_shortcut"), &BaseButton::get_shortcut);
@@ -552,6 +561,7 @@ void BaseButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "action_mode", PROPERTY_HINT_ENUM, "Button Press,Button Release"), "set_action_mode", "get_action_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask");
ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_enabled_focus_mode", "get_enabled_focus_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "ShortCut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group");
@@ -569,6 +579,7 @@ BaseButton::BaseButton() {
toggle_mode = false;
shortcut_in_tooltip = true;
+ keep_pressed_outside = false;
status.pressed = false;
status.press_attempt = false;
status.hovering = false;
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index 9a00cc79f2..22a8f6d8fe 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -52,6 +52,7 @@ private:
int button_mask;
bool toggle_mode;
bool shortcut_in_tooltip;
+ bool keep_pressed_outside;
FocusMode enabled_focus_mode;
Ref<ShortCut> shortcut;
@@ -110,6 +111,9 @@ public:
void set_action_mode(ActionMode p_mode);
ActionMode get_action_mode() const;
+ void set_keep_pressed_outside(bool p_on);
+ bool is_keep_pressed_outside() const;
+
void set_button_mask(int p_mask);
int get_button_mask() const;
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index 35e3119473..a2d0f388c4 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -34,13 +34,15 @@
#include "servers/visual_server.h"
Size2 CheckButton::get_icon_size() const {
- Ref<Texture> on = Control::get_icon("on");
- Ref<Texture> off = Control::get_icon("off");
+
+ Ref<Texture> on = Control::get_icon(is_disabled() ? "on_disabled" : "on");
+ Ref<Texture> off = Control::get_icon(is_disabled() ? "off_disabled" : "off");
Size2 tex_size = Size2(0, 0);
if (!on.is_null())
tex_size = Size2(on->get_width(), on->get_height());
if (!off.is_null())
tex_size = Size2(MAX(tex_size.width, off->get_width()), MAX(tex_size.height, off->get_height()));
+
return tex_size;
}
@@ -49,9 +51,8 @@ Size2 CheckButton::get_minimum_size() const {
Size2 minsize = Button::get_minimum_size();
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
- if (get_text().length() > 0) {
+ if (get_text().length() > 0)
minsize.width += get_constant("hseparation");
- }
Ref<StyleBox> sb = get_stylebox("normal");
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM));
@@ -67,8 +68,8 @@ void CheckButton::_notification(int p_what) {
RID ci = get_canvas_item();
- Ref<Texture> on = Control::get_icon("on");
- Ref<Texture> off = Control::get_icon("off");
+ Ref<Texture> on = Control::get_icon(is_disabled() ? "on_disabled" : "on");
+ Ref<Texture> off = Control::get_icon(is_disabled() ? "off_disabled" : "off");
Ref<StyleBox> sb = get_stylebox("normal");
Vector2 ofs;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index accf8aa7c2..bca3471091 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -38,8 +38,6 @@
#include "editor_scale.h"
#include "editor_settings.h"
#endif
-
-#include "scene/gui/separator.h"
#include "scene/main/viewport.h"
void ColorPicker::_notification(int p_what) {
@@ -469,7 +467,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
set_pick_color(presets[index]);
_update_color();
emit_signal("color_changed", color);
- } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT) {
+ } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) {
int index = bev->get_position().x / (preset->get_size().x / presets.size());
Color clicked_preset = presets[index];
erase_preset(clicked_preset);
@@ -565,6 +563,31 @@ void ColorPicker::_html_focus_exit() {
_focus_exit();
}
+void ColorPicker::set_presets_enabled(bool p_enabled) {
+ presets_enabled = p_enabled;
+ if (!p_enabled) {
+ bt_add_preset->set_disabled(true);
+ bt_add_preset->set_focus_mode(FOCUS_NONE);
+ } else {
+ bt_add_preset->set_disabled(false);
+ bt_add_preset->set_focus_mode(FOCUS_ALL);
+ }
+}
+
+bool ColorPicker::are_presets_enabled() const {
+ return presets_enabled;
+}
+
+void ColorPicker::set_presets_visible(bool p_visible) {
+ presets_visible = p_visible;
+ preset_separator->set_visible(p_visible);
+ preset_container->set_visible(p_visible);
+}
+
+bool ColorPicker::are_presets_visible() const {
+ return presets_visible;
+}
+
void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color);
@@ -575,6 +598,10 @@ void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_deferred_mode"), &ColorPicker::is_deferred_mode);
ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha);
ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha);
+ ClassDB::bind_method(D_METHOD("set_presets_enabled", "enabled"), &ColorPicker::set_presets_enabled);
+ ClassDB::bind_method(D_METHOD("are_presets_enabled"), &ColorPicker::are_presets_enabled);
+ ClassDB::bind_method(D_METHOD("set_presets_visible", "visible"), &ColorPicker::set_presets_visible);
+ ClassDB::bind_method(D_METHOD("are_presets_visible"), &ColorPicker::are_presets_visible);
ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset);
ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset);
ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets);
@@ -598,6 +625,8 @@ void ColorPicker::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible"), "set_presets_visible", "are_presets_visible");
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("preset_added", PropertyInfo(Variant::COLOR, "color")));
@@ -613,6 +642,8 @@ ColorPicker::ColorPicker() :
raw_mode_enabled = false;
deferred_mode_enabled = false;
changing_color = false;
+ presets_enabled = true;
+ presets_visible = true;
screen = NULL;
HBoxContainer *hb_smpl = memnew(HBoxContainer);
@@ -725,18 +756,19 @@ ColorPicker::ColorPicker() :
set_pick_color(Color(1, 1, 1));
- add_child(memnew(HSeparator));
+ preset_separator = memnew(HSeparator);
+ add_child(preset_separator);
- HBoxContainer *bbc = memnew(HBoxContainer);
- add_child(bbc);
+ preset_container = memnew(HBoxContainer);
+ add_child(preset_container);
preset = memnew(TextureRect);
- bbc->add_child(preset);
+ preset_container->add_child(preset);
preset->connect("gui_input", this, "_preset_input");
preset->connect("draw", this, "_update_presets");
bt_add_preset = memnew(Button);
- bbc->add_child(bt_add_preset);
+ preset_container->add_child(bt_add_preset);
bt_add_preset->set_tooltip(TTR("Add current color as a preset."));
bt_add_preset->connect("pressed", this, "_add_preset_pressed");
}
@@ -758,23 +790,27 @@ void ColorPickerButton::_modal_closed() {
void ColorPickerButton::pressed() {
_update_picker();
- popup->set_position(get_global_position() - picker->get_combined_minimum_size());
+ popup->set_position(get_global_position() - picker->get_combined_minimum_size() * get_global_transform().get_scale());
+ popup->set_scale(get_global_transform().get_scale());
popup->popup();
picker->set_focus_on_line_edit();
}
void ColorPickerButton::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
+ switch (p_what) {
+ case NOTIFICATION_DRAW: {
- Ref<StyleBox> normal = get_stylebox("normal");
- Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
- draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
- draw_rect(r, color);
- }
+ Ref<StyleBox> normal = get_stylebox("normal");
+ Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
+ draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
+ draw_rect(r, color);
+ } break;
+ case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
- if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST && popup) {
- popup->hide();
+ if (popup)
+ popup->hide();
+ } break;
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index b78844839a..b5ddf2d0c2 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -37,6 +37,7 @@
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/popup.h"
+#include "scene/gui/separator.h"
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
#include "scene/gui/texture_rect.h"
@@ -52,6 +53,8 @@ private:
Control *w_edit;
TextureRect *sample;
TextureRect *preset;
+ HBoxContainer *preset_container;
+ HSeparator *preset_separator;
Button *bt_add_preset;
List<Color> presets;
ToolButton *btn_pick;
@@ -70,6 +73,8 @@ private:
bool deferred_mode_enabled;
bool updating;
bool changing_color;
+ bool presets_enabled;
+ bool presets_visible;
float h, s, v;
Color last_hsv;
@@ -114,6 +119,12 @@ public:
void set_deferred_mode(bool p_enabled);
bool is_deferred_mode() const;
+ void set_presets_enabled(bool p_enabled);
+ bool are_presets_enabled() const;
+
+ void set_presets_visible(bool p_visible);
+ bool are_presets_visible() const;
+
void set_focus_on_line_edit();
ColorPicker();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index c7cd2bb6d8..a38f97a90c 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2634,6 +2634,12 @@ bool Control::is_visibility_clip_disabled() const {
void Control::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+#ifdef TOOLS_ENABLED
+ const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
+#else
+ const String quote_style = "\"";
+#endif
+
Node::get_argument_options(p_function, p_idx, r_options);
if (p_idx == 0) {
@@ -2651,7 +2657,7 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
sn.sort_custom<StringName::AlphCompare>();
for (List<StringName>::Element *E = sn.front(); E; E = E->next()) {
- r_options->push_back("\"" + E->get() + "\"");
+ r_options->push_back(quote_style + E->get() + quote_style);
}
}
}
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 026374ded1..f5e979e9e6 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -369,6 +369,7 @@ void ItemList::clear() {
update();
shape_changed = true;
defer_select_single = -1;
+ scroll_bar->set_value(0);
}
void ItemList::set_fixed_column_width(int p_size) {
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 1e8d73b6a4..d889c8d8b8 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -56,6 +56,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
menu->set_position(get_global_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
+ menu->set_scale(get_global_transform().get_scale());
menu->popup();
grab_focus();
return;
@@ -1327,7 +1328,27 @@ void LineEdit::select_all() {
void LineEdit::set_editable(bool p_editable) {
+ if (editable == p_editable)
+ return;
+
editable = p_editable;
+
+ // Reorganize context menu.
+ menu->clear();
+ if (editable)
+ menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
+ menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
+ if (editable)
+ menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
+ menu->add_separator();
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
+ if (editable) {
+ menu->add_item(RTR("Clear"), MENU_CLEAR);
+ menu->add_separator();
+ menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
+ menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
+ }
+
update();
}
@@ -1623,7 +1644,6 @@ LineEdit::LineEdit() {
deselect();
set_focus_mode(FOCUS_ALL);
- editable = true;
set_default_cursor_shape(CURSOR_IBEAM);
set_mouse_filter(MOUSE_FILTER_STOP);
@@ -1638,15 +1658,7 @@ LineEdit::LineEdit() {
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
- menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
- menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
- menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
- menu->add_separator();
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
- menu->add_item(RTR("Clear"), MENU_CLEAR);
- menu->add_separator();
- menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
- menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
+ set_editable(true);
menu->connect("id_pressed", this, "menu_option");
expand_to_text_length = false;
}
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 5f21d73ab2..e12cd55e6f 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -55,8 +55,9 @@ void MenuButton::pressed() {
Size2 size = get_size();
Point2 gp = get_global_position();
- popup->set_global_position(gp + Size2(0, size.height));
+ popup->set_global_position(gp + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
+ popup->set_scale(get_global_transform().get_scale());
popup->set_parent_rect(Rect2(Point2(gp - popup->get_global_position()), get_size()));
popup->popup();
}
@@ -135,7 +136,6 @@ MenuButton::MenuButton() {
popup = memnew(PopupMenu);
popup->hide();
add_child(popup);
- popup->set_as_toplevel(true);
popup->set_pass_on_modal_close_click(false);
popup->connect("about_to_show", this, "set_pressed", varray(true)); // For when switching from another MenuButton.
popup->connect("popup_hide", this, "set_pressed", varray(false));
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 8c75393d01..7238543a14 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -109,9 +109,9 @@ void OptionButton::_selected(int p_which) {
void OptionButton::pressed() {
Size2 size = get_size();
- popup->set_global_position(get_global_position() + Size2(0, size.height));
+ popup->set_global_position(get_global_position() + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
-
+ popup->set_scale(get_global_transform().get_scale());
popup->popup();
}
@@ -352,8 +352,8 @@ OptionButton::OptionButton() {
popup = memnew(PopupMenu);
popup->hide();
add_child(popup);
- popup->set_as_toplevel(true);
popup->set_pass_on_modal_close_click(false);
+ popup->set_notify_transform(true);
popup->connect("id_pressed", this, "_selected");
popup->connect("id_focused", this, "_focused");
popup->connect("popup_hide", this, "set_pressed", varray(false));
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 80ec7049fc..b7601bdd3e 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -65,7 +65,7 @@ void Popup::_notification(int p_what) {
void Popup::_fix_size() {
Point2 pos = get_global_position();
- Size2 size = get_size();
+ Size2 size = get_size() * get_scale();
Point2 window_size = get_viewport_rect().size;
if (pos.x + size.width > window_size.width)
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 23c61f37d6..5df18cece6 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -54,9 +54,11 @@ Size2 PopupMenu::get_minimum_size() const {
Ref<Font> font = get_font("font");
float max_w = 0;
+ float icon_w = 0;
int font_h = font->get_height();
- int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width());
+ int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation;
int accel_max_w = 0;
+ bool has_check = false;
for (int i = 0; i < items.size(); i++) {
@@ -65,8 +67,7 @@ Size2 PopupMenu::get_minimum_size() const {
Size2 icon_size = items[i].icon->get_size();
size.height = MAX(icon_size.height, font_h);
- size.width += icon_size.width;
- size.width += hseparation;
+ icon_w = MAX(icon_size.width + hseparation, icon_w);
} else {
size.height = font_h;
@@ -74,10 +75,8 @@ Size2 PopupMenu::get_minimum_size() const {
size.width += items[i].h_ofs;
- if (items[i].checkable_type) {
-
- size.width += check_w + hseparation;
- }
+ if (items[i].checkable_type)
+ has_check = true;
String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text;
size.width += font->get_string_size(text).width;
@@ -91,16 +90,17 @@ Size2 PopupMenu::get_minimum_size() const {
accel_max_w = MAX(accel_w, accel_max_w);
}
- if (items[i].submenu != "") {
-
+ if (items[i].submenu != "")
size.width += get_icon("submenu")->get_width();
- }
- minsize.height += size.height;
max_w = MAX(max_w, size.width);
+
+ minsize.height += size.height;
}
- minsize.width += max_w + accel_max_w;
+ minsize.width += max_w + icon_w + accel_max_w;
+ if (has_check)
+ minsize.width += check_w;
return minsize;
}
@@ -147,10 +147,10 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
void PopupMenu::_activate_submenu(int over) {
Node *n = get_node(items[over].submenu);
- ERR_EXPLAIN("item subnode does not exist: " + items[over].submenu);
+ ERR_EXPLAIN("Item subnode does not exist: " + items[over].submenu);
ERR_FAIL_COND(!n);
Popup *pm = Object::cast_to<Popup>(n);
- ERR_EXPLAIN("item subnode is not a Popup: " + items[over].submenu);
+ ERR_EXPLAIN("Item subnode is not a Popup: " + items[over].submenu);
ERR_FAIL_COND(!pm);
if (pm->is_visible_in_tree())
return; //already visible!
@@ -159,13 +159,14 @@ void PopupMenu::_activate_submenu(int over) {
Rect2 pr(p, get_size());
Ref<StyleBox> style = get_stylebox("panel");
- Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y);
+ Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y) * get_global_transform().get_scale();
Size2 size = pm->get_size();
// fix pos
if (pos.x + size.width > get_viewport_rect().size.width)
pos.x = p.x - size.width;
pm->set_position(pos);
+ pm->set_scale(get_global_transform().get_scale());
pm->popup();
PopupMenu *pum = Object::cast_to<PopupMenu>(pm);
@@ -196,11 +197,11 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
int vseparation = get_constant("vseparation");
Ref<Font> font = get_font("font");
- float dy = (vseparation + font->get_height()) * 3 * p_factor;
+ float dy = (vseparation + font->get_height()) * 3 * p_factor * get_global_transform().get_scale().y;
if (dy > 0 && global_y < 0)
dy = MIN(dy, -global_y - 1);
- else if (dy < 0 && global_y + get_size().y > get_viewport_rect().size.y)
- dy = -MIN(-dy, global_y + get_size().y - get_viewport_rect().size.y - 1);
+ else if (dy < 0 && global_y + get_size().y * get_global_transform().get_scale().y > get_viewport_rect().size.y)
+ dy = -MIN(-dy, global_y + get_size().y * get_global_transform().get_scale().y - get_viewport_rect().size.y - 1);
set_position(get_position() + Vector2(0, dy));
Ref<InputEventMouseMotion> ie;
@@ -289,7 +290,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
case BUTTON_WHEEL_DOWN: {
- if (get_global_position().y + get_size().y > get_viewport_rect().size.y) {
+ if (get_global_position().y + get_size().y * get_global_transform().get_scale().y > get_viewport_rect().size.y) {
_scroll(-b->get_factor(), b->get_position());
}
} break;
@@ -415,7 +416,6 @@ void PopupMenu::_notification(int p_what) {
minimum_size_changed();
update();
-
} break;
case NOTIFICATION_DRAW: {
@@ -443,15 +443,31 @@ void PopupMenu::_notification(int p_what) {
Color font_color_hover = get_color("font_color_hover");
float font_h = font->get_height();
+ // Add the check and the wider icon to the offset of all items.
+ float icon_ofs = 0.0;
+ bool has_check = false;
+ for (int i = 0; i < items.size(); i++) {
+
+ if (!items[i].icon.is_null())
+ icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs);
+
+ if (items[i].checkable_type)
+ has_check = true;
+ }
+ if (icon_ofs > 0.0)
+ icon_ofs += hseparation;
+
+ float check_ofs = 0.0;
+ if (has_check)
+ check_ofs = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation;
+
for (int i = 0; i < items.size(); i++) {
if (i > 0)
ofs.y += vseparation;
Point2 item_ofs = ofs;
- float h;
Size2 icon_size;
-
- Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+ float h;
if (!items[i].icon.is_null()) {
@@ -489,16 +505,15 @@ void PopupMenu::_notification(int p_what) {
}
}
+ Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+
if (items[i].checkable_type) {
Texture *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color);
- item_ofs.x += icon->get_width() + hseparation;
}
if (!items[i].icon.is_null()) {
- items[i].icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
- item_ofs.x += items[i].icon->get_width();
- item_ofs.x += hseparation;
+ items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
}
if (items[i].submenu != "") {
@@ -514,6 +529,7 @@ void PopupMenu::_notification(int p_what) {
}
} else {
+ item_ofs.x += icon_ofs + check_ofs;
font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color));
}
@@ -528,7 +544,6 @@ void PopupMenu::_notification(int p_what) {
ofs.y += h;
}
-
} break;
case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index ad41cc4167..39c76e6646 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -86,8 +86,8 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
emit_signal("pre_popup_pressed");
Vector2 popup_pos = get_global_position();
- popup_pos.x += size.width - popup->get_size().width;
- popup_pos.y += menu->get_height();
+ popup_pos.x += size.width * get_global_transform().get_scale().x - popup->get_size().width * popup->get_global_transform().get_scale().x;
+ popup_pos.y += menu->get_height() * get_global_transform().get_scale().y;
popup->set_global_position(popup_pos);
popup->popup();
@@ -146,6 +146,11 @@ void TabContainer::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_TRANSLATION_CHANGED: {
+
+ minimum_size_changed();
+ update();
+ } break;
case NOTIFICATION_RESIZED: {
Vector<Control *> tabs = _get_tabs();
@@ -181,7 +186,6 @@ void TabContainer::_notification(int p_what) {
first_tab_cache--;
}
} break;
-
case NOTIFICATION_DRAW: {
RID canvas = get_canvas_item();
@@ -350,6 +354,7 @@ void TabContainer::_notification(int p_what) {
}
} break;
case NOTIFICATION_THEME_CHANGED: {
+
minimum_size_changed();
call_deferred("_on_theme_changed"); //wait until all changed theme
} break;
@@ -731,6 +736,7 @@ void TabContainer::set_tab_title(int p_tab, const String &p_title) {
Control *child = _get_tab(p_tab);
ERR_FAIL_COND(!child);
child->set_meta("_tab_name", p_title);
+ update();
}
String TabContainer::get_tab_title(int p_tab) const {
@@ -748,6 +754,7 @@ void TabContainer::set_tab_icon(int p_tab, const Ref<Texture> &p_icon) {
Control *child = _get_tab(p_tab);
ERR_FAIL_COND(!child);
child->set_meta("_tab_icon", p_icon);
+ update();
}
Ref<Texture> TabContainer::get_tab_icon(int p_tab) const {
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index ac643c1320..36571cc878 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -222,6 +222,10 @@ void Tabs::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_TRANSLATION_CHANGED: {
+ minimum_size_changed();
+ update();
+ } break;
case NOTIFICATION_MOUSE_EXIT: {
rb_hover = -1;
cb_hover = -1;
@@ -232,7 +236,6 @@ void Tabs::_notification(int p_what) {
_update_cache();
_ensure_no_over_offset();
ensure_tab_visible(current);
-
} break;
case NOTIFICATION_DRAW: {
_update_cache();
@@ -394,7 +397,6 @@ void Tabs::_notification(int p_what) {
} else {
buttons_visible = false;
}
-
} break;
}
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index c77705f35f..10bd9e2a8b 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -825,6 +825,9 @@ void TextEdit::_notification(int p_what) {
// get the highlighted words
String highlighted_text = get_selection_text();
+ // check if highlighted words contains only whitespaces (tabs or spaces)
+ bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String();
+
String line_num_padding = line_numbers_zero_padded ? "0" : " ";
int cursor_wrap_index = get_cursor_wrap_index();
@@ -1123,7 +1126,7 @@ void TextEdit::_notification(int p_what) {
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color);
}
- if (highlight_all_occurrences) {
+ if (highlight_all_occurrences && !only_whitespaces_highlighted) {
if (highlighted_text_col != -1) {
// if we are at the end check for new word on same line
@@ -1557,8 +1560,7 @@ void TextEdit::_consume_pair_symbol(CharType ch) {
}
if ((ch == '\'' || ch == '"') &&
- cursor_get_column() > 0 &&
- _is_text_char(text[cursor.line][cursor_get_column() - 1])) {
+ cursor_get_column() > 0 && _is_text_char(text[cursor.line][cursor_get_column() - 1]) && !_is_pair_right_symbol(text[cursor.line][cursor_get_column()])) {
insert_text_at_cursor(ch_single);
cursor_set_column(cursor_position_to_move);
return;
@@ -2027,6 +2029,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
menu->set_position(get_global_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
+ menu->set_scale(get_global_transform().get_scale());
menu->popup();
grab_focus();
}
@@ -2272,6 +2275,36 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
k->set_command(true);
k->set_shift(false);
}
+#ifdef APPLE_STYLE_KEYS
+ if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) {
+ uint32_t remap_key = KEY_UNKNOWN;
+ switch (k->get_scancode()) {
+ case KEY_F: {
+ remap_key = KEY_RIGHT;
+ } break;
+ case KEY_B: {
+ remap_key = KEY_LEFT;
+ } break;
+ case KEY_P: {
+ remap_key = KEY_UP;
+ } break;
+ case KEY_N: {
+ remap_key = KEY_DOWN;
+ } break;
+ case KEY_D: {
+ remap_key = KEY_DELETE;
+ } break;
+ case KEY_H: {
+ remap_key = KEY_BACKSPACE;
+ } break;
+ }
+
+ if (remap_key != KEY_UNKNOWN) {
+ k->set_scancode(remap_key);
+ k->set_control(false);
+ }
+ }
+#endif
_reset_caret_blink_timer();
@@ -2606,9 +2639,22 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
#ifdef APPLE_STYLE_KEYS
if (k->get_command()) {
- cursor_set_column(0);
+ // Start at first column (it's slightly faster that way) and look for the first non-whitespace character.
+ int new_cursor_pos = 0;
+ for (int i = 0; i < text[cursor.line].length(); ++i) {
+ if (!_is_whitespace(text[cursor.line][i])) {
+ new_cursor_pos = i;
+ break;
+ }
+ }
+ if (new_cursor_pos == cursor.column) {
+ // We're already at the first text character, so move to the very beginning of the line.
+ cursor_set_column(0);
+ } else {
+ // We're somewhere to the right of the first text character; move to the first one.
+ cursor_set_column(new_cursor_pos);
+ }
} else if (k->get_alt()) {
-
#else
if (k->get_alt()) {
scancode_handled = false;
@@ -4362,7 +4408,27 @@ void TextEdit::clear() {
void TextEdit::set_readonly(bool p_readonly) {
+ if (readonly == p_readonly)
+ return;
+
readonly = p_readonly;
+
+ // Reorganize context menu.
+ menu->clear();
+ if (!readonly)
+ menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
+ menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
+ if (!readonly)
+ menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
+ menu->add_separator();
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
+ if (!readonly) {
+ menu->add_item(RTR("Clear"), MENU_CLEAR);
+ menu->add_separator();
+ menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
+ menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
+ }
+
update();
}
@@ -5762,19 +5828,29 @@ void TextEdit::_confirm_completion() {
cursor_set_column(cursor.column - completion_base.length(), false);
insert_text_at_cursor(completion_current);
- // When inserted into the middle of an existing string, don't add an unnecessary quote
+ // When inserted into the middle of an existing string/method, don't add an unnecessary quote/bracket.
String line = text[cursor.line];
CharType next_char = line[cursor.column];
CharType last_completion_char = completion_current[completion_current.length() - 1];
- if ((last_completion_char == '"' || last_completion_char == '\'') &&
- last_completion_char == next_char) {
+ if ((last_completion_char == '"' || last_completion_char == '\'') && last_completion_char == next_char) {
_base_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
}
- if (last_completion_char == '(' && auto_brace_completion_enabled) {
- insert_text_at_cursor(")");
- cursor.column--;
+ if (last_completion_char == '(') {
+
+ if (next_char == last_completion_char) {
+ _base_remove_text(cursor.line, cursor.column - 1, cursor.line, cursor.column);
+ } else if (auto_brace_completion_enabled) {
+ insert_text_at_cursor(")");
+ cursor.column--;
+ }
+ } else if (last_completion_char == ')' && next_char == '(') {
+
+ _base_remove_text(cursor.line, cursor.column - 2, cursor.line, cursor.column);
+ if (line[cursor.column + 1] != ')') {
+ cursor.column--;
+ }
}
end_complex_operation();
@@ -5818,6 +5894,7 @@ void TextEdit::_update_completion_candidates() {
bool inquote = false;
int first_quote = -1;
+ int restore_quotes = -1;
int c = cofs - 1;
while (c >= 0) {
@@ -5825,6 +5902,11 @@ void TextEdit::_update_completion_candidates() {
inquote = !inquote;
if (first_quote == -1)
first_quote = c;
+ restore_quotes = 0;
+ } else if (restore_quotes == 0 && l[c] == '$') {
+ restore_quotes = 1;
+ } else if (restore_quotes == 0 && !_is_whitespace(l[c])) {
+ restore_quotes = -1;
}
c--;
}
@@ -5892,6 +5974,11 @@ void TextEdit::_update_completion_candidates() {
completion_strings.write[i] = completion_strings[i].unquote().quote("'");
}
+ if (inquote && restore_quotes == 1 && !completion_strings[i].is_quoted()) {
+ String quote = single_quote ? "'" : "\"";
+ completion_strings.write[i] = completion_strings[i].quote(quote);
+ }
+
if (completion_strings[i].begins_with(s)) {
completion_options.push_back(completion_strings[i]);
} else if (completion_strings[i].to_lower().begins_with(s.to_lower())) {
@@ -5969,7 +6056,6 @@ void TextEdit::code_complete(const Vector<String> &p_strings, bool p_forced) {
completion_current = "";
completion_index = 0;
_update_completion_candidates();
- //
}
String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
@@ -6386,7 +6472,6 @@ void TextEdit::_bind_methods() {
TextEdit::TextEdit() {
- readonly = false;
setting_row = false;
draw_tabs = false;
override_selected_font_color = false;
@@ -6501,15 +6586,7 @@ TextEdit::TextEdit() {
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
- menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
- menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
- menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
- menu->add_separator();
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
- menu->add_item(RTR("Clear"), MENU_CLEAR);
- menu->add_separator();
- menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
- menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
+ set_readonly(false);
menu->connect("id_pressed", this, "menu_option");
first_draw = true;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index 795b25cce0..b5f949aeb7 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -64,7 +64,7 @@ bool TextureButton::has_point(const Point2 &p_point) const {
Rect2 rect = Rect2();
Size2 mask_size = click_mask->get_size();
- if (_position_rect.no_area()) {
+ if (_position_rect.has_no_area()) {
rect.size = mask_size;
} else if (_tile) {
// if the stretch mode is tile we offset the point to keep it inside the mask size
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index 2195de9694..423794d8ba 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -96,7 +96,7 @@ void TextureRect::_notification(int p_what) {
size.width *= hflip ? -1.0f : 1.0f;
size.height *= vflip ? -1.0f : 1.0f;
- if (region.no_area()) {
+ if (region.has_no_area()) {
draw_texture_rect(texture, Rect2(offset, size), tile);
} else {
draw_texture_rect_region(texture, Rect2(offset, size), region);