mirror of
https://github.com/aristocratos/btop.git
synced 2024-05-21 04:43:36 +12:00
Added theme loadfile function
This commit is contained in:
parent
b4d223cf40
commit
36f0264485
90
src/btop.cpp
90
src/btop.cpp
|
@ -67,7 +67,7 @@ namespace Global {
|
|||
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
|
||||
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
|
||||
};
|
||||
const std::string Version = "0.0.21";
|
||||
const std::string Version = "0.0.30";
|
||||
int coreCount;
|
||||
}
|
||||
|
||||
|
@ -329,18 +329,19 @@ int main(int argc, char **argv){
|
|||
}
|
||||
|
||||
|
||||
#if defined(LINUX)
|
||||
//? Linux init
|
||||
Proc::init();
|
||||
#endif
|
||||
|
||||
//? Platform init and error check
|
||||
Shared::init();
|
||||
|
||||
|
||||
|
||||
// Config::set("truecolor", false);
|
||||
|
||||
auto thts = time_ms();
|
||||
auto thts = time_micros();
|
||||
|
||||
//? Generate the theme
|
||||
Theme::set("Default");
|
||||
//? Update theme list and generate the theme
|
||||
Theme::updateThemes();
|
||||
Theme::setTheme();
|
||||
|
||||
//? Create the btop++ banner
|
||||
banner_gen();
|
||||
|
@ -371,29 +372,64 @@ int main(int argc, char **argv){
|
|||
|
||||
//* Test theme
|
||||
if (false) {
|
||||
cout << "Theme generation took " << time_ms() - thts << "ms" << endl;
|
||||
|
||||
cout << "Colors:" << endl;
|
||||
uint i = 0;
|
||||
for(auto& item : Theme::test_colors()) {
|
||||
cout << rjust(item.first, 15) << ":" << item.second << "■"s * 10 << Fx::reset << " ";
|
||||
// << Theme::dec(item.first)[0] << ":" << Theme::dec(item.first)[1] << ":" << Theme::dec(item.first)[2] << ;
|
||||
if (++i == 4) {
|
||||
i = 0;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
cout << Fx::reset << endl;
|
||||
// cout << Theme::theme_dir << ", " << Theme::user_theme_dir << endl;
|
||||
// for (auto& s : Theme::themes) {
|
||||
// cout << s << endl;
|
||||
// }
|
||||
|
||||
// exit(0);
|
||||
|
||||
string key;
|
||||
bool no_redraw = false;
|
||||
auto theme_index = v_index(Theme::themes, Config::getS("color_theme"));
|
||||
while (key != "q") {
|
||||
key.clear();
|
||||
|
||||
if (not no_redraw) {
|
||||
cout << "\nTheme generation of " << fs::path(Config::getS("color_theme")).filename().replace_extension("") << " took " << time_micros() - thts << "μs" << endl;
|
||||
|
||||
cout << "Colors:" << endl;
|
||||
uint i = 0;
|
||||
for(auto& item : Theme::test_colors()) {
|
||||
cout << rjust(item.first, 15) << ":" << item.second << "■"s * 10 << Fx::reset << " ";
|
||||
// << Theme::dec(item.first)[0] << ":" << Theme::dec(item.first)[1] << ":" << Theme::dec(item.first)[2] << ;
|
||||
if (++i == 4) {
|
||||
i = 0;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
cout << Fx::reset << endl;
|
||||
|
||||
|
||||
cout << "Gradients:";
|
||||
for (auto& [name, cvec] : Theme::test_gradients()) {
|
||||
cout << endl << rjust(name + ":", 10);
|
||||
for (auto& color : cvec) {
|
||||
cout << color << "■";
|
||||
cout << "Gradients:";
|
||||
for (auto& [name, cvec] : Theme::test_gradients()) {
|
||||
cout << endl << rjust(name + ":", 10);
|
||||
for (auto& color : cvec) {
|
||||
cout << color << "■";
|
||||
}
|
||||
|
||||
cout << Fx::reset << endl;
|
||||
}
|
||||
}
|
||||
|
||||
cout << Fx::reset << endl;
|
||||
no_redraw = true;
|
||||
key = Input::wait();
|
||||
if (key.empty()) continue;
|
||||
thts = time_micros();
|
||||
if (key == "right") {
|
||||
if (theme_index == Theme::themes.size() - 1) theme_index = 0;
|
||||
else theme_index++;
|
||||
}
|
||||
else if (key == "left") {
|
||||
if (theme_index == 0) theme_index = Theme::themes.size() - 1;
|
||||
else theme_index--;
|
||||
}
|
||||
else continue;
|
||||
no_redraw = false;
|
||||
Config::set("color_theme", Theme::themes.at(theme_index));
|
||||
Theme::setTheme();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -496,7 +532,7 @@ int main(int argc, char **argv){
|
|||
// else y++;
|
||||
// if (y == 100 or y == 0) flip = not flip;
|
||||
if (Input::poll()) {
|
||||
if (Input::get() == "space") Input::wait(true);
|
||||
if (Input::get() == "space") Input::wait();
|
||||
else break;
|
||||
}
|
||||
sleep_ms(50);
|
||||
|
|
|
@ -39,15 +39,14 @@ namespace Config {
|
|||
bool write_new;
|
||||
|
||||
vector<array<string, 2>> descriptions = {
|
||||
{"color_theme", "#* Color theme, looks for a .theme file in \"/usr/[local/]share/bpytop/themes\" and \"~/.config/bpytop/themes\", \"Default\" for builtin default theme.\n"
|
||||
"#* Prefix name by a plus sign (+) for a theme located in user themes folder, i.e. color_theme=\"+monokai\"." },
|
||||
{"color_theme", "#* Full path to a bashtop/bpytop/btop++ formatted \".theme\" file, \"Default\" and \"TTY\" for builtin themes."},
|
||||
|
||||
{"theme_background", "#* If the theme set background should be shown, set to False if you want terminal background transparency."},
|
||||
|
||||
{"truecolor", "#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false."},
|
||||
|
||||
{"force_tty", "#* Set to true to force tty mode regardless if a real tty has been detected or not.\n"
|
||||
"#* Will force 16-color mode, set all graph symbols to \"tty\" and swap out other non tty friendly symbols."},
|
||||
"#* Will force 16-color mode and TTY theme, set all graph symbols to \"tty\" and swap out other non tty friendly symbols."},
|
||||
|
||||
{"graph_symbol", "#* Default symbols to use for graph creation, \"braille\", \"block\" or \"tty\".\n"
|
||||
"#* \"braille\" offers the highest resolution but might not be included in all fonts.\n"
|
||||
|
|
|
@ -73,10 +73,8 @@ namespace Input {
|
|||
};
|
||||
}
|
||||
|
||||
//* Last entered key
|
||||
string last = "";
|
||||
|
||||
//* Poll keyboard & mouse input for <timeout> ms and return input availabilty as a bool
|
||||
bool poll(int timeout){
|
||||
if (timeout < 1) return cin.rdbuf()->in_avail() > 0;
|
||||
while (timeout > 0) {
|
||||
|
@ -87,11 +85,10 @@ namespace Input {
|
|||
return false;
|
||||
}
|
||||
|
||||
//* Get a key or mouse action from input
|
||||
string get(bool clear){
|
||||
string get(){
|
||||
string key;
|
||||
while (cin.rdbuf()->in_avail() > 0 and key.size() < 100) key += cin.get();
|
||||
if (not clear and not key.empty()){
|
||||
if (not key.empty()){
|
||||
if (key.substr(0,2) == Fx::e) key.erase(0, 1);
|
||||
if (Key_escapes.contains(key)) key = Key_escapes.at(key);
|
||||
else if (ulen(key) > 1) key = "";
|
||||
|
@ -100,10 +97,9 @@ namespace Input {
|
|||
return key;
|
||||
}
|
||||
|
||||
//* Wait until input is available
|
||||
void wait(bool clear){
|
||||
string wait(){
|
||||
while (cin.rdbuf()->in_avail() < 1) sleep_ms(10);
|
||||
if (clear) get(clear);
|
||||
return get();
|
||||
}
|
||||
|
||||
//* Clears last entered key
|
||||
|
|
|
@ -36,10 +36,10 @@ namespace Input {
|
|||
bool poll(int timeout=0);
|
||||
|
||||
//* Get a key or mouse action from input
|
||||
std::string get(bool clear = false);
|
||||
std::string get();
|
||||
|
||||
//* Wait until input is available
|
||||
void wait(bool clear=false);
|
||||
//* Wait until input is available and return key
|
||||
std::string wait();
|
||||
|
||||
//* Clears last entered key
|
||||
void clear();
|
||||
|
|
|
@ -56,6 +56,41 @@ namespace Tools {
|
|||
}
|
||||
}
|
||||
|
||||
namespace Shared {
|
||||
|
||||
fs::path proc_path;
|
||||
fs::path passwd_path;
|
||||
fs::file_time_type passwd_time;
|
||||
long page_size;
|
||||
long clk_tck;
|
||||
|
||||
void init(){
|
||||
proc_path = (fs::is_directory(fs::path("/proc")) and access("/proc", R_OK) != -1) ? "/proc" : "";
|
||||
if (proc_path.empty()) {
|
||||
string errmsg = "Proc filesystem not found or no permission to read from it!";
|
||||
Logger::error(errmsg);
|
||||
std::cout << "ERROR: " << errmsg << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
if (page_size <= 0) {
|
||||
page_size = 4096;
|
||||
Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect.");
|
||||
}
|
||||
|
||||
clk_tck = sysconf(_SC_CLK_TCK);
|
||||
if (clk_tck <= 0) {
|
||||
clk_tck = 100;
|
||||
Logger::warning("Could not get system clocks per second. Defaulting to 100, processes cpu usage might be incorrect.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Proc {
|
||||
namespace {
|
||||
struct p_cache {
|
||||
|
@ -67,15 +102,9 @@ namespace Proc {
|
|||
};
|
||||
unordered_flat_map<uint, p_cache> cache;
|
||||
unordered_flat_map<string, string> uid_user;
|
||||
fs::path passwd_path;
|
||||
fs::file_time_type passwd_time;
|
||||
|
||||
uint counter = 0;
|
||||
long page_size;
|
||||
long clk_tck;
|
||||
|
||||
}
|
||||
|
||||
fs::path proc_path;
|
||||
uint64_t old_cputimes = 0;
|
||||
size_t numpids = 500;
|
||||
atomic<bool> stop (false);
|
||||
|
@ -92,7 +121,7 @@ namespace Proc {
|
|||
};
|
||||
|
||||
//* Generate process tree list
|
||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<proc_info>& out_procs, int cur_depth, bool collapsed, string& prefix){
|
||||
void _tree_gen(const proc_info& cur_proc, const vector<proc_info>& in_procs, vector<proc_info>& out_procs, const int cur_depth, const bool collapsed, const string& prefix){
|
||||
auto cur_pos = out_procs.size();
|
||||
if (not collapsed)
|
||||
out_procs.push_back(cur_proc);
|
||||
|
@ -128,6 +157,8 @@ namespace Proc {
|
|||
auto& per_core = Config::getB("proc_per_core");
|
||||
auto& tree = Config::getB("proc_tree");
|
||||
ifstream pread;
|
||||
string long_string;
|
||||
string short_str;
|
||||
auto uptime = system_uptime();
|
||||
vector<proc_info> procs;
|
||||
vector<uint> pid_list;
|
||||
|
@ -138,11 +169,11 @@ namespace Proc {
|
|||
(void)tree;
|
||||
|
||||
//* Update uid_user map if /etc/passwd changed since last run
|
||||
if (not passwd_path.empty() and fs::last_write_time(passwd_path) != passwd_time) {
|
||||
if (not Shared::passwd_path.empty() and fs::last_write_time(Shared::passwd_path) != Shared::passwd_time) {
|
||||
string r_uid, r_user;
|
||||
passwd_time = fs::last_write_time(passwd_path);
|
||||
Shared::passwd_time = fs::last_write_time(Shared::passwd_path);
|
||||
uid_user.clear();
|
||||
pread.open(passwd_path);
|
||||
pread.open(Shared::passwd_path);
|
||||
if (pread.good()) {
|
||||
while (not pread.eof()){
|
||||
getline(pread, r_user, ':');
|
||||
|
@ -157,7 +188,7 @@ namespace Proc {
|
|||
|
||||
//* Get cpu total times from /proc/stat
|
||||
uint64_t cputimes = 0;
|
||||
pread.open(proc_path / "stat");
|
||||
pread.open(Shared::proc_path / "stat");
|
||||
if (pread.good()) {
|
||||
pread.ignore(SSmax, ' ');
|
||||
for (uint64_t times; pread >> times; cputimes += times);
|
||||
|
@ -166,7 +197,7 @@ namespace Proc {
|
|||
else return current_procs;
|
||||
|
||||
//* Iterate over all pids in /proc
|
||||
for (auto& d: fs::directory_iterator(proc_path)){
|
||||
for (auto& d: fs::directory_iterator(Shared::proc_path)){
|
||||
if (pread.is_open()) pread.close();
|
||||
if (stop) {
|
||||
collecting = false;
|
||||
|
@ -195,7 +226,7 @@ namespace Proc {
|
|||
pread.open(d.path() / "cmdline");
|
||||
if (pread.good()) {
|
||||
string tmpstr = "";
|
||||
while(getline(pread, tmpstr, '\0')) cmd += tmpstr + " ";
|
||||
while(getline(pread, tmpstr, '\0')) cmd += tmpstr + ' ';
|
||||
pread.close();
|
||||
if (not cmd.empty()) cmd.pop_back();
|
||||
}
|
||||
|
@ -238,58 +269,57 @@ namespace Proc {
|
|||
//* Parse /proc/[pid]/stat
|
||||
pread.open(d.path() / "stat");
|
||||
if (pread.good()) {
|
||||
string instr;
|
||||
getline(pread, instr);
|
||||
getline(pread, long_string);
|
||||
pread.close();
|
||||
size_t c_pos = 0, s_count = 0;
|
||||
size_t s_count = 0, c_pos = 0;
|
||||
uint64_t cpu_t = 0;
|
||||
|
||||
try {
|
||||
//? Skip pid and comm field and find comm fields closing ')'
|
||||
size_t s_pos = pid_str.size() + cache.at(new_proc.pid).name.size() + 4;
|
||||
if (instr.at(s_pos - 2) != ')')
|
||||
s_pos = instr.find_last_of(')') + 2;
|
||||
do {
|
||||
c_pos = instr.find(' ', s_pos);
|
||||
if (long_string.at(s_pos - 2) != ')')
|
||||
s_pos = long_string.find_last_of(')') + 2;
|
||||
while (s_count++ <= 37) {
|
||||
c_pos = long_string.find(' ', s_pos);
|
||||
if (c_pos == string::npos) break;
|
||||
|
||||
switch (s_count) {
|
||||
case 0: { //? Process state
|
||||
new_proc.state = instr[s_pos];
|
||||
case 1: { //? Process state
|
||||
new_proc.state = long_string[s_pos];
|
||||
break;
|
||||
}
|
||||
case 1: { //? Process parent pid
|
||||
new_proc.ppid = stoull(instr.substr(s_pos, c_pos - s_pos));
|
||||
case 2: { //? Process parent pid
|
||||
new_proc.ppid = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||
break;
|
||||
}
|
||||
case 11: { //? Process utime
|
||||
cpu_t = stoull(instr.substr(s_pos, c_pos - s_pos));
|
||||
case 12: { //? Process utime
|
||||
cpu_t = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||
break;
|
||||
}
|
||||
case 12: { //? Process stime
|
||||
cpu_t += stoull(instr.substr(s_pos, c_pos - s_pos));
|
||||
case 13: { //? Process stime
|
||||
cpu_t += stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||
break;
|
||||
}
|
||||
case 16: { //? Process nice value
|
||||
new_proc.p_nice = stoull(instr.substr(s_pos, c_pos - s_pos));
|
||||
case 17: { //? Process nice value
|
||||
new_proc.p_nice = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||
break;
|
||||
}
|
||||
case 17: { //? Process number of threads
|
||||
new_proc.threads = stoull(instr.substr(s_pos, c_pos - s_pos));
|
||||
case 18: { //? Process number of threads
|
||||
new_proc.threads = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||
break;
|
||||
}
|
||||
case 19: { //? Cache cpu seconds
|
||||
if (new_cache) cache[new_proc.pid].cpu_s = stoull(instr.substr(s_pos, c_pos - s_pos));
|
||||
case 20: { //? Cache cpu seconds
|
||||
if (new_cache) cache[new_proc.pid].cpu_s = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||
break;
|
||||
}
|
||||
case 36: { //? CPU number last executed on
|
||||
new_proc.cpu_n = stoull(instr.substr(s_pos, c_pos - s_pos));
|
||||
case 37: { //? CPU number last executed on
|
||||
new_proc.cpu_n = stoull(long_string.substr(s_pos, c_pos - s_pos));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s_pos = c_pos + 1;
|
||||
} while (s_count++ < 36);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
continue;
|
||||
|
@ -301,7 +331,7 @@ namespace Proc {
|
|||
new_proc.cpu_p = round(cmult * 1000 * (cpu_t - cache[new_proc.pid].cpu_t) / (cputimes - old_cputimes)) / 10.0;
|
||||
|
||||
//? Process cumulative cpu usage since process start
|
||||
new_proc.cpu_c = ((double)cpu_t / clk_tck) / (uptime - (cache[new_proc.pid].cpu_s / clk_tck));
|
||||
new_proc.cpu_c = ((double)cpu_t / Shared::clk_tck) / (uptime - (cache[new_proc.pid].cpu_s / Shared::clk_tck));
|
||||
|
||||
//? Update cache with latest cpu times
|
||||
cache[new_proc.pid].cpu_t = cpu_t;
|
||||
|
@ -312,9 +342,9 @@ namespace Proc {
|
|||
pread.open(d.path() / "statm");
|
||||
if (pread.good()) {
|
||||
pread.ignore(SSmax, ' ');
|
||||
pread >> new_proc.mem;
|
||||
getline(pread, short_str, ' ');
|
||||
pread.close();
|
||||
new_proc.mem *= page_size;
|
||||
new_proc.mem = stoull(short_str) * Shared::page_size;
|
||||
}
|
||||
|
||||
//? Push process to vector
|
||||
|
@ -345,8 +375,8 @@ namespace Proc {
|
|||
target = (max > 30.0) ? max : 10.0;
|
||||
if (i == offset and procs[i].cpu_p > 30.0)
|
||||
offset++;
|
||||
else if
|
||||
(procs[i].cpu_p > target) rotate(procs.begin() + offset, procs.begin() + i, procs.begin() + i + 1);
|
||||
else if (procs[i].cpu_p > target)
|
||||
rotate(procs.begin() + offset, procs.begin() + i, procs.begin() + i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,32 +410,6 @@ namespace Proc {
|
|||
collecting = false;
|
||||
return current_procs;
|
||||
}
|
||||
|
||||
//* Initialize needed variables for collect
|
||||
void init(){
|
||||
proc_path = (fs::is_directory(fs::path("/proc")) and access("/proc", R_OK) != -1) ? "/proc" : "";
|
||||
if (proc_path.empty()) {
|
||||
string errmsg = "Proc filesystem not found or no permission to read from it!";
|
||||
Logger::error(errmsg);
|
||||
std::cout << "ERROR: " << errmsg << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
if (page_size <= 0) {
|
||||
page_size = 4096;
|
||||
Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect.");
|
||||
}
|
||||
|
||||
clk_tck = sysconf(_SC_CLK_TCK);
|
||||
if (clk_tck <= 0) {
|
||||
clk_tck = 100;
|
||||
Logger::warning("Could not get system clocks per second. Defaulting to 100, processes cpu usage might be incorrect.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -36,8 +36,12 @@ namespace Tools {
|
|||
double system_uptime();
|
||||
}
|
||||
|
||||
namespace Shared {
|
||||
//* Initialize platform specific needed variables and check for errors
|
||||
void init();
|
||||
}
|
||||
|
||||
namespace Proc {
|
||||
extern std::filesystem::path proc_path;
|
||||
extern size_t numpids;
|
||||
extern std::atomic<bool> stop;
|
||||
extern std::atomic<bool> collecting;
|
||||
|
@ -58,9 +62,6 @@ namespace Proc {
|
|||
|
||||
extern vector<proc_info> current_procs;
|
||||
|
||||
//* Collects and sorts process information from /proc, saves to and returns reference to Proc::current_procs;
|
||||
//* Collects and sorts process information from /proc, saves and returns reference to Proc::current_procs;
|
||||
vector<proc_info>& collect();
|
||||
|
||||
//* Initialize needed variables for collect
|
||||
void init();
|
||||
}
|
|
@ -22,6 +22,7 @@ tab-size = 4
|
|||
#include <unordered_map>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
#include <btop_tools.hpp>
|
||||
#include <btop_config.hpp>
|
||||
|
@ -186,21 +187,6 @@ namespace Theme {
|
|||
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
||||
}
|
||||
|
||||
array<int, 3> esc_to_rgb(string c_string){
|
||||
array<int, 3> rgb = {-1, -1, -1};
|
||||
if (c_string.size() >= 14){
|
||||
c_string.erase(0, 7);
|
||||
auto c_split = ssplit(c_string, ';');
|
||||
if (c_split.size() == 3){
|
||||
rgb[0] = stoi(c_split[0]);
|
||||
rgb[1] = stoi(c_split[1]);
|
||||
rgb[2] = stoi(c_split[2].erase(c_split[2].size()));
|
||||
}
|
||||
}
|
||||
return rgb;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
unordered_flat_map<string, string> colors;
|
||||
unordered_flat_map<string, array<int, 3>> rgbs;
|
||||
|
@ -234,24 +220,40 @@ namespace Theme {
|
|||
bool t_to_256 = Config::getB("lowcolor");
|
||||
colors.clear(); rgbs.clear();
|
||||
for (auto& [name, color] : Default_theme) {
|
||||
if (name == "main_bg" and not Config::getB("theme_background")) {
|
||||
colors[name] = "\x1b[49m";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
depth = (name.ends_with("bg") and name != "meter_bg") ? "bg" : "fg";
|
||||
if (source.contains(name)) {
|
||||
if (source.at(name)[0] == '#') {
|
||||
if (name == "main_bg" and source.at(name).empty()) {
|
||||
colors[name] = "\x1b[49m";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
else if (source.at(name).empty() and (name.ends_with("_mid") or name.ends_with("_end"))) {
|
||||
colors[name] = "";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
else if (source.at(name).starts_with('#')) {
|
||||
colors[name] = hex_to_color(source.at(name), t_to_256, depth);
|
||||
rgbs[name] = hex_to_dec(source.at(name));
|
||||
}
|
||||
else {
|
||||
else if (not source.at(name).empty()) {
|
||||
t_rgb = ssplit(source.at(name));
|
||||
if (t_rgb.size() != 3)
|
||||
Logger::error("Invalid RGB decimal value: \"" + source.at(name) + "\"");
|
||||
else {
|
||||
colors[name] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), t_to_256, depth);
|
||||
rgbs[name] = array<int, 3>{stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2])};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (colors[name].empty()) {
|
||||
Logger::info("Missing color value for \"" + name + "\". Using value from default.");
|
||||
Logger::debug("Missing color value for \"" + name + "\". Using value from default.");
|
||||
colors[name] = hex_to_color(color, t_to_256, depth);
|
||||
rgbs[name] = array<int, 3>{-1, -1, -1};
|
||||
}
|
||||
|
@ -268,21 +270,21 @@ namespace Theme {
|
|||
array<array<int, 3>, 101> dec_arr;
|
||||
dec_arr[0][0] = -1;
|
||||
string wname = rtrim(name, "_start");
|
||||
array<array<int, 3>, 3> rgb_arr = {source_arr, rgbs[wname + "_mid"], rgbs[wname + "_end"]};
|
||||
array<array<int, 3>, 3> rgb_array = {source_arr, rgbs[wname + "_mid"], rgbs[wname + "_end"]};
|
||||
|
||||
//? Only start iteration if gradient has a _end color value defined
|
||||
if (rgb_arr[2][0] >= 0) {
|
||||
if (rgb_array[2][0] >= 0) {
|
||||
|
||||
//? Split iteration in two passes of 50 + 51 instead of 101 if gradient has _start, _mid and _end values defined
|
||||
int rng = (rgb_arr[1][0] >= 0) ? 50 : 100;
|
||||
int cur_range = (rgb_array[1][0] >= 0) ? 50 : 100;
|
||||
for (int rgb : iota(0, 3)){
|
||||
int arr1 = 0, offset = 0;
|
||||
int arr2 = (rng == 50) ? 1 : 2;
|
||||
int start = 0, offset = 0;
|
||||
int end = (cur_range == 50) ? 1 : 2;
|
||||
for (int i : iota(0, 101)) {
|
||||
dec_arr[i][rgb] = rgb_arr[arr1][rgb] + (i - offset) * (rgb_arr[arr2][rgb] - rgb_arr[arr1][rgb]) / rng;
|
||||
dec_arr[i][rgb] = rgb_array[start][rgb] + (i - offset) * (rgb_array[end][rgb] - rgb_array[start][rgb]) / cur_range;
|
||||
|
||||
//? Switch source arrays from _start/_mid to _mid/_end at 50 passes if _mid is defined
|
||||
if (i == rng) { ++arr1; ++arr2; offset = 50;}
|
||||
if (i == cur_range) { ++start; ++end; offset = 50;}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -301,8 +303,8 @@ namespace Theme {
|
|||
//* Set colors and generate gradients for the TTY theme
|
||||
void generateTTYColors(){
|
||||
rgbs.clear();
|
||||
colors = TTY_theme;
|
||||
gradients.clear();
|
||||
colors = TTY_theme;
|
||||
|
||||
for (auto& c : colors) {
|
||||
if (not c.first.ends_with("_start")) continue;
|
||||
|
@ -319,10 +321,39 @@ namespace Theme {
|
|||
}
|
||||
}
|
||||
|
||||
//* Load a .theme file from disk
|
||||
auto loadFile(string filename){
|
||||
unordered_flat_map<string, string> out;
|
||||
unordered_flat_map<string, string> theme_out;
|
||||
fs::path filepath = filename;
|
||||
if (not fs::exists(filepath))
|
||||
return Default_theme;
|
||||
|
||||
return out;
|
||||
std::ifstream themefile(filepath);
|
||||
if (themefile.good()) {
|
||||
Logger::debug("Loading theme file: " + filename);
|
||||
while (not themefile.bad()) {
|
||||
themefile.ignore(SSmax, '[');
|
||||
if (themefile.eof()) break;
|
||||
string name, value;
|
||||
getline(themefile, name, ']');
|
||||
if (not Default_theme.contains(name)) {
|
||||
continue;
|
||||
}
|
||||
themefile.ignore(SSmax, '=');
|
||||
themefile >> std::ws;
|
||||
if (themefile.eof()) break;
|
||||
if (themefile.peek() == '"') {
|
||||
themefile.ignore(1);
|
||||
getline(themefile, value, '"');
|
||||
}
|
||||
else getline(themefile, value, '\n');
|
||||
|
||||
theme_out[name] = value;
|
||||
}
|
||||
themefile.close();
|
||||
return theme_out;
|
||||
}
|
||||
return Default_theme;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,11 +362,18 @@ namespace Theme {
|
|||
themes.push_back("Default");
|
||||
themes.push_back("TTY");
|
||||
|
||||
for (const auto& path : { theme_dir, user_theme_dir } ) {
|
||||
for (auto& file : fs::directory_iterator(path)){
|
||||
if (file.path().extension() == ".theme" and access(file.path().c_str(), R_OK) != -1) {
|
||||
themes.push_back(file.path().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//* Set current theme using <source> map
|
||||
void set(string theme){
|
||||
void setTheme(){
|
||||
string theme = Config::getS("color_theme");
|
||||
if (theme == "TTY" or Config::getB("tty_mode"))
|
||||
generateTTYColors();
|
||||
else {
|
||||
|
@ -362,10 +400,10 @@ namespace Theme {
|
|||
return rgbs.at(name);
|
||||
}
|
||||
|
||||
robin_hood::unordered_flat_map<string, string>& test_colors(){
|
||||
unordered_flat_map<string, string>& test_colors(){
|
||||
return colors;
|
||||
}
|
||||
robin_hood::unordered_flat_map<string, std::array<string, 101>>& test_gradients(){
|
||||
unordered_flat_map<string, std::array<string, 101>>& test_gradients(){
|
||||
return gradients;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace Theme {
|
|||
extern std::filesystem::path theme_dir;
|
||||
extern std::filesystem::path user_theme_dir;
|
||||
|
||||
//* Contains "Default" and "TTY" at indeces 0 and 1, otherwise full paths to theme files
|
||||
extern vector<string> themes;
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
|
@ -42,14 +43,11 @@ namespace Theme {
|
|||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string dec_to_color(int r, int g, int b, bool t_to_256=false, string depth="fg");
|
||||
|
||||
//* Return an array of red, green and blue, 0-255 values for a 24-bit color escape string
|
||||
std::array<int, 3> esc_to_rgb(string c_string);
|
||||
|
||||
//* Update list of available themes
|
||||
//* Update list of paths for available themes
|
||||
void updateThemes();
|
||||
|
||||
//* Set current theme using <source> map
|
||||
void set(string theme);
|
||||
//* Set current theme from current "color_theme" value in config
|
||||
void setTheme();
|
||||
|
||||
//* Return escape code for color <name>
|
||||
const string& c(string name);
|
||||
|
|
Loading…
Reference in a new issue