Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
flet / controls / page_view.py
Size: Mime:
import logging
from dataclasses import dataclass, field
from typing import (
    Optional,
    Union,
)

from flet.controls.adaptive_control import AdaptiveControl
from flet.controls.animation import AnimationCurve
from flet.controls.base_control import BaseControl, control
from flet.controls.box import BoxDecoration
from flet.controls.control import Control
from flet.controls.control_event import (
    ControlEventHandler,
    Event,
    EventHandler,
)
from flet.controls.core.view import View
from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar
from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar
from flet.controls.dialog_control import DialogControl
from flet.controls.duration import DurationValue
from flet.controls.keys import ScrollKey
from flet.controls.material.app_bar import AppBar
from flet.controls.material.bottom_app_bar import BottomAppBar
from flet.controls.material.floating_action_button import FloatingActionButton
from flet.controls.material.navigation_bar import NavigationBar
from flet.controls.material.navigation_drawer import NavigationDrawer
from flet.controls.padding import Padding, PaddingValue
from flet.controls.scrollable_control import OnScrollEvent
from flet.controls.theme import Theme
from flet.controls.transform import OffsetValue
from flet.controls.types import (
    ColorValue,
    CrossAxisAlignment,
    FloatingActionButtonLocation,
    LocaleConfiguration,
    MainAxisAlignment,
    Number,
    ScrollMode,
    ThemeMode,
)
from flet.utils import deprecated

logger = logging.getLogger("flet")


@dataclass
class PageMediaData:
    padding: Padding
    view_padding: Padding
    view_insets: Padding


@dataclass
class PageResizeEvent(Event["PageView"]):
    width: float
    height: float


@control("PageView", isolated=True, kw_only=True)
class PageView(AdaptiveControl):
    """
    TBD
    """

    views: list[View] = field(default_factory=lambda: [View()])
    _overlay: "Overlay" = field(default_factory=lambda: Overlay())
    _dialogs: "Dialogs" = field(default_factory=lambda: Dialogs())

    theme_mode: Optional[ThemeMode] = ThemeMode.SYSTEM
    """
    The page's theme mode.

    Defaults to `ThemeMode.SYSTEM`.
    """
    theme: Optional[Theme] = None
    """
    Customizes the theme of the application when in light theme mode. Currently, a
    theme can only be automatically generated from a "seed" color. For example, to
    generate light theme from a green color.
    """
    dark_theme: Optional[Theme] = None
    """
    Customizes the theme of the application when in dark theme mode.
    """

    locale_configuration: Optional[LocaleConfiguration] = None

    show_semantics_debugger: Optional[bool] = None
    """
    `True` turns on an overlay that shows the accessibility information reported by the
    framework.
    """

    width: Optional[Number] = None

    height: Optional[Number] = None

    title: Optional[str] = None

    media: Optional[PageMediaData] = None

    scroll_event_interval: Optional[Number] = None

    on_resize: Optional[EventHandler["PageResizeEvent"]] = None
    """
    Called when a user resizes a browser or native OS window containing Flet app, for
    example:

    ```python
    def page_resize(e):
        print("New page size:", page.window.width, page.window_height)

    page.on_resize = page_resize
    ```
    """
    on_media_change: Optional[ControlEventHandler["PageView"]] = None
    """
    Called when `page.media` has changed.

    Event type: [`PageMediaData`][flet.PageMediaData]
    """

    on_scroll: Optional[EventHandler["OnScrollEvent"]] = None
    """
    Called when page's scroll position is changed by a user.
    """

    def __default_view(self) -> View:
        assert len(self.views) > 0, "views list is empty."
        return self.views[0]

    def update(self, *controls) -> None:
        if len(controls) == 0:
            self.page.update(self)
        else:
            self.page.update(*controls)

    def add(self, *controls: Control) -> None:
        """
        Adds controls to the page.

        ```python
        page.add(ft.Text("Hello!"), ft.FilledButton("Button"))
        ```
        """
        self.controls.extend(controls)
        self.update()

    def insert(self, at: int, *controls: Control) -> None:
        """
        Inserts controls at specific index of `page.controls` list.
        """
        n = at
        for c in controls:
            self.controls.insert(n, c)
            n += 1
        self.update()

    def remove(self, *controls: Control) -> None:
        """
        Removes specific controls from `page.controls` list.
        """
        for c in controls:
            self.controls.remove(c)
        self.update()

    def remove_at(self, index: int) -> None:
        """
        Remove controls from `page.controls` list at specific index.
        """
        self.controls.pop(index)
        self.update()

    def clean(self) -> None:
        self.controls.clear()
        self.update()

    def scroll_to(
        self,
        offset: Optional[Number] = None,
        delta: Optional[Number] = None,
        scroll_key: Union[ScrollKey, str, int, float, bool, None] = None,
        duration: Optional[DurationValue] = None,
        curve: Optional[AnimationCurve] = None,
    ) -> None:
        """
        Moves scroll position to either absolute `offset`, relative `delta` or jump to
        the control with specified `scroll_key`.

        See [`Column.scroll_to()`][flet.Column.scroll_to] for method details and examples.
        """
        self.__default_view().scroll_to(
            offset=offset,
            delta=delta,
            scroll_key=scroll_key,
            duration=duration,
            curve=curve,
        )

    @deprecated(
        reason="Use Page.show_dialog() instead",
        version="0.70.0",
        delete_version="0.73.0",
        show_parentheses=True,
    )
    def open(self, control: DialogControl) -> None:
        self.show_dialog(control)

    def show_dialog(self, dialog: DialogControl) -> None:
        """
        TBD
        """
        if dialog in self._dialogs.controls:
            raise Exception("Dialog is already opened")

        original_on_dismiss = dialog.on_dismiss

        def wrapped_on_dismiss(*args, **kwargs):
            if dialog in self._dialogs.controls:
                self._dialogs.controls.remove(dialog)
                self._dialogs.update()
            if (
                original_on_dismiss
                and not hasattr(dialog, "_force_close")
                and args[
                    0
                ].data  # e.data == False for TimePicker and DatePicker if they were
                # dismissed without changing the value
            ):
                original_on_dismiss(*args, **kwargs)
            dialog.on_dismiss = original_on_dismiss
            if hasattr(dialog, "_force_close"):
                del dialog._force_close

        dialog.open = True
        dialog.on_dismiss = wrapped_on_dismiss

        self._dialogs.controls.append(dialog)
        self._dialogs.update()

    @deprecated(
        reason="Use Page.pop_dialog() instead",
        version="0.70.0",
        delete_version="0.73.0",
        show_parentheses=True,
    )
    def close(self, control: DialogControl) -> None:
        self.pop_dialog()

    def pop_dialog(self) -> Optional[DialogControl]:
        # get the top most opened dialog
        dialog = next(
            (dlg for dlg in reversed(self._dialogs.controls) if dlg.open), None
        )
        if not dialog:
            return None
        dialog.open = False
        dialog._force_close = True
        dialog.update()
        return dialog

    # overlay
    @property
    def overlay(self) -> list[BaseControl]:
        return self._overlay.controls

    # controls
    @property
    def controls(self) -> list[BaseControl]:
        return self.__default_view().controls

    @controls.setter
    def controls(self, value: list[BaseControl]):
        self.__default_view().controls = value

    # appbar
    @property
    def appbar(self) -> Union[AppBar, CupertinoAppBar, None]:
        return self.__default_view().appbar

    @appbar.setter
    def appbar(self, value: Union[AppBar, CupertinoAppBar, None]):
        self.__default_view().appbar = value

    # bottom_appbar
    @property
    def bottom_appbar(self) -> Optional[BottomAppBar]:
        return self.__default_view().bottom_appbar

    @bottom_appbar.setter
    def bottom_appbar(self, value: Optional[BottomAppBar]):
        self.__default_view().bottom_appbar = value

    # navigation_bar
    @property
    def navigation_bar(self) -> Optional[Union[NavigationBar, CupertinoNavigationBar]]:
        return self.__default_view().navigation_bar

    @navigation_bar.setter
    def navigation_bar(
        self,
        value: Optional[Union[NavigationBar, CupertinoNavigationBar]],
    ):
        self.__default_view().navigation_bar = value

    # drawer
    @property
    def drawer(self) -> Optional[NavigationDrawer]:
        return self.__default_view().drawer

    @drawer.setter
    def drawer(self, value: Optional[NavigationDrawer]):
        self.__default_view().drawer = value

    # end_drawer
    @property
    def end_drawer(self) -> Optional[NavigationDrawer]:
        return self.__default_view().end_drawer

    @end_drawer.setter
    def end_drawer(self, value: Optional[NavigationDrawer]):
        self.__default_view().end_drawer = value

    # decoration
    @property
    def decoration(self) -> Optional[BoxDecoration]:
        return self.__default_view().decoration

    @decoration.setter
    def decoration(self, value: Optional[BoxDecoration]):
        self.__default_view().decoration = value

    # foreground_decoration
    @property
    def foreground_decoration(self) -> Optional[BoxDecoration]:
        return self.__default_view().foreground_decoration

    @foreground_decoration.setter
    def foreground_decoration(self, value: Optional[BoxDecoration]):
        self.__default_view().foreground_decoration = value

    # floating_action_button
    @property
    def floating_action_button(self) -> Optional[FloatingActionButton]:
        return self.__default_view().floating_action_button

    @floating_action_button.setter
    def floating_action_button(self, value: Optional[FloatingActionButton]):
        self.__default_view().floating_action_button = value

    # floating_action_button_location
    @property
    def floating_action_button_location(
        self,
    ) -> Optional[Union[FloatingActionButtonLocation, OffsetValue]]:
        return self.__default_view().floating_action_button_location

    @floating_action_button_location.setter
    def floating_action_button_location(
        self, value: Optional[Union[FloatingActionButtonLocation, OffsetValue]]
    ):
        self.__default_view().floating_action_button_location = value

    # horizontal_alignment
    @property
    def horizontal_alignment(self) -> Optional[CrossAxisAlignment]:
        return self.__default_view().horizontal_alignment

    @horizontal_alignment.setter
    def horizontal_alignment(self, value: Optional[CrossAxisAlignment]):
        self.__default_view().horizontal_alignment = value

    # vertical_alignment
    @property
    def vertical_alignment(self) -> Optional[MainAxisAlignment]:
        return self.__default_view().vertical_alignment

    @vertical_alignment.setter
    def vertical_alignment(self, value: Optional[MainAxisAlignment]):
        self.__default_view().vertical_alignment = value

    # spacing
    @property
    def spacing(self) -> Optional[Number]:
        return self.__default_view().spacing

    @spacing.setter
    def spacing(self, value: Optional[Number]):
        self.__default_view().spacing = value

    # padding
    @property
    def padding(self) -> Optional[PaddingValue]:
        return self.__default_view().padding

    @padding.setter
    def padding(self, value: Optional[PaddingValue]):
        self.__default_view().padding = value

    # bgcolor
    @property
    def bgcolor(self) -> Optional[ColorValue]:
        return self.__default_view().bgcolor

    @bgcolor.setter
    def bgcolor(self, value: Optional[ColorValue]):
        self.__default_view().bgcolor = value

    # scroll
    @property
    def scroll(self) -> Optional[ScrollMode]:
        return self.__default_view().scroll

    @scroll.setter
    def scroll(self, value: Optional[ScrollMode]):
        self.__default_view().scroll = value

    # auto_scroll
    @property
    def auto_scroll(self) -> bool:
        return self.__default_view().auto_scroll

    @auto_scroll.setter
    def auto_scroll(self, value: bool):
        self.__default_view().auto_scroll = value

    # Magic methods
    def __contains__(self, item: Control) -> bool:
        return item in self.controls


@control("Overlay")
class Overlay(BaseControl):
    controls: list[BaseControl] = field(default_factory=list)


@control("Dialogs")
class Dialogs(BaseControl):
    controls: list[DialogControl] = field(default_factory=list)