2023-01-13 15:13:56 +00:00
|
|
|
#include "Bar.h"
|
|
|
|
|
|
|
|
#include "System.h"
|
|
|
|
#include "Common.h"
|
2023-01-29 20:31:00 +00:00
|
|
|
#include "Config.h"
|
2023-03-17 23:02:40 +00:00
|
|
|
#include "SNI.h"
|
2023-05-03 16:37:36 +00:00
|
|
|
#include <mutex>
|
2023-01-13 15:13:56 +00:00
|
|
|
|
|
|
|
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;
|
2023-02-04 15:09:08 +00:00
|
|
|
static TimerResult UpdateCPU(Sensor& sensor)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-01-28 22:47:55 +00:00
|
|
|
static Text* batteryText;
|
2023-02-04 15:09:08 +00:00
|
|
|
static TimerResult UpdateBattery(Sensor& sensor)
|
2023-01-28 22:47:55 +00:00
|
|
|
{
|
|
|
|
double percentage = System::GetBatteryPercentage();
|
|
|
|
|
|
|
|
batteryText->SetText("Battery: " + Utils::ToStringPrecision(percentage * 100, "%0.1f") + "%");
|
|
|
|
sensor.SetValue(percentage);
|
|
|
|
return TimerResult::Ok;
|
|
|
|
}
|
|
|
|
|
2023-01-13 15:13:56 +00:00
|
|
|
static Text* ramText;
|
2023-02-04 15:09:08 +00:00
|
|
|
static TimerResult UpdateRAM(Sensor& sensor)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-01-30 16:23:28 +00:00
|
|
|
#if defined WITH_NVIDIA || defined WITH_AMD
|
2023-01-13 15:13:56 +00:00
|
|
|
static Text* gpuText;
|
2023-02-04 15:09:08 +00:00
|
|
|
static TimerResult UpdateGPU(Sensor& sensor)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
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;
|
2023-02-04 15:09:08 +00:00
|
|
|
static TimerResult UpdateVRAM(Sensor& sensor)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
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;
|
2023-02-04 15:09:08 +00:00
|
|
|
static TimerResult UpdateDisk(Sensor& sensor)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-01-30 15:57:15 +00:00
|
|
|
#ifdef WITH_BLUEZ
|
2023-01-14 22:18:34 +00:00
|
|
|
static Button* btIconText;
|
2023-01-13 15:13:56 +00:00
|
|
|
static Text* btDevText;
|
|
|
|
static TimerResult UpdateBluetooth(Box&)
|
|
|
|
{
|
|
|
|
System::BluetoothInfo info = System::GetBluetoothInfo();
|
|
|
|
if (info.defaultController.empty())
|
|
|
|
{
|
|
|
|
btIconText->SetClass("bt-label-off");
|
2023-05-04 21:25:57 +00:00
|
|
|
btIconText->SetText("");
|
2023-01-13 15:13:56 +00:00
|
|
|
btDevText->SetText("");
|
|
|
|
}
|
|
|
|
else if (info.devices.empty())
|
|
|
|
{
|
|
|
|
btIconText->SetClass("bt-label-on");
|
2023-05-03 21:21:21 +00:00
|
|
|
btIconText->SetText("");
|
2023-01-13 15:13:56 +00:00
|
|
|
btDevText->SetText("");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
btIconText->SetClass("bt-label-connected");
|
2023-05-03 21:21:21 +00:00
|
|
|
btIconText->SetText("");
|
2023-01-13 15:13:56 +00:00
|
|
|
std::string btDev;
|
2023-01-14 13:47:30 +00:00
|
|
|
std::string tooltip;
|
2023-01-13 15:13:56 +00:00
|
|
|
for (auto& dev : info.devices)
|
|
|
|
{
|
2023-01-14 22:18:34 +00:00
|
|
|
if (!dev.connected)
|
|
|
|
continue;
|
2023-01-15 10:09:06 +00:00
|
|
|
std::string ico = System::BTTypeToIcon(dev);
|
2023-01-14 13:47:30 +00:00
|
|
|
tooltip += dev.name + " & ";
|
2023-01-13 15:13:56 +00:00
|
|
|
btDev += ico;
|
|
|
|
}
|
2023-01-14 13:47:30 +00:00
|
|
|
// Delete last delim
|
|
|
|
if (tooltip.size())
|
|
|
|
tooltip.erase(tooltip.end() - 3, tooltip.end());
|
|
|
|
btDevText->SetTooltip(tooltip);
|
2023-01-13 15:13:56 +00:00
|
|
|
btDevText->SetText(std::move(btDev));
|
|
|
|
}
|
|
|
|
return TimerResult::Ok;
|
|
|
|
}
|
2023-01-14 22:18:34 +00:00
|
|
|
|
|
|
|
void OnBTClick(Button&)
|
|
|
|
{
|
|
|
|
System::OpenBTWidget();
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
#endif
|
|
|
|
|
2023-05-03 16:37:36 +00:00
|
|
|
static std::mutex packageTextLock;
|
|
|
|
static TimerResult UpdatePackages(Text& text)
|
|
|
|
{
|
|
|
|
System::GetOutdatedPackagesAsync(
|
|
|
|
[&](uint32_t numOutdatedPackages)
|
|
|
|
{
|
|
|
|
packageTextLock.lock();
|
|
|
|
if (numOutdatedPackages)
|
|
|
|
{
|
|
|
|
text.SetText(" ");
|
2023-05-03 17:02:26 +00:00
|
|
|
text.SetVisible(true);
|
2023-05-03 16:37:36 +00:00
|
|
|
text.SetClass("package-outofdate");
|
|
|
|
text.SetTooltip("Updates available! (" + std::to_string(numOutdatedPackages) + " packages)");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text.SetText("");
|
2023-05-03 17:02:26 +00:00
|
|
|
text.SetVisible(false);
|
2023-05-03 16:37:36 +00:00
|
|
|
text.SetClass("package-empty");
|
|
|
|
text.SetTooltip("");
|
|
|
|
}
|
|
|
|
packageTextLock.unlock();
|
|
|
|
});
|
|
|
|
return TimerResult::Ok;
|
|
|
|
}
|
|
|
|
|
2023-02-22 15:45:29 +00:00
|
|
|
void OnChangeVolumeSink(Slider&, double value)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-02-22 15:45:29 +00:00
|
|
|
System::SetVolumeSink(value);
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
|
2023-02-22 15:45:29 +00:00
|
|
|
void OnChangeVolumeSource(Slider&, double value)
|
|
|
|
{
|
|
|
|
System::SetVolumeSource(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
Slider* audioSlider;
|
|
|
|
Slider* micSlider;
|
2023-01-13 15:13:56 +00:00
|
|
|
Text* audioIcon;
|
2023-02-22 15:45:29 +00:00
|
|
|
Text* micIcon;
|
|
|
|
TimerResult UpdateAudio(Widget&)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
System::AudioInfo info = System::GetAudioInfo();
|
2023-02-22 15:45:29 +00:00
|
|
|
audioSlider->SetValue(info.sinkVolume);
|
|
|
|
if (info.sinkMuted)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-02-22 15:45:29 +00:00
|
|
|
audioIcon->SetText("");
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-02-22 15:45:29 +00:00
|
|
|
audioIcon->SetText("");
|
|
|
|
}
|
|
|
|
if (Config::Get().audioInput)
|
|
|
|
{
|
|
|
|
micSlider->SetValue(info.sourceVolume);
|
|
|
|
if (info.sourceMuted)
|
|
|
|
{
|
|
|
|
micIcon->SetText("");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
micIcon->SetText("");
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
return TimerResult::Ok;
|
|
|
|
}
|
|
|
|
|
2023-02-10 16:20:26 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-01-13 15:13:56 +00:00
|
|
|
TimerResult UpdateTime(Text& text)
|
|
|
|
{
|
|
|
|
text.SetText(System::GetTime());
|
|
|
|
return TimerResult::Ok;
|
|
|
|
}
|
|
|
|
|
2023-03-03 19:44:51 +00:00
|
|
|
#ifdef WITH_WORKSPACES
|
2023-01-13 15:13:56 +00:00
|
|
|
static std::array<Button*, 9> workspaces;
|
|
|
|
TimerResult UpdateWorkspaces(Box&)
|
|
|
|
{
|
2023-02-24 12:23:34 +00:00
|
|
|
System::PollWorkspaces((uint32_t)monitorID, workspaces.size());
|
2023-01-13 15:13:56 +00:00
|
|
|
for (size_t i = 0; i < workspaces.size(); i++)
|
|
|
|
{
|
2023-02-24 12:23:34 +00:00
|
|
|
switch (System::GetWorkspaceStatus(i + 1))
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-01-30 15:57:15 +00:00
|
|
|
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;
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
2023-01-29 11:07:24 +00:00
|
|
|
workspaces[i]->SetText(System::GetWorkspaceSymbol(i));
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
return TimerResult::Ok;
|
|
|
|
}
|
2023-02-12 13:57:32 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-02-04 15:09:08 +00:00
|
|
|
void WidgetSensor(Widget& parent, TimerCallback<Sensor>&& callback, const std::string& sensorClass, const std::string& textClass, Text*& textPtr)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
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
|
2023-02-12 13:28:46 +00:00
|
|
|
eventBox->SetHoverFn(
|
2023-01-13 15:13:56 +00:00
|
|
|
[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));
|
|
|
|
}
|
|
|
|
|
2023-02-04 15:09:08 +00:00
|
|
|
auto sensor = Widget::Create<Sensor>();
|
|
|
|
sensor->SetClass(sensorClass);
|
|
|
|
sensor->AddTimer<Sensor>(std::move(callback), DynCtx::updateTime);
|
|
|
|
sensor->SetHorizontalTransform({24, true, Alignment::Fill});
|
2023-01-13 15:13:56 +00:00
|
|
|
|
|
|
|
box->AddChild(std::move(revealer));
|
2023-02-04 15:09:08 +00:00
|
|
|
box->AddChild(std::move(sensor));
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
eventBox->AddChild(std::move(box));
|
|
|
|
}
|
|
|
|
|
|
|
|
parent.AddChild(std::move(eventBox));
|
|
|
|
}
|
|
|
|
|
2023-02-22 15:45:29 +00:00
|
|
|
// Handles in and out
|
2023-01-13 15:13:56 +00:00
|
|
|
void WidgetAudio(Widget& parent)
|
|
|
|
{
|
2023-02-22 15:45:29 +00:00
|
|
|
enum class AudioType
|
|
|
|
{
|
|
|
|
Input,
|
|
|
|
Output
|
|
|
|
};
|
|
|
|
auto widgetAudioSlider = [](Widget& parent, AudioType type)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
auto slider = Widget::Create<Slider>();
|
|
|
|
slider->SetOrientation(Orientation::Horizontal);
|
|
|
|
slider->SetHorizontalTransform({100, true, Alignment::Fill});
|
|
|
|
slider->SetInverted(true);
|
2023-02-22 15:45:29 +00:00
|
|
|
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;
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
slider->SetRange({0, 1, 0.01});
|
2023-02-20 22:04:37 +00:00
|
|
|
slider->SetScrollSpeed((double)Config::Get().audioScrollSpeed / 100.);
|
2023-01-13 15:13:56 +00:00
|
|
|
|
2023-02-04 14:07:05 +00:00
|
|
|
parent.AddChild(std::move(slider));
|
|
|
|
};
|
|
|
|
|
2023-02-22 15:45:29 +00:00
|
|
|
auto widgetAudioBody = [&widgetAudioSlider](Widget& parent, AudioType type)
|
2023-02-04 14:07:05 +00:00
|
|
|
{
|
|
|
|
auto box = Widget::Create<Box>();
|
|
|
|
box->SetSpacing({8, false});
|
|
|
|
box->SetHorizontalTransform({-1, true, Alignment::Right});
|
|
|
|
{
|
|
|
|
auto icon = Widget::Create<Text>();
|
2023-02-22 15:45:29 +00:00
|
|
|
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;
|
|
|
|
}
|
2023-02-04 14:07:05 +00:00
|
|
|
|
|
|
|
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
|
2023-02-12 13:28:46 +00:00
|
|
|
eventBox.SetHoverFn(
|
2023-02-04 14:07:05 +00:00
|
|
|
[slideRevealer = revealer.get()](EventBox&, bool hovered)
|
|
|
|
{
|
|
|
|
slideRevealer->SetRevealed(hovered);
|
|
|
|
});
|
|
|
|
{
|
2023-02-22 15:45:29 +00:00
|
|
|
widgetAudioSlider(*revealer, type);
|
2023-02-04 14:07:05 +00:00
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
|
2023-02-04 14:07:05 +00:00
|
|
|
box->AddChild(std::move(revealer));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Straight forward
|
2023-02-22 15:45:29 +00:00
|
|
|
widgetAudioSlider(*box, type);
|
2023-02-04 14:07:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
box->AddChild(std::move(icon));
|
|
|
|
}
|
|
|
|
parent.AddChild(std::move(box));
|
|
|
|
};
|
|
|
|
|
|
|
|
if (Config::Get().audioRevealer)
|
|
|
|
{
|
2023-02-22 15:45:29 +00:00
|
|
|
// Need an EventBox
|
|
|
|
if (Config::Get().audioInput)
|
|
|
|
{
|
|
|
|
auto eventBox = Widget::Create<EventBox>();
|
|
|
|
widgetAudioBody(*eventBox, AudioType::Input);
|
|
|
|
parent.AddChild(std::move(eventBox));
|
|
|
|
}
|
2023-02-04 14:07:05 +00:00
|
|
|
// Need an EventBox
|
|
|
|
auto eventBox = Widget::Create<EventBox>();
|
2023-02-22 15:45:29 +00:00
|
|
|
widgetAudioBody(*eventBox, AudioType::Output);
|
2023-02-04 14:07:05 +00:00
|
|
|
parent.AddChild(std::move(eventBox));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Just invoke it.
|
2023-02-22 15:45:29 +00:00
|
|
|
if (Config::Get().audioInput)
|
|
|
|
{
|
|
|
|
widgetAudioBody(parent, AudioType::Input);
|
|
|
|
}
|
|
|
|
widgetAudioBody(parent, AudioType::Output);
|
2023-02-04 14:07:05 +00:00
|
|
|
}
|
2023-02-22 15:45:29 +00:00
|
|
|
parent.AddTimer<Widget>(DynCtx::UpdateAudio, DynCtx::updateTimeFast);
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
|
2023-05-03 16:37:36 +00:00
|
|
|
void WidgetPackages(Widget& parent)
|
|
|
|
{
|
|
|
|
auto text = Widget::Create<Text>();
|
|
|
|
text->SetText("");
|
2023-05-03 17:02:26 +00:00
|
|
|
text->SetVisible(false);
|
2023-05-03 16:37:36 +00:00
|
|
|
text->SetClass("package-empty");
|
2023-05-03 17:02:26 +00:00
|
|
|
text->AddTimer<Text>(DynCtx::UpdatePackages, 1000 * Config::Get().checkUpdateInterval, TimerDispatchBehaviour::ImmediateDispatch);
|
2023-05-03 16:37:36 +00:00
|
|
|
parent.AddChild(std::move(text));
|
|
|
|
}
|
|
|
|
|
2023-01-30 15:57:15 +00:00
|
|
|
#ifdef WITH_BLUEZ
|
2023-01-13 15:13:56 +00:00
|
|
|
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");
|
|
|
|
|
2023-01-14 22:18:34 +00:00
|
|
|
auto iconText = Widget::Create<Button>();
|
|
|
|
iconText->OnClick(DynCtx::OnBTClick);
|
2023-01-13 15:13:56 +00:00
|
|
|
DynCtx::btIconText = iconText.get();
|
|
|
|
|
|
|
|
box->AddChild(std::move(devText));
|
|
|
|
box->AddChild(std::move(iconText));
|
|
|
|
}
|
2023-01-29 11:23:44 +00:00
|
|
|
box->AddTimer<Box>(DynCtx::UpdateBluetooth, DynCtx::updateTime);
|
2023-01-13 15:13:56 +00:00
|
|
|
|
|
|
|
parent.AddChild(std::move(box));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-02-10 16:20:26 +00:00
|
|
|
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
|
2023-02-12 13:28:46 +00:00
|
|
|
eventBox->SetHoverFn(
|
2023-02-10 16:20:26 +00:00
|
|
|
[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));
|
|
|
|
}
|
|
|
|
|
2023-01-13 15:13:56 +00:00
|
|
|
void WidgetSensors(Widget& parent)
|
|
|
|
{
|
2023-02-04 15:09:08 +00:00
|
|
|
WidgetSensor(parent, DynCtx::UpdateDisk, "disk-util-progress", "disk-data-text", DynCtx::diskText);
|
2023-01-30 16:23:28 +00:00
|
|
|
#if defined WITH_NVIDIA || defined WITH_AMD
|
|
|
|
if (RuntimeConfig::Get().hasNvidia || RuntimeConfig::Get().hasAMD)
|
2023-01-30 15:57:15 +00:00
|
|
|
{
|
2023-02-04 15:09:08 +00:00
|
|
|
WidgetSensor(parent, DynCtx::UpdateVRAM, "vram-util-progress", "vram-data-text", DynCtx::vramText);
|
|
|
|
WidgetSensor(parent, DynCtx::UpdateGPU, "gpu-util-progress", "gpu-data-text", DynCtx::gpuText);
|
2023-01-30 15:57:15 +00:00
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
#endif
|
2023-02-04 15:09:08 +00:00
|
|
|
WidgetSensor(parent, DynCtx::UpdateRAM, "ram-util-progress", "ram-data-text", DynCtx::ramText);
|
|
|
|
WidgetSensor(parent, DynCtx::UpdateCPU, "cpu-util-progress", "cpu-data-text", DynCtx::cpuText);
|
2023-01-28 22:47:55 +00:00
|
|
|
// Only show battery percentage if battery folder is set and exists
|
2023-01-30 15:57:15 +00:00
|
|
|
if (System::GetBatteryPercentage() >= 0)
|
|
|
|
{
|
2023-02-04 15:09:08 +00:00
|
|
|
WidgetSensor(parent, DynCtx::UpdateBattery, "battery-util-progress", "battery-data-text", DynCtx::batteryText);
|
2023-01-28 22:47:55 +00:00
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WidgetPower(Widget& parent)
|
|
|
|
{
|
2023-05-23 20:38:19 +00:00
|
|
|
// 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;
|
|
|
|
};
|
|
|
|
|
2023-01-13 15:13:56 +00:00
|
|
|
auto eventBox = Widget::Create<EventBox>();
|
2023-02-12 13:28:46 +00:00
|
|
|
eventBox->SetHoverFn(DynCtx::PowerBoxEvent);
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
|
|
|
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");
|
2023-05-04 21:25:57 +00:00
|
|
|
exitButton->SetText("");
|
2023-01-13 15:13:56 +00:00
|
|
|
exitButton->OnClick(
|
2023-05-23 20:38:19 +00:00
|
|
|
[setActivate](Button& but)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-05-23 20:38:19 +00:00
|
|
|
if (activatedExit)
|
|
|
|
{
|
|
|
|
System::ExitWM();
|
|
|
|
setActivate(but, activatedExit, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setActivate(but, activatedExit, true);
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
auto lockButton = Widget::Create<Button>();
|
|
|
|
lockButton->SetClass("sleep-button");
|
|
|
|
lockButton->SetText("");
|
|
|
|
lockButton->OnClick(
|
2023-05-23 20:38:19 +00:00
|
|
|
[setActivate](Button& but)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-05-23 20:38:19 +00:00
|
|
|
if (activatedLock)
|
|
|
|
{
|
|
|
|
System::Lock();
|
|
|
|
setActivate(but, activatedLock, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setActivate(but, activatedLock, true);
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
auto sleepButton = Widget::Create<Button>();
|
|
|
|
sleepButton->SetClass("sleep-button");
|
2023-05-04 21:25:57 +00:00
|
|
|
sleepButton->SetText("");
|
2023-01-13 15:13:56 +00:00
|
|
|
sleepButton->OnClick(
|
2023-05-23 20:38:19 +00:00
|
|
|
[setActivate](Button& but)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-05-23 20:38:19 +00:00
|
|
|
if (activatedSuspend)
|
|
|
|
{
|
|
|
|
System::Suspend();
|
|
|
|
setActivate(but, activatedSuspend, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setActivate(but, activatedSuspend, true);
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
auto rebootButton = Widget::Create<Button>();
|
|
|
|
rebootButton->SetClass("reboot-button");
|
2023-05-04 21:25:57 +00:00
|
|
|
rebootButton->SetText("");
|
2023-01-13 15:13:56 +00:00
|
|
|
rebootButton->OnClick(
|
2023-05-23 20:38:19 +00:00
|
|
|
[setActivate](Button& but)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-05-23 20:38:19 +00:00
|
|
|
if (activatedReboot)
|
|
|
|
{
|
|
|
|
System::Reboot();
|
|
|
|
setActivate(but, activatedReboot, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setActivate(but, activatedReboot, true);
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
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(
|
2023-05-23 20:38:19 +00:00
|
|
|
[setActivate](Button& but)
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-05-23 20:38:19 +00:00
|
|
|
if (activatedShutdown)
|
|
|
|
{
|
|
|
|
System::Shutdown();
|
|
|
|
setActivate(but, activatedShutdown, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setActivate(but, activatedShutdown, true);
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
powerBox->AddChild(std::move(revealer));
|
|
|
|
powerBox->AddChild(std::move(powerButton));
|
|
|
|
}
|
|
|
|
eventBox->AddChild(std::move(powerBox));
|
|
|
|
}
|
|
|
|
|
|
|
|
parent.AddChild(std::move(eventBox));
|
|
|
|
}
|
|
|
|
|
2023-03-03 19:44:51 +00:00
|
|
|
#ifdef WITH_WORKSPACES
|
2023-01-13 15:13:56 +00:00
|
|
|
void WidgetWorkspaces(Widget& parent)
|
|
|
|
{
|
|
|
|
auto margin = Widget::Create<Box>();
|
2023-06-10 21:44:28 +00:00
|
|
|
margin->SetHorizontalTransform({12, false, Alignment::Left});
|
2023-01-13 15:13:56 +00:00
|
|
|
parent.AddChild(std::move(margin));
|
2023-02-12 13:57:32 +00:00
|
|
|
auto eventBox = Widget::Create<EventBox>();
|
|
|
|
eventBox->SetScrollFn(DynCtx::ScrollWorkspaces);
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-02-12 13:57:32 +00:00
|
|
|
auto box = Widget::Create<Box>();
|
|
|
|
box->SetSpacing({8, true});
|
|
|
|
box->SetHorizontalTransform({-1, true, Alignment::Left});
|
2023-01-13 15:13:56 +00:00
|
|
|
{
|
2023-02-12 13:57:32 +00:00
|
|
|
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));
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
2023-02-12 13:57:32 +00:00
|
|
|
box->AddTimer<Box>(DynCtx::UpdateWorkspaces, DynCtx::updateTimeFast);
|
|
|
|
eventBox->AddChild(std::move(box));
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
2023-02-12 13:57:32 +00:00
|
|
|
parent.AddChild(std::move(eventBox));
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void Create(Window& window, int32_t monitor)
|
|
|
|
{
|
|
|
|
monitorID = monitor;
|
|
|
|
|
|
|
|
auto mainWidget = Widget::Create<Box>();
|
2023-06-10 21:44:28 +00:00
|
|
|
mainWidget->SetSpacing({0, false});
|
2023-01-13 15:13:56 +00:00
|
|
|
mainWidget->SetClass("bar");
|
|
|
|
{
|
2023-06-10 21:44:28 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2023-01-13 15:13:56 +00:00
|
|
|
auto left = Widget::Create<Box>();
|
|
|
|
left->SetSpacing({0, false});
|
2023-06-10 21:44:28 +00:00
|
|
|
// 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});
|
2023-03-03 19:44:51 +00:00
|
|
|
#ifdef WITH_WORKSPACES
|
|
|
|
if (RuntimeConfig::Get().hasWorkspaces)
|
2023-01-30 15:57:15 +00:00
|
|
|
{
|
|
|
|
WidgetWorkspaces(*left);
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
#endif
|
|
|
|
|
2023-06-10 21:44:28 +00:00
|
|
|
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));
|
|
|
|
}
|
2023-01-13 15:13:56 +00:00
|
|
|
|
|
|
|
auto right = Widget::Create<Box>();
|
|
|
|
right->SetClass("right");
|
|
|
|
right->SetSpacing({8, false});
|
|
|
|
right->SetHorizontalTransform({-1, true, Alignment::Right});
|
|
|
|
{
|
2023-05-03 18:57:24 +00:00
|
|
|
#ifdef WITH_SNI
|
2023-03-17 23:02:40 +00:00
|
|
|
SNI::WidgetSNI(*right);
|
2023-05-03 18:57:24 +00:00
|
|
|
#endif
|
2023-03-17 23:02:40 +00:00
|
|
|
|
2023-05-03 16:37:36 +00:00
|
|
|
WidgetPackages(*right);
|
|
|
|
|
2023-01-13 15:13:56 +00:00
|
|
|
WidgetAudio(*right);
|
|
|
|
|
2023-01-30 15:57:15 +00:00
|
|
|
#ifdef WITH_BLUEZ
|
|
|
|
if (RuntimeConfig::Get().hasBlueZ)
|
|
|
|
WidgetBluetooth(*right);
|
2023-01-13 15:13:56 +00:00
|
|
|
#endif
|
2023-02-12 19:45:05 +00:00
|
|
|
if (Config::Get().networkWidget && RuntimeConfig::Get().hasNet)
|
2023-02-10 16:20:26 +00:00
|
|
|
WidgetNetwork(*right);
|
2023-01-13 15:13:56 +00:00
|
|
|
|
|
|
|
WidgetSensors(*right);
|
|
|
|
|
|
|
|
WidgetPower(*right);
|
|
|
|
}
|
|
|
|
|
|
|
|
mainWidget->AddChild(std::move(left));
|
2023-06-10 21:44:28 +00:00
|
|
|
mainWidget->AddChild(std::move(center));
|
2023-01-13 15:13:56 +00:00
|
|
|
mainWidget->AddChild(std::move(right));
|
|
|
|
}
|
|
|
|
window.SetAnchor(Anchor::Left | Anchor::Right | Anchor::Top);
|
2023-06-10 21:42:41 +00:00
|
|
|
window.SetMainWidget(std::move(mainWidget));
|
2023-01-13 15:13:56 +00:00
|
|
|
}
|
|
|
|
}
|