ms-components 0.3.1__tar.gz → 0.3.3__tar.gz
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.
- {ms_components-0.3.1/src/ms_components.egg-info → ms_components-0.3.3}/PKG-INFO +1 -1
- ms_components-0.3.3/src/ms_components/backdrop.py +34 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/base.qss +37 -4
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_dockwidget/widget.py +4 -1
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_settings/panel.py +3 -2
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/cell_delegate.py +36 -24
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/query_builder.py +6 -4
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/smart_table_view.py +25 -10
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/table_config.py +10 -1
- ms_components-0.3.3/src/ms_components/palettes.py +39 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/theme.py +98 -134
- {ms_components-0.3.1 → ms_components-0.3.3/src/ms_components.egg-info}/PKG-INFO +1 -1
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components.egg-info/SOURCES.txt +1 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components.egg-info/scm_file_list.json +1 -0
- ms_components-0.3.3/src/ms_components.egg-info/scm_version.json +8 -0
- ms_components-0.3.3/tests/test_progress_column.py +48 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_query_builder_keyset.py +54 -0
- ms_components-0.3.3/tests/test_theme_contrast.py +68 -0
- ms_components-0.3.1/src/ms_components/palettes.py +0 -29
- ms_components-0.3.1/src/ms_components.egg-info/scm_version.json +0 -8
- ms_components-0.3.1/tests/test_progress_column.py +0 -36
- ms_components-0.3.1/tests/test_theme_contrast.py +0 -31
- {ms_components-0.3.1 → ms_components-0.3.3}/.github/workflows/docs.yml +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/.github/workflows/publish.yml +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/.gitignore +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/LICENSE +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/README.md +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/docs/api_reference.md +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/docs/examples.md +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/docs/index.md +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/docs/ms_tutorial.md +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/docs/usage.md +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/examples/tutorial_demo.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/examples/tutorial_demo.toml +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/pyproject.toml +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/setup.cfg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/chips.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/listview.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_dockwidget/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_dockwidget/resources/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_dockwidget/resources/icons/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_dockwidget/resources/icons/folder.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_executors.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/bridge.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/cards.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/config.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/detail_panel.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/formatting.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/job_cards.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/models.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/palette.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/polling.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_monitor/widget.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_projects/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_projects/app.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_projects/browser.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_projects/scratch.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_projects/widget.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/actions.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/box.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/center.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/display.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/hide.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/menu.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/orient.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/presets.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/rock.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/selection.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/settings.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/icons/zoom.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/plugins.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_pymol/widget.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_settings/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_stepper.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/action_header.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/column_panel.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/example_usage.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/filter_panel.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/columns.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/export.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/filter.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/menu.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/reload.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/search.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/settings.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/sort-asc.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/sort-desc.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/icons/sort.svg +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/metric_filter_bar.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/pagination_control.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/session_provider.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/sort_panel.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/table_model.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/test_external_filters.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_table/test_toolbar.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_tutorial/__init__.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_tutorial/bindings.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_tutorial/controller.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_tutorial/models.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/ms_tutorial/overlay.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/opengl.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/pagination.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/step_dialog.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/tool_panel.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components/wheel.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components.egg-info/dependency_links.txt +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components.egg-info/requires.txt +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/src/ms_components.egg-info/top_level.txt +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_app_settings.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_chips.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_dock_window.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_executors_ui.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_molsuite_monitor_bridge.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_molsuite_monitor_widgets.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_monitor_config.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_ms_projects_widget.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_opengl.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_project_browser.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_pymol_grid.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_pymol_toolbar.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_shift_hscroll.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_split_button_style.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_step_dialog.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_table_toolbar.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_table_view_state.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/tests/test_tutorial.py +0 -0
- {ms_components-0.3.1 → ms_components-0.3.3}/zensical.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ms_components
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: PySide6 UI components for MolSuite: smart table, project browser, job monitor, PyMOL dock, steppers.
|
|
5
5
|
Author: Mario S. Valdés-Tresanco, Mario E. Valdés-Tresanco
|
|
6
6
|
License-Expression: MIT
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""A faint, centred icon painted under a widget's own children (welcome pages, empty states)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from PySide6.QtCore import QRect, QSize
|
|
6
|
+
from PySide6.QtGui import QIcon, QPainter
|
|
7
|
+
from PySide6.QtWidgets import QWidget
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Backdrop(QWidget):
|
|
11
|
+
"""``icon`` drawn at ``opacity``, scaled to 80 % of the shorter side; ``None`` draws nothing."""
|
|
12
|
+
|
|
13
|
+
# One fixed-size render, scaled: asking the icon for each widget size would cache a
|
|
14
|
+
# multi-MB pixmap per size (~1 GB after a long window resize with a caching icon engine).
|
|
15
|
+
RENDER_PX = 512
|
|
16
|
+
|
|
17
|
+
def __init__(self, icon: QIcon | None = None, parent: QWidget | None = None, *, opacity: float = 0.06):
|
|
18
|
+
super().__init__(parent)
|
|
19
|
+
self._icon = icon
|
|
20
|
+
self._opacity = opacity
|
|
21
|
+
|
|
22
|
+
def paintEvent(self, event) -> None:
|
|
23
|
+
if self._icon is not None:
|
|
24
|
+
side = int(min(self.width(), self.height()) * 0.8)
|
|
25
|
+
painter = QPainter(self)
|
|
26
|
+
painter.setOpacity(self._opacity)
|
|
27
|
+
painter.setRenderHint(QPainter.SmoothPixmapTransform)
|
|
28
|
+
painter.drawPixmap(QRect((self.width() - side) // 2, (self.height() - side) // 2, side, side),
|
|
29
|
+
self._icon.pixmap(QSize(self.RENDER_PX, self.RENDER_PX)))
|
|
30
|
+
painter.end()
|
|
31
|
+
super().paintEvent(event)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__all__ = ["Backdrop"]
|
|
@@ -64,6 +64,19 @@ QProgressBar#ToolProgress::chunk {
|
|
|
64
64
|
background: palette(highlight);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/* ms_table: a PROGRESS cell, a filled bar with its text on top. The fill color is
|
|
68
|
+
the `tone` property, from the theme accents (theme.tone_qss). The track is the
|
|
69
|
+
header tone: it keeps text contrast and stands out from the rows. */
|
|
70
|
+
QProgressBar#CellProgress {
|
|
71
|
+
border: none;
|
|
72
|
+
border-radius: 3px;
|
|
73
|
+
background: palette(dark);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
QProgressBar#CellProgress::chunk {
|
|
77
|
+
border-radius: 3px;
|
|
78
|
+
}
|
|
79
|
+
|
|
67
80
|
|
|
68
81
|
/* Left gap for the first tab: `tab-bar { left }` shifts the whole bar.
|
|
69
82
|
Do NOT use margins on ::tab -- Qt places the close button flush to the full
|
|
@@ -98,7 +111,8 @@ QTextEdit,
|
|
|
98
111
|
QSpinBox,
|
|
99
112
|
QDoubleSpinBox,
|
|
100
113
|
QComboBox {
|
|
101
|
-
|
|
114
|
+
/* shadow = the control edge (3:1 on every surface); mid stays for hairlines */
|
|
115
|
+
border: 1px solid palette(shadow);
|
|
102
116
|
border-radius: 4px;
|
|
103
117
|
padding: 3px 6px;
|
|
104
118
|
}
|
|
@@ -123,7 +137,7 @@ QComboBox:focus {
|
|
|
123
137
|
}
|
|
124
138
|
|
|
125
139
|
QPushButton {
|
|
126
|
-
border: 1px solid palette(
|
|
140
|
+
border: 1px solid palette(shadow);
|
|
127
141
|
border-radius: 4px;
|
|
128
142
|
padding: 5px 14px;
|
|
129
143
|
}
|
|
@@ -141,19 +155,38 @@ QPushButton:default {
|
|
|
141
155
|
border-color: palette(highlight);
|
|
142
156
|
}
|
|
143
157
|
|
|
158
|
+
QLineEdit:disabled,
|
|
159
|
+
QPlainTextEdit:disabled,
|
|
160
|
+
QTextEdit:disabled,
|
|
161
|
+
QSpinBox:disabled,
|
|
162
|
+
QDoubleSpinBox:disabled,
|
|
163
|
+
QComboBox:disabled,
|
|
164
|
+
QPushButton:disabled,
|
|
165
|
+
QToolButton[popupMode="MenuButtonPopup"]:disabled {
|
|
166
|
+
border-color: palette(mid);
|
|
167
|
+
}
|
|
168
|
+
|
|
144
169
|
/* A split button (QToolButton with a menu arrow) is an action button, not a toolbar icon:
|
|
145
170
|
framed like QPushButton, the arrow in its own segment. */
|
|
146
171
|
QToolButton[popupMode="MenuButtonPopup"] {
|
|
147
|
-
border: 1px solid palette(
|
|
172
|
+
border: 1px solid palette(shadow);
|
|
148
173
|
padding: 5px 14px;
|
|
149
174
|
padding-right: 24px;
|
|
150
175
|
}
|
|
151
176
|
|
|
152
177
|
QToolButton[popupMode="MenuButtonPopup"]::menu-button {
|
|
153
|
-
border-left: 1px solid palette(
|
|
178
|
+
border-left: 1px solid palette(shadow);
|
|
154
179
|
width: 18px;
|
|
155
180
|
}
|
|
156
181
|
|
|
182
|
+
/* Qt's own tooltip colours are a pale grey that dark themes leave unreadable. */
|
|
183
|
+
QToolTip {
|
|
184
|
+
background: palette(window);
|
|
185
|
+
color: palette(text);
|
|
186
|
+
border: 1px solid palette(highlight);
|
|
187
|
+
padding: 4px;
|
|
188
|
+
}
|
|
189
|
+
|
|
157
190
|
/* Card = content surface. Nav trees/lists stay flat unless opted in. */
|
|
158
191
|
QTableView,
|
|
159
192
|
QTreeView[card="true"],
|
|
@@ -734,7 +734,10 @@ class VerticalToolbar(QWidget):
|
|
|
734
734
|
yield w
|
|
735
735
|
|
|
736
736
|
def _layout_has_buttons(self, layout: QVBoxLayout) -> bool:
|
|
737
|
-
|
|
737
|
+
# Action buttons (no dock_id) count too: a section holding only those is not empty.
|
|
738
|
+
return any(
|
|
739
|
+
isinstance(layout.itemAt(i).widget(), QToolButton) for i in range(layout.count())
|
|
740
|
+
)
|
|
738
741
|
|
|
739
742
|
def _update_separator_visibility(self):
|
|
740
743
|
self._separator.setVisible(
|
|
@@ -311,8 +311,8 @@ class AppSettingsPanel(QWidget):
|
|
|
311
311
|
font-weight: 700;
|
|
312
312
|
}
|
|
313
313
|
QLabel#sourceDefault { color: palette(text); background: rgba(128, 128, 128, 0.18); }
|
|
314
|
-
QLabel#sourceGlobal {
|
|
315
|
-
QLabel#sourceProject {
|
|
314
|
+
QLabel#sourceGlobal { background: rgba(76, 155, 232, 0.16); }
|
|
315
|
+
QLabel#sourceProject { background: rgba(52, 200, 138, 0.16); }
|
|
316
316
|
"""
|
|
317
317
|
)
|
|
318
318
|
|
|
@@ -743,6 +743,7 @@ class AppSettingsPanel(QWidget):
|
|
|
743
743
|
normalized = source if source in _SOURCE_LABELS else "default"
|
|
744
744
|
label.setText(_SOURCE_LABELS[normalized])
|
|
745
745
|
label.setObjectName(f"source{normalized.title()}")
|
|
746
|
+
label.setProperty("tone", {"global": "blue", "project": "green"}.get(normalized, "")) # theme text hue
|
|
746
747
|
label.style().unpolish(label)
|
|
747
748
|
label.style().polish(label)
|
|
748
749
|
|
|
@@ -58,10 +58,10 @@ from __future__ import annotations
|
|
|
58
58
|
|
|
59
59
|
from typing import Any, Callable, Optional
|
|
60
60
|
|
|
61
|
-
from PySide6.QtCore import QModelIndex, QRect, QRectF, QSize, Qt
|
|
62
|
-
from PySide6.QtGui import QImage, QPainter,
|
|
61
|
+
from PySide6.QtCore import QModelIndex, QPoint, QRect, QRectF, QSize, Qt
|
|
62
|
+
from PySide6.QtGui import QImage, QPainter, QPixmap, QRegion
|
|
63
63
|
from PySide6.QtWidgets import (
|
|
64
|
-
QApplication, QStyle, QStyledItemDelegate, QStyleOptionViewItem,
|
|
64
|
+
QApplication, QProgressBar, QStyle, QStyledItemDelegate, QStyleOptionViewItem,
|
|
65
65
|
QWidget,
|
|
66
66
|
)
|
|
67
67
|
|
|
@@ -159,6 +159,8 @@ class CellWidgetDelegate(QStyledItemDelegate):
|
|
|
159
159
|
# Persistent widget cache: row → QWidget
|
|
160
160
|
# Invalidated when the page changes (load_data)
|
|
161
161
|
self._persistent_widgets: dict[int, QWidget] = {}
|
|
162
|
+
# PROGRESS cells: one hidden bar per tone, so the tone property is set once.
|
|
163
|
+
self._progress_bars: dict[str, QProgressBar] = {}
|
|
162
164
|
|
|
163
165
|
# ── Invalidate the cache on page change ───────────────────────────────
|
|
164
166
|
|
|
@@ -185,30 +187,40 @@ class CellWidgetDelegate(QStyledItemDelegate):
|
|
|
185
187
|
|
|
186
188
|
row_data = self._get_row_data(index)
|
|
187
189
|
|
|
188
|
-
# ── progress mode: a fraction 0..1 as the style's own progress bar ──
|
|
190
|
+
# ── progress mode: a fraction 0..1 (or value/max) as the style's own progress bar ──
|
|
189
191
|
if col_def.kind == ColumnKind.PROGRESS:
|
|
190
192
|
try:
|
|
191
|
-
|
|
193
|
+
value = float(row_data.get(col_def.display_key) or 0.0)
|
|
194
|
+
maximum = float(row_data.get(col_def.progress_max) or 0.0) if col_def.progress_max else 1.0
|
|
195
|
+
fraction = min(max(value / maximum, 0.0), 1.0) if maximum > 0 else 0.0
|
|
192
196
|
except (TypeError, ValueError):
|
|
193
|
-
fraction = 0.0
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
#
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
197
|
+
value, maximum, fraction = 0.0, 0.0, 0.0
|
|
198
|
+
text = f"{int(fraction * 100)}%" # floored: 99.9% is not "100%"
|
|
199
|
+
if col_def.progress_max:
|
|
200
|
+
text = f"{int(value):,}/{int(maximum):,} ({text})"
|
|
201
|
+
tone = col_def.progress_tone(row_data) if col_def.progress_tone else "green"
|
|
202
|
+
# A hidden QProgressBar paints the cell, so the bar is the native one and its look is
|
|
203
|
+
# QSS (`QProgressBar#CellProgress`, `[tone=...]`). render(), not drawControl(): under a
|
|
204
|
+
# stylesheet drawControl lays the chunk out from the widget, not from the option. Into a
|
|
205
|
+
# pixmap: rendered on the view's painter it ignores the viewport offset and lands under
|
|
206
|
+
# the headers.
|
|
207
|
+
bar = self._progress_bars.get(tone)
|
|
208
|
+
if bar is None:
|
|
209
|
+
bar = self._progress_bars[tone] = QProgressBar()
|
|
210
|
+
bar.setObjectName("CellProgress")
|
|
211
|
+
bar.setProperty("tone", tone)
|
|
212
|
+
bar.setRange(0, 1000)
|
|
213
|
+
bar.setAlignment(Qt.AlignCenter)
|
|
214
|
+
bar.setValue(int(fraction * 1000))
|
|
215
|
+
bar.setFormat(text)
|
|
216
|
+
rect = option.rect.adjusted(4, 5, -4, -5)
|
|
217
|
+
bar.resize(rect.size())
|
|
218
|
+
ratio = painter.device().devicePixelRatioF()
|
|
219
|
+
pixmap = QPixmap(rect.size() * ratio)
|
|
220
|
+
pixmap.setDevicePixelRatio(ratio)
|
|
221
|
+
pixmap.fill(Qt.transparent)
|
|
222
|
+
bar.render(pixmap, QPoint(), QRegion(), QWidget.DrawChildren)
|
|
223
|
+
painter.drawPixmap(rect.topLeft(), pixmap)
|
|
212
224
|
return
|
|
213
225
|
|
|
214
226
|
# ── paint_factory mode (SVG / image) ───────────────────────────────
|
|
@@ -234,11 +234,13 @@ class QueryBuilder:
|
|
|
234
234
|
attr = self._resolve_attr(sort.field)
|
|
235
235
|
if attr is None:
|
|
236
236
|
return pk > pk_value
|
|
237
|
+
# SQLite puts NULLs first ascending and last descending.
|
|
238
|
+
rest_of_nulls = and_(attr.is_(None), pk > pk_value)
|
|
237
239
|
if sort_value is None:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return or_(
|
|
240
|
+
return or_(attr.is_not(None), rest_of_nulls) if not sort.descending else rest_of_nulls
|
|
241
|
+
if sort.descending:
|
|
242
|
+
return or_(attr < sort_value, and_(attr == sort_value, pk > pk_value), attr.is_(None))
|
|
243
|
+
return or_(attr > sort_value, and_(attr == sort_value, pk > pk_value))
|
|
242
244
|
|
|
243
245
|
def fetch(self) -> tuple[list[dict], int]:
|
|
244
246
|
"""Run the query and return (rows_as_dicts, total_count)."""
|
|
@@ -57,7 +57,7 @@ from PySide6.QtWidgets import (
|
|
|
57
57
|
QHeaderView, QLabel, QMenu, QPushButton, QSizePolicy, QFrame,
|
|
58
58
|
QTableView, QToolBar, QToolButton, QVBoxLayout, QWidget
|
|
59
59
|
)
|
|
60
|
-
from ..
|
|
60
|
+
from ..backdrop import Backdrop
|
|
61
61
|
from .action_header import ActionHeader, FilterPopup, SearchPopup
|
|
62
62
|
from .cell_delegate import CellWidgetDelegate
|
|
63
63
|
from .column_panel import ColumnConfigDialog
|
|
@@ -154,6 +154,15 @@ class SmartTableView(QWidget):
|
|
|
154
154
|
self._infinite_total_hint = total
|
|
155
155
|
self._infinite_total_exact = True
|
|
156
156
|
self._infinite_has_more = self._infinite_loaded_end < total
|
|
157
|
+
tail = self._infinite_pages.get(self._infinite_frontier_page)
|
|
158
|
+
if tail is not None and len(tail) < self._builder.page_size and self._infinite_has_more:
|
|
159
|
+
# The last page came back short and rows were added since: forget it, so the
|
|
160
|
+
# autofill set_total() triggers fetches it again once it is in view. Kept, its
|
|
161
|
+
# rows past the old end would stay blank forever.
|
|
162
|
+
del self._infinite_pages[self._infinite_frontier_page]
|
|
163
|
+
# The next page's cursor is the short page's last row: wrong now, so it is
|
|
164
|
+
# found by offset instead.
|
|
165
|
+
self._infinite_page_cursors.pop(self._infinite_frontier_page + 1, None)
|
|
157
166
|
self._model.set_total(total)
|
|
158
167
|
return True
|
|
159
168
|
|
|
@@ -326,21 +335,26 @@ class SmartTableView(QWidget):
|
|
|
326
335
|
self._empty_label.setObjectName("EmptyLabel")
|
|
327
336
|
self._empty_label.setAlignment(Qt.AlignCenter)
|
|
328
337
|
action = self._config.empty_action
|
|
329
|
-
if action is None:
|
|
338
|
+
if action is None and self._config.empty_backdrop is None:
|
|
330
339
|
self._empty_widget = self._empty_label
|
|
331
340
|
else:
|
|
332
|
-
self._empty_widget =
|
|
341
|
+
self._empty_widget = Backdrop(self._config.empty_backdrop, opacity=0.08)
|
|
333
342
|
empty_layout = QVBoxLayout(self._empty_widget)
|
|
334
343
|
empty_layout.setAlignment(Qt.AlignCenter)
|
|
335
344
|
empty_layout.setSpacing(12)
|
|
345
|
+
self._empty_label.setStyleSheet("font-size: 16px;")
|
|
346
|
+
empty_layout.addWidget(self._empty_label)
|
|
347
|
+
if action is not None:
|
|
336
348
|
button = QPushButton(action.label)
|
|
337
349
|
button.setObjectName("EmptyActionButton")
|
|
338
350
|
if action.icon is not None:
|
|
339
351
|
button.setIcon(action.icon)
|
|
340
352
|
button.setToolTip(action.tooltip or action.label)
|
|
353
|
+
button.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
354
|
+
button.setStyleSheet("font-size: 15px; padding: 8px 24px;")
|
|
341
355
|
if action.on_click is not None:
|
|
342
356
|
button.clicked.connect(lambda _=False, cb=action.on_click: cb([]))
|
|
343
|
-
empty_layout.
|
|
357
|
+
empty_layout.addSpacing(16)
|
|
344
358
|
empty_layout.addWidget(button, alignment=Qt.AlignCenter)
|
|
345
359
|
self._empty_widget.setVisible(False)
|
|
346
360
|
root.addWidget(self._empty_widget, stretch=1)
|
|
@@ -749,8 +763,9 @@ class SmartTableView(QWidget):
|
|
|
749
763
|
self.load_next_page()
|
|
750
764
|
|
|
751
765
|
def _on_refresh_clicked(self):
|
|
752
|
-
# Reload this table
|
|
753
|
-
|
|
766
|
+
# Reload this table where the user is looking (scroll and selection kept), then let
|
|
767
|
+
# the host (e.g. DockingStudio) refresh surrounding state.
|
|
768
|
+
self.refresh_preserving_view()
|
|
754
769
|
self.refresh_clicked.emit()
|
|
755
770
|
|
|
756
771
|
# ──────────────────────────────────────────
|
|
@@ -839,14 +854,14 @@ class SmartTableView(QWidget):
|
|
|
839
854
|
def _apply_toolbar_chrome(self) -> None:
|
|
840
855
|
"""Paint the toolbar as a band so the actions read as chrome, not as content.
|
|
841
856
|
|
|
842
|
-
|
|
843
|
-
of
|
|
844
|
-
|
|
857
|
+
The header's tone (`dark`): window/base/alternate-base are within a couple of steps
|
|
858
|
+
of each other in the flat light themes, so they separate nothing. Re-applied on
|
|
859
|
+
PaletteChange, so it still follows a live theme switch.
|
|
845
860
|
"""
|
|
846
861
|
if self._toolbar_row is None:
|
|
847
862
|
return
|
|
848
863
|
self._toolbar_row.setStyleSheet(
|
|
849
|
-
|
|
864
|
+
"#SmartTableToolbar { background: palette(dark);"
|
|
850
865
|
" border-bottom: 1px solid palette(mid); }"
|
|
851
866
|
" QToolBar { background: transparent; border: 0; }"
|
|
852
867
|
)
|
|
@@ -70,7 +70,7 @@ class ColumnKind(str, Enum):
|
|
|
70
70
|
NUMBER = "number"
|
|
71
71
|
INTEGER = "integer"
|
|
72
72
|
CHOICE = "choice"
|
|
73
|
-
# A fraction 0..1 drawn as a progress bar with its percentage
|
|
73
|
+
# A fraction 0..1 (or a count, with `progress_max`) drawn as a progress bar with its percentage.
|
|
74
74
|
PROGRESS = "progress"
|
|
75
75
|
|
|
76
76
|
|
|
@@ -109,6 +109,11 @@ class ColumnDef:
|
|
|
109
109
|
expr: SQLAlchemy expression producing the column value, for anything
|
|
110
110
|
that is not a model attribute (JSON_EXTRACT, CASE, func.*).
|
|
111
111
|
When set, `field` is only the key/label.
|
|
112
|
+
progress_max: PROGRESS columns only: the row key holding the maximum. Set, the
|
|
113
|
+
value is a count and the bar reads "value/max (pct%)", as
|
|
114
|
+
QProgressBar's "%v/%m (%p%)"; unset, the value is a 0..1 fraction.
|
|
115
|
+
progress_tone: PROGRESS columns only: callable(row_data) → a theme accent
|
|
116
|
+
("green", "red"), the bar's `tone` property. Unset, "green".
|
|
112
117
|
"""
|
|
113
118
|
field: str
|
|
114
119
|
label: Optional[str] = None
|
|
@@ -130,6 +135,8 @@ class ColumnDef:
|
|
|
130
135
|
tooltip: Any = None # str | Callable
|
|
131
136
|
db_column: Optional[str] = None
|
|
132
137
|
expr: Any = None # SQLAlchemy ColumnElement
|
|
138
|
+
progress_max: Optional[str] = None
|
|
139
|
+
progress_tone: Optional[Callable] = None
|
|
133
140
|
|
|
134
141
|
# ── Fields for rendering widgets inside a cell ──────────────────────
|
|
135
142
|
#
|
|
@@ -370,6 +377,8 @@ class TableConfig:
|
|
|
370
377
|
# action (import, create), a button that triggers it is more useful than
|
|
371
378
|
# `empty_message`. When set it replaces the text. `on_click` receives [].
|
|
372
379
|
empty_action: Optional["ToolbarAction"] = None
|
|
380
|
+
# Faint illustration under the empty state (a QIcon; see ms_components.backdrop).
|
|
381
|
+
empty_backdrop: Optional[Any] = None
|
|
373
382
|
# (row_data: dict) -> QColor | None. Tints a whole row from host state that is not a
|
|
374
383
|
# column (a marked/selected set, a validation flag). None = leave the default painting.
|
|
375
384
|
row_background: Optional[Callable] = None
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""The color values of every theme, as data: no Qt, so a settings model can list their names.
|
|
2
|
+
|
|
3
|
+
Palette data from **qt-themes** by Beat Reichenbach (MIT, see `ms_components.theme`), stored
|
|
4
|
+
here per QPalette role and nudged to the contrast floors that `tests/test_theme_contrast.py`
|
|
5
|
+
enforces. How the keys become a QPalette: `ms_components.theme.build_palette`.
|
|
6
|
+
|
|
7
|
+
Keys are the QPalette roles in snake_case, so a value is exactly what `palette(role)` returns
|
|
8
|
+
in a stylesheet. What MolSuite asks of the roles Qt leaves loosely defined:
|
|
9
|
+
|
|
10
|
+
* ``mid``: hairlines (separators, frames, table and group borders). Decorative.
|
|
11
|
+
* ``shadow``: the edge of a control (field, button, checkbox, radio); >= 3:1 on every surface.
|
|
12
|
+
* ``dark``: table header surface. ``midlight``: thin progress tracks.
|
|
13
|
+
* ``placeholder_text``: muted text (hints, meta lines); >= 4.5:1, below the body text.
|
|
14
|
+
* ``disabled_text``: the Disabled group's text; dimmer than a hint, so "off" reads as off.
|
|
15
|
+
|
|
16
|
+
The hues (red, orange, yellow, green, cyan, blue, magenta) have no QPalette role: read them
|
|
17
|
+
with `ms_components.theme.color`. Each is >= 4.5:1 on the theme's surfaces, since they are
|
|
18
|
+
used as text (errors, warnings) as well as fills.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
# Auto mode picks these based on the OS color scheme.
|
|
23
|
+
DEFAULT_LIGHT = "github_light"
|
|
24
|
+
DEFAULT_DARK = "catppuccin_mocha"
|
|
25
|
+
|
|
26
|
+
THEMES: dict[str, dict[str, str]] = {
|
|
27
|
+
"catppuccin_frappe": {"window": "#303446", "window_text": "#c6d0f5", "base": "#292c3c", "alternate_base": "#303446", "tooltip_base": "#292c3c", "tooltip_text": "#949cbb", "placeholder_text": "#959dbb", "text": "#c6d0f5", "button": "#303446", "button_text": "#c6d0f5", "bright_text": "#08080a", "light": "#232634", "midlight": "#292c3c", "mid": "#626880", "dark": "#51576d", "shadow": "#777d97", "highlight": "#ca9ee6", "highlighted_text": "#232634", "link": "#8caaee", "link_visited": "#8caaee", "accent": "#8caaee", "disabled_text": "#6c728c", "red": "#e78284", "orange": "#ef9f76", "yellow": "#e5c890", "green": "#a6d189", "cyan": "#99d1db", "blue": "#8caaee", "magenta": "#ca9ee6"},
|
|
28
|
+
"catppuccin_latte": {"window": "#ccd0da", "window_text": "#4c4f69", "base": "#ffffff", "alternate_base": "#e6e9ef", "tooltip_base": "#e6e9ef", "tooltip_text": "#666879", "placeholder_text": "#555871", "text": "#4c4f69", "button": "#ccd0da", "button_text": "#4c4f69", "bright_text": "#6d7196", "light": "#ffffff", "midlight": "#e6e9ef", "mid": "#9ca0b0", "dark": "#bfc3ce", "shadow": "#70737f", "highlight": "#8839ef", "highlighted_text": "#ffffff", "link": "#094cd2", "link_visited": "#094cd2", "accent": "#094cd2", "disabled_text": "#7a7d92", "red": "#b30d31", "orange": "#9b3901", "yellow": "#7c4f10", "green": "#29661b", "cyan": "#025f83", "blue": "#094cd2", "magenta": "#7113ec"},
|
|
29
|
+
"catppuccin_macchiato": {"window": "#24273a", "window_text": "#cad3f5", "base": "#1e2030", "alternate_base": "#24273a", "tooltip_base": "#1e2030", "tooltip_text": "#939ab7", "placeholder_text": "#888eaa", "text": "#cad3f5", "button": "#24273a", "button_text": "#cad3f5", "bright_text": "#08090a", "light": "#181926", "midlight": "#1e2030", "mid": "#5b6078", "dark": "#494d64", "shadow": "#6e738d", "highlight": "#c6a0f6", "highlighted_text": "#181926", "link": "#8aadf4", "link_visited": "#8aadf4", "accent": "#8aadf4", "disabled_text": "#61677f", "red": "#ed8796", "orange": "#f5a97f", "yellow": "#eed49f", "green": "#a6da95", "cyan": "#91d7e3", "blue": "#8aadf4", "magenta": "#c6a0f6"},
|
|
30
|
+
"catppuccin_mocha": {"window": "#1e1e2e", "window_text": "#cdd6f4", "base": "#181825", "alternate_base": "#1e1e2e", "tooltip_base": "#181825", "tooltip_text": "#9399b2", "placeholder_text": "#82879f", "text": "#cdd6f4", "button": "#1e1e2e", "button_text": "#cdd6f4", "bright_text": "#090a0b", "light": "#11111b", "midlight": "#181825", "mid": "#585b70", "dark": "#45475a", "shadow": "#6c7086", "highlight": "#cba6f7", "highlighted_text": "#11111b", "link": "#89b4fa", "link_visited": "#89b4fa", "accent": "#89b4fa", "disabled_text": "#5d6075", "red": "#f38ba8", "orange": "#fab387", "yellow": "#f9e2af", "green": "#a6e3a1", "cyan": "#89dceb", "blue": "#89b4fa", "magenta": "#cba6f7"},
|
|
31
|
+
"dracula": {"window": "#2d2f3c", "window_text": "#f8f8f2", "base": "#282a36", "alternate_base": "#2d2f3c", "tooltip_base": "#282a36", "tooltip_text": "#9ea0a6", "placeholder_text": "#97989b", "text": "#f8f8f2", "button": "#2d2f3c", "button_text": "#f8f8f2", "bright_text": "#070707", "light": "#1d1b22", "midlight": "#282a36", "mid": "#44475a", "dark": "#474959", "shadow": "#767985", "highlight": "#bd93f9", "highlighted_text": "#1d1b22", "link": "#ff79c6", "link_visited": "#ff79c6", "accent": "#ff79c6", "disabled_text": "#6e6f76", "red": "#ff6262", "orange": "#ffb86c", "yellow": "#f1fa8c", "green": "#50fa7b", "cyan": "#8be9fd", "blue": "#8a96bb", "magenta": "#bd93f9"},
|
|
32
|
+
"github_dark": {"window": "#262c36", "window_text": "#d1d7e0", "base": "#212830", "alternate_base": "#262c36", "tooltip_base": "#212830", "tooltip_text": "#989ea7", "placeholder_text": "#8d939c", "text": "#d1d7e0", "button": "#262c36", "button_text": "#d1d7e0", "bright_text": "#1d1e1f", "light": "#151b23", "midlight": "#212830", "mid": "#5f656f", "dark": "#4c525c", "shadow": "#727882", "highlight": "#79c0ff", "highlighted_text": "#151b23", "link": "#79c0ff", "link_visited": "#79c0ff", "accent": "#79c0ff", "disabled_text": "#656b75", "red": "#ffa198", "orange": "#ffa657", "yellow": "#e3b341", "green": "#56d364", "cyan": "#68cab2", "blue": "#79c0ff", "magenta": "#d2a8ff"},
|
|
33
|
+
"github_light": {"window": "#f6f8fa", "window_text": "#1f2328", "base": "#ffffff", "alternate_base": "#fbfcfd", "tooltip_base": "#fbfcfd", "tooltip_text": "#444952", "placeholder_text": "#61666e", "text": "#1f2328", "button": "#f6f8fa", "button_text": "#1f2328", "bright_text": "#a7bcd7", "light": "#ffffff", "midlight": "#fbfcfd", "mid": "#9da1a6", "dark": "#bbbec2", "shadow": "#7f838a", "highlight": "#5a94c8", "highlighted_text": "#1f2328", "link": "#0071d5", "link_visited": "#0071d5", "accent": "#0071d5", "disabled_text": "#979a9e", "red": "#e21400", "orange": "#b85600", "yellow": "#8f6b15", "green": "#22822d", "cyan": "#2c7e6a", "blue": "#0071d5", "magenta": "#9838ff"},
|
|
34
|
+
"modern_dark": {"window": "#2a2a2a", "window_text": "#c8c8c8", "base": "#1f1f1f", "alternate_base": "#2a2a2a", "tooltip_base": "#1f1f1f", "tooltip_text": "#868686", "placeholder_text": "#919191", "text": "#c8c8c8", "button": "#2a2a2a", "button_text": "#c8c8c8", "bright_text": "#373737", "light": "#141414", "midlight": "#1f1f1f", "mid": "#424242", "dark": "#444444", "shadow": "#737373", "highlight": "#2aa5da", "highlighted_text": "#141414", "link": "#2ad7da", "link_visited": "#2ad7da", "accent": "#2ad7da", "disabled_text": "#696969", "red": "#e16f53", "orange": "#da8a2a", "yellow": "#d7da2a", "green": "#2ada6f", "cyan": "#2ad7da", "blue": "#2aa5da", "magenta": "#c06fe4"},
|
|
35
|
+
"modern_light": {"window": "#e6ebf0", "window_text": "#000000", "base": "#ffffff", "alternate_base": "#eef2f6", "tooltip_base": "#eef2f6", "tooltip_text": "#484b4d", "placeholder_text": "#626568", "text": "#000000", "button": "#e6ebf0", "button_text": "#000000", "bright_text": "#ffffff", "light": "#ffffff", "midlight": "#eef2f6", "mid": "#979b9f", "dark": "#b1b6ba", "shadow": "#7d8084", "highlight": "#2590be", "highlighted_text": "#000000", "link": "#157677", "link_visited": "#157677", "accent": "#157677", "disabled_text": "#8f9295", "red": "#bb3f20", "orange": "#945c1a", "yellow": "#6b6d13", "green": "#157a3d", "cyan": "#157677", "blue": "#1a7196", "magenta": "#a22ad7"},
|
|
36
|
+
"monokai": {"window": "#2d2a2e", "window_text": "#fcfcfa", "base": "#221f22", "alternate_base": "#2d2a2e", "tooltip_base": "#221f22", "tooltip_text": "#939293", "placeholder_text": "#939293", "text": "#fcfcfa", "button": "#2d2a2e", "button_text": "#fcfcfa", "bright_text": "#030303", "light": "#19181a", "midlight": "#221f22", "mid": "#5b595c", "dark": "#4e4c4f", "shadow": "#757375", "highlight": "#ffd866", "highlighted_text": "#19181a", "link": "#ff6188", "link_visited": "#ff6188", "accent": "#ff6188", "disabled_text": "#6b696b", "red": "#ff6188", "orange": "#fc9867", "yellow": "#ffd866", "green": "#a9dc76", "cyan": "#91dcaf", "blue": "#78dce8", "magenta": "#ab9df2"},
|
|
37
|
+
"nord": {"window": "#3b4252", "window_text": "#eceff4", "base": "#2e3440", "alternate_base": "#3b4252", "tooltip_base": "#2e3440", "tooltip_text": "#d8dee9", "placeholder_text": "#abafb8", "text": "#eceff4", "button": "#3b4252", "button_text": "#eceff4", "bright_text": "#0b0b0b", "light": "#2e3440", "midlight": "#2e3440", "mid": "#4c566a", "dark": "#525a6b", "shadow": "#878e9b", "highlight": "#81a1c1", "highlighted_text": "#2e3440", "link": "#88c0d0", "link_visited": "#88c0d0", "accent": "#88c0d0", "disabled_text": "#7c828e", "red": "#d89fa4", "orange": "#daa18f", "yellow": "#ebcb8b", "green": "#a3be8c", "cyan": "#88c0d0", "blue": "#97b2cc", "magenta": "#c3a5be"},
|
|
38
|
+
"one_dark_two": {"window": "#282c34", "window_text": "#e6e6e6", "base": "#21252b", "alternate_base": "#282c34", "tooltip_base": "#21252b", "tooltip_text": "#969dab", "placeholder_text": "#919296", "text": "#e6e6e6", "button": "#282c34", "button_text": "#e6e6e6", "bright_text": "#191919", "light": "#1d1f23", "midlight": "#21252b", "mid": "#5b626d", "dark": "#4a505a", "shadow": "#6f7583", "highlight": "#62bac6", "highlighted_text": "#1d1f23", "link": "#eac786", "link_visited": "#eac786", "accent": "#eac786", "disabled_text": "#696b71", "red": "#e27881", "orange": "#e79c7e", "yellow": "#eac786", "green": "#98c379", "cyan": "#62bac6", "blue": "#71b9f4", "magenta": "#c88bda"},
|
|
39
|
+
}
|