mirror of
https://github.com/scorpion-26/gBar.git
synced 2024-11-23 03:32:51 +00:00
1f56e6ba15
Giving each main box element (left, center, right) caused the window to resize and clip out of the monitor when e.g. the right part was larger than the 1/3 of the window. Now we have a size for the center widget and try to manually center a box with that size by setting the left widget's size accordingly. This allows the right widget to have more room, so it can go right up to the center widget without issues.
764 lines
28 KiB
C++
764 lines
28 KiB
C++
#include "Bar.h"
|
|
|
|
#include "System.h"
|
|
#include "Common.h"
|
|
#include "Config.h"
|
|
#include "SNI.h"
|
|
#include <mutex>
|
|
|
|
namespace Bar
|
|
{
|
|
static int32_t monitorID;
|
|
|
|
namespace DynCtx
|
|
{
|
|
constexpr uint32_t updateTime = 1000;
|
|
constexpr uint32_t updateTimeFast = 100;
|
|
|
|
static Revealer* powerBoxRevealer;
|
|
static void PowerBoxEvent(EventBox&, bool hovered)
|
|
{
|
|
powerBoxRevealer->SetRevealed(hovered);
|
|
}
|
|
|
|
static Text* cpuText;
|
|
static TimerResult UpdateCPU(Sensor& sensor)
|
|
{
|
|
double usage = System::GetCPUUsage();
|
|
double temp = System::GetCPUTemp();
|
|
|
|
cpuText->SetText("CPU: " + Utils::ToStringPrecision(usage * 100, "%0.1f") + "% " + Utils::ToStringPrecision(temp, "%0.1f") + "°C");
|
|
sensor.SetValue(usage);
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
static Text* batteryText;
|
|
static TimerResult UpdateBattery(Sensor& sensor)
|
|
{
|
|
double percentage = System::GetBatteryPercentage();
|
|
|
|
batteryText->SetText("Battery: " + Utils::ToStringPrecision(percentage * 100, "%0.1f") + "%");
|
|
sensor.SetValue(percentage);
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
static Text* ramText;
|
|
static TimerResult UpdateRAM(Sensor& sensor)
|
|
{
|
|
System::RAMInfo info = System::GetRAMInfo();
|
|
double used = info.totalGiB - info.freeGiB;
|
|
double usedPercent = used / info.totalGiB;
|
|
|
|
ramText->SetText("RAM: " + Utils::ToStringPrecision(used, "%0.2f") + "GiB/" + Utils::ToStringPrecision(info.totalGiB, "%0.2f") + "GiB");
|
|
sensor.SetValue(usedPercent);
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
#if defined WITH_NVIDIA || defined WITH_AMD
|
|
static Text* gpuText;
|
|
static TimerResult UpdateGPU(Sensor& sensor)
|
|
{
|
|
System::GPUInfo info = System::GetGPUInfo();
|
|
|
|
gpuText->SetText("GPU: " + Utils::ToStringPrecision(info.utilisation, "%0.1f") + "% " + Utils::ToStringPrecision(info.coreTemp, "%0.1f") +
|
|
"°C");
|
|
sensor.SetValue(info.utilisation / 100);
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
static Text* vramText;
|
|
static TimerResult UpdateVRAM(Sensor& sensor)
|
|
{
|
|
System::VRAMInfo info = System::GetVRAMInfo();
|
|
|
|
vramText->SetText("VRAM: " + Utils::ToStringPrecision(info.usedGiB, "%0.2f") + "GiB/" + Utils::ToStringPrecision(info.totalGiB, "%0.2f") +
|
|
"GiB");
|
|
sensor.SetValue(info.usedGiB / info.totalGiB);
|
|
return TimerResult::Ok;
|
|
}
|
|
#endif
|
|
|
|
static Text* diskText;
|
|
static TimerResult UpdateDisk(Sensor& sensor)
|
|
{
|
|
System::DiskInfo info = System::GetDiskInfo();
|
|
|
|
diskText->SetText("Disk: " + Utils::ToStringPrecision(info.usedGiB, "%0.2f") + "GiB/" + Utils::ToStringPrecision(info.totalGiB, "%0.2f") +
|
|
"GiB");
|
|
sensor.SetValue(info.usedGiB / info.totalGiB);
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
#ifdef WITH_BLUEZ
|
|
static Button* btIconText;
|
|
static Text* btDevText;
|
|
static TimerResult UpdateBluetooth(Box&)
|
|
{
|
|
System::BluetoothInfo info = System::GetBluetoothInfo();
|
|
if (info.defaultController.empty())
|
|
{
|
|
btIconText->SetClass("bt-label-off");
|
|
btIconText->SetText("");
|
|
btDevText->SetText("");
|
|
}
|
|
else if (info.devices.empty())
|
|
{
|
|
btIconText->SetClass("bt-label-on");
|
|
btIconText->SetText("");
|
|
btDevText->SetText("");
|
|
}
|
|
else
|
|
{
|
|
btIconText->SetClass("bt-label-connected");
|
|
btIconText->SetText("");
|
|
std::string btDev;
|
|
std::string tooltip;
|
|
for (auto& dev : info.devices)
|
|
{
|
|
if (!dev.connected)
|
|
continue;
|
|
std::string ico = System::BTTypeToIcon(dev);
|
|
tooltip += dev.name + " & ";
|
|
btDev += ico;
|
|
}
|
|
// Delete last delim
|
|
if (tooltip.size())
|
|
tooltip.erase(tooltip.end() - 3, tooltip.end());
|
|
btDevText->SetTooltip(tooltip);
|
|
btDevText->SetText(std::move(btDev));
|
|
}
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
void OnBTClick(Button&)
|
|
{
|
|
System::OpenBTWidget();
|
|
}
|
|
#endif
|
|
|
|
static std::mutex packageTextLock;
|
|
static TimerResult UpdatePackages(Text& text)
|
|
{
|
|
System::GetOutdatedPackagesAsync(
|
|
[&](uint32_t numOutdatedPackages)
|
|
{
|
|
packageTextLock.lock();
|
|
if (numOutdatedPackages)
|
|
{
|
|
text.SetText(" ");
|
|
text.SetVisible(true);
|
|
text.SetClass("package-outofdate");
|
|
text.SetTooltip("Updates available! (" + std::to_string(numOutdatedPackages) + " packages)");
|
|
}
|
|
else
|
|
{
|
|
text.SetText("");
|
|
text.SetVisible(false);
|
|
text.SetClass("package-empty");
|
|
text.SetTooltip("");
|
|
}
|
|
packageTextLock.unlock();
|
|
});
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
void OnChangeVolumeSink(Slider&, double value)
|
|
{
|
|
System::SetVolumeSink(value);
|
|
}
|
|
|
|
void OnChangeVolumeSource(Slider&, double value)
|
|
{
|
|
System::SetVolumeSource(value);
|
|
}
|
|
|
|
Slider* audioSlider;
|
|
Slider* micSlider;
|
|
Text* audioIcon;
|
|
Text* micIcon;
|
|
TimerResult UpdateAudio(Widget&)
|
|
{
|
|
System::AudioInfo info = System::GetAudioInfo();
|
|
audioSlider->SetValue(info.sinkVolume);
|
|
if (info.sinkMuted)
|
|
{
|
|
audioIcon->SetText("");
|
|
}
|
|
else
|
|
{
|
|
audioIcon->SetText("");
|
|
}
|
|
if (Config::Get().audioInput)
|
|
{
|
|
micSlider->SetValue(info.sourceVolume);
|
|
if (info.sourceMuted)
|
|
{
|
|
micIcon->SetText("");
|
|
}
|
|
else
|
|
{
|
|
micIcon->SetText("");
|
|
}
|
|
}
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
Text* networkText;
|
|
TimerResult UpdateNetwork(NetworkSensor& sensor)
|
|
{
|
|
double bpsUp = System::GetNetworkBpsUpload(updateTime / 1000.0);
|
|
double bpsDown = System::GetNetworkBpsDownload(updateTime / 1000.0);
|
|
|
|
std::string upload = Utils::StorageUnitDynamic(bpsUp, "%0.1f%s");
|
|
std::string download = Utils::StorageUnitDynamic(bpsDown, "%0.1f%s");
|
|
|
|
networkText->SetText(Config::Get().networkAdapter + ": " + upload + " Up/" + download + " Down");
|
|
|
|
sensor.SetUp(bpsUp);
|
|
sensor.SetDown(bpsDown);
|
|
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
TimerResult UpdateTime(Text& text)
|
|
{
|
|
text.SetText(System::GetTime());
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
#ifdef WITH_WORKSPACES
|
|
static std::array<Button*, 9> workspaces;
|
|
TimerResult UpdateWorkspaces(Box&)
|
|
{
|
|
System::PollWorkspaces((uint32_t)monitorID, workspaces.size());
|
|
for (size_t i = 0; i < workspaces.size(); i++)
|
|
{
|
|
switch (System::GetWorkspaceStatus(i + 1))
|
|
{
|
|
case System::WorkspaceStatus::Dead: workspaces[i]->SetClass("ws-dead"); break;
|
|
case System::WorkspaceStatus::Inactive: workspaces[i]->SetClass("ws-inactive"); break;
|
|
case System::WorkspaceStatus::Visible: workspaces[i]->SetClass("ws-visible"); break;
|
|
case System::WorkspaceStatus::Current: workspaces[i]->SetClass("ws-current"); break;
|
|
case System::WorkspaceStatus::Active: workspaces[i]->SetClass("ws-active"); break;
|
|
}
|
|
workspaces[i]->SetText(System::GetWorkspaceSymbol(i));
|
|
}
|
|
return TimerResult::Ok;
|
|
}
|
|
|
|
void ScrollWorkspaces(EventBox&, ScrollDirection direction)
|
|
{
|
|
switch (direction)
|
|
{
|
|
case ScrollDirection::Up:
|
|
if (Config::Get().workspaceScrollInvert)
|
|
System::GotoNextWorkspace('+');
|
|
else
|
|
System::GotoNextWorkspace('-');
|
|
break;
|
|
case ScrollDirection::Down:
|
|
if (Config::Get().workspaceScrollInvert)
|
|
System::GotoNextWorkspace('-');
|
|
else
|
|
System::GotoNextWorkspace('+');
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void WidgetSensor(Widget& parent, TimerCallback<Sensor>&& callback, const std::string& sensorClass, const std::string& textClass, Text*& textPtr)
|
|
{
|
|
auto eventBox = Widget::Create<EventBox>();
|
|
{
|
|
auto box = Widget::Create<Box>();
|
|
box->SetSpacing({0, false});
|
|
box->SetHorizontalTransform({-1, true, Alignment::Right});
|
|
{
|
|
auto revealer = Widget::Create<Revealer>();
|
|
revealer->SetTransition({TransitionType::SlideLeft, 500});
|
|
// Add event to eventbox for the revealer to open
|
|
eventBox->SetHoverFn(
|
|
[textRevealer = revealer.get()](EventBox&, bool hovered)
|
|
{
|
|
textRevealer->SetRevealed(hovered);
|
|
});
|
|
{
|
|
auto text = Widget::Create<Text>();
|
|
text->SetClass(textClass);
|
|
textPtr = text.get();
|
|
revealer->AddChild(std::move(text));
|
|
}
|
|
|
|
auto sensor = Widget::Create<Sensor>();
|
|
sensor->SetClass(sensorClass);
|
|
sensor->AddTimer<Sensor>(std::move(callback), DynCtx::updateTime);
|
|
sensor->SetHorizontalTransform({24, true, Alignment::Fill});
|
|
|
|
box->AddChild(std::move(revealer));
|
|
box->AddChild(std::move(sensor));
|
|
}
|
|
eventBox->AddChild(std::move(box));
|
|
}
|
|
|
|
parent.AddChild(std::move(eventBox));
|
|
}
|
|
|
|
// Handles in and out
|
|
void WidgetAudio(Widget& parent)
|
|
{
|
|
enum class AudioType
|
|
{
|
|
Input,
|
|
Output
|
|
};
|
|
auto widgetAudioSlider = [](Widget& parent, AudioType type)
|
|
{
|
|
auto slider = Widget::Create<Slider>();
|
|
slider->SetOrientation(Orientation::Horizontal);
|
|
slider->SetHorizontalTransform({100, true, Alignment::Fill});
|
|
slider->SetInverted(true);
|
|
switch (type)
|
|
{
|
|
case AudioType::Input:
|
|
slider->SetClass("mic-volume");
|
|
slider->OnValueChange(DynCtx::OnChangeVolumeSource);
|
|
DynCtx::micSlider = slider.get();
|
|
break;
|
|
case AudioType::Output:
|
|
slider->SetClass("audio-volume");
|
|
slider->OnValueChange(DynCtx::OnChangeVolumeSink);
|
|
DynCtx::audioSlider = slider.get();
|
|
break;
|
|
}
|
|
slider->SetRange({0, 1, 0.01});
|
|
slider->SetScrollSpeed((double)Config::Get().audioScrollSpeed / 100.);
|
|
|
|
parent.AddChild(std::move(slider));
|
|
};
|
|
|
|
auto widgetAudioBody = [&widgetAudioSlider](Widget& parent, AudioType type)
|
|
{
|
|
auto box = Widget::Create<Box>();
|
|
box->SetSpacing({8, false});
|
|
box->SetHorizontalTransform({-1, true, Alignment::Right});
|
|
{
|
|
auto icon = Widget::Create<Text>();
|
|
switch (type)
|
|
{
|
|
case AudioType::Input:
|
|
icon->SetClass("mic-icon");
|
|
icon->SetText("");
|
|
DynCtx::micIcon = icon.get();
|
|
break;
|
|
case AudioType::Output:
|
|
icon->SetClass("audio-icon");
|
|
icon->SetText(" ");
|
|
DynCtx::audioIcon = icon.get();
|
|
break;
|
|
}
|
|
|
|
if (Config::Get().audioRevealer)
|
|
{
|
|
EventBox& eventBox = (EventBox&)parent;
|
|
auto revealer = Widget::Create<Revealer>();
|
|
revealer->SetTransition({TransitionType::SlideLeft, 500});
|
|
// Add event to eventbox for the revealer to open
|
|
eventBox.SetHoverFn(
|
|
[slideRevealer = revealer.get()](EventBox&, bool hovered)
|
|
{
|
|
slideRevealer->SetRevealed(hovered);
|
|
});
|
|
{
|
|
widgetAudioSlider(*revealer, type);
|
|
}
|
|
|
|
box->AddChild(std::move(revealer));
|
|
}
|
|
else
|
|
{
|
|
// Straight forward
|
|
widgetAudioSlider(*box, type);
|
|
}
|
|
|
|
box->AddChild(std::move(icon));
|
|
}
|
|
parent.AddChild(std::move(box));
|
|
};
|
|
|
|
if (Config::Get().audioRevealer)
|
|
{
|
|
// Need an EventBox
|
|
if (Config::Get().audioInput)
|
|
{
|
|
auto eventBox = Widget::Create<EventBox>();
|
|
widgetAudioBody(*eventBox, AudioType::Input);
|
|
parent.AddChild(std::move(eventBox));
|
|
}
|
|
// Need an EventBox
|
|
auto eventBox = Widget::Create<EventBox>();
|
|
widgetAudioBody(*eventBox, AudioType::Output);
|
|
parent.AddChild(std::move(eventBox));
|
|
}
|
|
else
|
|
{
|
|
// Just invoke it.
|
|
if (Config::Get().audioInput)
|
|
{
|
|
widgetAudioBody(parent, AudioType::Input);
|
|
}
|
|
widgetAudioBody(parent, AudioType::Output);
|
|
}
|
|
parent.AddTimer<Widget>(DynCtx::UpdateAudio, DynCtx::updateTimeFast);
|
|
}
|
|
|
|
void WidgetPackages(Widget& parent)
|
|
{
|
|
auto text = Widget::Create<Text>();
|
|
text->SetText("");
|
|
text->SetVisible(false);
|
|
text->SetClass("package-empty");
|
|
text->AddTimer<Text>(DynCtx::UpdatePackages, 1000 * Config::Get().checkUpdateInterval, TimerDispatchBehaviour::ImmediateDispatch);
|
|
parent.AddChild(std::move(text));
|
|
}
|
|
|
|
#ifdef WITH_BLUEZ
|
|
void WidgetBluetooth(Widget& parent)
|
|
{
|
|
auto box = Widget::Create<Box>();
|
|
box->SetSpacing({0, false});
|
|
{
|
|
auto devText = Widget::Create<Text>();
|
|
DynCtx::btDevText = devText.get();
|
|
devText->SetClass("bt-num");
|
|
|
|
auto iconText = Widget::Create<Button>();
|
|
iconText->OnClick(DynCtx::OnBTClick);
|
|
DynCtx::btIconText = iconText.get();
|
|
|
|
box->AddChild(std::move(devText));
|
|
box->AddChild(std::move(iconText));
|
|
}
|
|
box->AddTimer<Box>(DynCtx::UpdateBluetooth, DynCtx::updateTime);
|
|
|
|
parent.AddChild(std::move(box));
|
|
}
|
|
#endif
|
|
|
|
void WidgetNetwork(Widget& parent)
|
|
{
|
|
auto eventBox = Widget::Create<EventBox>();
|
|
{
|
|
auto box = Widget::Create<Box>();
|
|
box->SetSpacing({0, false});
|
|
box->SetHorizontalTransform({-1, true, Alignment::Right});
|
|
{
|
|
auto revealer = Widget::Create<Revealer>();
|
|
revealer->SetTransition({TransitionType::SlideLeft, 500});
|
|
// Add event to eventbox for the revealer to open
|
|
eventBox->SetHoverFn(
|
|
[textRevealer = revealer.get()](EventBox&, bool hovered)
|
|
{
|
|
textRevealer->SetRevealed(hovered);
|
|
});
|
|
{
|
|
auto text = Widget::Create<Text>();
|
|
text->SetClass("network-data-text");
|
|
DynCtx::networkText = text.get();
|
|
revealer->AddChild(std::move(text));
|
|
}
|
|
|
|
auto sensor = Widget::Create<NetworkSensor>();
|
|
sensor->SetLimitUp({(double)Config::Get().minUploadBytes, (double)Config::Get().maxUploadBytes});
|
|
sensor->SetLimitDown({(double)Config::Get().minDownloadBytes, (double)Config::Get().maxDownloadBytes});
|
|
sensor->AddTimer<NetworkSensor>(DynCtx::UpdateNetwork, DynCtx::updateTime);
|
|
sensor->SetHorizontalTransform({24, true, Alignment::Fill});
|
|
|
|
box->AddChild(std::move(revealer));
|
|
box->AddChild(std::move(sensor));
|
|
}
|
|
eventBox->AddChild(std::move(box));
|
|
}
|
|
|
|
parent.AddChild(std::move(eventBox));
|
|
}
|
|
|
|
void WidgetSensors(Widget& parent)
|
|
{
|
|
WidgetSensor(parent, DynCtx::UpdateDisk, "disk-util-progress", "disk-data-text", DynCtx::diskText);
|
|
#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);
|
|
}
|
|
#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);
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
void WidgetPower(Widget& parent)
|
|
{
|
|
// TODO: Abstract this (Currently not DRY)
|
|
static bool activatedExit = false;
|
|
static bool activatedLock = false;
|
|
static bool activatedSuspend = false;
|
|
static bool activatedReboot = false;
|
|
static bool activatedShutdown = false;
|
|
|
|
auto setActivate = [](Button& button, bool& activeBool, bool activate)
|
|
{
|
|
if (activate)
|
|
{
|
|
button.AddClass("system-confirm");
|
|
button.AddTimer<Button>(
|
|
[&](Button& button)
|
|
{
|
|
button.RemoveClass("system-confirm");
|
|
activeBool = false;
|
|
return TimerResult::Delete;
|
|
},
|
|
2000, TimerDispatchBehaviour::LateDispatch);
|
|
}
|
|
else
|
|
{
|
|
button.RemoveClass("system-confirm");
|
|
}
|
|
activeBool = activate;
|
|
};
|
|
|
|
auto eventBox = Widget::Create<EventBox>();
|
|
eventBox->SetHoverFn(DynCtx::PowerBoxEvent);
|
|
{
|
|
auto powerBox = Widget::Create<Box>();
|
|
powerBox->SetClass("power-box");
|
|
powerBox->SetHorizontalTransform({-1, false, Alignment::Right});
|
|
powerBox->SetSpacing({0, false});
|
|
{
|
|
auto revealer = Widget::Create<Revealer>();
|
|
DynCtx::powerBoxRevealer = revealer.get();
|
|
revealer->SetTransition({TransitionType::SlideLeft, 500});
|
|
{
|
|
auto powerBoxExpand = Widget::Create<Box>();
|
|
powerBoxExpand->SetClass("power-box-expand");
|
|
powerBoxExpand->SetSpacing({8, true});
|
|
{
|
|
auto exitButton = Widget::Create<Button>();
|
|
exitButton->SetClass("exit-button");
|
|
exitButton->SetText("");
|
|
exitButton->OnClick(
|
|
[setActivate](Button& but)
|
|
{
|
|
if (activatedExit)
|
|
{
|
|
System::ExitWM();
|
|
setActivate(but, activatedExit, false);
|
|
}
|
|
else
|
|
{
|
|
setActivate(but, activatedExit, true);
|
|
}
|
|
});
|
|
|
|
auto lockButton = Widget::Create<Button>();
|
|
lockButton->SetClass("sleep-button");
|
|
lockButton->SetText("");
|
|
lockButton->OnClick(
|
|
[setActivate](Button& but)
|
|
{
|
|
if (activatedLock)
|
|
{
|
|
System::Lock();
|
|
setActivate(but, activatedLock, false);
|
|
}
|
|
else
|
|
{
|
|
setActivate(but, activatedLock, true);
|
|
}
|
|
});
|
|
|
|
auto sleepButton = Widget::Create<Button>();
|
|
sleepButton->SetClass("sleep-button");
|
|
sleepButton->SetText("");
|
|
sleepButton->OnClick(
|
|
[setActivate](Button& but)
|
|
{
|
|
if (activatedSuspend)
|
|
{
|
|
System::Suspend();
|
|
setActivate(but, activatedSuspend, false);
|
|
}
|
|
else
|
|
{
|
|
setActivate(but, activatedSuspend, true);
|
|
}
|
|
});
|
|
|
|
auto rebootButton = Widget::Create<Button>();
|
|
rebootButton->SetClass("reboot-button");
|
|
rebootButton->SetText("");
|
|
rebootButton->OnClick(
|
|
[setActivate](Button& but)
|
|
{
|
|
if (activatedReboot)
|
|
{
|
|
System::Reboot();
|
|
setActivate(but, activatedReboot, false);
|
|
}
|
|
else
|
|
{
|
|
setActivate(but, activatedReboot, true);
|
|
}
|
|
});
|
|
|
|
powerBoxExpand->AddChild(std::move(exitButton));
|
|
powerBoxExpand->AddChild(std::move(lockButton));
|
|
powerBoxExpand->AddChild(std::move(sleepButton));
|
|
powerBoxExpand->AddChild(std::move(rebootButton));
|
|
}
|
|
|
|
revealer->AddChild(std::move(powerBoxExpand));
|
|
}
|
|
|
|
auto powerButton = Widget::Create<Button>();
|
|
powerButton->SetClass("power-button");
|
|
powerButton->SetText(" ");
|
|
powerButton->SetHorizontalTransform({24, true, Alignment::Fill});
|
|
powerButton->OnClick(
|
|
[setActivate](Button& but)
|
|
{
|
|
if (activatedShutdown)
|
|
{
|
|
System::Shutdown();
|
|
setActivate(but, activatedShutdown, false);
|
|
}
|
|
else
|
|
{
|
|
setActivate(but, activatedShutdown, true);
|
|
}
|
|
});
|
|
|
|
powerBox->AddChild(std::move(revealer));
|
|
powerBox->AddChild(std::move(powerButton));
|
|
}
|
|
eventBox->AddChild(std::move(powerBox));
|
|
}
|
|
|
|
parent.AddChild(std::move(eventBox));
|
|
}
|
|
|
|
#ifdef WITH_WORKSPACES
|
|
void WidgetWorkspaces(Widget& parent)
|
|
{
|
|
auto margin = Widget::Create<Box>();
|
|
margin->SetHorizontalTransform({12, false, Alignment::Left});
|
|
parent.AddChild(std::move(margin));
|
|
auto eventBox = Widget::Create<EventBox>();
|
|
eventBox->SetScrollFn(DynCtx::ScrollWorkspaces);
|
|
{
|
|
auto box = Widget::Create<Box>();
|
|
box->SetSpacing({8, true});
|
|
box->SetHorizontalTransform({-1, true, Alignment::Left});
|
|
{
|
|
for (size_t i = 0; i < DynCtx::workspaces.size(); i++)
|
|
{
|
|
auto workspace = Widget::Create<Button>();
|
|
workspace->SetHorizontalTransform({8, false, Alignment::Fill});
|
|
workspace->OnClick(
|
|
[i](Button&)
|
|
{
|
|
System::GotoWorkspace((uint32_t)i + 1);
|
|
});
|
|
DynCtx::workspaces[i] = workspace.get();
|
|
box->AddChild(std::move(workspace));
|
|
}
|
|
}
|
|
box->AddTimer<Box>(DynCtx::UpdateWorkspaces, DynCtx::updateTimeFast);
|
|
eventBox->AddChild(std::move(box));
|
|
}
|
|
parent.AddChild(std::move(eventBox));
|
|
}
|
|
#endif
|
|
|
|
void Create(Window& window, int32_t monitor)
|
|
{
|
|
monitorID = monitor;
|
|
|
|
auto mainWidget = Widget::Create<Box>();
|
|
mainWidget->SetSpacing({0, false});
|
|
mainWidget->SetClass("bar");
|
|
{
|
|
// Calculate how much space we need have for the left widget.
|
|
// The center widget will come directly after that.
|
|
// This ensures that the center widget is centered.
|
|
int windowCenter = window.GetWidth() / 2;
|
|
int endLeftWidgets = windowCenter - Config::Get().timeSpace / 2;
|
|
|
|
if (!Config::Get().centerTime)
|
|
{
|
|
// Don't care if time is centered or not.
|
|
endLeftWidgets = -1;
|
|
}
|
|
|
|
auto left = Widget::Create<Box>();
|
|
left->SetSpacing({0, false});
|
|
// 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.
|
|
left->SetHorizontalTransform({endLeftWidgets, !Config::Get().centerTime, Alignment::Left});
|
|
#ifdef WITH_WORKSPACES
|
|
if (RuntimeConfig::Get().hasWorkspaces)
|
|
{
|
|
WidgetWorkspaces(*left);
|
|
}
|
|
#endif
|
|
|
|
auto center = Widget::Create<Box>();
|
|
center->SetHorizontalTransform({(int)Config::Get().timeSpace, false, Alignment::Left});
|
|
{
|
|
auto time = Widget::Create<Text>();
|
|
time->SetHorizontalTransform({-1, true, Alignment::Center});
|
|
time->SetClass("time-text");
|
|
time->SetText("Uninitialized");
|
|
time->AddTimer<Text>(DynCtx::UpdateTime, 1000);
|
|
center->AddChild(std::move(time));
|
|
}
|
|
|
|
auto right = Widget::Create<Box>();
|
|
right->SetClass("right");
|
|
right->SetSpacing({8, false});
|
|
right->SetHorizontalTransform({-1, true, Alignment::Right});
|
|
{
|
|
#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);
|
|
}
|
|
|
|
mainWidget->AddChild(std::move(left));
|
|
mainWidget->AddChild(std::move(center));
|
|
mainWidget->AddChild(std::move(right));
|
|
}
|
|
window.SetAnchor(Anchor::Left | Anchor::Right | Anchor::Top);
|
|
window.SetMainWidget(std::move(mainWidget));
|
|
}
|
|
}
|