summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/ustring.cpp21
-rw-r--r--core/ustring.h1
-rw-r--r--scene/gui/control.cpp1
-rw-r--r--scene/gui/control.h1
-rw-r--r--scene/gui/menu_button.h3
-rw-r--r--scene/main/viewport.cpp29
6 files changed, 46 insertions, 10 deletions
diff --git a/core/ustring.cpp b/core/ustring.cpp
index bb08dd13c4..f552cb13ac 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -161,14 +161,21 @@ void String::copy_from(const CharType *p_cstr, int p_clip_to) {
return;
}
- resize(len + 1);
- set(len, 0);
+ copy_from_unchecked(p_cstr, len);
+}
- CharType *dst = &operator[](0);
+// assumes the following have already been validated:
+// p_char != NULL
+// p_length > 0
+// p_length <= p_char strlen
+void String::copy_from_unchecked(const CharType *p_char, int p_length) {
+ resize(p_length + 1);
+ set(p_length, 0);
- for (int i = 0; i < len; i++) {
+ CharType *dst = &operator[](0);
- dst[i] = p_cstr[i];
+ for (int i = 0; i < p_length; i++) {
+ dst[i] = p_char[i];
}
}
@@ -2246,7 +2253,9 @@ String String::substr(int p_from, int p_chars) const {
return String(*this);
}
- return String(&c_str()[p_from], p_chars);
+ String s = String();
+ s.copy_from_unchecked(&c_str()[p_from], p_chars);
+ return s;
}
int String::find_last(const String &p_str) const {
diff --git a/core/ustring.h b/core/ustring.h
index b57e9629d9..001d111d64 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -65,6 +65,7 @@ class String : public Vector<CharType> {
void copy_from(const char *p_cstr);
void copy_from(const CharType *p_cstr, int p_clip_to = -1);
void copy_from(const CharType &p_char);
+ void copy_from_unchecked(const CharType *p_char, int p_length);
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
public:
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 17c349858f..12aeed1520 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2972,7 +2972,6 @@ Control::Control() {
data.SI = NULL;
data.MI = NULL;
data.RI = NULL;
- data.modal = false;
data.theme_owner = NULL;
data.modal_exclusive = false;
data.default_cursor = CURSOR_ARROW;
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 94231867d7..6bea04345b 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -182,7 +182,6 @@ private:
Control *parent;
ObjectID drag_owner;
- bool modal;
bool modal_exclusive;
uint64_t modal_frame; //frame used to put something as modal
Ref<Theme> theme;
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index 2356444ecb..0636accfee 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -43,7 +43,6 @@ class MenuButton : public Button {
bool clicked;
bool disable_shortcuts;
PopupMenu *popup;
- virtual void pressed();
void _unhandled_key_input(Ref<InputEvent> p_event);
Array _get_items() const;
@@ -55,6 +54,8 @@ protected:
static void _bind_methods();
public:
+ virtual void pressed();
+
PopupMenu *get_popup() const;
void set_disable_shortcuts(bool p_disabled);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 9013d276c7..573c401290 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -41,7 +41,10 @@
#include "scene/3d/spatial.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/panel.h"
#include "scene/gui/panel_container.h"
+#include "scene/gui/popup_menu.h"
#include "scene/main/timer.h"
#include "scene/resources/mesh.h"
#include "scene/scene_string_names.h"
@@ -1853,8 +1856,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) {
Control *top = gui.modal_stack.back()->get();
+
if (over != top && !top->is_a_parent_of(over)) {
- over = NULL; //nothing can be found outside the modal stack
+
+ PopupMenu *popup_menu = Object::cast_to<PopupMenu>(top);
+ MenuButton *popup_menu_parent;
+ MenuButton *menu_button = Object::cast_to<MenuButton>(over);
+
+ if (popup_menu)
+ popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
+
+ // If the mouse is over a menu button, this menu will open automatically
+ // if there is already a pop-up menu open at the same hierarchical level.
+ if (popup_menu_parent && menu_button &&
+ popup_menu_parent->get_icon().is_null() &&
+ menu_button->get_icon().is_null() &&
+ (popup_menu->get_parent()->get_parent()->is_a_parent_of(menu_button) ||
+ menu_button->get_parent()->is_a_parent_of(popup_menu))) {
+
+ popup_menu->notification(Control::NOTIFICATION_MODAL_CLOSE);
+ popup_menu->_modal_stack_remove();
+ popup_menu->hide();
+
+ menu_button->pressed();
+ } else {
+ over = NULL; //nothing can be found outside the modal stack
+ }
}
}