Make timeline X position dynamic based on connection lines

- Added TIMELINE_LEFT_SPACING constant for spacing between connection lines and timeline
- Added _calculate_max_connection_line_x() to find rightmost connection line position
- Added _calculate_timeline_x() to dynamically calculate timeline X position
- Timeline now adjusts based on number of selected persons and their connection lines
- Updated on_draw() and find_event_at_position() to use dynamic timeline_x
- Timeline maintains minimum position to prevent overlap with year labels
- Event symbols and text now position relative to connection lines on the left
This commit is contained in:
Daniel Viegas 2025-11-29 22:20:49 +01:00
parent f6069dfd83
commit 66c932e4b8

View File

@ -111,6 +111,7 @@ CONNECTION_LINE_COLOR = (0.2, 0.5, 1.0, 0.75) # Brighter, more opaque blue
CONNECTION_LINE_WIDTH = 3.5
CONNECTION_VERTICAL_LINE_X = 5 # Left of year markers
CONNECTION_LINE_SPACING = 25 # Pixels between vertical lines for different persons
TIMELINE_LEFT_SPACING = 20 # Spacing between rightmost connection line and timeline
# Marker State Colors
SELECTED_MARKER_COLOR = (0.2, 0.4, 0.9) # Blue highlight for selected person's events
@ -2180,6 +2181,48 @@ class MyTimelineView(NavigationView):
"""
return CONNECTION_VERTICAL_LINE_X + (person_index * CONNECTION_LINE_SPACING)
def _calculate_max_connection_line_x(self) -> float:
"""
Calculate the maximum (rightmost) X position of connection lines.
Returns:
float: The X coordinate of the rightmost connection line, or 0 if no persons selected.
"""
if not self.selected_person_handles:
return 0
num_selected = len(self.selected_person_handles)
if num_selected == 0:
return 0
# The rightmost line is at the highest index
max_index = num_selected - 1
return CONNECTION_VERTICAL_LINE_X + (max_index * CONNECTION_LINE_SPACING)
def _calculate_timeline_x(self) -> float:
"""
Calculate the dynamic timeline X position based on connection lines.
The timeline should be positioned to the right of the rightmost connection line
with appropriate spacing. If no connection lines exist, use the default margin.
Returns:
float: The X coordinate for the timeline.
"""
max_connection_x = self._calculate_max_connection_line_x()
if max_connection_x == 0:
# No connection lines, use default margin
return TIMELINE_MARGIN_LEFT
# Position timeline to the right of connection lines with spacing
timeline_x = max_connection_x + TIMELINE_LEFT_SPACING
# Ensure minimum timeline X to prevent overlap with year labels
# Year labels need space on the left (around 130-150 pixels)
min_timeline_x = TIMELINE_MARGIN_LEFT
return max(timeline_x, min_timeline_x)
def _calculate_y_position(self, date_sort: int, min_date: int, date_range: int,
timeline_y_start: float, timeline_y_end: float) -> float:
"""
@ -2583,7 +2626,8 @@ class MyTimelineView(NavigationView):
# Get widget dimensions in drawing coordinates
height = self.drawing_area.get_allocated_height() / self.zoom_level
timeline_x = TIMELINE_MARGIN_LEFT
# Calculate dynamic timeline X position based on connection lines
timeline_x = self._calculate_timeline_x()
timeline_y_start = TIMELINE_MARGIN_TOP
timeline_y_end = height - TIMELINE_MARGIN_BOTTOM
@ -2877,8 +2921,8 @@ class MyTimelineView(NavigationView):
# Calculate date range
min_date, max_date, date_range = self._calculate_date_range()
# Draw timeline axis
timeline_x = TIMELINE_MARGIN_LEFT
# Calculate dynamic timeline X position based on connection lines
timeline_x = self._calculate_timeline_x()
timeline_y_start = TIMELINE_MARGIN_TOP
timeline_y_end = height - TIMELINE_MARGIN_BOTTOM