diff --git a/changes/2050.feature.rst b/changes/2050.feature.rst new file mode 100644 index 0000000000..e1632062c5 --- /dev/null +++ b/changes/2050.feature.rst @@ -0,0 +1 @@ +An implementation of ActivityIndicator was added to the Web backend. diff --git a/core/src/toga/style/pack.py b/core/src/toga/style/pack.py index 6208d1f604..0fd90facb2 100644 --- a/core/src/toga/style/pack.py +++ b/core/src/toga/style/pack.py @@ -767,7 +767,7 @@ def __css__(self): if (self.width == NONE and self.direction == ROW) or ( self.height == NONE and self.direction == COLUMN ): - css.append(f"flex: {self.flex} 0 0;") + css.append(f"flex: {self.flex} 0 auto;") # width/flex if self.width != NONE: diff --git a/core/tests/style/pack/test_css.py b/core/tests/style/pack/test_css.py index 6562754230..f204c79d1e 100644 --- a/core/tests/style/pack/test_css.py +++ b/core/tests/style/pack/test_css.py @@ -32,40 +32,40 @@ # Empty definition pytest.param( Pack(), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="empty", ), # Display pytest.param( Pack(display=PACK), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="display-pack", ), pytest.param( Pack(display=NONE), - "display: none; flex-direction: row; flex: 0.0 0 0;", + "display: none; flex-direction: row; flex: 0.0 0 auto;", id="display-none", ), # Visibility pytest.param( Pack(visibility=VISIBLE), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="visibility-visible", ), pytest.param( Pack(visibility=HIDDEN), - "visibility: hidden; flex-direction: row; flex: 0.0 0 0;", + "visibility: hidden; flex-direction: row; flex: 0.0 0 auto;", id="visibility-hidden", ), # Direction pytest.param( Pack(direction=ROW), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="direction-row", ), pytest.param( Pack(direction=COLUMN), - "flex-direction: column; flex: 0.0 0 0;", + "flex-direction: column; flex: 0.0 0 auto;", id="direction-column", ), # Width @@ -86,12 +86,12 @@ ), pytest.param( Pack(width=NONE), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="width-none", ), pytest.param( Pack(width=NONE, flex=5), - "flex-direction: row; flex: 5.0 0 0;", + "flex-direction: row; flex: 5.0 0 auto;", id="width-none-flex", ), pytest.param( @@ -111,88 +111,88 @@ ), pytest.param( Pack(direction=ROW, width=NONE), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="width-row-none", ), pytest.param( Pack(direction=ROW, width=NONE, flex=5), - "flex-direction: row; flex: 5.0 0 0;", + "flex-direction: row; flex: 5.0 0 auto;", id="width-row-none-flex", ), pytest.param( Pack(direction=COLUMN, width=42), - "flex-direction: column; flex: 0.0 0 0; width: 42px;", + "flex-direction: column; flex: 0.0 0 auto; width: 42px;", id="width-column-explicit", ), pytest.param( Pack(direction=COLUMN, width=42, flex=5), - "flex-direction: column; flex: 5.0 0 0; width: 42px;", + "flex-direction: column; flex: 5.0 0 auto; width: 42px;", id="width-column-explicit-flex", ), pytest.param( Pack(direction=COLUMN, width=0), - "flex-direction: column; flex: 0.0 0 0; width: 0px;", + "flex-direction: column; flex: 0.0 0 auto; width: 0px;", id="width-column-0", ), pytest.param( Pack(direction=COLUMN, width=NONE), - "flex-direction: column; flex: 0.0 0 0;", + "flex-direction: column; flex: 0.0 0 auto;", id="width-column-none", ), pytest.param( Pack(direction=COLUMN, width=NONE, flex=5), - "flex-direction: column; flex: 5.0 0 0;", + "flex-direction: column; flex: 5.0 0 auto;", id="width-column-none-flex", ), # Height pytest.param( Pack(height=42), - "flex-direction: row; flex: 0.0 0 0; height: 42px;", + "flex-direction: row; flex: 0.0 0 auto; height: 42px;", id="height-explicit", ), pytest.param( Pack(height=42, flex=5), - "flex-direction: row; flex: 5.0 0 0; height: 42px;", + "flex-direction: row; flex: 5.0 0 auto; height: 42px;", id="height-explicit-flex", ), pytest.param( Pack(height=0), - "flex-direction: row; flex: 0.0 0 0; height: 0px;", + "flex-direction: row; flex: 0.0 0 auto; height: 0px;", id="height-0", ), pytest.param( Pack(height=NONE), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="height-none", ), pytest.param( Pack(height=NONE, flex=5), - "flex-direction: row; flex: 5.0 0 0;", + "flex-direction: row; flex: 5.0 0 auto;", id="height-none-flex", ), pytest.param( Pack(direction=ROW, height=42), - "flex-direction: row; flex: 0.0 0 0; height: 42px;", + "flex-direction: row; flex: 0.0 0 auto; height: 42px;", id="height-row-explicit", ), pytest.param( Pack(direction=ROW, height=42, flex=5), - "flex-direction: row; flex: 5.0 0 0; height: 42px;", + "flex-direction: row; flex: 5.0 0 auto; height: 42px;", id="height-row-explicit", ), pytest.param( Pack(direction=ROW, height=0), - "flex-direction: row; flex: 0.0 0 0; height: 0px;", + "flex-direction: row; flex: 0.0 0 auto; height: 0px;", id="height-row-0", ), pytest.param( Pack(direction=ROW, height=NONE), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="height-row-none", ), pytest.param( Pack(direction=ROW, height=NONE, flex=5), - "flex-direction: row; flex: 5.0 0 0;", + "flex-direction: row; flex: 5.0 0 auto;", id="height-row-none", ), pytest.param( @@ -212,117 +212,117 @@ ), pytest.param( Pack(direction=COLUMN, height=NONE), - "flex-direction: column; flex: 0.0 0 0;", + "flex-direction: column; flex: 0.0 0 auto;", id="height-column-none", ), pytest.param( Pack(direction=COLUMN, height=NONE, flex=5), - "flex-direction: column; flex: 5.0 0 0;", + "flex-direction: column; flex: 5.0 0 auto;", id="height-column-none", ), # Alignment - default layout pytest.param( Pack(alignment=LEFT), - "flex-direction: row; flex: 0.0 0 0; align-items: start;", + "flex-direction: row; flex: 0.0 0 auto; align-items: start;", id="alignment-left", ), pytest.param( Pack(alignment=RIGHT), - "flex-direction: row; flex: 0.0 0 0; align-items: end;", + "flex-direction: row; flex: 0.0 0 auto; align-items: end;", id="alignment-right", ), pytest.param( # alignment is ignored Pack(alignment=TOP), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="alignment-top", ), pytest.param( # alignment is ignored Pack(alignment=BOTTOM), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="alignment-bottom", ), pytest.param( Pack(alignment=CENTER), - "flex-direction: row; flex: 0.0 0 0; align-items: center;", + "flex-direction: row; flex: 0.0 0 auto; align-items: center;", id="alignment-center", ), # Alignment - row layout pytest.param( Pack(direction=ROW, alignment=LEFT), - "flex-direction: row; flex: 0.0 0 0; align-items: start;", + "flex-direction: row; flex: 0.0 0 auto; align-items: start;", id="row-alignment-left", ), pytest.param( Pack(direction=ROW, alignment=RIGHT), - "flex-direction: row; flex: 0.0 0 0; align-items: end;", + "flex-direction: row; flex: 0.0 0 auto; align-items: end;", id="row-alignment-right", ), pytest.param( # alignment is ignored Pack(direction=ROW, alignment=TOP), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="row-alignment-top", ), pytest.param( # alignment is ignored Pack(direction=ROW, alignment=BOTTOM), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="row-alignment-bottom", ), pytest.param( Pack(direction=ROW, alignment=CENTER), - "flex-direction: row; flex: 0.0 0 0; align-items: center;", + "flex-direction: row; flex: 0.0 0 auto; align-items: center;", id="row-alignment-center", ), # Alignment - column layout pytest.param( # alignment is ignored Pack(direction=COLUMN, alignment=LEFT), - "flex-direction: column; flex: 0.0 0 0;", + "flex-direction: column; flex: 0.0 0 auto;", id="column-alignment-left", ), pytest.param( # alignment is ignored Pack(direction=COLUMN, alignment=RIGHT), - "flex-direction: column; flex: 0.0 0 0;", + "flex-direction: column; flex: 0.0 0 auto;", id="column-alignment-right", ), pytest.param( Pack(direction=COLUMN, alignment=TOP), - "flex-direction: column; flex: 0.0 0 0; align-items: start;", + "flex-direction: column; flex: 0.0 0 auto; align-items: start;", id="column-alignment-top", ), pytest.param( Pack(direction=COLUMN, alignment=BOTTOM), - "flex-direction: column; flex: 0.0 0 0; align-items: end;", + "flex-direction: column; flex: 0.0 0 auto; align-items: end;", id="column-alignment-bottom", ), pytest.param( Pack(direction=COLUMN, alignment=CENTER), - "flex-direction: column; flex: 0.0 0 0; align-items: center;", + "flex-direction: column; flex: 0.0 0 auto; align-items: center;", id="column-alignment-center", ), # Padding pytest.param( Pack(padding_top=42), - "flex-direction: row; flex: 0.0 0 0; margin-top: 42px;", + "flex-direction: row; flex: 0.0 0 auto; margin-top: 42px;", id="padding-top", ), pytest.param( Pack(padding_bottom=42), - "flex-direction: row; flex: 0.0 0 0; margin-bottom: 42px;", + "flex-direction: row; flex: 0.0 0 auto; margin-bottom: 42px;", id="padding-bottom", ), pytest.param( Pack(padding_left=42), - "flex-direction: row; flex: 0.0 0 0; margin-left: 42px;", + "flex-direction: row; flex: 0.0 0 auto; margin-left: 42px;", id="padding-left", ), pytest.param( Pack(padding_right=42), - "flex-direction: row; flex: 0.0 0 0; margin-right: 42px;", + "flex-direction: row; flex: 0.0 0 auto; margin-right: 42px;", id="padding-right", ), pytest.param( Pack(padding=42), ( - "flex-direction: row; flex: 0.0 0 0; " + "flex-direction: row; flex: 0.0 0 auto; " "margin-top: 42px; margin-bottom: 42px; " "margin-left: 42px; margin-right: 42px;" ), @@ -331,127 +331,127 @@ # Explicitly 0 padding pytest.param( Pack(padding_top=0), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="padding-top-0", ), pytest.param( Pack(padding_bottom=0), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="padding-bottom-0", ), pytest.param( Pack(padding_left=0), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="padding-left-0", ), pytest.param( Pack(padding_right=0), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="padding-right-0", ), pytest.param( Pack(padding=0), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="padding-0", ), # Color pytest.param( Pack(color=REBECCAPURPLE), - "flex-direction: row; flex: 0.0 0 0; color: rgb(102, 51, 153);", + "flex-direction: row; flex: 0.0 0 auto; color: rgb(102, 51, 153);", id="color", ), # Background Color pytest.param( Pack(background_color=REBECCAPURPLE), - "flex-direction: row; flex: 0.0 0 0; background-color: rgb(102, 51, 153);", + "flex-direction: row; flex: 0.0 0 auto; background-color: rgb(102, 51, 153);", id="background-color", ), # Text Alignment pytest.param( Pack(text_align=LEFT), - "flex-direction: row; flex: 0.0 0 0; text-align: left;", + "flex-direction: row; flex: 0.0 0 auto; text-align: left;", id="text-align-left", ), pytest.param( Pack(text_align=RIGHT), - "flex-direction: row; flex: 0.0 0 0; text-align: right;", + "flex-direction: row; flex: 0.0 0 auto; text-align: right;", id="text-align-right", ), pytest.param( Pack(text_align=CENTER), - "flex-direction: row; flex: 0.0 0 0; text-align: center;", + "flex-direction: row; flex: 0.0 0 auto; text-align: center;", id="text-align-center", ), pytest.param( Pack(text_align=JUSTIFY), - "flex-direction: row; flex: 0.0 0 0; text-align: justify;", + "flex-direction: row; flex: 0.0 0 auto; text-align: justify;", id="text-align-justify", ), # Text Direction pytest.param( Pack(text_direction=RTL), - "flex-direction: row; flex: 0.0 0 0; text-direction: rtl;", + "flex-direction: row; flex: 0.0 0 auto; text-direction: rtl;", id="text-align-rtl", ), pytest.param( Pack(text_direction=LTR), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="text-align-ltr", ), # Font pytest.param( Pack(font_family="Helvetica"), - "flex-direction: row; flex: 0.0 0 0; font-family: Helvetica;", + "flex-direction: row; flex: 0.0 0 auto; font-family: Helvetica;", id="font-family", ), pytest.param( Pack(font_family="Times New Roman"), - 'flex-direction: row; flex: 0.0 0 0; font-family: "Times New Roman";', + 'flex-direction: row; flex: 0.0 0 auto; font-family: "Times New Roman";', id="font-family", ), pytest.param( Pack(font_family=SYSTEM), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="font-family-explicit-default", ), pytest.param( Pack(font_style=ITALIC), - "flex-direction: row; flex: 0.0 0 0; font-style: italic;", + "flex-direction: row; flex: 0.0 0 auto; font-style: italic;", id="font-style", ), pytest.param( Pack(font_style=NORMAL), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="font-style-explicit-default", ), pytest.param( Pack(font_weight=BOLD), - "flex-direction: row; flex: 0.0 0 0; font-weight: bold;", + "flex-direction: row; flex: 0.0 0 auto; font-weight: bold;", id="font-weight", ), pytest.param( Pack(font_weight=NORMAL), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="font-weight-explicit-default", ), pytest.param( Pack(font_variant=SMALL_CAPS), - "flex-direction: row; flex: 0.0 0 0; font-variant: small-caps;", + "flex-direction: row; flex: 0.0 0 auto; font-variant: small-caps;", id="font-variant", ), pytest.param( Pack(font_variant=NORMAL), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="font-variant-explicit-default", ), pytest.param( Pack(font_size=42), - "flex-direction: row; flex: 0.0 0 0; font-size: 42pt;", + "flex-direction: row; flex: 0.0 0 auto; font-size: 42pt;", id="font-size", ), pytest.param( Pack(font_size=SYSTEM_DEFAULT_FONT_SIZE), - "flex-direction: row; flex: 0.0 0 0;", + "flex-direction: row; flex: 0.0 0 auto;", id="font-size-explicit-default", ), pytest.param( @@ -463,7 +463,7 @@ font_size=42, ), ( - "flex-direction: row; flex: 0.0 0 0; " + "flex-direction: row; flex: 0.0 0 auto; " "font-family: Helvetica; " "font-size: 42pt; " "font-weight: bold; " diff --git a/docs/reference/data/widgets_by_platform.csv b/docs/reference/data/widgets_by_platform.csv index c0e8abb91e..933348c101 100644 --- a/docs/reference/data/widgets_by_platform.csv +++ b/docs/reference/data/widgets_by_platform.csv @@ -2,7 +2,7 @@ Component,Type,Component,Description,macOS,GTK,Windows,iOS,Android,Web Application,Core Component,:class:`~toga.App`,The application itself,|b|,|b|,|b|,|b|,|b|,|b| Window,Core Component,:class:`~toga.Window`,Window object,|b|,|b|,|b|,|b|,|b|,|b| MainWindow,Core Component,:class:`~toga.MainWindow`,Main window of the application,|b|,|b|,|b|,|b|,|b|,|b| -ActivityIndicator,General Widget,:class:`~toga.ActivityIndicator`,A spinning activity animation,|y|,|y|,,,, +ActivityIndicator,General Widget,:class:`~toga.ActivityIndicator`,A spinning activity animation,|y|,|y|,,,,|b| Button,General Widget,:class:`~toga.Button`,Basic clickable Button,|y|,|y|,|y|,|y|,|y|,|b| Canvas,General Widget,:class:`~toga.Canvas`,Area you can draw on,|b|,|b|,|b|,|b|,, DateInput,General Widget,:class:`~toga.DateInput`,A widget to select a calendar date,,,|y|,,|y|, diff --git a/docs/reference/style/pack.rst b/docs/reference/style/pack.rst index 57209ee5d3..3dd07c0c56 100644 --- a/docs/reference/style/pack.rst +++ b/docs/reference/style/pack.rst @@ -314,7 +314,7 @@ The mapping that can be used to establish the reference implementation is: ``display: pack`` ``display: flex`` ``flex: `` If ``direction = row`` and ``width`` is set, or ``direction = column`` and ``height`` is set, - ignore. Otherwise, ``flex: 0 0``. + ignore. Otherwise, ``flex: 0 auto``. ``font_size: `` ``font-size: pt`` ``height: `` ``height: px`` if value is an integer; ``height: auto`` if value is ``none``. diff --git a/web/src/toga_web/factory.py b/web/src/toga_web/factory.py index be253f674f..8ca7af7735 100644 --- a/web/src/toga_web/factory.py +++ b/web/src/toga_web/factory.py @@ -8,6 +8,7 @@ # from .images import Image from .paths import Paths +from .widgets.activityindicator import ActivityIndicator from .widgets.box import Box from .widgets.button import Button @@ -64,6 +65,7 @@ def not_implemented(feature): # 'OptionContainer', # 'PasswordInput', "ProgressBar", + "ActivityIndicator", # 'ScrollContainer', # 'Selection', # 'Slider', diff --git a/web/src/toga_web/widgets/activityindicator.py b/web/src/toga_web/widgets/activityindicator.py new file mode 100644 index 0000000000..9366342146 --- /dev/null +++ b/web/src/toga_web/widgets/activityindicator.py @@ -0,0 +1,19 @@ +from .base import Widget + + +class ActivityIndicator(Widget): + def create(self): + self.native = self._create_native_widget("sl-spinner") + self.stop() + + # Actions + def start(self): + self.native.style.visibility = "visible" + self._is_running = True + + def stop(self): + self.native.style.visibility = "hidden" + self._is_running = False + + def is_running(self): + return self._is_running