import gradio as gr from gradio.components import FormComponent class ButtonGroup: """Base class for button groups with common functionality.""" def __init__(self, events: list[str], *args, **kwargs): self.buttons = {event: None for event in events} self.click_args = {event: None for event in events} self.render() def render(self): """Render the buttons and set up their event handlers.""" for event, button in self.buttons.items(): if self.click_args[event]: button.click(*self.click_args[event]) def _setup_button(self, event, fn, inputs, outputs): """Set up a button's click event handler.""" self.click_args[event] = fn, inputs, outputs if self.buttons[event]: self.buttons[event].click(fn, inputs, outputs) def api_info(self): return { "name": self.__class__.__name__, "events": self.EVENTS, "inputs": [], "outputs": [], } def example_payload(self): """Return None since this component doesn't have direct input values.""" return None def example_value(self): """Return None since this component doesn't have direct output values.""" return None class InputRowButtonGroup(ButtonGroup): """Button group for input rows with delete and add buttons.""" EVENTS = ["delete", "add"] def __init__(self, *args, **kwargs): self.disable_delete = kwargs.pop("disable_delete", False) super().__init__(self.EVENTS, *args, **kwargs) def render(self): with gr.Column(scale=0, min_width=40, elem_classes="button-column"): self.buttons["delete"] = gr.Button( "❌", elem_classes="icon-button delete-button", scale=0, interactive=not self.disable_delete ) self.buttons["add"] = gr.Button("➕", elem_classes="icon-button add-field-button", scale=0) super().render() def delete(self, fn, inputs, outputs): self._setup_button("delete", fn, inputs, outputs) def add(self, fn, inputs, outputs): self._setup_button("add", fn, inputs, outputs) class OutputRowButtonGroup(ButtonGroup): """Button group for output rows with delete, add, up, and down buttons.""" EVENTS = ["delete", "add", "up", "down"] def __init__(self, *args, **kwargs): self.disable_delete = kwargs.pop("disable_delete", False) super().__init__(self.EVENTS, *args, **kwargs) def render(self): with gr.Column(scale=0, elem_classes="button-column", min_width=40): self.buttons["delete"] = gr.Button( "❌", elem_classes="icon-button delete-button", scale=0, interactive=not self.disable_delete ) self.buttons["add"] = gr.Button("➕", elem_classes="icon-button add-field-button", scale=0) with gr.Column(scale=0, elem_classes="button-column", min_width=40): self.buttons["up"] = gr.Button("⬆️", elem_classes="icon-button up-button", scale=0) self.buttons["down"] = gr.Button("⬇️", elem_classes="icon-button down-button", scale=0) return super().render() def delete(self, fn, inputs, outputs): self._setup_button("delete", fn, inputs, outputs) def add(self, fn, inputs, outputs): self._setup_button("add", fn, inputs, outputs) def up(self, fn, inputs, outputs): self._setup_button("up", fn, inputs, outputs) def down(self, fn, inputs, outputs): self._setup_button("down", fn, inputs, outputs)