diff --git a/src/btop.cpp b/src/btop.cpp index 7dca917..901c697 100644 --- a/src/btop.cpp +++ b/src/btop.cpp @@ -753,6 +753,7 @@ int main(int argc, char **argv) { } //? Calculate sizes of all boxes + Config::presetsValid(Config::getS("presets")); Draw::calcSizes(); { @@ -817,7 +818,7 @@ int main(int argc, char **argv) { future_time = current_time; //? Poll for input and process any input detected - else if (Input::poll(min(1000ul, future_time - current_time))) { + else if (Input::poll(min((uint64_t)1000, future_time - current_time))) { if (not Runner::active) Config::unlock(); if (Menu::active) Menu::process(Input::get()); diff --git a/src/btop_config.cpp b/src/btop_config.cpp index aeec5b7..077ef93 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -26,7 +26,7 @@ tab-size = 4 #include #include -using std::array, std::atomic, std::string_view; +using std::array, std::atomic, std::string_view, std::string_literals::operator""s; namespace fs = std::filesystem; namespace rng = std::ranges; using namespace Tools; @@ -49,6 +49,11 @@ namespace Config { {"force_tty", "#* Set to true to force tty mode regardless if a real tty has been detected or not.\n" "#* Will force 16-color mode and TTY theme, set all graph symbols to \"tty\" and swap out other non tty friendly symbols."}, + {"presets", "#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets.\n" + "#* Format: \"box_name:P:G,box_name:P:G\" P=(0 or 1) for alternate positons, G=graph symbol to use for box.\n" + "#* Use withespace \" \" as seprator between different presets.\n" + "#* Example: \"cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty\""}, + {"rounded_corners", "#* Rounded corners on boxes, is ignored if TTY mode is ON."}, {"graph_symbol", "#* Default symbols to use for graph creation, \"braille\", \"block\" or \"tty\".\n" @@ -170,6 +175,7 @@ namespace Config { {"color_theme", "Default"}, {"shown_boxes", "cpu mem net proc"}, {"graph_symbol", "braille"}, + {"presets", "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty"}, {"graph_symbol_cpu", "default"}, {"graph_symbol_mem", "default"}, {"graph_symbol_net", "default"}, @@ -256,6 +262,61 @@ namespace Config { fs::path conf_file; vector current_boxes; + vector preset_list = {"cpu:0:default,mem:0:default,net:0:default,proc:0:default"}; + int current_preset = -1; + + bool presetsValid(const string& presets) { + vector new_presets = {preset_list.at(0)}; + + for (int x = 0; const auto& preset : ssplit(presets)) { + if (++x > 9) { + validError = "Too many presets entered!"; + return false; + } + for (int y = 0; const auto& box : ssplit(preset, ',')) { + if (++y > 4) { + validError = "Too many boxes entered for preset!"; + return false; + } + const auto& vals = ssplit(box, ':'); + if (vals.size() != 3) { + validError = "Malformatted preset in config value presets!"; + return false; + } + if (not is_in(vals.at(0), "cpu", "mem", "net", "proc")) { + validError = "Invalid box name in config value presets!"; + return false; + } + if (not is_in(vals.at(1), "0", "1")) { + validError = "Invalid position value in config value presets!"; + return false; + } + if (not v_contains(valid_graph_symbols_def, vals.at(2))) { + validError = "Invalid graph name in config value presets!"; + return false; + } + } + new_presets.push_back(preset); + } + + preset_list = move(new_presets); + return true; + } + + //* Apply selected preset + void apply_preset(const string& preset) { + string boxes; + for (const auto& box : ssplit(preset, ',')) { + const auto& vals = ssplit(box, ':'); + boxes += vals.at(0) + ' '; + if (vals.at(0) == "cpu") set("cpu_bottom", (vals.at(1) == "0" ? false : true)); + else if (vals.at(0) == "mem") set("mem_below_net", (vals.at(1) == "0" ? false : true)); + else if (vals.at(0) == "proc") set("proc_left", (vals.at(1) == "0" ? false : true)); + set("graph_symbol_" + vals.at(0), vals.at(2)); + } + if (not boxes.empty()) boxes.pop_back(); + if (check_boxes(boxes)) set("shown_boxes", boxes); + } void lock() { atomic_wait(writelock); @@ -307,6 +368,9 @@ namespace Config { else if (name == "shown_boxes" and not value.empty() and not check_boxes(value)) validError = "Invalid box name(s) in shown_boxes!"; + else if (name == "presets" and not presetsValid(value)) + return false; + else if (name == "cpu_core_map") { const auto maps = ssplit(value); bool all_good = true; diff --git a/src/btop_config.hpp b/src/btop_config.hpp index 78552bd..fd08d92 100644 --- a/src/btop_config.hpp +++ b/src/btop_config.hpp @@ -44,6 +44,8 @@ namespace Config { const vector temp_scales = { "celsius", "fahrenheit", "kelvin", "rankine" }; extern vector current_boxes; + extern vector preset_list; + extern int current_preset; //* Check if string only contains space seperated valid names for boxes bool check_boxes(const string& boxes); @@ -51,6 +53,12 @@ namespace Config { //* Toggle box and update config string shown_boxes void toggle_box(const string& box); + //* Parse and setup config value presets + bool presetsValid(const string& presets); + + //* Apply selected preset + void apply_preset(const string& preset); + bool _locked(const string& name); //* Return bool for config key diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index f51f989..2e844a3 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -518,6 +518,9 @@ namespace Cpu { //? Buttons on title out += Mv::to(button_y, x + 10) + title_left + Theme::c("hi_fg") + Fx::b + 'm' + Theme::c("title") + "enu" + Fx::ub + title_right; Input::mouse_mappings["m"] = {button_y, x + 11, 1, 4}; + out += Mv::to(button_y, x + 16) + title_left + Theme::c("hi_fg") + Fx::b + 'p' + Theme::c("title") + "reset " + + (Config::current_preset < 0 ? "*" : to_string(Config::current_preset)) + Fx::ub + title_right; + Input::mouse_mappings["p"] = {button_y, x + 17, 1, 8}; const string update = to_string(Config::getI("update_ms")) + "ms"; out += Mv::to(button_y, x + width - update.size() - 8) + title_left + Fx::b + Theme::c("hi_fg") + "- " + Theme::c("title") + update + Theme::c("hi_fg") + " +" + Fx::ub + title_right; @@ -1435,7 +1438,7 @@ namespace Proc { mem_str.resize((mem_p < 10 or mem_p >= 100 ? 3 : 4)); mem_str += '%'; } - out += (thread_size > 0 ? t_color + rjust(to_string(min(p.threads, 9999ul)), thread_size) + ' ' + end : "" ) + out += (thread_size > 0 ? t_color + rjust(to_string(min(p.threads, (size_t)9999)), thread_size) + ' ' + end : "" ) + g_color + ljust((cmp_greater(p.user.size(), user_size) ? p.user.substr(0, user_size - 1) + '+' : p.user), user_size) + ' ' + m_color + rjust(mem_str, 5) + end + ' ' + (is_selected ? "" : Theme::c("inactive_fg")) + graph_bg * 5 @@ -1457,7 +1460,7 @@ namespace Proc { //? Current selection and number of processes string location = to_string(start + selected) + '/' + to_string(numpids); - string loc_clear = Symbols::h_line * max(0ul, 9 - location.size()); + string loc_clear = Symbols::h_line * max((size_t)0, 9 - location.size()); out += Mv::to(y + height - 1, x+width - 3 - max(9, (int)location.size())) + Fx::ub + Theme::c("proc_box") + loc_clear + Symbols::title_left_down + Theme::c("title") + Fx::b + location + Fx::ub + Theme::c("proc_box") + Symbols::title_right_down; diff --git a/src/btop_input.cpp b/src/btop_input.cpp index 167735f..f4ffd3d 100644 --- a/src/btop_input.cpp +++ b/src/btop_input.cpp @@ -203,12 +203,26 @@ namespace Input { } else if (is_in(key, "1", "2", "3", "4")) { atomic_wait(Runner::active); + Config::current_preset = -1; static const array boxes = {"cpu", "mem", "net", "proc"}; Config::toggle_box(boxes.at(std::stoi(key) - 1)); Draw::calcSizes(); Runner::run("all", false, true); return; } + else if (is_in(key, "p", "P") and Config::preset_list.size() > 1) { + if (key == "p") { + if (++Config::current_preset >= (int)Config::preset_list.size()) Config::current_preset = 0; + } + else { + if (--Config::current_preset < 0) Config::current_preset = Config::preset_list.size() - 1; + } + atomic_wait(Runner::active); + Config::apply_preset(Config::preset_list.at(Config::current_preset)); + Draw::calcSizes(); + Runner::run("all", false, true); + return; + } else keep_going = true; diff --git a/src/btop_menu.cpp b/src/btop_menu.cpp index 37e9df5..5793cb8 100644 --- a/src/btop_menu.cpp +++ b/src/btop_menu.cpp @@ -103,7 +103,8 @@ namespace Menu { {"Mouse 1", "Clicks buttons and selects in process list."}, {"Mouse scroll", "Scrolls any scrollable list/text under cursor."}, {"Esc, m", "Toggles main menu."}, - {"p", "Cycle view presets"}, + {"p", "Cycle view presets forwards."}, + {"shift + p", "Cycle view presets backwards."}, {"1", "Toggle CPU box."}, {"2", "Toggle MEM box."}, {"3", "Toggle NET box."}, @@ -176,6 +177,22 @@ namespace Menu { "Will force 16-color mode and TTY theme,", "set all graph symbols to \"tty\" and swap", "out other non tty friendly symbols."}, + {"presets", + "Define presets for the layout of the boxes.", + "", + "Preset 0 is always all boxes shown with", + "default settings.", + "Max 9 presets.", + "", + "Format: \"box_name:P:G,box_name:P:G\"", + "P=(0 or 1) for alternate positons.", + "G=graph symbol to use for box.", + "", + "Use withespace \" \" as seprator between", + "different presets.", + "", + "Example:", + "\"mem:0:tty,proc:1:default cpu:0:braille\""}, {"shown_boxes", "Manually set which boxes to show.", "", @@ -965,7 +982,11 @@ namespace Menu { const auto& option = categories[selected_cat][item_height * page + selected][0]; if (selPred.test(isString) and Config::stringValid(option, editor.text)) { Config::set(option, editor.text); - if (is_in(option, "shown_boxes", "custom_cpu_name")) screen_redraw = true; + if (option == "custom_cpu_name") screen_redraw = true; + else if (is_in(option, "shown_boxes", "presets")) { + screen_redraw = true; + Config::current_preset = -1; + } else if (option == "clock_format") { Draw::update_clock(true); screen_redraw = true; diff --git a/src/btop_tools.cpp b/src/btop_tools.cpp index e9f31f8..74df467 100644 --- a/src/btop_tools.cpp +++ b/src/btop_tools.cpp @@ -164,7 +164,7 @@ namespace Tools { for (size_t x = 0, last_pos = 0, i = str.size() - 1; i > 0 ; i--) { if (wide and static_cast(str.at(i)) > 0xef) { x += 2; - last_pos = max(0ul, i - 1); + last_pos = max((size_t)0, i - 1); } else if ((static_cast(str.at(i)) & 0xC0) != 0x80) { x++; @@ -264,7 +264,7 @@ namespace Tools { string out = (not no_days and days > 0 ? to_string(days) + "d " : "") + (hours < 10 ? "0" : "") + to_string(hours) + ':' + (minutes < 10 ? "0" : "") + to_string(minutes) - + (not no_seconds ? ':' + (seconds < 10 ? "0" : "") + to_string(seconds) : ""); + + (not no_seconds ? ":" + string(std::cmp_less(seconds, 10) ? "0" : "") + to_string(seconds) : ""); return out; } diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 9387456..cc72370 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -890,7 +890,7 @@ namespace Mem { if (disk.io_read.empty()) disk.io_read.push_back(0); else - disk.io_read.push_back(max(0l, (sectors_read - disk.old_io.at(0)) * 512)); + disk.io_read.push_back(max((int64_t)0, (sectors_read - disk.old_io.at(0)) * 512)); disk.old_io.at(0) = sectors_read; while (cmp_greater(disk.io_read.size(), width * 2)) disk.io_read.pop_front(); @@ -899,7 +899,7 @@ namespace Mem { if (disk.io_write.empty()) disk.io_write.push_back(0); else - disk.io_write.push_back(max(0l, (sectors_write - disk.old_io.at(1)) * 512)); + disk.io_write.push_back(max((int64_t)0, (sectors_write - disk.old_io.at(1)) * 512)); disk.old_io.at(1) = sectors_write; while (cmp_greater(disk.io_write.size(), width * 2)) disk.io_write.pop_front(); @@ -1002,7 +1002,7 @@ namespace Net { auto& saved_stat = net.at(iface).stat.at(dir); auto& bandwidth = net.at(iface).bandwidth.at(dir); - const uint64_t val = max(stoul(readfile(sys_file, "0")), saved_stat.last); + const uint64_t val = max((uint64_t)stoul(readfile(sys_file, "0")), saved_stat.last); //? Update speed, total and top values saved_stat.speed = round((double)(val - saved_stat.last) / ((double)(new_timestamp - timestamp) / 1000)); @@ -1083,7 +1083,7 @@ namespace Net { const uint64_t avg_speed = (net[selected_iface].bandwidth[dir].size() > 5 ? std::accumulate(net.at(selected_iface).bandwidth.at(dir).rbegin(), net.at(selected_iface).bandwidth.at(dir).rbegin() + 5, 0) / 5 : net[selected_iface].stat[dir].speed); - graph_max[dir] = max(uint64_t(avg_speed * (sel == 0 ? 1.3 : 3.0)), 10ul << 10); + graph_max[dir] = max(uint64_t(avg_speed * (sel == 0 ? 1.3 : 3.0)), (uint64_t)10 << 10); max_count[dir][0] = max_count[dir][1] = 0; redraw = true; if (net_sync) sync = true; @@ -1152,7 +1152,7 @@ namespace Proc { //? Try to find name of the binary file and append to program name if not the same if (cur_proc.short_cmd.empty() and not cur_proc.cmd.empty()) { std::string_view cmd_view = cur_proc.cmd; - cmd_view = cmd_view.substr(0, min(cmd_view.find(' '), cmd_view.size())); + cmd_view = cmd_view.substr((size_t)0, min(cmd_view.find(' '), cmd_view.size())); cmd_view = cmd_view.substr(min(cmd_view.find_last_of('/') + 1, cmd_view.size())); cur_proc.short_cmd = (string)cmd_view; } @@ -1465,7 +1465,7 @@ namespace Proc { if (x-offset < 24) continue; //? Process cpu usage since last update - new_proc.cpu_p = round(cmult * 1000 * (cpu_t - new_proc.cpu_t) / max(1ul, cputimes - old_cputimes)) / 10.0; + new_proc.cpu_p = round(cmult * 1000 * (cpu_t - new_proc.cpu_t) / max((uint64_t)1, cputimes - old_cputimes)) / 10.0; //? Process cumulative cpu usage since process start new_proc.cpu_c = (double)cpu_t / max(1.0, (uptime * Shared::clkTck) - new_proc.cpu_s);