feat: add gauge and stacked bar graph type
This commit is contained in:
+14
-5
@@ -11,11 +11,12 @@
|
|||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
|
enum class GraphType { LINE, BAR, GAUGE };
|
||||||
|
|
||||||
class AGraph : public AModule {
|
class AGraph : public AModule {
|
||||||
public:
|
public:
|
||||||
AGraph(const Json::Value &, const std::string &, const std::string &,
|
AGraph(const Json::Value &, const std::string &, const std::string &, uint16_t interval = 0,
|
||||||
uint16_t interval = 0, bool enable_click = false,
|
bool enable_click = false, bool enable_scroll = false);
|
||||||
bool enable_scroll = false);
|
|
||||||
virtual ~AGraph() = default;
|
virtual ~AGraph() = default;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ class AGraph : public AModule {
|
|||||||
std::deque<int> values_;
|
std::deque<int> values_;
|
||||||
uint16_t datapoints_ = 20;
|
uint16_t datapoints_ = 20;
|
||||||
uint16_t y_offset_ = 0;
|
uint16_t y_offset_ = 0;
|
||||||
|
GraphType graph_type_ = GraphType::LINE;
|
||||||
|
|
||||||
void addValue(const int n);
|
void addValue(const int n);
|
||||||
|
|
||||||
@@ -37,14 +39,21 @@ class AGraph : public AModule {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void drawFilledArea(const Cairo::RefPtr<Cairo::Context> &cr,
|
void drawFilledArea(const Cairo::RefPtr<Cairo::Context> &cr,
|
||||||
const std::vector<std::pair<double, double>> &points,
|
const std::vector<std::pair<double, double>> &points, double height,
|
||||||
double height, const Gdk::RGBA &bg_color);
|
const Gdk::RGBA &bg_color);
|
||||||
|
|
||||||
void drawLine(const Cairo::RefPtr<Cairo::Context> &cr,
|
void drawLine(const Cairo::RefPtr<Cairo::Context> &cr,
|
||||||
const std::vector<std::pair<double, double>> &points, const Gdk::RGBA &fg_color);
|
const std::vector<std::pair<double, double>> &points, const Gdk::RGBA &fg_color);
|
||||||
|
|
||||||
void drawPath(const Cairo::RefPtr<Cairo::Context> &cr,
|
void drawPath(const Cairo::RefPtr<Cairo::Context> &cr,
|
||||||
const std::vector<std::pair<double, double>> &points);
|
const std::vector<std::pair<double, double>> &points);
|
||||||
|
|
||||||
|
void drawBars(const Cairo::RefPtr<Cairo::Context> &cr,
|
||||||
|
double width, double height, int current_value,
|
||||||
|
const Gdk::RGBA &fg_color);
|
||||||
|
|
||||||
|
void drawGauge(const Cairo::RefPtr<Cairo::Context> &cr, double width, double height,
|
||||||
|
int current_value, const Gdk::RGBA &fg_color);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "AGraph.hpp"
|
||||||
|
#include "util/command.hpp"
|
||||||
|
#include "util/json.hpp"
|
||||||
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules {
|
||||||
|
|
||||||
|
class CustomGraph : public AGraph {
|
||||||
|
public:
|
||||||
|
CustomGraph(const std::string&, const std::string&, const Json::Value&, const std::string&);
|
||||||
|
virtual ~CustomGraph();
|
||||||
|
auto update() -> void override;
|
||||||
|
void refresh(int /*signal*/) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void delayWorker();
|
||||||
|
void continuousWorker();
|
||||||
|
void waitingWorker();
|
||||||
|
void parseOutputRaw();
|
||||||
|
void parseOutputJson();
|
||||||
|
void handleEvent();
|
||||||
|
bool handleScroll(GdkEventScroll* e) override;
|
||||||
|
bool handleToggle(GdkEventButton* const& e) override;
|
||||||
|
|
||||||
|
const std::string name_;
|
||||||
|
const std::string output_name_;
|
||||||
|
std::string text_;
|
||||||
|
std::string id_;
|
||||||
|
std::string alt_;
|
||||||
|
std::string tooltip_;
|
||||||
|
const bool tooltip_format_enabled_;
|
||||||
|
std::vector<std::string> class_;
|
||||||
|
int percentage_;
|
||||||
|
FILE* fp_;
|
||||||
|
int pid_;
|
||||||
|
util::command::res output_;
|
||||||
|
util::JsonParser parser_;
|
||||||
|
|
||||||
|
util::SleeperThread thread_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules
|
||||||
@@ -165,6 +165,7 @@ src_files = files(
|
|||||||
'src/AIconLabel.cpp',
|
'src/AIconLabel.cpp',
|
||||||
'src/AAppIconLabel.cpp',
|
'src/AAppIconLabel.cpp',
|
||||||
'src/modules/custom.cpp',
|
'src/modules/custom.cpp',
|
||||||
|
'src/modules/custom_graph.cpp',
|
||||||
'src/modules/disk.cpp',
|
'src/modules/disk.cpp',
|
||||||
'src/modules/idle_inhibitor.cpp',
|
'src/modules/idle_inhibitor.cpp',
|
||||||
'src/modules/image.cpp',
|
'src/modules/image.cpp',
|
||||||
|
|||||||
+115
-7
@@ -3,6 +3,7 @@
|
|||||||
#include <cairomm/context.h>
|
#include <cairomm/context.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <util/command.hpp>
|
#include <util/command.hpp>
|
||||||
@@ -42,6 +43,17 @@ AGraph::AGraph(const Json::Value& config, const std::string& name, const std::st
|
|||||||
y_offset_ = config_["y_offset"].asUInt();
|
y_offset_ = config_["y_offset"].asUInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config_["graph_type"].isString()) {
|
||||||
|
std::string type = config_["graph_type"].asString();
|
||||||
|
if (type == "line") {
|
||||||
|
graph_type_ = GraphType::LINE;
|
||||||
|
} else if (type == "bar") {
|
||||||
|
graph_type_ = GraphType::BAR;
|
||||||
|
} else if (type == "gauge") {
|
||||||
|
graph_type_ = GraphType::GAUGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If a GTKMenu is requested in the config
|
// If a GTKMenu is requested in the config
|
||||||
if (config_["menu"].isString()) {
|
if (config_["menu"].isString()) {
|
||||||
// Create the GTKMenu widget
|
// Create the GTKMenu widget
|
||||||
@@ -137,19 +149,26 @@ bool AGraph::onDraw(const Cairo::RefPtr<Cairo::Context>& cr) {
|
|||||||
double y = height - (static_cast<double>(value) / 100.0 * height);
|
double y = height - (static_cast<double>(value) / 100.0 * height);
|
||||||
points.emplace_back(x, y);
|
points.emplace_back(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!points.empty()) {
|
if (!points.empty()) {
|
||||||
|
switch (graph_type_) {
|
||||||
drawFilledArea(cr, points, height, bg_color);
|
case GraphType::LINE:
|
||||||
|
drawFilledArea(cr, points, height, bg_color);
|
||||||
drawLine(cr, points, fg_color);
|
drawLine(cr, points, fg_color);
|
||||||
|
break;
|
||||||
|
case GraphType::BAR:
|
||||||
|
drawBars(cr, width, height, values_.empty() ? 0 : values_.back(), fg_color);
|
||||||
|
break;
|
||||||
|
case GraphType::GAUGE:
|
||||||
|
drawGauge(cr, width, height, values_.empty() ? 0 : values_.back(), fg_color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void AGraph::drawFilledArea(const Cairo::RefPtr<Cairo::Context>& cr,
|
void AGraph::drawFilledArea(const Cairo::RefPtr<Cairo::Context>& cr,
|
||||||
const std::vector<std::pair<double, double>>& points,
|
const std::vector<std::pair<double, double>>& points, double height,
|
||||||
double height, const Gdk::RGBA& bg_color) {
|
const Gdk::RGBA& bg_color) {
|
||||||
if (points.empty()) return;
|
if (points.empty()) return;
|
||||||
|
|
||||||
double first_x = points.front().first;
|
double first_x = points.front().first;
|
||||||
@@ -194,4 +213,93 @@ void AGraph::drawPath(const Cairo::RefPtr<Cairo::Context>& cr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AGraph::drawBars(const Cairo::RefPtr<Cairo::Context>& cr,
|
||||||
|
double width, double height, int current_value,
|
||||||
|
const Gdk::RGBA& fg_color) {
|
||||||
|
|
||||||
|
current_value = std::min(100, std::max(0, current_value));
|
||||||
|
|
||||||
|
double green_height = height * (std::min(current_value, 40) / 100.0);
|
||||||
|
cr->set_source_rgba(0.0, 1.0, 0.0, 1.0);
|
||||||
|
cr->rectangle(0, height - green_height, width, green_height);
|
||||||
|
cr->fill();
|
||||||
|
|
||||||
|
if (current_value > 40) {
|
||||||
|
double yellow_height = height * (std::min(current_value, 75) - 40) / 100.0;
|
||||||
|
cr->set_source_rgba(1.0, 1.0, 0.0, 1.0);
|
||||||
|
cr->rectangle(0, height - green_height - yellow_height, width, yellow_height);
|
||||||
|
cr->fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_value > 75) {
|
||||||
|
double orange_height = height * (std::min(current_value, 85) - 75) / 100.0;
|
||||||
|
cr->set_source_rgba(1.0, 0.5, 0.0, 1.0);
|
||||||
|
double yellow_height = height * (std::min(current_value, 75) - 40) / 100.0;
|
||||||
|
cr->rectangle(0, height - green_height - yellow_height - orange_height, width,
|
||||||
|
orange_height);
|
||||||
|
cr->fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_value > 85) {
|
||||||
|
double red_height = height * (current_value - 85) / 100.0;
|
||||||
|
cr->set_source_rgba(1.0, 0.0, 0.0, 1.0);
|
||||||
|
double yellow_height = height * (std::min(current_value, 75) - 40) / 100.0;
|
||||||
|
double orange_height = height * (std::min(current_value, 85) - 75) / 100.0;
|
||||||
|
cr->rectangle(0, height - green_height - yellow_height - orange_height - red_height, width,
|
||||||
|
red_height);
|
||||||
|
cr->fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
double value_height = height * (current_value / 100.0);
|
||||||
|
cr->set_source_rgba(0.2, 0.2, 0.2, 0.8);
|
||||||
|
cr->rectangle(0, height - value_height, width, 2);
|
||||||
|
cr->fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AGraph::drawGauge(const Cairo::RefPtr<Cairo::Context>& cr, double width, double height,
|
||||||
|
int current_value, const Gdk::RGBA& fg_color) {
|
||||||
|
double center_x = width / 2.0;
|
||||||
|
double center_y = height;
|
||||||
|
double radius = height / 2.0;
|
||||||
|
|
||||||
|
cr->set_line_width(10.0);
|
||||||
|
|
||||||
|
double angle1 = M_PI;
|
||||||
|
double angle2 = angle1 + 0.3 * angle1;
|
||||||
|
|
||||||
|
// Green section (0-33%)
|
||||||
|
cr->set_source_rgba(0.0, 1.0, 0.0, 1.0);
|
||||||
|
cr->arc(center_x, center_y, radius, angle1, angle2);
|
||||||
|
cr->stroke();
|
||||||
|
|
||||||
|
// Yellow section (33-66%)
|
||||||
|
angle1 = angle2;
|
||||||
|
angle2 = angle1 + 0.3 * angle1;
|
||||||
|
cr->set_source_rgba(1.0, 1.0, 0.0, 1.0);
|
||||||
|
cr->arc(center_x, center_y, radius, angle1, angle2);
|
||||||
|
cr->stroke();
|
||||||
|
|
||||||
|
// Red section (66-100%)
|
||||||
|
angle1 = angle2;
|
||||||
|
angle2 = 0.0;
|
||||||
|
cr->set_source_rgba(1.0, 0.0, 0.0, 0.8);
|
||||||
|
cr->arc(center_x, center_y, radius, angle1, angle2);
|
||||||
|
cr->stroke();
|
||||||
|
|
||||||
|
// Draw needle
|
||||||
|
double percentage = std::min(100, std::max(0, current_value)) / 100.0;
|
||||||
|
double needle_angle = M_PI * percentage;
|
||||||
|
double needle_length = radius;
|
||||||
|
|
||||||
|
double needle_x = center_x - needle_length * cos(needle_angle);
|
||||||
|
double needle_y = center_y - needle_length * sin(needle_angle);
|
||||||
|
|
||||||
|
cr->set_source_rgba(1.0, 1.0, 1.0, 1.0);
|
||||||
|
cr->set_line_width(2.0);
|
||||||
|
cr->begin_new_path();
|
||||||
|
cr->move_to(center_x, center_y);
|
||||||
|
cr->line_to(needle_x, needle_y);
|
||||||
|
cr->stroke();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
@@ -118,6 +118,7 @@
|
|||||||
#include "modules/cava/cava_frontend.hpp"
|
#include "modules/cava/cava_frontend.hpp"
|
||||||
#include "modules/cffi.hpp"
|
#include "modules/cffi.hpp"
|
||||||
#include "modules/custom.hpp"
|
#include "modules/custom.hpp"
|
||||||
|
#include "modules/custom_graph.hpp"
|
||||||
#include "modules/image.hpp"
|
#include "modules/image.hpp"
|
||||||
#include "modules/temperature.hpp"
|
#include "modules/temperature.hpp"
|
||||||
#include "modules/user.hpp"
|
#include "modules/user.hpp"
|
||||||
@@ -362,6 +363,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
|||||||
if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) {
|
if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) {
|
||||||
return new waybar::modules::Custom(ref.substr(7), id, config_[name], bar_.output->name);
|
return new waybar::modules::Custom(ref.substr(7), id, config_[name], bar_.output->name);
|
||||||
}
|
}
|
||||||
|
if (ref.compare(0, 13, "custom-graph/") == 0 && ref.size() > 7) {
|
||||||
|
return new waybar::modules::CustomGraph(ref.substr(7), id, config_[name], bar_.output->name);
|
||||||
|
}
|
||||||
if (ref.compare(0, 5, "cffi/") == 0 && ref.size() > 5) {
|
if (ref.compare(0, 5, "cffi/") == 0 && ref.size() > 5) {
|
||||||
return new waybar::modules::CFFI(ref.substr(5), id, config_[name]);
|
return new waybar::modules::CFFI(ref.substr(5), id, config_[name]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,283 @@
|
|||||||
|
#include "modules/custom_graph.hpp"
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include "util/scope_guard.hpp"
|
||||||
|
|
||||||
|
waybar::modules::CustomGraph::CustomGraph(const std::string& name, const std::string& id,
|
||||||
|
const Json::Value& config, const std::string& output_name)
|
||||||
|
: AGraph(config, "custom-graph" + name, id),
|
||||||
|
name_(name),
|
||||||
|
output_name_(output_name),
|
||||||
|
id_(id),
|
||||||
|
tooltip_format_enabled_{config_["tooltip-format"].isString()},
|
||||||
|
percentage_(0),
|
||||||
|
fp_(nullptr),
|
||||||
|
pid_(-1) {
|
||||||
|
if (config.isNull()) {
|
||||||
|
spdlog::warn("There is no configuration for 'custom-graph/{}', element will be hidden", name);
|
||||||
|
}
|
||||||
|
dp.emit();
|
||||||
|
if (!config_["signal"].empty() && config_["interval"].empty() &&
|
||||||
|
config_["restart-interval"].empty()) {
|
||||||
|
waitingWorker();
|
||||||
|
} else if (interval_.count() > 0) {
|
||||||
|
delayWorker();
|
||||||
|
} else if (config_["exec"].isString()) {
|
||||||
|
continuousWorker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waybar::modules::CustomGraph::~CustomGraph() {
|
||||||
|
if (pid_ != -1) {
|
||||||
|
killpg(pid_, SIGTERM);
|
||||||
|
waitpid(pid_, NULL, 0);
|
||||||
|
pid_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::modules::CustomGraph::delayWorker() {
|
||||||
|
thread_ = [this] {
|
||||||
|
for (int i : this->pid_children_) {
|
||||||
|
int status;
|
||||||
|
waitpid(i, &status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->pid_children_.clear();
|
||||||
|
|
||||||
|
bool can_update = true;
|
||||||
|
if (config_["exec-if"].isString()) {
|
||||||
|
output_ = util::command::execNoRead(config_["exec-if"].asString());
|
||||||
|
if (output_.exit_code != 0) {
|
||||||
|
can_update = false;
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (can_update) {
|
||||||
|
if (config_["exec"].isString()) {
|
||||||
|
output_ = util::command::exec(config_["exec"].asString(), output_name_);
|
||||||
|
}
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
thread_.sleep_for(interval_);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::modules::CustomGraph::continuousWorker() {
|
||||||
|
auto cmd = config_["exec"].asString();
|
||||||
|
pid_ = -1;
|
||||||
|
fp_ = util::command::open(cmd, pid_, output_name_);
|
||||||
|
if (!fp_) {
|
||||||
|
throw std::runtime_error("Unable to open " + cmd);
|
||||||
|
}
|
||||||
|
thread_ = [this, cmd] {
|
||||||
|
char* buff = nullptr;
|
||||||
|
waybar::util::ScopeGuard buff_deleter([&buff]() {
|
||||||
|
if (buff) {
|
||||||
|
free(buff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
size_t len = 0;
|
||||||
|
if (getline(&buff, &len, fp_) == -1) {
|
||||||
|
int exit_code = 1;
|
||||||
|
if (fp_) {
|
||||||
|
exit_code = WEXITSTATUS(util::command::close(fp_, pid_));
|
||||||
|
fp_ = nullptr;
|
||||||
|
}
|
||||||
|
if (exit_code != 0) {
|
||||||
|
output_ = {exit_code, ""};
|
||||||
|
dp.emit();
|
||||||
|
spdlog::error("{} stopped unexpectedly, is it endless?", name_);
|
||||||
|
}
|
||||||
|
if (config_["restart-interval"].isUInt()) {
|
||||||
|
pid_ = -1;
|
||||||
|
thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt()));
|
||||||
|
fp_ = util::command::open(cmd, pid_, output_name_);
|
||||||
|
if (!fp_) {
|
||||||
|
throw std::runtime_error("Unable to open " + cmd);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread_.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::string output = buff;
|
||||||
|
|
||||||
|
// Remove last newline
|
||||||
|
if (!output.empty() && output[output.length() - 1] == '\n') {
|
||||||
|
output.erase(output.length() - 1);
|
||||||
|
}
|
||||||
|
output_ = {0, output};
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::modules::CustomGraph::waitingWorker() {
|
||||||
|
thread_ = [this] {
|
||||||
|
bool can_update = true;
|
||||||
|
if (config_["exec-if"].isString()) {
|
||||||
|
output_ = util::command::execNoRead(config_["exec-if"].asString());
|
||||||
|
if (output_.exit_code != 0) {
|
||||||
|
can_update = false;
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (can_update) {
|
||||||
|
if (config_["exec"].isString()) {
|
||||||
|
output_ = util::command::exec(config_["exec"].asString(), output_name_);
|
||||||
|
}
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
thread_.sleep();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::modules::CustomGraph::refresh(int sig) {
|
||||||
|
if (sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||||
|
thread_.wake_up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::modules::CustomGraph::handleEvent() {
|
||||||
|
if (!config_["exec-on-event"].isBool() || config_["exec-on-event"].asBool()) {
|
||||||
|
thread_.wake_up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waybar::modules::CustomGraph::handleScroll(GdkEventScroll* e) {
|
||||||
|
auto ret = AGraph::handleScroll(e);
|
||||||
|
handleEvent();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waybar::modules::CustomGraph::handleToggle(GdkEventButton* const& e) {
|
||||||
|
auto ret = AGraph::handleToggle(e);
|
||||||
|
handleEvent();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto waybar::modules::CustomGraph::update() -> void {
|
||||||
|
// Hide label if output is empty
|
||||||
|
if ((config_["exec"].isString() || config_["exec-if"].isString()) &&
|
||||||
|
(output_.out.empty() || output_.exit_code != 0)) {
|
||||||
|
event_box_.hide();
|
||||||
|
} else {
|
||||||
|
if (config_["return-type"].asString() == "json") {
|
||||||
|
parseOutputJson();
|
||||||
|
} else {
|
||||||
|
parseOutputRaw();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
addValue(percentage_);
|
||||||
|
|
||||||
|
if (tooltipEnabled()) {
|
||||||
|
if (tooltip_format_enabled_) {
|
||||||
|
auto tooltip = config_["tooltip-format"].asString();
|
||||||
|
tooltip = fmt::format(
|
||||||
|
fmt::runtime(tooltip), fmt::arg("text", text_), fmt::arg("alt", alt_),
|
||||||
|
fmt::arg("percentage", percentage_));
|
||||||
|
graph_.set_tooltip_markup(tooltip);
|
||||||
|
} else {
|
||||||
|
if (graph_.get_tooltip_markup() != tooltip_) {
|
||||||
|
graph_.set_tooltip_markup(tooltip_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto style = graph_.get_style_context();
|
||||||
|
auto classes = style->list_classes();
|
||||||
|
for (auto const& c : classes) {
|
||||||
|
if (c == id_) continue;
|
||||||
|
style->remove_class(c);
|
||||||
|
}
|
||||||
|
for (auto const& c : class_) {
|
||||||
|
style->add_class(c);
|
||||||
|
}
|
||||||
|
style->add_class("flat");
|
||||||
|
style->add_class(MODULE_CLASS);
|
||||||
|
event_box_.show();
|
||||||
|
} catch (const fmt::format_error& e) {
|
||||||
|
if (std::strcmp(e.what(), "cannot switch from manual to automatic argument indexing") != 0)
|
||||||
|
throw;
|
||||||
|
|
||||||
|
throw fmt::format_error(
|
||||||
|
"mixing manual and automatic argument indexing is no longer supported; "
|
||||||
|
"try replacing \"{}\" with \"{text}\" in your format specifier");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Call parent update
|
||||||
|
AGraph::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::modules::CustomGraph::parseOutputRaw() {
|
||||||
|
std::istringstream output(output_.out);
|
||||||
|
std::string line;
|
||||||
|
int i = 0;
|
||||||
|
while (getline(output, line)) {
|
||||||
|
Glib::ustring validated_line = line;
|
||||||
|
if (!validated_line.validate()) {
|
||||||
|
validated_line = validated_line.make_valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
if (config_["escape"].isBool() && config_["escape"].asBool()) {
|
||||||
|
text_ = Glib::Markup::escape_text(validated_line);
|
||||||
|
tooltip_ = Glib::Markup::escape_text(validated_line);
|
||||||
|
} else {
|
||||||
|
text_ = validated_line;
|
||||||
|
tooltip_ = validated_line;
|
||||||
|
}
|
||||||
|
tooltip_ = validated_line;
|
||||||
|
class_.clear();
|
||||||
|
} else if (i == 1) {
|
||||||
|
if (config_["escape"].isBool() && config_["escape"].asBool()) {
|
||||||
|
tooltip_ = Glib::Markup::escape_text(validated_line);
|
||||||
|
} else {
|
||||||
|
tooltip_ = validated_line;
|
||||||
|
}
|
||||||
|
} else if (i == 2) {
|
||||||
|
class_.push_back(validated_line);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::modules::CustomGraph::parseOutputJson() {
|
||||||
|
std::istringstream output(output_.out);
|
||||||
|
std::string line;
|
||||||
|
class_.clear();
|
||||||
|
while (getline(output, line)) {
|
||||||
|
auto parsed = parser_.parse(line);
|
||||||
|
if (config_["escape"].isBool() && config_["escape"].asBool()) {
|
||||||
|
text_ = Glib::Markup::escape_text(parsed["text"].asString());
|
||||||
|
} else {
|
||||||
|
text_ = parsed["text"].asString();
|
||||||
|
}
|
||||||
|
if (config_["escape"].isBool() && config_["escape"].asBool()) {
|
||||||
|
alt_ = Glib::Markup::escape_text(parsed["alt"].asString());
|
||||||
|
} else {
|
||||||
|
alt_ = parsed["alt"].asString();
|
||||||
|
}
|
||||||
|
if (config_["escape"].isBool() && config_["escape"].asBool()) {
|
||||||
|
tooltip_ = Glib::Markup::escape_text(parsed["tooltip"].asString());
|
||||||
|
} else {
|
||||||
|
tooltip_ = parsed["tooltip"].asString();
|
||||||
|
}
|
||||||
|
if (parsed["class"].isString()) {
|
||||||
|
class_.push_back(parsed["class"].asString());
|
||||||
|
} else if (parsed["class"].isArray()) {
|
||||||
|
for (auto const& c : parsed["class"]) {
|
||||||
|
class_.push_back(c.asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!parsed["percentage"].asString().empty() && parsed["percentage"].isNumeric()) {
|
||||||
|
percentage_ = (int)lround(parsed["percentage"].asFloat());
|
||||||
|
} else {
|
||||||
|
percentage_ = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user