diff --git a/src/btop.cpp b/src/btop.cpp index 9cf1864..e2ae832 100644 --- a/src/btop.cpp +++ b/src/btop.cpp @@ -219,14 +219,9 @@ void banner_gen() { + Fx::i + "v" + Global::Version + Fx::ui; } -//* Threading test function -// string my_worker(int x){ -// for (int i = 0; i < 100 + (x * 100); i++){ -// sleep_ms(10); -// if (Global::stop_all.load()) return "Thread stopped! x=" + to_string(x); -// } -// return "Thread done! x=" + to_string(x); -// } +namespace Runner { + atomic active (false); +} //? --------------------------------------------- Main starts here! --------------------------------------------------- @@ -351,23 +346,33 @@ int main(int argc, char **argv){ Global::debuginit = true; + Draw::calcSizes(); + // cout << Cpu::box << Mem::box << Net::box << Proc::box << flush; + // cout << Theme("main_bg") << Term::clear << flush; // bool thread_test = false; - if (not Global::debuginit) cout << Term::alt_screen << Term::hide_cursor << flush; + if (not Global::debuginit) cout << Term::alt_screen << Term::hide_cursor << Term::clear << endl; - cout << Theme::c("main_fg") << Theme::c("main_bg") << Term::clear << endl; + // cout << Theme::c("main_fg") << Theme::c("main_bg") << Term::clear << endl; - cout << Mv::r(Term::width / 2 - Global::banner_width / 2) << Global::banner << endl; - // cout << string(Term::width - 1, '-') << endl; - size_t blen = (Term::width > 200) ? 200 : Term::width; - if (Term::width > 203) cout << Mv::r(Term::width / 2 - blen / 2) << flush; - int ill = 0; - for (int i : iota(0, (int)blen)){ - ill = (i <= (int)blen / 2) ? i : ill - 1; - cout << Theme::g("used")[ill] << Symbols::h_line; + // cout << Mv::r(Term::width / 2 - Global::banner_width / 2) << Global::banner << endl; + // // cout << string(Term::width - 1, '-') << endl; + // size_t blen = (Term::width > 200) ? 200 : Term::width; + // if (Term::width > 203) cout << Mv::r(Term::width / 2 - blen / 2) << flush; + // int ill = 0; + // for (int i : iota(0, (int)blen)){ + // ill = (i <= (int)blen / 2) ? i : ill - 1; + // cout << Theme::g("used")[ill] << Symbols::h_line; + // } + // cout << Fx::reset << endl; + + if (false) { + Draw::calcSizes(); + cout << Cpu::box << Mem::box << Net::box << Proc::box << flush; + Input::wait(); + exit(0); } - cout << Fx::reset << endl; //* Test theme if (false) { @@ -479,9 +484,9 @@ int main(int argc, char **argv){ Draw::Graph kgraph2 {}; Draw::Graph kgraph3 {}; - cout << Draw::createBox({.x = 5, .y = 10, .width = Term::width - 10, .height = 12, .line_color = Theme::c("proc_box"), .title = "braille", .fill = false, .num = 1}) << Mv::save; - cout << Draw::createBox({.x = 5, .y = 23, .width = Term::width - 10, .height = 12, .line_color = Theme::c("proc_box"), .title = "block", .fill = false, .num = 2}); - cout << Draw::createBox({.x = 5, .y = 36, .width = Term::width - 10, .height = 12, .line_color = Theme::c("proc_box"), .title = "tty", .fill = false, .num = 3}) << flush; + 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; // Draw::Meter kmeter {}; // Draw::Graph kgraph2 {}; // Draw::Graph kgraph3 {}; @@ -595,12 +600,10 @@ int main(int argc, char **argv){ - size_t lc; string ostring; uint64_t tsl, timestamp2, rcount = 0; list avgtimes; size_t timer = 2000; - bool filtering = false; vector greyscale; string filter; string filter_cur; @@ -613,9 +616,9 @@ int main(int argc, char **argv){ greyscale.push_back(Theme::dec_to_color(xc, xc, xc)); } - string pbox = Draw::createBox({.x = 1, .y = 10, .width = Term::width, .height = Term::height - 18, .line_color = Theme::c("proc_box"), .title = "testbox", .title2 = "below", .fill = false, .num = 7}); - pbox += Mv::r(1) + Theme::c("title") + Fx::b + rjust("Pid:", 8) + " " + ljust("Program:", 16) + " " + ljust("Command:", Term::width - 70) + " Threads: " + - ljust("User:", 10) + " " + rjust("MemB", 5) + " " + rjust("Cpu%", 14) + "\n" + Fx::reset + Mv::save; + // string pbox = Draw::createBox(1, 10, Term::width, Term::height - 18, Theme::c("proc_box"), false, "testbox", "below", 7); + // pbox += Mv::r(1) + Theme::c("title") + Fx::b + rjust("Pid:", 8) + " " + ljust("Program:", 16) + " " + ljust("Command:", Term::width - 70) + " Threads: " + + // ljust("User:", 10) + " " + rjust("MemB", 5) + " " + rjust("Cpu%", 14) + "\n" + Fx::reset + Mv::save; while (key != "q") { timestamp = time_micros(); @@ -630,62 +633,62 @@ int main(int argc, char **argv){ timestamp2 = time_micros(); timestamp = timestamp2 - timestamp; ostring.clear(); - lc = 0; + // lc = 0; - ostring = Mv::u(2) + Mv::l(Term::width) + Mv::r(12) - + trans("Filter: " + filter + (filtering ? Fx::bl + "█" + Fx::reset : " ")) - + trans(rjust("Per core: " + (Config::getB("proc_per_core") ? "On "s : "Off"s) + " Sorting: " - + string(Config::getS("proc_sorting")), Term::width - 23 - ulen(filter))) - + Mv::restore; + // ostring = Mv::u(2) + Mv::l(Term::width) + Mv::r(12) + // + trans("Filter: " + filter + (filtering ? Fx::bl + "█" + Fx::reset : " ")) + // + trans(rjust("Per core: " + (Config::getB("proc_per_core") ? "On "s : "Off"s) + " Sorting: " + // + string(Config::getS("proc_sorting")), Term::width - 23 - ulen(filter))) + // + Mv::restore; - for (auto& p : plist){ - if (not Config::getB("proc_tree")) { - ostring += Mv::r(1) + greyscale[lc] + rjust(to_string(p.pid), 8) + " " + ljust(p.name, 16) + " " + ljust(p.cmd, Term::width - 66, true) + " " - + rjust(to_string(p.threads), 5) + " " + ljust(p.user, 10) + " " + rjust(floating_humanizer(p.mem, true), 5) + string(11, ' ') - + (p.cpu_p < 10 or p.cpu_p >= 100 ? rjust(to_string(p.cpu_p), 3) + " " : rjust(to_string(p.cpu_p), 4)) - + "\n"; - } - else { - string cmd_cond; - if (not p.cmd.empty()) { - cmd_cond = p.cmd.substr(0, std::min(p.cmd.find(' '), p.cmd.size())); - cmd_cond = cmd_cond.substr(std::min(cmd_cond.find_last_of('/') + 1, cmd_cond.size())); - } - ostring += Mv::r(1) + (Config::getB("tty_mode") ? "" : greyscale[lc]) + ljust(p.prefix + to_string(p.pid) + " " + p.name + " " - + (not cmd_cond.empty() and cmd_cond != p.name ? "(" + cmd_cond + ")" : ""), Term::width - 40, true) + " " - + rjust(to_string(p.threads), 5) + " " + ljust(p.user, 10) + " " + rjust(floating_humanizer(p.mem, true), 5) + string(11, ' ') - + (p.cpu_p < 10 or p.cpu_p >= 100 ? rjust(to_string(p.cpu_p), 3) + " " : rjust(to_string(p.cpu_p), 4)) - + "\n"; - } - if (lc++ > Term::height - 23) break; - } - - while (lc++ < Term::height - 21) ostring += Mv::r(1) + string(Term::width - 2, ' ') + "\n"; + // for (auto& p : plist){ + // if (not Config::getB("proc_tree")) { + // ostring += Mv::r(1) + greyscale[lc] + rjust(to_string(p.pid), 8) + " " + ljust(p.name, 16) + " " + ljust(p.cmd, Term::width - 66, true) + " " + // + rjust(to_string(p.threads), 5) + " " + ljust(p.user, 10) + " " + rjust(floating_humanizer(p.mem, true), 5) + string(11, ' ') + // + (p.cpu_p < 10 or p.cpu_p >= 100 ? rjust(to_string(p.cpu_p), 3) + " " : rjust(to_string(p.cpu_p), 4)) + // + "\n"; + // } + // else { + // string cmd_cond; + // if (not p.cmd.empty()) { + // cmd_cond = p.cmd.substr(0, std::min(p.cmd.find(' '), p.cmd.size())); + // cmd_cond = cmd_cond.substr(std::min(cmd_cond.find_last_of('/') + 1, cmd_cond.size())); + // } + // ostring += Mv::r(1) + (Config::getB("tty_mode") ? "" : greyscale[lc]) + ljust(p.prefix + to_string(p.pid) + " " + p.name + " " + // + (not cmd_cond.empty() and cmd_cond != p.name ? "(" + cmd_cond + ")" : ""), Term::width - 40, true) + " " + // + rjust(to_string(p.threads), 5) + " " + ljust(p.user, 10) + " " + rjust(floating_humanizer(p.mem, true), 5) + string(11, ' ') + // + (p.cpu_p < 10 or p.cpu_p >= 100 ? rjust(to_string(p.cpu_p), 3) + " " : rjust(to_string(p.cpu_p), 4)) + // + "\n"; + // } + // if (lc++ > Term::height - 23) break; + // } + // while (lc++ < Term::height - 21) ostring += Mv::r(1) + string(Term::width - 2, ' ') + "\n"; + ostring = Proc::draw(plist); avgtimes.push_front(timestamp); if (avgtimes.size() > 30) avgtimes.pop_back(); - cout << pbox << ostring << Fx::reset << "\n" << endl; + cout << ostring << Fx::reset << Mv::to(2, 2) << endl; cout << " Details for " << Proc::detailed.entry.name << " (" << Proc::detailed.entry.pid << ") Status: " << Proc::detailed.status << " Elapsed: " << Proc::detailed.elapsed << " Mem: " << floating_humanizer(Proc::detailed.entry.mem) << " " << "\n Parent: " << Proc::detailed.parent << " IO in/out: " << Proc::detailed.io_read << "/" << Proc::detailed.io_write << " " << endl; - cout << Mv::to(Term::height - 4, 1) << "Processes call took: " << rjust(to_string(timestamp), 5) << " μs. Average: " << + cout << Mv::to(4, 2) << "Processes call took: " << rjust(to_string(timestamp), 5) << " μs. Average: " << rjust(to_string(accumulate(avgtimes.begin(), avgtimes.end(), 0) / avgtimes.size()), 5) << " μs of " << avgtimes.size() << - " samples. Drawing took: " << time_micros() - timestamp2 << " μs.\nNumber of processes: " << Proc::numpids << ". Number in vector: " << plist.size() << ". Run count: " << - ++rcount << ". Time: " << strf_time("%X ") << endl; + " samples. Drawing took: " << time_micros() - timestamp2 << " μs.\nNumber of processes: " << Proc::numpids << ". Number in vector: " << plist.size() << ". Run count: " << ++rcount << ". Time: " << strf_time("%X ") << endl; while (time_ms() < tsl) { if (Input::poll(tsl - time_ms())) key = Input::get(); else { key.clear() ; continue; } - if (filtering) { - if (key == "enter") filtering = false; + if (Config::getB("proc_filtering")) { + if (key == "enter") 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); else { key.clear(); continue; } if (filter != Config::getS("proc_filter")) Config::set("proc_filter", filter); key.clear(); + Proc::redraw = true; break; } else if (key == "q") break; @@ -699,7 +702,7 @@ int main(int argc, char **argv){ if (++cur_i > (int)Proc::sort_vector.size() - 1) cur_i = 0; Config::set("proc_sorting", Proc::sort_vector.at(cur_i)); } - else if (key == "f") filtering = true; + else if (key == "f") Config::flip("proc_filtering"); else if (key == "t") Config::flip("proc_tree"); else if (key == "r") Config::flip("proc_reversed"); else if (key == "c") Config::flip("proc_per_core"); @@ -711,8 +714,10 @@ int main(int argc, char **argv){ } } else continue; + Proc::redraw = true; break; } + cout << Mv::to(Term::height - 3, 1) << flush; } // cout << "Found " << plist.size() << " pids\n" << endl; diff --git a/src/btop_config.cpp b/src/btop_config.cpp index 30ec4c8..dc655a9 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -212,6 +212,7 @@ namespace Config { {"force_tty", false}, {"lowcolor", false}, {"show_detailed", false}, + {"proc_filtering", false}, }; unordered_flat_map boolsTmp; @@ -278,6 +279,7 @@ namespace Config { void unlock(){ if (not locked) return; + atomic_wait(Runner::active); atomic_wait_set(writelock); for (auto& item : stringsTmp){ diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index 2f1cb9c..f489ad1 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -29,9 +29,11 @@ tab-size = 4 #include -using std::round, std::views::iota, std::string_literals::operator""s, std::clamp, std::array, std::floor; +using std::round, std::views::iota, std::string_literals::operator""s, std::clamp, std::array, std::floor, std::max, std::min, + std::to_string; namespace rng = std::ranges; +using namespace Tools; namespace Symbols { const string h_line = "─"; @@ -98,44 +100,42 @@ namespace Symbols { namespace Draw { - using namespace Tools; - - string createBox(BoxConf c){ + 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 = (c.line_color.empty()) ? Theme::c("div_line") : c.line_color; - string numbering = (c.num == 0) ? "" : Theme::c("hi_fg") + (Config::getB("tty_mode") ? std::to_string(c.num) : Symbols::superscript[c.num]); + 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]); out = Fx::reset + lcolor; //? Draw horizontal lines - for (size_t hpos : {c.y, c.y + c.height - 1}){ - out += Mv::to(hpos, c.x) + Symbols::h_line * (c.width - 1); + for (int hpos : {y, y + height - 1}){ + out += Mv::to(hpos, x) + Symbols::h_line * (width - 1); } //? Draw vertical lines and fill if enabled - for (size_t 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)) + + 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; } //? 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; + 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 c.title.empty()){ - out += Mv::to(c.y, c.x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + c.title + + 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; } - if (not c.title2.empty()){ - out += Mv::to(c.y + c.height - 1, c.x + 2) + Symbols::title_left + Theme::c("title") + c.title2 + + 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; } - return out + Fx::reset + Mv::to(c.y + 1, c.x + 1); + return out + Fx::reset + Mv::to(y + 1, x + 1); } //* Meter class ------------------------------------------------------------------------------------------------------------> @@ -264,36 +264,258 @@ namespace Draw { } //*-------------------------------------------------------------------------------------------------------------------------> - void calcSizes(){ - - } - } namespace Cpu { - Draw::BoxConf box; - string background; + int width_p = 100, height_p = 32; + int min_w = 60, min_h = 8; + int x = 1, y = 1, width, height; + int b_columns, b_column_size; + int b_x, b_y, b_width, b_height; + bool shown = true, redraw = true; + string box; } namespace Mem { - Draw::BoxConf box; - string background; + int width_p = 45, height_p = 38; + int min_w = 36, min_h = 10; + int x = 1, y, width, height; + int mem_width, disks_width, divider, item_height, mem_size, mem_meter, graph_height, disk_meter; + bool shown = true, redraw = true; + string box; } namespace Net { - Draw::BoxConf box; - string background; + int width_p = 45, height_p = 30; + int min_w = 3, min_h = 6; + int x = 1, y, width, height; + int b_x, b_y, b_width, b_height, d_graph_height, u_graph_height; + int graph_height; + bool shown = true, redraw = true; + string box; } namespace Proc { - Draw::BoxConf box; - string background; + int width_p = 55, height_p = 68; + int min_w = 44, min_h = 16; + int x, y, width, height; + int current_y, current_h, select_max; + bool shown = true, redraw = true; + string box; + vector greyscale; + vector colorfade; + + string draw(vector plist){ + auto& filter = Config::getS("proc_filter"); + auto& filtering = Config::getB("proc_filtering"); + auto& proc_tree = Config::getB("proc_tree"); + bool proc_gradient = (Config::getB("proc_gradient") and not Config::getB("tty_mode")); + string out; + if (redraw) { + redraw = false; + out = box; + greyscale.clear(); + for (int xc = 0; size_t i : iota(0, height - 3)){ + xc = 230 - i * 150 / (Term::height - 20); + greyscale.push_back(Theme::dec_to_color(xc, xc, xc)); + } + out += Mv::to(y, x) + Mv::r(12) + + trans("Filter: " + filter + (filtering ? Fx::bl + "█" + 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))); + } + + if (not proc_tree) + out += Mv::to(y+1, x+1) + Theme::c("title") + Fx::b + rjust("Pid:", 8) + " " + ljust("Program:", 16) + " " + + ljust("Command:", width - 70) + " Threads: " + ljust("User:", 10) + " " + rjust("MemB", 5) + + " " + rjust("Cpu%", 14) + Fx::ub; + else + out += Mv::to(y+1, x+1) + Theme::c("title") + Fx::b + rjust("Pid:", 8) + " " + ljust("Program:", 16) + " " + + ljust("Command:", width - 70) + " Threads: " + ljust("User:", 10) + " " + rjust("MemB", 5) + + " " + rjust("Cpu%", 14) + Fx::ub; + + int lc = 0; + for (auto& p : plist){ + if (not proc_tree) { + out += Mv::to(y+2+lc, x+1) + (proc_gradient ? greyscale[lc] : "") + rjust(to_string(p.pid), 8) + " " + ljust(p.name, 16) + " " + + ljust(p.cmd, width - 67, true) + " " + rjust(to_string(p.threads), 5) + " " + ljust(p.user, 10) + " " + + rjust(floating_humanizer(p.mem, true), 5) + string(11, ' ') + + (p.cpu_p < 10 or p.cpu_p >= 100 ? rjust(to_string(p.cpu_p), 3) + " " : rjust(to_string(p.cpu_p), 4)); + } + else { + string cmd_cond; + if (not p.cmd.empty()) { + cmd_cond = p.cmd.substr(0, min(p.cmd.find(' '), p.cmd.size())); + cmd_cond = cmd_cond.substr(min(cmd_cond.find_last_of('/') + 1, cmd_cond.size())); + } + out += Mv::to(y+2+lc, x+1) + (proc_gradient ? greyscale[lc] : "") + ljust(p.prefix + to_string(p.pid) + " " + p.name + " " + + (not cmd_cond.empty() and cmd_cond != p.name ? "(" + cmd_cond + ")" : ""), width - 41, true) + " " + + rjust(to_string(p.threads), 5) + " " + ljust(p.user, 10) + " " + rjust(floating_humanizer(p.mem, true), 5) + string(11, ' ') + + (p.cpu_p < 10 or p.cpu_p >= 100 ? rjust(to_string(p.cpu_p), 3) + " " : rjust(to_string(p.cpu_p), 4)); + } + if (lc++ > height - 5) break; + } + + while (lc++ < height - 4) out += Mv::to(y+lc+2, x+1) + string(width - 3, ' '); + + return out; + } + +} + +namespace Draw { + void calcSizes(){ + Config::unlock(); + auto& boxes = Config::getS("shown_boxes"); + + Cpu::box.clear(); + Mem::box.clear(); + Net::box.clear(); + Proc::box.clear(); + + Cpu::width = Mem::width = Net::width = Proc::width = 0; + Cpu::height = Mem::height = Net::height = Proc::height = 0; + Cpu::redraw = Mem::redraw = Net::redraw = Proc::redraw = true; + + Cpu::shown = s_contains(boxes, "cpu") ? true : false; + Mem::shown = s_contains(boxes, "mem") ? true : false; + Net::shown = s_contains(boxes, "net") ? true : false; + Proc::shown = s_contains(boxes, "proc") ? true : false; + + //* Calculate and draw cpu box outlines + if (Cpu::shown) { + using namespace Cpu; + width = round(Term::width * width_p / 100); + height = max(8, (int)round(Term::height * (trim(boxes) == "cpu" ? 100 : height_p) / 100)); + + b_columns = max(1, (int)ceil((Global::coreCount + 1) / (height - 5))); + if (b_columns * (21 + 12 * got_sensors) < width - (width / 3)) { + b_column_size = 2; + b_width = (21 + 12 * got_sensors) * b_columns - (b_columns - 1); + } + else if (b_columns * (15 + 6 * got_sensors) < width - (width / 3)) { + b_column_size = 1; + b_width = (15 + 6 * got_sensors) * b_columns - (b_columns - 1); + } + else if (b_columns * (8 + 6 * got_sensors) < width - (width / 3)) { + b_column_size = 0; + } + else { + b_columns = (width - width / 3) / (8 + 6 * got_sensors); + b_column_size = 0; + } + + if (b_column_size == 0) b_width = (8 + 6 * got_sensors) * b_columns + 1; + b_height = min(height - 2, (int)ceil(Global::coreCount / b_columns) + 4); + + b_x = width - b_width - 1; + b_y = y + ceil((height - 2) / 2) - ceil(b_height / 2) + 1; + + box = createBox(x, y, width, height, Theme::c("cpu_box"), true, "cpu", "", 1); + box += Mv::to(y, x + 10) + Theme::c("cpu_box") + Symbols::title_left + Fx::b + Theme::c("hi_fg") + + 'M' + Theme::c("title") + "enu" + Fx::ub + Theme::c("cpu_box") + Symbols::title_right; + + auto& custom = Config::getS("custom_cpu_name"); + box += createBox(b_x, b_y, b_width, b_height, "", false, uresize((custom.empty() ? cpuName : custom) , b_width - 14)); + } + + //* Calculate and draw mem box outlines + if (Mem::shown) { + using namespace Mem; + auto& show_disks = Config::getB("show_disks"); + auto& swap_disk = Config::getB("swap_disk"); + auto& mem_graphs = Config::getB("mem_graphs"); + + // int hp; + // if (not Cpu::shown) hp = Net::shown ? 60 : 98; + // else if (not Net::shown) hp = 98 - Cpu::height_p; + // else hp = height_p; + + width = round(Term::width * (Proc::shown ? width_p : 100) / 100); + height = round(Term::height * (100 - Cpu::height_p * Cpu::shown - Net::height_p * Net::shown) / 100) + 1; + if (height + Cpu::height > Term::height) height = Term::height - Cpu::height; + y = Cpu::height + 1; + + if (show_disks) { + mem_width = ceil((width - 3) / 2); + disks_width = width - mem_width - 3; + mem_width += mem_width % 2; + divider = x + mem_width; + } + else + mem_width = width - 1; + + item_height = has_swap and not swap_disk ? 6 : 4; + if (height - (has_swap and not swap_disk ? 3 : 2) > 2 * item_height) + mem_size = 3; + else if (mem_width > 25) + mem_size = 2; + else + mem_size = 1; + + mem_meter = max(0, width - (disks_width * show_disks) - (mem_size > 2 ? 9 : 20)); + if (mem_size == 1) mem_meter += 6; + + if (mem_graphs) { + graph_height = max(1, (int)round(((height - (has_swap and not swap_disk ? 2 : 1)) - (mem_size == 3 ? 2 : 1) * item_height) / item_height)); + if (graph_height > 1) mem_meter += 6; + } + else + graph_height = 0; + + if (show_disks) { + disk_meter = max(0, width - mem_width - 23); + if (disks_width < 25) disk_meter += 10; + } + + box = createBox(x, y, width, height, Theme::c("mem_box"), true, "mem", "", 2); + box += Mv::to(y, (show_disks ? divider + 2 : x + width - 9)) + Theme::c("mem_box") + Symbols::title_left + (show_disks ? Fx::b : "") + + Theme::c("hi_fg") + 'd' + Theme::c("title") + "isks" + Fx::ub + Theme::c("mem_box") + Symbols::title_right; + if (show_disks) { + box += Mv::to(y, divider) + Symbols::div_up + Mv::to(y + height - 1, divider) + Symbols::div_down + Theme::c("div_line"); + for (auto i : iota(1, height - 1)) + box += Mv::to(y + i, divider) + Symbols::v_line; + } + } + + //* Calculate and draw net box outlines + if (Net::shown) { + using namespace Net; + width = round(Term::width * (Proc::shown ? width_p : 100) / 100); + height = Term::height - Cpu::height - Mem::height; + y = Term::height - height + 1; + b_width = (width > 45) ? 27 : 19; + b_height = (height > 10) ? 9 : height - 2; + b_x = width - b_width - 1; + b_y = y + ((height - 2) / 2) - b_height / 2 + 1; + d_graph_height = round((height - 2) / 2); + u_graph_height = height - 2 - d_graph_height; + + box = createBox(x, y, width, height, Theme::c("net_box"), true, "net", "", 3); + box += createBox(b_x, b_y, b_width, b_height, "", false, "download", "upload"); + } + + //* Calculate and draw proc box outlines + if (Proc::shown) { + using namespace Proc; + width = Term::width - (Mem::shown ? Mem::width : (Net::shown ? Net::width : 0)); + height = Term::height - Cpu::height; + x = Term::width - width + 1; + y = Cpu::height + 1; + current_y = y; + current_h = height; + select_max = height - 3; + + box = createBox(x, y, width, height, Theme::c("proc_box"), true, "proc", "", 4); + } + + } } \ No newline at end of file diff --git a/src/btop_draw.hpp b/src/btop_draw.hpp index f91ef3e..a59e159 100644 --- a/src/btop_draw.hpp +++ b/src/btop_draw.hpp @@ -40,17 +40,8 @@ namespace Symbols { namespace Draw { - struct BoxConf { - size_t x=0, y=0; - size_t width=0, height=0; - string line_color = "", title = "", title2 = ""; - bool fill = true; - size_t num=0; - size_t w_percent=0, h_percent=0; - }; - - //* Create a box using values from a BoxConf struct and return as a string - string createBox(BoxConf c); + //* 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); //* Class holding a percentage meter class Meter { @@ -95,24 +86,22 @@ namespace Draw { namespace Cpu { - extern Draw::BoxConf box; + } namespace Mem { - extern Draw::BoxConf box; + } namespace Net { - extern Draw::BoxConf box; + } namespace Proc { - extern Draw::BoxConf box; - } \ No newline at end of file diff --git a/src/btop_linux.cpp b/src/btop_linux.cpp index 9b5aad9..a14d9b3 100644 --- a/src/btop_linux.cpp +++ b/src/btop_linux.cpp @@ -90,6 +90,15 @@ namespace Shared { } +namespace Cpu { + bool got_sensors = false; + string cpuName = ""; +} + +namespace Mem { + bool has_swap = false; +} + namespace Proc { namespace { struct p_cache { @@ -144,10 +153,10 @@ namespace Proc { //? If filtering, include children of matching processes if (not filter.empty() and not found) { - if (std::to_string(cur_proc.pid).find(filter) == string::npos - and cur_proc.name.find(filter) == string::npos - and cur_proc.cmd.find(filter) == string::npos - and cur_proc.user.find(filter) == string::npos) { + if (not s_contains(std::to_string(cur_proc.pid), filter) + and not s_contains(cur_proc.name, filter) + and not s_contains(cur_proc.cmd, filter) + and not s_contains(cur_proc.user, filter)) { filtering = true; } else { @@ -373,10 +382,10 @@ namespace Proc { //* Match filter if defined if (not tree and not filter.empty() - and pid_str.find(filter) == string::npos - and cache[new_proc.pid].name.find(filter) == string::npos - and cache[new_proc.pid].cmd.find(filter) == string::npos - and cache[new_proc.pid].user.find(filter) == string::npos) { + and not s_contains(pid_str, filter) + and not s_contains(cache[new_proc.pid].name, filter) + and not s_contains(cache[new_proc.pid].cmd, filter) + and not s_contains(cache[new_proc.pid].user, filter)) { if (show_detailed and new_proc.pid == detailed_pid) detailed_filtered = true; else @@ -436,7 +445,7 @@ namespace Proc { next_x = 24; continue; } - case 24: { //? RSS memory (can be inaccurate, but parsing smaps increases total cpu usage by ~ 20x) + case 24: { //? RSS memory (can be inaccurate, but parsing smaps increases total cpu usage by ~20x) new_proc.mem = stoull(short_str) * Shared::page_size; next_x = 40; continue; @@ -487,14 +496,14 @@ namespace Proc { //* Sort processes auto cmp = [&reverse](const auto &a, const auto &b) { return (reverse ? a < b : a > b); }; switch (v_index(sort_vector, sorting)) { - case 0: { rng::sort(procs, cmp, &proc_info::pid); break; } - case 1: { rng::sort(procs, cmp, &proc_info::name); break; } - case 2: { rng::sort(procs, cmp, &proc_info::cmd); break; } + case 0: { rng::sort(procs, cmp, &proc_info::pid); break; } + case 1: { rng::sort(procs, cmp, &proc_info::name); break; } + case 2: { rng::sort(procs, cmp, &proc_info::cmd); break; } case 3: { rng::sort(procs, cmp, &proc_info::threads); break; } - case 4: { rng::sort(procs, cmp, &proc_info::user); break; } - case 5: { rng::sort(procs, cmp, &proc_info::mem); break; } - case 6: { rng::sort(procs, cmp, &proc_info::cpu_p); break; } - case 7: { rng::sort(procs, cmp, &proc_info::cpu_c); break; } + case 4: { rng::sort(procs, cmp, &proc_info::user); break; } + case 5: { rng::sort(procs, cmp, &proc_info::mem); break; } + case 6: { rng::sort(procs, cmp, &proc_info::cpu_p); break; } + case 7: { rng::sort(procs, cmp, &proc_info::cpu_c); break; } } //* When sorting with "cpu lazy" push processes over threshold cpu usage to the front regardless of cumulative usage @@ -515,6 +524,7 @@ namespace Proc { //* Generate tree view if enabled if (tree) { vector tree_procs; + tree_procs.reserve(procs.size()); //? Stable sort to retain selected sorting among processes with the same parent rng::stable_sort(procs, rng::less{}, &proc_info::ppid); diff --git a/src/btop_shared.hpp b/src/btop_shared.hpp index bd10d9f..1cd2e57 100644 --- a/src/btop_shared.hpp +++ b/src/btop_shared.hpp @@ -33,6 +33,12 @@ namespace Global { extern string banner; } +namespace Runner { + + extern std::atomic active; + +} + namespace Tools { //* Platform specific function for system_uptime (seconds since last restart) double system_uptime(); @@ -43,11 +49,30 @@ namespace Shared { void init(); } +namespace Cpu { + extern string box, cpuName; + extern bool shown, redraw, got_sensors; +} + +namespace Mem { + extern string box; + extern bool has_swap, shown, redraw; +} + +namespace Net { + extern string box; + extern bool shown, redraw; +} + namespace Proc { extern size_t numpids; extern std::atomic stop; extern std::atomic collecting; + extern string box; + extern bool shown, redraw; + extern int current_y, current_h, select_max; + //? Contains the valid sorting options for processes extern vector sort_vector; @@ -80,4 +105,6 @@ namespace Proc { //* Collects and sorts process information from /proc, saves and returns reference to Proc::current_procs; vector& collect(bool return_last=false); -} \ No newline at end of file + + string draw(vector plist); +} diff --git a/src/btop_tools.cpp b/src/btop_tools.cpp index 6d7195b..7757484 100644 --- a/src/btop_tools.cpp +++ b/src/btop_tools.cpp @@ -85,8 +85,8 @@ namespace Term { bool initialized = false; bool resized = false; - size_t width = 0; - size_t height = 0; + int width = 0; + int height = 0; string fg, bg, current_tty; const string hide_cursor = Fx::e + "?25l"; diff --git a/src/btop_tools.hpp b/src/btop_tools.hpp index 8a77bf3..f0064b0 100644 --- a/src/btop_tools.hpp +++ b/src/btop_tools.hpp @@ -91,8 +91,8 @@ namespace Mv { namespace Term { extern bool initialized; extern bool resized; - extern size_t width; - extern size_t height; + extern int width; + extern int height; extern string fg, bg, current_tty; //* Hide terminal cursor @@ -156,11 +156,17 @@ namespace Tools { string str_to_lower(const string& str); //* Check if vector contains value - template - bool v_contains(const vector& vec, const T find_val) { + template + bool v_contains(const vector& vec, const T2 find_val) { return std::ranges::find(vec, find_val) != vec.end(); } + //* Check if string contains value + template + bool s_contains(const string& str, const T find_val) { + return str.find(find_val) != string::npos; + } + //* Return index of from vector , returns size of if is not present template size_t v_index(vector& vec, T find_val) {