Added color gradients and function for drawing boxes

This commit is contained in:
aristocratos 2021-05-16 22:58:16 +02:00
parent 8364d856c8
commit e040e6bb74
8 changed files with 452 additions and 235 deletions

View file

@ -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 ";

View file

@ -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
View 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

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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);
}
};

View file

@ -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