Skip to content

Commit

Permalink
keep one view stack per task to allow async UI manipulation without m…
Browse files Browse the repository at this point in the history
…ixing up the containers
  • Loading branch information
falkoschindler committed Sep 23, 2022
1 parent e4af107 commit ee0fb9b
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 18 deletions.
6 changes: 2 additions & 4 deletions nicegui/elements/group.py
Expand Up @@ -12,13 +12,11 @@
class Group(Element):

def __enter__(self):
globals.view_stack.append(self.view)
globals.get_view_stack().append(self.view)
return self

def __exit__(self, *_):
globals.view_stack.pop()
if len(globals.view_stack) <= 1:
self.update() # NOTE: update when we are back on top of the stack (only the first page is in view stack)
globals.get_view_stack().pop()

def tight(self) -> Group:
return self.classes(replace='').style(replace='')
Expand Down
4 changes: 2 additions & 2 deletions nicegui/elements/scene.py
Expand Up @@ -108,14 +108,14 @@ def __init__(self, width: int = 400, height: int = 300, on_click: Optional[Calla
super().__init__(SceneView(width=width, height=height, on_click=on_click))

def __enter__(self):
globals.view_stack.append(self.view)
globals.get_view_stack().append(self.view)
scene = self.view.objects.get('scene', SceneObject(self.view, self.page))
Object3D.stack.clear()
Object3D.stack.append(scene)
return self

def __exit__(self, *_):
globals.view_stack.pop()
globals.get_view_stack().pop()

def move_camera(self,
x: Optional[float] = None,
Expand Down
24 changes: 21 additions & 3 deletions nicegui/globals.py
Expand Up @@ -18,7 +18,7 @@
server: Optional[Server] = None
loop: Optional[asyncio.AbstractEventLoop] = None
page_builders: Dict[str, 'PageBuilder'] = {}
view_stack: List[jp.HTMLBaseComponent] = []
view_stacks: Dict[List[jp.HTMLBaseComponent]] = {}
tasks: List[asyncio.tasks.Task] = []
log: logging.Logger = logging.getLogger('nicegui')
connect_handlers: List[Union[Callable, Awaitable]] = []
Expand All @@ -34,11 +34,29 @@ def find_route(function: Callable) -> str:
return routes[0]


def get_task_id() -> int:
return id(asyncio.current_task()) if loop and loop.is_running() else 0


def get_view_stack() -> List[jp.HTMLBaseComponent]:
task_id = get_task_id()
if task_id not in view_stacks:
view_stacks[task_id] = []
return view_stacks[task_id]


def prune_view_stack() -> None:
task_id = get_task_id()
if not view_stacks[task_id]:
del view_stacks[task_id]


@contextmanager
def within_view(view: jp.HTMLBaseComponent) -> Generator[None, None, None]:
child_count = len(view)
view_stack.append(view)
get_view_stack().append(view)
yield
view_stack.pop()
get_view_stack().pop()
prune_view_stack()
if len(view) != child_count:
create_task(view.update())
19 changes: 10 additions & 9 deletions nicegui/page.py
Expand Up @@ -168,9 +168,8 @@ async def decorated():
on_disconnect=on_disconnect,
shared=shared,
)
globals.view_stack.append(page.view)
await func() if is_coroutine(func) else func()
globals.view_stack.pop()
with globals.within_view(page.view):
await func() if is_coroutine(func) else func()
return page
builder = PageBuilder(decorated, shared)
if globals.server:
Expand All @@ -181,13 +180,14 @@ async def decorated():


def find_parent_view() -> jp.HTMLBaseComponent:
if not globals.view_stack:
view_stack = globals.get_view_stack()
if not view_stack:
if globals.loop and globals.loop.is_running():
raise RuntimeError('cannot find parent view, view stack is empty')
page = Page(shared=True)
globals.view_stack.append(page.view)
view_stack.append(page.view)
jp.Route('/', page._route_function)
return globals.view_stack[-1]
return view_stack[-1]


def error404() -> jp.QuasarPage:
Expand All @@ -204,14 +204,15 @@ def error404() -> jp.QuasarPage:


def init_auto_index_page() -> None:
if not globals.view_stack:
view_stack = globals.get_view_stack()
if not view_stack:
return # there is no auto-index page on the view stack
page: Page = globals.view_stack.pop().pages[0]
page: Page = view_stack.pop().pages[0]
page.title = globals.config.title
page.favicon = globals.config.favicon
page.dark = globals.config.dark
page.view.classes = globals.config.main_page_classes
assert len(globals.view_stack) == 0
assert len(view_stack) == 0


def create_page_routes() -> None:
Expand Down

0 comments on commit ee0fb9b

Please sign in to comment.