Use a GtkStack for the LutrisWindow views

So, now the scroll bars are updates when you switch.

But still allocate each view when first used. There's still some waste here if you switch back and forth between grid and list views, but it should not be too bad.

Resolves #3881
This commit is contained in:
Daniel Johnson 2023-01-02 09:39:36 -05:00
parent ee3133f1e9
commit 13df9d1367
5 changed files with 81 additions and 55 deletions

View file

@ -49,7 +49,7 @@ class LutrisWindow(Gtk.ApplicationWindow,
"view-updated": (GObject.SIGNAL_RUN_FIRST, None, ()),
}
games_scrollwindow = GtkTemplate.Child()
games_stack = GtkTemplate.Child()
sidebar_revealer = GtkTemplate.Child()
sidebar_scrolled = GtkTemplate.Child()
game_revealer = GtkTemplate.Child()
@ -86,7 +86,8 @@ class LutrisWindow(Gtk.ApplicationWindow,
self.set_service(self.filters.get("service"))
self.icon_type = self.load_icon_type()
self.game_store = GameStore(self.service, self.service_media)
self.view = Gtk.Box()
self.current_view = Gtk.Box()
self.views = {}
self.connect("delete-event", self.on_window_delete)
self.connect("configure-event", self.on_window_configure)
@ -97,7 +98,7 @@ class LutrisWindow(Gtk.ApplicationWindow,
self.init_template()
self._init_actions()
self.set_viewtype_icon(self.view_type)
self.set_viewtype_icon(self.current_view_type)
lutris_icon = Gtk.Image.new_from_icon_name("lutris", Gtk.IconSize.MENU)
lutris_icon.set_margin_right(3)
@ -195,12 +196,12 @@ class LutrisWindow(Gtk.ApplicationWindow,
def on_load(self, widget, data=None):
"""Finish initializing the view"""
self._bind_zoom_adjustment()
self.view.grab_focus()
self.view.contextual_menu = ContextualMenu(self.game_actions.get_game_actions())
self.current_view.grab_focus()
self.current_view.contextual_menu = ContextualMenu(self.game_actions.get_game_actions())
def on_sidebar_realize(self, widget, data=None):
"""Grab the initial focus after the sidebar is initialized - so the view is ready."""
self.view.grab_focus()
self.current_view.grab_focus()
def load_filters(self):
"""Load the initial filters when creating the view"""
@ -448,7 +449,8 @@ class LutrisWindow(Gtk.ApplicationWindow,
self.hide_overlay()
games = self.get_games_from_filters()
logger.debug("Showing %d games", len(games))
self.view.service = self.service.id if self.service else None
for view in self.views.values():
view.service = self.service.id if self.service else None
GLib.idle_add(self.update_revealer)
for game in games:
self.game_store.add_game(game)
@ -541,7 +543,7 @@ class LutrisWindow(Gtk.ApplicationWindow,
# which keys actually start searching
if event.keyval == Gdk.KEY_Escape:
self.search_entry.set_text("")
self.view.grab_focus()
self.current_view.grab_focus()
return Gtk.ApplicationWindow.do_key_press_event(self, event)
if ( # pylint: disable=too-many-boolean-expressions
@ -575,25 +577,33 @@ class LutrisWindow(Gtk.ApplicationWindow,
if not self.game_store:
logger.error("No game store yet")
return
if self.view:
self.view.destroy()
self.game_store = GameStore(self.service, self.service_media)
if self.view_type == "grid":
self.view = GameGridView(
self.game_store,
self.game_store.service_media,
hide_text=settings.read_setting("hide_text_under_icons") == "True"
)
else:
self.view = GameListView(self.game_store, self.game_store.service_media)
self.view.connect("game-selected", self.on_game_selection_changed)
self.view.connect("game-activated", self.on_game_activated)
self.view.contextual_menu = ContextualMenu(self.game_actions.get_game_actions())
for child in self.games_scrollwindow.get_children():
child.destroy()
self.games_scrollwindow.add(self.view)
self.view.show_all()
view_type = self.current_view_type
if view_type in self.views:
self.current_view = self.views[view_type]
self.current_view.set_game_store(self.game_store)
else:
if view_type == "grid":
self.current_view = GameGridView(
self.game_store,
hide_text=settings.read_setting("hide_text_under_icons") == "True"
)
else:
self.current_view = GameListView(self.game_store)
self.current_view.connect("game-selected", self.on_game_selection_changed)
self.current_view.connect("game-activated", self.on_game_activated)
self.current_view.contextual_menu = ContextualMenu(self.game_actions.get_game_actions())
scrolledwindow = Gtk.ScrolledWindow()
scrolledwindow.add(self.current_view)
scrolledwindow.show_all()
self.games_stack.add_named(scrolledwindow, view_type)
self.views[view_type] = self.current_view
self.games_stack.set_visible_child_name(view_type)
self.update_store()
def set_viewtype_icon(self, view_type):
@ -701,14 +711,14 @@ class LutrisWindow(Gtk.ApplicationWindow,
def on_search_entry_key_press(self, widget, event):
if event.keyval == Gdk.KEY_Down:
if self.current_view_type == 'grid':
self.view.select_path(Gtk.TreePath('0')) # needed for gridview only
self.current_view.select_path(Gtk.TreePath('0')) # needed for gridview only
# if game_bar is alive at this point it can mess grid item selection up
# for some unknown reason,
# it is safe to close it here, it will be reopened automatically.
if self.game_bar:
self.game_bar.destroy() # for gridview only
self.view.set_cursor(Gtk.TreePath('0'), None, False) # needed for both view types
self.view.grab_focus()
self.current_view.set_cursor(Gtk.TreePath('0'), None, False) # needed for both view types
self.current_view.grab_focus()
@GtkTemplate.Callback
def on_about_clicked(self, *_args):

View file

@ -13,29 +13,37 @@ class GameGridView(Gtk.IconView, GameView):
min_width = 70 # Minimum width for a cell
def __init__(self, store, service_media, hide_text=False):
self.game_store = store
self.service_media = service_media
self.model = self.game_store.store
super().__init__(model=self.game_store.store)
def __init__(self, store, hide_text=False):
super().__init__()
GameView.__init__(self)
self.service = None
self.set_column_spacing(6)
self.set_pixbuf_column(COL_ICON)
self.set_item_padding(1)
self.cell_width = max(service_media.size[0], self.min_width)
if hide_text:
self.cell_renderer = None
else:
self.cell_renderer = GridViewCellRendererText(self.cell_width)
self.cell_renderer = GridViewCellRendererText()
self.pack_end(self.cell_renderer, False)
self.add_attribute(self.cell_renderer, "markup", COL_NAME)
self.set_game_store(store)
self.connect_signals()
self.connect("item-activated", self.on_item_activated)
self.connect("selection-changed", self.on_selection_changed)
def set_game_store(self, game_store):
self.game_store = game_store
self.service_media = game_store.service_media
self.model = game_store.store
self.set_model(self.model)
if self.cell_renderer:
cell_width = max(game_store.service_media.size[0], self.min_width)
self.cell_renderer.set_width(cell_width)
def select(self):
self.select_path(self.current_path)

View file

@ -21,21 +21,24 @@ class GameListView(Gtk.TreeView, GameView):
__gsignals__ = GameView.__gsignals__
def __init__(self, store, service_media):
self.game_store = store
self.service_media = service_media
self.model = self.game_store.store
super().__init__(model=self.model)
def __init__(self, store):
super().__init__()
GameView.__init__(self)
self.set_rules_hint(True)
# Icon column
if settings.SHOW_MEDIA:
image_cell = Gtk.CellRendererPixbuf()
column = Gtk.TreeViewColumn("", image_cell, pixbuf=COL_ICON)
column.set_reorderable(True)
column.set_sort_indicator(False)
self.append_column(column)
self.media_column = Gtk.TreeViewColumn("", image_cell, pixbuf=COL_ICON)
self.media_column.set_reorderable(True)
self.media_column.set_sort_indicator(False)
self.media_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
self.append_column(self.media_column)
else:
self.media_column = None
self.set_game_store(store)
# Text columns
default_text_cell = self.set_text_cell()
@ -59,6 +62,16 @@ class GameListView(Gtk.TreeView, GameView):
self.connect("row-activated", self.on_row_activated)
self.get_selection().connect("changed", self.on_cursor_changed)
def set_game_store(self, game_store):
self.game_store = game_store
self.service_media = game_store.service_media
self.model = game_store.store
self.set_model(self.model)
if self.media_column:
media_width = game_store.service_media.size[0]
self.media_column.set_fixed_width(media_width)
@staticmethod
def set_text_cell():
text_cell = Gtk.CellRendererText()

View file

@ -4,10 +4,12 @@ from gi.repository import Gtk, Pango
class GridViewCellRendererText(Gtk.CellRendererText):
"""CellRendererText adjusted for grid view display, removes extra padding"""
def __init__(self, width, *args, **kwargs):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.props.alignment = Pango.Alignment.CENTER
self.props.wrap_mode = Pango.WrapMode.WORD
self.props.xalign = 0.5
self.props.yalign = 0
def set_width(self, width):
self.props.wrap_width = width

View file

@ -76,18 +76,11 @@
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkScrolledWindow" id="games_scrollwindow">
<object class="GtkStack" id="games_stack">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="vexpand">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkViewport" id="games_viewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<placeholder/>
</child>
</object>
<placeholder/>
</child>
</object>
<packing>