summaryrefslogtreecommitdiff
path: root/scene/gui/popup_menu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/popup_menu.cpp')
-rw-r--r--scene/gui/popup_menu.cpp570
1 files changed, 292 insertions, 278 deletions
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index e75dadd5e0..1e933c9aa1 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -30,11 +30,12 @@
#include "popup_menu.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/print_string.h"
#include "core/translation.h"
+#include "scene/gui/control.h"
String PopupMenu::_get_accel_text(int p_item) const {
@@ -47,18 +48,18 @@ String PopupMenu::_get_accel_text(int p_item) const {
return String();
}
-Size2 PopupMenu::get_minimum_size() const {
+Size2 PopupMenu::_get_contents_minimum_size() const {
- int vseparation = get_constant("vseparation");
- int hseparation = get_constant("hseparation");
+ int vseparation = get_theme_constant("vseparation");
+ int hseparation = get_theme_constant("hseparation");
- Size2 minsize = get_stylebox("panel")->get_minimum_size();
- Ref<Font> font = get_font("font");
+ Size2 minsize = get_theme_stylebox("panel")->get_minimum_size();
+ Ref<Font> font = get_theme_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()) + hseparation;
+ int check_w = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation;
int accel_max_w = 0;
bool has_check = false;
@@ -93,7 +94,7 @@ Size2 PopupMenu::get_minimum_size() const {
}
if (items[i].submenu != "")
- size.width += get_icon("submenu")->get_width();
+ size.width += get_theme_icon("submenu")->get_width();
max_w = MAX(max_w, size.width);
@@ -112,15 +113,15 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
if (p_over.x < 0 || p_over.x >= get_size().width)
return -1;
- Ref<StyleBox> style = get_stylebox("panel");
+ Ref<StyleBox> style = get_theme_stylebox("panel");
Point2 ofs = style->get_offset();
if (ofs.y > p_over.y)
return -1;
- Ref<Font> font = get_font("font");
- int vseparation = get_constant("vseparation");
+ Ref<Font> font = get_theme_font("font");
+ int vseparation = get_theme_constant("vseparation");
float font_h = font->get_height();
for (int i = 0; i < items.size(); i++) {
@@ -152,27 +153,27 @@ void PopupMenu::_activate_submenu(int over) {
ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + items[over].submenu + ".");
Popup *pm = Object::cast_to<Popup>(n);
ERR_FAIL_COND_MSG(!pm, "Item subnode is not a Popup: " + items[over].submenu + ".");
- if (pm->is_visible_in_tree())
+ if (pm->is_visible())
return; //already visible!
- Point2 p = get_global_position();
+ Point2 p = get_position();
Rect2 pr(p, get_size());
- Ref<StyleBox> style = get_stylebox("panel");
+ Ref<StyleBox> style = get_theme_stylebox("panel");
- Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y) * get_global_transform().get_scale();
+ Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y);
Size2 size = pm->get_size();
// fix pos
- if (pos.x + size.width > get_viewport_rect().size.width)
+ if (pos.x + size.width > get_parent_rect().size.width)
pos.x = p.x - size.width;
pm->set_position(pos);
- pm->set_scale(get_global_transform().get_scale());
+ // pm->set_scale(get_global_transform().get_scale());
pm->popup();
PopupMenu *pum = Object::cast_to<PopupMenu>(pm);
if (pum) {
- pr.position -= pum->get_global_position();
+ pr.position -= pum->get_position();
pum->clear_autohide_areas();
pum->add_autohide_area(Rect2(pr.position.x, pr.position.y, pr.size.x, items[over]._ofs_cache));
if (over < items.size() - 1) {
@@ -184,6 +185,9 @@ void PopupMenu::_activate_submenu(int over) {
void PopupMenu::_submenu_timeout() {
+ //if (!has_focus()) {
+ // return; //do not activate if not has focus
+ //}
if (mouse_over == submenu_over)
_activate_submenu(mouse_over);
@@ -192,20 +196,27 @@ void PopupMenu::_submenu_timeout() {
void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
- int vseparation = get_constant("vseparation");
- Ref<Font> font = get_font("font");
+ int vseparation = get_theme_constant("vseparation");
+ Ref<Font> font = get_theme_font("font");
- float dy = (vseparation + font->get_height()) * 3 * p_factor * get_global_transform().get_scale().y;
+ Rect2 visible_rect = get_usable_parent_rect();
+
+ int dy = (vseparation + font->get_height()) * 3 * p_factor;
if (dy > 0) {
- const float global_top = get_global_position().y;
- const float limit = global_top < 0 ? -global_top : 0;
+ const float global_top = get_position().y;
+ const float limit = global_top < visible_rect.position.y ? visible_rect.position.y - global_top : 0;
dy = MIN(dy, limit);
} else if (dy < 0) {
- const float global_bottom = get_global_position().y + get_size().y * get_global_transform().get_scale().y;
- const float viewport_height = get_viewport_rect().size.y;
+ const float global_bottom = get_position().y + get_size().y;
+ const float viewport_height = visible_rect.position.y + visible_rect.size.y;
const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0;
dy = -MIN(-dy, limit);
}
+
+ if (dy == 0) {
+ return;
+ }
+
set_position(get_position() + Vector2(0, dy));
Ref<InputEventMouseMotion> ie;
@@ -231,8 +242,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
emit_signal("id_focused", i);
- update();
- accept_event();
+ control->update();
+ set_input_as_handled();
break;
}
}
@@ -251,8 +262,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
emit_signal("id_focused", i);
- update();
- accept_event();
+ control->update();
+ set_input_as_handled();
break;
}
}
@@ -261,13 +272,13 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
Node *n = get_parent();
if (n && Object::cast_to<PopupMenu>(n)) {
hide();
- accept_event();
+ set_input_as_handled();
}
} else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) {
_activate_submenu(mouse_over);
- accept_event();
+ set_input_as_handled();
}
} else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
@@ -278,7 +289,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
} else {
activate_item(mouse_over);
}
- accept_event();
+ set_input_as_handled();
}
}
@@ -294,15 +305,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
case BUTTON_WHEEL_DOWN: {
- 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());
- }
+ _scroll(-b->get_factor(), b->get_position());
} break;
case BUTTON_WHEEL_UP: {
- if (get_global_position().y < 0) {
- _scroll(b->get_factor(), b->get_position());
- }
+ _scroll(b->get_factor(), b->get_position());
} break;
default: {
// Allow activating item by releasing the LMB or any that was down when the popup appeared
@@ -338,7 +345,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- //update();
+ //control->update();
}
Ref<InputEventMouseMotion> m = p_event;
@@ -354,7 +361,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) {
if (!Rect2(Point2(), get_size()).has_point(m->get_position()) && E->get().has_point(m->get_position())) {
- call_deferred("hide");
+
+ _close_pressed();
return;
}
}
@@ -364,7 +372,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (id < 0) {
mouse_over = -1;
- update();
+ control->update();
return;
}
@@ -375,20 +383,18 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (over != mouse_over) {
mouse_over = over;
- update();
+ control->update();
}
}
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid()) {
- if (get_global_position().y + get_size().y > get_viewport_rect().size.y || get_global_position().y < 0) {
- _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
- }
+ _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
}
Ref<InputEventKey> k = p_event;
- if (allow_search && k.is_valid() && k->get_unicode()) {
+ if (allow_search && k.is_valid() && k->get_unicode() && k->is_pressed()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
@@ -416,218 +422,227 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (items[i].text.findn(search_string) == 0) {
mouse_over = i;
emit_signal("id_focused", i);
- update();
- accept_event();
+ control->update();
+ set_input_as_handled();
break;
}
}
}
}
-bool PopupMenu::has_point(const Point2 &p_point) const {
+void PopupMenu::_draw() {
- if (parent_rect.has_point(p_point))
- return true;
- for (const List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) {
+ RID ci = control->get_canvas_item();
+ Size2 size = get_size();
- if (E->get().has_point(p_point))
- return true;
- }
+ Ref<StyleBox> style = get_theme_stylebox("panel");
+ Ref<StyleBox> hover = get_theme_stylebox("hover");
+ Ref<Font> font = get_theme_font("font");
+ // In Item::checkable_type enum order (less the non-checkable member)
+ Ref<Texture2D> check[] = { get_theme_icon("checked"), get_theme_icon("radio_checked") };
+ Ref<Texture2D> uncheck[] = { get_theme_icon("unchecked"), get_theme_icon("radio_unchecked") };
+ Ref<Texture2D> submenu = get_theme_icon("submenu");
+ Ref<StyleBox> separator = get_theme_stylebox("separator");
+ Ref<StyleBox> labeled_separator_left = get_theme_stylebox("labeled_separator_left");
+ Ref<StyleBox> labeled_separator_right = get_theme_stylebox("labeled_separator_right");
- return Control::has_point(p_point);
-}
-
-void PopupMenu::_notification(int p_what) {
+ style->draw(ci, Rect2(Point2(), get_size()));
+ Point2 ofs = style->get_offset();
+ int vseparation = get_theme_constant("vseparation");
+ int hseparation = get_theme_constant("hseparation");
+ Color font_color = get_theme_color("font_color");
+ Color font_color_disabled = get_theme_color("font_color_disabled");
+ Color font_color_accel = get_theme_color("font_color_accel");
+ Color font_color_hover = get_theme_color("font_color_hover");
+ float font_h = font->get_height();
- switch (p_what) {
+ // 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++) {
- case NOTIFICATION_ENTER_TREE: {
+ if (!items[i].icon.is_null())
+ icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs);
- PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent());
- if (pm) {
- // Inherit submenu's popup delay time from parent menu
- float pm_delay = pm->get_submenu_popup_delay();
- set_submenu_popup_delay(pm_delay);
- }
- } break;
- case NOTIFICATION_TRANSLATION_CHANGED: {
+ if (items[i].checkable_type)
+ has_check = true;
+ }
+ if (icon_ofs > 0.0)
+ icon_ofs += hseparation;
- for (int i = 0; i < items.size(); i++) {
- items.write[i].xl_text = tr(items[i].text);
- }
+ float check_ofs = 0.0;
+ if (has_check)
+ check_ofs = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation;
- minimum_size_changed();
- update();
- } break;
- case NOTIFICATION_DRAW: {
-
- RID ci = get_canvas_item();
- Size2 size = get_size();
-
- Ref<StyleBox> style = get_stylebox("panel");
- Ref<StyleBox> hover = get_stylebox("hover");
- Ref<Font> font = get_font("font");
- // In Item::checkable_type enum order (less the non-checkable member)
- Ref<Texture2D> check[] = { get_icon("checked"), get_icon("radio_checked") };
- Ref<Texture2D> uncheck[] = { get_icon("unchecked"), get_icon("radio_unchecked") };
- Ref<Texture2D> submenu = get_icon("submenu");
- Ref<StyleBox> separator = get_stylebox("separator");
- Ref<StyleBox> labeled_separator_left = get_stylebox("labeled_separator_left");
- Ref<StyleBox> labeled_separator_right = get_stylebox("labeled_separator_right");
-
- style->draw(ci, Rect2(Point2(), get_size()));
- Point2 ofs = style->get_offset();
- int vseparation = get_constant("vseparation");
- int hseparation = get_constant("hseparation");
- Color font_color = get_color("font_color");
- Color font_color_disabled = get_color("font_color_disabled");
- Color font_color_accel = get_color("font_color_accel");
- 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++) {
+ 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 (i > 0)
+ ofs.y += vseparation;
+ Point2 item_ofs = ofs;
+ Size2 icon_size;
+ float h;
- if (items[i].checkable_type)
- has_check = true;
- }
- if (icon_ofs > 0.0)
- icon_ofs += hseparation;
+ if (!items[i].icon.is_null()) {
- float check_ofs = 0.0;
- if (has_check)
- check_ofs = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation;
+ icon_size = items[i].icon->get_size();
+ h = MAX(icon_size.height, font_h);
+ } else {
- for (int i = 0; i < items.size(); i++) {
+ h = font_h;
+ }
- if (i > 0)
- ofs.y += vseparation;
- Point2 item_ofs = ofs;
- Size2 icon_size;
- float h;
+ if (i == mouse_over) {
- if (!items[i].icon.is_null()) {
+ hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
+ }
- icon_size = items[i].icon->get_size();
- h = MAX(icon_size.height, font_h);
- } else {
+ String text = items[i].xl_text;
- h = font_h;
+ item_ofs.x += items[i].h_ofs;
+ if (items[i].separator) {
+
+ int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
+ if (text != String()) {
+ int ss = font->get_string_size(text).width;
+ int center = (get_size().width) / 2;
+ int l = center - ss / 2;
+ int r = center + ss / 2;
+ if (l > item_ofs.x) {
+ labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h)));
}
-
- if (i == mouse_over) {
-
- hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
+ if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) {
+ labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h)));
}
+ } else {
+ separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h)));
+ }
+ }
- String text = items[i].xl_text;
+ Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
- item_ofs.x += items[i].h_ofs;
- if (items[i].separator) {
+ if (items[i].checkable_type) {
+ Texture2D *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);
+ }
- int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
- if (text != String()) {
- int ss = font->get_string_size(text).width;
- int center = (get_size().width) / 2;
- int l = center - ss / 2;
- int r = center + ss / 2;
- if (l > item_ofs.x) {
- labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h)));
- }
- if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) {
- labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h)));
- }
- } else {
- separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h)));
- }
- }
+ if (!items[i].icon.is_null()) {
+ items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
+ }
- Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+ if (items[i].submenu != "") {
+ submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ }
- if (items[i].checkable_type) {
- Texture2D *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.y += font->get_ascent();
+ if (items[i].separator) {
- if (!items[i].icon.is_null()) {
- items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
- }
+ if (text != String()) {
+ int center = (get_size().width - font->get_string_size(text).width) / 2;
+ font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled);
+ }
+ } else {
- if (items[i].submenu != "") {
- submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
- }
+ 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));
+ }
- item_ofs.y += font->get_ascent();
- if (items[i].separator) {
+ if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) {
+ //accelerator
+ String text2 = _get_accel_text(i);
+ item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width;
+ font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel);
+ }
- if (text != String()) {
- int center = (get_size().width - font->get_string_size(text).width) / 2;
- font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled);
- }
- } else {
+ items.write[i]._ofs_cache = ofs.y;
- 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));
- }
+ ofs.y += h;
+ }
+}
- if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) {
- //accelerator
- String text2 = _get_accel_text(i);
- item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width;
- font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel);
- }
+void PopupMenu::_notification(int p_what) {
+
+ switch (p_what) {
- items.write[i]._ofs_cache = ofs.y;
+ case NOTIFICATION_ENTER_TREE: {
- ofs.y += h;
+ PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent());
+ if (pm) {
+ // Inherit submenu's popup delay time from parent menu
+ float pm_delay = pm->get_submenu_popup_delay();
+ set_submenu_popup_delay(pm_delay);
}
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_TRANSLATION_CHANGED: {
- if (hide_on_window_lose_focus)
- hide();
+ for (int i = 0; i < items.size(); i++) {
+ items.write[i].xl_text = tr(items[i].text);
+ }
+
+ child_controls_changed();
+ control->update();
} break;
- case NOTIFICATION_MOUSE_ENTER: {
+ case NOTIFICATION_WM_MOUSE_ENTER: {
- grab_focus();
+ //grab_focus();
} break;
- case NOTIFICATION_MOUSE_EXIT: {
+ case NOTIFICATION_WM_MOUSE_EXIT: {
if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) {
mouse_over = -1;
- update();
+ control->update();
}
} break;
case NOTIFICATION_POST_POPUP: {
- initial_button_mask = Input::get_singleton()->get_mouse_button_mask();
+ initial_button_mask = InputFilter::get_singleton()->get_mouse_button_mask();
during_grabbed_click = (bool)initial_button_mask;
} break;
- case NOTIFICATION_POPUP_HIDE: {
+ case NOTIFICATION_WM_SIZE_CHANGED: {
- if (mouse_over >= 0) {
- mouse_over = -1;
- update();
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ //only used when using operating system windows
+ if (get_window_id() != DisplayServer::INVALID_WINDOW_ID && autohide_areas.size()) {
+ Point2 mouse_pos = DisplayServer::get_singleton()->mouse_get_position();
+ mouse_pos -= get_position();
+
+ for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) {
+
+ if (!Rect2(Point2(), get_size()).has_point(mouse_pos) && E->get().has_point(mouse_pos)) {
+ _close_pressed();
+ return;
+ }
+ }
}
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
- for (int i = 0; i < items.size(); i++) {
- if (items[i].submenu == "")
- continue;
+ if (!is_visible()) {
+ if (mouse_over >= 0) {
+ mouse_over = -1;
+ control->update();
+ }
+
+ for (int i = 0; i < items.size(); i++) {
+ if (items[i].submenu == "")
+ continue;
- Node *n = get_node(items[i].submenu);
- if (!n)
- continue;
+ Node *n = get_node(items[i].submenu);
+ if (!n)
+ continue;
- PopupMenu *pm = Object::cast_to<PopupMenu>(n);
- if (!pm || !pm->is_visible())
- continue;
+ PopupMenu *pm = Object::cast_to<PopupMenu>(n);
+ if (!pm || !pm->is_visible())
+ continue;
- pm->hide();
+ pm->hide();
+ }
+
+ set_process_internal(false);
+ } else {
+ if (get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ set_process_internal(true);
+ }
}
} break;
}
@@ -648,8 +663,8 @@ void PopupMenu::add_item(const String &p_label, int p_id, uint32_t p_accel) {
Item item;
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
@@ -658,8 +673,8 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
item.icon = p_icon;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) {
@@ -668,8 +683,8 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
@@ -679,8 +694,8 @@ void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &
item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p_accel) {
@@ -689,8 +704,8 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
@@ -700,8 +715,8 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St
item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, uint32_t p_accel) {
@@ -711,8 +726,8 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
item.max_states = p_max_states;
item.state = p_default_state;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
#define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \
@@ -729,8 +744,8 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_g
Item item;
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -739,8 +754,8 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortC
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.icon = p_icon;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -749,8 +764,8 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bo
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -760,8 +775,8 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<
item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -770,8 +785,8 @@ void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -781,8 +796,8 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons
item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) {
@@ -793,8 +808,8 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
item.id = p_id == -1 ? items.size() : p_id;
item.submenu = p_submenu;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
#undef ITEM_SETUP_WITH_ACCEL
@@ -808,16 +823,16 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
items.write[p_idx].text = p_text;
items.write[p_idx].xl_text = tr(p_text);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].icon = p_icon;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
@@ -825,16 +840,16 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
items.write[p_idx].checked = p_checked;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_id(int p_idx, int p_id) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].id = p_id;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
@@ -842,40 +857,40 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].accel = p_accel;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].metadata = p_meta;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].disabled = p_disabled;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].submenu = p_submenu;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::toggle_item_checked(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checked = !items[p_idx].checked;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
String PopupMenu::get_item_text(int p_idx) const {
@@ -968,7 +983,7 @@ void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].separator = p_separator;
- update();
+ control->update();
}
bool PopupMenu::is_item_separator(int p_idx) const {
@@ -980,21 +995,21 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
- update();
+ control->update();
}
void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE;
- update();
+ control->update();
}
void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].tooltip = p_tooltip;
- update();
+ control->update();
}
void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global) {
@@ -1009,29 +1024,29 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo
_ref_shortcut(items[p_idx].shortcut);
}
- update();
+ control->update();
}
void PopupMenu::set_item_h_offset(int p_idx, int p_offset) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].h_ofs = p_offset;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].state = p_state;
- update();
+ control->update();
}
void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].shortcut_is_disabled = p_disabled;
- update();
+ control->update();
}
void PopupMenu::toggle_item_multistate(int p_idx) {
@@ -1045,7 +1060,7 @@ void PopupMenu::toggle_item_multistate(int p_idx) {
if (items.write[p_idx].max_states <= items[p_idx].state)
items.write[p_idx].state = 0;
- update();
+ control->update();
}
bool PopupMenu::is_item_checkable(int p_idx) const {
@@ -1177,8 +1192,8 @@ void PopupMenu::remove_item(int p_idx) {
}
items.remove(p_idx);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_separator(const String &p_text) {
@@ -1191,7 +1206,7 @@ void PopupMenu::add_separator(const String &p_text) {
sep.xl_text = tr(p_text);
}
items.push_back(sep);
- update();
+ control->update();
}
void PopupMenu::clear() {
@@ -1203,8 +1218,8 @@ void PopupMenu::clear() {
}
items.clear();
mouse_over = -1;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
Array PopupMenu::_get_items() const {
@@ -1345,16 +1360,6 @@ bool PopupMenu::get_allow_search() const {
return allow_search;
}
-void PopupMenu::set_hide_on_window_lose_focus(bool p_enabled) {
-
- hide_on_window_lose_focus = p_enabled;
-}
-
-bool PopupMenu::is_hide_on_window_lose_focus() const {
-
- return hide_on_window_lose_focus;
-}
-
String PopupMenu::get_tooltip(const Point2 &p_pos) const {
int over = _get_mouse_over(p_pos);
@@ -1387,6 +1392,14 @@ void PopupMenu::clear_autohide_areas() {
autohide_areas.clear();
}
+void PopupMenu::take_mouse_focus() {
+ ERR_FAIL_COND(!is_inside_tree());
+
+ if (get_parent()) {
+ get_parent()->get_viewport()->pass_mouse_focus_to(this, control);
+ }
+}
+
void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input);
@@ -1466,9 +1479,6 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_submenu_popup_delay", "seconds"), &PopupMenu::set_submenu_popup_delay);
ClassDB::bind_method(D_METHOD("get_submenu_popup_delay"), &PopupMenu::get_submenu_popup_delay);
- ClassDB::bind_method(D_METHOD("set_hide_on_window_lose_focus", "enable"), &PopupMenu::set_hide_on_window_lose_focus);
- ClassDB::bind_method(D_METHOD("is_hide_on_window_lose_focus"), &PopupMenu::is_hide_on_window_lose_focus);
-
ClassDB::bind_method(D_METHOD("set_allow_search", "allow"), &PopupMenu::set_allow_search);
ClassDB::bind_method(D_METHOD("get_allow_search"), &PopupMenu::get_allow_search);
@@ -1486,7 +1496,6 @@ void PopupMenu::_bind_methods() {
void PopupMenu::popup(const Rect2 &p_bounds) {
- grab_click_focus();
moved = Vector2();
invalidated_click = true;
Popup::popup(p_bounds);
@@ -1494,21 +1503,26 @@ void PopupMenu::popup(const Rect2 &p_bounds) {
PopupMenu::PopupMenu() {
+ control = memnew(Control);
+ add_child(control);
+
+ control->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ connect("window_input", callable_mp(this, &PopupMenu::_gui_input));
+ control->connect("draw", callable_mp(this, &PopupMenu::_draw));
+
mouse_over = -1;
submenu_over = -1;
initial_button_mask = 0;
during_grabbed_click = false;
+ invalidated_click = false;
allow_search = false;
search_time_msec = 0;
search_string = "";
- set_focus_mode(FOCUS_ALL);
- set_as_toplevel(true);
set_hide_on_item_selection(true);
set_hide_on_checkable_item_selection(true);
set_hide_on_multistate_item_selection(false);
- set_hide_on_window_lose_focus(true);
submenu_timer = memnew(Timer);
submenu_timer->set_wait_time(0.3);