171 lines
5.8 KiB
C++
171 lines
5.8 KiB
C++
/**
|
|
roflcat
|
|
Copyright (C) 2019 rexy712
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef COLOR_PRINTER_TRUE_HPP
|
|
#define COLOR_PRINTER_TRUE_HPP
|
|
|
|
#ifndef _XOPEN_SOURCE
|
|
#define _XOPEN_SOURCE //for wcwidth
|
|
#endif
|
|
#include <cwchar> //wcwidth
|
|
|
|
#include "cmd.hpp"
|
|
#include "color_printer_base.hpp"
|
|
#include <cstdlib> //std::abs
|
|
#include <algorithm> //std::min, std::max
|
|
#include <cstdio> //wprintf, putwchar
|
|
|
|
//True color printer. Too many options to enumerate the entire list of possible colors, so we calculate on the fly
|
|
class color_printer_true : public color_printer_base<color_printer_true>
|
|
{
|
|
friend class printer_base<color_printer_true>;
|
|
private:
|
|
static constexpr const char* lookup_table[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", "253", "254", "255"};
|
|
static constexpr long lookup_table_len = sizeof(lookup_table)/sizeof(lookup_table[0]);
|
|
static constexpr int color_min_amount = 20;
|
|
static constexpr int color_max_amount = 255;
|
|
|
|
enum class color{
|
|
red, green, blue
|
|
};
|
|
struct color_state{
|
|
int r = color_min_amount, g = color_min_amount, b = color_max_amount;
|
|
color curr = color::red;
|
|
|
|
|
|
constexpr color_state(void)noexcept = default;
|
|
constexpr color inc(void){
|
|
switch(curr){
|
|
default:
|
|
case color::red:
|
|
return (curr = color::green);
|
|
case color::green:
|
|
return (curr = color::blue);
|
|
case color::blue:
|
|
return (curr = color::red);
|
|
};
|
|
}
|
|
constexpr color dec(void){
|
|
switch(curr){
|
|
default:
|
|
case color::red:
|
|
return (curr = color::blue);
|
|
case color::green:
|
|
return (curr = color::red);
|
|
case color::blue:
|
|
return (curr = color::green);
|
|
};
|
|
}
|
|
}m_line_color = {}, m_color = {};
|
|
public:
|
|
constexpr color_printer_true(const cmd_args& args)noexcept:
|
|
color_printer_base<color_printer_true>(args){}
|
|
|
|
protected:
|
|
color_printer_true& _print(const wchar_t s)noexcept{
|
|
bool updated = false;
|
|
if(s == L'\n'){
|
|
inc_line();
|
|
updated = true;
|
|
}else{
|
|
int width = wcwidth(s);
|
|
if(width > 0)
|
|
updated = inc_color(wcwidth(s));
|
|
else
|
|
updated = inc_color(1);
|
|
}
|
|
if(updated)
|
|
wprintf(L"\033[38;2;%s;%s;%sm", lookup_table[m_color.r], lookup_table[m_color.g], lookup_table[m_color.b]);
|
|
putwchar(s);
|
|
return *this;
|
|
}
|
|
constexpr void inc_line(void){
|
|
int amount = m_spread*(float{color_max_amount}/4);
|
|
_do_inc_color(amount, m_line_color);
|
|
m_color = m_line_color;
|
|
}
|
|
constexpr bool inc_color(int i){
|
|
int amount = i*m_freq*(float{color_max_amount}/4);
|
|
if(amount == 0)
|
|
return false;
|
|
_do_inc_color(amount, m_color);
|
|
return true;
|
|
}
|
|
constexpr static void _do_inc_color(int amount, color_state& c){
|
|
int* curr = nullptr, *next = nullptr, *prev = nullptr;
|
|
color (color_state::*inc)(void) = nullptr;
|
|
if(amount > 0){
|
|
inc = &color_state::inc;
|
|
switch(c.curr){
|
|
default:
|
|
case color::red:
|
|
curr = &c.r;
|
|
prev = &c.b;
|
|
next = &c.g;
|
|
break;
|
|
case color::green:
|
|
curr = &c.g;
|
|
prev = &c.r;
|
|
next = &c.b;
|
|
break;
|
|
case color::blue:
|
|
curr = &c.b;
|
|
prev = &c.g;
|
|
next = &c.r;
|
|
break;
|
|
};
|
|
}else{
|
|
inc = &color_state::dec;
|
|
switch(c.curr){
|
|
default:
|
|
case color::red:
|
|
curr = &c.b;
|
|
prev = &c.r;
|
|
next = &c.g;
|
|
break;
|
|
case color::green:
|
|
curr = &c.r;
|
|
prev = &c.g;
|
|
next = &c.b;
|
|
break;
|
|
case color::blue:
|
|
curr = &c.g;
|
|
prev = &c.b;
|
|
next = &c.r;
|
|
break;
|
|
};
|
|
}
|
|
amount = std::abs(amount);
|
|
while(amount != 0){
|
|
int old = *curr;
|
|
*curr = std::min((*curr)+amount, color_max_amount);
|
|
amount = (old+amount)-(*curr);
|
|
old = *prev;
|
|
*prev = std::max((*prev)-amount, color_min_amount);
|
|
amount = (amount-old)+(*prev);
|
|
if((*prev) == color_min_amount){
|
|
(c.*inc)();
|
|
int* tmp = curr;
|
|
curr = next;next = prev;prev = tmp;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif
|