Repository: matplotlib/matplotlib
File: lib/matplotlib/widgets.py (Python)

Code before:

    # New layout algorithm with text measurement
    # Parse layout parameter
    bad_layout_raise_msg = \
        "layout must be None, 'vertical', 'horizontal', or a (rows, cols) tuple; " \
        f"got {layout!r}"
    if isinstance(layout, str):
        if layout == "vertical":
            n_rows, n_cols = n_labels, 1
        elif layout == "horizontal":
            n_rows, n_cols = 1, n_labels
        else:
            raise ValueError(bad_layout_raise_msg)
    elif isinstance(layout, tuple) and len(layout) == 2:
        n_rows, n_cols = layout
        if not (isinstance(n_rows, int) and isinstance(n_cols, int)):
            raise TypeError(
                f"layout tuple must contain two integers; got {layout!r}"
            )
        if n_rows * n_cols < n_labels:
            raise ValueError(
                f"layout {layout} has {n_rows * n_cols} positions but "
                f"{n_labels} labels were provided"
            )
    else:
        raise ValueError(bad_layout_raise_msg)

    # Define spacing in display units (pixels) for consistency
    # across different axes sizes
    axes_width_display = ax.bbox.width
    left_margin_display = 15  # pixels
    button_text_offset_display = 6.5  # pixels
    col_spacing_display = 15  # pixels

    # Convert to axes coordinates
    left_margin = left_margin_display / axes_width_display
    button_text_offset = button_text_offset_display / axes_width_display
    col_spacing = col_spacing_display / axes_width_display

    # Create temporary text objects to measure widths
    temp_texts = []
    for label, props in zip(labels, label_props):
        temp_texts.append(ax.text(
            0,
            0,
            label,
            transform=ax.transAxes,
            **props,
        ))
    # Force a draw to get accurate text measurements
    ax.figure.canvas.draw()

Review comment (suggestion):
This is actually a good case for a `match`:
```suggestion
    match layout:
        case "vertical":
            n_rows, n_cols = n_labels, 1
        case "horizontal":
            n_rows, n_cols = 1, n_labels
        case (int() as n_rows, int() as n_cols):
            if n_rows * n_cols < n_labels:
                raise ValueError(
                    f"layout {layout} has {n_rows * n_cols} positions but "
                    f"{n_labels} labels were provided"
                )
        case _:
            raise ValueError(
                "layout must be None, 'vertical', 'horizontal', or a (rows, cols) "
                f"tuple; got {layout!r}")
```

Code after:
        if toolmanager is not None:
            # If using toolmanager, lock keypresses, and plan to release the
            # lock when typing stops.
            toolmanager.keypresslock(self)
            stack.callback(toolmanager.keypresslock.release, self)
        else:
            # If not using toolmanager, disable all keypress-related rcParams.
            # Avoid spurious warnings if keymaps are getting deprecated.
            with _api.suppress_matplotlib_deprecation_warning():
                stack.enter_context(mpl.rc_context(
                    {k: [] for k in mpl.rcParams if k.startswith("keymap.")}))

    def stop_typing(self):
        if self.capturekeystrokes:
            self._on_stop_typing()
            self._on_stop_typing = None
            notifysubmit = True
        else:
            notifysubmit = False
        self.capturekeystrokes = False
        self.cursor.set_visible(False)
        self.ax.get_figure(root=True).canvas.draw()
        if notifysubmit and self.eventson:
            # Because process() might throw an error in the user's code, only
            # call it once we've already done our cleanup.
            self._observers.process('submit', self.text)

    @_call_with_reparented_event
    def _click(self, event):
        if self.ignore(event):
            return
        if not self.ax.contains(event)[0]:
            self.stop_typing()
            return
        if not self.eventson:
            return
        if event.canvas.mouse_grabber != self.ax:
            event.canvas.grab_mouse(self.ax)
        if not self.capturekeystrokes:
            self.begin_typing()
        self.cursor_index = self.text_disp._char_index_at(event.x)
        self._rendercursor()

    @_call_with_reparented_event
    def _resize(self, event):
        self.stop_typing()

    @_call_with_reparented_event
    def _motion(self, event):
        if self.ignore(event):
            return