mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
taskbar: re-use capsule radius for workspace's groups + improved "visibleWhen" property to support OR conditions
This commit is contained in:
@@ -981,7 +981,8 @@
|
||||
},
|
||||
"capsule_radius": {
|
||||
"label": "Capsule Radius",
|
||||
"description": "Corner radius for this widget capsule; leave blank for automatic pill shape"
|
||||
"description": "Corner radius for this widget capsule; leave blank for automatic pill shape",
|
||||
"taskbar-description": "Corner radius for this widget capsule and taskbar workspace groups; leave blank for automatic pill shape"
|
||||
},
|
||||
"color": {
|
||||
"label": "Color",
|
||||
|
||||
+20
-19
@@ -123,6 +123,26 @@ WidgetBarCapsuleSpec resolveWidgetBarCapsuleSpec(const BarConfig& bar, const Wid
|
||||
} else {
|
||||
spec.enabled = bar.widgetCapsuleDefault;
|
||||
}
|
||||
|
||||
spec.padding = bar.widgetCapsulePadding;
|
||||
if (widget != nullptr && widget->hasSetting("capsule_padding")) {
|
||||
spec.padding = std::clamp(
|
||||
static_cast<float>(widget->getDouble("capsule_padding", static_cast<double>(spec.padding))), 0.0f, 48.0f);
|
||||
}
|
||||
if (bar.widgetCapsuleRadius.has_value()) {
|
||||
spec.radius = std::clamp(static_cast<float>(*bar.widgetCapsuleRadius), 0.0f, 80.0f);
|
||||
}
|
||||
if (widget != nullptr && widget->hasSetting("capsule_radius")) {
|
||||
spec.radius = std::clamp(
|
||||
static_cast<float>(widget->getDouble("capsule_radius", static_cast<double>(spec.radius.value_or(0.0f)))), 0.0f,
|
||||
80.0f);
|
||||
}
|
||||
spec.opacity = bar.widgetCapsuleOpacity;
|
||||
if (widget != nullptr && widget->hasSetting("capsule_opacity")) {
|
||||
spec.opacity = std::clamp(
|
||||
static_cast<float>(widget->getDouble("capsule_opacity", static_cast<double>(spec.opacity))), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (!spec.enabled) {
|
||||
return spec;
|
||||
}
|
||||
@@ -145,25 +165,6 @@ WidgetBarCapsuleSpec resolveWidgetBarCapsuleSpec(const BarConfig& bar, const Wid
|
||||
spec.border = std::nullopt;
|
||||
}
|
||||
|
||||
spec.padding = bar.widgetCapsulePadding;
|
||||
if (widget != nullptr && widget->hasSetting("capsule_padding")) {
|
||||
spec.padding = std::clamp(
|
||||
static_cast<float>(widget->getDouble("capsule_padding", static_cast<double>(spec.padding))), 0.0f, 48.0f);
|
||||
}
|
||||
if (bar.widgetCapsuleRadius.has_value()) {
|
||||
spec.radius = std::clamp(static_cast<float>(*bar.widgetCapsuleRadius), 0.0f, 80.0f);
|
||||
}
|
||||
if (widget != nullptr && widget->hasSetting("capsule_radius")) {
|
||||
spec.radius = std::clamp(
|
||||
static_cast<float>(widget->getDouble("capsule_radius", static_cast<double>(spec.radius.value_or(0.0f)))), 0.0f,
|
||||
80.0f);
|
||||
}
|
||||
spec.opacity = bar.widgetCapsuleOpacity;
|
||||
if (widget != nullptr && widget->hasSetting("capsule_opacity")) {
|
||||
spec.opacity = std::clamp(
|
||||
static_cast<float>(widget->getDouble("capsule_opacity", static_cast<double>(spec.opacity))), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (widget != nullptr && widget->hasSetting("capsule_foreground")) {
|
||||
spec.foreground = parseColorSpecString(widget->getString("capsule_foreground", ""));
|
||||
} else if (bar.widgetCapsuleForeground.has_value()) {
|
||||
|
||||
@@ -168,7 +168,8 @@ struct WidgetConfig {
|
||||
bool operator==(const WidgetConfig&) const = default;
|
||||
};
|
||||
|
||||
// Merges `[bar.*]` capsule defaults with `[widget.*]` overrides (see CONFIG.md).
|
||||
// Merges `[bar.*]` capsule defaults with `[widget.*]` overrides (see CONFIG.md). Size/style fields such as
|
||||
// `radius` are populated even when `enabled` is false so widgets can reuse capsule styling internally.
|
||||
[[nodiscard]] WidgetBarCapsuleSpec resolveWidgetBarCapsuleSpec(const BarConfig& bar, const WidgetConfig* widget);
|
||||
|
||||
// Color spec for `[widget.*] color` and other user color strings (same rules as `capsule_fill`).
|
||||
|
||||
@@ -38,14 +38,6 @@ namespace {
|
||||
constexpr float kAutoHideSlideExtraPx = 16.0f;
|
||||
constexpr std::int32_t kAutoHideTriggerRegionPx = 4;
|
||||
|
||||
float resolvedCapsuleRadius(const WidgetBarCapsuleSpec& spec, float scale, float width, float height) noexcept {
|
||||
const float maxRadius = std::max(0.0f, std::min(width, height) * 0.5f);
|
||||
if (!spec.radius.has_value()) {
|
||||
return maxRadius;
|
||||
}
|
||||
return std::clamp(*spec.radius * scale, 0.0f, maxRadius);
|
||||
}
|
||||
|
||||
bool pointInsideNode(const Node* node, float sceneX, float sceneY) {
|
||||
if (node == nullptr) {
|
||||
return false;
|
||||
@@ -476,7 +468,9 @@ namespace {
|
||||
bg->setPosition(0.0f, 0.0f);
|
||||
bg->setSize(shellW, shellH);
|
||||
content->setPosition(contentX, contentY);
|
||||
bg->setRadius(resolvedCapsuleRadius(run.spec, scale, shellW, shellH));
|
||||
const Widget* radiusSource = !run.widgets.empty() ? run.widgets.front() : nullptr;
|
||||
bg->setRadius(radiusSource != nullptr ? radiusSource->resolvedBarCapsuleRadius(shellW, shellH)
|
||||
: std::max(0.0f, std::min(shellW, shellH) * 0.5f));
|
||||
}
|
||||
};
|
||||
finalizeCapsules(instance.startCapsuleRuns);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "ui/controls/box.h"
|
||||
#include "ui/palette.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float kCapsuleInkEpsilon = 0.5f;
|
||||
@@ -41,6 +43,14 @@ bool Widget::shouldShowBarCapsule() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
float Widget::resolvedBarCapsuleRadius(float width, float height) const noexcept {
|
||||
const float maxRadius = std::max(0.0f, std::min(width, height) * 0.5f);
|
||||
if (!m_barCapsuleSpec.radius.has_value()) {
|
||||
return maxRadius;
|
||||
}
|
||||
return std::clamp(*m_barCapsuleSpec.radius * m_contentScale, 0.0f, maxRadius);
|
||||
}
|
||||
|
||||
void Widget::setBarCapsuleScene(Node* shell, Box* box) noexcept {
|
||||
m_capsuleShell = shell;
|
||||
m_capsuleBox = box;
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
[[nodiscard]] Box* barCapsuleBox() const noexcept { return m_capsuleBox; }
|
||||
// Outermost node for flex layout / anchor alignment (capsule shell when enabled).
|
||||
[[nodiscard]] Node* layoutBoundsNode() const noexcept { return m_capsuleShell != nullptr ? m_capsuleShell : root(); }
|
||||
[[nodiscard]] float resolvedBarCapsuleRadius(float width, float height) const noexcept;
|
||||
|
||||
// Whether the bar should paint the decorative capsule for this frame (spec enabled + visible ink).
|
||||
[[nodiscard]] virtual bool shouldShowBarCapsule() const;
|
||||
|
||||
@@ -230,7 +230,6 @@ void TaskbarWidget::buildTaskButtons(Renderer& renderer) {
|
||||
};
|
||||
|
||||
if (m_groupByWorkspace && !m_workspaces.empty()) {
|
||||
const float capsuleRadius = Style::radiusLg * m_contentScale;
|
||||
const float groupGap = Style::spaceXs * m_contentScale;
|
||||
const float groupPadCross = Style::spaceXs * 0.35f * m_contentScale;
|
||||
const float groupPadEnd = Style::spaceXs * 0.55f * m_contentScale;
|
||||
@@ -270,7 +269,7 @@ void TaskbarWidget::buildTaskButtons(Renderer& renderer) {
|
||||
group->setFrameSize(groupWidth, groupHeight);
|
||||
group->setFill(colorSpecFromRole(ColorRole::SurfaceVariant, ws.workspace.active ? 0.52f : 0.18f));
|
||||
group->setBorder(colorSpecFromRole(ColorRole::Primary, ws.workspace.active ? 0.65f : 0.16f), Style::borderWidth);
|
||||
group->setRadius(capsuleRadius);
|
||||
group->setRadius(resolvedBarCapsuleRadius(groupWidth, groupHeight));
|
||||
auto* groupPtr = static_cast<Box*>(m_taskStrip->addChild(std::move(group)));
|
||||
|
||||
if (tasks.empty()) {
|
||||
|
||||
@@ -598,10 +598,17 @@ namespace settings {
|
||||
if (!spec.visibleWhen.has_value()) {
|
||||
return true;
|
||||
}
|
||||
const auto& cond = *spec.visibleWhen;
|
||||
const auto currentValue = settingCurrentString(cfg, widgetName, cond.key, allSpecs);
|
||||
for (const auto& v : cond.values) {
|
||||
if (v == currentValue) {
|
||||
auto matches = [&](const std::string& key, const std::vector<std::string>& values) {
|
||||
const auto currentValue = settingCurrentString(cfg, widgetName, key, allSpecs);
|
||||
for (const auto& v : values) {
|
||||
if (v == currentValue) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (const auto& condition : spec.visibleWhen->any) {
|
||||
if (matches(condition.key, condition.values)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,6 +413,16 @@ namespace settings {
|
||||
} else if (type == "taskbar") {
|
||||
add(boolSpec("group_by_workspace", false));
|
||||
add(boolSpec("show_all_outputs", false));
|
||||
for (auto& spec : specs) {
|
||||
if (spec.key == "capsule_radius") {
|
||||
spec.descriptionKey = "settings.widgets.settings.capsule_radius.taskbar-description";
|
||||
spec.visibleWhen = WidgetSettingVisibility{
|
||||
WidgetSettingVisibilityCondition{"capsule", {"true"}},
|
||||
WidgetSettingVisibilityCondition{"group_by_workspace", {"true"}},
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (type == "tray") {
|
||||
add(stringListSpec("hidden"));
|
||||
add(stringListSpec("pinned"));
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
#include "config/config_service.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace settings {
|
||||
@@ -53,11 +55,20 @@ namespace settings {
|
||||
std::string_view labelKey;
|
||||
};
|
||||
|
||||
struct WidgetSettingVisibility {
|
||||
struct WidgetSettingVisibilityCondition {
|
||||
std::string key;
|
||||
std::vector<std::string> values;
|
||||
};
|
||||
|
||||
struct WidgetSettingVisibility {
|
||||
std::vector<WidgetSettingVisibilityCondition> any;
|
||||
|
||||
WidgetSettingVisibility() = default;
|
||||
WidgetSettingVisibility(std::string key, std::vector<std::string> values)
|
||||
: any{WidgetSettingVisibilityCondition{std::move(key), std::move(values)}} {}
|
||||
WidgetSettingVisibility(std::initializer_list<WidgetSettingVisibilityCondition> alternatives) : any(alternatives) {}
|
||||
};
|
||||
|
||||
struct WidgetSettingSpec {
|
||||
std::string key;
|
||||
std::string labelKey;
|
||||
|
||||
Reference in New Issue
Block a user