mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
feat(widgets): change active window indicator for taskbar from dot to configurable width line
This commit is contained in:
@@ -869,6 +869,10 @@
|
||||
"text": "Text"
|
||||
},
|
||||
"settings": {
|
||||
"active_indicator_width": {
|
||||
"label": "Active Indicator Width",
|
||||
"description": "Width of the active-task underline in pixels; set to 0 to hide"
|
||||
},
|
||||
"anchor": {
|
||||
"label": "Anchor",
|
||||
"description": "Pin this widget as the center alignment anchor"
|
||||
|
||||
@@ -47,10 +47,12 @@
|
||||
#include "ui/style.h"
|
||||
#include "wayland/wayland_connection.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
constexpr Logger kLog("shell");
|
||||
constexpr double kTaskbarActiveIndicatorWidthMax = 15.0;
|
||||
|
||||
std::string resolveDistroLogo(IconResolver& iconResolver) {
|
||||
if (const auto info = DistroDetector::detect(); info.has_value()) {
|
||||
@@ -325,7 +327,10 @@ std::unique_ptr<Widget> WidgetFactory::create(const std::string& name, wl_output
|
||||
|
||||
if (type == "taskbar") {
|
||||
const bool groupByWorkspace = wc != nullptr ? wc->getBool("group_by_workspace", false) : false;
|
||||
auto widget = std::make_unique<TaskbarWidget>(m_wayland, output, groupByWorkspace, barPosition);
|
||||
const double rawWidth = wc != nullptr ? wc->getDouble("active_indicator_width", 14.0) : 14.0;
|
||||
const float activeIndicatorWidth = static_cast<float>(std::clamp(rawWidth, 0.0, kTaskbarActiveIndicatorWidthMax));
|
||||
auto widget =
|
||||
std::make_unique<TaskbarWidget>(m_wayland, output, groupByWorkspace, barPosition, activeIndicatorWidth);
|
||||
widget->setContentScale(contentScale);
|
||||
return widget;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
TaskbarWidget::TaskbarWidget(WaylandConnection& connection, wl_output* output, bool groupByWorkspace,
|
||||
std::string barPosition)
|
||||
std::string barPosition, float activeIndicatorWidth)
|
||||
: m_connection(connection), m_output(output), m_groupByWorkspace(groupByWorkspace),
|
||||
m_barPosition(std::move(barPosition)) {
|
||||
m_activeIndicatorWidth(activeIndicatorWidth), m_barPosition(std::move(barPosition)) {
|
||||
buildDesktopIconIndex();
|
||||
}
|
||||
|
||||
@@ -136,33 +136,33 @@ void TaskbarWidget::buildTaskButtons(Renderer& renderer) {
|
||||
const float iconSize = Style::barGlyphSize * m_contentScale;
|
||||
const float tilePadding = Style::spaceXs * 0.35f * m_contentScale;
|
||||
const float tileSize = iconSize + tilePadding * 2.0f;
|
||||
const float indicatorSize = std::max(2.0f, Style::spaceXs * 0.4f * m_contentScale);
|
||||
const auto workspaceAxisHandler = [this](const InputArea::PointerData& data) -> bool {
|
||||
if (!m_groupByWorkspace) {
|
||||
return false;
|
||||
}
|
||||
if (data.axis != WL_POINTER_AXIS_VERTICAL_SCROLL && data.axis != WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float delta = data.scrollDelta(1.0f);
|
||||
if (delta == 0.0f && data.axisValue120 != 0) {
|
||||
delta = static_cast<float>(data.axisValue120) / 120.0f;
|
||||
}
|
||||
if (delta == 0.0f && data.axisDiscrete != 0) {
|
||||
delta = static_cast<float>(data.axisDiscrete);
|
||||
}
|
||||
if (delta == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
activateAdjacentWorkspace(delta > 0.0f ? 1 : -1);
|
||||
return true;
|
||||
};
|
||||
auto createTaskTile = [&](const TaskModel& task) {
|
||||
auto area = std::make_unique<InputArea>();
|
||||
area->setFrameSize(tileSize, tileSize);
|
||||
area->setAcceptedButtons(BTN_LEFT | BTN_RIGHT);
|
||||
area->setOnAxisHandler([this](const InputArea::PointerData& data) {
|
||||
if (!m_groupByWorkspace) {
|
||||
return false;
|
||||
}
|
||||
if (data.axis != WL_POINTER_AXIS_VERTICAL_SCROLL && data.axis != WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float delta = data.scrollDelta(1.0f);
|
||||
if (delta == 0.0f && data.axisValue120 != 0) {
|
||||
delta = static_cast<float>(data.axisValue120) / 120.0f;
|
||||
}
|
||||
if (delta == 0.0f && data.axisDiscrete != 0) {
|
||||
delta = static_cast<float>(data.axisDiscrete);
|
||||
}
|
||||
if (delta == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
activateAdjacentWorkspace(delta > 0.0f ? 1 : -1);
|
||||
return true;
|
||||
});
|
||||
area->setOnAxisHandler(workspaceAxisHandler);
|
||||
|
||||
if (task.firstHandle != nullptr) {
|
||||
auto* areaPtr = area.get();
|
||||
@@ -194,12 +194,14 @@ void TaskbarWidget::buildTaskButtons(Renderer& renderer) {
|
||||
area->addChild(std::move(glyph));
|
||||
}
|
||||
|
||||
if (task.active) {
|
||||
const float lineWidth = m_activeIndicatorWidth * m_contentScale;
|
||||
if (task.active && lineWidth > 0.0f) {
|
||||
const float lineThickness = std::max(1.0f, Style::spaceXs * 0.25f * m_contentScale);
|
||||
auto indicator = std::make_unique<Box>();
|
||||
indicator->setFill(colorSpecFromRole(ColorRole::Primary));
|
||||
indicator->setRadius(indicatorSize * 0.5f);
|
||||
indicator->setFrameSize(indicatorSize, indicatorSize);
|
||||
indicator->setPosition(std::round((tileSize - indicatorSize) * 0.5f), std::round(tileSize - indicatorSize));
|
||||
indicator->setRadius(lineThickness * 0.5f);
|
||||
indicator->setFrameSize(lineWidth, lineThickness);
|
||||
indicator->setPosition(std::round((tileSize - lineWidth) * 0.5f), std::round(tileSize - lineThickness));
|
||||
area->addChild(std::move(indicator));
|
||||
}
|
||||
return area;
|
||||
@@ -254,28 +256,7 @@ void TaskbarWidget::buildTaskButtons(Renderer& renderer) {
|
||||
switcher->setFrameSize(groupWidth, groupHeight);
|
||||
switcher->setPosition(0.0f, 0.0f);
|
||||
switcher->setAcceptedButtons(BTN_LEFT);
|
||||
switcher->setOnAxisHandler([this](const InputArea::PointerData& data) {
|
||||
if (!m_groupByWorkspace) {
|
||||
return false;
|
||||
}
|
||||
if (data.axis != WL_POINTER_AXIS_VERTICAL_SCROLL && data.axis != WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float delta = data.scrollDelta(1.0f);
|
||||
if (delta == 0.0f && data.axisValue120 != 0) {
|
||||
delta = static_cast<float>(data.axisValue120) / 120.0f;
|
||||
}
|
||||
if (delta == 0.0f && data.axisDiscrete != 0) {
|
||||
delta = static_cast<float>(data.axisDiscrete);
|
||||
}
|
||||
if (delta == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
activateAdjacentWorkspace(delta > 0.0f ? 1 : -1);
|
||||
return true;
|
||||
});
|
||||
switcher->setOnAxisHandler(workspaceAxisHandler);
|
||||
auto wsCopy = ws.workspace;
|
||||
switcher->setOnClick([this, wsCopy](const InputArea::PointerData& data) {
|
||||
if (data.button == BTN_LEFT) {
|
||||
@@ -296,15 +277,30 @@ void TaskbarWidget::buildTaskButtons(Renderer& renderer) {
|
||||
groupPtr->addChild(std::move(tile));
|
||||
}
|
||||
|
||||
const float badgeLeft = std::round(badgeWidth * -0.32f);
|
||||
const float badgeTop = std::round(badgeBase * -0.22f);
|
||||
auto badgeHit = std::make_unique<InputArea>();
|
||||
badgeHit->setFrameSize(badgeWidth, badgeBase);
|
||||
badgeHit->setPosition(badgeLeft, badgeTop);
|
||||
badgeHit->setAcceptedButtons(BTN_LEFT);
|
||||
badgeHit->setOnAxisHandler(workspaceAxisHandler);
|
||||
auto wsForBadge = ws.workspace;
|
||||
badgeHit->setOnClick([this, wsForBadge](const InputArea::PointerData& data) {
|
||||
if (data.button == BTN_LEFT) {
|
||||
m_connection.activateWorkspace(m_output, wsForBadge);
|
||||
}
|
||||
});
|
||||
|
||||
auto badge = std::make_unique<Box>();
|
||||
badge->setFrameSize(badgeWidth, badgeBase);
|
||||
badge->setRadius(badgeBase * 0.5f);
|
||||
badge->setFill(colorSpecFromRole(ws.workspace.active ? ColorRole::Primary : ColorRole::Surface));
|
||||
badge->setBorder(colorSpecFromRole(ColorRole::Outline, 0.45f), Style::borderWidth);
|
||||
badge->setPosition(std::round(badgeWidth * -0.32f), std::round(badgeBase * -0.22f));
|
||||
auto* badgePtr = static_cast<Box*>(groupPtr->addChild(std::move(badge)));
|
||||
badge->setPosition(0.0f, 0.0f);
|
||||
auto* badgePtr = static_cast<Box*>(badgeHit->addChild(std::move(badge)));
|
||||
|
||||
auto badgeText = std::make_unique<Label>();
|
||||
badgeText->setHitTestVisible(false);
|
||||
badgeText->setText(ws.label);
|
||||
badgeText->setBold(true);
|
||||
badgeText->setFontSize(badgeFontSize);
|
||||
@@ -314,8 +310,9 @@ void TaskbarWidget::buildTaskButtons(Renderer& renderer) {
|
||||
std::round((badgeBase - badgeText->height()) * 0.5f));
|
||||
badgePtr->addChild(std::move(badgeText));
|
||||
if (tasks.empty()) {
|
||||
badgePtr->setHitTestVisible(false);
|
||||
badgeHit->setHitTestVisible(false);
|
||||
}
|
||||
groupPtr->addChild(std::move(badgeHit));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ struct PointerEvent;
|
||||
|
||||
class TaskbarWidget : public Widget {
|
||||
public:
|
||||
TaskbarWidget(WaylandConnection& connection, wl_output* output, bool groupByWorkspace, std::string barPosition);
|
||||
TaskbarWidget(WaylandConnection& connection, wl_output* output, bool groupByWorkspace, std::string barPosition,
|
||||
float activeIndicatorWidth);
|
||||
~TaskbarWidget() override;
|
||||
|
||||
void create() override;
|
||||
@@ -74,6 +75,7 @@ private:
|
||||
WaylandConnection& m_connection;
|
||||
wl_output* m_output = nullptr;
|
||||
bool m_groupByWorkspace = false;
|
||||
float m_activeIndicatorWidth = 0.0f;
|
||||
std::string m_barPosition;
|
||||
bool m_rebuildPending = true;
|
||||
bool m_vertical = false;
|
||||
|
||||
@@ -473,6 +473,7 @@ namespace settings {
|
||||
add(segmentedSpec("display", "gauge", sysmonDisplay));
|
||||
add(boolSpec("show_label", true));
|
||||
} else if (type == "taskbar") {
|
||||
add(doubleSpec("active_indicator_width", 14.0, 0.0, 15.0, 1.0));
|
||||
add(boolSpec("group_by_workspace", false));
|
||||
} else if (type == "tray") {
|
||||
add(stringListSpec("hidden"));
|
||||
|
||||
Reference in New Issue
Block a user