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

feat: support textual [WIP] #537

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pyside2 = [
pyside6 = ["pyside6"]
tqdm = ["tqdm>=4.30.0"]
jupyter = ["ipywidgets>=8.0.0"]
textual = ["textual"] # TODO: figure min version
image = ["pillow>=4.0"]
quantity = ["pint>=0.13.0"]
testing = [
Expand Down
4 changes: 2 additions & 2 deletions src/magicgui/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ def get_obj(self, name: str) -> Any:
f"Could not import object {name!r} from backend {self.backend_module}"
) from e

def run(self) -> None:
def run(self, **kwargs: Any) -> None:
"""Enter the native GUI event loop."""
return self._backend._mgui_run()
return self._backend._mgui_run(**kwargs)

@property
def native(self) -> Any:
Expand Down
1 change: 1 addition & 0 deletions src/magicgui/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
BACKENDS: dict[str, tuple[str, str]] = {
"Qt": ("_qtpy", "qtpy"),
"ipynb": ("_ipynb", "ipynb"),
"textual": ("_textual", "textual"),
}

for key in list(BACKENDS):
Expand Down
4 changes: 4 additions & 0 deletions src/magicgui/backends/_textual/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .application import ApplicationBackend
from .widgets import CheckBox, Label, LineEdit, PushButton

Check warning on line 2 in src/magicgui/backends/_textual/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/__init__.py#L1-L2

Added lines #L1 - L2 were not covered by tests

__all__ = ["ApplicationBackend", "Label", "LineEdit", "PushButton", "CheckBox"]

Check warning on line 4 in src/magicgui/backends/_textual/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/__init__.py#L4

Added line #L4 was not covered by tests
89 changes: 89 additions & 0 deletions src/magicgui/backends/_textual/application.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from __future__ import annotations

Check warning on line 1 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L1

Added line #L1 was not covered by tests

from typing import TYPE_CHECKING, Callable, ClassVar, Iterable

Check warning on line 3 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L3

Added line #L3 was not covered by tests

from textual.app import App
from textual.binding import Binding
from textual.timer import Timer
from textual.widgets import Footer

Check warning on line 8 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L5-L8

Added lines #L5 - L8 were not covered by tests

from magicgui.widgets.protocols import BaseApplicationBackend

Check warning on line 10 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L10

Added line #L10 was not covered by tests

if TYPE_CHECKING:
from textual.message import Message
from textual.widget import Widget


class MguiApp(App):
BINDINGS = [

Check warning on line 18 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L17-L18

Added lines #L17 - L18 were not covered by tests
("ctrl+t", "app.toggle_dark", "Toggle Dark mode"),
("ctrl+s", "app.screenshot()", "Screenshot"),
Binding("ctrl+c,ctrl+q", "app.quit", "Quit", show=True),
]

HEADER = None
FOOTER = Footer()

Check warning on line 25 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L24-L25

Added lines #L24 - L25 were not covered by tests

_mgui_widgets: ClassVar[list[Widget]] = []

Check warning on line 27 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L27

Added line #L27 was not covered by tests

def compose(self) -> Iterable[Widget]:
if self.HEADER is not None:
yield self.HEADER
yield from self._mgui_widgets
yield self.FOOTER

Check warning on line 33 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L29-L33

Added lines #L29 - L33 were not covered by tests


class ApplicationBackend(BaseApplicationBackend):
_app: ClassVar[MguiApp | None] = None

Check warning on line 37 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L36-L37

Added lines #L36 - L37 were not covered by tests

@classmethod
def _instance(cls) -> MguiApp:

Check warning on line 40 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L39-L40

Added lines #L39 - L40 were not covered by tests
"""Return the current instance of the application backend."""
if not hasattr(cls, "__instance"):
cls.__instance = MguiApp()
return cls.__instance

Check warning on line 44 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L42-L44

Added lines #L42 - L44 were not covered by tests

def _mgui_get_backend_name(self) -> str:
return "textual"

Check warning on line 47 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L46-L47

Added lines #L46 - L47 were not covered by tests

def _mgui_process_events(self) -> None: ...

def _mgui_run(self, **kwargs) -> None:
self._mgui_get_native_app().run(**kwargs)

Check warning on line 52 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L51-L52

Added lines #L51 - L52 were not covered by tests

def _mgui_quit(self) -> None:
return self._mgui_get_native_app().exit()

Check warning on line 55 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L54-L55

Added lines #L54 - L55 were not covered by tests

def _mgui_get_native_app(self) -> App:

Check warning on line 57 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L57

Added line #L57 was not covered by tests
# Get native app
return self._instance()

Check warning on line 59 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L59

Added line #L59 was not covered by tests

def _mgui_start_timer(

Check warning on line 61 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L61

Added line #L61 was not covered by tests
self,
interval: int = 0,
on_timeout: Callable[[], None] | None = None,
single: bool = False,
) -> None:
# TODO: not sure what to do with these yet...
event_target = MessageTarget()
sender = MessageTarget()
self._timer = Timer(

Check warning on line 70 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L68-L70

Added lines #L68 - L70 were not covered by tests
event_target=event_target,
interval=interval / 1000,
sender=sender,
callback=on_timeout,
repeat=1 if single else None,
)
self._timer.start()

Check warning on line 77 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L77

Added line #L77 was not covered by tests

def _mgui_stop_timer(self) -> None:
if getattr(self, "_timer", None):
self._timer.stop()

Check warning on line 81 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L79-L81

Added lines #L79 - L81 were not covered by tests


class MessageTarget:

Check warning on line 84 in src/magicgui/backends/_textual/application.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/application.py#L84

Added line #L84 was not covered by tests
async def post_message(self, message: Message) -> bool: ...

async def _post_priority_message(self, message: Message) -> bool: ...

def post_message_no_wait(self, message: Message) -> bool: ...
253 changes: 253 additions & 0 deletions src/magicgui/backends/_textual/widgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
from typing import TYPE_CHECKING, Any, Callable, cast

Check warning on line 1 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L1

Added line #L1 was not covered by tests

from textual import widgets as txtwdgs
from textual.widget import Widget as TxWidget

Check warning on line 4 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L3-L4

Added lines #L3 - L4 were not covered by tests

from magicgui.widgets import protocols

Check warning on line 6 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L6

Added line #L6 was not covered by tests

from .application import MguiApp

Check warning on line 8 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L8

Added line #L8 was not covered by tests

try:

Check warning on line 10 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L10

Added line #L10 was not covered by tests
# useful, but not yet public...
from psygnal._weak_callback import WeakCallback, weak_callback

Check warning on line 12 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L12

Added line #L12 was not covered by tests

except ImportError:
WeakCallback = Callable[[Any], Any]

def weak_callback(callback: Callable[[Any], Any]) -> WeakCallback:
return callback


if TYPE_CHECKING:
import numpy as np
from textual.dom import DOMNode


# Convert class events to instance events...
# FIXME: there must be a better pattern, also need weakrefs
class _Button(txtwdgs.Button):
_callbacks: list[WeakCallback] = []

Check warning on line 29 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L28-L29

Added lines #L28 - L29 were not covered by tests

def on_button_pressed(self):
for callback in self._callbacks:
callback(True)

Check warning on line 33 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L31-L33

Added lines #L31 - L33 were not covered by tests


class _Input(txtwdgs.Input):
_callbacks: list[WeakCallback] = []

Check warning on line 37 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L36-L37

Added lines #L36 - L37 were not covered by tests

def on_input_changed(self):
for callback in self._callbacks:
callback(self.value)

Check warning on line 41 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L39-L41

Added lines #L39 - L41 were not covered by tests


class _Switch(txtwdgs.Switch):
_callbacks: list[WeakCallback] = []

Check warning on line 45 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L44-L45

Added lines #L44 - L45 were not covered by tests

def on_switch_changed(self):
for callback in self._callbacks:
callback(self.value)

Check warning on line 49 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L47-L49

Added lines #L47 - L49 were not covered by tests


class TxtBaseWidget(protocols.WidgetProtocol):

Check warning on line 52 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L52

Added line #L52 was not covered by tests
"""Base Widget Protocol: specifies methods that all widgets must provide."""

_txwidget: TxWidget

Check warning on line 55 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L55

Added line #L55 was not covered by tests

def __init__(

Check warning on line 57 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L57

Added line #L57 was not covered by tests
self, wdg_class: type[TxWidget] | None = None, parent: TxWidget | None = None
):
if wdg_class is None:
wdg_class = type(self).__annotations__.get("_txwidget")
if wdg_class is None:
raise TypeError("Must provide a valid textual widget type")
self._txwidget = wdg_class()

Check warning on line 64 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L60-L64

Added lines #L60 - L64 were not covered by tests

# TODO: here we add the widget to our global app instance... but perhaps
# we should be using `mount()`?
MguiApp._mgui_widgets.append(self._txwidget)

Check warning on line 68 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L68

Added line #L68 was not covered by tests

# TODO: assign parent ?

def _mgui_close_widget(self) -> None:

Check warning on line 72 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L72

Added line #L72 was not covered by tests
"""Close widget."""
# not sure there is a textual equivalent of closing?
self._mgui_set_visible(False)

Check warning on line 75 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L75

Added line #L75 was not covered by tests

def _mgui_get_visible(self) -> bool:

Check warning on line 77 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L77

Added line #L77 was not covered by tests
"""Get widget visibility."""
return self._txwidget.visible

Check warning on line 79 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L79

Added line #L79 was not covered by tests

def _mgui_set_visible(self, value: bool) -> None:

Check warning on line 81 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L81

Added line #L81 was not covered by tests
"""Set widget visibility."""
self._txwidget.visible = value

Check warning on line 83 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L83

Added line #L83 was not covered by tests

def _mgui_get_enabled(self) -> bool:

Check warning on line 85 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L85

Added line #L85 was not covered by tests
"""Get the enabled state of the widget."""
return not self._txwidget.disabled

Check warning on line 87 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L87

Added line #L87 was not covered by tests

def _mgui_set_enabled(self, enabled: bool) -> None:

Check warning on line 89 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L89

Added line #L89 was not covered by tests
"""Set the enabled state of the widget to `enabled`."""
self._txwidget.disabled = not enabled

Check warning on line 91 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L91

Added line #L91 was not covered by tests

def _mgui_get_parent(self) -> "DOMNode | None":

Check warning on line 93 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L93

Added line #L93 was not covered by tests
"""Return the parent widget of this widget."""
return self._txwidget.parent

Check warning on line 95 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L95

Added line #L95 was not covered by tests

def _mgui_set_parent(self, widget: TxWidget) -> None:

Check warning on line 97 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L97

Added line #L97 was not covered by tests
"""Set the parent widget of this widget."""
raise NotImplementedError("Setting parent of textual widget not supported")

def _mgui_get_native_widget(self) -> Any:

Check warning on line 101 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L101

Added line #L101 was not covered by tests
"""Return the native backend widget instance.

This is generally the widget that has the layout.
"""
return self._txwidget

Check warning on line 106 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L106

Added line #L106 was not covered by tests

def _mgui_get_root_native_widget(self) -> Any:

Check warning on line 108 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L108

Added line #L108 was not covered by tests
"""Return the root native backend widget.

In most cases, this is the same as ``_mgui_get_native_widget``. However, in
cases where the native widget is in a scroll layout, this might be different.
"""
return self._txwidget

Check warning on line 114 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L114

Added line #L114 was not covered by tests

def _mgui_bind_parent_change_callback(

Check warning on line 116 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L116

Added line #L116 was not covered by tests
self, callback: Callable[[Any], None]
) -> None:
"""Bind callback to parent change event."""
pass

def _mgui_render(self) -> "np.ndarray":

Check warning on line 122 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L122

Added line #L122 was not covered by tests
"""Return an RGBA (MxNx4) numpy array bitmap of the rendered widget."""
raise NotImplementedError("Textual widget screenshots not yet implemented")

def _mgui_get_width(self) -> int:

Check warning on line 126 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L126

Added line #L126 was not covered by tests
"""Get the width of the widget.

The intention is to get the width of the widget after it is shown, for the
purpose of unifying widget width in a layout. Backends may do what they need to
accomplish this. For example, Qt can use ``sizeHint().width()``, since
``width()`` may return something large if the widget has not yet been painted
on screen.
"""
return self._txwidget.styles.width

Check warning on line 135 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L135

Added line #L135 was not covered by tests

def _mgui_set_width(self, value: int) -> None:

Check warning on line 137 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L137

Added line #L137 was not covered by tests
"""Set the width of the widget."""
self._txwidget.styles.width = value

Check warning on line 139 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L139

Added line #L139 was not covered by tests

def _mgui_get_min_width(self) -> int:

Check warning on line 141 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L141

Added line #L141 was not covered by tests
"""Get the minimum width of the widget."""
return self._txwidget.styles.min_width

Check warning on line 143 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L143

Added line #L143 was not covered by tests

def _mgui_set_min_width(self, value: int) -> None:

Check warning on line 145 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L145

Added line #L145 was not covered by tests
"""Set the minimum width of the widget."""
self._txwidget.styles.min_width = value

Check warning on line 147 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L147

Added line #L147 was not covered by tests

def _mgui_get_max_width(self) -> int:

Check warning on line 149 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L149

Added line #L149 was not covered by tests
"""Get the maximum width of the widget."""
return self._txwidget.styles.max_width

Check warning on line 151 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L151

Added line #L151 was not covered by tests

def _mgui_set_max_width(self, value: int) -> None:

Check warning on line 153 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L153

Added line #L153 was not covered by tests
"""Set the maximum width of the widget."""
self._txwidget.styles.max_width = value

Check warning on line 155 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L155

Added line #L155 was not covered by tests

def _mgui_get_height(self) -> int:

Check warning on line 157 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L157

Added line #L157 was not covered by tests
"""Get the height of the widget.

The intention is to get the height of the widget after it is shown, for the
purpose of unifying widget height in a layout. Backends may do what they need to
accomplish this. For example, Qt can use ``sizeHint().height()``, since
``height()`` may return something large if the widget has not yet been painted
on screen.
"""
return self._txwidget.styles.height

Check warning on line 166 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L166

Added line #L166 was not covered by tests

def _mgui_set_height(self, value: int) -> None:

Check warning on line 168 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L168

Added line #L168 was not covered by tests
"""Set the height of the widget."""
self._txwidget.styles.height = value

Check warning on line 170 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L170

Added line #L170 was not covered by tests

def _mgui_get_min_height(self) -> int:

Check warning on line 172 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L172

Added line #L172 was not covered by tests
"""Get the minimum height of the widget."""
return self._txwidget.styles.min_height

Check warning on line 174 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L174

Added line #L174 was not covered by tests

def _mgui_set_min_height(self, value: int) -> None:

Check warning on line 176 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L176

Added line #L176 was not covered by tests
"""Set the minimum height of the widget."""
self._txwidget.styles.min_height = value

Check warning on line 178 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L178

Added line #L178 was not covered by tests

def _mgui_get_max_height(self) -> int:

Check warning on line 180 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L180

Added line #L180 was not covered by tests
"""Get the maximum height of the widget."""
return self._txwidget.styles.max_height

Check warning on line 182 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L182

Added line #L182 was not covered by tests

def _mgui_set_max_height(self, value: int) -> None:

Check warning on line 184 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L184

Added line #L184 was not covered by tests
"""Set the maximum height of the widget."""
self._txwidget.styles.max_height = value

Check warning on line 186 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L186

Added line #L186 was not covered by tests

def _mgui_get_tooltip(self) -> str:

Check warning on line 188 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L188

Added line #L188 was not covered by tests
"""Get the tooltip for this widget."""
return ""

Check warning on line 190 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L190

Added line #L190 was not covered by tests

def _mgui_set_tooltip(self, value: str | None) -> None:

Check warning on line 192 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L192

Added line #L192 was not covered by tests
"""Set a tooltip for this widget."""
pass


class TxtValueWidget(TxtBaseWidget, protocols.ValueWidgetProtocol):
_txwidget: txtwdgs.Static

Check warning on line 198 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L197-L198

Added lines #L197 - L198 were not covered by tests

def _mgui_get_value(self) -> Any:

Check warning on line 200 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L200

Added line #L200 was not covered by tests
"""Get current value of the widget."""
return self._txwidget.renderable

Check warning on line 202 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L202

Added line #L202 was not covered by tests

def _mgui_set_value(self, value: Any) -> None:

Check warning on line 204 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L204

Added line #L204 was not covered by tests
"""Set current value of the widget."""
self._txwidget.renderable = value

Check warning on line 206 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L206

Added line #L206 was not covered by tests

def _mgui_bind_change_callback(self, callback: Callable[[Any], Any]) -> None:

Check warning on line 208 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L208

Added line #L208 was not covered by tests
"""Bind callback to value change event."""
if hasattr(self._txwidget, "_callbacks"):
callbacks = cast("list", self._txwidget._callbacks)
callbacks.append(weak_callback(callback))

Check warning on line 212 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L210-L212

Added lines #L210 - L212 were not covered by tests


class TxtStringWidget(TxtValueWidget):
def _mgui_set_value(self, value) -> None:
super()._mgui_set_value(str(value))

Check warning on line 217 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L215-L217

Added lines #L215 - L217 were not covered by tests


class Label(TxtStringWidget):
_txwidget: txtwdgs.Label

Check warning on line 221 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L220-L221

Added lines #L220 - L221 were not covered by tests


class LineEdit(TxtStringWidget):
_txwidget: _Input

Check warning on line 225 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L224-L225

Added lines #L224 - L225 were not covered by tests

def _mgui_get_value(self) -> Any:

Check warning on line 227 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L227

Added line #L227 was not covered by tests
"""Get current value of the widget."""
return self._txwidget.value

Check warning on line 229 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L229

Added line #L229 was not covered by tests

def _mgui_set_value(self, value: Any) -> None:

Check warning on line 231 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L231

Added line #L231 was not covered by tests
"""Set current value of the widget."""
self._txwidget.value = value

Check warning on line 233 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L233

Added line #L233 was not covered by tests


class TxtBaseButtonWidget(TxtValueWidget, protocols.SupportsText):
_txwidget: _Button

Check warning on line 237 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L236-L237

Added lines #L236 - L237 were not covered by tests

def _mgui_set_text(self, value: str) -> None:

Check warning on line 239 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L239

Added line #L239 was not covered by tests
"""Set text."""
self._txwidget.label = value

Check warning on line 241 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L241

Added line #L241 was not covered by tests

def _mgui_get_text(self) -> str:

Check warning on line 243 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L243

Added line #L243 was not covered by tests
"""Get text."""
return self._txwidget.label

Check warning on line 245 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L245

Added line #L245 was not covered by tests


class PushButton(TxtBaseButtonWidget):

Check warning on line 248 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L248

Added line #L248 was not covered by tests
pass


class CheckBox(TxtBaseButtonWidget):
_txwidget: _Switch

Check warning on line 253 in src/magicgui/backends/_textual/widgets.py

View check run for this annotation

Codecov / codecov/patch

src/magicgui/backends/_textual/widgets.py#L252-L253

Added lines #L252 - L253 were not covered by tests
2 changes: 1 addition & 1 deletion src/magicgui/widgets/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ def _mgui_start_timer(
Parameters
----------
interval : int, optional
Interval between timeouts, by default 0
Interval (in msec) between timeouts, by default 0
on_timeout : Optional[Callable[[], None]], optional
Function to call when timer finishes, by default None
single : bool, optional
Expand Down
Loading