Skip to content

Commit ad7e176

Browse files
committed
Add Encyclopaedia.set_entry, emit EncEntry viewed callback when viewed status is changed, not just after Actions
1 parent 16aaa4c commit ad7e176

File tree

6 files changed

+141
-70
lines changed

6 files changed

+141
-70
lines changed

encyclopaedia/actions_ren.py

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1+
from typing import TYPE_CHECKING
2+
13
from .constants_ren import SortMode
4+
from .types_ren import ENTRY_TYPE
25

36
import renpy.exports as renpy
47
from renpy.store import DictEquality
58
from renpy.ui import Action
69

7-
from typing import TYPE_CHECKING
8-
910
if TYPE_CHECKING: # pragma: no cover
1011
from .encyclopaedia_ren import Encyclopaedia
11-
from .encentry_ren import EncEntry
12-
13-
from .book import Book
1412

1513
"""renpy
1614
init python:
@@ -38,54 +36,14 @@ class SetEntry(EncyclopaediaAction):
3836
encyclopaedia: The Encyclopaedia instance to use.
3937
entry: The entry to be made active.
4038
"""
41-
def __init__(self, encyclopaedia: 'Encyclopaedia', entry: 'EncEntry') -> None:
39+
def __init__(self, encyclopaedia: 'Encyclopaedia', entry: ENTRY_TYPE) -> None:
4240
super().__init__(encyclopaedia)
4341

4442
self.entry = entry
4543

46-
def _get_entry_index(self) -> int:
47-
# Find the position of the entry
48-
if self.enc.show_locked_entry:
49-
target_position = self.enc.all_entries.index(self.entry)
50-
else:
51-
target_position = self.enc.unlocked_entries.index(self.entry)
52-
53-
return target_position
54-
55-
def set_entry(self) -> None:
56-
"""Set the Entry as active and update the Encyclopaeda's internal state."""
57-
target_position = self._get_entry_index()
58-
59-
# The active entry is set to whichever list position was found.
60-
self.enc.active = self.entry
61-
62-
if self.enc.active.locked is False:
63-
if not isinstance(self.entry, Book):
64-
if self.entry.viewed is False:
65-
# Run the callback, if provided.
66-
self.entry.emit("viewed")
67-
# Mark the entry as viewed.
68-
self.enc.active.viewed = True
69-
70-
# When setting a Book, set the first page to viewed, not the Book.
71-
elif isinstance(self.entry, Book):
72-
self.entry.active.viewed = True
73-
self.entry.active.emit("viewed")
74-
75-
# When sorting by Unread, setting an entry marks is as read.
76-
# Thus we have to resort the entries to ensure they appear in the
77-
# correct order.
78-
if self.enc.sorting_mode.value == SortMode.UNREAD.value:
79-
self.enc.sort_entries(
80-
entries=self.enc.current_entries,
81-
sorting=self.enc.sorting_mode.value,
82-
)
83-
84-
self.enc.current_position = target_position
85-
8644
def __call__(self) -> None:
8745
"""Used by Ren'Py to invoke this Action."""
88-
self.set_entry()
46+
self.enc.set_entry(self.entry)
8947

9048
# Show the entry screen associated with the encyclopaedia.
9149
renpy.show_screen(self.enc.entry_screen, enc=self.enc)

encyclopaedia/encentry_ren.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,12 @@ def viewed(self, new_value: bool) -> None:
182182
if self.viewed_persistent:
183183
setattr(persistent, self._name + "_viewed", new_value)
184184

185+
if self._viewed is False and new_value is True:
186+
self.emit("viewed")
187+
185188
self._viewed = new_value
186189

190+
187191
@property
188192
def current_page(self) -> 'EncEntry':
189193
"""Get the sub-page that's currently viewing viewed.

encyclopaedia/encyclopaedia_ren.py

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@
1717
ToggleShowLockedEntryAction,
1818
)
1919
from .entry_sorting_ren import push_locked_to_bottom
20-
from .exceptions_ren import AddEntryError
20+
from .exceptions_ren import AddEntryError, UnknownEntryError
2121
from .eventemitter_ren import EventEmitter
2222
from .constants_ren import Direction, SortMode
2323
from .book import Book
24-
2524
from .types_ren import ENTRY_TYPE
2625

2726
if TYPE_CHECKING: # pragma: no cover
@@ -115,12 +114,17 @@ def __str__(self) -> str: # NOQA D105
115114

116115
def __len__(self) -> int:
117116
"""The total number of entries, relative to if locked ones are shown or not."""
118-
rv = len(self.unlocked_entries)
119-
if self.show_locked_entry:
120-
rv = len(self.all_entries)
121-
117+
rv = len(self.viewable_entries)
122118
return rv
123119

120+
@property
121+
def viewable_entries(self):
122+
"""Get the list of entries which are currently viewable."""
123+
if self.show_locked_entry:
124+
return self.all_entries
125+
else:
126+
return self.unlocked_entries
127+
124128
@property
125129
def current_entries(self) -> list[ENTRY_TYPE]:
126130
"""Get all the entries which should be visible to the user.
@@ -148,10 +152,7 @@ def current_entry(self) -> ENTRY_TYPE:
148152
Return:
149153
EncEntry
150154
"""
151-
entry = self.unlocked_entries[self.current_position]
152-
if self.show_locked_entry:
153-
entry = self.all_entries[self.current_position]
154-
155+
entry = self.viewable_entries[self.current_position]
155156
return entry
156157

157158
@property
@@ -311,8 +312,73 @@ def _build_subject_filter(self, subject: str) -> None:
311312

312313
self.filtered_entries = [i for i in entries if i.subject == subject]
313314

315+
def _change_active_entry_viewed_status(self) -> bool:
316+
"""Change the viewed status of the active Entry.
317+
318+
Return:
319+
True if status was changed, else False
320+
"""
321+
if self.active is None:
322+
raise ValueError(
323+
'Tried to change active entry viewed status with no active entry.',
324+
)
325+
if self.active.locked is False:
326+
entry = None
327+
328+
if isinstance(self.active, Book):
329+
# When Book, set the first page to viewed, not the Book.
330+
entry = self.active.active
331+
else:
332+
entry = self.active
333+
334+
# Mark the entry as viewed.
335+
entry.viewed = True
336+
337+
return True
338+
339+
return False
340+
341+
def set_entry(self, entry: ENTRY_TYPE) -> None:
342+
"""Set an Entry as active.
343+
344+
Args:
345+
entry: The Entry to set.
346+
347+
Raises:
348+
ValueError: If the entry cannot be set.
349+
"""
350+
try:
351+
target_position = self.viewable_entries.index(entry)
352+
except ValueError as e:
353+
if entry not in self.all_entries:
354+
raise UnknownEntryError(f"{entry} is not in this Encyclopaedia") from e
355+
else:
356+
raise ValueError(
357+
f"{entry} cannot be set because it is locked and 'show_locked_entry' is False",
358+
) from e
359+
360+
self.current_position = target_position
361+
362+
self.active = entry
363+
self._change_active_entry_viewed_status()
364+
365+
# When sorting by Unread, setting an entry marks is as read.
366+
# Thus we have to resort the entries to ensure they appear in the
367+
# correct order.
368+
if self.sorting_mode.value == SortMode.UNREAD.value:
369+
self.sort_entries(
370+
entries=self.current_entries,
371+
sorting=self.sorting_mode.value,
372+
)
373+
314374
def _change_entry(self, direction: Direction) -> bool:
315-
"""Change the current active EncEntry."""
375+
"""Change the active entry by changing the index.
376+
377+
This is relative to the current sorting.
378+
379+
Args:
380+
direction: The direction to move.
381+
"""
316382
test_position = self.current_position + direction.value
317383

318384
# Boundary check
@@ -328,18 +394,7 @@ def _change_entry(self, direction: Direction) -> bool:
328394
# Update the active entry.
329395
self.active = self.current_entry
330396

331-
if self.active.locked is False:
332-
if not isinstance(self.active, Book):
333-
# Run the callback, if provided.
334-
self.active.emit("viewed")
335-
336-
# Mark the entry as viewed.
337-
self.active.viewed = True
338-
339-
# When setting a Book, set the first page to viewed, not the Book.
340-
elif isinstance(self.active, Book):
341-
self.active.active.viewed = True
342-
self.active.active.emit("viewed")
397+
self._change_active_entry_viewed_status()
343398

344399
# When changing an entry, the current entry page number is reset.
345400
self.active._unlocked_page_index = 0

encyclopaedia/exceptions_ren.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,9 @@ class AddEntryError(Exception):
99

1010
class GetEntryError(Exception):
1111
"""Raised when getting an entry fails."""
12+
pass
13+
14+
15+
class UnknownEntryError(Exception):
16+
"""Raised when looking for an entry that is not in an Encyclopaedia."""
17+
pass
File renamed without changes.

tests/encyclopaedia/test_set_entry.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from encyclopaedia import Encyclopaedia
2+
from encyclopaedia import EncEntry
3+
from encyclopaedia.exceptions_ren import UnknownEntryError
4+
5+
import pytest
6+
7+
8+
def test__change_active_entry_viewed_status_no_active():
9+
enc = Encyclopaedia()
10+
11+
EncEntry(
12+
parent=enc,
13+
name="Test Name",
14+
text=["Test Text"],
15+
)
16+
17+
with pytest.raises(ValueError):
18+
enc._change_active_entry_viewed_status()
19+
20+
21+
def test__change_active_entry_viewed_status_locked_entry():
22+
enc = Encyclopaedia()
23+
24+
e = EncEntry(
25+
parent=enc,
26+
name="Test Name",
27+
text=["Test Text"],
28+
locked=True,
29+
)
30+
31+
enc.active = e
32+
33+
result = enc._change_active_entry_viewed_status()
34+
assert result is False
35+
36+
37+
def test_set_entry_unknown_entry():
38+
enc = Encyclopaedia()
39+
another_enc = Encyclopaedia()
40+
41+
e = EncEntry(
42+
parent=enc,
43+
name="Test Name",
44+
text=["Test Text"],
45+
)
46+
47+
with pytest.raises(UnknownEntryError):
48+
another_enc.set_entry(e)

0 commit comments

Comments
 (0)