graphica-plot 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- graphica/Graphica.ico +0 -0
- graphica/__init__.py +1 -0
- graphica/__main__.py +111 -0
- graphica/assets/__init__.py +0 -0
- graphica/assets/icons/__init__.py +0 -0
- graphica/assets/icons/arrow-right.svg +21 -0
- graphica/assets/icons/bold.svg +20 -0
- graphica/assets/icons/calculator.svg +26 -0
- graphica/assets/icons/chart-histogram.svg +24 -0
- graphica/assets/icons/chart-line.svg +20 -0
- graphica/assets/icons/chevron-down.svg +19 -0
- graphica/assets/icons/chevron-right.svg +19 -0
- graphica/assets/icons/color-swatch.svg +22 -0
- graphica/assets/icons/column-insert-right.svg +21 -0
- graphica/assets/icons/column-remove.svg +21 -0
- graphica/assets/icons/copy.svg +20 -0
- graphica/assets/icons/download.svg +21 -0
- graphica/assets/icons/edit.svg +21 -0
- graphica/assets/icons/eye-off.svg +21 -0
- graphica/assets/icons/eye.svg +20 -0
- graphica/assets/icons/file-plus.svg +22 -0
- graphica/assets/icons/folder-plus.svg +21 -0
- graphica/assets/icons/folder.svg +19 -0
- graphica/assets/icons/highlight.svg +22 -0
- graphica/assets/icons/history.svg +20 -0
- graphica/assets/icons/italic.svg +21 -0
- graphica/assets/icons/layout-grid.svg +22 -0
- graphica/assets/icons/math-function.svg +22 -0
- graphica/assets/icons/message-2.svg +21 -0
- graphica/assets/icons/mountain.svg +20 -0
- graphica/assets/icons/palette.svg +22 -0
- graphica/assets/icons/pointer.svg +19 -0
- graphica/assets/icons/refresh.svg +20 -0
- graphica/assets/icons/row-insert-bottom.svg +21 -0
- graphica/assets/icons/row-remove.svg +21 -0
- graphica/assets/icons/search.svg +20 -0
- graphica/assets/icons/select-all.svg +35 -0
- graphica/assets/icons/subscript.svg +20 -0
- graphica/assets/icons/superscript.svg +20 -0
- graphica/assets/icons/table.svg +21 -0
- graphica/assets/icons/trash.svg +23 -0
- graphica/assets/icons/typography.svg +23 -0
- graphica/assets/icons/x.svg +20 -0
- graphica/core/__init__.py +0 -0
- graphica/core/analysis.py +1278 -0
- graphica/core/app_paths.py +35 -0
- graphica/core/axis_settings.py +128 -0
- graphica/core/caption_export.py +47 -0
- graphica/core/color_palettes.py +56 -0
- graphica/core/commands.py +226 -0
- graphica/core/cvd_simulation.py +49 -0
- graphica/core/dataset.py +443 -0
- graphica/core/diagnostics.py +105 -0
- graphica/core/excel_utils.py +58 -0
- graphica/core/fit_models.py +379 -0
- graphica/core/grid_data.py +128 -0
- graphica/core/i18n.py +44 -0
- graphica/core/json_utils.py +27 -0
- graphica/core/label_utils.py +21 -0
- graphica/core/methods_text.py +115 -0
- graphica/core/named_colors.py +126 -0
- graphica/core/plugin_api.py +515 -0
- graphica/core/plugin_context.py +167 -0
- graphica/core/plugin_install.py +82 -0
- graphica/core/plugin_manifest.py +67 -0
- graphica/core/plugin_testing.py +213 -0
- graphica/core/plugin_types.py +118 -0
- graphica/core/provenance.py +19 -0
- graphica/core/report_export.py +51 -0
- graphica/core/safe_eval.py +194 -0
- graphica/core/script_export.py +272 -0
- graphica/core/translations_en.py +530 -0
- graphica/core/unit_conversion.py +51 -0
- graphica/core/update_check.py +43 -0
- graphica/core/version.py +14 -0
- graphica/gui/__init__.py +0 -0
- graphica/gui/app_settings.py +119 -0
- graphica/gui/axis_bindings.py +173 -0
- graphica/gui/binding.py +135 -0
- graphica/gui/builders/__init__.py +1 -0
- graphica/gui/builders/axis_panel.py +431 -0
- graphica/gui/builders/canvas_area.py +176 -0
- graphica/gui/builders/common.py +120 -0
- graphica/gui/builders/dataset_panel.py +433 -0
- graphica/gui/builders/property_sections.py +208 -0
- graphica/gui/canvas.py +519 -0
- graphica/gui/color_history.py +47 -0
- graphica/gui/color_picker_widget.py +198 -0
- graphica/gui/crash_handler.py +77 -0
- graphica/gui/cvd_preview.py +23 -0
- graphica/gui/data_editor.py +761 -0
- graphica/gui/data_import_flow.py +355 -0
- graphica/gui/dataset_bindings.py +107 -0
- graphica/gui/dataset_style_icon.py +80 -0
- graphica/gui/datasets/__init__.py +1 -0
- graphica/gui/datasets/actions_menu.py +114 -0
- graphica/gui/datasets/colors.py +218 -0
- graphica/gui/datasets/fitting.py +70 -0
- graphica/gui/datasets/host.py +162 -0
- graphica/gui/datasets/operations/__init__.py +1 -0
- graphica/gui/datasets/operations/fitting.py +468 -0
- graphica/gui/datasets/operations/peaks.py +109 -0
- graphica/gui/datasets/operations/processing.py +659 -0
- graphica/gui/datasets/operations/runner.py +148 -0
- graphica/gui/datasets/operations/transfer.py +227 -0
- graphica/gui/datasets/order.py +310 -0
- graphica/gui/datasets/overlays.py +74 -0
- graphica/gui/datasets/peaks.py +21 -0
- graphica/gui/datasets/plugin_runs.py +99 -0
- graphica/gui/datasets/processing.py +68 -0
- graphica/gui/datasets/property_panel.py +538 -0
- graphica/gui/datasets/transfer.py +36 -0
- graphica/gui/detached_canvas_window.py +22 -0
- graphica/gui/dialogs/__init__.py +137 -0
- graphica/gui/dialogs/analysis.py +1322 -0
- graphica/gui/dialogs/app.py +1015 -0
- graphica/gui/dialogs/appearance.py +851 -0
- graphica/gui/dialogs/data_edit.py +577 -0
- graphica/gui/dialogs/data_import.py +679 -0
- graphica/gui/dialogs/export.py +433 -0
- graphica/gui/dock_layout.py +176 -0
- graphica/gui/export_preview_panel.py +321 -0
- graphica/gui/export_settings.py +16 -0
- graphica/gui/file_association.py +97 -0
- graphica/gui/icon_utils.py +44 -0
- graphica/gui/main_app_window.py +210 -0
- graphica/gui/main_window.py +1151 -0
- graphica/gui/mathtext_preview.py +168 -0
- graphica/gui/menu_bar.py +320 -0
- graphica/gui/minimap_widget.py +151 -0
- graphica/gui/mixins/__init__.py +0 -0
- graphica/gui/mixins/export_mixin.py +520 -0
- graphica/gui/mixins/help_mixin.py +127 -0
- graphica/gui/mixins/project_io_mixin.py +289 -0
- graphica/gui/mixins/quick_access_mixin.py +194 -0
- graphica/gui/mixins/ui_setup_mixin.py +206 -0
- graphica/gui/notify.py +61 -0
- graphica/gui/panels/__init__.py +43 -0
- graphica/gui/panels/axis_settings.py +605 -0
- graphica/gui/panels/dataset_tree.py +424 -0
- graphica/gui/plot_type_drawers.py +131 -0
- graphica/gui/plugin_context.py +119 -0
- graphica/gui/project_files.py +361 -0
- graphica/gui/provenance_panel.py +65 -0
- graphica/gui/rendering/__init__.py +1 -0
- graphica/gui/rendering/annotations.py +177 -0
- graphica/gui/rendering/appearance.py +368 -0
- graphica/gui/rendering/common.py +316 -0
- graphica/gui/rendering/data_1d.py +376 -0
- graphica/gui/rendering/data_2d.py +66 -0
- graphica/gui/residual_panel.py +62 -0
- graphica/gui/resources.py +16 -0
- graphica/gui/single_instance.py +141 -0
- graphica/gui/splash.py +83 -0
- graphica/gui/task_runner.py +41 -0
- graphica/gui/theme.py +864 -0
- graphica/gui/tools/__init__.py +56 -0
- graphica/gui/tools/annotation.py +275 -0
- graphica/gui/tools/cursor.py +259 -0
- graphica/gui/tools/layout_edit.py +285 -0
- graphica/gui/tools/manager.py +78 -0
- graphica/gui/tools/peak_placement.py +132 -0
- graphica/gui/tools/range_select.py +191 -0
- graphica/gui/tools/region_highlight.py +222 -0
- graphica/gui/tools/slice_extraction.py +200 -0
- graphica/gui/widget_translation.py +46 -0
- graphica/gui/workers.py +280 -0
- graphica/models/__init__.py +0 -0
- graphica/models/project.py +197 -0
- graphica/plugin/__init__.py +20 -0
- graphica/plugin/testing.py +57 -0
- graphica/sample_data/__init__.py +0 -0
- graphica/sample_data/cooling_curve_sample.csv +42 -0
- graphica/ui_main_window.py +581 -0
- graphica_plot-2.0.0.dist-info/METADATA +317 -0
- graphica_plot-2.0.0.dist-info/RECORD +181 -0
- graphica_plot-2.0.0.dist-info/WHEEL +5 -0
- graphica_plot-2.0.0.dist-info/entry_points.txt +2 -0
- graphica_plot-2.0.0.dist-info/licenses/LICENSE +30 -0
- graphica_plot-2.0.0.dist-info/licenses/THIRD_PARTY_LICENSES.md +91 -0
- graphica_plot-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""画面の組み立てで共有する定数と小さな部品。main_window からも同じ名前で読める。"""
|
|
2
|
+
import os
|
|
3
|
+
from PySide6.QtCore import QRectF, Qt, Signal
|
|
4
|
+
from PySide6.QtGui import QPainter, QPainterPath
|
|
5
|
+
from PySide6.QtWidgets import QStyle, QStyleOptionViewItem, QStyledItemDelegate
|
|
6
|
+
from graphica.core.i18n import tr
|
|
7
|
+
from graphica.gui import theme
|
|
8
|
+
from graphica.gui.icon_utils import ICONS_DIR, load_svg_icon
|
|
9
|
+
from graphica.gui.mathtext_preview import FitWidthPixmapLabel
|
|
10
|
+
from graphica.gui.resources import resource_path
|
|
11
|
+
|
|
12
|
+
EXPORT_PREVIEW_DOCK_INITIAL_HEIGHT = 340
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# 列番号は dataset_mixin も使うので gui/dataset_style_icon.py にある(循環 import を避けるため)
|
|
16
|
+
DATASET_TREE_VISIBILITY_COLUMN_WIDTH = 26 # 目のアイコン(16px)+クリックの余白
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# ドックの既定の配置を変えたら上げる。保存時の値と違えば保存済みの配置を戻さない
|
|
20
|
+
# (戻すと、新しい既定の配置が既存の利用者に届かない)。
|
|
21
|
+
DOCK_LAYOUT_VERSION = 4
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# データセットのプロパティ欄の節。行は self._prop_form(キー).addRow で足す(番号指定の挿入はしない)。
|
|
25
|
+
DATASET_PROPERTY_SECTIONS = (
|
|
26
|
+
('data', 'データ列'),
|
|
27
|
+
('style', '基本スタイル'),
|
|
28
|
+
('gradient', 'グラデーション'),
|
|
29
|
+
('waterfall', 'ウォーターフォール'),
|
|
30
|
+
('map', '2Dマップ・値による配色'),
|
|
31
|
+
('extra', '表示の追加要素'),
|
|
32
|
+
('place', '配置・情報'),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# プラグインの種類名は任意の長さなので、コンボの希望幅を固定して省略表示させる
|
|
37
|
+
# (広がると QFormLayout の列幅を通じてドックに横スクロールバーが出る)。
|
|
38
|
+
PLOT_TYPE_COMBO_MIN_CHARS = 16
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
COLORMAP_CHOICES = [
|
|
42
|
+
'viridis', 'plasma', 'inferno', 'magma', 'cividis',
|
|
43
|
+
'coolwarm', 'RdBu', 'seismic', 'jet', 'turbo',
|
|
44
|
+
'gray', 'Blues', 'Greens', 'Reds', 'YlOrRd',
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Qt 既定の 24px だと、狭いウィンドウでボタンが「>>」に押し込まれて押せない
|
|
49
|
+
TOOLBAR_ICON_SIZE = 18
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _svg_icon(name, size=20):
|
|
53
|
+
"""テーマの text_secondary 色で描いたアイコン。テーマが変わっても自動では変わらない
|
|
54
|
+
|
|
55
|
+
(常に見えているものは _refresh_custom_svg_icons で作り直す)。
|
|
56
|
+
"""
|
|
57
|
+
from graphica.gui import theme
|
|
58
|
+
color = theme.current_tokens()["text_secondary"]
|
|
59
|
+
return load_svg_icon(resource_path(os.path.join(ICONS_DIR, f"{name}.svg")),
|
|
60
|
+
color=color, size=size)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class _DatasetTreeSelectionDelegate(QStyledItemDelegate):
|
|
64
|
+
"""選択の背景を、アイコンの列と文字の列にまたがる1つの角丸で描く。
|
|
65
|
+
|
|
66
|
+
QSS の ::item:selected は2つの列に別々の角丸を描き、間に隙間ができる。背景だけ自前で塗り、
|
|
67
|
+
State_Selected を外してから標準の描画に任せる。
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def paint(self, painter, option, index):
|
|
71
|
+
opt = QStyleOptionViewItem(option)
|
|
72
|
+
self.initStyleOption(opt, index)
|
|
73
|
+
|
|
74
|
+
if opt.state & QStyle.StateFlag.State_Selected:
|
|
75
|
+
painter.save()
|
|
76
|
+
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
|
|
77
|
+
# 展開矢印の字下げの分だけ左が空くので、左端まで塗る(字下げの列には何も描かれない)
|
|
78
|
+
rect = QRectF(opt.rect)
|
|
79
|
+
rect.setLeft(0)
|
|
80
|
+
path = QPainterPath()
|
|
81
|
+
path.addRoundedRect(
|
|
82
|
+
rect, theme.DATASET_LIST_ITEM_RADIUS, theme.DATASET_LIST_ITEM_RADIUS
|
|
83
|
+
)
|
|
84
|
+
painter.fillPath(path, theme.current_selection_highlight_qcolor())
|
|
85
|
+
painter.restore()
|
|
86
|
+
# 標準の選択の背景を重ねないよう落とす(文字とアイコンの色は選択で変わらない)
|
|
87
|
+
opt.state &= ~QStyle.StateFlag.State_Selected
|
|
88
|
+
|
|
89
|
+
super().paint(painter, opt, index)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class _ClickableMathPreviewLabel(FitWidthPixmapLabel):
|
|
93
|
+
"""タイトルと軸ラベルの欄。mathtext を描いたプレビューで、クリックで編集ダイアログを開く。
|
|
94
|
+
|
|
95
|
+
値は隠した元の QLineEdit が持つ(textChanged もそちらから出る)。
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
clicked = Signal()
|
|
99
|
+
|
|
100
|
+
def __init__(self, parent=None):
|
|
101
|
+
super().__init__(parent)
|
|
102
|
+
self.setObjectName("mathtext_preview_label")
|
|
103
|
+
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
104
|
+
self.setMinimumHeight(28)
|
|
105
|
+
self.setToolTip(tr("クリックして編集"))
|
|
106
|
+
# QLabel は既定でホバーを追跡せず、QSS の :hover が効かない
|
|
107
|
+
self.setAttribute(Qt.WidgetAttribute.WA_Hover, True)
|
|
108
|
+
|
|
109
|
+
def mousePressEvent(self, event):
|
|
110
|
+
if event.button() == Qt.MouseButton.LeftButton:
|
|
111
|
+
self.clicked.emit()
|
|
112
|
+
super().mousePressEvent(event)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _insert_form_row_after(form, anchor, *row):
|
|
116
|
+
"""form の anchor(ラベルか欄)の行の次に入れる。行番号で入れると、ほかの挿入の順番が変わったときに黙って別の位置に入る。"""
|
|
117
|
+
anchor_row, _ = form.getWidgetPosition(anchor)
|
|
118
|
+
if anchor_row < 0:
|
|
119
|
+
raise ValueError(f"{anchor!r} は {form.objectName()} にありません")
|
|
120
|
+
form.insertRow(anchor_row + 1, *row)
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
"""データセットの一覧とプロパティ欄の欄の組み立て。"""
|
|
2
|
+
from PySide6.QtCore import Qt
|
|
3
|
+
from PySide6.QtGui import QFont
|
|
4
|
+
from PySide6.QtWidgets import (
|
|
5
|
+
QAbstractItemView, QCheckBox, QComboBox, QDoubleSpinBox, QFormLayout, QFrame, QGridLayout, QGroupBox, QHeaderView,
|
|
6
|
+
QLabel, QLineEdit,
|
|
7
|
+
QMenu, QPushButton, QSpinBox, QTextEdit, QToolButton, QTreeWidget, QVBoxLayout, QWidget, QWidgetAction)
|
|
8
|
+
from graphica.core.i18n import tr
|
|
9
|
+
from graphica.gui.builders.common import (
|
|
10
|
+
COLORMAP_CHOICES, DATASET_TREE_VISIBILITY_COLUMN_WIDTH, _DatasetTreeSelectionDelegate, _insert_form_row_after,
|
|
11
|
+
_svg_icon)
|
|
12
|
+
from graphica.gui.color_picker_widget import ColorPickerWidget
|
|
13
|
+
from graphica.gui.dataset_style_icon import DATASET_TREE_NAME_COLUMN, DATASET_TREE_VISIBILITY_COLUMN
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def build_dataset_color_picker(app):
|
|
17
|
+
old_color_button = app.ui.color_button
|
|
18
|
+
app.color_picker_widget = ColorPickerWidget(app.settings, app)
|
|
19
|
+
app.ui.formLayout_4.replaceWidget(old_color_button, app.color_picker_widget)
|
|
20
|
+
old_color_button.hide()
|
|
21
|
+
old_color_button.deleteLater()
|
|
22
|
+
|
|
23
|
+
# 「データ追加」のすぐ隣
|
|
24
|
+
app.new_dataset_button = QPushButton(tr("新規データセット作成..."))
|
|
25
|
+
app.ui.horizontalLayout_3.insertWidget(1, app.new_dataset_button)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def build_dataset_list_buttons(app):
|
|
29
|
+
app.duplicate_dataset_button = QPushButton(tr("プロット複製"))
|
|
30
|
+
app.view_edit_data_button = QPushButton(tr("データ表示/編集"))
|
|
31
|
+
app.fit_curve_button = QPushButton(tr("曲線フィット"))
|
|
32
|
+
app.find_peaks_button = QPushButton(tr("ピーク検出"))
|
|
33
|
+
app.multi_peak_fit_button = QPushButton(tr("多峰フィット"))
|
|
34
|
+
app.auto_color_button = QPushButton(tr("自動配色"))
|
|
35
|
+
app.new_folder_button = QPushButton(tr("新しいフォルダ"))
|
|
36
|
+
|
|
37
|
+
# ボタンをアイコンだけにして「データ処理」「解析」「整理」の3組に分ける(文字はツールチップに残す)。
|
|
38
|
+
# ダークモードの切り替えでアイコンを作り直すので(_refresh_custom_svg_icons)、対応を持っておく
|
|
39
|
+
app._dataset_action_button_icons = {
|
|
40
|
+
app.ui.add_dataset_button: ("file-plus", tr("データ追加")),
|
|
41
|
+
app.new_dataset_button: ("table", tr("新規作成")),
|
|
42
|
+
app.duplicate_dataset_button: ("copy", tr("複製")),
|
|
43
|
+
app.view_edit_data_button: ("edit", tr("表示/編集")),
|
|
44
|
+
app.ui.remove_dataset_button: ("trash", tr("削除")),
|
|
45
|
+
app.fit_curve_button: ("chart-line", tr("曲線フィット")),
|
|
46
|
+
app.find_peaks_button: ("mountain", tr("ピーク検出")),
|
|
47
|
+
app.multi_peak_fit_button: ("chart-histogram", tr("多峰フィット")),
|
|
48
|
+
app.auto_color_button: ("palette", tr("自動配色")),
|
|
49
|
+
app.new_folder_button: ("folder-plus", tr("新しいフォルダ")),
|
|
50
|
+
}
|
|
51
|
+
for button, (icon_name, short_label) in app._dataset_action_button_icons.items():
|
|
52
|
+
button.setToolTip(button.text() or short_label)
|
|
53
|
+
button.setText("")
|
|
54
|
+
button.setIcon(_svg_icon(icon_name, size=18))
|
|
55
|
+
button.setProperty("iconOnly", True)
|
|
56
|
+
button.setFixedSize(34, 34)
|
|
57
|
+
# フォーカスを持つと、押した後も :focus の枠が残って押されたままに見える
|
|
58
|
+
button.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
|
59
|
+
|
|
60
|
+
def _make_group_separator():
|
|
61
|
+
sep = QFrame()
|
|
62
|
+
sep.setFrameShape(QFrame.Shape.VLine)
|
|
63
|
+
sep.setObjectName("button_row_separator")
|
|
64
|
+
sep.setFixedWidth(2)
|
|
65
|
+
return sep
|
|
66
|
+
|
|
67
|
+
# データ処理: 追加・新規作成・複製・表示編集・削除(削除は Designer の配置のまま)
|
|
68
|
+
app.ui.horizontalLayout_3.insertWidget(2, app.duplicate_dataset_button)
|
|
69
|
+
app.ui.horizontalLayout_3.insertWidget(3, app.view_edit_data_button)
|
|
70
|
+
|
|
71
|
+
app.ui.horizontalLayout_3.insertWidget(5, _make_group_separator())
|
|
72
|
+
# 解析
|
|
73
|
+
app.ui.horizontalLayout_3.addWidget(app.fit_curve_button)
|
|
74
|
+
app.ui.horizontalLayout_3.addWidget(app.find_peaks_button)
|
|
75
|
+
app.ui.horizontalLayout_3.addWidget(app.multi_peak_fit_button)
|
|
76
|
+
|
|
77
|
+
app.ui.horizontalLayout_3.addWidget(_make_group_separator())
|
|
78
|
+
# 整理
|
|
79
|
+
app.ui.horizontalLayout_3.addWidget(app.auto_color_button)
|
|
80
|
+
app.ui.horizontalLayout_3.addWidget(app.new_folder_button)
|
|
81
|
+
|
|
82
|
+
app.ui.horizontalLayout_3.addStretch()
|
|
83
|
+
|
|
84
|
+
# 「⋯」: たまにしか使わない操作
|
|
85
|
+
app.dataset_overflow_button = QToolButton()
|
|
86
|
+
app.dataset_overflow_button.setText("⋯")
|
|
87
|
+
app.dataset_overflow_button.setToolTip(tr("その他の操作"))
|
|
88
|
+
app.dataset_overflow_button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
|
89
|
+
app.dataset_overflow_button.setFixedSize(34, 34)
|
|
90
|
+
overflow_menu = QMenu(app.dataset_overflow_button)
|
|
91
|
+
app.manage_palette_action = overflow_menu.addAction(
|
|
92
|
+
_svg_icon("palette", size=16), tr("パレット管理...")
|
|
93
|
+
)
|
|
94
|
+
app.colormap_assign_action = overflow_menu.addAction(
|
|
95
|
+
_svg_icon("palette", size=16), tr("カラーマップから自動配色...")
|
|
96
|
+
)
|
|
97
|
+
# 登録はいつでも変わるので開くたびに作り直す。QMenu と menuAction() の両方を持つ(持たないと回収される)
|
|
98
|
+
app._named_color_apply_menu = overflow_menu.addMenu(
|
|
99
|
+
_svg_icon("color-swatch", size=16), tr("登録した色を適用"))
|
|
100
|
+
app._named_color_apply_menu_action = app._named_color_apply_menu.menuAction()
|
|
101
|
+
app._named_color_apply_menu.aboutToShow.connect(
|
|
102
|
+
app.colors.populate_named_color_menu)
|
|
103
|
+
app.colors.populate_named_color_menu()
|
|
104
|
+
app.dataset_overflow_button.setMenu(overflow_menu)
|
|
105
|
+
app.ui.horizontalLayout_3.addWidget(app.dataset_overflow_button)
|
|
106
|
+
|
|
107
|
+
# データセットのプロパティ欄を7つの節に分ける。Designer の行もここで移すので、formLayout_4 を触る
|
|
108
|
+
# 色欄の差し替え(_build_dataset_color_picker)より後であること。以降の行は app._prop_form(キー) に足す
|
|
109
|
+
app._build_dataset_property_sections()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def build_dataset_style_controls(app):
|
|
113
|
+
app.x_col_combo = QComboBox()
|
|
114
|
+
app.y_col_combo = QComboBox()
|
|
115
|
+
app._prop_form('data').addRow("X軸の列", app.x_col_combo)
|
|
116
|
+
app._prop_form('data').addRow("Y軸の列", app.y_col_combo)
|
|
117
|
+
|
|
118
|
+
app.x_err_col_combo = QComboBox()
|
|
119
|
+
app.y_err_col_combo = QComboBox()
|
|
120
|
+
app._prop_form('data').addRow("X誤差列", app.x_err_col_combo)
|
|
121
|
+
app._prop_form('data').addRow("Y誤差列", app.y_err_col_combo)
|
|
122
|
+
|
|
123
|
+
app.alpha_label = QLabel("透明度")
|
|
124
|
+
app.alpha_spinbox = QDoubleSpinBox()
|
|
125
|
+
app.alpha_spinbox.setRange(0.0, 1.0)
|
|
126
|
+
app.alpha_spinbox.setSingleStep(0.05)
|
|
127
|
+
app.alpha_spinbox.setDecimals(2)
|
|
128
|
+
app.alpha_spinbox.setValue(1.0)
|
|
129
|
+
app._prop_form('style').addRow(app.alpha_label, app.alpha_spinbox)
|
|
130
|
+
|
|
131
|
+
# グラデーション(線・面の塗り)。出し入れは property_panel.update_gradient_controls_visibility
|
|
132
|
+
app.gradient_checkbox = QCheckBox(tr("グラデーションを適用"))
|
|
133
|
+
app._prop_form('gradient').addRow(app.gradient_checkbox)
|
|
134
|
+
|
|
135
|
+
app.gradient_color2_label = QLabel(tr("終端色"))
|
|
136
|
+
app.gradient_color2_picker = ColorPickerWidget(app.settings, app, initial_color='#ffffff')
|
|
137
|
+
app._prop_form('gradient').addRow(app.gradient_color2_label, app.gradient_color2_picker)
|
|
138
|
+
|
|
139
|
+
app.gradient_target_label = QLabel(tr("対象"))
|
|
140
|
+
app.gradient_target_combo = QComboBox()
|
|
141
|
+
app.gradient_target_combo.addItem(tr("線"), "line")
|
|
142
|
+
app.gradient_target_combo.addItem(tr("塗り"), "fill")
|
|
143
|
+
app.gradient_target_combo.addItem(tr("両方"), "both")
|
|
144
|
+
app._prop_form('gradient').addRow(app.gradient_target_label, app.gradient_target_combo)
|
|
145
|
+
|
|
146
|
+
# ウォーターフォールは種類ではなく、どの種類とも組み合わせられるオプション。
|
|
147
|
+
# 出し入れは property_panel.update_waterfall_controls_visibility
|
|
148
|
+
app.waterfall_checkbox = QCheckBox(tr("ウォーターフォール表示(積み重ね)"))
|
|
149
|
+
app._prop_form('waterfall').addRow(app.waterfall_checkbox)
|
|
150
|
+
|
|
151
|
+
app.waterfall_offset_x_label = QLabel(tr("Xオフセット"))
|
|
152
|
+
app.waterfall_offset_x_spinbox = QDoubleSpinBox()
|
|
153
|
+
app.waterfall_offset_x_spinbox.setRange(-1e6, 1e6)
|
|
154
|
+
app.waterfall_offset_x_spinbox.setSingleStep(0.1)
|
|
155
|
+
app.waterfall_offset_x_spinbox.setDecimals(4)
|
|
156
|
+
app.waterfall_offset_x_spinbox.setValue(0.0)
|
|
157
|
+
app._prop_form('waterfall').addRow(app.waterfall_offset_x_label, app.waterfall_offset_x_spinbox)
|
|
158
|
+
|
|
159
|
+
app.waterfall_offset_y_label = QLabel(tr("Yオフセット"))
|
|
160
|
+
app.waterfall_offset_y_spinbox = QDoubleSpinBox()
|
|
161
|
+
app.waterfall_offset_y_spinbox.setRange(-1e6, 1e6)
|
|
162
|
+
app.waterfall_offset_y_spinbox.setSingleStep(0.1)
|
|
163
|
+
app.waterfall_offset_y_spinbox.setDecimals(4)
|
|
164
|
+
app.waterfall_offset_y_spinbox.setValue(1.0)
|
|
165
|
+
app._prop_form('waterfall').addRow(app.waterfall_offset_y_label, app.waterfall_offset_y_spinbox)
|
|
166
|
+
|
|
167
|
+
app.waterfall_occlusion_checkbox = QCheckBox(tr("背面のトレースを隠す(オクルージョン)"))
|
|
168
|
+
app.waterfall_occlusion_checkbox.setChecked(True)
|
|
169
|
+
app._prop_form('waterfall').addRow(app.waterfall_occlusion_checkbox)
|
|
170
|
+
|
|
171
|
+
# 奥の段ほど Y をわずかに縮めて立体風にする
|
|
172
|
+
app.waterfall_depth_checkbox = QCheckBox(tr("奥行き効果(奥のトレースをわずかに縮小)"))
|
|
173
|
+
app.waterfall_depth_checkbox.setChecked(False)
|
|
174
|
+
app._prop_form('waterfall').addRow(app.waterfall_depth_checkbox)
|
|
175
|
+
|
|
176
|
+
app.waterfall_depth_ratio_label = QLabel(tr("1段あたりの縮小率"))
|
|
177
|
+
app.waterfall_depth_ratio_spinbox = QDoubleSpinBox()
|
|
178
|
+
app.waterfall_depth_ratio_spinbox.setRange(0.0, 0.9)
|
|
179
|
+
app.waterfall_depth_ratio_spinbox.setSingleStep(0.01)
|
|
180
|
+
app.waterfall_depth_ratio_spinbox.setDecimals(3)
|
|
181
|
+
app.waterfall_depth_ratio_spinbox.setValue(0.03)
|
|
182
|
+
app._prop_form('waterfall').addRow(app.waterfall_depth_ratio_label, app.waterfall_depth_ratio_spinbox)
|
|
183
|
+
|
|
184
|
+
app.point_labels_checkbox = QCheckBox("データ点にラベルを表示")
|
|
185
|
+
app._prop_form('extra').addRow(app.point_labels_checkbox)
|
|
186
|
+
# 点が上限を超えてラベルを描かないときに、その理由を出す
|
|
187
|
+
app.point_labels_limit_note = QLabel()
|
|
188
|
+
app.point_labels_limit_note.setObjectName("point_labels_limit_note")
|
|
189
|
+
app.point_labels_limit_note.setWordWrap(True)
|
|
190
|
+
app.point_labels_limit_note.setVisible(False)
|
|
191
|
+
app._prop_form('extra').addRow(app.point_labels_limit_note)
|
|
192
|
+
app.point_label_col_label = QLabel("ラベルの内容")
|
|
193
|
+
app.point_label_col_combo = QComboBox()
|
|
194
|
+
app._prop_form('extra').addRow(app.point_label_col_label, app.point_label_col_combo)
|
|
195
|
+
|
|
196
|
+
# 誤差の表し方。誤差列が無ければどれを選んでも描かれない
|
|
197
|
+
app.error_display_label = QLabel(tr("誤差の表示形式"))
|
|
198
|
+
app.error_display_combo = QComboBox()
|
|
199
|
+
app.error_display_combo.addItem(tr("エラーバー"), "bar")
|
|
200
|
+
app.error_display_combo.addItem(tr("誤差バンド"), "band")
|
|
201
|
+
app.error_display_combo.addItem(tr("両方"), "both")
|
|
202
|
+
app._prop_form('extra').addRow(app.error_display_label, app.error_display_combo)
|
|
203
|
+
|
|
204
|
+
# X/Y/Z 列の長形式を2Dマップとして描く。関係する欄の出し入れは property_panel.update_2d_controls_visibility
|
|
205
|
+
app.data_2d_checkbox = QCheckBox(tr("2Dグリッドデータとして扱う(ヒートマップ)"))
|
|
206
|
+
app._prop_form('map').addRow(app.data_2d_checkbox)
|
|
207
|
+
|
|
208
|
+
app.z_col_label = QLabel(tr("Z軸の列"))
|
|
209
|
+
app.z_col_combo = QComboBox()
|
|
210
|
+
app._prop_form('map').addRow(app.z_col_label, app.z_col_combo)
|
|
211
|
+
|
|
212
|
+
app.colormap_label = QLabel(tr("カラーマップ"))
|
|
213
|
+
app.colormap_combo = QComboBox()
|
|
214
|
+
app.colormap_combo.addItems(COLORMAP_CHOICES)
|
|
215
|
+
app._prop_form('map').addRow(app.colormap_label, app.colormap_combo)
|
|
216
|
+
|
|
217
|
+
app.map_display_mode_label = QLabel(tr("表示方式"))
|
|
218
|
+
app.map_display_mode_combo = QComboBox()
|
|
219
|
+
app.map_display_mode_combo.addItem(tr("ヒートマップ"), "heatmap")
|
|
220
|
+
app.map_display_mode_combo.addItem(tr("等高線(線)"), "contour")
|
|
221
|
+
app.map_display_mode_combo.addItem(tr("等高線(塗りつぶし)"), "contour_filled")
|
|
222
|
+
app.map_display_mode_combo.addItem(tr("ヒートマップ+等高線"), "heatmap_contour")
|
|
223
|
+
app._prop_form('map').addRow(app.map_display_mode_label, app.map_display_mode_combo)
|
|
224
|
+
|
|
225
|
+
app.contour_levels_label = QLabel(tr("等高線レベル数"))
|
|
226
|
+
app.contour_levels_spinbox = QSpinBox()
|
|
227
|
+
app.contour_levels_spinbox.setRange(2, 100)
|
|
228
|
+
app.contour_levels_spinbox.setValue(10)
|
|
229
|
+
app._prop_form('map').addRow(app.contour_levels_label, app.contour_levels_spinbox)
|
|
230
|
+
|
|
231
|
+
app.grid_interp_method_label = QLabel(tr("補間方法"))
|
|
232
|
+
app.grid_interp_method_combo = QComboBox()
|
|
233
|
+
app.grid_interp_method_combo.addItems(['linear', 'cubic', 'nearest'])
|
|
234
|
+
app._prop_form('map').addRow(app.grid_interp_method_label, app.grid_interp_method_combo)
|
|
235
|
+
|
|
236
|
+
app.color_range_auto_checkbox = QCheckBox(tr("値域を自動"))
|
|
237
|
+
app.color_range_auto_checkbox.setChecked(True)
|
|
238
|
+
app._prop_form('map').addRow(app.color_range_auto_checkbox)
|
|
239
|
+
|
|
240
|
+
app.vmin_label = QLabel(tr("値域の最小"))
|
|
241
|
+
app.vmin_spinbox = QDoubleSpinBox()
|
|
242
|
+
app.vmin_spinbox.setRange(-1e12, 1e12)
|
|
243
|
+
app.vmin_spinbox.setDecimals(4)
|
|
244
|
+
app.vmin_spinbox.setEnabled(False)
|
|
245
|
+
app._prop_form('map').addRow(app.vmin_label, app.vmin_spinbox)
|
|
246
|
+
|
|
247
|
+
app.vmax_label = QLabel(tr("値域の最大"))
|
|
248
|
+
app.vmax_spinbox = QDoubleSpinBox()
|
|
249
|
+
app.vmax_spinbox.setRange(-1e12, 1e12)
|
|
250
|
+
app.vmax_spinbox.setDecimals(4)
|
|
251
|
+
app.vmax_spinbox.setValue(1.0)
|
|
252
|
+
app.vmax_spinbox.setEnabled(False)
|
|
253
|
+
app._prop_form('map').addRow(app.vmax_label, app.vmax_spinbox)
|
|
254
|
+
|
|
255
|
+
# 欠損値の扱いは描くときだけに効く(データ自体は変えない)。
|
|
256
|
+
# ラベルの列幅は全部の節で揃えるので、ここが一番長いと全体の入力欄が狭まる。「(NaN)」はツールチップに回す
|
|
257
|
+
app.nan_policy_label = QLabel(tr("欠損値の扱い"))
|
|
258
|
+
app.nan_policy_label.setToolTip(tr("欠損値(NaN)を含む点の描画方法"))
|
|
259
|
+
app.nan_policy_combo = QComboBox()
|
|
260
|
+
app.nan_policy_combo.addItem(tr("線を切る(既定)"), "gap")
|
|
261
|
+
app.nan_policy_combo.addItem(tr("前の値で埋める"), "ffill")
|
|
262
|
+
app.nan_policy_combo.addItem(tr("無視してつなぐ"), "drop")
|
|
263
|
+
app._prop_form('data').addRow(app.nan_policy_label, app.nan_policy_combo)
|
|
264
|
+
|
|
265
|
+
# 平滑化の手法。オン/オフは Designer の smoothing_checkbox
|
|
266
|
+
app.smoothing_method_label = QLabel(tr("平滑化の手法"))
|
|
267
|
+
app.smoothing_method_combo = QComboBox()
|
|
268
|
+
app.smoothing_method_combo.addItem(tr("CubicSpline(既定)"), "cubic_spline")
|
|
269
|
+
app.smoothing_method_combo.addItem(tr("移動平均"), "moving_average")
|
|
270
|
+
app.smoothing_method_combo.addItem(tr("中央値フィルタ"), "median")
|
|
271
|
+
app.smoothing_method_combo.addItem(tr("ガウシアンフィルタ"), "gaussian")
|
|
272
|
+
# 「平滑化」のチェックは手法と対なので、_build_dataset_property_sections では移さずここで手法の直前に置く
|
|
273
|
+
# (そうしないと間に「透明度」が挟まる)
|
|
274
|
+
app._prop_form('style').addRow(app.ui.smoothing_checkbox)
|
|
275
|
+
app._prop_form('style').addRow(app.smoothing_method_label, app.smoothing_method_combo)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def build_fit_info_and_stats(app):
|
|
279
|
+
app.fit_info_label = QLabel("フィット情報")
|
|
280
|
+
app.fit_info_textedit = QTextEdit()
|
|
281
|
+
app.fit_info_textedit.setReadOnly(True)
|
|
282
|
+
app.fit_info_textedit.setFixedHeight(100)
|
|
283
|
+
# 節の最後(描画先の後ろ)に置く(_add_subplot_target_row)。フィットが無いと隠れる欄なので、
|
|
284
|
+
# 先頭に置くとフィットのたびに下の項目が押し下げられる
|
|
285
|
+
|
|
286
|
+
# 統計値はいつも見るものではないので、ツールバーのボタンから開く小窓に出す。
|
|
287
|
+
# 中身は選択が変わるたびに property_panel.update_stats_summary_label が更新する(閉じている間も)
|
|
288
|
+
app.stats_summary_label = QLabel("-")
|
|
289
|
+
app.stats_summary_label.setWordWrap(True)
|
|
290
|
+
app.stats_summary_label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
|
291
|
+
|
|
292
|
+
app.stats_toolbar_button = QToolButton()
|
|
293
|
+
app.stats_toolbar_button.setIcon(_svg_icon("chart-histogram"))
|
|
294
|
+
app.stats_toolbar_button.setToolTip(tr("統計情報 (選択中データセットのY列の要約統計量)"))
|
|
295
|
+
app.stats_toolbar_button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
|
|
296
|
+
|
|
297
|
+
stats_popup = QWidget()
|
|
298
|
+
stats_popup_layout = QVBoxLayout(stats_popup)
|
|
299
|
+
stats_popup_layout.setContentsMargins(10, 8, 10, 8)
|
|
300
|
+
stats_popup_title = QLabel(tr("統計 (Y列)"))
|
|
301
|
+
stats_popup_title_font = QFont(stats_popup_title.font())
|
|
302
|
+
stats_popup_title_font.setBold(True)
|
|
303
|
+
stats_popup_title.setFont(stats_popup_title_font)
|
|
304
|
+
stats_popup_layout.addWidget(stats_popup_title)
|
|
305
|
+
app.stats_summary_label.setMinimumWidth(260)
|
|
306
|
+
stats_popup_layout.addWidget(app.stats_summary_label)
|
|
307
|
+
|
|
308
|
+
stats_menu = QMenu(app.stats_toolbar_button)
|
|
309
|
+
stats_widget_action = QWidgetAction(app.stats_toolbar_button)
|
|
310
|
+
stats_widget_action.setDefaultWidget(stats_popup)
|
|
311
|
+
stats_menu.addAction(stats_widget_action)
|
|
312
|
+
app.stats_toolbar_button.setMenu(stats_menu)
|
|
313
|
+
app.mpl_toolbar.addSeparator()
|
|
314
|
+
app.mpl_toolbar.addWidget(app.stats_toolbar_button)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _y2_value_spinbox(decimals=2):
|
|
318
|
+
spinbox = QDoubleSpinBox()
|
|
319
|
+
spinbox.setRange(-2147483648.0, 2147483648.0)
|
|
320
|
+
spinbox.setDecimals(decimals)
|
|
321
|
+
return spinbox
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def _build_secondary_y_axis_group(app):
|
|
325
|
+
"""「Y軸」タブの末尾に、第 2 Y 軸の範囲と目盛りの欄を足す(主の Y 軸の欄と同じ並び)。"""
|
|
326
|
+
app.y2_axis_group = QGroupBox(tr("第2Y軸"))
|
|
327
|
+
form = QFormLayout(app.y2_axis_group)
|
|
328
|
+
app.y2_autoscale_checkbox = QCheckBox(tr("自動スケール"))
|
|
329
|
+
app.y2_autoscale_checkbox.setChecked(True)
|
|
330
|
+
form.addRow(app.y2_autoscale_checkbox)
|
|
331
|
+
app.y2_min_spinbox = _y2_value_spinbox()
|
|
332
|
+
form.addRow(tr("最小値"), app.y2_min_spinbox)
|
|
333
|
+
app.y2_max_spinbox = _y2_value_spinbox()
|
|
334
|
+
app.y2_max_spinbox.setValue(1.0)
|
|
335
|
+
form.addRow(tr("最大値"), app.y2_max_spinbox)
|
|
336
|
+
app.y2_log_checkbox = QCheckBox(tr("対数表示"))
|
|
337
|
+
form.addRow(app.y2_log_checkbox)
|
|
338
|
+
app.y2_invert_checkbox = QCheckBox(tr("軸を反転"))
|
|
339
|
+
form.addRow(app.y2_invert_checkbox)
|
|
340
|
+
app.y2_major_tick_mode_combo = QComboBox()
|
|
341
|
+
# 選んだ番号で値を持つ(index の束ね)ので、表示を訳してよい
|
|
342
|
+
app.y2_major_tick_mode_combo.addItems([tr("自動"), tr("固定間隔")])
|
|
343
|
+
form.addRow(tr("主目盛"), app.y2_major_tick_mode_combo)
|
|
344
|
+
app.y2_major_tick_interval_spinbox = _y2_value_spinbox()
|
|
345
|
+
app.y2_major_tick_interval_spinbox.setValue(1.0)
|
|
346
|
+
form.addRow(tr("間隔"), app.y2_major_tick_interval_spinbox)
|
|
347
|
+
app.y2_minor_ticks_visible_checkbox = QCheckBox(tr("補助目盛を表示"))
|
|
348
|
+
form.addRow(app.y2_minor_ticks_visible_checkbox)
|
|
349
|
+
app.y2_minor_tick_interval_spinbox = _y2_value_spinbox()
|
|
350
|
+
app.y2_minor_tick_interval_spinbox.setValue(0.5)
|
|
351
|
+
form.addRow(tr("補助目盛の間隔"), app.y2_minor_tick_interval_spinbox)
|
|
352
|
+
layout = app.ui.gridLayout_3
|
|
353
|
+
layout.addWidget(app.y2_axis_group, layout.rowCount(), 0, 1, layout.columnCount() or 1)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def build_secondary_y_controls(app):
|
|
357
|
+
app.use_secondary_y_checkbox = QCheckBox("第2Y軸 (右側) を使用")
|
|
358
|
+
app._prop_form('place').addRow(app.use_secondary_y_checkbox)
|
|
359
|
+
|
|
360
|
+
app.y2_label_text_label = QLabel("第2Y軸ラベル")
|
|
361
|
+
app.y2_label_text_edit = QLineEdit()
|
|
362
|
+
_insert_form_row_after(app.ui.formLayout_3, app.ui.y_label_text_edit,
|
|
363
|
+
app.y2_label_text_label, app.y2_label_text_edit)
|
|
364
|
+
|
|
365
|
+
_build_secondary_y_axis_group(app)
|
|
366
|
+
|
|
367
|
+
def add_subplot_target_row(app):
|
|
368
|
+
app.subplot_target_label = QLabel("描画先プロット")
|
|
369
|
+
app.subplot_target_combo = QComboBox()
|
|
370
|
+
app._prop_form('place').addRow(app.subplot_target_label, app.subplot_target_combo)
|
|
371
|
+
# フィット情報欄 (上で構築済み) は、このセクションの最後に置く
|
|
372
|
+
app._prop_form('place').addRow(app.fit_info_label, app.fit_info_textedit)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def replace_dataset_list_with_tree(app):
|
|
376
|
+
"""Designer の QListWidget を、同じセルに「検索欄 + QTreeWidget」を縦に並べたものへ差し替える。"""
|
|
377
|
+
old_widget = app.ui.dataset_list_widget
|
|
378
|
+
parent_widget = old_widget.parentWidget()
|
|
379
|
+
parent_layout = parent_widget.layout()
|
|
380
|
+
|
|
381
|
+
idx = parent_layout.indexOf(old_widget)
|
|
382
|
+
row = col = rowspan = colspan = None
|
|
383
|
+
if isinstance(parent_layout, QGridLayout):
|
|
384
|
+
row, col, rowspan, colspan = parent_layout.getItemPosition(idx)
|
|
385
|
+
|
|
386
|
+
parent_layout.removeWidget(old_widget)
|
|
387
|
+
old_widget.setParent(None)
|
|
388
|
+
old_widget.deleteLater()
|
|
389
|
+
|
|
390
|
+
container = QWidget(parent_widget)
|
|
391
|
+
container_layout = QVBoxLayout(container)
|
|
392
|
+
container_layout.setContentsMargins(0, 0, 0, 0)
|
|
393
|
+
container_layout.setSpacing(6)
|
|
394
|
+
|
|
395
|
+
search_edit = QLineEdit(container)
|
|
396
|
+
search_edit.setObjectName("dataset_search_edit")
|
|
397
|
+
search_edit.setPlaceholderText("データセットを検索...")
|
|
398
|
+
search_edit.setClearButtonEnabled(True)
|
|
399
|
+
container_layout.addWidget(search_edit)
|
|
400
|
+
|
|
401
|
+
tree = QTreeWidget(container)
|
|
402
|
+
tree.setObjectName("dataset_list_widget")
|
|
403
|
+
tree.setHeaderHidden(True)
|
|
404
|
+
# 列1は表示/非表示の目のアイコン。stretchLastSection のままだと目の列が余白を吸って広がる
|
|
405
|
+
tree.setColumnCount(2)
|
|
406
|
+
header = tree.header()
|
|
407
|
+
header.setStretchLastSection(False)
|
|
408
|
+
header.setSectionResizeMode(DATASET_TREE_NAME_COLUMN, QHeaderView.ResizeMode.Stretch)
|
|
409
|
+
header.setSectionResizeMode(DATASET_TREE_VISIBILITY_COLUMN, QHeaderView.ResizeMode.Fixed)
|
|
410
|
+
tree.setColumnWidth(DATASET_TREE_VISIBILITY_COLUMN, DATASET_TREE_VISIBILITY_COLUMN_WIDTH)
|
|
411
|
+
tree.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
|
412
|
+
tree.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
|
|
413
|
+
tree.setDefaultDropAction(Qt.DropAction.MoveAction)
|
|
414
|
+
tree.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
|
415
|
+
# 行の伸びをキャンバスに譲ったので、放っておくと数件でも窮屈な高さまで縮む
|
|
416
|
+
tree.setMinimumHeight(90)
|
|
417
|
+
tree.setItemDelegate(_DatasetTreeSelectionDelegate(tree))
|
|
418
|
+
container_layout.addWidget(tree)
|
|
419
|
+
|
|
420
|
+
# 一覧のすぐ下に、選んでいるデータセットの短い統計値
|
|
421
|
+
mini_stats_label = QLabel("-")
|
|
422
|
+
mini_stats_label.setObjectName("dataset_mini_stats_label")
|
|
423
|
+
mini_stats_label.setWordWrap(True)
|
|
424
|
+
container_layout.addWidget(mini_stats_label)
|
|
425
|
+
app.dataset_mini_stats_label = mini_stats_label
|
|
426
|
+
|
|
427
|
+
if isinstance(parent_layout, QGridLayout) and row is not None:
|
|
428
|
+
parent_layout.addWidget(container, row, col, rowspan, colspan)
|
|
429
|
+
else:
|
|
430
|
+
parent_layout.addWidget(container)
|
|
431
|
+
|
|
432
|
+
app.ui.dataset_list_widget = tree
|
|
433
|
+
app.dataset_search_edit = search_edit
|