2021-06-19 14:57:27 +02:00
|
|
|
|
/* 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 <array>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <ranges>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
2021-06-19 22:48:31 +02:00
|
|
|
|
#include <btop_draw.hpp>
|
|
|
|
|
#include <btop_config.hpp>
|
|
|
|
|
#include <btop_theme.hpp>
|
2021-07-04 01:18:48 +02:00
|
|
|
|
#include <btop_shared.hpp>
|
2021-06-19 22:48:31 +02:00
|
|
|
|
#include <btop_tools.hpp>
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
2021-07-04 01:18:48 +02:00
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
using std::round, std::views::iota, std::string_literals::operator""s, std::clamp, std::array, std::floor, std::max, std::min,
|
|
|
|
|
std::to_string;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
|
|
|
|
namespace rng = std::ranges;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
using namespace Tools;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
|
|
|
|
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 string meter = "■";
|
|
|
|
|
|
|
|
|
|
const array<string, 10> superscript = { "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" };
|
|
|
|
|
|
|
|
|
|
const unordered_flat_map<string, vector<string>> graph_symbols = {
|
|
|
|
|
{ "braille_up", {
|
|
|
|
|
" ", "⢀", "⢠", "⢰", "⢸",
|
|
|
|
|
"⡀", "⣀", "⣠", "⣰", "⣸",
|
|
|
|
|
"⡄", "⣄", "⣤", "⣴", "⣼",
|
|
|
|
|
"⡆", "⣆", "⣦", "⣶", "⣾",
|
|
|
|
|
"⡇", "⣇", "⣧", "⣷", "⣿"
|
|
|
|
|
}},
|
|
|
|
|
{"braille_down", {
|
|
|
|
|
" ", "⠈", "⠘", "⠸", "⢸",
|
|
|
|
|
"⠁", "⠉", "⠙", "⠹", "⢹",
|
|
|
|
|
"⠃", "⠋", "⠛", "⠻", "⢻",
|
|
|
|
|
"⠇", "⠏", "⠟", "⠿", "⢿",
|
|
|
|
|
"⡇", "⡏", "⡟", "⡿", "⣿"
|
|
|
|
|
}},
|
|
|
|
|
{"block_up", {
|
|
|
|
|
" ", "▗", "▗", "▐", "▐",
|
|
|
|
|
"▖", "▄", "▄", "▟", "▟",
|
|
|
|
|
"▖", "▄", "▄", "▟", "▟",
|
|
|
|
|
"▌", "▙", "▙", "█", "█",
|
|
|
|
|
"▌", "▙", "▙", "█", "█"
|
|
|
|
|
}},
|
|
|
|
|
{"block_down", {
|
|
|
|
|
" ", "▝", "▝", "▐", "▐",
|
|
|
|
|
"▘", "▀", "▀", "▜", "▜",
|
|
|
|
|
"▘", "▀", "▀", "▜", "▜",
|
|
|
|
|
"▌", "▛", "▛", "█", "█",
|
|
|
|
|
"▌", "▛", "▛", "█", "█"
|
|
|
|
|
}},
|
|
|
|
|
{"tty_up", {
|
|
|
|
|
" ", "░", "░", "▒", "▒",
|
|
|
|
|
"░", "░", "▒", "▒", "█",
|
|
|
|
|
"░", "▒", "▒", "▒", "█",
|
|
|
|
|
"▒", "▒", "▒", "█", "█",
|
|
|
|
|
"▒", "█", "█", "█", "█"
|
|
|
|
|
}},
|
|
|
|
|
{"tty_down", {
|
|
|
|
|
" ", "░", "░", "▒", "▒",
|
|
|
|
|
"░", "░", "▒", "▒", "█",
|
|
|
|
|
"░", "▒", "▒", "▒", "█",
|
|
|
|
|
"▒", "▒", "▒", "█", "█",
|
|
|
|
|
"▒", "█", "█", "█", "█"
|
|
|
|
|
}}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Draw {
|
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
string createBox(int x, int y, int width, int height, string line_color, bool fill, string title, string title2, int num){
|
2021-06-19 14:57:27 +02:00
|
|
|
|
string out;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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]);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
|
|
|
|
out = Fx::reset + lcolor;
|
|
|
|
|
|
2021-06-30 22:28:12 +02:00
|
|
|
|
//? Draw horizontal lines
|
2021-07-04 22:02:31 +02:00
|
|
|
|
for (int hpos : {y, y + height - 1}){
|
|
|
|
|
out += Mv::to(hpos, x) + Symbols::h_line * (width - 1);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 22:28:12 +02:00
|
|
|
|
//? Draw vertical lines and fill if enabled
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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)) +
|
2021-06-19 14:57:27 +02:00
|
|
|
|
Symbols::v_line;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 22:28:12 +02:00
|
|
|
|
//? Draw corners
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
2021-06-30 22:28:12 +02:00
|
|
|
|
//? Draw titles if defined
|
2021-07-04 22:02:31 +02:00
|
|
|
|
if (not title.empty()){
|
|
|
|
|
out += Mv::to(y, x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + title +
|
2021-06-19 14:57:27 +02:00
|
|
|
|
Fx::ub + lcolor + Symbols::title_right;
|
|
|
|
|
}
|
2021-07-04 22:02:31 +02:00
|
|
|
|
if (not title2.empty()){
|
|
|
|
|
out += Mv::to(y + height - 1, x + 2) + Symbols::title_left + Theme::c("title") + title2 +
|
2021-06-19 14:57:27 +02:00
|
|
|
|
Fx::ub + lcolor + Symbols::title_right;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
return out + Fx::reset + Mv::to(y + 1, x + 1);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-04 01:18:48 +02:00
|
|
|
|
//* Meter class ------------------------------------------------------------------------------------------------------------>
|
2021-06-19 14:57:27 +02:00
|
|
|
|
void Meter::operator()(int width, string color_gradient, bool invert) {
|
|
|
|
|
this->width = width;
|
|
|
|
|
this->color_gradient = color_gradient;
|
|
|
|
|
this->invert = invert;
|
|
|
|
|
cache.clear();
|
|
|
|
|
cache.insert(cache.begin(), 101, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string Meter::operator()(int value) {
|
|
|
|
|
if (width < 1) return "";
|
|
|
|
|
value = clamp(value, 0, 100);
|
2021-06-21 22:52:55 +02:00
|
|
|
|
if (not cache.at(value).empty()) return cache.at(value);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
string& out = cache.at(value);
|
|
|
|
|
for (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;
|
|
|
|
|
else {
|
|
|
|
|
out += Theme::c("meter_bg") + Symbols::meter * (width + 1 - i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
out += Fx::reset;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-04 01:18:48 +02:00
|
|
|
|
//* Graph class ------------------------------------------------------------------------------------------------------------>
|
|
|
|
|
void Graph::_create(const deque<long long>& data, int data_offset) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
const bool mult = (data.size() - data_offset > 1);
|
2021-06-21 22:52:55 +02:00
|
|
|
|
if (mult and (data.size() - data_offset) % 2 != 0) data_offset--;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
auto& graph_symbol = Symbols::graph_symbols.at(symbol + '_' + (invert ? "down" : "up"));
|
|
|
|
|
array<int, 2> result;
|
|
|
|
|
const float mod = (height == 1) ? 0.3 : 0.1;
|
|
|
|
|
long long data_value = 0;
|
2021-06-21 22:52:55 +02:00
|
|
|
|
if (mult and data_offset > 0) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
last = data[data_offset - 1];
|
|
|
|
|
if (max_value > 0) last = clamp((last + offset) * 100 / max_value, 0ll, 100ll);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//? Horizontal iteration over values in <data>
|
|
|
|
|
for (int i : iota(data_offset, (int)data.size())) {
|
2021-06-21 22:52:55 +02:00
|
|
|
|
if (tty_mode and mult and i % 2 != 0) continue;
|
|
|
|
|
else if (not tty_mode) current = not current;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
if (i == -1) { data_value = 0; last = 0; }
|
|
|
|
|
else data_value = data[i];
|
|
|
|
|
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;
|
|
|
|
|
//? Calculate previous + current value to fit two values in 1 braille character
|
|
|
|
|
int ai = 0;
|
|
|
|
|
for (auto value : {last, data_value}) {
|
|
|
|
|
if (value >= cur_high)
|
|
|
|
|
result[ai++] = 4;
|
|
|
|
|
else if (value <= cur_low)
|
|
|
|
|
result[ai++] = 0;
|
|
|
|
|
else {
|
|
|
|
|
result[ai++] = round((float)(value - cur_low) * 4 / (cur_high - cur_low) + mod);
|
2021-06-21 22:52:55 +02:00
|
|
|
|
if (no_zero and horizon == height - 1 and i != -1 and result[ai] == 0) result[ai] = 1;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-30 22:28:12 +02:00
|
|
|
|
//? Generate graph symbol from 5x5 2D vector
|
2021-06-21 22:52:55 +02:00
|
|
|
|
graphs[current][horizon] += (height == 1 and result[0] + result[1] == 0) ? Mv::r(1) : graph_symbol[(result[0] * 5 + result[1])];
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
2021-06-21 22:52:55 +02:00
|
|
|
|
if (mult and i > data_offset) last = data_value;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
last = data_value;
|
|
|
|
|
if (height == 1)
|
|
|
|
|
out = (last < 1 ? 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 += (invert) ? graphs[current][ (height - 1) - i] : graphs[current][i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
out += Fx::reset;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-04 01:18:48 +02:00
|
|
|
|
void Graph::operator()(int width, int height, string color_gradient, const deque<long long>& data, string symbol, bool invert, bool no_zero, long long max_value, long long offset) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
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;
|
2021-06-21 22:52:55 +02:00
|
|
|
|
if (Config::getB("tty_mode") or symbol == "tty") {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
tty_mode = true;
|
|
|
|
|
this->symbol = "tty";
|
|
|
|
|
}
|
2021-06-21 22:52:55 +02:00
|
|
|
|
else if (symbol != "default") this->symbol = symbol;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
else this->symbol = Config::getS("graph_symbol");
|
2021-06-21 22:52:55 +02:00
|
|
|
|
if (max_value == 0 and offset > 0) max_value = 100;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
this->max_value = max_value;
|
|
|
|
|
int value_width = ceil((float)data.size() / 2);
|
|
|
|
|
int data_offset = 0;
|
|
|
|
|
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)) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-04 01:18:48 +02:00
|
|
|
|
string& Graph::operator()(const deque<long long>& data, bool data_same) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
if (data_same) return out;
|
|
|
|
|
|
|
|
|
|
//? Make room for new characters on graph
|
2021-06-21 22:52:55 +02:00
|
|
|
|
bool select_graph = (tty_mode ? current : not current);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
for (int i : iota(0, height)) {
|
|
|
|
|
if (graphs[select_graph][i].starts_with(Fx::e)) graphs[current][i].erase(0, 4);
|
|
|
|
|
else graphs[select_graph][i].erase(0, 3);
|
|
|
|
|
}
|
|
|
|
|
this->_create(data, (int)data.size() - 1);
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string& Graph::operator()() {
|
|
|
|
|
return out;
|
|
|
|
|
}
|
2021-07-04 01:18:48 +02:00
|
|
|
|
//*------------------------------------------------------------------------------------------------------------------------->
|
|
|
|
|
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-04 01:18:48 +02:00
|
|
|
|
namespace Cpu {
|
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
2021-07-04 01:18:48 +02:00
|
|
|
|
|
|
|
|
|
}
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
2021-07-04 01:18:48 +02:00
|
|
|
|
namespace Mem {
|
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
2021-07-04 01:18:48 +02:00
|
|
|
|
|
|
|
|
|
}
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
2021-07-04 01:18:48 +02:00
|
|
|
|
namespace Net {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Proc {
|
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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<string> greyscale;
|
|
|
|
|
vector<string> colorfade;
|
|
|
|
|
|
|
|
|
|
string draw(vector<proc_info> 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);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|