from __future__ import annotations
"""Legend rendering logic for SecInterp preview.
Handles the drawing of the legend on a QPainter, including topography,
structures, and geological units.
"""
from typing import Any
from qgis.PyQt.QtCore import QCoreApplication, QRectF, Qt
from qgis.PyQt.QtGui import QColor, QFont, QPainter, QPen
from sec_interp.logger_config import get_logger
logger = get_logger(__name__)
[docs]
class PreviewLegendRenderer:
"""Handles drawing the map legend for the profile preview."""
[docs]
@staticmethod
def draw_legend(
painter: QPainter,
rect: QRectF,
active_units: dict[str, QColor],
has_topography: bool = False,
has_structures: bool = False,
) -> None:
"""Draw legend on the given painter within the rect."""
if not active_units and not has_topography and not has_structures:
return
# Configuration
config = {
"padding": 6,
"item_height": 16,
"symbol_size": 10,
"line_width": 2,
"margin": 20,
}
painter.save()
painter.setFont(QFont("Arial", 8))
legend_size, max_text_width = PreviewLegendRenderer._calculate_legend_size(
painter, active_units, has_topography, has_structures, config
)
# Position: Top Right
x = rect.width() - legend_size.width() - config["margin"]
y = config["margin"]
PreviewLegendRenderer._draw_legend_background(
painter, x, y, legend_size.width(), legend_size.height()
)
# Draw items
current_y = y + config["padding"]
if has_topography:
PreviewLegendRenderer._draw_line_item(
painter,
x,
current_y,
QCoreApplication.translate("PreviewLegendRenderer", "Topography"),
QColor(0, 102, 204),
max_text_width,
config,
)
current_y += config["item_height"]
if has_structures:
PreviewLegendRenderer._draw_line_item(
painter,
x,
current_y,
QCoreApplication.translate("PreviewLegendRenderer", "Structures"),
QColor(204, 0, 0),
max_text_width,
config,
)
current_y += config["item_height"]
PreviewLegendRenderer._draw_geology_items(
painter, x, current_y, active_units, max_text_width, config
)
painter.restore()
@staticmethod
def _calculate_legend_size(
painter: QPainter,
active_units: dict[str, QColor],
has_topo: bool,
has_struct: bool,
config: dict[str, Any],
) -> tuple[QRectF, float]:
"""Calculate dimensions of the legend box."""
fm = painter.fontMetrics()
max_text_width = 0
items = []
if has_topo:
items.append(QCoreApplication.translate("PreviewLegendRenderer", "Topography"))
if has_struct:
items.append(QCoreApplication.translate("PreviewLegendRenderer", "Structures"))
items.extend(active_units.keys())
for item in items:
max_text_width = max(max_text_width, fm.boundingRect(item).width())
width = max_text_width + config["symbol_size"] + config["padding"] * 3
height = len(items) * config["item_height"] + config["padding"] * 2
return QRectF(0, 0, width, height), max_text_width
@staticmethod
def _draw_legend_background(
painter: QPainter, x: float, y: float, width: float, height: float
) -> None:
"""Draw the legend box background and border."""
rect = QRectF(x, y, width, height)
painter.setBrush(QColor(255, 255, 255, 200))
painter.setPen(Qt.NoPen)
painter.drawRect(rect)
painter.setBrush(Qt.NoBrush)
painter.setPen(QColor(100, 100, 100))
painter.drawRect(rect)
@staticmethod
def _draw_line_item(
painter: QPainter,
x: float,
y: float,
label: str,
color: QColor,
max_width: float,
config: dict[str, Any],
) -> None:
"""Draw a legend item with a line symbol."""
p = config["padding"]
ih = config["item_height"]
ss = config["symbol_size"]
painter.setPen(QPen(color, config["line_width"]))
painter.drawLine(int(x + p), int(y + ih / 2), int(x + p + ss), int(y + ih / 2))
painter.setPen(QColor(0, 0, 0))
text_rect = QRectF(x + p * 2 + ss, y, max_width, ih)
painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, label)
@staticmethod
def _draw_geology_items(
painter: QPainter,
x: float,
y: float,
units: dict[str, QColor],
max_width: float,
config: dict[str, Any],
) -> None:
"""Draw geological unit legend items."""
p = config["padding"]
ih = config["item_height"]
ss = config["symbol_size"]
for name, color in units.items():
painter.setBrush(color)
painter.setPen(Qt.NoPen)
painter.drawRect(QRectF(x + p, y + (ih - ss) / 2, ss, ss))
painter.setPen(QColor(0, 0, 0))
text_rect = QRectF(x + p * 2 + ss, y, max_width, ih)
painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, name)
y += ih