Merge pull request #3151 from VPavliashvili/module-images
feat: add new module 'images' to render multiple images under one gtk container
This commit is contained in:
+201
-28
@@ -1,20 +1,12 @@
|
||||
#include "modules/image.hpp"
|
||||
|
||||
#include <json/value.h>
|
||||
|
||||
#include <config.hpp>
|
||||
|
||||
waybar::modules::Image::Image(const std::string& id, const Json::Value& config)
|
||||
: AModule(config, "image", id), box_(Gtk::ORIENTATION_HORIZONTAL, 0) {
|
||||
box_.pack_start(image_);
|
||||
box_.set_name("image");
|
||||
if (!id.empty()) {
|
||||
box_.get_style_context()->add_class(id);
|
||||
}
|
||||
box_.get_style_context()->add_class(MODULE_CLASS);
|
||||
event_box_.add(box_);
|
||||
|
||||
dp.emit();
|
||||
|
||||
size_ = config["size"].asInt();
|
||||
: AModule(config, "image", id) {
|
||||
strategy_ = getStrategy(id, config, MODULE_CLASS, event_box_, tooltipEnabled());
|
||||
|
||||
const auto once = std::chrono::milliseconds::max();
|
||||
if (!config_.isMember("interval") || config_["interval"].isNull() ||
|
||||
@@ -33,20 +25,24 @@ waybar::modules::Image::Image(const std::string& id, const Json::Value& config)
|
||||
interval_ = once;
|
||||
}
|
||||
|
||||
if (size_ == 0) {
|
||||
size_ = 16;
|
||||
}
|
||||
|
||||
if (config_["path"].isString()) {
|
||||
auto result = Config::tryExpandPath(config_["path"].asString(), "");
|
||||
path_ = result.empty() ? "" : result.front();
|
||||
} else {
|
||||
path_.clear();
|
||||
}
|
||||
|
||||
delayWorker();
|
||||
}
|
||||
|
||||
auto waybar::modules::Image::getStrategy(const std::string& id, const Json::Value& cfg,
|
||||
const std::string& module, Gtk::EventBox& evbox,
|
||||
bool hasTooltip)
|
||||
-> std::unique_ptr<waybar::modules::image::IStrategy> {
|
||||
std::unique_ptr<waybar::modules::image::IStrategy> strat;
|
||||
if (!cfg["multiple"].empty() && cfg["multiple"].asBool()) {
|
||||
strat = std::make_unique<waybar::modules::image::MultipleImageStrategy>(id, cfg, module, evbox);
|
||||
} else {
|
||||
strat = std::make_unique<waybar::modules::image::SingleImageStrategy>(id, cfg, module, evbox,
|
||||
hasTooltip);
|
||||
}
|
||||
|
||||
return strat;
|
||||
}
|
||||
|
||||
void waybar::modules::Image::delayWorker() {
|
||||
thread_ = [this] {
|
||||
dp.emit();
|
||||
@@ -63,7 +59,184 @@ void waybar::modules::Image::refresh(int sig) {
|
||||
}
|
||||
|
||||
auto waybar::modules::Image::update() -> void {
|
||||
if (config_["exec"].isString()) {
|
||||
strategy_->update();
|
||||
|
||||
AModule::update();
|
||||
}
|
||||
|
||||
namespace waybar::modules::image {
|
||||
|
||||
MultipleImageStrategy::MultipleImageStrategy(const std::string& id, const Json::Value& config,
|
||||
const std::string& module, Gtk::EventBox& evbox)
|
||||
: IStrategy(), box_(Gtk::ORIENTATION_HORIZONTAL, 0) {
|
||||
config_ = config;
|
||||
|
||||
box_.set_name("image");
|
||||
box_.get_style_context()->add_class(id);
|
||||
box_.get_style_context()->add_class(module);
|
||||
evbox.add(box_);
|
||||
|
||||
size_ = config["size"].asInt();
|
||||
if (size_ == 0) {
|
||||
size_ = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void MultipleImageStrategy::update() {
|
||||
// spdlog::info("update function run");
|
||||
|
||||
// clear box_, previous css classes and memory
|
||||
if (box_.get_children().size() > 0) {
|
||||
resetBoxAndMemory();
|
||||
}
|
||||
|
||||
// set new images from config script
|
||||
if (!config_["entries"].empty()) {
|
||||
setImagesData(config_["entries"]);
|
||||
} else if (!config_["exec"].empty()) {
|
||||
auto exec = util::command::exec(config_["exec"].asString(), "");
|
||||
Json::Value as_json;
|
||||
Json::Reader reader;
|
||||
|
||||
if (!reader.parse(exec.out, as_json)) {
|
||||
spdlog::error("invalid json from exec {}", exec.out);
|
||||
return;
|
||||
}
|
||||
|
||||
setImagesData(as_json);
|
||||
} else {
|
||||
spdlog::error("no image files provded in config");
|
||||
return;
|
||||
}
|
||||
|
||||
setupAndDraw();
|
||||
}
|
||||
|
||||
void MultipleImageStrategy::setupAndDraw() {
|
||||
for (unsigned int i = 0; i < images_data_.size(); i++) {
|
||||
images_data_[i].img = std::make_shared<Gtk::Image>();
|
||||
images_data_[i].btn = std::make_shared<Gtk::Button>();
|
||||
|
||||
auto img = images_data_[i].img;
|
||||
auto data = images_data_[i];
|
||||
|
||||
auto path = data.path;
|
||||
auto marker = data.marker;
|
||||
auto tooltip = data.tooltip;
|
||||
bool has_onclick = !data.on_click.empty();
|
||||
|
||||
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
|
||||
pixbuf = Gdk::Pixbuf::create_from_file(path, size_, size_);
|
||||
|
||||
if (has_onclick) {
|
||||
auto btn = images_data_[i].btn;
|
||||
btn->set_name("button_" + path);
|
||||
btn->get_style_context()->add_class(marker);
|
||||
btn->set_tooltip_text(tooltip);
|
||||
btn->set_image(*img);
|
||||
box_.pack_start(*btn);
|
||||
|
||||
btn->add_events(Gdk::BUTTON_PRESS_MASK);
|
||||
btn->signal_clicked().connect(
|
||||
sigc::bind(sigc::mem_fun(*this, &MultipleImageStrategy::handleClick), data.on_click));
|
||||
|
||||
if (pixbuf) {
|
||||
btn->show_all();
|
||||
img->set(pixbuf);
|
||||
box_.get_style_context()->remove_class("empty");
|
||||
} else {
|
||||
btn->hide();
|
||||
img->clear();
|
||||
img->hide();
|
||||
box_.get_style_context()->add_class("empty");
|
||||
}
|
||||
} else {
|
||||
img->set_name(path);
|
||||
img->get_style_context()->add_class(marker);
|
||||
img->set_tooltip_text(tooltip);
|
||||
box_.pack_start(*img);
|
||||
// spdlog::info("added image -> {}:{}", marker, path);
|
||||
|
||||
if (pixbuf) {
|
||||
img->set(pixbuf);
|
||||
img->show();
|
||||
box_.get_style_context()->remove_class("empty");
|
||||
} else {
|
||||
img->clear();
|
||||
img->hide();
|
||||
box_.get_style_context()->add_class("empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultipleImageStrategy::setImagesData(const Json::Value& entries) {
|
||||
for (unsigned int i = 0; i < entries.size(); i++) {
|
||||
auto path = entries[i]["path"];
|
||||
auto marker = entries[i]["marker"];
|
||||
auto tooltip = entries[i]["tooltip"];
|
||||
auto onclick = entries[i]["on-click"];
|
||||
|
||||
bool has_tooltip_err = !tooltip.empty() && !tooltip.isString();
|
||||
bool has_onclick_err = !onclick.empty() && !onclick.isString();
|
||||
|
||||
if (!path.isString() || !marker.isString() || has_tooltip_err || has_onclick_err ||
|
||||
!Glib::file_test(path.asString(), Glib::FILE_TEST_EXISTS)) {
|
||||
spdlog::error("invalid input in images config -> {}", entries[i]);
|
||||
return;
|
||||
}
|
||||
ImageData data;
|
||||
data.path = path.asString();
|
||||
data.marker = marker.asString();
|
||||
data.tooltip = !tooltip.empty() ? tooltip.asString() : "";
|
||||
data.on_click = onclick.asString();
|
||||
|
||||
images_data_.push_back(data);
|
||||
}
|
||||
}
|
||||
|
||||
void MultipleImageStrategy::resetBoxAndMemory() {
|
||||
auto children = box_.get_children();
|
||||
for (auto child : children) {
|
||||
box_.remove(*child);
|
||||
// spdlog::info("child removed with name -> {}", std::string(child->get_name()));
|
||||
}
|
||||
|
||||
images_data_.clear();
|
||||
}
|
||||
|
||||
void MultipleImageStrategy::handleClick(const Glib::ustring& data) {
|
||||
auto msg = std::string(data);
|
||||
|
||||
auto exec = util::command::exec(data, "");
|
||||
}
|
||||
|
||||
SingleImageStrategy::SingleImageStrategy(const std::string& id, const Json::Value& config,
|
||||
const std::string& module, Gtk::EventBox& evbox,
|
||||
bool tooltipEnabled)
|
||||
: IStrategy(), box_(Gtk::ORIENTATION_HORIZONTAL, 0) {
|
||||
config_ = config;
|
||||
hasTooltip_ = tooltipEnabled;
|
||||
|
||||
box_.pack_start(image_);
|
||||
box_.set_name("image");
|
||||
if (!id.empty()) {
|
||||
box_.get_style_context()->add_class(id);
|
||||
}
|
||||
box_.get_style_context()->add_class(module);
|
||||
evbox.add(box_);
|
||||
|
||||
size_ = config["size"].asInt();
|
||||
if (size_ == 0) {
|
||||
size_ = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void SingleImageStrategy::update() {
|
||||
if (config_["path"].isString()) {
|
||||
auto result = Config::tryExpandPath(config_["path"].asString(), "");
|
||||
path_ = result.empty() ? "" : result.front();
|
||||
} else if (config_["exec"].isString()) {
|
||||
output_ = util::command::exec(config_["exec"].asString(), "");
|
||||
parseOutputRaw();
|
||||
// expand path if "~" or "$HOME" is present in original path
|
||||
@@ -82,7 +255,7 @@ auto waybar::modules::Image::update() -> void {
|
||||
image_.set(surface);
|
||||
image_.show();
|
||||
|
||||
if (tooltipEnabled() && !tooltip_.empty()) {
|
||||
if (hasTooltip_ && !tooltip_.empty()) {
|
||||
if (box_.get_tooltip_markup() != tooltip_) {
|
||||
box_.set_tooltip_markup(tooltip_);
|
||||
}
|
||||
@@ -94,11 +267,9 @@ auto waybar::modules::Image::update() -> void {
|
||||
image_.hide();
|
||||
box_.get_style_context()->add_class("empty");
|
||||
}
|
||||
|
||||
AModule::update();
|
||||
}
|
||||
|
||||
void waybar::modules::Image::parseOutputRaw() {
|
||||
void SingleImageStrategy::parseOutputRaw() {
|
||||
std::istringstream output(output_.out);
|
||||
std::string line;
|
||||
int i = 0;
|
||||
@@ -113,3 +284,5 @@ void waybar::modules::Image::parseOutputRaw() {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace waybar::modules::image
|
||||
|
||||
Reference in New Issue
Block a user