cct-cli 0.7.9.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.
- calc_terminal/__init__.py +14 -0
- calc_terminal/__main__.py +14 -0
- calc_terminal/activity.py +1334 -0
- calc_terminal/agent.py +3387 -0
- calc_terminal/agent_runtime.py +519 -0
- calc_terminal/ai_context.py +447 -0
- calc_terminal/ai_modes.py +752 -0
- calc_terminal/ai_personalization.py +286 -0
- calc_terminal/ai_preview_feedback.py +213 -0
- calc_terminal/aicore.py +2572 -0
- calc_terminal/anim.py +367 -0
- calc_terminal/app.py +3685 -0
- calc_terminal/art.py +639 -0
- calc_terminal/atomsim.py +368 -0
- calc_terminal/attachments.py +743 -0
- calc_terminal/benchmark_system.py +414 -0
- calc_terminal/browser/__init__.py +36 -0
- calc_terminal/browser/browser_state.py +346 -0
- calc_terminal/browser/devserver.py +176 -0
- calc_terminal/browser/engine.py +494 -0
- calc_terminal/browser/navigation.py +84 -0
- calc_terminal/browser/preview.py +429 -0
- calc_terminal/browser/preview_entry.py +95 -0
- calc_terminal/browser/project_detector.py +144 -0
- calc_terminal/browser/server.py +449 -0
- calc_terminal/browser/state.py +75 -0
- calc_terminal/browser/watcher.py +99 -0
- calc_terminal/browser_gui/__init__.py +1 -0
- calc_terminal/browser_gui/__main__.py +3 -0
- calc_terminal/browser_gui/launcher.py +173 -0
- calc_terminal/browser_gui/playwright_browser.py +117 -0
- calc_terminal/browser_gui/qt_browser.py +1501 -0
- calc_terminal/browser_gui/webview_browser.py +57 -0
- calc_terminal/capabilities/__init__.py +35 -0
- calc_terminal/capabilities/adapters/__init__.py +33 -0
- calc_terminal/capabilities/adapters/bioinformatics.py +204 -0
- calc_terminal/capabilities/adapters/browser_adapter.py +205 -0
- calc_terminal/capabilities/adapters/filesystem.py +206 -0
- calc_terminal/capabilities/adapters/git_adapter.py +202 -0
- calc_terminal/capabilities/adapters/jupyter_adapter.py +138 -0
- calc_terminal/capabilities/adapters/ml_frameworks.py +158 -0
- calc_terminal/capabilities/adapters/platforms.py +200 -0
- calc_terminal/capabilities/adapters/python_exec.py +93 -0
- calc_terminal/capabilities/adapters/quantum_adapter.py +150 -0
- calc_terminal/capabilities/adapters/scientific_comp.py +123 -0
- calc_terminal/capabilities/adapters/structural_bio.py +161 -0
- calc_terminal/capabilities/adapters/terminal.py +99 -0
- calc_terminal/capabilities/bus.py +178 -0
- calc_terminal/capabilities/discovery.py +207 -0
- calc_terminal/capabilities/schema.py +221 -0
- calc_terminal/cat.ico +0 -0
- calc_terminal/cat_browser.py +2018 -0
- calc_terminal/chat_store.py +703 -0
- calc_terminal/cli.py +1178 -0
- calc_terminal/code_editor.py +640 -0
- calc_terminal/collaboration.py +723 -0
- calc_terminal/commands_data.py +139 -0
- calc_terminal/compatibility_engine.py +352 -0
- calc_terminal/compute/__init__.py +31 -0
- calc_terminal/compute/fabric.py +350 -0
- calc_terminal/config.py +227 -0
- calc_terminal/core/__init__.py +41 -0
- calc_terminal/core/checkpoint.py +156 -0
- calc_terminal/core/input/__init__.py +45 -0
- calc_terminal/core/mode_registry.py +300 -0
- calc_terminal/core/project_graph.py +172 -0
- calc_terminal/core/recovery.py +129 -0
- calc_terminal/core/security_layer.py +112 -0
- calc_terminal/core/task_graph.py +202 -0
- calc_terminal/core/unified_runtime.py +184 -0
- calc_terminal/core/verification.py +257 -0
- calc_terminal/customization.py +1566 -0
- calc_terminal/derivations.py +153 -0
- calc_terminal/device_control.py +263 -0
- calc_terminal/diagnostics/__init__.py +27 -0
- calc_terminal/diagnostics/doctor_engine.py +382 -0
- calc_terminal/diagnostics/self_test.py +247 -0
- calc_terminal/doctor.py +519 -0
- calc_terminal/easter_eggs.py +274 -0
- calc_terminal/editor/__init__.py +1 -0
- calc_terminal/editor/actions.py +263 -0
- calc_terminal/editor/commands.py +160 -0
- calc_terminal/editor/shortcuts.py +226 -0
- calc_terminal/engine.py +259 -0
- calc_terminal/errors.py +120 -0
- calc_terminal/event_stream.py +146 -0
- calc_terminal/eventbus.py +133 -0
- calc_terminal/extensions.py +733 -0
- calc_terminal/fallback_cli.py +1321 -0
- calc_terminal/first_run.py +265 -0
- calc_terminal/fomoji_auth.py +1043 -0
- calc_terminal/formulas.py +82 -0
- calc_terminal/fs_cache.py +121 -0
- calc_terminal/fs_watcher.py +277 -0
- calc_terminal/game.py +193 -0
- calc_terminal/gen1.py +5 -0
- calc_terminal/generators.py +245 -0
- calc_terminal/gestures/__init__.py +42 -0
- calc_terminal/gestures/bindings.py +175 -0
- calc_terminal/gestures/manager.py +477 -0
- calc_terminal/goodbye.py +363 -0
- calc_terminal/gpu3d.py +290 -0
- calc_terminal/graphs.py +358 -0
- calc_terminal/hardware_analyzer.py +440 -0
- calc_terminal/host/__init__.py +30 -0
- calc_terminal/host/browser_manager.py +187 -0
- calc_terminal/host/desktop.py +1386 -0
- calc_terminal/host/launcher.py +395 -0
- calc_terminal/host/terminal.py +279 -0
- calc_terminal/identity.py +216 -0
- calc_terminal/input/__init__.py +54 -0
- calc_terminal/input/capabilities.py +258 -0
- calc_terminal/input/focus.py +87 -0
- calc_terminal/input/gestures.py +64 -0
- calc_terminal/input/pointer.py +114 -0
- calc_terminal/input/touch.py +345 -0
- calc_terminal/keys.py +84 -0
- calc_terminal/live_automation.py +165 -0
- calc_terminal/mathtext.py +433 -0
- calc_terminal/mcp.py +386 -0
- calc_terminal/memory.py +337 -0
- calc_terminal/memory_v2.py +479 -0
- calc_terminal/metrics.py +333 -0
- calc_terminal/mode_detection.py +146 -0
- calc_terminal/model.py +2431 -0
- calc_terminal/model_router.py +665 -0
- calc_terminal/models/__init__.py +0 -0
- calc_terminal/models/active_state.py +187 -0
- calc_terminal/models/dynamic_registry.py +584 -0
- calc_terminal/models/manager.py +781 -0
- calc_terminal/models/model_metadata.json +3526 -0
- calc_terminal/models/profiles.py +194 -0
- calc_terminal/models/registry.py +265 -0
- calc_terminal/models/schema.py +197 -0
- calc_terminal/models/validator.py +287 -0
- calc_terminal/models/verification_engine.py +368 -0
- calc_terminal/native_picker.py +215 -0
- calc_terminal/ollama_catalog.py +279 -0
- calc_terminal/ollama_download.py +233 -0
- calc_terminal/orchestrator.py +304 -0
- calc_terminal/package_research.py +322 -0
- calc_terminal/packages.py +1024 -0
- calc_terminal/pc_specs.py +116 -0
- calc_terminal/permissions.py +334 -0
- calc_terminal/pet.py +106 -0
- calc_terminal/pipeline.py +505 -0
- calc_terminal/platform/__init__.py +491 -0
- calc_terminal/platform/desktop.py +491 -0
- calc_terminal/platform/web.py +781 -0
- calc_terminal/preview/__init__.py +1 -0
- calc_terminal/preview/dev_server.py +303 -0
- calc_terminal/preview/diagnostics.py +131 -0
- calc_terminal/preview/live_reload.py +66 -0
- calc_terminal/preview/manager.py +129 -0
- calc_terminal/project_stats.py +209 -0
- calc_terminal/projects.py +328 -0
- calc_terminal/providers/__init__.py +0 -0
- calc_terminal/providers/adapters/__init__.py +80 -0
- calc_terminal/providers/adapters/anthropic_adapter.py +127 -0
- calc_terminal/providers/adapters/base.py +106 -0
- calc_terminal/providers/adapters/chinese_adapters.py +420 -0
- calc_terminal/providers/adapters/gemini_adapter.py +101 -0
- calc_terminal/providers/adapters/ollama_adapter.py +83 -0
- calc_terminal/providers/adapters/openai_adapter.py +159 -0
- calc_terminal/providers/adapters/other_adapters.py +246 -0
- calc_terminal/providers/anthropic_provider.py +172 -0
- calc_terminal/providers/auto_update.py +416 -0
- calc_terminal/providers/base_provider.py +105 -0
- calc_terminal/providers/discovery_manager.py +207 -0
- calc_terminal/providers/gemini_provider.py +178 -0
- calc_terminal/providers/lifecycle.py +767 -0
- calc_terminal/providers/ollama_adapter.py +707 -0
- calc_terminal/providers/openai_provider.py +254 -0
- calc_terminal/providers/provider_manager.py +1827 -0
- calc_terminal/providers/providers.json +4075 -0
- calc_terminal/reactionsim.py +279 -0
- calc_terminal/registry.py +337 -0
- calc_terminal/report.py +162 -0
- calc_terminal/research/__init__.py +45 -0
- calc_terminal/research/artifact_intel.py +126 -0
- calc_terminal/research/data_lineage.py +123 -0
- calc_terminal/research/experiment_ledger.py +303 -0
- calc_terminal/research/reproducibility.py +131 -0
- calc_terminal/resilience/__init__.py +47 -0
- calc_terminal/resilience/agent_state.py +121 -0
- calc_terminal/resilience/capability_matcher.py +174 -0
- calc_terminal/resilience/circuit_breaker.py +158 -0
- calc_terminal/resilience/failover_engine.py +230 -0
- calc_terminal/resilience/health_monitor.py +192 -0
- calc_terminal/resilience/ollama_adapter.py +125 -0
- calc_terminal/resilience/orchestrator.py +312 -0
- calc_terminal/resilience/types.py +134 -0
- calc_terminal/sandbox.py +98 -0
- calc_terminal/scires.py +558 -0
- calc_terminal/security_scanner.py +126 -0
- calc_terminal/session.py +294 -0
- calc_terminal/sim3d.py +206 -0
- calc_terminal/solver.py +276 -0
- calc_terminal/sound.py +127 -0
- calc_terminal/task_reports.py +287 -0
- calc_terminal/terminal_host.py +201 -0
- calc_terminal/terminal_identity.py +411 -0
- calc_terminal/test_ai_mode_reliability.py +344 -0
- calc_terminal/test_browser.py +368 -0
- calc_terminal/test_code_editor_upgrade.py +485 -0
- calc_terminal/test_customization.py +1148 -0
- calc_terminal/test_customization_ui.py +612 -0
- calc_terminal/test_dynamic_registry.py +304 -0
- calc_terminal/test_extensions.py +436 -0
- calc_terminal/test_overhaul.py +557 -0
- calc_terminal/test_project_detect.py +255 -0
- calc_terminal/test_root_cause_fix.py +527 -0
- calc_terminal/test_stability.py +532 -0
- calc_terminal/test_terminal_identity.py +132 -0
- calc_terminal/test_v079_speed.py +460 -0
- calc_terminal/theme.py +1107 -0
- calc_terminal/timeline.py +139 -0
- calc_terminal/todos.py +246 -0
- calc_terminal/tool_call_normalizer.py +419 -0
- calc_terminal/tui.py +104 -0
- calc_terminal/ui/__init__.py +8 -0
- calc_terminal/ui/activity_panel.py +231 -0
- calc_terminal/ui/activity_stream_panel.py +238 -0
- calc_terminal/ui/animations.py +122 -0
- calc_terminal/ui/app.py +7271 -0
- calc_terminal/ui/attach_panel.py +597 -0
- calc_terminal/ui/attachments.py +424 -0
- calc_terminal/ui/backup_panel.py +810 -0
- calc_terminal/ui/browser_shell.py +887 -0
- calc_terminal/ui/cat_agent.py +357 -0
- calc_terminal/ui/chats_panel.py +899 -0
- calc_terminal/ui/command_palette.py +125 -0
- calc_terminal/ui/command_palette_modal.py +166 -0
- calc_terminal/ui/composer.py +1141 -0
- calc_terminal/ui/context_menu.py +197 -0
- calc_terminal/ui/conversation.py +1435 -0
- calc_terminal/ui/customization_panel.py +1229 -0
- calc_terminal/ui/dashboard.py +404 -0
- calc_terminal/ui/design_system.py +557 -0
- calc_terminal/ui/diff_panel.py +213 -0
- calc_terminal/ui/editor.py +2102 -0
- calc_terminal/ui/empty_state.py +302 -0
- calc_terminal/ui/events.py +487 -0
- calc_terminal/ui/extensions_panel.py +815 -0
- calc_terminal/ui/footer.py +166 -0
- calc_terminal/ui/gestures_panel.py +383 -0
- calc_terminal/ui/goodbye_screen.py +100 -0
- calc_terminal/ui/header.py +1034 -0
- calc_terminal/ui/help_panel.py +254 -0
- calc_terminal/ui/live_activities.py +914 -0
- calc_terminal/ui/mcp_panel.py +570 -0
- calc_terminal/ui/memory_center.py +524 -0
- calc_terminal/ui/mode_colors_panel.py +525 -0
- calc_terminal/ui/nav_screens.py +747 -0
- calc_terminal/ui/ollama_panel.py +536 -0
- calc_terminal/ui/palette.py +221 -0
- calc_terminal/ui/permission_panel.py +269 -0
- calc_terminal/ui/personalization_panel.py +517 -0
- calc_terminal/ui/personalize_center.py +1568 -0
- calc_terminal/ui/preview_panel.py +441 -0
- calc_terminal/ui/resizers.py +402 -0
- calc_terminal/ui/sidebar.py +1285 -0
- calc_terminal/ui/statusbar.py +168 -0
- calc_terminal/ui/theme_css.py +1396 -0
- calc_terminal/ui/thinking.py +226 -0
- calc_terminal/ui/timeline_panel.py +102 -0
- calc_terminal/ui/todo_panel.py +193 -0
- calc_terminal/ui/viewport.py +136 -0
- calc_terminal/ui/vision_panel.py +489 -0
- calc_terminal/ui/welcome_modal.py +343 -0
- calc_terminal/ui/widgets.py +160 -0
- calc_terminal/ui/workspace.py +831 -0
- calc_terminal/viewers/__init__.py +1 -0
- calc_terminal/viewers/document_viewer.py +252 -0
- calc_terminal/viewers/image_viewer.py +241 -0
- calc_terminal/viewers/pdf_viewer.py +203 -0
- calc_terminal/viewers/presentation_viewer.py +164 -0
- calc_terminal/viewers/registry.py +120 -0
- calc_terminal/viewers/spreadsheet_viewer.py +204 -0
- calc_terminal/vision/__init__.py +89 -0
- calc_terminal/vision/analysis.py +194 -0
- calc_terminal/vision/annotations.py +297 -0
- calc_terminal/vision/capture.py +171 -0
- calc_terminal/vision/context.py +231 -0
- calc_terminal/vision/correlation.py +169 -0
- calc_terminal/vision/cursor.py +258 -0
- calc_terminal/vision/events.py +66 -0
- calc_terminal/vision/frame_pipeline.py +259 -0
- calc_terminal/vision/priority.py +218 -0
- calc_terminal/vision/provider.py +180 -0
- calc_terminal/vision/safety.py +149 -0
- calc_terminal/vision/session.py +281 -0
- calc_terminal/vision/verify.py +162 -0
- calc_terminal/vision.py +514 -0
- calc_terminal/vscode_integration.py +113 -0
- calc_terminal/web/__init__.py +8 -0
- calc_terminal/web/cat_runtime.py +710 -0
- calc_terminal/web/server.py +2891 -0
- calc_terminal/web/static/css/app.css +3152 -0
- calc_terminal/web/static/icons/badge-72.png +0 -0
- calc_terminal/web/static/icons/cat.ico +0 -0
- calc_terminal/web/static/icons/icon-128.png +0 -0
- calc_terminal/web/static/icons/icon-144.png +0 -0
- calc_terminal/web/static/icons/icon-152.png +0 -0
- calc_terminal/web/static/icons/icon-192.png +0 -0
- calc_terminal/web/static/icons/icon-384.png +0 -0
- calc_terminal/web/static/icons/icon-512.png +0 -0
- calc_terminal/web/static/icons/icon-72.png +0 -0
- calc_terminal/web/static/icons/icon-96.png +0 -0
- calc_terminal/web/static/icons/icon.svg +34 -0
- calc_terminal/web/static/icons/new-project.png +0 -0
- calc_terminal/web/static/icons/open-project.png +0 -0
- calc_terminal/web/static/index.html +734 -0
- calc_terminal/web/static/js/app.js +2403 -0
- calc_terminal/web/static/manifest.json +88 -0
- calc_terminal/web/static/sw.js +230 -0
- calc_terminal/workflow_engine.py +769 -0
- calc_terminal/workspace.py +593 -0
- calc_terminal/workspace_index.py +385 -0
- cct_cli-0.7.9.0.dist-info/METADATA +210 -0
- cct_cli-0.7.9.0.dist-info/RECORD +325 -0
- cct_cli-0.7.9.0.dist-info/WHEEL +5 -0
- cct_cli-0.7.9.0.dist-info/entry_points.txt +4 -0
- cct_cli-0.7.9.0.dist-info/licenses/LICENSE +21 -0
- cct_cli-0.7.9.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CCT UI — ModeColorsPanel / ModesManager (v0.7.9.8).
|
|
3
|
+
|
|
4
|
+
User Section > Modes: fully customizable AI modes — change colour (gradient
|
|
5
|
+
auto), edit label/icon/purpose, create new modes, delete modes, reorder,
|
|
6
|
+
reset. Persists to ~/.cct_config.json via ai_modes.* and instantly repaints.
|
|
7
|
+
|
|
8
|
+
Design: responsive, easy to use, not in main menu (only User section).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
print("This is a library file and is not meant to be run directly.")
|
|
13
|
+
import sys
|
|
14
|
+
sys.exit(1)
|
|
15
|
+
|
|
16
|
+
import re
|
|
17
|
+
|
|
18
|
+
TEXTUAL_AVAILABLE = True
|
|
19
|
+
try:
|
|
20
|
+
from textual.screen import Screen
|
|
21
|
+
from textual.containers import Vertical, Horizontal, VerticalScroll
|
|
22
|
+
from textual.widgets import Static, Button, Input, TextArea
|
|
23
|
+
from textual.binding import Binding
|
|
24
|
+
except Exception:
|
|
25
|
+
TEXTUAL_AVAILABLE = False
|
|
26
|
+
|
|
27
|
+
if TEXTUAL_AVAILABLE:
|
|
28
|
+
try:
|
|
29
|
+
from .. import ai_modes
|
|
30
|
+
except Exception:
|
|
31
|
+
ai_modes = None
|
|
32
|
+
try:
|
|
33
|
+
from . import theme_css
|
|
34
|
+
except Exception:
|
|
35
|
+
theme_css = None
|
|
36
|
+
|
|
37
|
+
_HEX_RE = re.compile(r"^#?[0-9a-fA-F]{6}$")
|
|
38
|
+
_KEY_RE = re.compile(r"^[a-z0-9_]{2,20}$")
|
|
39
|
+
|
|
40
|
+
_PRESETS = [
|
|
41
|
+
"#7aa2f7", "#bb9af7", "#e0af68", "#9ece6a", "#ff69b4", "#dc143c",
|
|
42
|
+
"#ff7f50", "#40e0d0", "#ffd700", "#8a2be2", "#00fa9a", "#ff6347",
|
|
43
|
+
"#1e90ff", "#ff1493", "#32cd32", "#ffa500",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
def _valid_hex(s):
|
|
47
|
+
return bool(_HEX_RE.match((s or "").strip()))
|
|
48
|
+
|
|
49
|
+
def _valid_key(k):
|
|
50
|
+
return bool(_KEY_RE.match((k or "").strip().lower()))
|
|
51
|
+
|
|
52
|
+
class _ModeRow(Horizontal):
|
|
53
|
+
"""One mode's full editor row (colour + label/icon/purpose + actions)."""
|
|
54
|
+
def __init__(self, mode_key):
|
|
55
|
+
super().__init__(classes="mcc-row", id=f"mcc-row-{mode_key}")
|
|
56
|
+
self.mode_key = mode_key
|
|
57
|
+
|
|
58
|
+
def compose(self):
|
|
59
|
+
m = ai_modes.MODE_META.get(self.mode_key, {})
|
|
60
|
+
label = m.get("label", self.mode_key)
|
|
61
|
+
icon = m.get("icon", "")
|
|
62
|
+
purpose = m.get("purpose", "")[:80]
|
|
63
|
+
accent = ai_modes.accent_hex(self.mode_key)
|
|
64
|
+
g_start, g_end = ai_modes.gradient(self.mode_key)
|
|
65
|
+
is_current = (self.mode_key == ai_modes.current_mode())
|
|
66
|
+
cur_mark = "●" if is_current else "○"
|
|
67
|
+
# left: info + editable fields
|
|
68
|
+
with Vertical(classes="mcc-info"):
|
|
69
|
+
# header: current marker + icon + label (editable)
|
|
70
|
+
with Horizontal(classes="mcc-header"):
|
|
71
|
+
yield Static(f"[{accent}]{cur_mark}[/] {icon} {label}", classes="mcc-label", markup=True)
|
|
72
|
+
yield Static(f"[{accent}]{self.mode_key}[/]", classes="mcc-key", markup=True)
|
|
73
|
+
yield Static(purpose or "No purpose", classes="mcc-purpose")
|
|
74
|
+
yield Static(f"[{accent}]█[/] {accent} grad [{g_start}]█[/][{g_end}]█[/] {g_start}→{g_end}", classes="mcc-preview", markup=True)
|
|
75
|
+
# inline edit fields (collapsed by default, shown on Edit)
|
|
76
|
+
with Vertical(classes="mcc-editbox", id=f"mcc-edit-{self.mode_key}"):
|
|
77
|
+
with Horizontal(classes="mcc-edit-row"):
|
|
78
|
+
yield Input(value=label, placeholder="Label", id=f"mcc-label-{self.mode_key}", classes="mcc-input-sm")
|
|
79
|
+
yield Input(value=icon, placeholder="Icon", id=f"mcc-icon-{self.mode_key}", classes="mcc-input-sm mcc-input-icon")
|
|
80
|
+
yield Input(value=accent, placeholder="#rrggbb", id=f"mcc-input-{self.mode_key}", classes="mcc-input")
|
|
81
|
+
yield Input(value=purpose, placeholder="Purpose (one-line)", id=f"mcc-purpose-{self.mode_key}", classes="mcc-input-wide")
|
|
82
|
+
# right: actions
|
|
83
|
+
with Vertical(classes="mcc-actions"):
|
|
84
|
+
with Horizontal(classes="mcc-actions-row"):
|
|
85
|
+
yield Button("Save", id=f"mcc-save-{self.mode_key}", variant="primary", classes="cct-btn-sm")
|
|
86
|
+
yield Button("Delete", id=f"mcc-delete-{self.mode_key}", variant="error", classes="cct-btn-sm")
|
|
87
|
+
with Horizontal(classes="mcc-actions-row"):
|
|
88
|
+
yield Button("↑", id=f"mcc-up-{self.mode_key}", classes="cct-btn-sm")
|
|
89
|
+
yield Button("↓", id=f"mcc-down-{self.mode_key}", classes="cct-btn-sm")
|
|
90
|
+
yield Button("Reset", id=f"mcc-reset-{self.mode_key}", classes="cct-btn-sm")
|
|
91
|
+
|
|
92
|
+
def refresh_preview(self):
|
|
93
|
+
try:
|
|
94
|
+
m = ai_modes.MODE_META.get(self.mode_key, {})
|
|
95
|
+
label = m.get("label", self.mode_key)
|
|
96
|
+
icon = m.get("icon", "")
|
|
97
|
+
purpose = m.get("purpose", "")[:80]
|
|
98
|
+
accent = ai_modes.accent_hex(self.mode_key)
|
|
99
|
+
g_start, g_end = ai_modes.gradient(self.mode_key)
|
|
100
|
+
is_current = (self.mode_key == ai_modes.current_mode())
|
|
101
|
+
cur_mark = "●" if is_current else "○"
|
|
102
|
+
self.query_one(".mcc-label", Static).update(f"[{accent}]{cur_mark}[/] {icon} {label}")
|
|
103
|
+
self.query_one(".mcc-key", Static).update(f"[{accent}]{self.mode_key}[/]")
|
|
104
|
+
self.query_one(".mcc-purpose", Static).update(purpose or "No purpose")
|
|
105
|
+
self.query_one(".mcc-preview", Static).update(f"[{accent}]█[/] {accent} grad [{g_start}]█[/][{g_end}]█[/] {g_start}→{g_end}")
|
|
106
|
+
# update inputs to reflect new values (keep user edits if focused? just update)
|
|
107
|
+
try:
|
|
108
|
+
self.query_one(f"#mcc-input-{self.mode_key}", Input).value = accent
|
|
109
|
+
except Exception:
|
|
110
|
+
pass
|
|
111
|
+
try:
|
|
112
|
+
self.query_one(f"#mcc-label-{self.mode_key}", Input).value = label
|
|
113
|
+
except Exception:
|
|
114
|
+
pass
|
|
115
|
+
try:
|
|
116
|
+
self.query_one(f"#mcc-icon-{self.mode_key}", Input).value = icon
|
|
117
|
+
except Exception:
|
|
118
|
+
pass
|
|
119
|
+
try:
|
|
120
|
+
self.query_one(f"#mcc-purpose-{self.mode_key}", Input).value = purpose
|
|
121
|
+
except Exception:
|
|
122
|
+
pass
|
|
123
|
+
except Exception:
|
|
124
|
+
pass
|
|
125
|
+
|
|
126
|
+
# Alias for backward compat (old name)
|
|
127
|
+
_ModeColorRow = _ModeRow
|
|
128
|
+
|
|
129
|
+
class ModeColorsPanel(Screen):
|
|
130
|
+
"""Modes manager — User Section only (not main menu). Full CRUD."""
|
|
131
|
+
|
|
132
|
+
CSS = """
|
|
133
|
+
ModeColorsPanel { align: center middle; background: $app-background 60%; }
|
|
134
|
+
#mcc-box {
|
|
135
|
+
width: 96; max-width: 98%; height: auto; max-height: 46;
|
|
136
|
+
background: $surface; border: round $border;
|
|
137
|
+
padding: 0; layout: vertical; overflow: hidden;
|
|
138
|
+
}
|
|
139
|
+
#mcc-titlebar {
|
|
140
|
+
height: 3; min-height: 3; padding: 1 2 0 2;
|
|
141
|
+
border-bottom: solid $border; layout: horizontal;
|
|
142
|
+
}
|
|
143
|
+
#mcc-title { width: 1fr; text-style: bold; }
|
|
144
|
+
#mcc-subtitle { color: $text-faint; height: auto; padding: 0 2 1 2; }
|
|
145
|
+
#mcc-presets {
|
|
146
|
+
height: auto; padding: 0 2 1 2; layout: horizontal;
|
|
147
|
+
border-bottom: solid $border;
|
|
148
|
+
}
|
|
149
|
+
#mcc-presets-label { width: auto; color: $text-faint; height: 1; padding-right: 1; }
|
|
150
|
+
.mcc-preset {
|
|
151
|
+
width: 3; min-width: 3; height: 1; min-height: 1; padding: 0;
|
|
152
|
+
margin-right: 1; border: none; content-align: center middle;
|
|
153
|
+
}
|
|
154
|
+
#mcc-create {
|
|
155
|
+
height: auto; padding: 1 2; border-bottom: solid $border; background: $surface-alt 20%;
|
|
156
|
+
}
|
|
157
|
+
#mcc-create-title { height: 1; text-style: bold; color: $accent; }
|
|
158
|
+
#mcc-create-row1 { height: 3; layout: horizontal; margin-top: 1; }
|
|
159
|
+
#mcc-create-row1 Input { width: 1fr; margin-right: 1; }
|
|
160
|
+
#mcc-create-row2 { height: 3; layout: horizontal; margin-top: 1; }
|
|
161
|
+
#mcc-create-row2 Input { width: 1fr; margin-right: 1; }
|
|
162
|
+
#mcc-create-row3 { height: 3; layout: horizontal; margin-top: 1; }
|
|
163
|
+
#mcc-create-row3 Input { width: 1fr; }
|
|
164
|
+
#mcc-create-actions { height: 3; layout: horizontal; margin-top: 1; }
|
|
165
|
+
#mcc-create-actions Button { margin-right: 1; }
|
|
166
|
+
#mcc-list {
|
|
167
|
+
height: 1fr; min-height: 10; max-height: 22;
|
|
168
|
+
overflow-y: auto; overflow-x: hidden;
|
|
169
|
+
scrollbar-gutter: stable; scrollbar-size: 1 1;
|
|
170
|
+
margin: 0 1; padding: 0;
|
|
171
|
+
}
|
|
172
|
+
.mcc-row {
|
|
173
|
+
height: auto; min-height: 7; padding: 1 1;
|
|
174
|
+
border-bottom: solid $border; border-left: thick transparent;
|
|
175
|
+
layout: horizontal; overflow: hidden;
|
|
176
|
+
}
|
|
177
|
+
.mcc-row:hover { border-left: thick $accent; background: $surface-alt 30%; }
|
|
178
|
+
.mcc-info { width: 1fr; height: auto; min-width: 24; }
|
|
179
|
+
.mcc-header { height: 1; layout: horizontal; }
|
|
180
|
+
.mcc-label { width: auto; height: 1; text-style: bold; margin-right: 1; }
|
|
181
|
+
.mcc-key { width: auto; height: 1; color: $text-faint; }
|
|
182
|
+
.mcc-purpose { width: auto; height: 1; color: $text-faint; }
|
|
183
|
+
.mcc-preview { width: auto; height: 1; color: $text-muted; }
|
|
184
|
+
.mcc-editbox { height: auto; margin-top: 1; display: none; }
|
|
185
|
+
.mcc-editbox.show { display: block; }
|
|
186
|
+
.mcc-edit-row { height: 3; layout: horizontal; margin-bottom: 1; }
|
|
187
|
+
.mcc-input-sm { width: 1fr; margin-right: 1; }
|
|
188
|
+
.mcc-input-icon { width: 10; min-width: 10; }
|
|
189
|
+
.mcc-input { width: 16; min-width: 16; height: 3; margin-right: 1; }
|
|
190
|
+
.mcc-input-wide { width: 100%; height: 3; }
|
|
191
|
+
.mcc-actions {
|
|
192
|
+
width: auto; height: auto; min-width: 24;
|
|
193
|
+
layout: vertical; align: center middle;
|
|
194
|
+
}
|
|
195
|
+
.mcc-actions-row { height: 3; layout: horizontal; margin-bottom: 1; }
|
|
196
|
+
.mcc-actions-row Button { min-width: 10; height: 3; margin-right: 1; }
|
|
197
|
+
#mcc-actions {
|
|
198
|
+
height: auto; padding: 1 2; border-top: solid $border;
|
|
199
|
+
layout: horizontal;
|
|
200
|
+
}
|
|
201
|
+
#mcc-actions-left { width: 1fr; layout: horizontal; }
|
|
202
|
+
#mcc-actions-left Button { margin-right: 1; }
|
|
203
|
+
#mcc-actions-right { width: auto; layout: horizontal; }
|
|
204
|
+
#mcc-actions-right Button { margin-left: 1; }
|
|
205
|
+
#mcc-hint { color: $text-faint; height: auto; padding: 0 2 1 2; text-align: center; }
|
|
206
|
+
#mcc-error { color: $error; height: 1; padding: 0 2; display: none; }
|
|
207
|
+
#mcc-error.show { display: block; }
|
|
208
|
+
.cct-compact .mcc-row { layout: vertical; min-height: 10; }
|
|
209
|
+
.cct-compact .mcc-actions { width: 100%; padding-top: 1; }
|
|
210
|
+
.cct-compact #mcc-box { width: 98; }
|
|
211
|
+
.cct-compact #mcc-create-row1 { layout: vertical; height: auto; }
|
|
212
|
+
.cct-compact #mcc-create-row1 Input { width: 100%; margin-bottom: 1; }
|
|
213
|
+
.cct-compact #mcc-create-row2 { layout: vertical; height: auto; }
|
|
214
|
+
.cct-compact #mcc-create-row2 Input { width: 100%; margin-bottom: 1; }
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
BINDINGS = [Binding("escape", "cancel", "Cancel")]
|
|
218
|
+
|
|
219
|
+
def compose(self):
|
|
220
|
+
with Vertical(id="mcc-box"):
|
|
221
|
+
with Horizontal(id="mcc-titlebar"):
|
|
222
|
+
yield Static("🎨 AI Modes — Manage", id="mcc-title")
|
|
223
|
+
yield Button("✕", id="mcc-close", classes="cct-ctrl")
|
|
224
|
+
yield Static("Create, edit, reorder, delete modes — colours auto-gradient. Only in User section.", id="mcc-subtitle")
|
|
225
|
+
with Horizontal(id="mcc-presets"):
|
|
226
|
+
yield Static("Presets:", id="mcc-presets-label")
|
|
227
|
+
for idx, hx in enumerate(_PRESETS):
|
|
228
|
+
btn = Button("█", id=f"mcc-preset-{idx}", classes="mcc-preset")
|
|
229
|
+
btn.tooltip = hx
|
|
230
|
+
btn._preset_hex = hx
|
|
231
|
+
yield btn
|
|
232
|
+
# create form
|
|
233
|
+
with Vertical(id="mcc-create"):
|
|
234
|
+
yield Static("+ Create New Mode", id="mcc-create-title")
|
|
235
|
+
with Horizontal(id="mcc-create-row1"):
|
|
236
|
+
yield Input(placeholder="key (a-z0-9_, 2-20)", id="mcc-new-key", classes="mcc-input-sm")
|
|
237
|
+
yield Input(placeholder="Label", id="mcc-new-label", classes="mcc-input-sm")
|
|
238
|
+
yield Input(placeholder="Icon", id="mcc-new-icon", classes="mcc-input-sm mcc-input-icon")
|
|
239
|
+
yield Input(placeholder="#rrggbb", id="mcc-new-color", classes="mcc-input")
|
|
240
|
+
with Horizontal(id="mcc-create-row2"):
|
|
241
|
+
yield Input(placeholder="Purpose (one-line)", id="mcc-new-purpose", classes="mcc-input-sm")
|
|
242
|
+
with Horizontal(id="mcc-create-actions"):
|
|
243
|
+
yield Button("Create", id="mcc-create-btn", variant="primary", classes="cct-btn-sm")
|
|
244
|
+
yield Button("Clear", id="mcc-create-clear", classes="cct-btn-sm")
|
|
245
|
+
yield Static("", id="mcc-error")
|
|
246
|
+
with VerticalScroll(id="mcc-list"):
|
|
247
|
+
for key in list(ai_modes.MODE_ORDER):
|
|
248
|
+
yield _ModeRow(key)
|
|
249
|
+
with Horizontal(id="mcc-actions"):
|
|
250
|
+
with Horizontal(id="mcc-actions-left"):
|
|
251
|
+
yield Button("↺ Reset All to Defaults", id="mcc-reset-all", classes="cct-btn-sm")
|
|
252
|
+
with Horizontal(id="mcc-actions-right"):
|
|
253
|
+
yield Button("Close", id="mcc-close2", variant="primary", classes="cct-btn-sm")
|
|
254
|
+
yield Static("Tip: Edit label/icon/purpose/colour then Save. ↑↓ to reorder. Delete removes mode (min 1).", id="mcc-hint")
|
|
255
|
+
|
|
256
|
+
def on_mount(self):
|
|
257
|
+
try:
|
|
258
|
+
self.query_one("#mcc-box").add_class("open")
|
|
259
|
+
except Exception:
|
|
260
|
+
pass
|
|
261
|
+
try:
|
|
262
|
+
for idx, hx in enumerate(_PRESETS):
|
|
263
|
+
btn = self.query_one(f"#mcc-preset-{idx}", Button)
|
|
264
|
+
btn.label = f"[{hx}]█[/]"
|
|
265
|
+
except Exception:
|
|
266
|
+
pass
|
|
267
|
+
if self.size.width < 90 or self.size.height < 34:
|
|
268
|
+
try:
|
|
269
|
+
self.query_one("#mcc-box").add_class("cct-compact")
|
|
270
|
+
except Exception:
|
|
271
|
+
pass
|
|
272
|
+
try:
|
|
273
|
+
self.query_one("#mcc-new-key", Input).focus()
|
|
274
|
+
except Exception:
|
|
275
|
+
pass
|
|
276
|
+
|
|
277
|
+
def _show_error(self, msg=""):
|
|
278
|
+
try:
|
|
279
|
+
lbl = self.query_one("#mcc-error", Static)
|
|
280
|
+
if msg:
|
|
281
|
+
lbl.update(msg)
|
|
282
|
+
lbl.add_class("show")
|
|
283
|
+
else:
|
|
284
|
+
lbl.remove_class("show")
|
|
285
|
+
except Exception:
|
|
286
|
+
pass
|
|
287
|
+
|
|
288
|
+
def _repaint_app(self):
|
|
289
|
+
try:
|
|
290
|
+
app = self.app
|
|
291
|
+
if hasattr(app, "_repaint_theme_layers"):
|
|
292
|
+
app._repaint_theme_layers()
|
|
293
|
+
else:
|
|
294
|
+
app.refresh_css(animate=False)
|
|
295
|
+
try:
|
|
296
|
+
if hasattr(app, "composer") and hasattr(app, "_current_ai_mode"):
|
|
297
|
+
app.composer.set_ai_mode(app._current_ai_mode)
|
|
298
|
+
except Exception:
|
|
299
|
+
pass
|
|
300
|
+
except Exception:
|
|
301
|
+
pass
|
|
302
|
+
|
|
303
|
+
def _refresh_list(self):
|
|
304
|
+
# rebuild list from current MODE_ORDER
|
|
305
|
+
try:
|
|
306
|
+
container = self.query_one("#mcc-list", VerticalScroll)
|
|
307
|
+
container.remove_children()
|
|
308
|
+
for key in list(ai_modes.MODE_ORDER):
|
|
309
|
+
container.mount(_ModeRow(key))
|
|
310
|
+
except Exception:
|
|
311
|
+
pass
|
|
312
|
+
self._repaint_app()
|
|
313
|
+
|
|
314
|
+
def _refresh_row(self, key):
|
|
315
|
+
try:
|
|
316
|
+
row = self.query_one(f"#mcc-row-{key}", _ModeRow)
|
|
317
|
+
row.refresh_preview()
|
|
318
|
+
except Exception:
|
|
319
|
+
pass
|
|
320
|
+
self._repaint_app()
|
|
321
|
+
|
|
322
|
+
def on_button_pressed(self, event):
|
|
323
|
+
bid = event.button.id or ""
|
|
324
|
+
if bid.startswith("mcc-preset-"):
|
|
325
|
+
try:
|
|
326
|
+
hx = getattr(event.button, "_preset_hex", None) or _PRESETS[int(bid.split("-")[-1])]
|
|
327
|
+
# paste into focused color input or new-color
|
|
328
|
+
focused = None
|
|
329
|
+
for k in list(ai_modes.MODE_ORDER):
|
|
330
|
+
try:
|
|
331
|
+
inp = self.query_one(f"#mcc-input-{k}", Input)
|
|
332
|
+
if inp.has_focus:
|
|
333
|
+
focused = inp
|
|
334
|
+
break
|
|
335
|
+
except Exception:
|
|
336
|
+
pass
|
|
337
|
+
if focused is None:
|
|
338
|
+
try:
|
|
339
|
+
new_inp = self.query_one("#mcc-new-color", Input)
|
|
340
|
+
if new_inp.has_focus or not focused:
|
|
341
|
+
focused = new_inp
|
|
342
|
+
except Exception:
|
|
343
|
+
pass
|
|
344
|
+
if focused is None:
|
|
345
|
+
cur = ai_modes.current_mode()
|
|
346
|
+
try:
|
|
347
|
+
focused = self.query_one(f"#mcc-input-{cur}", Input)
|
|
348
|
+
except Exception:
|
|
349
|
+
focused = self.query_one("#mcc-new-color", Input)
|
|
350
|
+
focused.value = hx
|
|
351
|
+
focused.focus()
|
|
352
|
+
self._show_error("")
|
|
353
|
+
except Exception:
|
|
354
|
+
pass
|
|
355
|
+
return
|
|
356
|
+
if bid in ("mcc-close", "mcc-close2"):
|
|
357
|
+
self.dismiss(None)
|
|
358
|
+
return
|
|
359
|
+
if bid == "mcc-reset-all":
|
|
360
|
+
ai_modes.reset_all_modes()
|
|
361
|
+
self._refresh_list()
|
|
362
|
+
try:
|
|
363
|
+
self.app._system_note("All modes reset to defaults")
|
|
364
|
+
except Exception:
|
|
365
|
+
pass
|
|
366
|
+
self._show_error("")
|
|
367
|
+
return
|
|
368
|
+
if bid == "mcc-create-clear":
|
|
369
|
+
for iid in ["#mcc-new-key", "#mcc-new-label", "#mcc-new-icon", "#mcc-new-color", "#mcc-new-purpose"]:
|
|
370
|
+
try:
|
|
371
|
+
self.query_one(iid, Input).value = ""
|
|
372
|
+
except Exception:
|
|
373
|
+
pass
|
|
374
|
+
self._show_error("")
|
|
375
|
+
return
|
|
376
|
+
if bid == "mcc-create-btn":
|
|
377
|
+
try:
|
|
378
|
+
key = self.query_one("#mcc-new-key", Input).value.strip().lower()
|
|
379
|
+
label = self.query_one("#mcc-new-label", Input).value.strip()
|
|
380
|
+
icon = self.query_one("#mcc-new-icon", Input).value.strip()
|
|
381
|
+
color = self.query_one("#mcc-new-color", Input).value.strip()
|
|
382
|
+
purpose = self.query_one("#mcc-new-purpose", Input).value.strip()
|
|
383
|
+
if not _valid_key(key):
|
|
384
|
+
self._show_error("Key: 2-20 chars a-z0-9_")
|
|
385
|
+
return
|
|
386
|
+
if not _valid_hex(color):
|
|
387
|
+
self._show_error(f"Invalid hex '{color}'")
|
|
388
|
+
return
|
|
389
|
+
ok, msg = ai_modes.create_mode(key, label or key.title(), icon or "●", color, purpose)
|
|
390
|
+
if ok:
|
|
391
|
+
self._show_error("")
|
|
392
|
+
self._refresh_list()
|
|
393
|
+
# clear create form
|
|
394
|
+
for iid in ["#mcc-new-key", "#mcc-new-label", "#mcc-new-icon", "#mcc-new-color", "#mcc-new-purpose"]:
|
|
395
|
+
try:
|
|
396
|
+
self.query_one(iid, Input).value = ""
|
|
397
|
+
except Exception:
|
|
398
|
+
pass
|
|
399
|
+
try:
|
|
400
|
+
self.app._system_note(f"Mode '{key}' created")
|
|
401
|
+
except Exception:
|
|
402
|
+
pass
|
|
403
|
+
else:
|
|
404
|
+
self._show_error(msg)
|
|
405
|
+
except Exception as e:
|
|
406
|
+
self._show_error(str(e))
|
|
407
|
+
return
|
|
408
|
+
if bid.startswith("mcc-save-"):
|
|
409
|
+
mode = bid.replace("mcc-save-", "")
|
|
410
|
+
try:
|
|
411
|
+
label = self.query_one(f"#mcc-label-{mode}", Input).value.strip()
|
|
412
|
+
icon = self.query_one(f"#mcc-icon-{mode}", Input).value.strip()
|
|
413
|
+
color = self.query_one(f"#mcc-input-{mode}", Input).value.strip()
|
|
414
|
+
purpose = self.query_one(f"#mcc-purpose-{mode}", Input).value.strip()
|
|
415
|
+
if color and not _valid_hex(color):
|
|
416
|
+
self._show_error(f"Invalid hex for {mode}: '{color}'")
|
|
417
|
+
return
|
|
418
|
+
# update each field if provided
|
|
419
|
+
ok = True
|
|
420
|
+
if label or icon or purpose or color:
|
|
421
|
+
# use update_mode with provided values; if blank keep old
|
|
422
|
+
ok = ai_modes.update_mode(mode,
|
|
423
|
+
label=label if label else None,
|
|
424
|
+
icon=icon if icon else None,
|
|
425
|
+
accent_hex=color if color and _valid_hex(color) else None,
|
|
426
|
+
purpose=purpose if purpose else None)
|
|
427
|
+
if ok:
|
|
428
|
+
self._show_error("")
|
|
429
|
+
self._refresh_row(mode)
|
|
430
|
+
try:
|
|
431
|
+
self.app._system_note(f"{mode} saved")
|
|
432
|
+
except Exception:
|
|
433
|
+
pass
|
|
434
|
+
else:
|
|
435
|
+
self._show_error(f"Could not save {mode}")
|
|
436
|
+
except Exception as e:
|
|
437
|
+
self._show_error(str(e))
|
|
438
|
+
return
|
|
439
|
+
if bid.startswith("mcc-delete-"):
|
|
440
|
+
mode = bid.replace("mcc-delete-", "")
|
|
441
|
+
ok, msg = ai_modes.delete_mode(mode)
|
|
442
|
+
if ok:
|
|
443
|
+
self._show_error("")
|
|
444
|
+
self._refresh_list()
|
|
445
|
+
try:
|
|
446
|
+
self.app._system_note(msg)
|
|
447
|
+
except Exception:
|
|
448
|
+
pass
|
|
449
|
+
else:
|
|
450
|
+
self._show_error(msg)
|
|
451
|
+
return
|
|
452
|
+
if bid.startswith("mcc-up-"):
|
|
453
|
+
mode = bid.replace("mcc-up-", "")
|
|
454
|
+
if ai_modes.move_mode(mode, -1):
|
|
455
|
+
self._refresh_list()
|
|
456
|
+
self._show_error("")
|
|
457
|
+
else:
|
|
458
|
+
self._show_error("Already at top")
|
|
459
|
+
return
|
|
460
|
+
if bid.startswith("mcc-down-"):
|
|
461
|
+
mode = bid.replace("mcc-down-", "")
|
|
462
|
+
if ai_modes.move_mode(mode, 1):
|
|
463
|
+
self._refresh_list()
|
|
464
|
+
self._show_error("")
|
|
465
|
+
else:
|
|
466
|
+
self._show_error("Already at bottom")
|
|
467
|
+
return
|
|
468
|
+
if bid.startswith("mcc-reset-"):
|
|
469
|
+
# careful: mcc-reset-all handled above, this is per-mode reset (only for built-ins)
|
|
470
|
+
mode = bid.replace("mcc-reset-", "")
|
|
471
|
+
if mode == "all":
|
|
472
|
+
return
|
|
473
|
+
if ai_modes.reset_mode_color(mode):
|
|
474
|
+
self._refresh_row(mode)
|
|
475
|
+
try:
|
|
476
|
+
self.app._system_note(f"{mode} colour reset")
|
|
477
|
+
except Exception:
|
|
478
|
+
pass
|
|
479
|
+
self._show_error("")
|
|
480
|
+
else:
|
|
481
|
+
# try full reset for custom modes? delete and recreate as default if was built-in?
|
|
482
|
+
self._show_error(f"Cannot reset '{mode}' (custom mode — delete to remove)")
|
|
483
|
+
return
|
|
484
|
+
if bid.startswith("mcc-preset"):
|
|
485
|
+
return
|
|
486
|
+
|
|
487
|
+
def on_input_submitted(self, event):
|
|
488
|
+
iid = getattr(event.input, "id", "") or ""
|
|
489
|
+
if iid.startswith("mcc-input-") and not iid.startswith("mcc-new"):
|
|
490
|
+
mode = iid.replace("mcc-input-", "")
|
|
491
|
+
try:
|
|
492
|
+
val = event.input.value.strip()
|
|
493
|
+
if not _valid_hex(val):
|
|
494
|
+
self._show_error(f"Invalid hex: '{val}'")
|
|
495
|
+
return
|
|
496
|
+
if ai_modes.update_mode(mode, accent_hex=val):
|
|
497
|
+
self._show_error("")
|
|
498
|
+
self._refresh_row(mode)
|
|
499
|
+
try:
|
|
500
|
+
self.app._system_note(f"{mode} colour → {val}")
|
|
501
|
+
except Exception:
|
|
502
|
+
pass
|
|
503
|
+
except Exception as e:
|
|
504
|
+
self._show_error(str(e))
|
|
505
|
+
elif iid == "mcc-new-color" or iid.startswith("mcc-new-"):
|
|
506
|
+
# enter in create form triggers create
|
|
507
|
+
try:
|
|
508
|
+
# simulate create btn
|
|
509
|
+
self.on_button_pressed(type("E", (), {"button": type("B", (), {"id": "mcc-create-btn"})(), "stop": lambda: None})())
|
|
510
|
+
except Exception:
|
|
511
|
+
pass
|
|
512
|
+
|
|
513
|
+
def action_cancel(self):
|
|
514
|
+
self.dismiss(None)
|
|
515
|
+
|
|
516
|
+
def on_key(self, event):
|
|
517
|
+
if event.key == "escape":
|
|
518
|
+
self.dismiss(None)
|
|
519
|
+
|
|
520
|
+
# Keep old name alias for any external import
|
|
521
|
+
ModeColorsPanel_OLD = ModeColorsPanel
|
|
522
|
+
|
|
523
|
+
else:
|
|
524
|
+
ModeColorsPanel = None
|
|
525
|
+
_ModeRow = None
|