Add options for reordering widget layout.

Partially implements https://github.com/scorpion-26/gBar/issues/48 and https://github.com/scorpion-26/gBar/issues/20
This commit is contained in:
scorpion-26 2023-10-21 18:32:51 +02:00
parent b19b091c92
commit 996a6611ad
6 changed files with 303 additions and 72 deletions

View file

@ -7,6 +7,18 @@
# - After the ':'
# - After the value
# The following three options control the ordering of the widgets.
# Reordering can cause slight margin inconsistencies,
# so it is recommend to only make minor adjustments to the default layout.
# Adding the same widget multiple times to the layout is *not* supported and will cause issues.
# Widgets to show on the left side
WidgetsLeft: [Workspaces]
# Widgets to center
WidgetsCenter: [Time]
# Widgets to display on the right side
WidgetsRight: [Tray, Packages, Audio, Bluetooth, Network, Disk, VRAM, GPU, RAM, CPU, Battery, Power]
# The CPU sensor to use
CPUThermalZone: /sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon2/temp1_input

View file

@ -358,19 +358,47 @@ namespace Bar
#endif
}
void WidgetSensor(Widget& parent, TimerCallback<Sensor>&& callback, const std::string& sensorClass, const std::string& textClass, Text*& textPtr)
enum Side
{
Left,
Right,
Center
};
Alignment SideToAlignment(Side side)
{
switch (side)
{
case Left: return Alignment::Left;
case Right: return Alignment::Right;
case Center: return Alignment::Fill;
}
}
TransitionType SideToDefaultTransition(Side side)
{
switch (side)
{
case Right:
case Center: return TransitionType::SlideLeft;
case Left: return TransitionType::SlideRight;
}
}
void WidgetSensor(Widget& parent, TimerCallback<Sensor>&& callback, const std::string& sensorClass, const std::string& textClass, Text*& textPtr,
Side side)
{
auto eventBox = Widget::Create<EventBox>();
Utils::SetTransform(*eventBox, {-1, false, SideToAlignment(side)});
{
auto box = Widget::Create<Box>();
box->SetSpacing({0, false});
Utils::SetTransform(*box, {-1, true, Alignment::Right});
box->SetOrientation(Utils::GetOrientation());
{
auto revealer = Widget::Create<Revealer>();
if (!Config::Get().sensorTooltips)
{
auto revealer = Widget::Create<Revealer>();
revealer->SetTransition({Utils::GetTransitionType(), 500});
revealer->SetTransition({Utils::GetTransitionType(SideToDefaultTransition(side)), 500});
// Add event to eventbox for the revealer to open
eventBox->SetHoverFn(
[textRevealer = revealer.get()](EventBox&, bool hovered)
@ -381,11 +409,13 @@ namespace Bar
auto text = Widget::Create<Text>();
text->SetClass(textClass);
text->SetAngle(Utils::GetAngle());
Utils::SetTransform(*text, {-1, true, Alignment::Fill, 0, 6});
// Since we don't know, on which side the text is, add padding to both sides.
// This creates double padding on the side opposite to the sensor.
// TODO: Remove that padding.
Utils::SetTransform(*text, {-1, true, Alignment::Fill, 6, 6});
textPtr = text.get();
revealer->AddChild(std::move(text));
}
box->AddChild(std::move(revealer));
}
auto sensor = Widget::Create<Sensor>();
@ -402,7 +432,25 @@ namespace Bar
sensor->AddTimer<Sensor>(std::move(callback), DynCtx::updateTime);
Utils::SetTransform(*sensor, {24, true, Alignment::Fill});
box->AddChild(std::move(sensor));
switch (side)
{
case Side::Right:
case Side::Center:
{
if (!Config::Get().sensorTooltips)
box->AddChild(std::move(revealer));
box->AddChild(std::move(sensor));
break;
}
case Side::Left:
{
// Invert
box->AddChild(std::move(sensor));
if (!Config::Get().sensorTooltips)
box->AddChild(std::move(revealer));
break;
}
}
}
eventBox->AddChild(std::move(box));
}
@ -411,7 +459,7 @@ namespace Bar
}
// Handles in and out
void WidgetAudio(Widget& parent)
void WidgetAudio(Widget& parent, Side side)
{
enum class AudioType
{
@ -477,11 +525,11 @@ namespace Bar
}
};
auto widgetAudioBody = [&widgetAudioVolume](Widget& parent, AudioType type)
auto widgetAudioBody = [&widgetAudioVolume, side](Widget& parent, AudioType type)
{
auto box = Widget::Create<Box>();
box->SetSpacing({8, false});
Utils::SetTransform(*box, {-1, true, Alignment::Right});
Utils::SetTransform(*box, {-1, false, SideToAlignment(side)});
box->SetOrientation(Utils::GetOrientation());
{
auto icon = Widget::Create<Text>();
@ -505,7 +553,7 @@ namespace Bar
{
EventBox& eventBox = (EventBox&)parent;
auto revealer = Widget::Create<Revealer>();
revealer->SetTransition({Utils::GetTransitionType(), 500});
revealer->SetTransition({Utils::GetTransitionType(SideToDefaultTransition(side)), 500});
// Add event to eventbox for the revealer to open
eventBox.SetHoverFn(
[slideRevealer = revealer.get()](EventBox&, bool hovered)
@ -555,7 +603,7 @@ namespace Bar
parent.AddTimer<Widget>(DynCtx::UpdateAudio, DynCtx::updateTimeFast);
}
void WidgetPackages(Widget& parent)
void WidgetPackages(Widget& parent, Side)
{
auto text = Widget::Create<Text>();
text->SetText("");
@ -567,16 +615,19 @@ namespace Bar
}
#ifdef WITH_BLUEZ
void WidgetBluetooth(Widget& parent)
void WidgetBluetooth(Widget& parent, Side side)
{
auto box = Widget::Create<Box>();
box->SetSpacing({0, false});
box->SetOrientation(Utils::GetOrientation());
Utils::SetTransform(*box, {-1, false, SideToAlignment(side)});
{
auto devText = Widget::Create<Text>();
devText->SetAngle(Utils::GetAngle());
DynCtx::btDevText = devText.get();
devText->SetClass("bt-num");
if (side == Side::Left)
Utils::SetTransform(*devText, {-1, true, Alignment::Fill, 6, 0});
auto iconText = Widget::Create<Button>();
iconText->OnClick(DynCtx::OnBTClick);
@ -584,8 +635,23 @@ namespace Bar
Utils::SetTransform(*iconText, {-1, true, Alignment::Fill, 0, 6});
DynCtx::btIconText = iconText.get();
box->AddChild(std::move(devText));
box->AddChild(std::move(iconText));
switch (side)
{
case Side::Right:
case Side::Center:
{
box->AddChild(std::move(devText));
box->AddChild(std::move(iconText));
break;
}
case Side::Left:
{
// Invert
box->AddChild(std::move(iconText));
box->AddChild(std::move(devText));
break;
}
}
}
box->AddTimer<Box>(DynCtx::UpdateBluetooth, DynCtx::updateTime);
@ -593,19 +659,19 @@ namespace Bar
}
#endif
void WidgetNetwork(Widget& parent)
void WidgetNetwork(Widget& parent, Side side)
{
auto eventBox = Widget::Create<EventBox>();
Utils::SetTransform(*eventBox, {-1, false, SideToAlignment(side)});
{
auto box = Widget::Create<Box>();
box->SetSpacing({0, false});
Utils::SetTransform(*box, {-1, true, Alignment::Right});
box->SetOrientation(Utils::GetOrientation());
{
auto revealer = Widget::Create<Revealer>();
if (!Config::Get().sensorTooltips)
{
auto revealer = Widget::Create<Revealer>();
revealer->SetTransition({Utils::GetTransitionType(), 500});
revealer->SetTransition({Utils::GetTransitionType(SideToDefaultTransition(side)), 500});
// Add event to eventbox for the revealer to open
eventBox->SetHoverFn(
[textRevealer = revealer.get()](EventBox&, bool hovered)
@ -616,11 +682,11 @@ namespace Bar
auto text = Widget::Create<Text>();
text->SetClass("network-data-text");
text->SetAngle(Utils::GetAngle());
Utils::SetTransform(*text, {-1, true, Alignment::Fill, 0, 6});
// Margins have the same problem as the WidgetSensor ones...
Utils::SetTransform(*text, {-1, true, Alignment::Fill, 6, 6});
DynCtx::networkText = text.get();
revealer->AddChild(std::move(text));
}
box->AddChild(std::move(revealer));
}
auto sensor = Widget::Create<NetworkSensor>();
@ -630,7 +696,25 @@ namespace Bar
sensor->AddTimer<NetworkSensor>(DynCtx::UpdateNetwork, DynCtx::updateTime);
Utils::SetTransform(*sensor, {24, true, Alignment::Fill});
box->AddChild(std::move(sensor));
switch (side)
{
case Side::Right:
case Side::Center:
{
if (!Config::Get().sensorTooltips)
box->AddChild(std::move(revealer));
box->AddChild(std::move(sensor));
break;
}
case Side::Left:
{
// Invert
box->AddChild(std::move(sensor));
if (!Config::Get().sensorTooltips)
box->AddChild(std::move(revealer));
break;
}
}
}
eventBox->AddChild(std::move(box));
}
@ -638,26 +722,26 @@ namespace Bar
parent.AddChild(std::move(eventBox));
}
void WidgetSensors(Widget& parent)
void WidgetSensors(Widget& parent, Side side)
{
WidgetSensor(parent, DynCtx::UpdateDisk, "disk-util-progress", "disk-data-text", DynCtx::diskText);
WidgetSensor(parent, DynCtx::UpdateDisk, "disk-util-progress", "disk-data-text", DynCtx::diskText, side);
#if defined WITH_NVIDIA || defined WITH_AMD
if (RuntimeConfig::Get().hasNvidia || RuntimeConfig::Get().hasAMD)
{
WidgetSensor(parent, DynCtx::UpdateVRAM, "vram-util-progress", "vram-data-text", DynCtx::vramText);
WidgetSensor(parent, DynCtx::UpdateGPU, "gpu-util-progress", "gpu-data-text", DynCtx::gpuText);
WidgetSensor(parent, DynCtx::UpdateVRAM, "vram-util-progress", "vram-data-text", DynCtx::vramText, side);
WidgetSensor(parent, DynCtx::UpdateGPU, "gpu-util-progress", "gpu-data-text", DynCtx::gpuText, side);
}
#endif
WidgetSensor(parent, DynCtx::UpdateRAM, "ram-util-progress", "ram-data-text", DynCtx::ramText);
WidgetSensor(parent, DynCtx::UpdateCPU, "cpu-util-progress", "cpu-data-text", DynCtx::cpuText);
WidgetSensor(parent, DynCtx::UpdateRAM, "ram-util-progress", "ram-data-text", DynCtx::ramText, side);
WidgetSensor(parent, DynCtx::UpdateCPU, "cpu-util-progress", "cpu-data-text", DynCtx::cpuText, side);
// Only show battery percentage if battery folder is set and exists
if (System::GetBatteryPercentage() >= 0)
{
WidgetSensor(parent, DynCtx::UpdateBattery, "battery-util-progress", "battery-data-text", DynCtx::batteryText);
WidgetSensor(parent, DynCtx::UpdateBattery, "battery-util-progress", "battery-data-text", DynCtx::batteryText, side);
}
}
void WidgetPower(Widget& parent)
void WidgetPower(Widget& parent, Side side)
{
// TODO: Abstract this (Currently not DRY)
static bool activatedExit = false;
@ -689,16 +773,16 @@ namespace Bar
auto eventBox = Widget::Create<EventBox>();
eventBox->SetHoverFn(DynCtx::PowerBoxEvent);
Utils::SetTransform(*eventBox, {-1, false, SideToAlignment(side)});
{
auto powerBox = Widget::Create<Box>();
powerBox->SetClass("power-box");
Utils::SetTransform(*powerBox, {-1, false, Alignment::Right});
powerBox->SetSpacing({0, false});
powerBox->SetOrientation(Utils::GetOrientation());
{
auto revealer = Widget::Create<Revealer>();
DynCtx::powerBoxRevealer = revealer.get();
revealer->SetTransition({Utils::GetTransitionType(), 500});
revealer->SetTransition({Utils::GetTransitionType(SideToDefaultTransition(side)), 500});
{
auto powerBoxExpand = Widget::Create<Box>();
powerBoxExpand->SetClass("power-box-expand");
@ -792,7 +876,7 @@ namespace Bar
powerButton->SetClass("power-button");
powerButton->SetText("");
powerButton->SetAngle(Utils::GetAngle());
Utils::SetTransform(*powerButton, {24, true, Alignment::Fill});
Utils::SetTransform(*powerButton, {24, false, Alignment::Fill});
powerButton->OnClick(
[setActivate](Button& but)
{
@ -807,8 +891,23 @@ namespace Bar
}
});
powerBox->AddChild(std::move(revealer));
powerBox->AddChild(std::move(powerButton));
switch (side)
{
case Side::Right:
case Side::Center:
{
powerBox->AddChild(std::move(revealer));
powerBox->AddChild(std::move(powerButton));
break;
}
case Side::Left:
{
// Invert
powerBox->AddChild(std::move(powerButton));
powerBox->AddChild(std::move(revealer));
break;
}
}
}
eventBox->AddChild(std::move(powerBox));
}
@ -817,15 +916,15 @@ namespace Bar
}
#ifdef WITH_WORKSPACES
void WidgetWorkspaces(Widget& parent)
void WidgetWorkspaces(Widget& parent, Side side)
{
auto eventBox = Widget::Create<EventBox>();
eventBox->SetScrollFn(DynCtx::ScrollWorkspaces);
Utils::SetTransform(*eventBox, {-1, false, SideToAlignment(side)});
{
auto box = Widget::Create<Box>();
box->SetSpacing({8, true});
box->SetOrientation(Utils::GetOrientation());
Utils::SetTransform(*box, {-1, true, Alignment::Left, 12, 0});
{
DynCtx::workspaces.resize(Config::Get().numWorkspaces);
for (size_t i = 0; i < DynCtx::workspaces.size(); i++)
@ -848,6 +947,119 @@ namespace Bar
}
#endif
void WidgetTime(Widget& parent, Side side)
{
auto time = Widget::Create<Text>();
Utils::SetTransform(*time, {-1, false, SideToAlignment(side)});
time->SetAngle(Utils::GetAngle());
time->SetClass("time-text");
time->SetText("Uninitialized");
time->AddTimer<Text>(DynCtx::UpdateTime, 1000);
parent.AddChild(std::move(time));
}
void ChooseWidgetToDraw(const std::string& widgetName, Widget& parent, Side side)
{
if (widgetName == "Workspaces")
{
#ifdef WITH_WORKSPACES
if (RuntimeConfig::Get().hasWorkspaces)
{
WidgetWorkspaces(parent, side);
}
#endif
return;
}
if (widgetName == "Time")
{
WidgetTime(parent, side);
return;
}
if (widgetName == "Tray")
{
#ifdef WITH_SNI
SNI::WidgetSNI(parent);
#endif
return;
}
if (widgetName == "Packages")
{
WidgetPackages(parent, side);
return;
}
if (widgetName == "Audio")
{
WidgetAudio(parent, side);
return;
}
if (widgetName == "Bluetooth")
{
#ifdef WITH_BLUEZ
if (RuntimeConfig::Get().hasBlueZ)
WidgetBluetooth(parent, side);
#endif
return;
}
if (widgetName == "Network")
{
if (Config::Get().networkWidget && RuntimeConfig::Get().hasNet)
WidgetNetwork(parent, side);
return;
}
// Cheeky shorthand for all sensors
if (widgetName == "Sensors")
{
WidgetSensors(parent, side);
return;
}
if (widgetName == "Disk")
{
WidgetSensor(parent, DynCtx::UpdateDisk, "disk-util-progress", "disk-data-text", DynCtx::diskText, side);
return;
}
if (widgetName == "VRAM")
{
#if defined WITH_NVIDIA || defined WITH_AMD
if (RuntimeConfig::Get().hasNvidia || RuntimeConfig::Get().hasAMD)
WidgetSensor(parent, DynCtx::UpdateVRAM, "vram-util-progress", "vram-data-text", DynCtx::vramText, side);
return;
#endif
}
if (widgetName == "GPU")
{
#if defined WITH_NVIDIA || defined WITH_AMD
if (RuntimeConfig::Get().hasNvidia || RuntimeConfig::Get().hasAMD)
WidgetSensor(parent, DynCtx::UpdateGPU, "gpu-util-progress", "gpu-data-text", DynCtx::gpuText, side);
return;
#endif
}
if (widgetName == "RAM")
{
WidgetSensor(parent, DynCtx::UpdateRAM, "ram-util-progress", "ram-data-text", DynCtx::ramText, side);
return;
}
if (widgetName == "CPU")
{
WidgetSensor(parent, DynCtx::UpdateCPU, "cpu-util-progress", "cpu-data-text", DynCtx::cpuText, side);
return;
}
if (widgetName == "Battery")
{
// Only show battery percentage if battery folder is set and exists
if (System::GetBatteryPercentage() >= 0)
WidgetSensor(parent, DynCtx::UpdateBattery, "battery-util-progress", "battery-data-text", DynCtx::batteryText, side);
return;
}
if (widgetName == "Power")
{
WidgetPower(parent, side);
return;
}
LOG("Warning: Unkwown widget name " << widgetName << "!"
<< "\n\tKnown names are: Workspaces, Time, Tray, Packages, Sound, Bluetooth, Network, Sensors, Disk, "
"VRAM, GPU, RAM, CPU, Battery, Power");
}
void Create(Window& window, int32_t monitor)
{
monitorID = monitor;
@ -871,55 +1083,36 @@ namespace Bar
}
auto left = Widget::Create<Box>();
left->SetSpacing({0, false});
left->SetSpacing({6, false});
left->SetOrientation(Utils::GetOrientation());
// For centerTime the width of the left widget handles the centering.
// For not centerTime we want to set it as much right as possible. So let this expand as much as possible.
Utils::SetTransform(*left, {endLeftWidgets, !Config::Get().centerTime, Alignment::Left});
#ifdef WITH_WORKSPACES
if (RuntimeConfig::Get().hasWorkspaces)
Utils::SetTransform(*left, {endLeftWidgets, !Config::Get().centerTime, Alignment::Left, 12, 0});
for (auto& widget : Config::Get().widgetsLeft)
{
WidgetWorkspaces(*left);
ChooseWidgetToDraw(widget, *left, Side::Left);
}
#endif
auto center = Widget::Create<Box>();
center->SetOrientation(Utils::GetOrientation());
Utils::SetTransform(*center, {(int)Config::Get().timeSpace, false, Alignment::Left});
center->SetSpacing({6, false});
for (auto& widget : Config::Get().widgetsCenter)
{
auto time = Widget::Create<Text>();
Utils::SetTransform(*time, {-1, true, Alignment::Center});
time->SetAngle(Utils::GetAngle());
time->SetClass("time-text");
time->SetText("Uninitialized");
time->AddTimer<Text>(DynCtx::UpdateTime, 1000);
center->AddChild(std::move(time));
ChooseWidgetToDraw(widget, *center, Side::Center);
}
auto right = Widget::Create<Box>();
right->SetClass("right");
right->SetSpacing({8, false});
right->SetSpacing({6, false});
right->SetOrientation(Utils::GetOrientation());
Utils::SetTransform(*right, {-1, true, Alignment::Right, 0, 10});
for (auto& widget : Config::Get().widgetsRight)
{
#ifdef WITH_SNI
SNI::WidgetSNI(*right);
#endif
WidgetPackages(*right);
WidgetAudio(*right);
#ifdef WITH_BLUEZ
if (RuntimeConfig::Get().hasBlueZ)
WidgetBluetooth(*right);
#endif
if (Config::Get().networkWidget && RuntimeConfig::Get().hasNet)
WidgetNetwork(*right);
WidgetSensors(*right);
WidgetPower(*right);
ChooseWidgetToDraw(widget, *right, Side::Right);
}
mainWidget->AddChild(std::move(left));

View file

@ -220,6 +220,10 @@ void Config::Load()
}
bool foundProperty = false;
AddConfigVar("WidgetsLeft", config.widgetsLeft, lineView, foundProperty);
AddConfigVar("WidgetsCenter", config.widgetsCenter, lineView, foundProperty);
AddConfigVar("WidgetsRight", config.widgetsRight, lineView, foundProperty);
AddConfigVar("CPUThermalZone", config.cpuThermalZone, lineView, foundProperty);
AddConfigVar("NetworkAdapter", config.networkAdapter, lineView, foundProperty);
AddConfigVar("SuspendCommand", config.suspendCommand, lineView, foundProperty);

View file

@ -8,6 +8,10 @@
class Config
{
public:
std::vector<std::string> widgetsLeft = {"Workspaces"};
std::vector<std::string> widgetsCenter = {"Time"};
std::vector<std::string> widgetsRight = {"Tray", "Sound", "Bluetooth", "Network", "Disk", "VRAM", "GPU", "CPU", "Battery", "Power"};
std::string cpuThermalZone = ""; // idk, no standard way of doing this.
std::string networkAdapter = "eno1"; // Is this standard?
std::string suspendCommand = "systemctl suspend";

View file

@ -514,6 +514,7 @@ namespace SNI
}
// Add parent box
auto box = Widget::Create<Box>();
Utils::SetTransform(*box, {-1, false, Alignment::Fill});
auto container = Widget::Create<Box>();
container->AddTimer<Box>(UpdateWidgets, 1000, TimerDispatchBehaviour::LateDispatch);
iconBox = container.get();

View file

@ -423,14 +423,31 @@ namespace Utils
return 0;
}
inline TransitionType GetTransitionType()
// defaultTransition is the transition in top position
inline TransitionType GetTransitionType(TransitionType defaultTransition)
{
switch (Config::Get().location)
{
case 'T':
case 'B': return TransitionType::SlideLeft;
case 'B':
{
switch (defaultTransition)
{
case TransitionType::SlideLeft: return TransitionType::SlideLeft;
case TransitionType::SlideRight: return TransitionType::SlideRight;
default: ASSERT(false, "Utils::GetTransitionType(): Invalid defaultTransition!");
}
}
case 'L':
case 'R': return TransitionType::SlideUp;
case 'R':
{
switch (defaultTransition)
{
case TransitionType::SlideLeft: return TransitionType::SlideUp;
case TransitionType::SlideRight: return TransitionType::SlideDown;
default: ASSERT(false, "Utils::GetTransitionType(): Invalid defaultTransition!");
}
}
default: LOG("Invalid location char \"" << Config::Get().location << "\"!"); return TransitionType::SlideLeft;
}
}