You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When setting z=X on a layout that is nested, the behavior is surprising. Controlling the eventual rendered z of a nested layout ranges from difficult to impossible (i.e. with a scrollview)
Examples of unexpected behavior:
fromrich.textimportTextfromtextualimporteventsfromtextual.appimportAppfromtextual.viewsimportDockViewfromtextual.widgetimportWidgetfromtextual.widgetsimportPlaceholderfromtextual.widgetsimportScrollViewclassLongText(Widget):
def__init__(self):
super().__init__(name='long_text')
self.border='round'self.layout_offset_y=20defrender(self):
text=Text.assemble(*(f'{i}\n'foriinrange(40)))
returntextclassZ_DockADockView(App):
"""Docking a DockView with z=1 behaves surprisingly - renders behind main layout"""shown=Falseasyncdefaction_toggle_scroll(self) ->None:
offset=self.shownand-20or0self.shown=notself.shownself.long_text.animate('layout_offset_y', offset)
asyncdefon_load(self, event: events.Load) ->None:
"""Bind keys with the app loads (but before entering application mode)"""self.shown=Falseawaitself.bind('b', 'toggle_scroll', 'Toggle scroll')
awaitself.bind('q', 'quit', 'Quit')
asyncdefon_mount(self, event: events.Mount) ->None:
"""Create and dock the widgets."""self.long_text=LongText()
self.subview=DockView()
awaitself.subview.dock(self.long_text, edge='top')
""" Above would would work as expected if z=1 set there However, less surprising would be if the z=1 on the following line affected it """awaitself.view.dock(self.subview, edge='top', size=10, z=1)
awaitself.view.dock(Placeholder(), edge='top', size=8, name='main')
classZ_DockADockViewAlt(App):
"""Docking a DockView with a z=1 widget docked, behaves surprisingly - z as expected but outer layout takes up spaces asif z=0"""shown=Falseasyncdefaction_toggle_scroll(self) ->None:
offset=self.shownand-20or0self.shown=notself.shownself.long_text.animate('layout_offset_y', offset)
asyncdefon_load(self, event: events.Load) ->None:
"""Bind keys with the app loads (but before entering application mode)"""self.shown=Falseawaitself.bind('b', 'toggle_scroll', 'Toggle scroll')
awaitself.bind('q', 'quit', 'Quit')
asyncdefon_mount(self, event: events.Mount) ->None:
"""Create and dock the widgets."""self.long_text=LongText()
self.subview=DockView()
awaitself.subview.dock(self.long_text, edge='top', z=1)
awaitself.view.dock(self.subview, edge='top', size=10)
awaitself.view.dock(Placeholder(), edge='top', size=8, name='main')
classZ_ScrollView(App):
"""Setting Z when docking a ScrollView gets unmanagable - renders behind main placeholder, an no way currently to pass z-index into scrollview"""asyncdefaction_toggle_scroll(self) ->None:
""" Toggle the long_text offset - show or hide"""offset=self.shownand20or0self.shown=notself.shown# self.scroll.animate('layout_offset_y', offset) # I'm also inclined to think this should work... however, the folling is required insteadself.long_text.animate('layout_offset_y', offset)
asyncdefon_load(self, event: events.Load) ->None:
"""Bind keys with the app loads (but before entering application mode)"""self.shown=Falseawaitself.bind('b', 'toggle_scroll', 'Toggle scroll')
awaitself.bind('q', 'quit', 'Quit')
asyncdefon_mount(self, event: events.Mount) ->None:
"""Create and dock the widgets. Note that the scrollview, confusingly, show's _behind_ the main placeholder, not in front of it """self.subview=DockView()
awaitself.subview.dock(Placeholder(), edge='top', name='main')
self.long_text=LongText()
self.scroll=ScrollView(self.long_text)
awaitself.subview.dock(self.scroll, edge='bottom', size=10, z=1)
awaitself.view.dock(self.subview, edge='top')
Z_DockADockView.run(title='Z_DockADockView example')
Z_DockADockViewAlt.run(title='Z_DockADockView Alt example')
Z_ScrollView.run(title='Z_ScrollView example')
I propose as a solution:
Adding a z_index contextvar to _context which initializes to 0.
Adding a z_index_context (name?) contextmanager to layout.py which sets the contextvar and returns it to previous value on exit
Letting all places where z=X can be passed (this seems to mainly be the domain of Layouts) - default to None instead of 0
When z=None, use value of the z_index contextvar
I wouldn't call this solution perfect - I think some thinking needs to go into z-index of a layout being maybe relative to the layout it's nested inside of? But I think this does provide a simple/intuitive interface that allows setting z-index in most/all situations with the current setup.
With the proposed solution:
fromrich.textimportTextfromtextualimporteventsfromtextual.appimportAppfromtextual.viewsimportDockViewfromtextual.layoutimportz_index_contextfromtextual.widgetimportWidgetfromtextual.widgetsimportPlaceholderfromtextual.widgetsimportScrollViewclassLongText(Widget):
def__init__(self):
super().__init__(name='long_text')
self.border='round'self.layout_offset_y=20defrender(self):
text=Text.assemble(*(f'{i}\n'foriinrange(40)))
returntextclassProposed_Z_ScrollView(App):
"""Setting Z context when docking a ScrollView works as expected"""asyncdefaction_toggle_scroll(self) ->None:
""" Toggle the long_text offset - show or hide"""offset=self.shownand20or0self.shown=notself.shown# self.scroll.animate('layout_offset_y', offset) # I'm also inclined to think this should work... however, the folling is required insteadself.long_text.animate('layout_offset_y', offset)
self.scroll.animate('layout_offset_y', offset)
self.subview.animate('layout_offset_y', offset)
asyncdefon_load(self, event: events.Load) ->None:
"""Bind keys with the app loads (but before entering application mode)"""self.shown=Falseawaitself.bind('b', 'toggle_scroll', 'Toggle scroll')
awaitself.bind('q', 'quit', 'Quit')
asyncdefon_mount(self, event: events.Mount) ->None:
"""Create and dock the widgets. Note that the scrollview, confusingly, show's _behind_ the main placeholder, not in front of it """self.subview=DockView()
awaitself.subview.dock(Placeholder(), edge='top', name='main')
withz_index_context(1):
self.long_text=LongText()
self.scroll=ScrollView(self.long_text)
awaitself.subview.dock(self.scroll, edge='bottom', size=10)
# await self.view.dock(self.subview, edge='bottom', size=5)awaitself.view.dock(self.subview, edge='top')
classProposed_Z_DockADockView(App):
"""Docking a DockView also fails to respect the z set on the top-level docking"""shown=Falseasyncdefaction_toggle_scroll(self) ->None:
offset=self.shownand-20or0self.shown=notself.shownself.long_text.animate('layout_offset_y', offset)
asyncdefon_load(self, event: events.Load) ->None:
"""Bind keys with the app loads (but before entering application mode)"""self.shown=Falseawaitself.bind('b', 'toggle_scroll', 'Toggle scroll')
awaitself.bind('q', 'quit', 'Quit')
asyncdefon_mount(self, event: events.Mount) ->None:
"""Create and dock the widgets."""self.long_text=LongText()
self.subview=DockView()
withz_index_context(1):
awaitself.subview.dock(self.long_text, edge='top')
awaitself.view.dock(self.subview, edge='top', size=10)
awaitself.view.dock(Placeholder(), edge='top', size=8, name='main')
Proposed_Z_ScrollView.run(title='Z_ScrollView example')
Proposed_Z_DockADockView.run(title='Z_DockADockView example')
I've got a working implementation - if you like the proposed solution I'm happy to show or open a PR
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
When setting z=X on a layout that is nested, the behavior is surprising. Controlling the eventual rendered z of a nested layout ranges from difficult to impossible (i.e. with a scrollview)
Examples of unexpected behavior:
I propose as a solution:
I wouldn't call this solution perfect - I think some thinking needs to go into z-index of a layout being maybe relative to the layout it's nested inside of? But I think this does provide a simple/intuitive interface that allows setting z-index in most/all situations with the current setup.
With the proposed solution:
I've got a working implementation - if you like the proposed solution I'm happy to show or open a PR
Beta Was this translation helpful? Give feedback.
All reactions