Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OptionButton fix remove and select #21837

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 77 additions & 6 deletions scene/gui/option_button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,53 @@ void OptionButton::pressed() {
popup->popup();
}

void OptionButton::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id) {
bool OptionButton::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id) {

if (!allow_duplicates) {
for (int i = 0; i < popup->get_item_count(); i++) {
if (p_label == popup->get_item_text(i)) {
return false;
}
}
}

if (p_id == -1) {
p_id = popup->get_item_count();
} else {
p_id -= 1;
}
popup->add_icon_radio_check_item(p_icon, p_label, p_id);
popup->sort_items_by_id();
if (p_id < current) {
current += 1;
}
if (popup->get_item_count() == 1)
select(0);
return true;
}
void OptionButton::add_item(const String &p_label, int p_id) {
bool OptionButton::add_item(const String &p_label, int p_id) {

if (!allow_duplicates) {
for (int i = 0; i < popup->get_item_count(); i++) {
if (p_label == popup->get_item_text(i)) {
return false;
}
}
}

if (p_id == -1) {
p_id = popup->get_item_count();
} else {
p_id -= 1;
}
popup->add_radio_check_item(p_label, p_id);
popup->sort_items_by_id();
if (p_id < current) {
current += 1;
}
if (popup->get_item_count() == 1)
select(0);
return true;
}

void OptionButton::set_item_text(int p_idx, const String &p_text) {
Expand Down Expand Up @@ -191,10 +227,21 @@ void OptionButton::clear() {

void OptionButton::_select(int p_which, bool p_emit) {

if (p_which < 0)
return;
if (p_which == current)
if (p_which == -1) {
for (int i = 0; i < popup->get_item_count(); i++) {

popup->set_item_checked(i, i == p_which);
}

current = p_which;
set_text("");
set_icon(NULL);

if (is_inside_tree() && p_emit) {
emit_signal("item_selected", current);
}
return;
}

ERR_FAIL_INDEX(p_which, popup->get_item_count());

Expand Down Expand Up @@ -245,7 +292,20 @@ Variant OptionButton::get_selected_metadata() const {

void OptionButton::remove_item(int p_idx) {

ERR_FAIL_INDEX(p_idx, popup->get_item_count());

int next = -1;
if (popup->get_item_count() > 1) {
if (p_idx < popup->get_item_count() - 1) {
next = p_idx;
} else if (p_idx == popup->get_item_count() - 1) {
next = p_idx - 1;
}
}

popup->remove_item(p_idx);
popup->sort_items_by_id();
_select(next, true);
}

PopupMenu *OptionButton::get_popup() const {
Expand Down Expand Up @@ -288,6 +348,13 @@ void OptionButton::_set_items(const Array &p_items) {
}
}

void OptionButton::set_allow_duplicates(bool p_allow) {
allow_duplicates = p_allow;
}

bool OptionButton::get_allow_duplicates() const {
return allow_duplicates;
}
void OptionButton::get_translatable_strings(List<String> *p_strings) const {

popup->get_translatable_strings(p_strings);
Expand Down Expand Up @@ -321,6 +388,9 @@ void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_item", "idx"), &OptionButton::remove_item);
ClassDB::bind_method(D_METHOD("_select_int"), &OptionButton::_select_int);

ClassDB::bind_method(D_METHOD("set_allow_duplicates", "allow"), &OptionButton::set_allow_duplicates);
ClassDB::bind_method(D_METHOD("get_allow_duplicates"), &OptionButton::get_allow_duplicates);

ClassDB::bind_method(D_METHOD("get_popup"), &OptionButton::get_popup);

ClassDB::bind_method(D_METHOD("_set_items"), &OptionButton::_set_items);
Expand All @@ -329,14 +399,15 @@ void OptionButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
// "selected" property must come after "items", otherwise GH-10213 occurs
ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "Allow Duplicates"), "set_allow_duplicates", "get_allow_duplicates");
ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "id")));
}

OptionButton::OptionButton() {

current = -1;
set_toggle_mode(true);
allow_duplicates = true;
set_text_align(ALIGN_LEFT);
set_action_mode(ACTION_MODE_BUTTON_PRESS);

Expand Down
8 changes: 6 additions & 2 deletions scene/gui/option_button.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class OptionButton : public Button {

PopupMenu *popup;
int current;
bool allow_duplicates;

void _focused(int p_which);
void _selected(int p_which);
Expand All @@ -57,15 +58,18 @@ class OptionButton : public Button {
static void _bind_methods();

public:
void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1);
void add_item(const String &p_label, int p_id = -1);
bool add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1);
bool add_item(const String &p_label, int p_id = -1);

void set_item_text(int p_idx, const String &p_text);
void set_item_icon(int p_idx, const Ref<Texture> &p_icon);
void set_item_id(int p_idx, int p_id);
void set_item_metadata(int p_idx, const Variant &p_metadata);
void set_item_disabled(int p_idx, bool p_disabled);

void set_allow_duplicates(bool p_allow);
bool get_allow_duplicates() const;

String get_item_text(int p_idx) const;
Ref<Texture> get_item_icon(int p_idx) const;
int get_item_id(int p_idx) const;
Expand Down
8 changes: 8 additions & 0 deletions scene/gui/popup_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,13 @@ void PopupMenu::clear_autohide_areas() {
autohide_areas.clear();
}

void PopupMenu::sort_items_by_id() {
items.sort_custom<PopupMenu::SortItems>();
for (int i = 0; i < items.size(); i++) {
items.write[i].id = i;
}
}

void PopupMenu::_bind_methods() {

ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input);
Expand Down Expand Up @@ -1444,6 +1451,7 @@ void PopupMenu::_bind_methods() {

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("sort_items_by_id"), &PopupMenu::sort_items_by_id);

ClassDB::bind_method(D_METHOD("_set_items"), &PopupMenu::_set_items);
ClassDB::bind_method(D_METHOD("_get_items"), &PopupMenu::_get_items);
Expand Down
8 changes: 7 additions & 1 deletion scene/gui/popup_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ class PopupMenu : public Popup {
}
};

struct SortItems {
bool operator()(Item p_a, Item p_b) const {
return p_a.id < p_b.id;
}
};

Timer *submenu_timer;
List<Rect2> autohide_areas;
Vector<Item> items;
Expand Down Expand Up @@ -186,7 +192,7 @@ class PopupMenu : public Popup {
void add_separator(const String &p_text = String());

void clear();

void sort_items_by_id();
void set_parent_rect(const Rect2 &p_rect);

virtual String get_tooltip(const Point2 &p_pos) const;
Expand Down