From 55e2a3f02ba0830b50e15d00ac003a01b874a5c7 Mon Sep 17 00:00:00 2001 From: aristocratos Date: Sat, 8 May 2021 14:56:48 +0200 Subject: [PATCH] Split up code in multiple files --- .gitignore | 4 +- Include/btop_config.h | 124 ++++++++++ Include/btop_globs.h | 114 +++++++++ Include/btop_tools.h | 327 +++++++++++++++++++++++++ Makefile | 14 +- btop.cpp | 541 ++++++------------------------------------ 6 files changed, 653 insertions(+), 471 deletions(-) create mode 100644 Include/btop_config.h create mode 100644 Include/btop_globs.h create mode 100644 Include/btop_tools.h diff --git a/.gitignore b/.gitignore index 722fa72..bf37c5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -* -!*.* - # Prerequisites *.d @@ -35,4 +32,5 @@ *.app build +bin btop diff --git a/Include/btop_config.h b/Include/btop_config.h new file mode 100644 index 0000000..e3e6ec0 --- /dev/null +++ b/Include/btop_config.h @@ -0,0 +1,124 @@ +/* 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 +*/ + +#ifndef _btop_config_included_ +#define _btop_config_included_ + + +#include +#include +#include +#include + +using std::string; +using std::to_string; +using std::vector; +using std::map; + +#define Bool bool() +#define Int int() +#define String string() + + +//* Used for classes and functions needing pre-initialised values +namespace State { + bool truecolor = true; + string fg, bg; +} + +class C_Config { + map strings = { + {"color_theme", "Default"}, + {"shown_boxes", "cpu mem net proc"}, + {"proc_sorting", "cpu lazy"}, + {"cpu_graph_upper", "total"}, + {"cpu_graph_lower", "total"}, + {"cpu_sensor", "Auto"}, + {"temp_scale", "celsius"}, + {"draw_clock", "%X"}, + {"custom_cpu_name", ""}, + {"disks_filter", ""}, + {"io_graph_speeds", ""}, + {"net_download", "10M"}, + {"net_upload", "10M"}, + {"net_iface", ""}, + {"log_level", "WARNING"} + }; + map bools = { + {"theme_background", true}, + {"truecolor", true}, + {"proc_reversed", false}, + {"proc_tree", false}, + {"proc_colors", true}, + {"proc_gradient", true}, + {"proc_per_core", false}, + {"proc_mem_bytes", true}, + {"cpu_invert_lower", true}, + {"cpu_single_graph", false}, + {"show_uptime", true}, + {"check_temp", true}, + {"show_coretemp", true}, + {"show_cpu_freq", true}, + {"background_update", true}, + {"update_check", true}, + {"mem_graphs", true}, + {"show_swap", true}, + {"swap_disk", true}, + {"show_disks", true}, + {"only_physical", true}, + {"use_fstab", false}, + {"show_io_stat", true}, + {"io_mode", false}, + {"io_graph_combined", false}, + {"net_color_fixed", false}, + {"net_auto", true}, + {"net_sync", false}, + {"show_battery", true}, + {"show_init", false} + }; + map ints = { + {"update_ms", 2000}, + {"proc_update_mult", 2}, + {"tree_depth", 3} + }; +public: + C_Config(){ + bools["truecolor"] = "true"; + strings["color_theme"] = "Default"; + ints["tree_depth"] = 3; + + State::truecolor = bools["truecolor"]; + } + + //* Return config value as a bool + bool operator()(bool b_type, string name){ + return bools.at(name); + } + + //* Return config value as a int + int operator()(int i_type, string name){ + return ints.at(name); + } + + //* Return config value as a string + string operator()(string s_type, string name){ + return strings.at(name); + } +}; + +#endif \ No newline at end of file diff --git a/Include/btop_globs.h b/Include/btop_globs.h new file mode 100644 index 0000000..fe0caba --- /dev/null +++ b/Include/btop_globs.h @@ -0,0 +1,114 @@ +/* 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 +*/ + +#ifndef _btop_globs_included_ +#define _btop_globs_included_ + +#include +#include +#include + +using std::string, std::vector, std::map; + +namespace Global { + const map Default_theme = { + { "main_bg", "#00" }, + { "main_fg", "#cc" }, + { "title", "#ee" }, + { "hi_fg", "#969696" }, + { "selected_bg", "#7e2626" }, + { "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" }, + { "div_line", "#30" }, + { "temp_start", "#4897d4" }, + { "temp_mid", "#5474e8" }, + { "temp_end", "#ff40b6" }, + { "cpu_start", "#50f095" }, + { "cpu_mid", "#f2e266" }, + { "cpu_end", "#fa1e1e" }, + { "free_start", "#223014" }, + { "free_mid", "#b5e685" }, + { "free_end", "#dcff85" }, + { "cached_start", "#0b1a29" }, + { "cached_mid", "#74e6fc" }, + { "cached_end", "#26c5ff" }, + { "available_start", "#292107" }, + { "available_mid", "#ffd77a" }, + { "available_end", "#ffb814" }, + { "used_start", "#3b1f1c" }, + { "used_mid", "#d9626d" }, + { "used_end", "#ff4769" }, + { "download_start", "#231a63" }, + { "download_mid", "#4f43a3" }, + { "download_end", "#b0a9de" }, + { "upload_start", "#510554" }, + { "upload_mid", "#7d4180" }, + { "upload_end", "#dcafde" }, + { "process_start", "#80d0a3" }, + { "process_mid", "#dcd179" }, + { "process_end", "#d45454" } + }; + + const map>> Menus = { + { "options", { + { "normal", { + "┌─┐┌─┐┌┬┐┬┌─┐┌┐┌┌─┐", + "│ │├─┘ │ ││ ││││└─┐", + "└─┘┴ ┴ ┴└─┘┘└┘└─┘" + } }, + { "selected", { + "╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗", + "║ ║╠═╝ ║ ║║ ║║║║╚═╗", + "╚═╝╩ ╩ ╩╚═╝╝╚╝╚═╝" + } } + } }, + { "help", { + { "normal", { + "┬ ┬┌─┐┬ ┌─┐", + "├─┤├┤ │ ├─┘", + "┴ ┴└─┘┴─┘┴ " + } }, + { "selected", { + "╦ ╦╔═╗╦ ╔═╗", + "╠═╣║╣ ║ ╠═╝", + "╩ ╩╚═╝╩═╝╩ " + } } + } }, + { "quit", { + { "normal", { + "┌─┐ ┬ ┬ ┬┌┬┐", + "│─┼┐│ │ │ │ ", + "└─┘└└─┘ ┴ ┴ " + } }, + { "selected", { + "╔═╗ ╦ ╦ ╦╔╦╗ ", + "║═╬╗║ ║ ║ ║ ", + "╚═╝╚╚═╝ ╩ ╩ " + } } + } } + }; + } + +#endif \ No newline at end of file diff --git a/Include/btop_tools.h b/Include/btop_tools.h new file mode 100644 index 0000000..9a2ce66 --- /dev/null +++ b/Include/btop_tools.h @@ -0,0 +1,327 @@ +/* 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 +*/ + +#ifndef _btop_tools_included_ +#define _btop_tools_included_ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::string, std::to_string, std::round, std::vector, std::map, std::cin; + +//? ------------------------------------------------- NAMESPACES ------------------------------------------------------ + +//* Collection of escape codes for text style and formatting +namespace Fx { + //* Escape sequence start + const string e = "\x1b["; + //* Bold on + const string b = e + "1m"; + //* Bold off + const string ub = e + "22m"; + //* Dark on + const string d = e + "2m"; + //* Dark off + const string ud = e + "22m"; + //* Italic on + const string i = e + "3m"; + //* Italic off + const string ui = e + "23m"; + //* Underline on + const string ul = e + "4m"; + //* Underline off + const string uul = e + "24m"; + //* Blink on + const string bl = e + "5m"; + //* Blink off + const string ubl = e + "25m"; + //* Strike / crossed-out on + const string s = e + "9m"; + //* Strike / crossed-out off + const string us = e + "29m"; + //* Reset foreground/background color and text effects + const string reset_base = e + "0m"; + //* Reset text effects and restore default foregrund and background color < Changed by C_Theme + string reset = reset_base; +}; + +//* Collection of escape codes and functions for cursor manipulation +namespace Mv { + //* Move cursor to , + inline string to(int line, int col){ return Fx::e + to_string(line) + ";" + to_string(col) + "f";} + //* Move cursor right columns + inline string r(int x){ return Fx::e + to_string(x) + "C";} + //* Move cursor left columns + inline string l(int x){ return Fx::e + to_string(x) + "D";} + //* Move cursor up x lines + inline string u(int x){ return Fx::e + to_string(x) + "A";} + //* Move cursor down x lines + inline string d(int x) { return Fx::e + to_string(x) + "B";} + //* Save cursor position + const string save = Fx::e + "s"; + //* Restore saved cursor postion + const string restore = Fx::e + "u"; +}; + +//? --------------------------------------------------- CLASSES ----------------------------------------------------- + +//* Collection of escape codes and functions for terminal manipulation +class C_Term { + struct termios initial_settings; +public: + bool initialized = false; + int width = 0; + int height = 0; + bool resized = false; + + //* Hide terminal cursor + const string hide_cursor = Fx::e + "?25l"; + + //* Show terminal cursor + const string show_cursor = Fx::e + "?25h"; + + //* Switch to alternate screen + const string alt_screen = Fx::e + "?1049h"; + + //* Switch to normal screen + const string normal_screen = Fx::e + "?1049l"; + + //* Clear screen and set cursor to position 0,0 + const string clear = Fx::e + "2J" + Fx::e + "0;0f"; + + //* Enable reporting of mouse position on click and release + const string mouse_on = Fx::e + "?1002h" + Fx::e + "?1015h" + Fx::e + "?1006h"; + + //* Disable mouse reporting + const string mouse_off = Fx::e + "?1002l"; + + //* Enable reporting of mouse position at any movement + const string mouse_direct_on = Fx::e + "?1003h"; + + //* Disable direct mouse reporting + const string mouse_direct_off = Fx::e + "?1003l"; + + //* Toggle need for return key when reading input + bool linebuffered(bool on=true){ + struct termios settings; + if (tcgetattr(STDIN_FILENO, &settings)) return false; + if (on) settings.c_lflag |= ICANON; + else settings.c_lflag &= ~(ICANON); + if (tcsetattr(STDIN_FILENO, TCSANOW, &settings)) return false; + if (on) setlinebuf(stdin); + else setbuf(stdin, NULL); + return true; + } + + //* Toggle terminal input echo + bool echo(bool on=true){ + struct termios settings; + if (tcgetattr(STDIN_FILENO, &settings)) return false; + if (on) settings.c_lflag |= ECHO; + else settings.c_lflag &= ~(ECHO); + return 0 == tcsetattr(STDIN_FILENO, TCSANOW, &settings); + } + + //* Refresh variables holding current terminal width and height and return true if resized + bool refresh(){ + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + resized = (width != w.ws_col || height != w.ws_row) ? true : false; + width = w.ws_col; + height = w.ws_row; + return resized; + } + + //* Check for a valid tty, save terminal options and set new options + bool init(){ + if (!initialized){ + initialized = (bool)isatty(STDIN_FILENO); + if (initialized) { + initialized = (0 == tcgetattr(STDIN_FILENO, &initial_settings)); + cin.sync_with_stdio(false); + cin.tie(NULL); + echo(false); + linebuffered(false); + } + } + return initialized; + } + + //* Restore terminal options + void restore(){ + if (initialized) { + echo(true); + linebuffered(true); + tcsetattr(STDIN_FILENO, TCSANOW, &initial_settings); + initialized = false; + } + } + + C_Term() { + init(); + refresh(); + resized = false; + } + +}; + +//? --------------------------------------------------- FUNCTIONS ----------------------------------------------------- + +//* Return number of UTF8 characters in a string +inline size_t ulen(const string& str){ + size_t len = 0; + for (char c : str) if ((c & 0xC0) != 0x80) ++len; + return len; +} + +//* Return current time since epoch in milliseconds +uint64_t time_ms(){ + return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); +} + +//* Check if a string is a valid bool value +bool isbool(string str){ + return (str == "true") | (str == "false") | (str == "True") | (str == "False"); +} + +//* Check if a string is a valid integer value +bool isint(string str){ + return all_of(str.begin(), str.end(), ::isdigit); +} + +//* Convert 24-bit colors to 256 colors using 6x6x6 color cube +int truecolor_to_256(unsigned r, unsigned g, unsigned b){ + if (r / 11 == g / 11 && g / 11 == b / 11) { + return 232 + r / 11; + } else { + return round((float)(r / 51)) * 36 + round((float)(g / 51)) * 6 + round((float)(b / 51)) + 16; + } +} + +//* Generate escape sequence for 24-bit or 256 color and return as a string +//* Args hexa: ["#000000"-"#ffffff"] for color, ["#00"-"#ff"] for greyscale +//* t_to_256: [true|false] convert 24bit value to 256 color value +//* depth: ["fg"|"bg"] for either a foreground color or a background color +string hex_to_color(string hexa, bool t_to_256=false, string depth="fg"){ + if (hexa.size() > 1){ + hexa.erase(0, 1); + for (auto& c : hexa) if (!isxdigit(c)) return ""; + depth = (depth == "fg") ? "38" : "48"; + string pre = Fx::e + depth + ";"; + pre += (t_to_256) ? "5;" : "2;"; + + if (hexa.size() == 2){ + unsigned h_int = stoi(hexa, 0, 16); + if (t_to_256){ + return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m"; + } else { + string h_str = to_string(h_int); + return pre + h_str + ";" + h_str + ";" + h_str + "m"; + } + } + else if (hexa.size() == 6){ + if (t_to_256){ + return pre + to_string(truecolor_to_256( + stoi(hexa.substr(0, 2), 0, 16), + stoi(hexa.substr(2, 2), 0, 16), + stoi(hexa.substr(4, 2), 0, 16))) + "m"; + } else { + return pre + + to_string(stoi(hexa.substr(0, 2), 0, 16)) + ";" + + to_string(stoi(hexa.substr(2, 2), 0, 16)) + ";" + + to_string(stoi(hexa.substr(4, 2), 0, 16)) + "m"; + } + } + } + return ""; +} + +//* Generate escape sequence for 24-bit or 256 color and return as a string +//* Args r: [0-255], g: [0-255], b: [0-255] +//* t_to_256: [true|false] convert 24bit value to 256 color value +//* depth: ["fg"|"bg"] for either a foreground color or a background color +string dec_to_color(unsigned r, unsigned g, unsigned b, bool t_to_256=false, string depth="fg"){ + depth = (depth == "fg") ? "38" : "48"; + string pre = Fx::e + depth + ";"; + pre += (t_to_256) ? "5;" : "2;"; + r = (r > 255) ? 255 : r; + g = (g > 255) ? 255 : g; + b = (b > 255) ? 255 : b; + if (t_to_256) return pre + to_string(truecolor_to_256(r, g, b)) + "m"; + else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m"; +} + +//* Left-trim from and return string +string ltrim(string str, string t_str = " "){ + while (str.starts_with(t_str)) str.erase(0, t_str.size()); + return str; +} + +//* Right-trim from and return string +string rtrim(string str, string t_str = " "){ + while (str.ends_with(t_str)) str.resize(str.size() - t_str.size()); + return str; +} + +//* Left-right-trim from and return string +string trim(string str, string t_str = " "){ + return ltrim(rtrim(str, t_str), t_str); +} + +//* Split at (0 for unlimited) times and return vector +vector ssplit(string str, string delim = " ", int times = 0){ + vector out; + if (str != "" && delim != ""){ + size_t pos = 0; + int x = 0; + string tmp; + while ((pos = str.find(delim)) != string::npos){ + tmp = str.substr(0, pos); + if (tmp != delim && tmp != "") out.push_back(tmp); + str.erase(0, pos + delim.size()); + if (times > 0 && ++x >= times) break; + } + } + out.push_back(str); + return out; +} + +//* Return a map of "r", "g", "b", 0-255 values for a 24-bit color escape string +map c_to_rgb(string c_string){ + map rgb = {{"r", 0}, {"g", 0}, {"b", 0}}; + if (c_string.size() >= 14){ + c_string.erase(0, 7); + auto c_split = ssplit(c_string, ";"); + if (c_split.size() == 3){ + rgb["r"] = stoi(c_split[0]); + rgb["g"] = stoi(c_split[1]); + rgb["b"] = stoi(c_split[2].erase(c_split[2].size())); + } + } + return rgb; +} + +#endif \ No newline at end of file diff --git a/Makefile b/Makefile index f2d680a..a6cd154 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,16 @@ PREFIX ?= /usr/local DOCDIR ?= $(PREFIX)/share/btop/doc -CXX=g++ -CXXFLAGS=-std=c++20 -pthread +CXX = g++ +CXXFLAGS = -std=c++20 -pthread +INCLUDES = -I./Include btop: btop.cpp - $(CXX) $(CXXFLAGS) -o btop btop.cpp + @mkdir -p bin + $(CXX) $(CXXFLAGS) $(INCLUDES) -o bin/btop btop.cpp install: @mkdir -p $(DESTDIR)$(PREFIX)/bin - @cp -p btop $(DESTDIR)$(PREFIX)/bin/btop + @cp -p bin/btop $(DESTDIR)$(PREFIX)/bin/btop @mkdir -p $(DESTDIR)$(DOCDIR) @cp -p README.md $(DESTDIR)$(DOCDIR) @cp -pr themes $(DESTDIR)$(PREFIX)/share/btop @@ -19,5 +21,5 @@ uninstall: @rm -rf $(DESTDIR)$(DOCDIR) @rm -rf $(DESTDIR)$(PREFIX)/share/btop -distclean: - rm -f btop +clean: + rm -rf bin diff --git a/btop.cpp b/btop.cpp index 6f054f6..ee52778 100644 --- a/btop.cpp +++ b/btop.cpp @@ -31,159 +31,63 @@ tab-size = 4 #include #include #include +#include #include -#include -#include #include +#include +#include +#include + +#if defined(__linux__) + #define SYSTEM "linux" +#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__) + #include + #if defined(BSD) + #define SYSTEM "bsd" + #else + #define SYSTEM "unknown" + #endif +#elif defined(__APPLE__) && defined(__MACH__) + #include + #if TARGET_OS_MAC == 1 + #define SYSTEM "osx" + #else + #define SYSTEM "unknown" + #endif +#else + #define SYSTEM "unknown" +#endif + using namespace std; + //? ------------------------------------------------- GLOBALS --------------------------------------------------------- -const vector> BANNER_SRC = { - {"#E62525", "██████╗ ████████╗ ██████╗ ██████╗"}, - {"#CD2121", "██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ██╗ ██╗"}, - {"#B31D1D", "██████╔╝ ██║ ██║ ██║██████╔╝ ██████╗██████╗"}, - {"#9A1919", "██╔══██╗ ██║ ██║ ██║██╔═══╝ ╚═██╔═╝╚═██╔═╝"}, - {"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"}, - {"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"}, -}; +namespace Global { + const vector> Banner_src = { + {"#E62525", "██████╗ ████████╗ ██████╗ ██████╗"}, + {"#CD2121", "██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ██╗ ██╗"}, + {"#B31D1D", "██████╔╝ ██║ ██║ ██║██████╔╝ ██████╗██████╗"}, + {"#9A1919", "██╔══██╗ ██║ ██║ ██║██╔═══╝ ╚═██╔═╝╚═██╔═╝"}, + {"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"}, + {"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"}, + }; -const string VERSION = "0.0.1"; + const string Version = "0.0.1"; +} -const map DEFAULT_THEME = { - { "main_bg", "#00" }, - { "main_fg", "#cc" }, - { "title", "#ee" }, - { "hi_fg", "#969696" }, - { "selected_bg", "#7e2626" }, - { "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" }, - { "div_line", "#30" }, - { "temp_start", "#4897d4" }, - { "temp_mid", "#5474e8" }, - { "temp_end", "#ff40b6" }, - { "cpu_start", "#50f095" }, - { "cpu_mid", "#f2e266" }, - { "cpu_end", "#fa1e1e" }, - { "free_start", "#223014" }, - { "free_mid", "#b5e685" }, - { "free_end", "#dcff85" }, - { "cached_start", "#0b1a29" }, - { "cached_mid", "#74e6fc" }, - { "cached_end", "#26c5ff" }, - { "available_start", "#292107" }, - { "available_mid", "#ffd77a" }, - { "available_end", "#ffb814" }, - { "used_start", "#3b1f1c" }, - { "used_mid", "#d9626d" }, - { "used_end", "#ff4769" }, - { "download_start", "#231a63" }, - { "download_mid", "#4f43a3" }, - { "download_end", "#b0a9de" }, - { "upload_start", "#510554" }, - { "upload_mid", "#7d4180" }, - { "upload_end", "#dcafde" }, - { "process_start", "#80d0a3" }, - { "process_mid", "#dcd179" }, - { "process_end", "#d45454" } -}; - -const map>> MENUS = { - { "options", { - { "normal", - { "┌─┐┌─┐┌┬┐┬┌─┐┌┐┌┌─┐", - "│ │├─┘ │ ││ ││││└─┐", - "└─┘┴ ┴ ┴└─┘┘└┘└─┘" - } }, - { "selected", - { "╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗", - "║ ║╠═╝ ║ ║║ ║║║║╚═╗", - "╚═╝╩ ╩ ╩╚═╝╝╚╝╚═╝" - } } - } }, - { "help", { - { "normal", - { "┬ ┬┌─┐┬ ┌─┐", - "├─┤├┤ │ ├─┘", - "┴ ┴└─┘┴─┘┴ " - } }, - { "selected", - { "╦ ╦╔═╗╦ ╔═╗", - "╠═╣║╣ ║ ╠═╝", - "╩ ╩╚═╝╩═╝╩ " - } } - } }, - { "quit", { - { "normal", - { "┌─┐ ┬ ┬ ┬┌┬┐", - "│─┼┐│ │ │ │ ", - "└─┘└└─┘ ┴ ┴ " - } }, - { "selected", - { "╔═╗ ╦ ╦ ╦╔╦╗ ", - "║═╬╗║ ║ ║ ║ ", - "╚═╝╚╚═╝ ╩ ╩ " - } } - } } -}; - -#define Bool bool() -#define Int int() -#define String string() - -//? ------------------------------------------------- NAMESPACES ------------------------------------------------------ - -namespace State { - atomic MenuActive(false); -}; - -//? Collection of escape codes for text style and formatting -namespace Fx { - const string e = "\x1b["; //* Escape sequence start - const string r = e + "0m"; //* Reset foreground/background color and text effects - const string b = e + "1m"; //* Bold on - const string ub = e + "22m"; //* Bold off - const string d = e + "2m"; //* Dark on - const string ud = e + "22m"; //* Dark off - const string i = e + "3m"; //* Italic on - const string ui = e + "23m"; //* Italic off - const string ul = e + "4m"; //* Underline on - const string uul = e + "24m"; //* Underline off - const string bl = e + "5m"; //* Blink on - const string ubl = e + "25m"; //* Blink off - const string s = e + "9m"; //* Strike / crossed-out on - const string us = e + "29m"; //* Strike / crossed-out off -}; - -//? Collection of escape codes and functions for cursor manipulation -namespace Mv { - string to(int line, int col){ return Fx::e + to_string(line) + ";" + to_string(col) + "f";} //* Move cursor to line, column - string r(int x){ return Fx::e + to_string(x) + "C";} //* Move cursor right x columns - string l(int x){ return Fx::e + to_string(x) + "D";} //* Move cursor left x columns - string u(int x){ return Fx::e + to_string(x) + "A";} //* Move cursor up x lines - string d(int x) { return Fx::e + to_string(x) + "B";} //* Move cursor down x lines - const string save = Fx::e + "s"; //* Save cursor position - const string restore = Fx::e + "u"; //* Restore saved cursor postion -}; //? --------------------------------------- FUNCTIONS, STRUCTS & CLASSES ---------------------------------------------- -//? A simple argument parser +//* A simple argument parser void argumentParser(int argc, char **argv){ string argument; for(int i = 1; i < argc; i++) { argument = argv[i]; if (argument == "-v" || argument == "--version") { - cout << "btop version: " << VERSION << endl; + cout << "btop version: " << Global::Version << endl; exit(0); } else if (argument == "-h" || argument == "--help") { cout << "help here" << endl; @@ -196,291 +100,7 @@ void argumentParser(int argc, char **argv){ } } -//? Return number of UTF8 characters in a string -inline size_t ulen(const string& str){ - size_t len = 0; - for (char c : str) if ((c & 0xC0) != 0x80) ++len; - return len; -} - -//? Return current time since epoch in milliseconds -uint64_t time_ms(){ - return chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); -} - -//? Check if a string is a valid bool value -bool isbool(string str){ - return (str == "true") | (str == "false") | (str == "True") | (str == "False"); -} - -//? Check if a string is a valid integer value -bool isint(string str){ - return all_of(str.begin(), str.end(), ::isdigit); -} - -//? Convert 24-bit colors to 256 colors using 6x6x6 color cube -int truecolor_to_256(unsigned r, unsigned g, unsigned b){ - if (r / 11 == g / 11 && g / 11 == b / 11) { - return 232 + r / 11; - } else { - return round((float)(r / 51)) * 36 + round((float)(g / 51)) * 6 + round((float)(b / 51)) + 16; - } -} - -//? Generate escape sequence for 24-bit or 256 color and return as a string -//? Args hexa: ["#000000"-"#ffffff"] for color, ["#00"-"#ff"] for greyscale -//? t_to_256: [true|false] convert 24bit value to 256 color value -//? depth: ["fg"|"bg"] for either a foreground color or a background color -string hex_to_color(string hexa, bool t_to_256=false, string depth="fg"){ - if (hexa.size() > 1){ - hexa.erase(0, 1); - for (auto& c : hexa) if (!isxdigit(c)) return ""; - depth = (depth == "fg") ? "38" : "48"; - string pre = Fx::e + depth + ";"; - pre += (t_to_256) ? "5;" : "2;"; - - if (hexa.size() == 2){ - unsigned h_int = stoi(hexa, 0, 16); - if (t_to_256){ - return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m"; - } else { - string h_str = to_string(h_int); - return pre + h_str + ";" + h_str + ";" + h_str + "m"; - } - } - else if (hexa.size() == 6){ - if (t_to_256){ - return pre + to_string(truecolor_to_256( - stoi(hexa.substr(0, 2), 0, 16), - stoi(hexa.substr(2, 2), 0, 16), - stoi(hexa.substr(4, 2), 0, 16))) + "m"; - } else { - return pre + - to_string(stoi(hexa.substr(0, 2), 0, 16)) + ";" + - to_string(stoi(hexa.substr(2, 2), 0, 16)) + ";" + - to_string(stoi(hexa.substr(4, 2), 0, 16)) + "m"; - } - } - } - return ""; -} - -//? Generate escape sequence for 24-bit or 256 color and return as a string -//? Args r: [0-255], g: [0-255], b: [0-255] -//? t_to_256: [true|false] convert 24bit value to 256 color value -//? depth: ["fg"|"bg"] for either a foreground color or a background color -string dec_to_color(unsigned r, unsigned g, unsigned b, bool t_to_256=false, string depth="fg"){ - depth = (depth == "fg") ? "38" : "48"; - string pre = Fx::e + depth + ";"; - pre += (t_to_256) ? "5;" : "2;"; - r = (r > 255) ? 255 : r; - g = (g > 255) ? 255 : g; - b = (b > 255) ? 255 : b; - if (t_to_256) return pre + to_string(truecolor_to_256(r, g, b)) + "m"; - else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m"; -} - -//? Left-trim from and return string -string ltrim(string str, string t_str = " "){ - while (str.starts_with(t_str)) str.erase(0, t_str.size()); - return str; -} - -//? Right-trim from and return string -string rtrim(string str, string t_str = " "){ - while (str.ends_with(t_str)) str.resize(str.size() - t_str.size()); - return str; -} - -//? Left-right-trim from and return string -string trim(string str, string t_str = " "){ - return ltrim(rtrim(str, t_str), t_str); -} - -//? Split at (0 for unlimited) times and return vector -vector ssplit(string str, string delim = " ", int times = 0){ - vector out; - if (str != "" && delim != ""){ - size_t pos = 0; - int x = 0; - string tmp; - while ((pos = str.find(delim)) != string::npos){ - tmp = str.substr(0, pos); - if (tmp != delim && tmp != "") out.push_back(tmp); - str.erase(0, pos + delim.size()); - if (times > 0 && ++x >= times) break; - } - } - out.push_back(str); - return out; -} - -//? Return a map of "r", "g", "b", 0-255 values for a 24-bit color escape string -map c_to_rgb(string c_string){ - map rgb = {{"r", 0}, {"g", 0}, {"b", 0}}; - if (c_string.size() >= 14){ - c_string.erase(0, 7); - auto c_split = ssplit(c_string, ";"); - if (c_split.size() == 3){ - rgb["r"] = stoi(c_split[0]); - rgb["g"] = stoi(c_split[1]); - rgb["b"] = stoi(c_split[2].erase(c_split[2].size())); - } - } - return rgb; -} - -//? Collection of escape codes and functions for terminal manipulation -class C_Term { - bool initialized = false; - struct termios initial_settings; -public: - int width = 0; - int height = 0; - bool resized = false; - string fg = "" ; //* Default foreground color - string bg = ""; //* Default background color - const string hide_cursor = Fx::e + "?25l"; //* Hide terminal cursor - const string show_cursor = Fx::e + "?25h"; //* Show terminal cursor - const string alt_screen = Fx::e + "?1049h"; //* Switch to alternate screen - const string normal_screen = Fx::e + "?1049l"; //* Switch to normal screen - const string clear = Fx::e + "2J" + Fx::e + "0;0f"; //* Clear screen and set cursor to position 0,0 - const string mouse_on = Fx::e + "?1002h" + Fx::e + "?1015h" + Fx::e + "?1006h"; //* Enable reporting of mouse position on click and release - const string mouse_off = Fx::e + "?1002l"; //* Disable mouse reporting - const string mouse_direct_on = Fx::e + "?1003h"; //* Enable reporting of mouse position at any movement - const string mouse_direct_off = Fx::e + "?1003l"; //* Disable direct mouse reporting - - //? Save terminal options and check valid tty - bool init(){ - if (!initialized){ - initialized = (bool)isatty(STDIN_FILENO); - if (initialized) initialized = (0 == tcgetattr(STDIN_FILENO, &initial_settings)); - if (initialized) cin.sync_with_stdio(); - } - return initialized; - } - - //? Restore terminal options - void restore(){ - if (initialized) tcsetattr(STDIN_FILENO, TCSANOW, &initial_settings); - } - - //? Toggle need for return key when reading input - bool linebuffered(bool on=true){ - struct termios settings; - if (tcgetattr(STDIN_FILENO, &settings)) return false; - if (on) settings.c_lflag |= ICANON; - else settings.c_lflag &= ~(ICANON); - if (tcsetattr(STDIN_FILENO, TCSANOW, &settings)) return false; - if (on) setlinebuf(stdin); - else setbuf(stdin, NULL); - return true; - } - - //? Toggle terminal input echo - bool echo(bool on=true){ - struct termios settings; - if (tcgetattr(STDIN_FILENO, &settings)) return false; - if (on) settings.c_lflag |= ECHO; - else settings.c_lflag &= ~(ECHO); - return 0 == tcsetattr(STDIN_FILENO, TCSANOW, &settings); - } - - //? Refresh variables holding current terminal width and height and return true if resized - bool refresh(){ - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - resized = (width != w.ws_col || height != w.ws_row) ? true : false; - width = w.ws_col; - height = w.ws_row; - return resized; - } - - C_Term() { - init(); - refresh(); - resized = false; - } - -}; - -C_Term Term; //* Make C_Term globally available as Term - -class C_Config { - map strings = { - {"color_theme", "Default"}, - {"shown_boxes", "cpu mem net proc"}, - {"proc_sorting", "cpu lazy"}, - {"cpu_graph_upper", "total"}, - {"cpu_graph_lower", "total"}, - {"cpu_sensor", "Auto"}, - {"temp_scale", "celsius"}, - {"draw_clock", "%X"}, - {"custom_cpu_name", ""}, - {"disks_filter", ""}, - {"io_graph_speeds", ""}, - {"net_download", "10M"}, - {"net_upload", "10M"}, - {"net_iface", ""}, - {"log_level", "WARNING"} - }; - map bools = { - {"theme_background", true}, - {"truecolor", true}, - {"proc_reversed", false}, - {"proc_tree", false}, - {"proc_colors", true}, - {"proc_gradient", true}, - {"proc_per_core", false}, - {"proc_mem_bytes", true}, - {"cpu_invert_lower", true}, - {"cpu_single_graph", false}, - {"show_uptime", true}, - {"check_temp", true}, - {"show_coretemp", true}, - {"show_cpu_freq", true}, - {"background_update", true}, - {"update_check", true}, - {"mem_graphs", true}, - {"show_swap", true}, - {"swap_disk", true}, - {"show_disks", true}, - {"only_physical", true}, - {"use_fstab", false}, - {"show_io_stat", true}, - {"io_mode", false}, - {"io_graph_combined", false}, - {"net_color_fixed", false}, - {"net_auto", true}, - {"net_sync", false}, - {"show_battery", true}, - {"show_init", false} - }; - map ints = { - {"update_ms", 2000}, - {"proc_update_mult", 2}, - {"tree_depth", 3} - }; -public: - C_Config(){ - bools["truecolor"] = "true"; - strings["color_theme"] = "Default"; - ints["tree_depth"] = 3; - } - bool operator()(bool b_type, string name){ - return bools.at(name); - } - int operator()(int i_type, string name){ - return ints.at(name); - } - string operator()(string s_type, string name){ - return strings.at(name); - } -}; - -C_Config Config; - -//? Functions and variables for handling keyboard and mouse input +//* Functions and variables for handling keyboard and mouse input class C_Key { const map KEY_ESCAPES = { {"\033", "escape"}, @@ -538,9 +158,9 @@ class C_Key { public: string last = ""; - //? Wait ms for input on stdin and return true if available - //? 0 to just check for input - //? -1 for infinite wait + //* Wait ms for input on stdin and return true if available + //* 0 to just check for input + //* -1 for infinite wait bool operator()(int timeout){ if (wait(timeout)) { last = get(); @@ -551,61 +171,62 @@ public: } } - //? Return last entered key + //* Return last entered key string operator()(){ return last; } }; -C_Key Key; //* Make C_Key globally available as Key - class C_Theme { map c; map> g; + C_Config conf; map generate(map& source){ map out; vector t_rgb; string depth; - for (auto& item : DEFAULT_THEME) { + for (auto& item : Global::Default_theme) { depth = (item.first.ends_with("bg")) ? "bg" : "fg"; if (source.count(item.first)) { - if (source.at(item.first)[0] == '#') out[item.first] = hex_to_color(source.at(item.first), !Config(Bool, "truecolor"), depth); + if (source.at(item.first)[0] == '#') out[item.first] = hex_to_color(source.at(item.first), !State::truecolor, depth); else { t_rgb = ssplit(source.at(item.first), " "); - out[item.first] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), !Config(Bool, "truecolor"), depth); + out[item.first] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), !State::truecolor, depth); } } else out[item.first] = ""; - if (out[item.first] == "") out[item.first] = hex_to_color(item.second, !Config(Bool, "truecolor"), depth); + if (out[item.first] == "") out[item.first] = hex_to_color(item.second, !State::truecolor, depth); } return out; } public: - void swap(map& source){ + //* Change to theme using map + void change(map source){ c = generate(source); - Term.fg = c.at("main_fg"); - Term.bg = c.at("main_bg"); + State::fg = c.at("main_fg"); + State::bg = c.at("main_bg"); + Fx::reset = Fx::reset_base + State::fg + State::bg; } - //? Generate theme from map, default to DEFAULT_THEME on missing or malformatted values + //* Generate theme from map, default to DEFAULT_THEME on missing or malformatted values C_Theme(map source){ - swap(source); + change(source); } - //? Return escape code for color + //* Return escape code for color auto operator()(string name){ return c.at(name); } - //? Return vector of escape codes for color gradient + //* Return vector of escape codes for color gradient auto gradient(string name){ return g.at(name); } - //? Return map of decimal int's (r, g, b) for color + //* Return map of decimal int's (r, g, b) for color auto rgb(string name){ return c_to_rgb(c.at(name)); } @@ -622,7 +243,7 @@ struct C_Banner { int bg_i; int new_len; banner_str = ""; - for (auto line: BANNER_SRC) { + for (auto line: Global::Banner_src) { new_len = ulen(line[1]); if (new_len > width) width = new_len; fg = hex_to_color(line[0]); @@ -641,24 +262,23 @@ struct C_Banner { oc = b_color; } z++; - if (z < BANNER_SRC.size()) out += Mv::l(ulen(line[1])) + Mv::d(1); + if (z < Global::Banner_src.size()) out += Mv::l(ulen(line[1])) + Mv::d(1); } - banner_str = out + Mv::r(18 - VERSION.size()) + Fx::i + dec_to_color(150, 150, 150) + - "v" + VERSION + Fx::r + Term.bg; + banner_str = out + Mv::r(18 - Global::Version.size()) + Fx::i + dec_to_color(0,0,0, State::truecolor, "bg") + dec_to_color(150, 150, 150) + "v" + Global::Version; } - //? Returns the pre-generated btop++ banner + //* Returns the pre-generated btop++ banner string operator() (){ - return banner_str + Term.fg; + return banner_str + Fx::reset; } }; -C_Banner Banner; + //? --------------------------------------------- Main starts here! --------------------------------------------------- int main(int argc, char **argv){ - int debug = 2; - int tests = 8; + int debug = 0; + int tests = 0; //? Init @@ -666,17 +286,18 @@ int main(int argc, char **argv){ if (argc > 1) argumentParser(argc, argv); - if (!Term.init()) { + C_Term Term; + + if (!Term.initialized) { cout << "No terminal detected!" << endl; exit(1); } - Term.echo(false); - Term.linebuffered(false); - ios_base::sync_with_stdio(false); - cin.tie(NULL); - C_Theme Theme(DEFAULT_THEME); + C_Config Config; + C_Theme Theme(Global::Default_theme); + C_Banner Banner; + C_Key Key; cout << Theme("main_bg") << Term.clear << flush; // bool thread_test = false; @@ -690,7 +311,7 @@ int main(int argc, char **argv){ //* Test MENUS - for (auto& outer : MENUS){ + for (auto& outer : Global::Menus){ for (auto& inner : outer.second){ for (auto& item : inner.second){ cout << item << endl; @@ -703,10 +324,6 @@ int main(int argc, char **argv){ if (korv5.starts_with("hej")) cout << "hej" << endl; - State::MenuActive.store(true); - - if (State::MenuActive.load()) cout << "WHUUUU and time: " << time_ms() << endl; - //cout << korv2.size() << " " << ulen(korv2) << endl; cout << Config(Bool, "truecolor") << endl; @@ -715,15 +332,15 @@ int main(int argc, char **argv){ //* Test theme int i = 0; - if (tests==0) for(auto& item : DEFAULT_THEME) { - cout << Theme(item.first) << item.first << ":" << Term.fg << Theme(item.first).erase(0, 1) << Term.bg << " "; + if (tests==0) for(auto& item : Global::Default_theme) { + cout << Theme(item.first) << item.first << ":" << Theme("main_fg") << Theme(item.first).erase(0, 2) << Fx::reset << " "; if (++i == 4) { i = 0; cout << endl; } } - cout << Term.fg << endl; + cout << Fx::reset << endl; // if (thread_test){ // int max = 50000; @@ -768,7 +385,7 @@ int main(int argc, char **argv){ if (tests>3){ - auto nbcolor = hex_to_color(DEFAULT_THEME.at("net_box")); + auto nbcolor = hex_to_color(Global::Default_theme.at("net_box")); auto nbcolor_rgb = c_to_rgb(nbcolor); auto nbcolor_man = ssplit(nbcolor, ";"); cout << nbcolor << "Some color" << endl;