Coverage for graphica/gui/widgets/color_chips.py: 100.0%
75 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
1"""色のチップの列(今の配色パレットの色をすぐ選べるように、色欄の横に並べる)。"""
2from PySide6.QtCore import QRectF, QSize, Qt, Signal
3from PySide6.QtGui import QColor, QPainter, QPen
4from PySide6.QtWidgets import QAbstractButton, QHBoxLayout, QWidget
6from graphica.gui import theme
9class ColorChip(QAbstractButton):
10 """角丸の色の見本。選んでいる色は、面の色のすき間の外に強調の色の輪を付ける。"""
12 def __init__(self, color, size=20, parent=None):
13 super().__init__(parent)
14 self.color = QColor(color)
15 self._size = size
16 self.setCheckable(True)
17 self.setCursor(Qt.CursorShape.PointingHandCursor)
18 self.setToolTip(self.color.name().upper())
19 self.setFixedSize(size + 8, size + 8)
21 def sizeHint(self):
22 return QSize(self._size + 8, self._size + 8)
24 def paintEvent(self, event):
25 tokens = theme.current_tokens()
26 painter = QPainter(self)
27 painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
28 inner = QRectF(4, 4, self._size, self._size)
29 if self.isChecked():
30 ring = QPen(QColor(tokens["accent"]))
31 ring.setWidthF(2.0)
32 painter.setPen(ring)
33 painter.setBrush(Qt.BrushStyle.NoBrush)
34 painter.drawRoundedRect(inner.adjusted(-3, -3, 3, 3), 8, 8)
35 edge = QColor(tokens["text_primary"])
36 edge.setAlphaF(0.12)
37 painter.setPen(QPen(edge, 1))
38 painter.setBrush(self.color)
39 painter.drawRoundedRect(inner, 6, 6)
40 painter.end()
43class ColorChipRow(QWidget):
44 """色のチップを並べる。押すと colorPicked(#RRGGBB) を出す(どれを選んでいるかは set_current_color で合わせる)。
46 幅が足りないときは入るだけ並べ、残りは隠す(最小幅を 0 にして、フォームの行が折り返されないように)。
47 """
49 colorPicked = Signal(str)
51 def __init__(self, colors=(), chip_size=20, parent=None):
52 super().__init__(parent)
53 self._chip_size = chip_size
54 layout = QHBoxLayout(self)
55 layout.setContentsMargins(0, 0, 0, 0)
56 layout.setSpacing(0)
57 self.chips = []
58 self.set_colors(colors)
60 def set_colors(self, colors):
61 layout = self.layout()
62 while layout.count():
63 item = layout.takeAt(0)
64 if item.widget() is not None:
65 item.widget().deleteLater()
66 self.chips = []
67 for color in colors:
68 chip = ColorChip(color, self._chip_size, self)
69 chip.clicked.connect(lambda _checked=False, c=chip: self._on_chip_clicked(c))
70 layout.addWidget(chip)
71 self.chips.append(chip)
72 layout.addStretch(1)
73 self._fit_chips()
75 def minimumSizeHint(self):
76 return QSize(0, self._chip_size + 8)
78 def resizeEvent(self, event):
79 super().resizeEvent(event)
80 self._fit_chips()
82 def _fit_chips(self):
83 cell = self._chip_size + 8
84 fits = max(0, self.width() // cell)
85 for index, chip in enumerate(self.chips):
86 chip.setVisible(index < fits)
88 def colors(self):
89 return [chip.color.name().upper() for chip in self.chips]
91 def set_current_color(self, color):
92 target = QColor(color).name().upper() if color else None
93 for chip in self.chips:
94 chip.setChecked(chip.color.name().upper() == target)
96 def _on_chip_clicked(self, chip):
97 self.set_current_color(chip.color.name())
98 self.colorPicked.emit(chip.color.name().upper())