diff options
Diffstat (limited to 'scene/gui/popup_menu.cpp')
-rw-r--r-- | scene/gui/popup_menu.cpp | 265 |
1 files changed, 177 insertions, 88 deletions
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index c0a559e624..2e854abb76 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -39,7 +39,7 @@ String PopupMenu::_get_accel_text(const Item &p_item) const { if (p_item.shortcut.is_valid()) { return p_item.shortcut->get_as_text(); - } else if (p_item.accel) { + } else if (p_item.accel != Key::NONE) { return keycode_get_string(p_item.accel); } return String(); @@ -74,7 +74,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const { size.width += items[i].text_buf->get_size().x; size.height += vseparation; - if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) { + if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) { int accel_w = hseparation * 2; accel_w += items[i].accel_text_buf->get_size().x; accel_max_w = MAX(accel_w, accel_max_w); @@ -358,15 +358,15 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { return; } - int button_idx = b->get_button_index(); + MouseButton button_idx = b->get_button_index(); if (!b->is_pressed()) { // Activate the item on release of either the left mouse button or // any mouse button held down when the popup was opened. // This allows for opening the popup and triggering an action in a single mouse click. - if (button_idx == MOUSE_BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) { + if (button_idx == MouseButton::LEFT || (initial_button_mask & mouse_button_to_mask(button_idx)) != MouseButton::NONE) { bool was_during_grabbed_click = during_grabbed_click; during_grabbed_click = false; - initial_button_mask = 0; + initial_button_mask = MouseButton::NONE; // Disable clicks under a time threshold to avoid selection right when opening the popup. uint64_t now = OS::get_singleton()->get_ticks_msec(); @@ -637,7 +637,7 @@ void PopupMenu::_draw_items() { } // Accelerator / Shortcut - if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) { + if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) { if (rtl) { item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding; } else { @@ -813,16 +813,17 @@ void PopupMenu::_notification(int p_what) { item.id = p_id == -1 ? items.size() : p_id; \ item.accel = p_accel; -void PopupMenu::add_item(const String &p_label, int p_id, uint32_t p_accel) { +void PopupMenu::add_item(const String &p_label, int p_id, Key p_accel) { Item item; ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); items.push_back(item); _shape_item(items.size() - 1); control->update(); child_controls_changed(); + notify_property_list_changed(); } -void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { +void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) { Item item; ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.icon = p_icon; @@ -830,9 +831,10 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe _shape_item(items.size() - 1); control->update(); child_controls_changed(); + notify_property_list_changed(); } -void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) { +void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) { Item item; ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; @@ -842,7 +844,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel 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) { +void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) { Item item; ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.icon = p_icon; @@ -853,7 +855,7 @@ void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String & child_controls_changed(); } -void PopupMenu::add_radio_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, Key p_accel) { Item item; ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; @@ -863,7 +865,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p 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) { +void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) { Item item; ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.icon = p_icon; @@ -874,7 +876,7 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St 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) { +void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, Key p_accel) { Item item; ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.max_states = p_max_states; @@ -1043,7 +1045,7 @@ void PopupMenu::set_item_id(int p_idx, int p_id) { child_controls_changed(); } -void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { +void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].accel = p_accel; items.write[p_idx].dirty = true; @@ -1119,8 +1121,8 @@ Ref<Texture2D> PopupMenu::get_item_icon(int p_idx) const { return items[p_idx].icon; } -uint32_t PopupMenu::get_item_accelerator(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, items.size(), 0); +Key PopupMenu::get_item_accelerator(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, items.size(), Key::NONE); return items[p_idx].accel; } @@ -1271,30 +1273,38 @@ int PopupMenu::get_current_index() const { return mouse_over; } +void PopupMenu::set_item_count(int p_count) { + ERR_FAIL_COND(p_count < 0); + items.resize(p_count); + control->update(); + child_controls_changed(); + notify_property_list_changed(); +} + int PopupMenu::get_item_count() const { return items.size(); } bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_for_global_only) { - Key code = KEY_NONE; + Key code = Key::NONE; Ref<InputEventKey> k = p_event; if (k.is_valid()) { code = k->get_keycode(); - if (code == KEY_NONE) { + if (code == Key::NONE) { code = (Key)k->get_unicode(); } if (k->is_ctrl_pressed()) { - code |= KEY_MASK_CTRL; + code |= KeyModifierMask::CTRL; } if (k->is_alt_pressed()) { - code |= KEY_MASK_ALT; + code |= KeyModifierMask::ALT; } if (k->is_meta_pressed()) { - code |= KEY_MASK_META; + code |= KeyModifierMask::META; } if (k->is_shift_pressed()) { - code |= KEY_MASK_SHIFT; + code |= KeyModifierMask::SHIFT; } } @@ -1308,7 +1318,7 @@ bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_fo return true; } - if (code != 0 && items[i].accel == code) { + if (code != Key::NONE && items[i].accel == code) { activate_item(i); return true; } @@ -1393,7 +1403,7 @@ void PopupMenu::remove_item(int p_idx) { _unref_shortcut(items[p_idx].shortcut); } - items.remove(p_idx); + items.remove_at(p_idx); control->update(); child_controls_changed(); } @@ -1420,27 +1430,7 @@ void PopupMenu::clear() { mouse_over = -1; control->update(); child_controls_changed(); -} - -Array PopupMenu::_get_items() const { - Array items; - for (int i = 0; i < get_item_count(); i++) { - items.push_back(get_item_text(i)); - items.push_back(get_item_icon(i)); - // For compatibility, use false/true for no/checkbox and integers for other values - int ct = this->items[i].checkable_type; - items.push_back(Variant(ct <= Item::CHECKABLE_TYPE_CHECK_BOX ? is_item_checkable(i) : ct)); - items.push_back(is_item_checked(i)); - items.push_back(is_item_disabled(i)); - - items.push_back(get_item_id(i)); - items.push_back(get_item_accelerator(i)); - items.push_back(get_item_metadata(i)); - items.push_back(get_item_submenu(i)); - items.push_back(is_item_separator(i)); - } - - return items; + notify_property_list_changed(); } void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) { @@ -1461,45 +1451,6 @@ void PopupMenu::_unref_shortcut(Ref<Shortcut> p_sc) { } } -void PopupMenu::_set_items(const Array &p_items) { - ERR_FAIL_COND(p_items.size() % 10); - clear(); - - for (int i = 0; i < p_items.size(); i += 10) { - String text = p_items[i + 0]; - Ref<Texture2D> icon = p_items[i + 1]; - // For compatibility, use false/true for no/checkbox and integers for other values - bool checkable = p_items[i + 2]; - bool radio_checkable = (int)p_items[i + 2] == Item::CHECKABLE_TYPE_RADIO_BUTTON; - bool checked = p_items[i + 3]; - bool disabled = p_items[i + 4]; - - int id = p_items[i + 5]; - int accel = p_items[i + 6]; - Variant meta = p_items[i + 7]; - String subm = p_items[i + 8]; - bool sep = p_items[i + 9]; - - int idx = get_item_count(); - add_item(text, id); - set_item_icon(idx, icon); - if (checkable) { - if (radio_checkable) { - set_item_as_radio_checkable(idx, true); - } else { - set_item_as_checkable(idx, true); - } - } - set_item_checked(idx, checked); - set_item_disabled(idx, disabled); - set_item_id(idx, id); - set_item_metadata(idx, meta); - set_item_as_separator(idx, sep); - set_item_accelerator(idx, accel); - set_item_submenu(idx, subm); - } -} - // Hide on item selection determines whether or not the popup will close after item selection void PopupMenu::set_hide_on_item_selection(bool p_enabled) { hide_on_item_selection = p_enabled; @@ -1581,6 +1532,145 @@ void PopupMenu::take_mouse_focus() { } } +bool PopupMenu::_set(const StringName &p_name, const Variant &p_value) { + Vector<String> components = String(p_name).split("/", true, 2); + if (components.size() >= 2 && components[0].begins_with("item_") && components[0].trim_prefix("item_").is_valid_int()) { + int item_index = components[0].trim_prefix("item_").to_int(); + String property = components[1]; + if (property == "text") { + set_item_text(item_index, p_value); + return true; + } else if (property == "icon") { + set_item_icon(item_index, p_value); + return true; + } else if (property == "checkable") { + bool radio_checkable = (int)p_value == Item::CHECKABLE_TYPE_RADIO_BUTTON; + if (radio_checkable) { + set_item_as_radio_checkable(item_index, true); + } else { + bool checkable = p_value; + set_item_as_checkable(item_index, checkable); + } + return true; + } else if (property == "checked") { + set_item_checked(item_index, p_value); + return true; + } else if (property == "id") { + set_item_id(item_index, p_value); + return true; + } else if (components[1] == "disabled") { + set_item_disabled(item_index, p_value); + return true; + } else if (property == "separator") { + set_item_as_separator(item_index, p_value); + return true; + } + } +#ifndef DISABLE_DEPRECATED + // Compatibility. + if (p_name == "items") { + Array arr = p_value; + ERR_FAIL_COND_V(arr.size() % 10, false); + clear(); + + for (int i = 0; i < arr.size(); i += 10) { + String text = arr[i + 0]; + Ref<Texture2D> icon = arr[i + 1]; + // For compatibility, use false/true for no/checkbox and integers for other values + bool checkable = arr[i + 2]; + bool radio_checkable = (int)arr[i + 2] == Item::CHECKABLE_TYPE_RADIO_BUTTON; + bool checked = arr[i + 3]; + bool disabled = arr[i + 4]; + + int id = arr[i + 5]; + int accel = arr[i + 6]; + Variant meta = arr[i + 7]; + String subm = arr[i + 8]; + bool sep = arr[i + 9]; + + int idx = get_item_count(); + add_item(text, id); + set_item_icon(idx, icon); + if (checkable) { + if (radio_checkable) { + set_item_as_radio_checkable(idx, true); + } else { + set_item_as_checkable(idx, true); + } + } + set_item_checked(idx, checked); + set_item_disabled(idx, disabled); + set_item_id(idx, id); + set_item_metadata(idx, meta); + set_item_as_separator(idx, sep); + set_item_accelerator(idx, (Key)accel); + set_item_submenu(idx, subm); + } + } +#endif + return false; +} + +bool PopupMenu::_get(const StringName &p_name, Variant &r_ret) const { + Vector<String> components = String(p_name).split("/", true, 2); + if (components.size() >= 2 && components[0].begins_with("item_") && components[0].trim_prefix("item_").is_valid_int()) { + int item_index = components[0].trim_prefix("item_").to_int(); + String property = components[1]; + if (property == "text") { + r_ret = get_item_text(item_index); + return true; + } else if (property == "icon") { + r_ret = get_item_icon(item_index); + return true; + } else if (property == "checkable") { + r_ret = this->items[item_index].checkable_type; + return true; + } else if (property == "checked") { + r_ret = is_item_checked(item_index); + return true; + } else if (property == "id") { + r_ret = get_item_id(item_index); + return true; + } else if (components[1] == "disabled") { + r_ret = is_item_disabled(item_index); + return true; + } else if (property == "separator") { + r_ret = is_item_separator(item_index); + return true; + } + } + return false; +} + +void PopupMenu::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < items.size(); i++) { + p_list->push_back(PropertyInfo(Variant::STRING, vformat("item_%d/text", i))); + + PropertyInfo pi = PropertyInfo(Variant::OBJECT, vformat("item_%d/icon", i), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"); + pi.usage &= ~(get_item_icon(i).is_null() ? PROPERTY_USAGE_STORAGE : 0); + p_list->push_back(pi); + + pi = PropertyInfo(Variant::INT, vformat("item_%d/checkable", i), PROPERTY_HINT_ENUM, "No,As checkbox,As radio button"); + pi.usage &= ~(!is_item_checkable(i) ? PROPERTY_USAGE_STORAGE : 0); + p_list->push_back(pi); + + pi = PropertyInfo(Variant::BOOL, vformat("item_%d/checked", i)); + pi.usage &= ~(!is_item_checked(i) ? PROPERTY_USAGE_STORAGE : 0); + p_list->push_back(pi); + + pi = PropertyInfo(Variant::INT, vformat("item_%d/id", i), PROPERTY_HINT_RANGE, "1,10,1,or_greater"); + p_list->push_back(pi); + + pi = PropertyInfo(Variant::BOOL, vformat("item_%d/disabled", i)); + pi.usage &= ~(!is_item_disabled(i) ? PROPERTY_USAGE_STORAGE : 0); + p_list->push_back(pi); + + pi = PropertyInfo(Variant::BOOL, vformat("item_%d/separator", i)); + pi.usage &= ~(!is_item_separator(i) ? PROPERTY_USAGE_STORAGE : 0); + p_list->push_back(pi); + } +} + void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0)); @@ -1643,6 +1733,7 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_shortcut", "idx"), &PopupMenu::get_item_shortcut); ClassDB::bind_method(D_METHOD("get_current_index"), &PopupMenu::get_current_index); + ClassDB::bind_method(D_METHOD("set_item_count", "count"), &PopupMenu::set_item_count); ClassDB::bind_method(D_METHOD("get_item_count"), &PopupMenu::get_item_count); ClassDB::bind_method(D_METHOD("remove_item", "idx"), &PopupMenu::remove_item); @@ -1650,9 +1741,6 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("add_separator", "label", "id"), &PopupMenu::add_separator, DEFVAL(String()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("clear"), &PopupMenu::clear); - ClassDB::bind_method(D_METHOD("_set_items"), &PopupMenu::_set_items); - ClassDB::bind_method(D_METHOD("_get_items"), &PopupMenu::_get_items); - ClassDB::bind_method(D_METHOD("set_hide_on_item_selection", "enable"), &PopupMenu::set_hide_on_item_selection); ClassDB::bind_method(D_METHOD("is_hide_on_item_selection"), &PopupMenu::is_hide_on_item_selection); @@ -1668,13 +1756,14 @@ void PopupMenu::_bind_methods() { 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); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "submenu_popup_delay"), "set_submenu_popup_delay", "get_submenu_popup_delay"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_search"), "set_allow_search", "get_allow_search"); + ADD_ARRAY_COUNT("Items", "items_count", "set_item_count", "get_item_count", "item_"); + ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index"))); |