diff options
Diffstat (limited to 'scene/gui/popup_menu.cpp')
-rw-r--r-- | scene/gui/popup_menu.cpp | 154 |
1 files changed, 115 insertions, 39 deletions
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 18e609c798..436dda41a4 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -398,10 +398,19 @@ void PopupMenu::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + + 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: { for (int i = 0; i < items.size(); i++) { - items[i].xl_text = tr(items[i].text); + items.write[i].xl_text = tr(items[i].text); } minimum_size_changed(); @@ -421,6 +430,8 @@ void PopupMenu::_notification(int p_what) { Ref<Texture> uncheck[] = { get_icon("unchecked"), get_icon("radio_unchecked") }; Ref<Texture> 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(); @@ -457,10 +468,25 @@ void PopupMenu::_notification(int p_what) { hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation))); } + String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text; + if (items[i].separator) { int sep_h = separator->get_center_size().height + separator->get_minimum_size().height; - 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 (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].checkable_type) { @@ -480,8 +506,13 @@ void PopupMenu::_notification(int p_what) { } item_ofs.y += font->get_ascent(); - String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text; - if (!items[i].separator) { + if (items[i].separator) { + + 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 { 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)); } @@ -493,12 +524,17 @@ void PopupMenu::_notification(int p_what) { font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, i == mouse_over ? font_color_hover : font_color_accel); } - items[i]._ofs_cache = ofs.y; + items.write[i]._ofs_cache = ofs.y; ofs.y += h; } } break; + case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { + + if (hide_on_window_lose_focus) + hide(); + } break; case NOTIFICATION_MOUSE_ENTER: { grab_focus(); @@ -591,7 +627,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p_accel) { add_check_item(p_label, p_ID, p_accel); - items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } @@ -599,7 +635,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) { add_icon_check_item(p_icon, p_label, p_ID, p_accel); - items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } @@ -671,7 +707,7 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { add_check_shortcut(p_shortcut, p_ID, p_global); - items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } @@ -693,8 +729,8 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int void PopupMenu::set_item_text(int p_idx, const String &p_text) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].text = p_text; - items[p_idx].xl_text = tr(p_text); + items.write[p_idx].text = p_text; + items.write[p_idx].xl_text = tr(p_text); update(); minimum_size_changed(); @@ -702,7 +738,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) { void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].icon = p_icon; + items.write[p_idx].icon = p_icon; update(); minimum_size_changed(); @@ -711,7 +747,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].checked = p_checked; + items.write[p_idx].checked = p_checked; update(); minimum_size_changed(); @@ -719,7 +755,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { void PopupMenu::set_item_id(int p_idx, int p_ID) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].ID = p_ID; + items.write[p_idx].ID = p_ID; update(); minimum_size_changed(); @@ -728,7 +764,7 @@ void PopupMenu::set_item_id(int p_idx, int p_ID) { void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].accel = p_accel; + items.write[p_idx].accel = p_accel; update(); minimum_size_changed(); @@ -737,7 +773,7 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].metadata = p_meta; + items.write[p_idx].metadata = p_meta; update(); minimum_size_changed(); } @@ -745,7 +781,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].disabled = p_disabled; + items.write[p_idx].disabled = p_disabled; update(); minimum_size_changed(); } @@ -753,7 +789,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].submenu = p_submenu; + items.write[p_idx].submenu = p_submenu; update(); minimum_size_changed(); } @@ -761,7 +797,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { void PopupMenu::toggle_item_checked(int p_idx) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].checked = !items[p_idx].checked; + items.write[p_idx].checked = !items[p_idx].checked; update(); minimum_size_changed(); } @@ -855,7 +891,7 @@ int PopupMenu::get_item_state(int p_idx) const { void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].separator = p_separator; + items.write[p_idx].separator = p_separator; update(); } @@ -867,21 +903,21 @@ bool PopupMenu::is_item_separator(int p_idx) const { void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE; + items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE; update(); } void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE; + items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE; update(); } void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].tooltip = p_tooltip; + items.write[p_idx].tooltip = p_tooltip; update(); } @@ -890,8 +926,8 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo if (items[p_idx].shortcut.is_valid()) { _unref_shortcut(items[p_idx].shortcut); } - items[p_idx].shortcut = p_shortcut; - items[p_idx].shortcut_is_global = p_global; + items.write[p_idx].shortcut = p_shortcut; + items.write[p_idx].shortcut_is_global = p_global; if (items[p_idx].shortcut.is_valid()) { _ref_shortcut(items[p_idx].shortcut); @@ -903,7 +939,7 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].h_ofs = p_offset; + items.write[p_idx].h_ofs = p_offset; update(); minimum_size_changed(); } @@ -911,14 +947,14 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { void PopupMenu::set_item_multistate(int p_idx, int p_state) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].state = p_state; + items.write[p_idx].state = p_state; update(); } void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].shortcut_is_disabled = p_disabled; + items.write[p_idx].shortcut_is_disabled = p_disabled; update(); } @@ -929,9 +965,9 @@ void PopupMenu::toggle_item_multistate(int p_idx) { return; } - ++items[p_idx].state; - if (items[p_idx].max_states <= items[p_idx].state) - items[p_idx].state = 0; + ++items.write[p_idx].state; + if (items.write[p_idx].max_states <= items[p_idx].state) + items.write[p_idx].state = 0; update(); } @@ -1013,10 +1049,8 @@ void PopupMenu::activate_item(int p_item) { ERR_FAIL_INDEX(p_item, items.size()); ERR_FAIL_COND(items[p_item].separator); int id = items[p_item].ID >= 0 ? items[p_item].ID : p_item; - emit_signal("id_pressed", id); - emit_signal("index_pressed", p_item); - //hide all parent PopupMenue's + //hide all parent PopupMenus Node *next = get_parent(); PopupMenu *pop = Object::cast_to<PopupMenu>(next); while (pop) { @@ -1040,16 +1074,23 @@ void PopupMenu::activate_item(int p_item) { // Hides popup by default; unless otherwise specified // by using set_hide_on_item_selection and set_hide_on_checkable_item_selection + bool need_hide = true; + if (items[p_item].checkable_type) { if (!hide_on_checkable_item_selection) - return; + need_hide = false; } else if (0 < items[p_item].max_states) { if (!hide_on_multistate_item_selection) - return; + need_hide = false; } else if (!hide_on_item_selection) - return; + need_hide = false; - hide(); + emit_signal("id_pressed", id); + emit_signal("index_pressed", p_item); + + if (need_hide) { + hide(); + } } void PopupMenu::remove_item(int p_idx) { @@ -1062,13 +1103,18 @@ void PopupMenu::remove_item(int p_idx) { items.remove(p_idx); update(); + minimum_size_changed(); } -void PopupMenu::add_separator() { +void PopupMenu::add_separator(const String &p_text) { Item sep; sep.separator = true; sep.ID = -1; + if (p_text != String()) { + sep.text = p_text; + sep.xl_text = tr(p_text); + } items.push_back(sep); update(); } @@ -1201,6 +1247,29 @@ bool PopupMenu::is_hide_on_multistate_item_selection() const { return hide_on_multistate_item_selection; } +void PopupMenu::set_submenu_popup_delay(float p_time) { + + if (p_time <= 0) + p_time = 0.01; + + submenu_timer->set_wait_time(p_time); +} + +float PopupMenu::get_submenu_popup_delay() const { + + return submenu_timer->get_wait_time(); +} + +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); @@ -1288,7 +1357,7 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_item", "idx"), &PopupMenu::remove_item); - ClassDB::bind_method(D_METHOD("add_separator"), &PopupMenu::add_separator); + ClassDB::bind_method(D_METHOD("add_separator", "label"), &PopupMenu::add_separator, DEFVAL(String())); ClassDB::bind_method(D_METHOD("clear"), &PopupMenu::clear); ClassDB::bind_method(D_METHOD("_set_items"), &PopupMenu::_set_items); @@ -1303,12 +1372,19 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hide_on_state_item_selection", "enable"), &PopupMenu::set_hide_on_multistate_item_selection); ClassDB::bind_method(D_METHOD("is_hide_on_state_item_selection"), &PopupMenu::is_hide_on_multistate_item_selection); + 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("_submenu_timeout"), &PopupMenu::_submenu_timeout); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "submenu_popup_delay"), "set_submenu_popup_delay", "get_submenu_popup_delay"); ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID"))); ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "ID"))); |