diff --git a/Makefile b/Makefile index 37c236e..39db6a2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ PREFIX ?= /usr/local DOCDIR ?= $(PREFIX)/share/btop/doc CPP = g++ -CPPFLAGS = -std=c++20 -pthread +override CPPFLAGS += -std=c++20 -pthread OPTFLAG = -O3 INFOFLAGS += -Wall -Wextra -Wno-stringop-overread -pedantic INCLUDES = -I./src -I./include diff --git a/btop.cpp b/btop.cpp index 3ec509b..9a170a4 100644 --- a/btop.cpp +++ b/btop.cpp @@ -246,7 +246,7 @@ int main(int argc, char **argv){ //? Read config file if present Config::load("____"); - Config::setB("truecolor", false); + // Config::setB("truecolor", false); auto thts = time_ms(); @@ -260,7 +260,7 @@ int main(int argc, char **argv){ //* ------------------------------------------------ TESTING ------------------------------------------------------ - Global::debuginit = false; + Global::debuginit = true; // cout << Theme("main_bg") << Term::clear << flush; bool thread_test = false; @@ -336,6 +336,45 @@ int main(int argc, char **argv){ exit(0); } + if (true) { + + vector mydata; + for (long long i = 0; i <= 100; i++) mydata.push_back(i); + for (long long i = 100; i >= 0; i--) mydata.push_back(i); + for (long long i = 0; i <= 100; i++) mydata.push_back(i); + for (long long i = 100; i >= 0; i--) mydata.push_back(i); + + Draw::Graph kgraph {}; + + auto kts = time_micros(); + kgraph(Term::width, Term::height - 10, "cpu", mydata); + + + cout << Mv::save << kgraph() << "\n\nInit took " << time_micros() - kts << " μs. "; + + // int x = 0; + // long long y = 0; + // bool flip = false; + list ktavg; + while (!Input::poll()) { + mydata.back() = std::rand() % 101; + // mydata.back() = y; + kts = time_micros(); + cout << Mv::restore << kgraph(mydata) << endl; + ktavg.push_front(time_micros() - kts); + if (ktavg.size() > 100) ktavg.pop_back(); + cout << "Time: " << ktavg.front() << " μs. Avg: " << accumulate(ktavg.begin(), ktavg.end(), 0) / ktavg.size() << " μs. " << flush; + // if (flip) y--; + // else y++; + // if (y == 100 || y == 0) flip = !flip; + sleep_ms(50); + } + Input::get(); + + exit(0); + + } + if (thread_test){ diff --git a/src/btop_draw.h b/src/btop_draw.h index 2066789..58d1c03 100644 --- a/src/btop_draw.h +++ b/src/btop_draw.h @@ -20,6 +20,7 @@ tab-size = 4 #include #include +#include #include #include #include @@ -31,7 +32,8 @@ tab-size = 4 #ifndef _btop_draw_included_ #define _btop_draw_included_ 1 -using std::string, std::vector, robin_hood::unordered_flat_map, std::round, std::views::iota, std::string_literals::operator""s, std::clamp; +using std::string, std::vector, robin_hood::unordered_flat_map, std::round, std::views::iota, + std::string_literals::operator""s, std::clamp, std::array, std::floor; namespace Symbols { const string h_line = "─"; @@ -49,9 +51,7 @@ namespace Symbols { const array superscript = { "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" }; - const unordered_flat_map graph_00 = { {true, Mv::r(1)}, {false, " "} }; - - unordered_flat_map graph_up = { + const unordered_flat_map graph_up = { {0.0, " "}, {0.1, "⢀"}, {0.2, "⢠"}, {0.3, "⢰"}, {0.4, "⢸"}, {1.0, "⡀"}, {1.1, "⣀"}, {1.2, "⣠"}, {1.3, "⣰"}, {1.4, "⣸"}, {2.0, "⡄"}, {2.1, "⣄"}, {2.2, "⣤"}, {2.3, "⣴"}, {2.4, "⣼"}, @@ -59,13 +59,29 @@ namespace Symbols { {4.0, "⡇"}, {4.1, "⣇"}, {4.2, "⣧"}, {4.3, "⣷"}, {4.4, "⣿"} }; - unordered_flat_map graph_down = { + const unordered_flat_map graph_down = { {0.0, " "}, {0.1, "⠈"}, {0.2, "⠘"}, {0.3, "⠸"}, {0.4, "⢸"}, {1.0, "⠁"}, {1.1, "⠉"}, {1.2, "⠙"}, {1.3, "⠹"}, {1.4, "⢹"}, {2.0, "⠃"}, {2.1, "⠋"}, {2.2, "⠛"}, {2.3, "⠻"}, {2.4, "⢻"}, {3.0, "⠇"}, {3.1, "⠏"}, {3.2, "⠟"}, {3.3, "⠿"}, {3.4, "⢿"}, {4.0, "⡇"}, {4.1, "⡏"}, {4.2, "⡟"}, {4.3, "⡿"}, {4.4, "⣿"} }; + + const unordered_flat_map graph_up_small = { + {0.0, Mv::r(1)}, {0.1, "⢀"}, {0.2, "⢠"}, {0.3, "⢰"}, {0.4, "⢸"}, + {1.0, "⡀"}, {1.1, "⣀"}, {1.2, "⣠"}, {1.3, "⣰"}, {1.4, "⣸"}, + {2.0, "⡄"}, {2.1, "⣄"}, {2.2, "⣤"}, {2.3, "⣴"}, {2.4, "⣼"}, + {3.0, "⡆"}, {3.1, "⣆"}, {3.2, "⣦"}, {3.3, "⣶"}, {3.4, "⣾"}, + {4.0, "⡇"}, {4.1, "⣇"}, {4.2, "⣧"}, {4.3, "⣷"}, {4.4, "⣿"} + }; + + const unordered_flat_map graph_down_small = { + {0.0, Mv::r(1)}, {0.1, "⠈"}, {0.2, "⠘"}, {0.3, "⠸"}, {0.4, "⢸"}, + {1.0, "⠁"}, {1.1, "⠉"}, {1.2, "⠙"}, {1.3, "⠹"}, {1.4, "⢹"}, + {2.0, "⠃"}, {2.1, "⠋"}, {2.2, "⠛"}, {2.3, "⠻"}, {2.4, "⢻"}, + {3.0, "⠇"}, {3.1, "⠏"}, {3.2, "⠟"}, {3.3, "⠿"}, {3.4, "⢿"}, + {4.0, "⡇"}, {4.1, "⡏"}, {4.2, "⡟"}, {4.3, "⡿"}, {4.4, "⣿"} + }; } namespace Draw { @@ -120,7 +136,7 @@ namespace Draw { //* Class holding a percentage meter class Meter { string out, color_gradient; - int width = 10; + int width = 0; bool invert = false; vector cache; public: @@ -160,6 +176,103 @@ namespace Draw { }; + //* Class holding a graph + class Graph { + string out, color_gradient; + int width = 0, height = 0, lowest = 0; + long long last = 0, max_value = 0, offset = 0; + bool current = true, no_zero = false, invert = false, data_same = true; + unordered_flat_map> graphs = { {true, {}}, {false, {}}}; + unordered_flat_map graph_symbol; + + void _create(vector& data, int data_offset = 0) { + bool mult = (data.size() - data_offset > 1); + unordered_flat_map shifter; + unordered_flat_map result; + long long data_value = 0; + for (int horizon : iota(0, height)){ + long long cur_high = (height > 1) ? round(100.0 * (height - horizon) / height) : 100; + long long cur_low = (height > 1) ? round(100.0 * (height - (horizon + 1)) / height) : 0; + for (int i = data_offset; i < (int)data.size(); i++) { + if (mult) current = !current; + if (mult && i == data_offset) last = 0; + data_value = data[i]; + if (max_value > 0) data_value = clamp((data_value + offset) * 100 / max_value, 0ll, 100ll); + shifter = { {"left", last}, {"right", data_value} }; + for (auto [side, value] : shifter) { + if (value >= cur_high) + result[side] = 4; + else if (value <= cur_low) + result[side] = 0; + else { + if (height == 1) result[side] = round((float)value * 4 / 100 + 0.3); + else result[side] = round((float)(value - cur_low) * 4 / (cur_high - cur_low) + 0.1); + } + if (no_zero && horizon == height - 1 && result[side] == 0) result[side] = 1; + } + if (mult) last = data_value; + graphs[current][horizon] += graph_symbol[(float)result["left"] + (float)result["right"] / 10]; + } + } + last = data_value; + if (height == 1) + out = (last < 5 ? Theme::c("inactive_fg") : Theme::g(color_gradient)[last]) + graphs[current][0]; + else { + out.clear(); + for (int i : iota(0, height)) { + if (i > 0) out += Mv::d(1) + Mv::l(width); + out += (invert) ? Theme::g(color_gradient)[i * 100 / (height - 1)] : Theme::g(color_gradient)[100 - (i * 100 / (height - 1))]; + out += graphs[current][i]; + } + } + out += Fx::reset; + } + + public: + //* Set graph options and initialize with data + void operator()(int width, int height, string color_gradient, vector data, bool invert = false, bool no_zero = false, long long max_value = 0, long long offset = 0, bool data_same = true) { + graphs[true].clear(); graphs[false].clear(); + this->width = width; this->height = height; + this->invert = invert; this->offset = offset; + this->no_zero = no_zero; this->max_value = max_value; + this->color_gradient = color_gradient; + this->data_same = data_same; + if (height == 1) graph_symbol = (invert) ? Symbols::graph_down_small : Symbols::graph_up_small; + else graph_symbol = (invert) ? Symbols::graph_down : Symbols::graph_up; + if (no_zero) lowest = 1; + int value_width = ceil((float)data.size() / 2); + int data_offset = 0; + if (value_width > width) data_offset = data.size() - width * 2; + current = ((data.size() - data_offset) % 2 == 0); + + for (int i : iota(0, height)) { + (void) i; + graphs[true].push_back((value_width < width) ? graph_symbol[0.0] * (width - value_width) : ""); + graphs[false].push_back((value_width < width) ? graph_symbol[0.0] * (width - value_width) : ""); + } + if (data.size() == 0) return; + this->_create(data, data_offset); + } + + //* Add number of values from back of and return string representation of graph + string operator()(vector& data, int num = 1) { + if (data_same || data.size() == 0) {data_same = false; return out;} + current = !current; + for (int i : iota(0, height)) { + if (graphs[current][i].starts_with(graph_symbol[0.0])) graphs[current][i].erase(0, graph_symbol[0.0].size()); + else graphs[current][i].erase(0, 3); + } + this->_create(data, (int)data.size() - num); + return out; + } + + //* Return string representation of graph + string operator()() { + data_same = false; + return out; + } + }; + } namespace Box { diff --git a/src/btop_theme.h b/src/btop_theme.h index 92d4ffa..717867a 100644 --- a/src/btop_theme.h +++ b/src/btop_theme.h @@ -31,7 +31,7 @@ tab-size = 4 #include #include -using std::string, std::round, std::vector, robin_hood::unordered_flat_map, std::stoi, std::views::iota, std::array, std::clamp, std::max, std::min; +using std::string, std::round, std::vector, robin_hood::unordered_flat_map, std::stoi, std::views::iota, std::array, std::clamp, std::max, std::min, std::ceil; using namespace Tools; namespace Theme {