Add multi-person event selection
- Add _get_all_persons_for_event helper to get all persons for an event (e.g., both spouses for marriage events) - Add _format_color_for_display helper to format colors for display - Modify event click handler to select all persons involved in an event - When clicking a marriage event, both spouses are now selected together - Event lines are shown for all selected persons
This commit is contained in:
parent
cdba794cda
commit
137de07052
140
MyTimeline.py
140
MyTimeline.py
@ -2759,6 +2759,111 @@ class MyTimelineView(NavigationView):
|
|||||||
self.person_colors[person_handle] = color
|
self.person_colors[person_handle] = color
|
||||||
return color
|
return color
|
||||||
|
|
||||||
|
def _format_color_for_display(self, color: Tuple[float, float, float, float]) -> str:
|
||||||
|
"""
|
||||||
|
Format color tuple for display in tooltips.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
color: RGBA color tuple (values 0-1).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Formatted color string like "RGB(255, 128, 64)".
|
||||||
|
"""
|
||||||
|
r, g, b = color[0], color[1], color[2] # Ignore alpha for display
|
||||||
|
r_int = int(r * 255)
|
||||||
|
g_int = int(g * 255)
|
||||||
|
b_int = int(b * 255)
|
||||||
|
return f"RGB({r_int}, {g_int}, {b_int})"
|
||||||
|
|
||||||
|
def _get_all_persons_for_event(self, event: 'Event', event_data: 'TimelineEvent') -> List['Person']:
|
||||||
|
"""
|
||||||
|
Get all persons associated with an event.
|
||||||
|
For marriage events, returns both spouses.
|
||||||
|
For other events, returns the associated person (if any).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event: The event object.
|
||||||
|
event_data: The TimelineEvent object containing event data.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Person]: List of all persons associated with the event.
|
||||||
|
"""
|
||||||
|
persons: List['Person'] = []
|
||||||
|
|
||||||
|
if not event or not self.dbstate.is_open():
|
||||||
|
return persons
|
||||||
|
|
||||||
|
# Check if this is a marriage event
|
||||||
|
try:
|
||||||
|
actual_event_type = event.get_type()
|
||||||
|
event_type_val = int(actual_event_type) if hasattr(actual_event_type, '__int__') else None
|
||||||
|
marriage_type_val = int(EventType.MARRIAGE) if hasattr(EventType.MARRIAGE, '__int__') else None
|
||||||
|
|
||||||
|
is_marriage = False
|
||||||
|
if event_type_val is not None and marriage_type_val is not None:
|
||||||
|
is_marriage = (event_type_val == marriage_type_val)
|
||||||
|
elif actual_event_type == EventType.MARRIAGE:
|
||||||
|
is_marriage = True
|
||||||
|
elif "Marriage" in str(actual_event_type) or "MARRIAGE" in str(actual_event_type):
|
||||||
|
is_marriage = True
|
||||||
|
except (ValueError, TypeError, AttributeError):
|
||||||
|
is_marriage = False
|
||||||
|
|
||||||
|
# For marriage events, get both spouses from the family
|
||||||
|
if is_marriage:
|
||||||
|
try:
|
||||||
|
event_handle = event.get_handle()
|
||||||
|
# Use cached family lookup
|
||||||
|
family = self._event_to_family_cache.get(event_handle)
|
||||||
|
|
||||||
|
# If not in cache, try to find the family by searching
|
||||||
|
if not family:
|
||||||
|
for family_handle in self.dbstate.db.get_family_handles():
|
||||||
|
try:
|
||||||
|
test_family = self.dbstate.db.get_family_from_handle(family_handle)
|
||||||
|
if not test_family:
|
||||||
|
continue
|
||||||
|
family_event_refs = test_family.get_event_ref_list()
|
||||||
|
for event_ref in family_event_refs:
|
||||||
|
if event_ref.ref == event_handle:
|
||||||
|
family = test_family
|
||||||
|
# Cache it for next time
|
||||||
|
self._event_to_family_cache[event_handle] = family
|
||||||
|
break
|
||||||
|
if family:
|
||||||
|
break
|
||||||
|
except (AttributeError, KeyError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# If we found a family, get both spouses
|
||||||
|
if family:
|
||||||
|
father_handle = family.get_father_handle()
|
||||||
|
mother_handle = family.get_mother_handle()
|
||||||
|
|
||||||
|
if father_handle:
|
||||||
|
try:
|
||||||
|
father = self.dbstate.db.get_person_from_handle(father_handle)
|
||||||
|
if father:
|
||||||
|
persons.append(father)
|
||||||
|
except (AttributeError, KeyError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if mother_handle:
|
||||||
|
try:
|
||||||
|
mother = self.dbstate.db.get_person_from_handle(mother_handle)
|
||||||
|
if mother:
|
||||||
|
persons.append(mother)
|
||||||
|
except (AttributeError, KeyError):
|
||||||
|
pass
|
||||||
|
except (AttributeError, KeyError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# For other events, add the associated person if available
|
||||||
|
if not persons and event_data.person:
|
||||||
|
persons.append(event_data.person)
|
||||||
|
|
||||||
|
return persons
|
||||||
|
|
||||||
def _get_person_vertical_line_x(self, person_index: int) -> float:
|
def _get_person_vertical_line_x(self, person_index: int) -> float:
|
||||||
"""
|
"""
|
||||||
Calculate the X position for a person's vertical connection line.
|
Calculate the X position for a person's vertical connection line.
|
||||||
@ -3126,19 +3231,30 @@ class MyTimelineView(NavigationView):
|
|||||||
# Navigate to this event in the view
|
# Navigate to this event in the view
|
||||||
self.uistate.set_active(event_handle, "Event")
|
self.uistate.set_active(event_handle, "Event")
|
||||||
|
|
||||||
# Toggle person selection (always toggle, even if event is same)
|
# Get all persons for this event (e.g., both spouses for marriage)
|
||||||
if clicked_event_data.person:
|
all_persons = self._get_all_persons_for_event(clicked_event_data.event, clicked_event_data)
|
||||||
person_handle = clicked_event_data.person.get_handle()
|
|
||||||
if person_handle in self.selected_person_handles:
|
# Toggle selection for all persons involved in the event
|
||||||
# Remove from selection
|
if all_persons:
|
||||||
self.selected_person_handles.remove(person_handle)
|
# Check if all persons are already selected
|
||||||
# Clean up color if no longer selected
|
all_selected = all(person.get_handle() in self.selected_person_handles for person in all_persons)
|
||||||
if person_handle in self.person_colors:
|
|
||||||
del self.person_colors[person_handle]
|
if all_selected:
|
||||||
|
# Remove all persons from selection
|
||||||
|
for person in all_persons:
|
||||||
|
person_handle = person.get_handle()
|
||||||
|
if person_handle in self.selected_person_handles:
|
||||||
|
self.selected_person_handles.remove(person_handle)
|
||||||
|
# Clean up color if no longer selected
|
||||||
|
if person_handle in self.person_colors:
|
||||||
|
del self.person_colors[person_handle]
|
||||||
else:
|
else:
|
||||||
# Add to selection
|
# Add all persons to selection
|
||||||
self.selected_person_handles.add(person_handle)
|
for person in all_persons:
|
||||||
# Color will be assigned when drawing
|
person_handle = person.get_handle()
|
||||||
|
if person_handle not in self.selected_person_handles:
|
||||||
|
self.selected_person_handles.add(person_handle)
|
||||||
|
# Color will be assigned when drawing
|
||||||
|
|
||||||
self._queue_draw()
|
self._queue_draw()
|
||||||
return False
|
return False
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user