mirror of
https://github.com/aristocratos/btop.git
synced 2024-05-18 19:33:03 +12:00
Added color gradients and function for drawing boxes
This commit is contained in:
parent
8364d856c8
commit
e040e6bb74
95
btop.cpp
95
btop.cpp
|
@ -22,12 +22,14 @@ tab-size = 4
|
|||
#include <thread>
|
||||
#include <future>
|
||||
#include <atomic>
|
||||
#include <ranges>
|
||||
|
||||
#include <btop_globs.h>
|
||||
#include <btop_tools.h>
|
||||
#include <btop_config.h>
|
||||
#include <btop_input.h>
|
||||
#include <btop_theme.h>
|
||||
#include <btop_draw.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <btop_linux.h>
|
||||
|
@ -43,8 +45,8 @@ tab-size = 4
|
|||
#endif
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std;
|
||||
using std::string, std::vector, std::map, std::atomic, std::endl, std::cout, std::views::iota;
|
||||
using namespace Tools;
|
||||
|
||||
|
||||
//? ------------------------------------------------- GLOBALS ---------------------------------------------------------
|
||||
|
@ -88,7 +90,7 @@ void argumentParser(int argc, char **argv){
|
|||
}
|
||||
|
||||
//* Generate the btop++ banner
|
||||
auto create_banner(){
|
||||
auto createBanner(){
|
||||
struct out_vals {
|
||||
uint w;
|
||||
string s;
|
||||
|
@ -137,6 +139,8 @@ string my_worker(int x){
|
|||
//? --------------------------------------------- Main starts here! ---------------------------------------------------
|
||||
int main(int argc, char **argv){
|
||||
|
||||
using namespace std;
|
||||
|
||||
//? Init
|
||||
|
||||
cout.setf(std::ios::boolalpha);
|
||||
|
@ -161,11 +165,13 @@ int main(int argc, char **argv){
|
|||
//? Read config file if present
|
||||
Config::load("____");
|
||||
|
||||
auto thts = time_ms();
|
||||
|
||||
//? Generate the theme
|
||||
Theme::set(Global::Default_theme);
|
||||
|
||||
//? Create the btop++ banner
|
||||
auto [banner_width, banner] = create_banner();
|
||||
auto [banner_width, banner] = createBanner();
|
||||
Global::banner_width = move(banner_width);
|
||||
Global::banner = move(banner);
|
||||
|
||||
|
@ -186,31 +192,43 @@ int main(int argc, char **argv){
|
|||
cout << string(Term::width - 1, '-') << endl;
|
||||
|
||||
|
||||
//* Test MENUS
|
||||
// for (auto& outer : Global::Menus){
|
||||
// for (auto& inner : outer.second){
|
||||
// for (auto& item : inner.second){
|
||||
// cout << item << endl;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//* Test boxes
|
||||
if (true){
|
||||
cout << Box::draw(Box::Conf(10, 5, 50, 10, Theme::c("title"), "testing", "testagain", true, 7)) << Mv::d(12) << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// cout << Config(Bool, "truecolor") << endl;
|
||||
// cout << Config(Int, "tree_depth") << endl;
|
||||
// cout << Config(String, "color_theme") << endl;
|
||||
|
||||
//* Test theme
|
||||
|
||||
int i = 0;
|
||||
if (tests>0) for(auto& item : Global::Default_theme) {
|
||||
cout << Theme::c(item.first) << item.first << ":" << Theme::c("main_fg") << Theme::c(item.first).erase(0, 2) << Fx::reset << " ";
|
||||
if (++i == 4) {
|
||||
i = 0;
|
||||
cout << endl;
|
||||
if (false) {
|
||||
cout << "Theme generation took " << time_ms() - thts << "ms" << endl;
|
||||
|
||||
cout << "Colors:" << endl;
|
||||
uint i = 0;
|
||||
for(auto& item : Theme::colors) {
|
||||
cout << rjust(item.first, 15) << ":" << item.second << "■"s * 10 << Fx::reset << " ";
|
||||
// << Theme::dec(item.first)[0] << ":" << Theme::dec(item.first)[1] << ":" << Theme::dec(item.first)[2] << ;
|
||||
if (++i == 4) {
|
||||
i = 0;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
cout << Fx::reset << endl;
|
||||
|
||||
|
||||
cout << "Gradients:";
|
||||
for (auto& [name, cvec] : Theme::gradients) {
|
||||
cout << endl << rjust(name + ":", 10);
|
||||
for (auto& color : cvec) {
|
||||
cout << color << "■";
|
||||
}
|
||||
|
||||
cout << Fx::reset << endl;
|
||||
}
|
||||
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,13 +238,13 @@ int main(int argc, char **argv){
|
|||
map<int, future<string>> runners;
|
||||
map<int, string> outputs;
|
||||
|
||||
for (int i = 0; i < 10; i++){
|
||||
for (int i : iota(0, 10)){
|
||||
runners[i] = async(my_worker, i);
|
||||
}
|
||||
i = 0;
|
||||
// uint i = 0;
|
||||
while (outputs.size() < 10){
|
||||
|
||||
for (int i = 0; i < 10; i++){
|
||||
for (int i : iota(0, 10)){
|
||||
if (runners[i].valid() && runners[i].wait_for(chrono::milliseconds(10)) == future_status::ready) {
|
||||
outputs[i] = runners[i].get();
|
||||
cout << "Thread " << i << " : " << outputs[i] << endl;
|
||||
|
@ -272,8 +290,8 @@ int main(int argc, char **argv){
|
|||
string filter;
|
||||
string filter_cur;
|
||||
string key;
|
||||
cout << rjustify("Pid:", 8) << " " << ljustify("Program:", 16) << " " << ljustify("Command:", Term::width - 69) << " Threads: " <<
|
||||
ljustify("User:", 10) << " " << rjustify("MemB", 5) << " " << rjustify("Cpu%", 14) << "\n" << Mv::save << flush;
|
||||
cout << rjust("Pid:", 8) << " " << ljust("Program:", 16) << " " << ljust("Command:", Term::width - 69) << " Threads: " <<
|
||||
ljust("User:", 10) << " " << rjust("MemB", 5) << " " << rjust("Cpu%", 14) << "\n" << Mv::save << flush;
|
||||
|
||||
while (key != "q") {
|
||||
timestamp = time_ms();
|
||||
|
@ -284,13 +302,13 @@ int main(int argc, char **argv){
|
|||
ostring.clear();
|
||||
lc = 0;
|
||||
filter_cur = (filtering) ? Fx::bl + "█" + Fx::reset : "";
|
||||
cout << Mv::restore << Mv::u(2) << Mv::r(20) << rjustify("Filter: " + filter + filter_cur + string(Term::width / 3, ' ') +
|
||||
cout << Mv::restore << Mv::u(2) << Mv::r(20) << rjust("Filter: " + filter + filter_cur + string(Term::width / 3, ' ') +
|
||||
"Sorting: " + Proc::sort_vector[sortint], Term::width - 22, true, filtering) << Mv::restore << flush;
|
||||
|
||||
for (Proc::proc_info& procs : plist){
|
||||
ostring += rjustify(to_string(procs.pid), 8) + " " + ljustify(procs.name, 16) + " " + ljustify(procs.cmd, Term::width - 66, true) + " " +
|
||||
rjustify(to_string(procs.threads), 5) + " " + ljustify(procs.user, 10) + " " + rjustify(floating_humanizer(procs.mem, true), 5) + string(11, ' ');
|
||||
ostring += (procs.cpu_p > 100) ? rjustify(to_string(procs.cpu_p), 3) + " " : rjustify(to_string(procs.cpu_p), 4);
|
||||
ostring += rjust(to_string(procs.pid), 8) + " " + ljust(procs.name, 16) + " " + ljust(procs.cmd, Term::width - 66, true) + " " +
|
||||
rjust(to_string(procs.threads), 5) + " " + ljust(procs.user, 10) + " " + rjust(floating_humanizer(procs.mem, true), 5) + string(11, ' ');
|
||||
ostring += (procs.cpu_p > 100) ? rjust(to_string(procs.cpu_p), 3) + " " : rjust(to_string(procs.cpu_p), 4);
|
||||
ostring += "\n";
|
||||
if (lc++ > Term::height - 20) break;
|
||||
}
|
||||
|
@ -329,19 +347,6 @@ int main(int argc, char **argv){
|
|||
|
||||
|
||||
|
||||
if (tests>3){
|
||||
auto nbcolor = Theme::hex_to_color(Global::Default_theme.at("net_box"));
|
||||
auto nbcolor_rgb = Theme::rgb(nbcolor);
|
||||
auto nbcolor_man = ssplit(nbcolor, ";");
|
||||
cout << nbcolor << "Some color" << endl;
|
||||
cout << "nbcolor_rgb size=" << nbcolor_rgb.size() << endl;
|
||||
cout << "R:" << nbcolor_rgb.at("r") << " G:" << nbcolor_rgb.at("g") << " B:" << nbcolor_rgb.at("b") << endl;
|
||||
cout << "MANUAL R:" << nbcolor_man.at(2) << " G:" << nbcolor_man.at(3) << " B:" << nbcolor_man.at(4) << endl;
|
||||
|
||||
auto ccc = Theme::dec_to_color(100, 255, 100);
|
||||
cout << "\n" << ccc << "Testing..." << endl;
|
||||
}
|
||||
|
||||
|
||||
if (tests>4){
|
||||
string trim_test1 = "-*vad ";
|
||||
|
|
|
@ -25,7 +25,8 @@ tab-size = 4
|
|||
|
||||
#include <btop_tools.h>
|
||||
|
||||
using namespace std;
|
||||
using std::string, std::vector, std::map;
|
||||
using namespace Tools;
|
||||
|
||||
|
||||
//* Functions and variables for reading and writing the btop config file
|
||||
|
|
90
src/btop_draw.h
Normal file
90
src/btop_draw.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
|
||||
#include <btop_globs.h>
|
||||
#include <btop_config.h>
|
||||
#include <btop_tools.h>
|
||||
|
||||
#ifndef _btop_draw_included_
|
||||
#define _btop_draw_included_ 1
|
||||
|
||||
using std::string, std::vector, std::map, std::round, std::views::iota;
|
||||
|
||||
namespace Box {
|
||||
|
||||
struct Conf {
|
||||
uint x=0, y=0;
|
||||
uint width=0, height=0;
|
||||
string line_color = "", title = "", title2 = "";
|
||||
bool fill = true;
|
||||
uint num=0;
|
||||
};
|
||||
|
||||
|
||||
string draw(Conf c){
|
||||
string out;
|
||||
string lcolor = (c.line_color.empty()) ? Theme::c("div_line") : c.line_color;
|
||||
string numbering = (c.num == 0) ? "" : Theme::c("hi_fg") + Symbols::superscript[c.num];
|
||||
|
||||
out = Fx::reset + lcolor;
|
||||
|
||||
//* Draw horizontal lines
|
||||
for (uint hpos : {c.y, c.y + c.height - 1}){
|
||||
out += Mv::to(hpos, c.x) + Symbols::h_line * (c.width - 1);
|
||||
}
|
||||
|
||||
//* Draw vertical lines and fill if enabled
|
||||
for (uint hpos : iota(c.y + 1, c.y + c.height - 1)){
|
||||
out += Mv::to(hpos, c.x) + Symbols::v_line +
|
||||
((c.fill) ? string(c.width - 2, ' ') : Mv::r(c.width - 2)) +
|
||||
Symbols::v_line;
|
||||
}
|
||||
|
||||
//* Draw corners
|
||||
out += Mv::to(c.y, c.x) + Symbols::left_up +
|
||||
Mv::to(c.y, c.x + c.width - 1) + Symbols::right_up +
|
||||
Mv::to(c.y + c.height - 1, c.x) + Symbols::left_down +
|
||||
Mv::to(c.y + c.height - 1, c.x + c.width - 1) + Symbols::right_down;
|
||||
|
||||
//* Draw titles if defined
|
||||
if (!c.title.empty()){
|
||||
out += Mv::to(c.y, c.x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + c.title +
|
||||
Fx::ub + lcolor + Symbols::title_right;
|
||||
}
|
||||
|
||||
return out + Fx::reset + Mv::to(c.y + 1, c.x + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Proc {
|
||||
|
||||
// Box::Conf box;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -24,7 +24,7 @@ tab-size = 4
|
|||
#include <vector>
|
||||
#include <atomic>
|
||||
|
||||
using namespace std;
|
||||
using std::string, std::vector, std::map, std::atomic;
|
||||
|
||||
namespace Global {
|
||||
|
||||
|
@ -120,4 +120,19 @@ namespace Global {
|
|||
|
||||
}
|
||||
|
||||
namespace Symbols {
|
||||
const string h_line = "─";
|
||||
const string v_line = "│";
|
||||
const string left_up = "┌";
|
||||
const string right_up = "┐";
|
||||
const string left_down = "└";
|
||||
const string right_down = "┘";
|
||||
const string title_left = "┤";
|
||||
const string title_right = "├";
|
||||
const string div_up = "┬";
|
||||
const string div_down = "┴";
|
||||
|
||||
const vector<string> superscript = { "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" };
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,8 @@ tab-size = 4
|
|||
#include <btop_globs.h>
|
||||
#include <btop_tools.h>
|
||||
|
||||
using namespace std;
|
||||
using std::string, std::map, std::cin;
|
||||
using namespace Tools;
|
||||
|
||||
|
||||
//* Functions and variables for handling keyboard and mouse input
|
||||
|
|
|
@ -21,7 +21,6 @@ tab-size = 4
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <map>
|
||||
#include <atomic>
|
||||
#include <fstream>
|
||||
|
@ -34,13 +33,15 @@ tab-size = 4
|
|||
#include <btop_globs.h>
|
||||
#include <btop_tools.h>
|
||||
|
||||
|
||||
using std::string, std::vector, std::map, std::ifstream, std::atomic, std::numeric_limits, std::streamsize;
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std;
|
||||
using namespace Tools;
|
||||
|
||||
namespace Global {
|
||||
|
||||
const string System = "linux";
|
||||
filesystem::path proc_path;
|
||||
fs::path proc_path;
|
||||
|
||||
}
|
||||
|
||||
|
@ -254,7 +255,7 @@ namespace Proc {
|
|||
// auto st = time_ms();
|
||||
|
||||
//* Sort processes vector
|
||||
ranges::sort(procs, [&sortint, &reverse](proc_info& a, proc_info& b)
|
||||
std::ranges::sort(procs, [&sortint, &reverse](proc_info& a, proc_info& b)
|
||||
{
|
||||
switch (sortint) {
|
||||
case 0: return (reverse) ? a.pid < b.pid : a.pid > b.pid;
|
||||
|
@ -281,15 +282,12 @@ namespace Proc {
|
|||
}
|
||||
}
|
||||
|
||||
//* Clear all cached values at a regular interval to get rid of dead processes
|
||||
if (++counter >= 5 || (filter.empty() && cache.size() > procs.size() + 100)) {
|
||||
//* Clear dead processes from cache at a regular interval
|
||||
if (++counter >= 10000 || (filter.empty() && cache.size() > procs.size() + 100)) {
|
||||
map<uint, p_cache> r_cache;
|
||||
counter = 0;
|
||||
for (auto& p : c_pids){
|
||||
r_cache[p] = cache[p];
|
||||
}
|
||||
for (auto& p : c_pids) r_cache[p] = cache[p];
|
||||
cache = move(r_cache);
|
||||
|
||||
}
|
||||
|
||||
tstamp = time_ms();
|
||||
|
|
120
src/btop_theme.h
120
src/btop_theme.h
|
@ -23,12 +23,14 @@ tab-size = 4
|
|||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
|
||||
#include <btop_globs.h>
|
||||
#include <btop_tools.h>
|
||||
#include <btop_config.h>
|
||||
|
||||
using namespace std;
|
||||
using std::string, std::round, std::vector, std::map, std::stoi, std::views::iota;
|
||||
using namespace Tools;
|
||||
|
||||
namespace Theme {
|
||||
|
||||
|
@ -97,7 +99,7 @@ namespace Theme {
|
|||
}
|
||||
|
||||
//* Return a map of "r", "g", "b", 0-255 values for a 24-bit color escape string
|
||||
map<string, int> rgb(string c_string){
|
||||
map<string, int> esc_to_rgb(string c_string){
|
||||
map<string, int> rgb = {{"r", 0}, {"g", 0}, {"b", 0}};
|
||||
if (c_string.size() >= 14){
|
||||
c_string.erase(0, 7);
|
||||
|
@ -111,48 +113,122 @@ namespace Theme {
|
|||
return rgb;
|
||||
}
|
||||
|
||||
namespace {
|
||||
map<string, string> color;
|
||||
map<string, vector<string>> gradient;
|
||||
|
||||
//* Generate the theme
|
||||
map<string,string> generate(map<string, string>& source){
|
||||
map<string, string> out;
|
||||
namespace {
|
||||
map<string, string> colors;
|
||||
map<string, vector<int>> rgbs;
|
||||
map<string, vector<string>> gradients;
|
||||
|
||||
//* Convert hex color to a vector of decimals
|
||||
vector<int> hex_to_dec(string hexa){
|
||||
if (hexa.size() > 1){
|
||||
hexa.erase(0, 1);
|
||||
for (auto& c : hexa) if (!isxdigit(c)) return vector<int>{-1, -1, -1};
|
||||
|
||||
if (hexa.size() == 2){
|
||||
int h_int = stoi(hexa, 0, 16);
|
||||
return vector<int>{h_int, h_int, h_int};
|
||||
}
|
||||
else if (hexa.size() == 6){
|
||||
return vector<int>{
|
||||
stoi(hexa.substr(0, 2), 0, 16),
|
||||
stoi(hexa.substr(2, 2), 0, 16),
|
||||
stoi(hexa.substr(4, 2), 0, 16)
|
||||
};
|
||||
}
|
||||
}
|
||||
return vector<int>{-1 ,-1 ,-1};
|
||||
}
|
||||
|
||||
//* Generate colors and rgb decimal vectors for the theme
|
||||
void generateColors(map<string, string>& source){
|
||||
vector<string> t_rgb;
|
||||
string depth;
|
||||
for (auto& item : Global::Default_theme) {
|
||||
depth = (item.first.ends_with("bg")) ? "bg" : "fg";
|
||||
if (source.contains(item.first)) {
|
||||
if (source.at(item.first)[0] == '#') out[item.first] = hex_to_color(source.at(item.first), !Config::getB("truecolor"), depth);
|
||||
colors.clear(); rgbs.clear();
|
||||
for (auto& [name, color] : Global::Default_theme) {
|
||||
depth = (name.ends_with("bg")) ? "bg" : "fg";
|
||||
if (source.contains(name)) {
|
||||
if (source.at(name)[0] == '#') {
|
||||
colors[name] = hex_to_color(source.at(name), !Config::getB("truecolor"), depth);
|
||||
rgbs[name] = hex_to_dec(source.at(name));
|
||||
}
|
||||
else {
|
||||
t_rgb = ssplit(source.at(item.first), " ");
|
||||
out[item.first] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), !Config::getB("truecolor"), depth);
|
||||
t_rgb = ssplit(source.at(name), " ");
|
||||
colors[name] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), !Config::getB("truecolor"), depth);
|
||||
rgbs[name] = vector<int>{stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2])};
|
||||
}
|
||||
}
|
||||
else out[item.first] = "";
|
||||
if (out[item.first].empty()) out[item.first] = hex_to_color(item.second, !Config::getB("truecolor"), depth);
|
||||
else colors[name] = "";
|
||||
if (colors[name].empty()) {
|
||||
colors[name] = hex_to_color(color, !Config::getB("truecolor"), depth);
|
||||
rgbs[name] = vector<int>{-1, -1, -1};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Generate color gradients from one, two or three colors, 101 values indexed 0-100
|
||||
void generateGradients(){
|
||||
gradients.clear();
|
||||
vector<string> c_gradient;
|
||||
string wname;
|
||||
vector<vector<int>> rgb_vec;
|
||||
map<int, vector<int>> dec_map;
|
||||
int f, s, r, o;
|
||||
for (auto& [name, s_vector] : rgbs){
|
||||
dec_map.clear(); c_gradient.clear();
|
||||
if (!name.ends_with("_start")) continue;
|
||||
wname = rtrim(name, "_start");
|
||||
rgb_vec = {s_vector, rgbs[wname + "_mid"], rgbs[wname + "_end"]};
|
||||
|
||||
//? Only start iteration if gradient has a _end color value defined
|
||||
if (rgb_vec[2][0] >= 0) {
|
||||
|
||||
//? Split iteration in two passes of 50 + 51 instead of 101 if gradient has _start, _mid and _end values defined
|
||||
r = (rgb_vec[1][0] >= 0) ? 50 : 100;
|
||||
for (int i : iota(0, 3)){
|
||||
f = 0; s = (r == 50) ? 1 : 2; o = 0;
|
||||
for (int c : iota(0, 101)){
|
||||
dec_map[c].push_back(rgb_vec[f][i] + (c - o) * (rgb_vec[s][i] - rgb_vec[f][i]) / r);
|
||||
|
||||
//? Switch source vectors from _start/_mid to _mid/_end at 50 passes if _mid is defined
|
||||
if (c == r) { ++f; ++s; o = 50;}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dec_map.empty()) {
|
||||
for (auto& vec : dec_map) c_gradient.push_back(dec_to_color(vec.second[0], vec.second[1], vec.second[2], !Config::getB("truecolor")));
|
||||
} else {
|
||||
//? If only _start was defined create vector of 101 copies of _start color
|
||||
c_gradient = vector<string>(101, colors[name]);
|
||||
}
|
||||
gradients[wname] = c_gradient;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//* Set current theme using <source> map
|
||||
void set(map<string, string> source){
|
||||
color = generate(source);
|
||||
Term::fg = color.at("main_fg");
|
||||
Term::bg = color.at("main_bg");
|
||||
generateColors(source);
|
||||
generateGradients();
|
||||
Term::fg = colors.at("main_fg");
|
||||
Term::bg = colors.at("main_bg");
|
||||
Fx::reset = Fx::reset_base + Term::fg + Term::bg;
|
||||
}
|
||||
|
||||
//* Return escape code for color <name>
|
||||
auto c(string name){
|
||||
return color.at(name);
|
||||
return colors.at(name);
|
||||
}
|
||||
|
||||
//* Return vector of escape codes for color gradient <name>
|
||||
auto g(string name){
|
||||
return gradient.at(name);
|
||||
return gradients.at(name);
|
||||
}
|
||||
|
||||
//* Return vector of red, green and blue in decimal for color <name>
|
||||
auto dec(string name){
|
||||
return rgbs.at(name);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
341
src/btop_tools.h
341
src/btop_tools.h
|
@ -25,15 +25,15 @@ tab-size = 4
|
|||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <btop_globs.h>
|
||||
#include <btop_config.h>
|
||||
|
||||
using namespace std;
|
||||
using std::string, std::vector, std::map, std::regex, std::max, std::to_string, std::cin;
|
||||
|
||||
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
||||
|
||||
|
@ -42,23 +42,29 @@ namespace Fx {
|
|||
//* Escape sequence start
|
||||
const string e = "\x1b[";
|
||||
|
||||
//* Bold on
|
||||
//* Bold on/off
|
||||
const string b = e + "1m";
|
||||
const string ub = e + "22m";
|
||||
|
||||
//* Dark on
|
||||
//* Dark on/off
|
||||
const string d = e + "2m";
|
||||
const string ud = e + "22m";
|
||||
|
||||
//* Italic on
|
||||
//* Italic on/off
|
||||
const string i = e + "3m";
|
||||
const string ui = e + "23m";
|
||||
|
||||
//* Underline on
|
||||
//* Underline on/off
|
||||
const string ul = e + "4m";
|
||||
const string uul = e + "24m";
|
||||
|
||||
//* Blink on
|
||||
//* Blink on/off
|
||||
const string bl = e + "5m";
|
||||
const string ubl = e + "25m";
|
||||
|
||||
//* Strike / crossed-out on
|
||||
//* Strike / crossed-out on/off
|
||||
const string s = e + "9m";
|
||||
const string us = e + "29m";
|
||||
|
||||
//* Reset foreground/background color and text effects
|
||||
const string reset_base = e + "0m";
|
||||
|
@ -212,177 +218,202 @@ namespace Term {
|
|||
|
||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
//* Return number of UTF8 characters in a string with option to disregard escape sequences
|
||||
inline size_t ulen(string s, bool escape=false){
|
||||
if (escape) s = regex_replace(s, Fx::escape_regex, "");
|
||||
return std::count_if(s.begin(), s.end(),
|
||||
[](char c) { return (static_cast<unsigned char>(c) & 0xC0) != 0x80; } );
|
||||
}
|
||||
namespace Tools {
|
||||
|
||||
//* Return current time since epoch in milliseconds
|
||||
uint64_t time_ms(){
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
//* Return number of UTF8 characters in a string with option to disregard escape sequences
|
||||
inline size_t ulen(string s, bool escape=false){
|
||||
if (escape) s = std::regex_replace(s, Fx::escape_regex, "");
|
||||
return std::count_if(s.begin(), s.end(),
|
||||
[](char c) { return (static_cast<unsigned char>(c) & 0xC0) != 0x80; } );
|
||||
}
|
||||
|
||||
//* Check if a string is a valid bool value
|
||||
bool isbool(string str){
|
||||
return (str == "true") || (str == "false") || (str == "True") || (str == "False");
|
||||
}
|
||||
//* Return current time since epoch in milliseconds
|
||||
uint64_t time_ms(){
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Check if a string is a valid integer value
|
||||
bool isint(string str){
|
||||
return all_of(str.begin(), str.end(), ::isdigit);
|
||||
}
|
||||
//* Check if a string is a valid bool value
|
||||
bool isbool(string str){
|
||||
return (str == "true") || (str == "false") || (str == "True") || (str == "False");
|
||||
}
|
||||
|
||||
//* Left-trim <t_str> from <str> and return string
|
||||
string ltrim(string str, string t_str = " "){
|
||||
while (str.starts_with(t_str)) str.erase(0, t_str.size());
|
||||
return str;
|
||||
}
|
||||
//* Check if a string is a valid integer value
|
||||
bool isint(string str){
|
||||
return all_of(str.begin(), str.end(), ::isdigit);
|
||||
}
|
||||
|
||||
//* Right-trim <t_str> from <str> and return string
|
||||
string rtrim(string str, string t_str = " "){
|
||||
while (str.ends_with(t_str)) str.resize(str.size() - t_str.size());
|
||||
return str;
|
||||
}
|
||||
//* Left-trim <t_str> from <str> and return string
|
||||
string ltrim(string str, string t_str = " "){
|
||||
while (str.starts_with(t_str)) str.erase(0, t_str.size());
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Left-right-trim <t_str> from <str> and return string
|
||||
string trim(string str, string t_str = " "){
|
||||
return ltrim(rtrim(str, t_str), t_str);
|
||||
}
|
||||
//* Right-trim <t_str> from <str> and return string
|
||||
string rtrim(string str, string t_str = " "){
|
||||
while (str.ends_with(t_str)) str.resize(str.size() - t_str.size());
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Split <string> at <delim> <time> number of times (0 for unlimited) and return vector
|
||||
vector<string> ssplit(string str, string delim = " ", int times = 0){
|
||||
vector<string> out;
|
||||
if (!str.empty() && !delim.empty()){
|
||||
size_t pos = 0;
|
||||
int x = 0;
|
||||
string tmp;
|
||||
while ((pos = str.find(delim)) != string::npos){
|
||||
tmp = str.substr(0, pos);
|
||||
if (tmp != delim && !tmp.empty()) out.push_back(tmp);
|
||||
str.erase(0, pos + delim.size());
|
||||
if (times > 0 && ++x >= times) break;
|
||||
//* Left-right-trim <t_str> from <str> and return string
|
||||
string trim(string str, string t_str = " "){
|
||||
return ltrim(rtrim(str, t_str), t_str);
|
||||
}
|
||||
|
||||
//* Split <string> at <delim> <time> number of times (0 for unlimited) and return vector
|
||||
vector<string> ssplit(string str, string delim = " ", int times = 0){
|
||||
vector<string> out;
|
||||
if (!str.empty() && !delim.empty()){
|
||||
size_t pos = 0;
|
||||
int x = 0;
|
||||
string tmp;
|
||||
while ((pos = str.find(delim)) != string::npos){
|
||||
tmp = str.substr(0, pos);
|
||||
if (tmp != delim && !tmp.empty()) out.push_back(tmp);
|
||||
str.erase(0, pos + delim.size());
|
||||
if (times > 0 && ++x >= times) break;
|
||||
}
|
||||
}
|
||||
out.push_back(str);
|
||||
return out;
|
||||
}
|
||||
|
||||
//* Put current thread to sleep for <ms> milliseconds
|
||||
void sleep_ms(uint ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
//* Left justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string ljust(string str, const size_t x, bool utf=false, bool escape=false, bool lim=true){
|
||||
if (utf || escape) {
|
||||
if (!escape && lim && ulen(str) > x) {
|
||||
auto i = str.size();
|
||||
while (ulen(str) > x) str.resize(--i);
|
||||
}
|
||||
return str + string(max((int)(x - ulen(str, escape)), 0), ' ');
|
||||
}
|
||||
else {
|
||||
if (lim && str.size() > x) str.resize(x);
|
||||
return str + string(max((int)(x - str.size()), 0), ' ');
|
||||
}
|
||||
}
|
||||
out.push_back(str);
|
||||
return out;
|
||||
}
|
||||
|
||||
//* Put current thread to sleep for <ms> milliseconds
|
||||
void sleep_ms(uint ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
//* Left justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string ljustify(string str, size_t x, bool utf=false, bool escape=false, bool lim=true){
|
||||
if (utf || escape) {
|
||||
if (!escape && lim && ulen(str) > x) {
|
||||
auto i = str.size();
|
||||
while (ulen(str) > x) str.resize(--i);
|
||||
//* Right justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string rjust(string str, const size_t x, bool utf=false, bool escape=false, bool lim=true){
|
||||
if (utf || escape) {
|
||||
if (!escape && lim && ulen(str) > x) {
|
||||
auto i = str.size();
|
||||
while (ulen(str) > x) str.resize(--i);
|
||||
}
|
||||
return string(max((int)(x - ulen(str, escape)), 0), ' ') + str;
|
||||
}
|
||||
return str + string(max((int)(x - ulen(str, escape)), 0), ' ');
|
||||
}
|
||||
else {
|
||||
if (lim && str.size() > x) str.resize(x);
|
||||
return str + string(max((int)(x - str.size()), 0), ' ');
|
||||
}
|
||||
}
|
||||
|
||||
//* Right justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string rjustify(string str, size_t x, bool utf=false, bool escape=false, bool lim=true){
|
||||
if (utf || escape) {
|
||||
if (!escape && lim && ulen(str) > x) {
|
||||
auto i = str.size();
|
||||
while (ulen(str) > x) str.resize(--i);
|
||||
else {
|
||||
if (lim && str.size() > x) str.resize(x);
|
||||
return string(max((int)(x - str.size()), 0), ' ') + str;
|
||||
}
|
||||
return string(max((int)(x - ulen(str, escape)), 0), ' ') + str;
|
||||
}
|
||||
else {
|
||||
if (lim && str.size() > x) str.resize(x);
|
||||
return string(max((int)(x - str.size()), 0), ' ') + str;
|
||||
|
||||
//* Trim trailing characters if utf8 string length is greatear than <x>
|
||||
string uresize(string str, const size_t x){
|
||||
if (str.empty()) return str;
|
||||
while (ulen(str) > x) str.pop_back();
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
//* Trim trailing characters if utf8 string length is greatear than <x>
|
||||
string uresize(string str, size_t x){
|
||||
// auto i = str.size();
|
||||
if (str.empty()) return str;
|
||||
while (ulen(str) > x) str.pop_back();
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Replace whitespaces " " with escape code for move right
|
||||
string trans(string str){
|
||||
size_t pos;
|
||||
string newstr;
|
||||
while ((pos = str.find(' ')) != string::npos){
|
||||
newstr.append(str.substr(0, pos));
|
||||
str.erase(0, pos);
|
||||
pos = 1;
|
||||
while (pos < str.size() && str.at(pos) == ' ') pos++;
|
||||
newstr.append(Mv::r(pos));
|
||||
str.erase(0, pos);
|
||||
//* Replace whitespaces " " with escape code for move right
|
||||
string trans(string str){
|
||||
size_t pos;
|
||||
string newstr;
|
||||
while ((pos = str.find(' ')) != string::npos){
|
||||
newstr.append(str.substr(0, pos));
|
||||
str.erase(0, pos);
|
||||
pos = 1;
|
||||
while (pos < str.size() && str.at(pos) == ' ') pos++;
|
||||
newstr.append(Mv::r(pos));
|
||||
str.erase(0, pos);
|
||||
}
|
||||
return (newstr.empty()) ? str : newstr;
|
||||
}
|
||||
return (newstr.empty()) ? str : newstr;
|
||||
}
|
||||
|
||||
string sec_to_dhms(uint sec){
|
||||
string out;
|
||||
uint d, h, m;
|
||||
d = sec / (3600 * 24);
|
||||
sec %= 3600 * 24;
|
||||
h = sec / 3600;
|
||||
sec %= 3600;
|
||||
m = sec / 60;
|
||||
sec %= 60;
|
||||
if (d>0) out = to_string(d) + "d ";
|
||||
out += (h<10) ? "0" + to_string(h) + ":" : to_string(h) + ":";
|
||||
out += (m<10) ? "0" + to_string(m) + ":" : to_string(m) + ":";
|
||||
out += (sec<10) ? "0" + to_string(sec) : to_string(sec);
|
||||
return out;
|
||||
}
|
||||
//* Convert seconds to format "Xd HH:MM:SS" and return string
|
||||
string sec_to_dhms(uint sec){
|
||||
string out;
|
||||
uint d, h, m;
|
||||
d = sec / (3600 * 24);
|
||||
sec %= 3600 * 24;
|
||||
h = sec / 3600;
|
||||
sec %= 3600;
|
||||
m = sec / 60;
|
||||
sec %= 60;
|
||||
if (d>0) out = to_string(d) + "d ";
|
||||
out += (h<10) ? "0" + to_string(h) + ":" : to_string(h) + ":";
|
||||
out += (m<10) ? "0" + to_string(m) + ":" : to_string(m) + ":";
|
||||
out += (sec<10) ? "0" + to_string(sec) : to_string(sec);
|
||||
return out;
|
||||
}
|
||||
|
||||
//* Scales up in steps of 1024 to highest possible unit and returns string with unit suffixed
|
||||
//* bit=True or defaults to bytes
|
||||
//* start=int to set 1024 multiplier starting unit
|
||||
//* short=True always returns 0 decimals and shortens unit to 1 character
|
||||
string floating_humanizer(uint64_t value, bool shorten=false, uint start=0, bool bit=false, bool per_second=false){
|
||||
string out;
|
||||
uint mult = (bit) ? 8 : 1;
|
||||
auto& units = (bit) ? Global::Units_bit : Global::Units_byte;
|
||||
//* Scales up in steps of 1024 to highest possible unit and returns string with unit suffixed
|
||||
//* bit=True or defaults to bytes
|
||||
//* start=int to set 1024 multiplier starting unit
|
||||
//* short=True always returns 0 decimals and shortens unit to 1 character
|
||||
string floating_humanizer(uint64_t value, bool shorten=false, uint start=0, bool bit=false, bool per_second=false){
|
||||
string out;
|
||||
uint mult = (bit) ? 8 : 1;
|
||||
auto& units = (bit) ? Global::Units_bit : Global::Units_byte;
|
||||
|
||||
value *= 100 * mult;
|
||||
value *= 100 * mult;
|
||||
|
||||
while (value >= 102400){
|
||||
value >>= 10;
|
||||
if (value < 100){
|
||||
while (value >= 102400){
|
||||
value >>= 10;
|
||||
if (value < 100){
|
||||
out = to_string(value);
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = to_string(value);
|
||||
break;
|
||||
if (out.size() == 4 && start > 0) { out.pop_back(); out.insert(2, ".");}
|
||||
else if (out.size() == 3 && start > 0) out.insert(1, ".");
|
||||
else if (out.size() >= 2) out.resize(out.size() - 2);
|
||||
}
|
||||
start++;
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = to_string(value);
|
||||
if (out.size() == 4 && start > 0) { out.pop_back(); out.insert(2, ".");}
|
||||
else if (out.size() == 3 && start > 0) out.insert(1, ".");
|
||||
else if (out.size() >= 2) out.resize(out.size() - 2);
|
||||
}
|
||||
if (shorten){
|
||||
if (out.find('.') != string::npos) out = to_string((int)round(stof(out)));
|
||||
if (out.size() > 3) { out = to_string((int)(out[0] - '0') + 1); start++;}
|
||||
out.push_back(units[start][0]);
|
||||
}
|
||||
else out += " " + units[start];
|
||||
if (shorten){
|
||||
if (out.find('.') != string::npos) out = to_string((int)round(stof(out)));
|
||||
if (out.size() > 3) { out = to_string((int)(out[0] - '0') + 1); start++;}
|
||||
out.push_back(units[start][0]);
|
||||
}
|
||||
else out += " " + units[start];
|
||||
|
||||
if (per_second) out += (bit) ? "ps" : "/s";
|
||||
return out;
|
||||
}
|
||||
|
||||
//* Repeat string <str> <n> number of times
|
||||
string repeat(string str, const size_t n){
|
||||
if (n == 0){
|
||||
str.clear();
|
||||
str.shrink_to_fit();
|
||||
return str;
|
||||
} else if (n == 1 || str.empty()){
|
||||
return str;
|
||||
}
|
||||
const auto period = str.size();
|
||||
if (period == 1){
|
||||
str.append(n - 1, str.front());
|
||||
return str;
|
||||
}
|
||||
str.reserve(period * n);
|
||||
size_t m = 2;
|
||||
for (; m < n; m *= 2) str += str;
|
||||
str.append(str.c_str(), (n - (m / 2)) * period);
|
||||
return str;
|
||||
}
|
||||
|
||||
//* String gets passed to repeat function
|
||||
std::string operator*(string str, size_t n){
|
||||
return repeat(std::move(str), n);
|
||||
}
|
||||
|
||||
if (per_second) out += (bit) ? "ps" : "/s";
|
||||
return out;
|
||||
}
|
||||
|
||||
//? --------------------------------------------------- CLASSES -----------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//? --------------------------------------------------- STRUCTS -------------------------------------------------------
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue