Repository: bevyengine/bevy
File: crates/bevy_ui_widgets/src/radio.rs (Rust)

Code before:
                        // Move to the next one
                        current_index + 1
                    }
                }
                KeyCode::Home => {
                    // Navigate to the first radio button in the group
                    0
                }
                KeyCode::End => {
                    // Navigate to the last radio button in the group
                    radio_buttons.len() - 1
                }
                _ => {
                    return;
                }
            };

            if current_index == next_index {
                // If the next index is the same as the current, do nothing
                return;
            }

            let (next_id, _) = radio_buttons[next_index];

            // Trigger the value change event on the radio button
            commands.trigger(ValueChange::<bool> {
                source: next_id,
                value: true,
            });
            // Trigger the on_change event for the newly checked radio button on radio group
            commands.trigger(ValueChange::<Entity> {
                source: ev.focused_entity,
                value: next_id,
            });
        }
    }
}

// Provides functionality for standalone focusable [`RadioButton`] to react
// on `Space` or `Enter` key press.
fn radio_button_on_key_input(
    mut ev: On<FocusedInput<KeyboardInput>>,
    q_radio_button: Query<Has<Checked>, (With<RadioButton>, Without<InteractionDisabled>)>,
    q_group: Query<(), With<RadioGroup>>,
    q_parents: Query<&ChildOf>,
    mut commands: Commands,
) {
    let Ok(checked) = q_radio_button.get(ev.focused_entity) else {
        // Not a radio button
        return;
    };

Review comment (suggestion):
This seems like an odd way to use `ValueChange`:
* If the value is always the same (`true`), then we should trigger `Activate` instead. `Activate` is meant for widgets whose state never changes.
* Alternatively, we could trigger `ValueChange(false)` when the button gets deselected because of mutual exclusion. However, that's more complicated because now you would have to pass around the entity id of the previously checked button (which is not a problem here, but might be further down).
More generally, if we're going to use `ValueChange`, it should always reflect the current state of the widget triggering it: a listener that only listens to `ValueChange` should always know what state the source is in. We can't do this if it only sends `ValueChange` for some state transitions and not others.


Code after:
                        // Move to the next one
                        current_index + 1
                    }
                }
                KeyCode::Home => {
                    // Navigate to the first radio button in the group
                    0
                }
                KeyCode::End => {
                    // Navigate to the last radio button in the group
                    radio_buttons.len() - 1
                }
                _ => {
                    return;
                }
            };

            if current_index == next_index {
                // If the next index is the same as the current, do nothing
                return;
            }

            let (next_id, _) = radio_buttons[next_index];

            // Trigger the value change event on the radio button
            commands.trigger(ValueChange::<bool> {
                source: next_id,
                value: true,
            });
            // Trigger the on_change event for the newly checked radio button on radio group
            commands.trigger(ValueChange::<Entity> {
                source: ev.focused_entity,
                value: next_id,
            });
        }
    }
}

// Provides functionality for standalone focusable [`RadioButton`] to react
// on `Space` or `Enter` key press.
fn radio_button_on_key_input(
    mut ev: On<FocusedInput<KeyboardInput>>,
    q_radio_button: Query<(Has<InteractionDisabled>, Has<Checked>), With<RadioButton>>,
    q_group: Query<(), With<RadioGroup>>,
    q_parents: Query<&ChildOf>,
    mut commands: Commands,
) {
    let Ok((disabled, checked)) = q_radio_button.get(ev.focused_entity) else {
        // Not a radio button
        return;
    };