diff --git a/CHANGELOG.md b/CHANGELOG.md index 26da09c..4d5a6aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 0.3.2 * Add weekday letters on left axis of Statistics page + * Allow clicking on a date in the Statistics heatmap and have it open that page * Add the ability to choose the database path at startup * Add in-app bug report functionality * Add ability to take screenshots in-app and insert them into the page diff --git a/bouquin/main_window.py b/bouquin/main_window.py index a411175..3221809 100644 --- a/bouquin/main_window.py +++ b/bouquin/main_window.py @@ -1163,6 +1163,14 @@ class MainWindow(QMainWindow): return dlg = StatisticsDialog(self.db, self) + + if hasattr(dlg, "_heatmap"): + + def on_date_clicked(d: datetime.date): + qd = QDate(d.year, d.month, d.day) + self._open_date_in_tab(qd) + + dlg._heatmap.date_clicked.connect(on_date_clicked) dlg.exec() # ------------ Window positioning --------------- # diff --git a/bouquin/statistics_dialog.py b/bouquin/statistics_dialog.py index 25ba137..5d208de 100644 --- a/bouquin/statistics_dialog.py +++ b/bouquin/statistics_dialog.py @@ -3,7 +3,7 @@ from __future__ import annotations import datetime as _dt from typing import Dict -from PySide6.QtCore import Qt, QSize +from PySide6.QtCore import Qt, QSize, Signal from PySide6.QtGui import QColor, QPainter, QPen, QBrush from PySide6.QtWidgets import ( QDialog, @@ -32,6 +32,8 @@ class DateHeatmap(QWidget): Data is a mapping: datetime.date -> integer value. """ + date_clicked = Signal(_dt.date) + def __init__(self, parent=None): super().__init__(parent) self._data: Dict[_dt.date, int] = {} @@ -192,6 +194,46 @@ class DateHeatmap(QWidget): painter.end() + def mousePressEvent(self, event): + if event.button() != Qt.LeftButton: + return super().mousePressEvent(event) + + # No data = nothing to click + if not self._start or not self._end: + return + + # Qt6: position(), older: pos() + pos = event.position() if hasattr(event, "position") else event.pos() + x = pos.x() + y = pos.y() + + # Outside grid area (left of weekday labels or above rows) + if x < self._margin_left or y < self._margin_top: + return + + cell_span = self._cell + self._gap + col = int((x - self._margin_left) // cell_span) # week index + row = int((y - self._margin_top) // cell_span) # dow (0..6) + + # Only 7 rows (Mon–Sun) + if not (0 <= row < 7): + return + + # Only as many weeks as we actually have + day_count = (self._end - self._start).days + 1 + weeks = (day_count + 6) // 7 + if col < 0 or col >= weeks: + return + + idx = col * 7 + row + date = self._start + _dt.timedelta(days=idx) + + # Skip trailing empty cells beyond the last date + if date > self._end: + return + + self.date_clicked.emit(date) + # ---------- Statistics dialog itself ----------