Coverage for graphica/gui/shell/inspector.py: 97.3%
101 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"""右のインスペクタ: 下線のタブ(プロパティ・軸・凡例・エクスポート)と、選んでいるデータセットの見出し。
3見本(docs/dev/mockups/gui_redesign/)では幅 340px。中身は今の部品をそのまま並べ直す(値の対応は変わらない)。
4"""
5from PySide6.QtCore import QSize, Qt
6from PySide6.QtWidgets import (QFormLayout, QHBoxLayout, QLabel, QScrollArea, QStackedWidget, QTabBar, QVBoxLayout,
7 QWidget)
9from graphica.core.i18n import tr
10from graphica.gui.dataset_bindings import MARKER_CHOICES, NO_MARKER
11from graphica.gui.dataset_style_icon import NON_MARKER_PLOT_TYPES, make_dataset_style_icon
13INSPECTOR_WIDTH = 340
14# (キー, タブの名前)。並びは見本どおり
15INSPECTOR_PAGES = (("properties", "プロパティ"), ("axes", "軸"), ("legend", "凡例"), ("export", "エクスポート"))
18def scroll_page(widget, object_name):
19 """縦だけスクロールする入れ物(横に出ると欄が切れるので、横のスクロールバーは出さない)。"""
20 scroll = QScrollArea()
21 scroll.setObjectName(object_name)
22 scroll.setWidgetResizable(True)
23 scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
24 scroll.setWidget(widget)
25 return scroll
28def wrap_long_rows(widget):
29 """中の QFormLayout を、入らない行は名前を上・欄を下に折り返す形にする(幅 340px に収めるため)。"""
30 for form in widget.findChildren(QFormLayout):
31 form.setRowWrapPolicy(QFormLayout.RowWrapPolicy.WrapLongRows)
34class TargetHeader(QWidget):
35 """選んでいるデータセットの見出し: 線の見本・名前・「時間_s → 温度_degC · Line」。"""
37 def __init__(self, parent=None):
38 super().__init__(parent)
39 self.setObjectName("inspector_target")
40 self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
41 layout = QHBoxLayout(self)
42 layout.setContentsMargins(16, 10, 16, 10)
43 layout.setSpacing(10)
44 self.swatch = QLabel()
45 self.swatch.setFixedWidth(24)
46 texts = QVBoxLayout()
47 texts.setSpacing(0)
48 self.name_label = QLabel("-")
49 self.name_label.setObjectName("inspector_target_name")
50 self.sub_label = QLabel("")
51 self.sub_label.setObjectName("inspector_target_sub")
52 texts.addWidget(self.name_label)
53 texts.addWidget(self.sub_label)
54 layout.addWidget(self.swatch)
55 layout.addLayout(texts, 1)
57 def set_dataset(self, dataset):
58 if dataset is None:
59 self.swatch.clear()
60 self.name_label.setText(tr("データセットを選んでください"))
61 self.sub_label.setText("")
62 return
63 self.swatch.setPixmap(make_dataset_style_icon(dataset).pixmap(QSize(24, 10)))
64 self.name_label.setText(dataset.name)
65 x_name = getattr(dataset, 'x_col_name', '') or ''
66 y_name = getattr(dataset, 'y_col_name', '') or ''
67 self.sub_label.setText(f"{x_name} → {y_name} · {dataset.plot_type}")
70def section_state_texts(dataset):
71 """閉じていても分かるよう、節の見出しの右に出す今の状態(節のキー -> 文字)。"""
72 if dataset is None:
73 return {}
74 marker_names = dict(MARKER_CHOICES)
75 if dataset.plot_type in NON_MARKER_PLOT_TYPES or dataset.marker in (NO_MARKER, None, ''):
76 marker = tr("なし")
77 else:
78 marker = tr(marker_names.get(dataset.marker, dataset.marker))
79 on, off = tr("オン"), tr("オフ")
80 return {
81 "marker": marker,
82 "gradient": on if dataset.gradient_enabled else off,
83 "waterfall": on if dataset.waterfall_enabled else off,
84 "map": "2D" if getattr(dataset, 'data_kind', '1d') == '2d_grid' else off,
85 }
88class Inspector(QWidget):
89 """下線のタブと、タブごとのページ。"""
91 def __init__(self, parent=None):
92 super().__init__(parent)
93 self.setObjectName("inspector")
94 self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
95 layout = QVBoxLayout(self)
96 layout.setContentsMargins(0, 0, 0, 0)
97 layout.setSpacing(0)
98 self.tab_bar = QTabBar()
99 self.tab_bar.setObjectName("inspector_tabs")
100 self.tab_bar.setDrawBase(False)
101 self.tab_bar.setExpanding(False)
102 self.tab_bar.setFocusPolicy(Qt.FocusPolicy.NoFocus)
103 tab_row = QHBoxLayout()
104 tab_row.setContentsMargins(16, 0, 16, 0)
105 tab_row.addWidget(self.tab_bar)
106 tab_row.addStretch(1)
107 tab_box = QWidget()
108 tab_box.setObjectName("inspector_tab_row")
109 tab_box.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
110 tab_box.setLayout(tab_row)
111 layout.addWidget(tab_box)
112 self.stack = QStackedWidget()
113 layout.addWidget(self.stack, 1)
114 self._keys = []
115 self.tab_bar.currentChanged.connect(self.stack.setCurrentIndex)
117 def add_page(self, key, title, widget):
118 self._keys.append(key)
119 self.stack.addWidget(widget)
120 self.tab_bar.addTab(tr(title))
122 def page_index(self, key):
123 return self._keys.index(key)
125 def show_page(self, key):
126 self.tab_bar.setCurrentIndex(self.page_index(key))
128 def current_page(self):
129 index = self.tab_bar.currentIndex()
130 return self._keys[index] if 0 <= index < len(self._keys) else None
132 def set_page_visible(self, key, visible):
133 """タブを見せる・隠す(アドバンスドだけの「凡例」)。隠したタブを開いていたら最初のタブへ。"""
134 index = self.page_index(key)
135 self.tab_bar.setTabVisible(index, visible)
136 if not visible and self.tab_bar.currentIndex() == index: 136 ↛ 137line 136 didn't jump to line 137 because the condition on line 136 was never true
137 self.tab_bar.setCurrentIndex(0)
139 def is_page_visible(self, key):
140 return self.tab_bar.isTabVisible(self.page_index(key))