diff --git a/src/btop.cpp b/src/btop.cpp index 4c691bf..e2f5f41 100644 --- a/src/btop.cpp +++ b/src/btop.cpp @@ -464,7 +464,13 @@ int main(int argc, char **argv) { } //? Platform dependent init and error check - Shared::init(); + try { + Shared::init(); + } + catch (const std::exception& e) { + Global::exit_error_msg = "Exception in Shared::init() -> " + (string)e.what(); + clean_quit(1); + } //? Update list of available themes and generate the selected theme Theme::updateThemes(); @@ -561,19 +567,21 @@ int main(int argc, char **argv) { deque 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); - mydata.push_back(50); + // mydata.push_back(50); + auto mydata2 = mydata; + mydata2.push_back(10); + for (long long i = 0; i <= 100; i++) mydata2.push_back(i); + for (long long i = 100; i >= 0; i--) mydata2.push_back(i); + - Draw::Graph kgraph {}; - Draw::Graph kgraph2 {}; - Draw::Graph kgraph3 {}; cout << Draw::createBox(5, 10, Term::width - 10, 12, Theme::c("proc_box"), false, "braille", "", 1) << Mv::save; cout << Draw::createBox(5, 23, Term::width - 10, 12, Theme::c("proc_box"), false, "block", "", 2); cout << Draw::createBox(5, 36, Term::width - 10, 12, Theme::c("proc_box"), false, "tty", "", 3) << flush; auto kts = time_micros(); - kgraph(Term::width - 13, 10, "cpu", mydata, "braille", false, false); - kgraph2(Term::width - 13, 10, "cpu", mydata, "block", false, false); - kgraph3(Term::width - 13, 10, "cpu", mydata, "tty", false, false); + Draw::Graph kgraph {Term::width - 13, 10, "cpu", mydata, "block", false, false}; + Draw::Graph kgraph2 {Term::width - 13, 10, "upload", {0, 1}, "block", false, false}; + Draw::Graph kgraph3 {Term::width - 13, 10, "download", {}, "block", false, false}; cout << Mv::restore << kgraph(mydata, true) diff --git a/src/btop_config.cpp b/src/btop_config.cpp index 8c37fd4..a84cadc 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -240,22 +240,12 @@ namespace Config { vector current_boxes; - void set(string name, bool value) { - if (_locked(name)) boolsTmp.insert_or_assign(name, value); - else bools.at(name) = value; + void lock() { + writelock.wait(true); + locked = true; } - void set(string name, int value) { - if (_locked(name)) intsTmp.insert_or_assign(name, value); - ints.at(name) = value; - } - - void set(string name, string value) { - if (_locked(name)) stringsTmp.insert_or_assign(name, value); - else strings.at(name) = value; - } - - void flip(string name) { + void flip(const string& name) { if (_locked(name)) { if (boolsTmp.contains(name)) boolsTmp.at(name) = not boolsTmp.at(name); else boolsTmp.insert_or_assign(name, (not bools.at(name))); @@ -263,11 +253,6 @@ namespace Config { else bools.at(name) = not bools.at(name); } - void lock() { - writelock.wait(true); - locked = true; - } - void unlock() { if (not locked) return; writelock.wait(true); @@ -305,7 +290,7 @@ namespace Config { writelock.notify_all(); } - bool check_boxes(string boxes) { + bool check_boxes(const string& boxes) { auto new_boxes = ssplit(boxes); for (auto& box : new_boxes) { if (not v_contains(valid_boxes, box)) return false; @@ -314,7 +299,7 @@ namespace Config { return true; } - void load(fs::path conf_file, vector& load_errors) { + void load(const fs::path& conf_file, vector& load_errors) { if (conf_file.empty()) return; else if (not fs::exists(conf_file)) { diff --git a/src/btop_config.hpp b/src/btop_config.hpp index 2dadff5..46f56ab 100644 --- a/src/btop_config.hpp +++ b/src/btop_config.hpp @@ -32,15 +32,20 @@ namespace Config { extern std::filesystem::path conf_file; extern unordered_flat_map strings; + extern unordered_flat_map stringsTmp; extern unordered_flat_map bools; + extern unordered_flat_map boolsTmp; extern unordered_flat_map ints; + extern unordered_flat_map intsTmp; const vector valid_graph_symbols = { "braille", "block", "tty" }; extern vector current_boxes; //* Check if string only contains space seperated valid names for boxes - bool check_boxes(string boxes); + bool check_boxes(const string& boxes); + + bool _locked(const string& name); //* Return bool for config key inline const bool& getB(const string& name) { return bools.at(name); } @@ -52,16 +57,25 @@ namespace Config { inline const string& getS(const string& name) { return strings.at(name); } //* Set config key to bool - void set(string name, bool value); + inline void set(const string& name, const bool& value) { + if (_locked(name)) boolsTmp.insert_or_assign(name, value); + else bools.at(name) = value; + } //* Set config key to int - void set(string name, int value); + inline void set(const string& name, const int& value) { + if (_locked(name)) intsTmp.insert_or_assign(name, value); + ints.at(name) = value; + } //* Set config key to string - void set(string name, string value); + inline void set(const string& name, const string& value) { + if (_locked(name)) stringsTmp.insert_or_assign(name, value); + else strings.at(name) = value; + } //* Flip config key bool - void flip(string name); + void flip(const string& name); //* Lock config and cache changes until unlocked void lock(); @@ -70,8 +84,15 @@ namespace Config { void unlock(); //* Load the config file from disk - void load(std::filesystem::path conf_file, vector& load_errors); + void load(const std::filesystem::path& conf_file, vector& load_errors); //* Write the config file to disk void write(); -} \ No newline at end of file +} + + + + + + + diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index 532028e..058c7ff 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -47,6 +47,12 @@ namespace Symbols { const string div_up = "┬"; const string div_down = "┴"; + const string up = "↑"; + const string down = "↓"; + const string left = "←"; + const string right = "→"; + const string enter = "↲"; + const string meter = "■"; const array superscript = { "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" }; @@ -71,7 +77,7 @@ namespace Symbols { "▖", "▄", "▄", "▟", "▟", "▖", "▄", "▄", "▟", "▟", "▌", "▙", "▙", "█", "█", - "▌", "▙", "▙", "█", "█", + "▌", "▙", "▙", "█", "█" }}, {"block_down", { " ", "▝", "▝", "▐", "▐", @@ -100,50 +106,127 @@ namespace Symbols { namespace Draw { - string createBox(int x, int y, int width, int height, string line_color, bool fill, string title, string title2, int num) { - string out; - string lcolor = (line_color.empty()) ? Theme::c("div_line") : line_color; - string numbering = (num == 0) ? "" : Theme::c("hi_fg") + (Config::getB("tty_mode") ? std::to_string(num) : Symbols::superscript[num]); + TextEdit::TextEdit() {} + TextEdit::TextEdit(string text) : text(text) { + pos = this->text.size(); + upos = ulen(this->text); + } - out = Fx::reset + lcolor; + bool TextEdit::command(const string& key) { + if (key == "left" and upos > 0) { + upos--; + pos = uresize(text, upos).size(); + } + else if (key == "right" and pos < text.size()) { + upos++; + pos = uresize(text, upos).size(); + } + else if (key == "home" and pos > 0) { + pos = upos = 0; + } + else if (key == "end" and pos < text.size()) { + pos = text.size(); + upos = ulen(text); + } + else if (key == "backspace" and pos > 0) { + if (pos == text.size()) { + text = uresize(text, --upos); + pos = text.size(); + } + else { + const string first = uresize(text, --upos); + pos = first.size(); + text = first + text.substr(pos); + } + } + else if (key == "delete" and pos < text.size()) { + const string first = uresize(text, upos + 1); + text = uresize(first, ulen(first) - 1) + text.substr(first.size()); + } + else if (key == "space") { + text.insert(pos++, 1, ' '); + upos++; + } + else if (ulen(key) == 1) { + if (key.size() == 1) { + text.insert(pos++, 1, key[0]); + upos++; + } + else { + const string first = uresize(text, upos) + key; + text = first + text.substr(pos); + upos++; + pos = first.size(); + } + } + else + return false; + + return true; + } + + string TextEdit::operator()(const size_t limit) { + if (limit > 0 and ulen(text) + 1 > limit) { + try { + const size_t half = (size_t)round((double)limit / 2); + string first; + + if (upos + half > ulen(text)) + first = luresize(text.substr(0, pos), limit - (ulen(text) - upos)); + else if (upos - half < 1) + first = text.substr(0, pos); + else + first = luresize(text.substr(0, pos), half); + + return first + Fx::bl + "█" + Fx::ubl + uresize(text.substr(pos), limit - ulen(first)); + } + catch (const std::exception& e) { + Logger::error("In TextEdit::operator() : " + (string)e.what()); + } + } + return text.substr(0, pos) + Fx::bl + "█" + Fx::ubl + text.substr(pos); + } + + string createBox(const int x, const int y, const int width, const int height, string line_color, const bool fill, const string title, const string title2, const int num) { + string out; + if (line_color.empty()) line_color = Theme::c("div_line"); + const string numbering = (num == 0) ? "" : Theme::c("hi_fg") + (Config::getB("tty_mode") ? std::to_string(num) : Symbols::superscript[num]); + + out = Fx::reset + line_color; //? Draw horizontal lines - for (int hpos : {y, y + height - 1}) { + for (const int& hpos : {y, y + height - 1}) { out += Mv::to(hpos, x) + Symbols::h_line * (width - 1); } //? Draw vertical lines and fill if enabled - for (int hpos : iota(y + 1, y + height - 1)) { - out += Mv::to(hpos, x) + Symbols::v_line + - ((fill) ? string(width - 2, ' ') : Mv::r(width - 2)) + - Symbols::v_line; + for (const int& hpos : iota(y + 1, y + height - 1)) { + out += Mv::to(hpos, x) + Symbols::v_line + + ((fill) ? string(width - 2, ' ') : Mv::r(width - 2)) + + Symbols::v_line; } //? Draw corners - out += Mv::to(y, x) + Symbols::left_up + - Mv::to(y, x + width - 1) + Symbols::right_up + - Mv::to(y + height - 1, x) + Symbols::left_down + - Mv::to(y + height - 1, x + width - 1) + Symbols::right_down; + out += Mv::to(y, x) + Symbols::left_up + + Mv::to(y, x + width - 1) + Symbols::right_up + + Mv::to(y + height - 1, x) + Symbols::left_down + + Mv::to(y + height - 1, x + width - 1) + Symbols::right_down; //? Draw titles if defined if (not title.empty()) { - out += Mv::to(y, x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + title + - Fx::ub + lcolor + Symbols::title_right; + out += Mv::to(y, x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + title + + Fx::ub + line_color + Symbols::title_right; } if (not title2.empty()) { - out += Mv::to(y + height - 1, x + 2) + Symbols::title_left + Theme::c("title") + title2 + - Fx::ub + lcolor + Symbols::title_right; + out += Mv::to(y + height - 1, x + 2) + Symbols::title_left + Theme::c("title") + title2 + + Fx::ub + line_color + Symbols::title_right; } return out + Fx::reset + Mv::to(y + 1, x + 1); } //* Meter class ------------------------------------------------------------------------------------------------------------> - void Meter::operator()(int width, string color_gradient, bool invert) { - this->width = width; - this->color_gradient = color_gradient; - this->invert = invert; - cache.clear(); + Meter::Meter(const int width, const string& color_gradient, const bool invert) : width(width), color_gradient(color_gradient), invert(invert) { cache.insert(cache.begin(), 101, ""); } @@ -152,7 +235,7 @@ namespace Draw { value = clamp(value, 0, 100); if (not cache.at(value).empty()) return cache.at(value); string& out = cache.at(value); - for (int i : iota(1, width + 1)) { + for (const int& i : iota(1, width + 1)) { int y = round((double)i * 100.0 / width); if (value >= y) out += Theme::g(color_gradient)[invert ? 100 - y : y] + Symbols::meter; @@ -169,7 +252,7 @@ namespace Draw { void Graph::_create(const deque& data, int data_offset) { const bool mult = (data.size() - data_offset > 1); if (mult and (data.size() - data_offset) % 2 != 0) data_offset--; - auto& graph_symbol = Symbols::graph_symbols.at(symbol + '_' + (invert ? "down" : "up")); + const auto& graph_symbol = Symbols::graph_symbols.at(symbol + '_' + (invert ? "down" : "up")); array result; const float mod = (height == 1) ? 0.3 : 0.1; long long data_value = 0; @@ -187,12 +270,12 @@ namespace Draw { if (max_value > 0) data_value = clamp((data_value + offset) * 100 / max_value, 0ll, 100ll); //? Vertical iteration over height of graph - for (int horizon : iota(0, height)) { - int cur_high = (height > 1) ? round(100.0 * (height - horizon) / height) : 100; - int cur_low = (height > 1) ? round(100.0 * (height - (horizon + 1)) / height) : 0; - int clamp_min = (no_zero and horizon == height - 1 and i != -1) ? 1 : 0; + for (const int& horizon : iota(0, height)) { + const int cur_high = (height > 1) ? round(100.0 * (height - horizon) / height) : 100; + const int cur_low = (height > 1) ? round(100.0 * (height - (horizon + 1)) / height) : 0; + const int clamp_min = (no_zero and horizon == height - 1 and i != -1) ? 1 : 0; //? Calculate previous + current value to fit two values in 1 braille character - for (int ai = 0; auto value : {last, data_value}) { + for (int ai = 0; const auto& value : {last, data_value}) { if (value >= cur_high) result[ai++] = 4; else if (value <= cur_low) @@ -214,7 +297,7 @@ namespace Draw { out += graphs[current][0]; } else { - for (int i : iota(0, height)) { + for (const int& i : iota(0, height)) { if (i > 0) out += Mv::d(1) + Mv::l(width); if (not color_gradient.empty()) out += (invert) ? Theme::g(color_gradient)[i * 100 / (height - 1)] : Theme::g(color_gradient)[100 - (i * 100 / (height - 1))]; @@ -224,12 +307,10 @@ namespace Draw { if (not color_gradient.empty()) out += Fx::reset; } - void Graph::operator()(int width, int height, string color_gradient, const deque& data, string symbol, bool invert, bool no_zero, long long max_value, long long offset) { - graphs[true].clear(); graphs[false].clear(); - this->width = width; this->height = height; - this->invert = invert; this->offset = offset; - this->no_zero = no_zero; - this->color_gradient = color_gradient; + Graph::Graph() {}; + + Graph::Graph(int width, int height, const string& color_gradient, const deque& data, const string& symbol, bool invert, bool no_zero, long long max_value, long long offset) + : width(width), height(height), color_gradient(color_gradient), invert(invert), no_zero(no_zero), offset(offset) { if (Config::getB("tty_mode") or symbol == "tty") { tty_mode = true; this->symbol = "tty"; @@ -243,21 +324,22 @@ namespace Draw { if (value_width > width) data_offset = data.size() - width * 2; //? Populate the two switching graph vectors and fill empty space if data size < width - for (int i : iota(0, height * 2)) { + for (const int& i : iota(0, height * 2)) { + if (tty_mode and i % 2 != current) continue; graphs[(i % 2 != 0)].push_back((value_width < width) ? ((height == 1) ? Mv::r(1) : " "s) * (width - value_width) : ""); } if (data.size() == 0) return; - this->_create(data, data_offset); + this->_create((data.size() == 1 ? deque{0, data[0]} : data), data_offset); } - string& Graph::operator()(const deque& data, bool data_same) { + string& Graph::operator()(const deque& data, const bool data_same) { if (data_same) return out; //? Make room for new characters on graph - // bool select_graph = tty_mode ? current : not current; - for (int i : iota(0, height)) { - if (graphs[current][i][1] == '[') graphs[current][i].erase(0, 4); - else graphs[current][i].erase(0, 3); + bool select_graph = (tty_mode) ? current : not current; + for (const int& i : iota(0, height)) { + if (graphs[select_graph][i][1] == '[') graphs[select_graph][i].erase(0, 4); + else graphs[select_graph][i].erase(0, 3); } this->_create(data, (int)data.size() - 1); return out; @@ -345,6 +427,7 @@ namespace Proc { unordered_flat_map p_graphs; unordered_flat_map p_counters; int counter = 0; + Draw::TextEdit filter; string box; @@ -396,11 +479,9 @@ namespace Proc { } string draw(const vector& plist, const bool force_redraw, const bool data_same) { - auto& filter = Config::getS("proc_filter"); - auto& filtering = Config::getB("proc_filtering"); auto& proc_tree = Config::getB("proc_tree"); const bool show_detailed = (Config::getB("show_detailed") and Proc::detailed.last_pid == (size_t)Config::getI("detailed_pid")); - const bool proc_gradient = (Config::getB("proc_gradient") and not Config::getB("tty_mode")); + const bool proc_gradient = (Config::getB("proc_gradient") and not Config::getB("tty_mode") and not Config::getB("lowcolor")); auto& proc_colors = Config::getB("proc_colors"); const auto& graph_symbol = (Config::getB("tty_mode") ? "tty" : Config::getS("graph_symbol_proc")); const auto& graph_bg = Symbols::graph_symbols.at((graph_symbol == "default" ? "braille_up" : graph_symbol + "_up"))[1]; @@ -417,11 +498,48 @@ namespace Proc { out = box; const string title_left = Theme::c("proc_box") + Symbols::title_left; const string title_right = Theme::c("proc_box") + Symbols::title_right; - //? Buttons etc. in box titlebar - out += Mv::to(y, x) + Mv::r(12) - + trans("Filter: " + filter + (filtering ? Fx::bl + "█"s + Fx::reset : " ")) - + trans(rjust("Per core: " + (Config::getB("proc_per_core") ? "On "s : "Off"s) + " Sorting: " - + string(Config::getS("proc_sorting")), width - 23 - ulen(filter))); + const auto& filtering = Config::getB("proc_filtering"); // ? filter(20) : Config::getS("proc_filter")) + const auto filter_text = (filtering) ? filter(max(6, width - 58)) : uresize(Config::getS("proc_filter"), max(6, width - 58)); + + //? Filter + out += Mv::to(y, x+9) + title_left + (not filter_text.empty() ? Fx::b : "") + Theme::c("hi_fg") + 'f' + + Theme::c("title") + (not filter_text.empty() ? ' ' + filter_text : "ilter") + + (not filtering and not filter_text.empty() ? Theme::c("hi_fg") + " del" : "") + + (filtering ? Theme::c("hi_fg") + ' ' + Symbols::enter : "") + Fx::ub + title_right; + if (not filtering) { + int f_len = (filter_text.empty() ? 6 : ulen(filter_text) + 2); + Input::mouse_mappings["f"] = {y, x + 10, 1, f_len}; + if (filter_text.empty() and Input::mouse_mappings.contains("delete")) + Input::mouse_mappings.erase("delete"); + else if (not filter_text.empty()) + Input::mouse_mappings["delete"] = {y, x + 11 + f_len, 1, 3}; + } + + //? per-core, reverse, tree and sorting + const auto& sorting = Config::getS("proc_sorting"); + const int sort_len = sorting.size(); + const int sort_pos = x + width - sort_len - 8; + + if (width > 55 + sort_len) { + out += Mv::to(y, sort_pos - 25) + title_left + (Config::getB("proc_per_core") ? Fx::b : "") + Theme::c("title") + + "per-" + Theme::c("hi_fg") + 'c' + Theme::c("title") + "ore" + Fx::ub + title_right; + } + if (width > 45 + sort_len) { + out += Mv::to(y, sort_pos - 15) + title_left + (Config::getB("proc_reversed") ? Fx::b : "") + Theme::c("hi_fg") + + 'r' + Theme::c("title") + "everse" + Fx::ub + title_right; + } + if (width > 35 + sort_len) { + out += Mv::to(y, sort_pos - 6) + title_left + (Config::getB("proc_tree") ? Fx::b : "") + Theme::c("title") + "tre" + + Theme::c("hi_fg") + 'e' + Fx::ub + title_right; + } + out += Mv::to(y, sort_pos) + title_left + Fx::b + Theme::c("hi_fg") + "< " + Theme::c("title") + sorting + Theme::c("hi_fg") + + " >" + Fx::ub + title_right; + + + // out += Mv::to(y, x) + Mv::r(12) + // + trans("Filter: " + filter_text) + // + trans(rjust("Per core: " + (Config::getB("proc_per_core") ? "On "s : "Off"s) + " Sorting: " + // + string(Config::getS("proc_sorting")), width - 23 - ulen(filter_text))); //? Labels for fields in list if (not proc_tree) @@ -436,8 +554,6 @@ namespace Proc { out += Mv::to(y+1, x+1) + Theme::c("title") + Fx::b + ljust("Tree:", width - 40) + "Threads: " + ljust("User:", 10) + " " + rjust("MemB", 5) + " " + rjust("Cpu%", 10) + Fx::ub; - - Input::mouse_mappings["down"] = {2, 2, 10, 10}; } //* Check bounds of current selection and view @@ -460,7 +576,7 @@ namespace Proc { //? Update graphs for processes with above 0.0% cpu usage, delete if below 0.1% 10x times if (not data_same and (p.cpu_p > 0 or p_counters.contains(p.pid))) { if (not p_graphs.contains(p.pid)) { - p_graphs[p.pid](5, 1, "", {0}, graph_symbol); + p_graphs[p.pid] = {5, 1, "", {}, graph_symbol}; p_counters[p.pid] = 0; } else if (p.cpu_p < 0.1) { diff --git a/src/btop_draw.hpp b/src/btop_draw.hpp index 2f0b918..0c5d2be 100644 --- a/src/btop_draw.hpp +++ b/src/btop_draw.hpp @@ -27,18 +27,29 @@ using std::string, std::vector, robin_hood::unordered_flat_map, std::deque; namespace Draw { + //* An editable text field + class TextEdit { + size_t pos = 0; + size_t upos = 0; + public: + string text; + TextEdit(); + TextEdit(string text); + bool command(const string& key); + string operator()(const size_t limit=0); + }; + //* Create a box and return as a string - string createBox(int x, int y, int width, int height, string line_color="", bool fill=false, string title="", string title2="", int num=0); + string createBox(const int x, const int y, const int width, const int height, string line_color="", const bool fill=false, const string title="", const string title2="", const int num=0); //* Class holding a percentage meter class Meter { - string color_gradient; - int width = 0; - bool invert = false; + const int width; + const string color_gradient; + const bool invert; vector cache; public: - //* Set meter options - void operator()(int width, string color_gradient, bool invert = false); + Meter(const int width, const string& color_gradient, const bool invert = false); //* Return a string representation of the meter with given value string operator()(int value); @@ -46,21 +57,32 @@ namespace Draw { //* Class holding a percentage graph class Graph { - string out, color_gradient, symbol = "default"; - int width = 0, height = 0; - long long last = 0, max_value = 0, offset = 0; - bool current = true, no_zero = false, invert = false, tty_mode = false; + int width, height; + string color_gradient; + string out, symbol = "default"; + bool invert, no_zero; + long long offset; + long long last = 0, max_value = 0; + bool current = true, tty_mode = false; unordered_flat_map> graphs = { {true, {}}, {false, {}}}; //* Create two representations of the graph to switch between to represent two values for each braille character void _create(const deque& data, int data_offset); public: - //* Set graph options and initialize with data - void operator()(int width, int height, string color_gradient, const deque& data, string symbol="default", bool invert=false, bool no_zero=false, long long max_value=0, long long offset=0); + Graph(); + Graph( int width, + int height, + const string& color_gradient, + const deque& data, + const string& symbol="default", + bool invert=false, + bool no_zero=false, + long long max_value=0, + long long offset=0); //* Add last value from back of and return string representation of graph - string& operator()(const deque& data, bool data_same=false); + string& operator()(const deque& data, const bool data_same=false); //* Return string representation of graph string& operator()(); @@ -69,4 +91,8 @@ namespace Draw { //* Calculate sizes of boxes, draw outlines and save to enabled boxes namespaces void calcSizes(); +} + +namespace Proc { + extern Draw::TextEdit filter; } \ No newline at end of file diff --git a/src/btop_input.cpp b/src/btop_input.cpp index c803a7e..49708ec 100644 --- a/src/btop_input.cpp +++ b/src/btop_input.cpp @@ -23,6 +23,7 @@ tab-size = 4 #include #include #include +#include using std::cin, std::string_literals::operator""s; using namespace Tools; @@ -72,6 +73,7 @@ namespace Input { unordered_flat_map mouse_mappings; string last = ""; + string old_filter; bool poll(int timeout) { if (timeout < 1) return cin.rdbuf()->in_avail() > 0; @@ -116,6 +118,12 @@ namespace Input { else key.clear(); + if (Config::getB("proc_filtering")) { + if (mouse_event == "mouse_click") last = mouse_event; + else last.clear(); + return last; + } + //? Get column and line position of mouse and check for any actions mapped to current position if (not key.empty()) { try { @@ -175,23 +183,24 @@ namespace Input { if (Proc::shown) { bool keep_going = false; if (filtering) { - string filter = Config::getS("proc_filter"); - if (key == "enter") + if (key == "enter") { + Config::set("proc_filter", Proc::filter.text); Config::set("proc_filtering", false); - - else if (key == "backspace" and not filter.empty()) - filter = uresize(filter, ulen(filter) - 1); - - else if (key == "space") - filter.push_back(' '); - - else if (ulen(key) == 1) - filter.append(key); - + old_filter.clear(); + } + else if (key == "escape" or key == "mouse_click") { + Config::set("proc_filter", old_filter); + Config::set("proc_filtering", false); + old_filter.clear(); + } + else if (Proc::filter.command(key)) { + if (Config::getS("proc_filter") != Proc::filter.text) + Config::set("proc_filter", Proc::filter.text); + else + recollect = false; + } else return; - - Config::set("proc_filter", filter); } else if (key == "left") { int cur_i = v_index(Proc::sort_vector, Config::getS("proc_sorting")); @@ -207,6 +216,8 @@ namespace Input { } else if (key == "f") { Config::flip("proc_filtering"); + Proc::filter = { Config::getS("proc_filter") }; + old_filter = Proc::filter.text; recollect = false; } else if (key == "t") diff --git a/src/btop_input.hpp b/src/btop_input.hpp index bbfa9c5..03ae976 100644 --- a/src/btop_input.hpp +++ b/src/btop_input.hpp @@ -34,9 +34,10 @@ using robin_hood::unordered_flat_map, std::array, std::string, std::atomic; namespace Input { struct Mouse_loc { - int col, line, width, height; + int line, col, height, width; }; + //? line, col, height, width extern unordered_flat_map mouse_mappings; extern atomic interrupt; diff --git a/src/btop_linux.cpp b/src/btop_linux.cpp index 3ee47e4..cd37023 100644 --- a/src/btop_linux.cpp +++ b/src/btop_linux.cpp @@ -56,13 +56,12 @@ namespace Shared { void init() { proc_path = (fs::is_directory(fs::path("/proc")) and access("/proc", R_OK) != -1) ? "/proc" : ""; - if (proc_path.empty()) { - Global::exit_error_msg = "Proc filesystem not found or no permission to read from it!"; - clean_quit(1); - } + if (proc_path.empty()) + throw std::runtime_error("Proc filesystem not found or no permission to read from it!"); - passwd_path = (access("/etc/passwd", R_OK) != -1) ? fs::path("/etc/passwd") : passwd_path; - if (passwd_path.empty()) Logger::warning("Could not read /etc/passwd, will show UID instead of username."); + passwd_path = (fs::is_regular_file(fs::path("/etc/passwd")) and access("/etc/passwd", R_OK) != -1) ? "/etc/passwd" : ""; + if (passwd_path.empty()) + Logger::warning("Could not read /etc/passwd, will show UID instead of username."); page_size = sysconf(_SC_PAGE_SIZE); if (page_size <= 0) { diff --git a/src/btop_shared.hpp b/src/btop_shared.hpp index 391768c..c4026e8 100644 --- a/src/btop_shared.hpp +++ b/src/btop_shared.hpp @@ -62,6 +62,7 @@ namespace Shared { void init(); } + namespace Cpu { extern string box, cpuName; extern int x, y, width, height; diff --git a/src/btop_theme.cpp b/src/btop_theme.cpp index 357abd7..6ec3a06 100644 --- a/src/btop_theme.cpp +++ b/src/btop_theme.cpp @@ -48,24 +48,24 @@ namespace Theme { { "main_bg", "#00" }, { "main_fg", "#cc" }, { "title", "#ee" }, - { "hi_fg", "#969696" }, - { "selected_bg", "#7e2626" }, + { "hi_fg", "#b54040" }, + { "selected_bg", "#6a2f2f" }, { "selected_fg", "#ee" }, { "inactive_fg", "#40" }, { "graph_text", "#60" }, { "meter_bg", "#40" }, { "proc_misc", "#0de756" }, - { "cpu_box", "#3d7b46" }, - { "mem_box", "#8a882e" }, - { "net_box", "#423ba5" }, - { "proc_box", "#923535" }, + { "cpu_box", "#556d59" }, + { "mem_box", "#6c6c4b" }, + { "net_box", "#5c588d" }, + { "proc_box", "#805252" }, { "div_line", "#30" }, { "temp_start", "#4897d4" }, { "temp_mid", "#5474e8" }, { "temp_end", "#ff40b6" }, - { "cpu_start", "#50f095" }, - { "cpu_mid", "#f2e266" }, - { "cpu_end", "#fa1e1e" }, + { "cpu_start", "#77ca9b" }, + { "cpu_mid", "#cbc06c" }, + { "cpu_end", "#dc4c4c" }, { "free_start", "#223014" }, { "free_mid", "#b5e685" }, { "free_end", "#dcff85" }, @@ -93,7 +93,7 @@ namespace Theme { { "main_bg", "\x1b[0;40m" }, { "main_fg", "\x1b[37m" }, { "title", "\x1b[97m" }, - { "hi_fg", "\x1b[31m" }, + { "hi_fg", "\x1b[91m" }, { "selected_bg", "\x1b[41m" }, { "selected_fg", "\x1b[97m" }, { "inactive_fg", "\x1b[90m" }, @@ -138,7 +138,7 @@ namespace Theme { //* Convert 24-bit colors to 256 colors int truecolor_to_256(const int& r, const int& g, const int& b) { //? Use upper 232-255 greyscale values if the downscaled red, green and blue are the same value - if (int red = round((double)r / 11); red == round((double)g / 11) and round((double)g / 11) == round((double)b / 11)) { + if (const int red = round((double)r / 11); red == round((double)g / 11) and red == round((double)b / 11)) { return 232 + red; } //? Else use 6x6x6 color cube to calculate approximate colors diff --git a/src/btop_tools.cpp b/src/btop_tools.cpp index f9af57f..96914f9 100644 --- a/src/btop_tools.cpp +++ b/src/btop_tools.cpp @@ -114,7 +114,7 @@ namespace Term { namespace Tools { string uresize(string str, const size_t len) { - if (len < 1) return ""; + if (len < 1 or str.empty()) return ""; for (size_t x = 0, i = 0; i < str.size(); i++) { if ((static_cast(str.at(i)) & 0xC0) != 0x80) x++; if (x == len + 1) { @@ -126,6 +126,22 @@ namespace Tools { return str; } + string luresize(string str, const size_t len) { + if (len < 1 or str.empty()) return ""; + for (size_t x = 0, last_pos = 0, i = str.size() - 1; i > 0 ; i--) { + if ((static_cast(str.at(i)) & 0xC0) != 0x80) { + x++; + last_pos = i; + } + if (x == len) { + str = str.substr(last_pos); + str.shrink_to_fit(); + break; + } + } + return str; + } + string ltrim(const string& str, const string& t_str) { string_view str_v = str; while (str_v.starts_with(t_str)) str_v.remove_prefix(t_str.size()); diff --git a/src/btop_tools.hpp b/src/btop_tools.hpp index bcdecac..115c92f 100644 --- a/src/btop_tools.hpp +++ b/src/btop_tools.hpp @@ -133,6 +133,9 @@ namespace Tools { //* Resize a string consisting of UTF8 characters (only reduces size) string uresize(const string str, const size_t len); + //* Resize a string consisting of UTF8 characters from left (only reduces size) + string luresize(const string str, const size_t len); + //* Return with only uppercase characters inline string str_to_upper(string str) { std::ranges::for_each(str, [](auto& c) { c = ::toupper(c); } ); diff --git a/themes/default.theme-sample b/themes/old-default.theme similarity index 100% rename from themes/default.theme-sample rename to themes/old-default.theme