diff --git a/resources/web/dialog/PluginsDialog/index.js b/resources/web/dialog/PluginsDialog/index.js index 2c0ce1ade8..b627881c93 100644 --- a/resources/web/dialog/PluginsDialog/index.js +++ b/resources/web/dialog/PluginsDialog/index.js @@ -385,6 +385,21 @@ function IsPluginChecked(plugin) { return GetStatus(plugin) === "Activated"; } +function HasMixedCapabilityState(plugin) { + if (!IsPluginChecked(plugin)) + return false; + + const toggleableCapabilities = GetCapabilities(plugin).filter((capability) => + capability?.can_toggle !== false && + String(capability?.name || "") && + String(capability?.type_key || "") + ); + + const hasEnabled = toggleableCapabilities.some((capability) => capability?.enabled === true); + const hasDisabled = toggleableCapabilities.some((capability) => capability?.enabled !== true); + return hasEnabled && hasDisabled; +} + function IsPluginLoading(plugin) { return GetStatus(plugin) === "Loading"; } @@ -420,12 +435,20 @@ function CheckCell(row, plugin) { checkboxLabel.classList.add("loading"); if (!plugin.can_toggle) checkboxLabel.classList.add("disabled"); + const hasMixedCapabilityState = HasMixedCapabilityState(plugin); + if (hasMixedCapabilityState) + checkboxLabel.classList.add("mixed"); const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.className = "plugin-checkbox-input"; checkbox.checked = IsPluginChecked(plugin); + checkbox.indeterminate = hasMixedCapabilityState; checkbox.disabled = isLoading || !plugin.can_toggle; checkbox.dataset.pluginKey = row.dataset.pluginKey; + if (checkbox.indeterminate) { + checkbox.setAttribute("aria-checked", "mixed"); + checkbox.setAttribute("aria-label", "Some plugin capabilities are enabled"); + } const checkboxMark = document.createElement("span"); checkboxMark.className = "plugin-checkbox-mark"; checkboxLabel.appendChild(checkbox); diff --git a/resources/web/dialog/PluginsDialog/styles.css b/resources/web/dialog/PluginsDialog/styles.css index 1a63c89343..0c571e38dc 100644 --- a/resources/web/dialog/PluginsDialog/styles.css +++ b/resources/web/dialog/PluginsDialog/styles.css @@ -878,6 +878,25 @@ body { transform: rotate(45deg); } +.plugin-checkbox-input:indeterminate + .plugin-checkbox-mark, +.plugin-checkbox.mixed .plugin-checkbox-mark { + border-color: #009688; + background: #009688; +} + +.plugin-checkbox-input:indeterminate + .plugin-checkbox-mark::after, +.plugin-checkbox.mixed .plugin-checkbox-mark::after { + content: ""; + position: absolute; + left: 2px; + top: 5px; + width: 6px; + height: 0; + border: solid #fff; + border-width: 1.5px 0 0 0; + transform: none; +} + .plugin-checkbox-input:disabled + .plugin-checkbox-mark { opacity: 0.6; } diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 2083e0bbe3..56173f259e 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -33,7 +33,6 @@ #include "Widgets/TextCtrl.h" #include "../Utils/ColorSpaceConvert.hpp" -#include "slic3r/plugin/PluginManager.hpp" #ifdef __WXOSX__ #define wxOSX true #else diff --git a/src/slic3r/plugin/PluginManager.cpp b/src/slic3r/plugin/PluginManager.cpp index b88ff8697e..7062dfda29 100644 --- a/src/slic3r/plugin/PluginManager.cpp +++ b/src/slic3r/plugin/PluginManager.cpp @@ -2,10 +2,8 @@ #include "slic3r/GUI/GUI_App.hpp" #include -namespace py = pybind11; #include "PythonPluginBridge.hpp" -#include "PythonPluginInterface.hpp" #include "PluginFsUtils.hpp" #include "PythonFileUtils.hpp" @@ -13,7 +11,6 @@ namespace py = pybind11; #include #include #include -#include #include #include #include