Fix mouse position/selection mismatch and improve interaction
- Fix mouse coordinate transformation to account for zoom level - Enable whole-line selection (click anywhere on event line to select person) - Update tooltip to show date first, then event type - Make connection lines more visible with increased opacity and width - Improved click detection using scaled coordinates - Expanded clickable area to include both marker and label regions
This commit is contained in:
parent
0abe20849c
commit
0642e20315
@ -607,28 +607,31 @@ class MyTimelineView(NavigationView):
|
|||||||
# Find which event was clicked
|
# Find which event was clicked
|
||||||
clicked_index = self.find_event_at_position(event.x, event.y)
|
clicked_index = self.find_event_at_position(event.x, event.y)
|
||||||
if clicked_index is not None:
|
if clicked_index is not None:
|
||||||
# Check if clicking on marker (for person selection) or label (for expansion)
|
# Convert mouse coordinates to drawing coordinates (account for zoom)
|
||||||
|
scaled_x = event.x / self.zoom_level
|
||||||
|
|
||||||
date_sort, date_obj, clicked_event, clicked_person, event_type, expanded, _y_pos = self.events[clicked_index]
|
date_sort, date_obj, clicked_event, clicked_person, event_type, expanded, _y_pos = self.events[clicked_index]
|
||||||
|
|
||||||
# Check if click is on marker area (left side) or label area (right side)
|
# Check if click is on marker area (left side) or label area (right side)
|
||||||
timeline_x = TIMELINE_MARGIN_LEFT
|
timeline_x = TIMELINE_MARGIN_LEFT
|
||||||
marker_area_width = EVENT_MARKER_SIZE * self.zoom_level + 20
|
marker_area_width = EVENT_MARKER_SIZE + 20
|
||||||
|
|
||||||
if event.x < timeline_x + marker_area_width:
|
# Allow person selection from anywhere on the line
|
||||||
# Click on marker - toggle person selection
|
# Clicking anywhere on the event line selects the person
|
||||||
if clicked_person:
|
if clicked_person:
|
||||||
person_handle = clicked_person.get_handle()
|
person_handle = clicked_person.get_handle()
|
||||||
if self.selected_person_handle == person_handle:
|
if self.selected_person_handle == person_handle:
|
||||||
# Deselect if clicking same person
|
# Deselect if clicking same person
|
||||||
self.selected_person_handle = None
|
|
||||||
else:
|
|
||||||
# Select this person
|
|
||||||
self.selected_person_handle = person_handle
|
|
||||||
else:
|
|
||||||
# No person for this event, deselect
|
|
||||||
self.selected_person_handle = None
|
self.selected_person_handle = None
|
||||||
|
else:
|
||||||
|
# Select this person
|
||||||
|
self.selected_person_handle = person_handle
|
||||||
else:
|
else:
|
||||||
# Click on label - toggle expansion
|
# No person for this event, deselect
|
||||||
|
self.selected_person_handle = None
|
||||||
|
|
||||||
|
# Also toggle expansion if clicking on label area (right side)
|
||||||
|
if scaled_x > timeline_x + marker_area_width:
|
||||||
if self.expanded_event_index == clicked_index:
|
if self.expanded_event_index == clicked_index:
|
||||||
self.expanded_event_index = None
|
self.expanded_event_index = None
|
||||||
else:
|
else:
|
||||||
@ -690,9 +693,13 @@ class MyTimelineView(NavigationView):
|
|||||||
if not self.events:
|
if not self.events:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Get widget dimensions
|
# Convert mouse coordinates to drawing coordinates (account for zoom)
|
||||||
width = self.drawing_area.get_allocated_width()
|
scaled_x = x / self.zoom_level
|
||||||
height = self.drawing_area.get_allocated_height()
|
scaled_y = y / self.zoom_level
|
||||||
|
|
||||||
|
# Get widget dimensions in drawing coordinates
|
||||||
|
width = self.drawing_area.get_allocated_width() / self.zoom_level
|
||||||
|
height = self.drawing_area.get_allocated_height() / self.zoom_level
|
||||||
|
|
||||||
# Calculate date range
|
# Calculate date range
|
||||||
min_date = min(event[0] for event in self.events)
|
min_date = min(event[0] for event in self.events)
|
||||||
@ -703,17 +710,34 @@ class MyTimelineView(NavigationView):
|
|||||||
|
|
||||||
timeline_x = TIMELINE_MARGIN_LEFT
|
timeline_x = TIMELINE_MARGIN_LEFT
|
||||||
|
|
||||||
# Check each event
|
# Calculate initial Y positions (same as in on_draw)
|
||||||
for i, (date_sort, date_obj, event, person, event_type, expanded, _y_pos) in enumerate(self.events):
|
events_with_y_pos = []
|
||||||
# Calculate Y position
|
for i, event_data in enumerate(self.events):
|
||||||
|
date_sort, date_obj, event, person, event_type, expanded, _ = event_data
|
||||||
y_pos = TIMELINE_MARGIN_TOP + (
|
y_pos = TIMELINE_MARGIN_TOP + (
|
||||||
(date_sort - min_date) / date_range
|
(date_sort - min_date) / date_range
|
||||||
) * (height - TIMELINE_MARGIN_TOP - TIMELINE_MARGIN_BOTTOM)
|
) * (height - TIMELINE_MARGIN_TOP - TIMELINE_MARGIN_BOTTOM)
|
||||||
|
events_with_y_pos.append((i, y_pos, event_data))
|
||||||
|
|
||||||
# Check if click is near the marker
|
# Check each event using adjusted positions
|
||||||
marker_size = EVENT_MARKER_SIZE * self.zoom_level
|
# We need to simulate the collision detection, but for simplicity,
|
||||||
if (abs(x - timeline_x) < marker_size + 10 and
|
# we'll check against the calculated positions and use a wider tolerance
|
||||||
abs(y - y_pos) < marker_size + 20):
|
for i, y_pos, event_data in events_with_y_pos:
|
||||||
|
date_sort, date_obj, event, person, event_type, expanded, _ = event_data
|
||||||
|
|
||||||
|
# Calculate clickable area - wider to include label area
|
||||||
|
marker_size = EVENT_MARKER_SIZE
|
||||||
|
label_x = timeline_x + 25
|
||||||
|
|
||||||
|
# Estimate label width (we'll use a reasonable default)
|
||||||
|
# For whole-line selection, check if click is in the event's horizontal band
|
||||||
|
clickable_width = 600 # Reasonable width for label area
|
||||||
|
clickable_height = max(marker_size * 2, 30) # At least marker size or 30px
|
||||||
|
|
||||||
|
# Check if click is in the event's area (marker + label)
|
||||||
|
if (scaled_x >= timeline_x - marker_size - 10 and
|
||||||
|
scaled_x <= label_x + clickable_width and
|
||||||
|
abs(scaled_y - y_pos) < clickable_height / 2):
|
||||||
return i
|
return i
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@ -744,11 +768,11 @@ class MyTimelineView(NavigationView):
|
|||||||
tooltip_text = f"<b>{person_name}</b>\n"
|
tooltip_text = f"<b>{person_name}</b>\n"
|
||||||
tooltip_text += "─" * 30 + "\n"
|
tooltip_text += "─" * 30 + "\n"
|
||||||
|
|
||||||
# List all events for this person
|
# List all events for this person (date first)
|
||||||
for evt_date_sort, evt_date_obj, evt_event, evt_event_type in person_events:
|
for evt_date_sort, evt_date_obj, evt_event, evt_event_type in person_events:
|
||||||
evt_date_str = get_date(evt_event)
|
evt_date_str = get_date(evt_event)
|
||||||
evt_event_type_str = str(evt_event_type)
|
evt_event_type_str = str(evt_event_type)
|
||||||
tooltip_text += f"{evt_event_type_str} - {evt_date_str}\n"
|
tooltip_text += f"{evt_date_str} - {evt_event_type_str}\n"
|
||||||
|
|
||||||
# Add place if available
|
# Add place if available
|
||||||
evt_place_handle = evt_event.get_place_handle()
|
evt_place_handle = evt_event.get_place_handle()
|
||||||
@ -761,11 +785,11 @@ class MyTimelineView(NavigationView):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# Family event (no person) - show single event info
|
# Family event (no person) - show single event info (date first)
|
||||||
date_str = get_date(event)
|
date_str = get_date(event)
|
||||||
event_type_str = str(event_type)
|
event_type_str = str(event_type)
|
||||||
|
|
||||||
tooltip_text = f"<b>{event_type_str}</b>\n{date_str}"
|
tooltip_text = f"<b>{date_str}</b>\n{event_type_str}"
|
||||||
|
|
||||||
# Get place information
|
# Get place information
|
||||||
place_handle = event.get_place_handle()
|
place_handle = event.get_place_handle()
|
||||||
@ -1207,9 +1231,9 @@ class MyTimelineView(NavigationView):
|
|||||||
|
|
||||||
context.save()
|
context.save()
|
||||||
|
|
||||||
# Draw connecting lines
|
# Draw connecting lines - more visible with brighter color and increased opacity
|
||||||
context.set_source_rgba(0.2, 0.4, 0.9, 0.5) # Semi-transparent blue
|
context.set_source_rgba(0.2, 0.5, 1.0, 0.75) # Brighter, more opaque blue
|
||||||
context.set_line_width(2)
|
context.set_line_width(3.5) # Increased from 2
|
||||||
context.set_line_cap(cairo.LINE_CAP_ROUND)
|
context.set_line_cap(cairo.LINE_CAP_ROUND)
|
||||||
context.set_line_join(cairo.LINE_JOIN_ROUND)
|
context.set_line_join(cairo.LINE_JOIN_ROUND)
|
||||||
|
|
||||||
@ -1219,19 +1243,16 @@ class MyTimelineView(NavigationView):
|
|||||||
context.line_to(timeline_x + EVENT_MARKER_SIZE * 1.5, y_pos)
|
context.line_to(timeline_x + EVENT_MARKER_SIZE * 1.5, y_pos)
|
||||||
context.stroke()
|
context.stroke()
|
||||||
|
|
||||||
# Draw curved path connecting all events (optional - can be commented out if too cluttered)
|
# Draw vertical connector line on the left side
|
||||||
if len(person_events) > 1:
|
if len(person_events) > 1:
|
||||||
# Draw a subtle curved path connecting all markers
|
|
||||||
context.set_source_rgba(0.2, 0.4, 0.9, 0.3) # More transparent
|
|
||||||
context.set_line_width(1.5)
|
|
||||||
|
|
||||||
# Create a smooth curve through all points
|
|
||||||
y_positions = [y for y, _event_data in person_events]
|
y_positions = [y for y, _event_data in person_events]
|
||||||
min_y = min(y_positions)
|
min_y = min(y_positions)
|
||||||
max_y = max(y_positions)
|
max_y = max(y_positions)
|
||||||
|
|
||||||
# Draw a vertical line on the left side connecting the range
|
# Draw a more visible vertical line connecting the range
|
||||||
if max_y - min_y > EVENT_MARKER_SIZE * 2:
|
if max_y - min_y > EVENT_MARKER_SIZE * 2:
|
||||||
|
context.set_source_rgba(0.2, 0.5, 1.0, 0.6) # Slightly less opaque but still visible
|
||||||
|
context.set_line_width(2.5) # Thicker than before
|
||||||
context.move_to(timeline_x - 15, min_y)
|
context.move_to(timeline_x - 15, min_y)
|
||||||
context.line_to(timeline_x - 15, max_y)
|
context.line_to(timeline_x - 15, max_y)
|
||||||
context.stroke()
|
context.stroke()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user