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 <algorithm>
|
|
|
|
|
#include <cmath>
|
2021-07-23 01:41:00 +02:00
|
|
|
|
#include <ranges>
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
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-07-23 01:41:00 +02:00
|
|
|
|
#include <btop_input.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
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
using namespace Tools;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
namespace rng = std::ranges;
|
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 = "┴";
|
|
|
|
|
|
2021-07-24 02:13:26 +02:00
|
|
|
|
const string up = "↑";
|
|
|
|
|
const string down = "↓";
|
|
|
|
|
const string left = "←";
|
|
|
|
|
const string right = "→";
|
|
|
|
|
const string enter = "↲";
|
|
|
|
|
|
2021-06-19 14:57:27 +02:00
|
|
|
|
const string meter = "■";
|
|
|
|
|
|
|
|
|
|
const array<string, 10> superscript = { "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" };
|
|
|
|
|
|
|
|
|
|
const unordered_flat_map<string, vector<string>> graph_symbols = {
|
|
|
|
|
{ "braille_up", {
|
|
|
|
|
" ", "⢀", "⢠", "⢰", "⢸",
|
|
|
|
|
"⡀", "⣀", "⣠", "⣰", "⣸",
|
|
|
|
|
"⡄", "⣄", "⣤", "⣴", "⣼",
|
|
|
|
|
"⡆", "⣆", "⣦", "⣶", "⣾",
|
|
|
|
|
"⡇", "⣇", "⣧", "⣷", "⣿"
|
|
|
|
|
}},
|
|
|
|
|
{"braille_down", {
|
|
|
|
|
" ", "⠈", "⠘", "⠸", "⢸",
|
|
|
|
|
"⠁", "⠉", "⠙", "⠹", "⢹",
|
|
|
|
|
"⠃", "⠋", "⠛", "⠻", "⢻",
|
|
|
|
|
"⠇", "⠏", "⠟", "⠿", "⢿",
|
|
|
|
|
"⡇", "⡏", "⡟", "⡿", "⣿"
|
|
|
|
|
}},
|
|
|
|
|
{"block_up", {
|
|
|
|
|
" ", "▗", "▗", "▐", "▐",
|
|
|
|
|
"▖", "▄", "▄", "▟", "▟",
|
|
|
|
|
"▖", "▄", "▄", "▟", "▟",
|
|
|
|
|
"▌", "▙", "▙", "█", "█",
|
2021-07-24 02:13:26 +02:00
|
|
|
|
"▌", "▙", "▙", "█", "█"
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}},
|
|
|
|
|
{"block_down", {
|
|
|
|
|
" ", "▝", "▝", "▐", "▐",
|
|
|
|
|
"▘", "▀", "▀", "▜", "▜",
|
|
|
|
|
"▘", "▀", "▀", "▜", "▜",
|
|
|
|
|
"▌", "▛", "▛", "█", "█",
|
|
|
|
|
"▌", "▛", "▛", "█", "█"
|
|
|
|
|
}},
|
|
|
|
|
{"tty_up", {
|
|
|
|
|
" ", "░", "░", "▒", "▒",
|
|
|
|
|
"░", "░", "▒", "▒", "█",
|
|
|
|
|
"░", "▒", "▒", "▒", "█",
|
|
|
|
|
"▒", "▒", "▒", "█", "█",
|
|
|
|
|
"▒", "█", "█", "█", "█"
|
|
|
|
|
}},
|
|
|
|
|
{"tty_down", {
|
|
|
|
|
" ", "░", "░", "▒", "▒",
|
|
|
|
|
"░", "░", "▒", "▒", "█",
|
|
|
|
|
"░", "▒", "▒", "▒", "█",
|
|
|
|
|
"▒", "▒", "▒", "█", "█",
|
|
|
|
|
"▒", "█", "█", "█", "█"
|
|
|
|
|
}}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Draw {
|
|
|
|
|
|
2021-07-24 02:13:26 +02:00
|
|
|
|
TextEdit::TextEdit() {}
|
|
|
|
|
TextEdit::TextEdit(string text) : text(text) {
|
|
|
|
|
pos = this->text.size();
|
|
|
|
|
upos = ulen(this->text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
string out;
|
2021-07-24 02:13:26 +02:00
|
|
|
|
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]);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
2021-07-24 02:13:26 +02:00
|
|
|
|
out = Fx::reset + line_color;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
|
2021-06-30 22:28:12 +02:00
|
|
|
|
//? Draw horizontal lines
|
2021-07-24 02:13:26 +02:00
|
|
|
|
for (const int& hpos : {y, y + height - 1}) {
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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-24 02:13:26 +02:00
|
|
|
|
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;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 22:28:12 +02:00
|
|
|
|
//? Draw corners
|
2021-07-24 02:13:26 +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-21 03:17:34 +02:00
|
|
|
|
if (not title.empty()) {
|
2021-07-24 02:13:26 +02:00
|
|
|
|
out += Mv::to(y, x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + title
|
|
|
|
|
+ Fx::ub + line_color + Symbols::title_right;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
2021-07-21 03:17:34 +02:00
|
|
|
|
if (not title2.empty()) {
|
2021-07-24 02:13:26 +02:00
|
|
|
|
out += Mv::to(y + height - 1, x + 2) + Symbols::title_left + Theme::c("title") + title2
|
|
|
|
|
+ Fx::ub + line_color + Symbols::title_right;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
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-07-24 02:13:26 +02:00
|
|
|
|
Meter::Meter(const int width, const string& color_gradient, const bool invert) : width(width), color_gradient(color_gradient), invert(invert) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
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);
|
2021-07-24 02:13:26 +02:00
|
|
|
|
for (const int& i : iota(1, width + 1)) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
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-07-24 02:13:26 +02:00
|
|
|
|
const auto& graph_symbol = Symbols::graph_symbols.at(symbol + '_' + (invert ? "down" : "up"));
|
2021-06-19 14:57:27 +02:00
|
|
|
|
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-07-26 01:06:34 +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);
|
|
|
|
|
}
|
2021-07-23 01:41:00 +02:00
|
|
|
|
|
2021-06-19 14:57:27 +02:00
|
|
|
|
//? Vertical iteration over height of graph
|
2021-07-24 02:13:26 +02:00
|
|
|
|
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;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
//? Calculate previous + current value to fit two values in 1 braille character
|
2021-07-24 02:13:26 +02:00
|
|
|
|
for (int ai = 0; const auto& value : {last, data_value}) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
if (value >= cur_high)
|
|
|
|
|
result[ai++] = 4;
|
|
|
|
|
else if (value <= cur_low)
|
2021-07-26 01:06:34 +02:00
|
|
|
|
result[ai++] = clamp_min;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
else {
|
2021-07-23 01:41:00 +02:00
|
|
|
|
result[ai++] = clamp((int)round((float)(value - cur_low) * 4 / (cur_high - cur_low) + mod), clamp_min, 4);
|
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;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
out.clear();
|
|
|
|
|
if (height == 1) {
|
|
|
|
|
if (not color_gradient.empty())
|
|
|
|
|
out += (last < 1 and not color_gradient.empty() ? Theme::c("inactive_fg") : Theme::g(color_gradient)[last]);
|
|
|
|
|
out += graphs[current][0];
|
|
|
|
|
}
|
2021-06-19 14:57:27 +02:00
|
|
|
|
else {
|
2021-07-24 02:13:26 +02:00
|
|
|
|
for (const int& i : iota(0, height)) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
if (i > 0) out += Mv::d(1) + Mv::l(width);
|
2021-07-23 01:41:00 +02:00
|
|
|
|
if (not color_gradient.empty())
|
|
|
|
|
out += (invert) ? Theme::g(color_gradient)[i * 100 / (height - 1)] : Theme::g(color_gradient)[100 - (i * 100 / (height - 1))];
|
2021-06-19 14:57:27 +02:00
|
|
|
|
out += (invert) ? graphs[current][ (height - 1) - i] : graphs[current][i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-23 01:41:00 +02:00
|
|
|
|
if (not color_gradient.empty()) out += Fx::reset;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-24 02:13:26 +02:00
|
|
|
|
Graph::Graph() {};
|
|
|
|
|
|
|
|
|
|
Graph::Graph(int width, int height, const string& color_gradient, const deque<long long>& 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) {
|
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
|
2021-07-24 02:13:26 +02:00
|
|
|
|
for (const int& i : iota(0, height * 2)) {
|
|
|
|
|
if (tty_mode and i % 2 != current) continue;
|
2021-06-19 14:57:27 +02:00
|
|
|
|
graphs[(i % 2 != 0)].push_back((value_width < width) ? ((height == 1) ? Mv::r(1) : " "s) * (width - value_width) : "");
|
|
|
|
|
}
|
|
|
|
|
if (data.size() == 0) return;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
if (data.size() == 1) data_offset--;
|
|
|
|
|
this->_create(data, data_offset);
|
|
|
|
|
// this->_create((data.size() == 1 ? deque{0, data[0]} : data), data_offset);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-24 02:13:26 +02:00
|
|
|
|
string& Graph::operator()(const deque<long long>& data, const bool data_same) {
|
2021-06-19 14:57:27 +02:00
|
|
|
|
if (data_same) return out;
|
|
|
|
|
|
|
|
|
|
//? Make room for new characters on graph
|
2021-07-24 02:13:26 +02:00
|
|
|
|
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);
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|
|
|
|
|
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-07-23 01:41:00 +02:00
|
|
|
|
string draw(const cpu_info& cpu, const bool force_redraw, const bool data_same) {
|
2021-07-18 15:44:32 +02:00
|
|
|
|
(void)cpu;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
(void)data_same;
|
2021-07-18 15:44:32 +02:00
|
|
|
|
string out;
|
|
|
|
|
if (redraw or force_redraw) {
|
|
|
|
|
redraw = false;
|
|
|
|
|
out += box;
|
|
|
|
|
}
|
|
|
|
|
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 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-07-23 01:41:00 +02:00
|
|
|
|
string draw(const mem_info& mem, const bool force_redraw, const bool data_same) {
|
2021-07-18 15:44:32 +02:00
|
|
|
|
(void)mem;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
(void)data_same;
|
2021-07-18 15:44:32 +02:00
|
|
|
|
string out;
|
|
|
|
|
if (redraw or force_redraw) {
|
|
|
|
|
redraw = false;
|
|
|
|
|
out += box;
|
|
|
|
|
}
|
|
|
|
|
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 Net {
|
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
|
|
|
|
|
2021-07-23 01:41:00 +02:00
|
|
|
|
string draw(const net_info& net, const bool force_redraw, const bool data_same) {
|
2021-07-18 15:44:32 +02:00
|
|
|
|
(void)net;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
(void)data_same;
|
2021-07-18 15:44:32 +02:00
|
|
|
|
string out;
|
|
|
|
|
if (redraw or force_redraw) {
|
|
|
|
|
redraw = false;
|
|
|
|
|
out += box;
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
int start, selected, select_max;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
bool shown = true, redraw = true;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
int selected_pid = 0;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
unordered_flat_map<size_t, Draw::Graph> p_graphs;
|
|
|
|
|
unordered_flat_map<size_t, int> p_counters;
|
|
|
|
|
int counter = 0;
|
2021-07-24 02:13:26 +02:00
|
|
|
|
Draw::TextEdit filter;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
Draw::Graph detailed_cpu_graph;
|
|
|
|
|
Draw::Graph detailed_mem_graph;
|
|
|
|
|
int user_size, thread_size, prog_size, cmd_size, tree_size;
|
|
|
|
|
int dgraph_x, dgraph_width, d_width, d_x, d_y;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
|
|
|
|
|
string box;
|
|
|
|
|
|
2021-07-26 01:06:34 +02:00
|
|
|
|
int selection(const string& cmd_key) {
|
2021-07-15 23:49:16 +02:00
|
|
|
|
auto start = Config::getI("proc_start");
|
|
|
|
|
auto selected = Config::getI("proc_selected");
|
2021-07-26 01:06:34 +02:00
|
|
|
|
auto last_selected = Config::getI("proc_last_selected");
|
|
|
|
|
const int select_max = (Config::getB("show_detailed") ? Proc::select_max - 8 : Proc::select_max);
|
|
|
|
|
|
2021-07-18 15:44:32 +02:00
|
|
|
|
int numpids = Proc::numpids;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
if (cmd_key == "up" and selected > 0) {
|
|
|
|
|
if (start > 0 and selected == 1) start--;
|
|
|
|
|
else selected--;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
if (Config::getI("proc_last_selected") > 0) Config::set("proc_last_selected", 0);
|
2021-07-15 23:49:16 +02:00
|
|
|
|
}
|
2021-07-23 01:41:00 +02:00
|
|
|
|
else if (cmd_key == "mouse_scroll_up" and start > 0) {
|
|
|
|
|
start = max(0, start - 3);
|
|
|
|
|
}
|
|
|
|
|
else if (cmd_key == "mouse_scroll_down" and start < numpids - select_max) {
|
|
|
|
|
start = min(numpids - select_max, start + 3);
|
|
|
|
|
}
|
2021-07-15 23:49:16 +02:00
|
|
|
|
else if (cmd_key == "down") {
|
|
|
|
|
if (start < numpids - select_max and selected == select_max) start++;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
else if (selected == 0 and last_selected > 0) {
|
|
|
|
|
selected = last_selected;
|
|
|
|
|
Config::set("proc_last_selected", 0);
|
|
|
|
|
}
|
2021-07-15 23:49:16 +02:00
|
|
|
|
else selected++;
|
|
|
|
|
}
|
|
|
|
|
else if (cmd_key == "page_up") {
|
2021-07-18 18:04:49 +02:00
|
|
|
|
if (selected > 0 and start == 0) selected = 0;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
else start = max(0, start - select_max);
|
2021-07-15 23:49:16 +02:00
|
|
|
|
}
|
|
|
|
|
else if (cmd_key == "page_down") {
|
2021-07-18 18:04:49 +02:00
|
|
|
|
if (selected > 0 and start >= numpids - select_max) selected = select_max;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
else start = clamp(start + select_max, 0, max(0, numpids - select_max));
|
|
|
|
|
}
|
|
|
|
|
else if (cmd_key == "home") {
|
|
|
|
|
start = 0;
|
2021-07-18 18:04:49 +02:00
|
|
|
|
if (selected > 0) selected = 1;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
}
|
|
|
|
|
else if (cmd_key == "end") {
|
|
|
|
|
start = max(0, numpids - select_max);
|
2021-07-18 18:04:49 +02:00
|
|
|
|
if (selected > 0) selected = select_max;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
}
|
2021-07-26 01:06:34 +02:00
|
|
|
|
else if (cmd_key.starts_with("mousey")) {
|
|
|
|
|
int mouse_y = std::stoi(cmd_key.substr(6));
|
|
|
|
|
start = clamp((int)round((double)mouse_y * (numpids - select_max - 2) / (select_max - 2)), 0, max(0, numpids - select_max));
|
|
|
|
|
}
|
2021-07-15 23:49:16 +02:00
|
|
|
|
|
2021-07-23 01:41:00 +02:00
|
|
|
|
bool changed = false;
|
|
|
|
|
if (start != Config::getI("proc_start")) {
|
|
|
|
|
Config::set("proc_start", start);
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
if (selected != Config::getI("proc_selected")) {
|
|
|
|
|
Config::set("proc_selected", selected);
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
2021-07-26 01:06:34 +02:00
|
|
|
|
return (not changed ? -1 : selected);
|
2021-07-15 23:49:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-23 01:41:00 +02:00
|
|
|
|
string draw(const vector<proc_info>& plist, const bool force_redraw, const bool data_same) {
|
2021-07-04 22:02:31 +02:00
|
|
|
|
auto& proc_tree = Config::getB("proc_tree");
|
2021-07-23 01:41:00 +02:00
|
|
|
|
const bool show_detailed = (Config::getB("show_detailed") and Proc::detailed.last_pid == (size_t)Config::getI("detailed_pid"));
|
2021-07-24 02:13:26 +02:00
|
|
|
|
const bool proc_gradient = (Config::getB("proc_gradient") and not Config::getB("tty_mode") and not Config::getB("lowcolor"));
|
2021-07-05 22:18:58 +02:00
|
|
|
|
auto& proc_colors = Config::getB("proc_colors");
|
2021-07-23 01:41:00 +02:00
|
|
|
|
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];
|
2021-07-26 01:06:34 +02:00
|
|
|
|
const auto& mem_bytes = Config::getB("proc_mem_bytes");
|
2021-07-15 23:49:16 +02:00
|
|
|
|
start = Config::getI("proc_start");
|
|
|
|
|
selected = Config::getI("proc_selected");
|
2021-07-05 22:18:58 +02:00
|
|
|
|
uint64_t total_mem = 16328872 << 10;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
const int y = show_detailed ? Proc::y + 8 : Proc::y;
|
|
|
|
|
const int height = show_detailed ? Proc::height - 8 : Proc::height;
|
|
|
|
|
const int select_max = show_detailed ? Proc::select_max - 8 : Proc::select_max;
|
2021-07-18 15:44:32 +02:00
|
|
|
|
int numpids = Proc::numpids;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
string out;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
out.reserve(width * height);
|
2021-07-23 01:41:00 +02:00
|
|
|
|
|
|
|
|
|
//* Redraw elements not needed to be updated every cycle
|
2021-07-18 15:44:32 +02:00
|
|
|
|
if (redraw or force_redraw) {
|
2021-07-04 22:02:31 +02:00
|
|
|
|
out = box;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
const string title_left = Theme::c("proc_box") + Symbols::title_left;
|
|
|
|
|
const string title_right = Theme::c("proc_box") + Symbols::title_right;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
for (const auto& key : {"T", "K", "S", "enter"})
|
|
|
|
|
if (Input::mouse_mappings.contains(key)) Input::mouse_mappings.erase(key);
|
|
|
|
|
|
|
|
|
|
//? Adapt sizes of text fields
|
|
|
|
|
user_size = (width < 75 ? 5 : 10);
|
|
|
|
|
thread_size = (width < 75 ? - 1 : 4);
|
|
|
|
|
prog_size = (width > 70 ? 16 : ( width > 55 ? 8 : width - user_size - thread_size - 33));
|
|
|
|
|
cmd_size = (width > 55 ? width - prog_size - user_size - thread_size - 33 : -1);
|
|
|
|
|
tree_size = width - user_size - thread_size - 23;
|
|
|
|
|
|
|
|
|
|
//? Detailed box
|
|
|
|
|
if (show_detailed) {
|
|
|
|
|
const bool alive = detailed.status != "Dead";
|
|
|
|
|
dgraph_x = x;
|
|
|
|
|
dgraph_width = max(width / 3, width - 121);
|
|
|
|
|
d_width = width - dgraph_width - 1;
|
|
|
|
|
d_x = x + dgraph_width + 1;
|
|
|
|
|
d_y = Proc::y;
|
|
|
|
|
|
|
|
|
|
//? Create cpu and mem graphs if process is alive
|
|
|
|
|
if (alive) {
|
|
|
|
|
detailed_cpu_graph = {dgraph_width - 1, 7, "cpu", detailed.cpu_percent, graph_symbol};
|
|
|
|
|
detailed_mem_graph = {d_width / 3, 1, "", detailed.mem_bytes, graph_symbol, false, false, detailed.first_mem};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//? Draw structure of details box
|
|
|
|
|
const string pid_str = to_string(detailed.entry.pid);
|
|
|
|
|
out += Mv::to(y, x) + title_right + Symbols::h_line + title_left + Theme::c("hi_fg") + Fx::b + Symbols::superscript[4]
|
|
|
|
|
+ Theme::c("title") + "proc" + Fx::ub + title_right + Symbols::h_line * (width - 10) + title_left
|
|
|
|
|
+ Mv::to(d_y, dgraph_x + 2) + title_left + Fx::b + Theme::c("title") + pid_str + Fx::ub + title_left
|
|
|
|
|
+ title_right + Fx::b + Theme::c("title") + uresize(detailed.entry.name, dgraph_width - pid_str.size() - 7) + Fx::ub + title_right;
|
|
|
|
|
|
|
|
|
|
out += Mv::to(d_y, d_x - 1) + Theme::c("proc_box") + Symbols::div_up + Mv::to(y, d_x - 1) + Symbols::div_down + Theme::c("div_line");
|
|
|
|
|
for (const int& i : iota(1, 8)) out += Mv::to(d_y + i, d_x - 1) + Symbols::v_line;
|
|
|
|
|
|
|
|
|
|
const string& t_color = (not alive or selected > 0 ? Theme::c("inactive_fg") : Theme::c("title"));
|
|
|
|
|
const string& hi_color = (not alive or selected > 0 ? t_color : Theme::c("hi_fg"));
|
|
|
|
|
const string hide = (selected > 0 ? t_color + "hide " : Theme::c("title") + "hide " + Theme::c("hi_fg"));
|
|
|
|
|
int mouse_x = d_x + 2;
|
|
|
|
|
out += Mv::to(d_y, d_x + 1);
|
|
|
|
|
if (width > 55) {
|
|
|
|
|
out += title_left + hi_color + Fx::b + 'T' + t_color + "erminate" + Fx::ub + title_right;
|
|
|
|
|
if (alive and selected == 0) Input::mouse_mappings["T"] = {d_y, mouse_x, 1, 9};
|
|
|
|
|
mouse_x += 11;
|
|
|
|
|
}
|
|
|
|
|
out += title_left + hi_color + Fx::b + 'K' + t_color + "ill" + Fx::ub + title_right
|
|
|
|
|
+ title_left + hi_color + Fx::b + 'S' + t_color + "ignals" + Fx::ub + title_right
|
|
|
|
|
+ Mv::to(d_y, d_x + d_width - 10) + title_left + t_color + Fx::b + hide + Symbols::enter + Fx::ub + title_right;
|
|
|
|
|
if (alive and selected == 0) {
|
|
|
|
|
Input::mouse_mappings["K"] = {d_y, mouse_x, 1, 4};
|
|
|
|
|
mouse_x += 6;
|
|
|
|
|
Input::mouse_mappings["S"] = {d_y, mouse_x, 1, 7};
|
|
|
|
|
}
|
|
|
|
|
if (selected == 0) Input::mouse_mappings["enter"] = {d_y, d_x + d_width - 9, 1, 6};
|
|
|
|
|
|
|
|
|
|
}
|
2021-07-24 02:13:26 +02:00
|
|
|
|
|
|
|
|
|
//? Filter
|
2021-07-26 01:06:34 +02:00
|
|
|
|
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));
|
2021-07-24 02:13:26 +02:00
|
|
|
|
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;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
Input::mouse_mappings["c"] = {y, sort_pos - 24, 1, 8};
|
2021-07-24 02:13:26 +02:00
|
|
|
|
}
|
|
|
|
|
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;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
Input::mouse_mappings["r"] = {y, sort_pos - 14, 1, 7};
|
2021-07-24 02:13:26 +02:00
|
|
|
|
}
|
|
|
|
|
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;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
Input::mouse_mappings["e"] = {y, sort_pos - 5, 1, 4};
|
2021-07-24 02:13:26 +02:00
|
|
|
|
}
|
|
|
|
|
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;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
Input::mouse_mappings["left"] = {y, sort_pos + 1, 1, 2};
|
|
|
|
|
Input::mouse_mappings["right"] = {y, sort_pos + sort_len + 3, 1, 2};
|
|
|
|
|
|
|
|
|
|
//? select, info and signal buttons
|
|
|
|
|
const string down_button = (selected == select_max and start == numpids - select_max ? Theme::c("inactive_fg") : Theme::c("hi_fg")) + Symbols::down;
|
|
|
|
|
const string t_color = (selected == 0 ? Theme::c("inactive_fg") : Theme::c("title"));
|
|
|
|
|
const string hi_color = (selected == 0 ? Theme::c("inactive_fg") : Theme::c("hi_fg"));
|
|
|
|
|
int mouse_x = x + 14;
|
|
|
|
|
out += Mv::to(y + height - 1, x + 1) + title_left + Fx::b + hi_color + Symbols::up + Theme::c("title") + " select " + down_button + Fx::ub + title_right
|
|
|
|
|
+ title_left + Fx::b + t_color + "info " + hi_color + Symbols::enter + Fx::ub + title_right;
|
|
|
|
|
if (selected > 0) Input::mouse_mappings["enter"] = {y + height - 1, mouse_x, 1, 6};
|
|
|
|
|
mouse_x += 8;
|
|
|
|
|
if (width > 60) {
|
|
|
|
|
out += title_left + Fx::b + hi_color + 'T' + t_color + "erminate" + Fx::ub + title_right;
|
|
|
|
|
if (selected > 0) Input::mouse_mappings["T"] = {y + height - 1, mouse_x, 1, 9};
|
|
|
|
|
mouse_x += 11;
|
|
|
|
|
}
|
|
|
|
|
if (width > 55) {
|
|
|
|
|
out += title_left + Fx::b + hi_color + 'K' + t_color + "ill" + Fx::ub + title_right;
|
|
|
|
|
if (selected > 0) Input::mouse_mappings["K"] = {y + height - 1, mouse_x, 1, 4};
|
|
|
|
|
mouse_x += 6;
|
|
|
|
|
}
|
|
|
|
|
out += title_left + Fx::b + hi_color + 'S' + t_color + "ignals" + Fx::ub + title_right;
|
|
|
|
|
if (selected > 0) Input::mouse_mappings["S"] = {y + height - 1, mouse_x, 1, 7};
|
2021-07-04 22:02:31 +02:00
|
|
|
|
|
2021-07-23 01:41:00 +02:00
|
|
|
|
//? Labels for fields in list
|
2021-07-05 22:18:58 +02:00
|
|
|
|
if (not proc_tree)
|
2021-07-15 23:49:16 +02:00
|
|
|
|
out += Mv::to(y+1, x+1) + Theme::c("title") + Fx::b
|
2021-07-26 01:06:34 +02:00
|
|
|
|
+ rjust("Pid:", 8) + ' '
|
|
|
|
|
+ ljust("Program:", prog_size) + ' '
|
|
|
|
|
+ (cmd_size > 0 ? ljust("Command:", cmd_size) : "") + ' ';
|
2021-07-05 22:18:58 +02:00
|
|
|
|
else
|
2021-07-26 01:06:34 +02:00
|
|
|
|
out += Mv::to(y+1, x+1) + Theme::c("title") + Fx::b
|
|
|
|
|
+ ljust("Tree:", tree_size) + ' ';
|
|
|
|
|
|
|
|
|
|
out += (thread_size > 0 ? Mv::l(4) + "Threads: " : "")
|
|
|
|
|
+ ljust("User:", user_size) + ' '
|
|
|
|
|
+ rjust((mem_bytes ? "MemB" : "Mem%"), 5) + ' '
|
|
|
|
|
+ rjust("Cpu%", 10) + Fx::ub;
|
|
|
|
|
}
|
|
|
|
|
//* End of redraw block
|
|
|
|
|
|
|
|
|
|
//? Draw details box if shown
|
|
|
|
|
if (show_detailed) {
|
|
|
|
|
const bool alive = detailed.status != "Dead";
|
|
|
|
|
const int item_fit = floor((double)(d_width - 2) / 10);
|
|
|
|
|
const int item_width = floor((double)(d_width - 2) / min(item_fit, 8));
|
|
|
|
|
|
|
|
|
|
//? Graph part of box
|
|
|
|
|
string cpu_str = (alive ? to_string(detailed.entry.cpu_p) : "");
|
|
|
|
|
if (alive) {
|
|
|
|
|
cpu_str.resize((detailed.entry.cpu_p < 10 or detailed.entry.cpu_p >= 100 ? 3 : 4));
|
|
|
|
|
cpu_str += '%' + Mv::r(1) + (dgraph_width < 20 ? "C" : "Core") + to_string(detailed.entry.cpu_n);
|
|
|
|
|
}
|
|
|
|
|
out += Mv::to(d_y + 1, dgraph_x + 1) + detailed_cpu_graph(detailed.cpu_percent, (data_same or not alive))
|
|
|
|
|
+ Mv::to(d_y + 1, dgraph_x + 1) + Theme::c("title") + Fx::b + cpu_str;
|
|
|
|
|
for (int i = 0; const auto& l : {'C', 'P', 'U'})
|
|
|
|
|
out += Mv::to(d_y + 3 + i++, dgraph_x + 1) + l;
|
|
|
|
|
|
|
|
|
|
//? Info part of box
|
|
|
|
|
const string mv_down = Mv::l(item_width) + Mv::d(1) + Fx::ub + Theme::c("main_fg");
|
|
|
|
|
const string mv_up = Mv::u(1) + Fx::b + Theme::c("title");
|
|
|
|
|
const string stat_color = (not alive ? Theme::c("inactive_fg") : (detailed.status == "Running" ? Theme::c("proc_misc") : ""));
|
|
|
|
|
out += Mv::to(d_y + 1, d_x + 1)
|
|
|
|
|
+ cjust("Status:", item_width) + mv_down + stat_color + cjust(detailed.status, item_width) + mv_up
|
|
|
|
|
+ cjust("Elapsed:", item_width) + mv_down + cjust(detailed.elapsed, item_width);
|
|
|
|
|
if (item_fit >= 3) out += mv_up + cjust("IO/R:", item_width) + mv_down + cjust(detailed.io_read, item_width);
|
|
|
|
|
if (item_fit >= 4) out += mv_up + cjust("IO/W:", item_width) + mv_down + cjust(detailed.io_write, item_width);
|
|
|
|
|
if (item_fit >= 5) out += mv_up + cjust("Parent:", item_width) + mv_down + cjust(detailed.parent, item_width);
|
|
|
|
|
if (item_fit >= 6) out += mv_up + cjust("User:", item_width) + mv_down + cjust(detailed.entry.user, item_width);
|
|
|
|
|
if (item_fit >= 7) out += mv_up + cjust("Nice:", item_width) + mv_down + cjust(to_string(detailed.entry.p_nice), item_width);
|
|
|
|
|
if (item_fit >= 8) out += mv_up + cjust("Threads:", item_width) + mv_down + cjust(to_string(detailed.entry.threads), item_width);
|
|
|
|
|
|
|
|
|
|
const double mem_p = (double)detailed.mem_bytes.back() * 100 / Shared::totalMem;
|
|
|
|
|
// const int mem_fuzz = min(detailed.mem * 100 / (Shared::totalMem / 10), 100ul);
|
|
|
|
|
string mem_str = to_string(mem_p);
|
|
|
|
|
mem_str.resize((mem_p < 10 or mem_p >= 100 ? 3 : 4));
|
|
|
|
|
out += Mv::to(d_y + 4, d_x + 1) + Theme::c("title") + Fx::b + rjust((item_fit > 4 ? "Memory: " : "M:") + mem_str + "% ", d_width / 3)
|
|
|
|
|
+ Theme::c("inactive_fg") + Fx::ub + graph_bg * (d_width / 3) + Mv::l(d_width / 3)
|
|
|
|
|
+ Theme::c("proc_misc") + detailed_mem_graph(detailed.mem_bytes, (data_same or not alive)) + ' '
|
|
|
|
|
+ Theme::c("title") + Fx::b + detailed.memory;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; const auto& l : {'C', 'M', 'D'})
|
|
|
|
|
out += Mv::to(d_y + 5 + i++, d_x + 1) + l;
|
|
|
|
|
|
|
|
|
|
out += Theme::c("main_fg") + Fx::ub;
|
|
|
|
|
const int cmd_size = ulen(detailed.entry.cmd);
|
|
|
|
|
for (int num_lines = min(3, (int)ceil((double)cmd_size / (d_width - 5))), i = 0; i < num_lines; i++) {
|
|
|
|
|
out += Mv::to(d_y + 5 + (num_lines == 1 ? 1 : i), d_x + 3)
|
|
|
|
|
+ cjust(luresize(detailed.entry.cmd, cmd_size - (d_width - 5) * i), d_width - 5, true);
|
|
|
|
|
}
|
2021-07-05 22:18:58 +02:00
|
|
|
|
}
|
2021-07-04 22:02:31 +02:00
|
|
|
|
|
2021-07-26 01:06:34 +02:00
|
|
|
|
|
|
|
|
|
//? Check bounds of current selection and view
|
2021-07-15 23:49:16 +02:00
|
|
|
|
if (start > 0 and numpids <= select_max)
|
|
|
|
|
start = 0;
|
|
|
|
|
if (start > numpids - select_max)
|
|
|
|
|
start = max(0, numpids - select_max);
|
|
|
|
|
if (selected > select_max)
|
|
|
|
|
selected = select_max;
|
|
|
|
|
if (selected > numpids)
|
|
|
|
|
selected = numpids;
|
|
|
|
|
|
2021-07-05 22:18:58 +02:00
|
|
|
|
//* Iteration over processes
|
2021-07-04 22:02:31 +02:00
|
|
|
|
int lc = 0;
|
2021-07-21 03:17:34 +02:00
|
|
|
|
for (int n=0; auto& p : plist) {
|
2021-07-15 23:49:16 +02:00
|
|
|
|
if (n++ < start) continue;
|
|
|
|
|
bool is_selected = (lc + 1 == selected);
|
|
|
|
|
if (is_selected) selected_pid = (int)p.pid;
|
|
|
|
|
|
2021-07-23 01:41:00 +02:00
|
|
|
|
//? 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)) {
|
2021-07-24 02:13:26 +02:00
|
|
|
|
p_graphs[p.pid] = {5, 1, "", {}, graph_symbol};
|
2021-07-23 01:41:00 +02:00
|
|
|
|
p_counters[p.pid] = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (p.cpu_p < 0.1) {
|
|
|
|
|
if (++p_counters[p.pid] >= 10) {
|
|
|
|
|
p_graphs.erase(p.pid);
|
|
|
|
|
p_counters.erase(p.pid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
p_counters[p.pid] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-15 23:49:16 +02:00
|
|
|
|
out += Fx::reset;
|
|
|
|
|
|
2021-07-05 22:18:58 +02:00
|
|
|
|
//? Set correct gradient colors if enabled
|
2021-07-15 23:49:16 +02:00
|
|
|
|
string c_color, m_color, t_color, g_color, end;
|
|
|
|
|
if (is_selected) {
|
|
|
|
|
c_color = m_color = t_color = g_color = Fx::b;
|
|
|
|
|
end = Fx::ub;
|
|
|
|
|
out += Theme::c("selected_bg") + Theme::c("selected_fg") + Fx::b;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int calc = (selected > lc) ? selected - lc : lc - selected;
|
|
|
|
|
if (proc_colors) {
|
|
|
|
|
end = Theme::c("main_fg") + Fx::ub;
|
|
|
|
|
array<string, 3> colors;
|
|
|
|
|
for (int i = 0; int v : {(int)round(p.cpu_p), (int)round(p.mem * 100 / total_mem), (int)p.threads / 3}) {
|
|
|
|
|
if (proc_gradient) {
|
|
|
|
|
int val = (min(v, 100) + 100) - calc * 100 / select_max;
|
|
|
|
|
if (val < 100) colors[i++] = Theme::g("proc_color")[val];
|
|
|
|
|
else colors[i++] = Theme::g("process")[val - 100];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
colors[i++] = Theme::g("process")[min(v, 100)];
|
2021-07-05 22:18:58 +02:00
|
|
|
|
}
|
2021-07-15 23:49:16 +02:00
|
|
|
|
c_color = colors[0]; m_color = colors[1]; t_color = colors[2];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
c_color = m_color = t_color = Fx::b;
|
|
|
|
|
end = Fx::ub;
|
|
|
|
|
}
|
|
|
|
|
if (proc_gradient) {
|
|
|
|
|
g_color = Theme::g("proc")[calc * 100 / select_max];
|
2021-07-05 22:18:58 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//? Normal view line
|
2021-07-04 22:02:31 +02:00
|
|
|
|
if (not proc_tree) {
|
2021-07-05 22:18:58 +02:00
|
|
|
|
out += Mv::to(y+2+lc, x+1)
|
2021-07-15 23:49:16 +02:00
|
|
|
|
+ g_color + rjust(to_string(p.pid), 8) + ' '
|
2021-07-26 01:06:34 +02:00
|
|
|
|
+ c_color + ljust(p.name, prog_size) + ' ' + end
|
|
|
|
|
+ (cmd_size > 0 ? g_color + ljust(p.cmd, cmd_size, true) + ' ' : "");
|
2021-07-04 22:02:31 +02:00
|
|
|
|
}
|
2021-07-05 22:18:58 +02:00
|
|
|
|
//? Tree view line
|
2021-07-04 22:02:31 +02:00
|
|
|
|
else {
|
2021-07-15 23:49:16 +02:00
|
|
|
|
string prefix_pid = p.prefix + to_string(p.pid);
|
2021-07-26 01:06:34 +02:00
|
|
|
|
int width_left = tree_size;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
out += Mv::to(y+2+lc, x+1) + g_color + uresize(prefix_pid, width_left) + ' ';
|
|
|
|
|
width_left -= ulen(prefix_pid);
|
|
|
|
|
if (width_left > 0) {
|
|
|
|
|
out += c_color + uresize(p.name, width_left - 1) + end + ' ';
|
|
|
|
|
width_left -= (ulen(p.name) + 1);
|
2021-07-04 22:02:31 +02:00
|
|
|
|
}
|
2021-07-15 23:49:16 +02:00
|
|
|
|
if (width_left > 7 and not p.cmd.empty()) {
|
|
|
|
|
out += g_color + uresize(p.cmd, width_left - 1) + ' ';
|
|
|
|
|
width_left -= (ulen(p.cmd) + 1);
|
|
|
|
|
}
|
|
|
|
|
out += string(max(0, width_left), ' ');
|
2021-07-04 22:02:31 +02:00
|
|
|
|
}
|
2021-07-05 22:18:58 +02:00
|
|
|
|
//? Common end of line
|
2021-07-15 23:49:16 +02:00
|
|
|
|
string cpu_str = to_string(p.cpu_p);
|
|
|
|
|
if (p.cpu_p < 10 or p.cpu_p >= 100) cpu_str.resize(3);
|
2021-07-26 01:06:34 +02:00
|
|
|
|
string mem_str = (mem_bytes ? floating_humanizer(p.mem, true) : "");
|
|
|
|
|
if (not mem_bytes) {
|
|
|
|
|
double mem_p = (double)p.mem * 100 / Shared::totalMem;
|
|
|
|
|
mem_str = to_string(mem_p);
|
|
|
|
|
mem_str.resize((mem_p < 10 or mem_p >= 100 ? 3 : 4));
|
|
|
|
|
mem_str += '%';
|
|
|
|
|
}
|
|
|
|
|
out += (thread_size > 0 ? t_color + rjust(to_string(p.threads), thread_size) + ' ' + end : "" )
|
|
|
|
|
+ g_color + ljust(p.user, user_size) + ' '
|
|
|
|
|
+ m_color + rjust(mem_str, 5) + end + ' '
|
2021-07-23 01:41:00 +02:00
|
|
|
|
+ (is_selected ? "" : Theme::c("inactive_fg")) + graph_bg * 5
|
2021-07-26 01:06:34 +02:00
|
|
|
|
+ (p_graphs.contains(p.pid) ? Mv::l(5) + c_color + p_graphs[p.pid]({(p.cpu_p >= 0.1 and p.cpu_p < 5 ? 5ll : (long long)round(p.cpu_p))}, data_same) : "") + end + ' '
|
2021-07-23 01:41:00 +02:00
|
|
|
|
+ c_color + rjust(cpu_str, 4) + " " + end;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
if (lc++ > height - 5) break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-15 23:49:16 +02:00
|
|
|
|
out += Fx::reset;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
while (lc++ < height - 4) out += Mv::to(y+lc+2, x+1) + string(width - 2, ' ');
|
|
|
|
|
|
2021-07-26 01:06:34 +02:00
|
|
|
|
//? Draw scrollbar if needed
|
2021-07-23 01:41:00 +02:00
|
|
|
|
if (numpids > select_max) {
|
|
|
|
|
const int scroll_pos = clamp((int)round((double)start * (select_max - 2) / (numpids - (select_max - 2))), 0, height - 5);
|
2021-07-26 01:06:34 +02:00
|
|
|
|
out += Mv::to(y + 1, x + width - 2) + Fx::b + Theme::c("main_fg") + Symbols::up
|
|
|
|
|
+ Mv::to(y + height - 2, x + width - 2) + Symbols::down
|
2021-07-23 01:41:00 +02:00
|
|
|
|
+ Mv::to(y + 2 + scroll_pos, x + width - 2) + "█";
|
|
|
|
|
}
|
2021-07-15 23:49:16 +02:00
|
|
|
|
|
2021-07-26 01:06:34 +02:00
|
|
|
|
//? Current selection and number of processes
|
2021-07-15 23:49:16 +02:00
|
|
|
|
string location = to_string(start + selected) + '/' + to_string(numpids);
|
|
|
|
|
string loc_clear = Symbols::h_line * max(0ul, 9 - location.size());
|
|
|
|
|
out += Mv::to(y+height, x+width - 3 - max(9, (int)location.size())) + Theme::c("proc_box") + loc_clear
|
|
|
|
|
+ Symbols::title_left + Theme::c("title") + Fx::b + location + Fx::ub + Theme::c("proc_box") + Symbols::title_right;
|
|
|
|
|
|
2021-07-26 01:06:34 +02:00
|
|
|
|
//? Clear out left over graphs from dead processes at a regular interval
|
|
|
|
|
if (not data_same and ++counter >= 1000) {
|
|
|
|
|
counter = 0;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
for (auto element = p_graphs.begin(); element != p_graphs.end();) {
|
|
|
|
|
if (rng::find(plist, element->first, &proc_info::pid) == plist.end()) {
|
2021-07-26 01:06:34 +02:00
|
|
|
|
element = p_graphs.erase(element);
|
2021-07-23 01:41:00 +02:00
|
|
|
|
p_counters.erase(element->first);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
++element;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-15 23:49:16 +02:00
|
|
|
|
if (selected == 0 and selected_pid != 0) selected_pid = 0;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
redraw = false;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
return out + Fx::reset;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Draw {
|
2021-07-21 03:17:34 +02:00
|
|
|
|
void calcSizes() {
|
2021-07-04 22:02:31 +02:00
|
|
|
|
auto& boxes = Config::getS("shown_boxes");
|
|
|
|
|
|
|
|
|
|
Cpu::box.clear();
|
|
|
|
|
Mem::box.clear();
|
|
|
|
|
Net::box.clear();
|
|
|
|
|
Proc::box.clear();
|
|
|
|
|
|
2021-07-23 01:41:00 +02:00
|
|
|
|
Input::mouse_mappings.clear();
|
|
|
|
|
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
|
|
|
|
|
2021-07-15 23:49:16 +02:00
|
|
|
|
Cpu::shown = s_contains(boxes, "cpu");
|
|
|
|
|
Mem::shown = s_contains(boxes, "mem");
|
|
|
|
|
Net::shown = s_contains(boxes, "net");
|
|
|
|
|
Proc::shown = s_contains(boxes, "proc");
|
2021-07-04 22:02:31 +02:00
|
|
|
|
|
|
|
|
|
//* Calculate and draw cpu box outlines
|
|
|
|
|
if (Cpu::shown) {
|
|
|
|
|
using namespace Cpu;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
width = round((double)Term::width * width_p / 100);
|
|
|
|
|
height = max(8, (int)round((double)Term::height * (trim(boxes) == "cpu" ? 100 : height_p) / 100));
|
2021-07-04 22:02:31 +02:00
|
|
|
|
|
2021-07-26 01:06:34 +02:00
|
|
|
|
b_columns = max(1, (int)ceil((double)(Shared::coreCount + 1) / (height - 5)));
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
2021-07-26 01:06:34 +02:00
|
|
|
|
b_height = min(height - 2, (int)ceil((double)Shared::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;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
b_y = y + ceil((double)(height - 2) / 2) - ceil((double)b_height / 2) + 1;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
2021-07-23 01:41:00 +02:00
|
|
|
|
width = round((double)Term::width * (Proc::shown ? width_p : 100) / 100);
|
|
|
|
|
height = round((double)Term::height * (100 - Cpu::height_p * Cpu::shown - Net::height_p * Net::shown) / 100) + 1;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
if (height + Cpu::height > Term::height) height = Term::height - Cpu::height;
|
|
|
|
|
y = Cpu::height + 1;
|
|
|
|
|
|
|
|
|
|
if (show_disks) {
|
2021-07-23 01:41:00 +02:00
|
|
|
|
mem_width = ceil((double)(width - 3) / 2);
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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) {
|
2021-07-23 01:41:00 +02:00
|
|
|
|
graph_height = max(1, (int)round((double)((height - (has_swap and not swap_disk ? 2 : 1)) - (mem_size == 3 ? 2 : 1) * item_height) / item_height));
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
width = round((double)Term::width * (Proc::shown ? width_p : 100) / 100);
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
2021-07-23 01:41:00 +02:00
|
|
|
|
d_graph_height = round((double)(height - 2) / 2);
|
2021-07-04 22:02:31 +02:00
|
|
|
|
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;
|
2021-07-15 23:49:16 +02:00
|
|
|
|
select_max = height - 3;
|
2021-07-04 22:02:31 +02:00
|
|
|
|
box = createBox(x, y, width, height, Theme::c("proc_box"), true, "proc", "", 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2021-06-19 14:57:27 +02:00
|
|
|
|
}
|