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

1"""右のインスペクタ: 下線のタブ(プロパティ・軸・凡例・エクスポート)と、選んでいるデータセットの見出し。 

2 

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) 

8 

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 

12 

13INSPECTOR_WIDTH = 340 

14# (キー, タブの名前)。並びは見本どおり 

15INSPECTOR_PAGES = (("properties", "プロパティ"), ("axes", "軸"), ("legend", "凡例"), ("export", "エクスポート")) 

16 

17 

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 

26 

27 

28def wrap_long_rows(widget): 

29 """中の QFormLayout を、入らない行は名前を上・欄を下に折り返す形にする(幅 340px に収めるため)。""" 

30 for form in widget.findChildren(QFormLayout): 

31 form.setRowWrapPolicy(QFormLayout.RowWrapPolicy.WrapLongRows) 

32 

33 

34class TargetHeader(QWidget): 

35 """選んでいるデータセットの見出し: 線の見本・名前・「時間_s → 温度_degC · Line」。""" 

36 

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) 

56 

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}") 

68 

69 

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 } 

86 

87 

88class Inspector(QWidget): 

89 """下線のタブと、タブごとのページ。""" 

90 

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) 

116 

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)) 

121 

122 def page_index(self, key): 

123 return self._keys.index(key) 

124 

125 def show_page(self, key): 

126 self.tab_bar.setCurrentIndex(self.page_index(key)) 

127 

128 def current_page(self): 

129 index = self.tab_bar.currentIndex() 

130 return self._keys[index] if 0 <= index < len(self._keys) else None 

131 

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) 

138 

139 def is_page_visible(self, key): 

140 return self.tab_bar.isTabVisible(self.page_index(key))