11import math
22import time
3+ from collections .abc import Iterable
34from pathlib import Path
45from typing import TYPE_CHECKING , Any , override
56
6- from PySide6 .QtCore import QPoint , QRect , QSize
7+ from PySide6 .QtCore import QPoint , QRect , QSize , Signal
78from PySide6 .QtGui import QPixmap
89from PySide6 .QtWidgets import QLayout , QLayoutItem , QScrollArea
910
1920
2021
2122class ThumbGridLayout (QLayout ):
23+ # Id of first visible entry
24+ visible_changed = Signal (int )
25+
2226 def __init__ (self , driver : "QtDriver" , scroll_area : QScrollArea ) -> None :
2327 super ().__init__ (None )
2428 self .driver : QtDriver = driver
2529 self .scroll_area : QScrollArea = scroll_area
2630
2731 self ._item_thumbs : list [ItemThumb ] = []
2832 self ._items : list [QLayoutItem ] = []
29- # Entry.id -> _entry_ids[index]
30- self ._selected : dict [int , int ] = {}
31- # _entry_ids[index]
32- self ._last_selected : int | None = None
3333
3434 self ._entry_ids : list [int ] = []
3535 self ._entries : dict [int , Entry ] = {}
@@ -47,12 +47,14 @@ def __init__(self, driver: "QtDriver", scroll_area: QScrollArea) -> None:
4747 # _entry_ids[StartIndex:EndIndex]
4848 self ._last_page_update : tuple [int , int ] | None = None
4949
50+ self ._scroll_to : int | None = None
51+
52+ def scroll_to (self , entry_id : int ):
53+ self ._scroll_to = entry_id
54+
5055 def set_entries (self , entry_ids : list [int ]):
5156 self .scroll_area .verticalScrollBar ().setValue (0 )
5257
53- self ._selected .clear ()
54- self ._last_selected = None
55-
5658 self ._entry_ids = entry_ids
5759 self ._entries .clear ()
5860 self ._tag_entries .clear ()
@@ -83,90 +85,20 @@ def set_entries(self, entry_ids: list[int]):
8385
8486 self ._last_page_update = None
8587
86- def select_all (self ):
87- self ._selected .clear ()
88- for index , id in enumerate (self ._entry_ids ):
89- self ._selected [id ] = index
90- self ._last_selected = index
91-
92- for entry_id in self ._entry_items :
93- self ._set_selected (entry_id )
94-
95- def select_inverse (self ):
96- selected = {}
97- for index , id in enumerate (self ._entry_ids ):
98- if id not in self ._selected :
99- selected [id ] = index
100- self ._last_selected = index
101-
102- for id in self ._selected :
103- if id not in selected :
104- self ._set_selected (id , value = False )
105- for id in selected :
106- self ._set_selected (id )
107-
108- self ._selected = selected
109-
110- def select_entry (self , entry_id : int ):
111- if entry_id in self ._selected :
112- index = self ._selected .pop (entry_id )
113- if index == self ._last_selected :
114- self ._last_selected = None
115- self ._set_selected (entry_id , value = False )
116- else :
117- try :
118- index = self ._entry_ids .index (entry_id )
119- except ValueError :
120- index = - 1
121-
122- self ._selected [entry_id ] = index
123- self ._last_selected = index
124- self ._set_selected (entry_id )
125-
126- def select_to_entry (self , entry_id : int ):
127- index = self ._entry_ids .index (entry_id )
128- if len (self ._selected ) == 0 :
129- self .select_entry (entry_id )
130- return
131- if self ._last_selected is None :
132- self ._last_selected = min (self ._selected .values (), key = lambda i : abs (index - i ))
133-
134- start = self ._last_selected
135- self ._last_selected = index
88+ def update_selected (self ):
89+ for item_thumb in self ._item_thumbs :
90+ value = item_thumb .item_id in self .driver ._selected
91+ item_thumb .thumb_button .set_selected (value )
13692
137- if start > index :
138- index , start = start , index
139- else :
140- index += 1
141-
142- for i in range (start , index ):
143- entry_id = self ._entry_ids [i ]
144- self ._selected [entry_id ] = i
145- self ._set_selected (entry_id )
146-
147- def clear_selected (self ):
148- for entry_id in self ._entry_items :
149- self ._set_selected (entry_id , value = False )
150-
151- self ._selected .clear ()
152- self ._last_selected = None
153-
154- def _set_selected (self , entry_id : int , value : bool = True ):
155- if entry_id not in self ._entry_items :
156- return
157- index = self ._entry_items [entry_id ]
158- if index < len (self ._item_thumbs ):
159- self ._item_thumbs [index ].thumb_button .set_selected (value )
160-
161- def add_tags (self , entry_ids : list [int ], tag_ids : list [int ]):
93+ def add_tags (self , entry_ids : Iterable [int ], tag_ids : Iterable [int ]):
16294 for tag_id in tag_ids :
16395 self ._tag_entries .setdefault (tag_id , set ()).update (entry_ids )
16496
165- def remove_tags (self , entry_ids : list [int ], tag_ids : list [int ]):
97+ def remove_tags (self , entry_ids : Iterable [int ], tag_ids : Iterable [int ]):
16698 for tag_id in tag_ids :
16799 self ._tag_entries .setdefault (tag_id , set ()).difference_update (entry_ids )
168100
169- def _fetch_entries (self , ids : list [int ]):
101+ def _fetch_entries (self , ids : Iterable [int ]):
170102 ids = [id for id in ids if id not in self ._entries ]
171103 entries = self .driver .lib .get_entries (ids )
172104 for entry in entries :
@@ -263,12 +195,24 @@ def setGeometry(self, arg__1: QRect) -> None:
263195 per_row , width_offset , height_offset = self ._size (rect .right ())
264196 view_height = self .parentWidget ().parentWidget ().height ()
265197 offset = self .scroll_area .verticalScrollBar ().value ()
198+ if self ._scroll_to is not None :
199+ try :
200+ index = self ._entry_ids .index (self ._scroll_to )
201+ value = (index // per_row ) * height_offset
202+ self .scroll_area .verticalScrollBar ().setMaximum (value )
203+ self .scroll_area .verticalScrollBar ().setSliderPosition (value )
204+ offset = value
205+ except ValueError :
206+ pass
207+ self ._scroll_to = None
266208
267209 visible_rows = math .ceil ((view_height + (offset % height_offset )) / height_offset )
268210 offset = int (offset / height_offset )
269211 start = offset * per_row
270212 end = start + (visible_rows * per_row )
271213
214+ self .visible_changed .emit (self ._entry_ids [start ])
215+
272216 # Load closest off screen rows
273217 start -= per_row * 3
274218 end += per_row * 3
@@ -363,7 +307,7 @@ def setGeometry(self, arg__1: QRect) -> None:
363307 entry_id = self ._entry_ids [i ]
364308 item_index = self ._entry_items [entry_id ]
365309 item_thumb = self ._item_thumbs [item_index ]
366- item_thumb .thumb_button .set_selected (entry_id in self ._selected )
310+ item_thumb .thumb_button .set_selected (entry_id in self .driver . _selected )
367311
368312 item_thumb .assign_badge (BadgeType .ARCHIVED , entry_id in self ._tag_entries [TAG_ARCHIVED ])
369313 item_thumb .assign_badge (BadgeType .FAVORITE , entry_id in self ._tag_entries [TAG_FAVORITE ])
0 commit comments