Added functionality for text editing and slight modifications to default theme colors

This commit is contained in:
aristocratos 2021-07-24 02:13:26 +02:00
parent f8005aeb21
commit 9ee9f3232d
13 changed files with 325 additions and 138 deletions

View File

@ -464,7 +464,13 @@ int main(int argc, char **argv) {
}
//? Platform dependent init and error check
Shared::init();
try {
Shared::init();
}
catch (const std::exception& e) {
Global::exit_error_msg = "Exception in Shared::init() -> " + (string)e.what();
clean_quit(1);
}
//? Update list of available themes and generate the selected theme
Theme::updateThemes();
@ -561,19 +567,21 @@ int main(int argc, char **argv) {
deque<long long> mydata;
for (long long i = 0; i <= 100; i++) mydata.push_back(i);
for (long long i = 100; i >= 0; i--) mydata.push_back(i);
mydata.push_back(50);
// mydata.push_back(50);
auto mydata2 = mydata;
mydata2.push_back(10);
for (long long i = 0; i <= 100; i++) mydata2.push_back(i);
for (long long i = 100; i >= 0; i--) mydata2.push_back(i);
Draw::Graph kgraph {};
Draw::Graph kgraph2 {};
Draw::Graph kgraph3 {};
cout << Draw::createBox(5, 10, Term::width - 10, 12, Theme::c("proc_box"), false, "braille", "", 1) << Mv::save;
cout << Draw::createBox(5, 23, Term::width - 10, 12, Theme::c("proc_box"), false, "block", "", 2);
cout << Draw::createBox(5, 36, Term::width - 10, 12, Theme::c("proc_box"), false, "tty", "", 3) << flush;
auto kts = time_micros();
kgraph(Term::width - 13, 10, "cpu", mydata, "braille", false, false);
kgraph2(Term::width - 13, 10, "cpu", mydata, "block", false, false);
kgraph3(Term::width - 13, 10, "cpu", mydata, "tty", false, false);
Draw::Graph kgraph {Term::width - 13, 10, "cpu", mydata, "block", false, false};
Draw::Graph kgraph2 {Term::width - 13, 10, "upload", {0, 1}, "block", false, false};
Draw::Graph kgraph3 {Term::width - 13, 10, "download", {}, "block", false, false};
cout << Mv::restore << kgraph(mydata, true)

View File

@ -240,22 +240,12 @@ namespace Config {
vector<string> current_boxes;
void set(string name, bool value) {
if (_locked(name)) boolsTmp.insert_or_assign(name, value);
else bools.at(name) = value;
void lock() {
writelock.wait(true);
locked = true;
}
void set(string name, int value) {
if (_locked(name)) intsTmp.insert_or_assign(name, value);
ints.at(name) = value;
}
void set(string name, string value) {
if (_locked(name)) stringsTmp.insert_or_assign(name, value);
else strings.at(name) = value;
}
void flip(string name) {
void flip(const string& name) {
if (_locked(name)) {
if (boolsTmp.contains(name)) boolsTmp.at(name) = not boolsTmp.at(name);
else boolsTmp.insert_or_assign(name, (not bools.at(name)));
@ -263,11 +253,6 @@ namespace Config {
else bools.at(name) = not bools.at(name);
}
void lock() {
writelock.wait(true);
locked = true;
}
void unlock() {
if (not locked) return;
writelock.wait(true);
@ -305,7 +290,7 @@ namespace Config {
writelock.notify_all();
}
bool check_boxes(string boxes) {
bool check_boxes(const string& boxes) {
auto new_boxes = ssplit(boxes);
for (auto& box : new_boxes) {
if (not v_contains(valid_boxes, box)) return false;
@ -314,7 +299,7 @@ namespace Config {
return true;
}
void load(fs::path conf_file, vector<string>& load_errors) {
void load(const fs::path& conf_file, vector<string>& load_errors) {
if (conf_file.empty())
return;
else if (not fs::exists(conf_file)) {

View File

@ -32,15 +32,20 @@ namespace Config {
extern std::filesystem::path conf_file;
extern unordered_flat_map<string, string> strings;
extern unordered_flat_map<string, string> stringsTmp;
extern unordered_flat_map<string, bool> bools;
extern unordered_flat_map<string, bool> boolsTmp;
extern unordered_flat_map<string, int> ints;
extern unordered_flat_map<string, int> intsTmp;
const vector<string> valid_graph_symbols = { "braille", "block", "tty" };
extern vector<string> current_boxes;
//* Check if string only contains space seperated valid names for boxes
bool check_boxes(string boxes);
bool check_boxes(const string& boxes);
bool _locked(const string& name);
//* Return bool for config key <name>
inline const bool& getB(const string& name) { return bools.at(name); }
@ -52,16 +57,25 @@ namespace Config {
inline const string& getS(const string& name) { return strings.at(name); }
//* Set config key <name> to bool <value>
void set(string name, bool value);
inline void set(const string& name, const bool& value) {
if (_locked(name)) boolsTmp.insert_or_assign(name, value);
else bools.at(name) = value;
}
//* Set config key <name> to int <value>
void set(string name, int value);
inline void set(const string& name, const int& value) {
if (_locked(name)) intsTmp.insert_or_assign(name, value);
ints.at(name) = value;
}
//* Set config key <name> to string <value>
void set(string name, string value);
inline void set(const string& name, const string& value) {
if (_locked(name)) stringsTmp.insert_or_assign(name, value);
else strings.at(name) = value;
}
//* Flip config key bool <name>
void flip(string name);
void flip(const string& name);
//* Lock config and cache changes until unlocked
void lock();
@ -70,8 +84,15 @@ namespace Config {
void unlock();
//* Load the config file from disk
void load(std::filesystem::path conf_file, vector<string>& load_errors);
void load(const std::filesystem::path& conf_file, vector<string>& load_errors);
//* Write the config file to disk
void write();
}
}

View File

@ -47,6 +47,12 @@ namespace Symbols {
const string div_up = "";
const string div_down = "";
const string up = "";
const string down = "";
const string left = "";
const string right = "";
const string enter = "";
const string meter = "";
const array<string, 10> superscript = { "", "¹", "²", "³", "", "", "", "", "", "" };
@ -71,7 +77,7 @@ namespace Symbols {
"", "", "", "", "",
"", "", "", "", "",
"", "", "", "", "",
"", "", "", "", "",
"", "", "", "", ""
}},
{"block_down", {
"", "", "", "", "",
@ -100,50 +106,127 @@ namespace Symbols {
namespace Draw {
string createBox(int x, int y, int width, int height, string line_color, bool fill, string title, string title2, int num) {
string out;
string lcolor = (line_color.empty()) ? Theme::c("div_line") : line_color;
string numbering = (num == 0) ? "" : Theme::c("hi_fg") + (Config::getB("tty_mode") ? std::to_string(num) : Symbols::superscript[num]);
TextEdit::TextEdit() {}
TextEdit::TextEdit(string text) : text(text) {
pos = this->text.size();
upos = ulen(this->text);
}
out = Fx::reset + lcolor;
bool TextEdit::command(const string& key) {
if (key == "left" and upos > 0) {
upos--;
pos = uresize(text, upos).size();
}
else if (key == "right" and pos < text.size()) {
upos++;
pos = uresize(text, upos).size();
}
else if (key == "home" and pos > 0) {
pos = upos = 0;
}
else if (key == "end" and pos < text.size()) {
pos = text.size();
upos = ulen(text);
}
else if (key == "backspace" and pos > 0) {
if (pos == text.size()) {
text = uresize(text, --upos);
pos = text.size();
}
else {
const string first = uresize(text, --upos);
pos = first.size();
text = first + text.substr(pos);
}
}
else if (key == "delete" and pos < text.size()) {
const string first = uresize(text, upos + 1);
text = uresize(first, ulen(first) - 1) + text.substr(first.size());
}
else if (key == "space") {
text.insert(pos++, 1, ' ');
upos++;
}
else if (ulen(key) == 1) {
if (key.size() == 1) {
text.insert(pos++, 1, key[0]);
upos++;
}
else {
const string first = uresize(text, upos) + key;
text = first + text.substr(pos);
upos++;
pos = first.size();
}
}
else
return false;
return true;
}
string TextEdit::operator()(const size_t limit) {
if (limit > 0 and ulen(text) + 1 > limit) {
try {
const size_t half = (size_t)round((double)limit / 2);
string first;
if (upos + half > ulen(text))
first = luresize(text.substr(0, pos), limit - (ulen(text) - upos));
else if (upos - half < 1)
first = text.substr(0, pos);
else
first = luresize(text.substr(0, pos), half);
return first + Fx::bl + "" + Fx::ubl + uresize(text.substr(pos), limit - ulen(first));
}
catch (const std::exception& e) {
Logger::error("In TextEdit::operator() : " + (string)e.what());
}
}
return text.substr(0, pos) + Fx::bl + "" + Fx::ubl + text.substr(pos);
}
string createBox(const int x, const int y, const int width, const int height, string line_color, const bool fill, const string title, const string title2, const int num) {
string out;
if (line_color.empty()) line_color = Theme::c("div_line");
const string numbering = (num == 0) ? "" : Theme::c("hi_fg") + (Config::getB("tty_mode") ? std::to_string(num) : Symbols::superscript[num]);
out = Fx::reset + line_color;
//? Draw horizontal lines
for (int hpos : {y, y + height - 1}) {
for (const int& hpos : {y, y + height - 1}) {
out += Mv::to(hpos, x) + Symbols::h_line * (width - 1);
}
//? Draw vertical lines and fill if enabled
for (int hpos : iota(y + 1, y + height - 1)) {
out += Mv::to(hpos, x) + Symbols::v_line +
((fill) ? string(width - 2, ' ') : Mv::r(width - 2)) +
Symbols::v_line;
for (const int& hpos : iota(y + 1, y + height - 1)) {
out += Mv::to(hpos, x) + Symbols::v_line
+ ((fill) ? string(width - 2, ' ') : Mv::r(width - 2))
+ Symbols::v_line;
}
//? Draw corners
out += Mv::to(y, x) + Symbols::left_up +
Mv::to(y, x + width - 1) + Symbols::right_up +
Mv::to(y + height - 1, x) + Symbols::left_down +
Mv::to(y + height - 1, x + width - 1) + Symbols::right_down;
out += Mv::to(y, x) + Symbols::left_up
+ Mv::to(y, x + width - 1) + Symbols::right_up
+ Mv::to(y + height - 1, x) + Symbols::left_down
+ Mv::to(y + height - 1, x + width - 1) + Symbols::right_down;
//? Draw titles if defined
if (not title.empty()) {
out += Mv::to(y, x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + title +
Fx::ub + lcolor + Symbols::title_right;
out += Mv::to(y, x + 2) + Symbols::title_left + Fx::b + numbering + Theme::c("title") + title
+ Fx::ub + line_color + Symbols::title_right;
}
if (not title2.empty()) {
out += Mv::to(y + height - 1, x + 2) + Symbols::title_left + Theme::c("title") + title2 +
Fx::ub + lcolor + Symbols::title_right;
out += Mv::to(y + height - 1, x + 2) + Symbols::title_left + Theme::c("title") + title2
+ Fx::ub + line_color + Symbols::title_right;
}
return out + Fx::reset + Mv::to(y + 1, x + 1);
}
//* Meter class ------------------------------------------------------------------------------------------------------------>
void Meter::operator()(int width, string color_gradient, bool invert) {
this->width = width;
this->color_gradient = color_gradient;
this->invert = invert;
cache.clear();
Meter::Meter(const int width, const string& color_gradient, const bool invert) : width(width), color_gradient(color_gradient), invert(invert) {
cache.insert(cache.begin(), 101, "");
}
@ -152,7 +235,7 @@ namespace Draw {
value = clamp(value, 0, 100);
if (not cache.at(value).empty()) return cache.at(value);
string& out = cache.at(value);
for (int i : iota(1, width + 1)) {
for (const int& i : iota(1, width + 1)) {
int y = round((double)i * 100.0 / width);
if (value >= y)
out += Theme::g(color_gradient)[invert ? 100 - y : y] + Symbols::meter;
@ -169,7 +252,7 @@ namespace Draw {
void Graph::_create(const deque<long long>& data, int data_offset) {
const bool mult = (data.size() - data_offset > 1);
if (mult and (data.size() - data_offset) % 2 != 0) data_offset--;
auto& graph_symbol = Symbols::graph_symbols.at(symbol + '_' + (invert ? "down" : "up"));
const auto& graph_symbol = Symbols::graph_symbols.at(symbol + '_' + (invert ? "down" : "up"));
array<int, 2> result;
const float mod = (height == 1) ? 0.3 : 0.1;
long long data_value = 0;
@ -187,12 +270,12 @@ namespace Draw {
if (max_value > 0) data_value = clamp((data_value + offset) * 100 / max_value, 0ll, 100ll);
//? Vertical iteration over height of graph
for (int horizon : iota(0, height)) {
int cur_high = (height > 1) ? round(100.0 * (height - horizon) / height) : 100;
int cur_low = (height > 1) ? round(100.0 * (height - (horizon + 1)) / height) : 0;
int clamp_min = (no_zero and horizon == height - 1 and i != -1) ? 1 : 0;
for (const int& horizon : iota(0, height)) {
const int cur_high = (height > 1) ? round(100.0 * (height - horizon) / height) : 100;
const int cur_low = (height > 1) ? round(100.0 * (height - (horizon + 1)) / height) : 0;
const int clamp_min = (no_zero and horizon == height - 1 and i != -1) ? 1 : 0;
//? Calculate previous + current value to fit two values in 1 braille character
for (int ai = 0; auto value : {last, data_value}) {
for (int ai = 0; const auto& value : {last, data_value}) {
if (value >= cur_high)
result[ai++] = 4;
else if (value <= cur_low)
@ -214,7 +297,7 @@ namespace Draw {
out += graphs[current][0];
}
else {
for (int i : iota(0, height)) {
for (const int& i : iota(0, height)) {
if (i > 0) out += Mv::d(1) + Mv::l(width);
if (not color_gradient.empty())
out += (invert) ? Theme::g(color_gradient)[i * 100 / (height - 1)] : Theme::g(color_gradient)[100 - (i * 100 / (height - 1))];
@ -224,12 +307,10 @@ namespace Draw {
if (not color_gradient.empty()) out += Fx::reset;
}
void Graph::operator()(int width, int height, string color_gradient, const deque<long long>& data, string symbol, bool invert, bool no_zero, long long max_value, long long offset) {
graphs[true].clear(); graphs[false].clear();
this->width = width; this->height = height;
this->invert = invert; this->offset = offset;
this->no_zero = no_zero;
this->color_gradient = color_gradient;
Graph::Graph() {};
Graph::Graph(int width, int height, const string& color_gradient, const deque<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) {
if (Config::getB("tty_mode") or symbol == "tty") {
tty_mode = true;
this->symbol = "tty";
@ -243,21 +324,22 @@ namespace Draw {
if (value_width > width) data_offset = data.size() - width * 2;
//? Populate the two switching graph vectors and fill empty space if data size < width
for (int i : iota(0, height * 2)) {
for (const int& i : iota(0, height * 2)) {
if (tty_mode and i % 2 != current) continue;
graphs[(i % 2 != 0)].push_back((value_width < width) ? ((height == 1) ? Mv::r(1) : ""s) * (width - value_width) : "");
}
if (data.size() == 0) return;
this->_create(data, data_offset);
this->_create((data.size() == 1 ? deque{0, data[0]} : data), data_offset);
}
string& Graph::operator()(const deque<long long>& data, bool data_same) {
string& Graph::operator()(const deque<long long>& data, const bool data_same) {
if (data_same) return out;
//? Make room for new characters on graph
// bool select_graph = tty_mode ? current : not current;
for (int i : iota(0, height)) {
if (graphs[current][i][1] == '[') graphs[current][i].erase(0, 4);
else graphs[current][i].erase(0, 3);
bool select_graph = (tty_mode) ? current : not current;
for (const int& i : iota(0, height)) {
if (graphs[select_graph][i][1] == '[') graphs[select_graph][i].erase(0, 4);
else graphs[select_graph][i].erase(0, 3);
}
this->_create(data, (int)data.size() - 1);
return out;
@ -345,6 +427,7 @@ namespace Proc {
unordered_flat_map<size_t, Draw::Graph> p_graphs;
unordered_flat_map<size_t, int> p_counters;
int counter = 0;
Draw::TextEdit filter;
string box;
@ -396,11 +479,9 @@ namespace Proc {
}
string draw(const vector<proc_info>& plist, const bool force_redraw, const bool data_same) {
auto& filter = Config::getS("proc_filter");
auto& filtering = Config::getB("proc_filtering");
auto& proc_tree = Config::getB("proc_tree");
const bool show_detailed = (Config::getB("show_detailed") and Proc::detailed.last_pid == (size_t)Config::getI("detailed_pid"));
const bool proc_gradient = (Config::getB("proc_gradient") and not Config::getB("tty_mode"));
const bool proc_gradient = (Config::getB("proc_gradient") and not Config::getB("tty_mode") and not Config::getB("lowcolor"));
auto& proc_colors = Config::getB("proc_colors");
const auto& graph_symbol = (Config::getB("tty_mode") ? "tty" : Config::getS("graph_symbol_proc"));
const auto& graph_bg = Symbols::graph_symbols.at((graph_symbol == "default" ? "braille_up" : graph_symbol + "_up"))[1];
@ -417,11 +498,48 @@ namespace Proc {
out = box;
const string title_left = Theme::c("proc_box") + Symbols::title_left;
const string title_right = Theme::c("proc_box") + Symbols::title_right;
//? Buttons etc. in box titlebar
out += Mv::to(y, x) + Mv::r(12)
+ trans("Filter: " + filter + (filtering ? Fx::bl + ""s + Fx::reset : " "))
+ trans(rjust("Per core: " + (Config::getB("proc_per_core") ? "On "s : "Off"s) + " Sorting: "
+ string(Config::getS("proc_sorting")), width - 23 - ulen(filter)));
const auto& filtering = Config::getB("proc_filtering"); // ? filter(20) : Config::getS("proc_filter"))
const auto filter_text = (filtering) ? filter(max(6, width - 58)) : uresize(Config::getS("proc_filter"), max(6, width - 58));
//? Filter
out += Mv::to(y, x+9) + title_left + (not filter_text.empty() ? Fx::b : "") + Theme::c("hi_fg") + 'f'
+ Theme::c("title") + (not filter_text.empty() ? ' ' + filter_text : "ilter")
+ (not filtering and not filter_text.empty() ? Theme::c("hi_fg") + " del" : "")
+ (filtering ? Theme::c("hi_fg") + ' ' + Symbols::enter : "") + Fx::ub + title_right;
if (not filtering) {
int f_len = (filter_text.empty() ? 6 : ulen(filter_text) + 2);
Input::mouse_mappings["f"] = {y, x + 10, 1, f_len};
if (filter_text.empty() and Input::mouse_mappings.contains("delete"))
Input::mouse_mappings.erase("delete");
else if (not filter_text.empty())
Input::mouse_mappings["delete"] = {y, x + 11 + f_len, 1, 3};
}
//? per-core, reverse, tree and sorting
const auto& sorting = Config::getS("proc_sorting");
const int sort_len = sorting.size();
const int sort_pos = x + width - sort_len - 8;
if (width > 55 + sort_len) {
out += Mv::to(y, sort_pos - 25) + title_left + (Config::getB("proc_per_core") ? Fx::b : "") + Theme::c("title")
+ "per-" + Theme::c("hi_fg") + 'c' + Theme::c("title") + "ore" + Fx::ub + title_right;
}
if (width > 45 + sort_len) {
out += Mv::to(y, sort_pos - 15) + title_left + (Config::getB("proc_reversed") ? Fx::b : "") + Theme::c("hi_fg")
+ 'r' + Theme::c("title") + "everse" + Fx::ub + title_right;
}
if (width > 35 + sort_len) {
out += Mv::to(y, sort_pos - 6) + title_left + (Config::getB("proc_tree") ? Fx::b : "") + Theme::c("title") + "tre"
+ Theme::c("hi_fg") + 'e' + Fx::ub + title_right;
}
out += Mv::to(y, sort_pos) + title_left + Fx::b + Theme::c("hi_fg") + "< " + Theme::c("title") + sorting + Theme::c("hi_fg")
+ " >" + Fx::ub + title_right;
// out += Mv::to(y, x) + Mv::r(12)
// + trans("Filter: " + filter_text)
// + trans(rjust("Per core: " + (Config::getB("proc_per_core") ? "On "s : "Off"s) + " Sorting: "
// + string(Config::getS("proc_sorting")), width - 23 - ulen(filter_text)));
//? Labels for fields in list
if (not proc_tree)
@ -436,8 +554,6 @@ namespace Proc {
out += Mv::to(y+1, x+1) + Theme::c("title") + Fx::b + ljust("Tree:", width - 40)
+ "Threads: " + ljust("User:", 10) + " " + rjust("MemB", 5)
+ " " + rjust("Cpu%", 10) + Fx::ub;
Input::mouse_mappings["down"] = {2, 2, 10, 10};
}
//* Check bounds of current selection and view
@ -460,7 +576,7 @@ namespace Proc {
//? Update graphs for processes with above 0.0% cpu usage, delete if below 0.1% 10x times
if (not data_same and (p.cpu_p > 0 or p_counters.contains(p.pid))) {
if (not p_graphs.contains(p.pid)) {
p_graphs[p.pid](5, 1, "", {0}, graph_symbol);
p_graphs[p.pid] = {5, 1, "", {}, graph_symbol};
p_counters[p.pid] = 0;
}
else if (p.cpu_p < 0.1) {

View File

@ -27,18 +27,29 @@ using std::string, std::vector, robin_hood::unordered_flat_map, std::deque;
namespace Draw {
//* An editable text field
class TextEdit {
size_t pos = 0;
size_t upos = 0;
public:
string text;
TextEdit();
TextEdit(string text);
bool command(const string& key);
string operator()(const size_t limit=0);
};
//* Create a box and return as a string
string createBox(int x, int y, int width, int height, string line_color="", bool fill=false, string title="", string title2="", int num=0);
string createBox(const int x, const int y, const int width, const int height, string line_color="", const bool fill=false, const string title="", const string title2="", const int num=0);
//* Class holding a percentage meter
class Meter {
string color_gradient;
int width = 0;
bool invert = false;
const int width;
const string color_gradient;
const bool invert;
vector<string> cache;
public:
//* Set meter options
void operator()(int width, string color_gradient, bool invert = false);
Meter(const int width, const string& color_gradient, const bool invert = false);
//* Return a string representation of the meter with given value
string operator()(int value);
@ -46,21 +57,32 @@ namespace Draw {
//* Class holding a percentage graph
class Graph {
string out, color_gradient, symbol = "default";
int width = 0, height = 0;
long long last = 0, max_value = 0, offset = 0;
bool current = true, no_zero = false, invert = false, tty_mode = false;
int width, height;
string color_gradient;
string out, symbol = "default";
bool invert, no_zero;
long long offset;
long long last = 0, max_value = 0;
bool current = true, tty_mode = false;
unordered_flat_map<bool, vector<string>> graphs = { {true, {}}, {false, {}}};
//* Create two representations of the graph to switch between to represent two values for each braille character
void _create(const deque<long long>& data, int data_offset);
public:
//* Set graph options and initialize with data
void operator()(int width, int height, string color_gradient, const deque<long long>& data, string symbol="default", bool invert=false, bool no_zero=false, long long max_value=0, long long offset=0);
Graph();
Graph( int width,
int height,
const string& color_gradient,
const deque<long long>& data,
const string& symbol="default",
bool invert=false,
bool no_zero=false,
long long max_value=0,
long long offset=0);
//* Add last value from back of <data> and return string representation of graph
string& operator()(const deque<long long>& data, bool data_same=false);
string& operator()(const deque<long long>& data, const bool data_same=false);
//* Return string representation of graph
string& operator()();
@ -69,4 +91,8 @@ namespace Draw {
//* Calculate sizes of boxes, draw outlines and save to enabled boxes namespaces
void calcSizes();
}
namespace Proc {
extern Draw::TextEdit filter;
}

View File

@ -23,6 +23,7 @@ tab-size = 4
#include <btop_config.hpp>
#include <btop_shared.hpp>
#include <btop_menu.hpp>
#include <btop_draw.hpp>
using std::cin, std::string_literals::operator""s;
using namespace Tools;
@ -72,6 +73,7 @@ namespace Input {
unordered_flat_map<string, Mouse_loc> mouse_mappings;
string last = "";
string old_filter;
bool poll(int timeout) {
if (timeout < 1) return cin.rdbuf()->in_avail() > 0;
@ -116,6 +118,12 @@ namespace Input {
else
key.clear();
if (Config::getB("proc_filtering")) {
if (mouse_event == "mouse_click") last = mouse_event;
else last.clear();
return last;
}
//? Get column and line position of mouse and check for any actions mapped to current position
if (not key.empty()) {
try {
@ -175,23 +183,24 @@ namespace Input {
if (Proc::shown) {
bool keep_going = false;
if (filtering) {
string filter = Config::getS("proc_filter");
if (key == "enter")
if (key == "enter") {
Config::set("proc_filter", Proc::filter.text);
Config::set("proc_filtering", false);
else if (key == "backspace" and not filter.empty())
filter = uresize(filter, ulen(filter) - 1);
else if (key == "space")
filter.push_back(' ');
else if (ulen(key) == 1)
filter.append(key);
old_filter.clear();
}
else if (key == "escape" or key == "mouse_click") {
Config::set("proc_filter", old_filter);
Config::set("proc_filtering", false);
old_filter.clear();
}
else if (Proc::filter.command(key)) {
if (Config::getS("proc_filter") != Proc::filter.text)
Config::set("proc_filter", Proc::filter.text);
else
recollect = false;
}
else
return;
Config::set("proc_filter", filter);
}
else if (key == "left") {
int cur_i = v_index(Proc::sort_vector, Config::getS("proc_sorting"));
@ -207,6 +216,8 @@ namespace Input {
}
else if (key == "f") {
Config::flip("proc_filtering");
Proc::filter = { Config::getS("proc_filter") };
old_filter = Proc::filter.text;
recollect = false;
}
else if (key == "t")

View File

@ -34,9 +34,10 @@ using robin_hood::unordered_flat_map, std::array, std::string, std::atomic;
namespace Input {
struct Mouse_loc {
int col, line, width, height;
int line, col, height, width;
};
//? line, col, height, width
extern unordered_flat_map<string, Mouse_loc> mouse_mappings;
extern atomic<bool> interrupt;

View File

@ -56,13 +56,12 @@ namespace Shared {
void init() {
proc_path = (fs::is_directory(fs::path("/proc")) and access("/proc", R_OK) != -1) ? "/proc" : "";
if (proc_path.empty()) {
Global::exit_error_msg = "Proc filesystem not found or no permission to read from it!";
clean_quit(1);
}
if (proc_path.empty())
throw std::runtime_error("Proc filesystem not found or no permission to read from it!");
passwd_path = (access("/etc/passwd", R_OK) != -1) ? fs::path("/etc/passwd") : passwd_path;
if (passwd_path.empty()) Logger::warning("Could not read /etc/passwd, will show UID instead of username.");
passwd_path = (fs::is_regular_file(fs::path("/etc/passwd")) and access("/etc/passwd", R_OK) != -1) ? "/etc/passwd" : "";
if (passwd_path.empty())
Logger::warning("Could not read /etc/passwd, will show UID instead of username.");
page_size = sysconf(_SC_PAGE_SIZE);
if (page_size <= 0) {

View File

@ -62,6 +62,7 @@ namespace Shared {
void init();
}
namespace Cpu {
extern string box, cpuName;
extern int x, y, width, height;

View File

@ -48,24 +48,24 @@ namespace Theme {
{ "main_bg", "#00" },
{ "main_fg", "#cc" },
{ "title", "#ee" },
{ "hi_fg", "#969696" },
{ "selected_bg", "#7e2626" },
{ "hi_fg", "#b54040" },
{ "selected_bg", "#6a2f2f" },
{ "selected_fg", "#ee" },
{ "inactive_fg", "#40" },
{ "graph_text", "#60" },
{ "meter_bg", "#40" },
{ "proc_misc", "#0de756" },
{ "cpu_box", "#3d7b46" },
{ "mem_box", "#8a882e" },
{ "net_box", "#423ba5" },
{ "proc_box", "#923535" },
{ "cpu_box", "#556d59" },
{ "mem_box", "#6c6c4b" },
{ "net_box", "#5c588d" },
{ "proc_box", "#805252" },
{ "div_line", "#30" },
{ "temp_start", "#4897d4" },
{ "temp_mid", "#5474e8" },
{ "temp_end", "#ff40b6" },
{ "cpu_start", "#50f095" },
{ "cpu_mid", "#f2e266" },
{ "cpu_end", "#fa1e1e" },
{ "cpu_start", "#77ca9b" },
{ "cpu_mid", "#cbc06c" },
{ "cpu_end", "#dc4c4c" },
{ "free_start", "#223014" },
{ "free_mid", "#b5e685" },
{ "free_end", "#dcff85" },
@ -93,7 +93,7 @@ namespace Theme {
{ "main_bg", "\x1b[0;40m" },
{ "main_fg", "\x1b[37m" },
{ "title", "\x1b[97m" },
{ "hi_fg", "\x1b[31m" },
{ "hi_fg", "\x1b[91m" },
{ "selected_bg", "\x1b[41m" },
{ "selected_fg", "\x1b[97m" },
{ "inactive_fg", "\x1b[90m" },
@ -138,7 +138,7 @@ namespace Theme {
//* Convert 24-bit colors to 256 colors
int truecolor_to_256(const int& r, const int& g, const int& b) {
//? Use upper 232-255 greyscale values if the downscaled red, green and blue are the same value
if (int red = round((double)r / 11); red == round((double)g / 11) and round((double)g / 11) == round((double)b / 11)) {
if (const int red = round((double)r / 11); red == round((double)g / 11) and red == round((double)b / 11)) {
return 232 + red;
}
//? Else use 6x6x6 color cube to calculate approximate colors

View File

@ -114,7 +114,7 @@ namespace Term {
namespace Tools {
string uresize(string str, const size_t len) {
if (len < 1) return "";
if (len < 1 or str.empty()) return "";
for (size_t x = 0, i = 0; i < str.size(); i++) {
if ((static_cast<unsigned char>(str.at(i)) & 0xC0) != 0x80) x++;
if (x == len + 1) {
@ -126,6 +126,22 @@ namespace Tools {
return str;
}
string luresize(string str, const size_t len) {
if (len < 1 or str.empty()) return "";
for (size_t x = 0, last_pos = 0, i = str.size() - 1; i > 0 ; i--) {
if ((static_cast<unsigned char>(str.at(i)) & 0xC0) != 0x80) {
x++;
last_pos = i;
}
if (x == len) {
str = str.substr(last_pos);
str.shrink_to_fit();
break;
}
}
return str;
}
string ltrim(const string& str, const string& t_str) {
string_view str_v = str;
while (str_v.starts_with(t_str)) str_v.remove_prefix(t_str.size());

View File

@ -133,6 +133,9 @@ namespace Tools {
//* Resize a string consisting of UTF8 characters (only reduces size)
string uresize(const string str, const size_t len);
//* Resize a string consisting of UTF8 characters from left (only reduces size)
string luresize(const string str, const size_t len);
//* Return <str> with only uppercase characters
inline string str_to_upper(string str) {
std::ranges::for_each(str, [](auto& c) { c = ::toupper(c); } );