Skip to content
Snippets Groups Projects
Commit cb4eddcb authored by Rob Swindell's avatar Rob Swindell :speech_balloon:
Browse files

Add rainbow (elite text) attribute feature

New key "rainbow" in ctrl/attr.ini
New Ctrl-A codes: 'X' to turn on repeating/wrapping rainbow attributes,
 'x' to turn on non-repeating/wrapping rainbow attributes.
New @-code: RAINBOW:x to set the list of (comma-separated) rainbow attribute
 values (in same form as attr.ini).
 When used in a display file, the rainbow attribute change is temporary.

Ever wanted to add alternating attributes to @-code expanded text in display
files? Now you can.

Also can be used to easily/quickly create display files with repeating
elements (e.g. commands/options) using alternating attributes.
parent 351690e5
No related branches found
No related tags found
1 merge request!455Update branch with changes from master
Pipeline #6431 passed
......@@ -357,6 +357,12 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode,
return nulstr;
}
if(strncmp(sp, "RAINBOW:", 8) == 0) {
memset(rainbow, 0, sizeof rainbow);
parse_attr_str_list(rainbow, LEN_RAINBOW, sp + 8);
return nulstr;
}
if(strncmp(sp, "U+", 2) == 0) { // UNICODE
enum unicode_codepoint codepoint = (enum unicode_codepoint)strtoul(sp + 2, &tp, 16);
if(tp == NULL || *tp == 0)
......
......@@ -675,6 +675,15 @@ int sbbs_t::outchar(char ch)
}
else
outchar_esc = ansiState_none;
if(outchar_esc == ansiState_none && rainbow_index >= 0) {
attr(rainbow[rainbow_index]);
if(rainbow[rainbow_index + 1] == 0) {
if(rainbow_repeat)
rainbow_index = 0;
} else
++rainbow_index;
}
int term = term_supports();
char utf8[UTF8_MAX_LEN + 1] = "";
if(!(term&PETSCII)) {
......@@ -1155,6 +1164,8 @@ void sbbs_t::ctrl_a(char x)
cursor_right((uchar)x-0x7f);
return;
}
if(valid_ctrl_a_attr(x) && toupper(x) != 'X')
rainbow_index = -1;
if(IS_DIGIT(x)) { /* background color */
atr &= (BG_BRIGHT|BLINK|0x0f);
}
......@@ -1322,6 +1333,11 @@ void sbbs_t::ctrl_a(char x)
case '7': /* White Background */
attr(atr | BG_LIGHTGRAY);
break;
case 'X': // Rainbow
if(rainbow[rainbow_index + 1] != 0)
++rainbow_index;
rainbow_repeat = (x == 'X');
break;
}
}
......
......@@ -441,6 +441,9 @@ bool read_attr_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
cfg->color[clr_progress_full] = strtoattr(iniGetString(ini, ROOT_SECTION, "progress_full", "WH5", value), /* endptr: */NULL);
cfg->color[clr_progress_empty] = strtoattr(iniGetString(ini, ROOT_SECTION, "progress_empty", "WH", value), /* endptr: */NULL);
iniGetString(ini, ROOT_SECTION, "rainbow", "WH,W,CH,C,MH,M,BH,B,YH,Y,GH,G,RH,R,KH", value);
memset(cfg->rainbow, 0, sizeof cfg->rainbow);
parse_attr_str_list(cfg->rainbow, LEN_RAINBOW, value);
iniFreeStringList(ini);
return(true);
}
......
......@@ -3569,6 +3569,8 @@ sbbs_t::sbbs_t(ushort node_num, union xp_sockaddr *addr, size_t addr_len, const
for(i=0;i<TOTAL_TEXT;i++)
text[i]=text_sav[i]=global_text[i];
memcpy(rainbow, cfg.rainbow, sizeof rainbow);
}
//****************************************************************************
......
......@@ -127,6 +127,9 @@ bool sbbs_t::printfile(const char* fname, int mode, int org_cols, JSObject* obj)
errormsg(WHERE,ERR_ALLOC,fpath,length+1L);
return false;
}
uint rainbow_sav[LEN_RAINBOW + 1];
memcpy(rainbow_sav, rainbow, sizeof rainbow_sav);
while(!feof(stream) && !msgabort()) {
if(fgets(buf, length + 1, stream) == NULL)
break;
......@@ -135,6 +138,7 @@ bool sbbs_t::printfile(const char* fname, int mode, int org_cols, JSObject* obj)
if(putmsgfrag(buf, mode, org_cols, obj) != '\0') // early-EOF?
break;
}
memcpy(rainbow, rainbow_sav, sizeof rainbow);
free(buf);
fclose(stream);
if(!(mode&P_SAVEATR)) {
......@@ -161,6 +165,7 @@ bool sbbs_t::printfile(const char* fname, int mode, int org_cols, JSObject* obj)
if(rip)
ansi_getlines();
console=savcon;
return true;
}
......
......@@ -41,6 +41,7 @@ char sbbs_t::putmsg(const char *buf, int mode, int org_cols, JSObject* obj)
uint org_line_delay = line_delay;
uint orgcon=console;
uint sys_status_sav=sys_status;
uint rainbow_sav[LEN_RAINBOW + 1];
enum output_rate output_rate = cur_output_rate;
attr_sp=0; /* clear any saved attributes */
......@@ -50,7 +51,9 @@ char sbbs_t::putmsg(const char *buf, int mode, int org_cols, JSObject* obj)
if(mode&P_NOPAUSE)
sys_status|=SS_PAUSEOFF;
memcpy(rainbow_sav, rainbow, sizeof rainbow_sav);
char ret = putmsgfrag(buf, mode, org_cols, obj);
memcpy(rainbow, rainbow_sav, sizeof rainbow);
if(!(mode&P_SAVEATR)) {
console=orgcon;
attr(tmpatr);
......
......@@ -627,6 +627,9 @@ public:
uint mneattr_low = LIGHTGRAY;
uint mneattr_high = LIGHTGRAY;
uint mneattr_cmd = LIGHTGRAY;
uint rainbow[LEN_RAINBOW + 1]{};
bool rainbow_repeat = false;
int rainbow_index = -1;
int lncntr = 0; /* Line Counter - for PAUSE */
bool msghdr_tos = false; /* Message header was displayed at Top of Screen */
int row=0; /* Current row */
......
......@@ -538,6 +538,7 @@ typedef enum { /* Values for xtrn_t.event */
#define LEN_ARSTR 40 /* Max length of Access Requirement string */
#define LEN_CHATACTCMD 9 /* Chat action command */
#define LEN_CHATACTOUT 65 /* Chat action output string */
#define LEN_RAINBOW 40 // Rainbow attribute array length
#define SIF_MAXBUF 0x7000 /* Maximum buffer size of SIF data */
......
......@@ -625,6 +625,7 @@ typedef struct
uint max_getkey_inactivity; // Seconds before user inactivity hang-up
uint color[NUM_COLORS]; /* Different colors for the BBS */
uint rainbow[LEN_RAINBOW + 1];
uint32_t ctrlkey_passthru; /* Bits represent control keys NOT handled by inkey() */
uint user_backup_level;
......
......@@ -52,6 +52,7 @@ DLLEXPORT void free_chat_cfg(scfg_t* cfg);
DLLEXPORT uint32_t aftou32(const char *str); /* Converts flag string to uint32_t */
DLLEXPORT char* u32toaf(uint32_t t, char *str); /* Converts uint32_t to flag string */
uint strtoattr(const char *str, char** endptr); /* Convert ATTR string into attribute int */
void parse_attr_str_list(uint*, int, const char*);
int getdirnum(scfg_t*, const char* code);
int getlibnum(scfg_t*, const char* code);
......
......@@ -845,6 +845,17 @@ uint strtoattr(const char *str, char** endptr)
return(atr);
}
void parse_attr_str_list(uint* list, int max, const char* str)
{
char* endptr = NULL;
for(int i = 0; i < max && *str != '\0'; ++i) {
list[i] = strtoattr(str, &endptr);
if(*endptr == '\0')
break;
str = endptr + 1;
}
}
void free_file_cfg(scfg_t* cfg)
{
int i;
......
......@@ -457,6 +457,7 @@ bool valid_ctrl_a_attr(char a)
case 'N': /* normal */
case 'R': /* red fg */
case 'W': /* white fg */
case 'X': /* rainbow */
case 'Y': /* yellow fg */
case '0': /* black bg */
case '1': /* red bg */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment