git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@954 c06c8d41-db1a-0410-9941-cceddc491573
4XGOVPFCU6KZIYHKWCHUTZY6G5S326DKBG3UREPR34Q4TSDD3TAAC
5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC
X3RDT655FEYO6XEVPIUAPEPJZAFE55KZBH2AZOLK3NGHINMVIGFQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
ID2OZJTHFXL74RVUCS3JCMDQEUHAXCQFZU7235VU6IEVAAUWD2FAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
GCIZIUXO5TYROKDUYB3HAY7H7MRDTJNM7HR7DGSH7KXDIZC2LCDAC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
class formatted_string
{
public:
formatted_string(int init_colour = 0);
formatted_string(const std::string &s, int init_colour = 0);
void cprintf(const char *s, ...);
void cprintf(const std::string &s);
void gotoxy(int x, int y);
void movexy(int delta_x, int delta_y);
void add_glyph(const monsters *mons);
void add_glyph(const item_def *item);
void textcolor(int color);
void clear();
std::string::size_type length() const;
const formatted_string &operator += (const formatted_string &other);
public:
static formatted_string parse_string(
const std::string &s,
bool eol_ends_format = true,
bool (*process_tag)(const std::string &tag) = NULL );
static int get_colour(const std::string &tag);
private:
int find_last_colour() const;
public:
struct fs_op
{
fs_op_type type;
int x, y;
bool relative;
std::string text;
fs_op(int color)
: type(FSOP_COLOUR), x(color), y(-1), relative(false), text()
{
}
fs_op(int cx, int cy, bool rel = false)
: type(FSOP_CURSOR), x(cx), y(cy), relative(rel), text()
{
}
fs_op(const std::string &s)
: type(FSOP_TEXT), x(-1), y(-1), relative(false), text(s)
{
}
operator fs_op_type () const
{
return type;
}
void display() const;
};
std::vector<fs_op> ops;
};
struct item_def;
}
////////////////////////////////////////////////////////////////////
// formatted_string
//
formatted_string::formatted_string(int init_colour)
: ops()
{
if (init_colour)
textcolor(init_colour);
}
formatted_string::formatted_string(const std::string &s, int init_colour)
: ops()
{
if (init_colour)
textcolor(init_colour);
cprintf(s);
}
int formatted_string::get_colour(const std::string &tag)
{
if (tag == "h")
return (YELLOW);
if (tag == "w")
return (WHITE);
const int colour = str_to_colour(tag);
return (colour != -1? colour : LIGHTGREY);
}
formatted_string formatted_string::parse_string(
const std::string &s,
bool eol_ends_format,
bool (*process)(const std::string &tag))
{
// FIXME This is a lame mess, just good enough for the task on hand
// (keyboard help).
formatted_string fs;
std::string::size_type tag = std::string::npos;
std::string::size_type length = s.length();
std::string currs;
int curr_colour = LIGHTGREY;
bool masked = false;
for (tag = 0; tag < length; ++tag)
{
bool invert_colour = false;
std::string::size_type endpos = std::string::npos;
if (s[tag] != '<' || tag >= length - 2)
{
if (!masked)
currs += s[tag];
continue;
}
// Is this a << escape?
if (s[tag + 1] == '<')
{
if (!masked)
currs += s[tag];
tag++;
continue;
}
endpos = s.find('>', tag + 1);
// No closing >?
if (endpos == std::string::npos)
{
if (!masked)
currs += s[tag];
continue;
}
std::string tagtext = s.substr(tag + 1, endpos - tag - 1);
if (tagtext.empty() || tagtext == "/")
{
if (!masked)
currs += s[tag];
continue;
}
if (tagtext[0] == '/')
{
invert_colour = true;
tagtext = tagtext.substr(1);
tag++;
}
if (tagtext[0] == '?')
{
if (tagtext.length() == 1)
masked = false;
else if (process && !process(tagtext.substr(1)))
masked = true;
tag += tagtext.length() + 1;
continue;
}
const int new_colour = invert_colour? LIGHTGREY : get_colour(tagtext);
if (new_colour != curr_colour)
{
fs.cprintf(currs);
currs.clear();
fs.textcolor( curr_colour = new_colour );
}
tag += tagtext.length() + 1;
}
if (currs.length())
fs.cprintf(currs);
if (eol_ends_format && curr_colour != LIGHTGREY)
fs.textcolor(LIGHTGREY);
return (fs);
}
formatted_string::operator std::string() const
{
std::string s;
for (unsigned i = 0, size = ops.size(); i < size; ++i)
{
if (ops[i] == FSOP_TEXT)
s += ops[i].text;
}
return (s);
}
const formatted_string &
formatted_string::operator += (const formatted_string &other)
{
ops.insert(ops.end(), other.ops.begin(), other.ops.end());
return (*this);
std::string::size_type formatted_string::length() const
{
// Just add up the individual string lengths.
std::string::size_type len = 0;
for (unsigned i = 0, size = ops.size(); i < size; ++i)
if (ops[i] == FSOP_TEXT)
len += ops[i].text.length();
return (len);
}
inline void cap(int &i, int max)
{
if (i < 0 && -i <= max)
i += max;
if (i >= max)
i = max - 1;
if (i < 0)
i = 0;
}
std::string formatted_string::tostring(int s, int e) const
{
std::string st;
int size = ops.size();
cap(s, size);
cap(e, size);
for (int i = s; i <= e && i < size; ++i)
{
if (ops[i] == FSOP_TEXT)
st += ops[i].text;
}
return st;
}
void formatted_string::display(int s, int e) const
{
int size = ops.size();
if (!size)
return;
cap(s, size);
cap(e, size);
for (int i = s; i <= e && i < size; ++i)
ops[i].display();
}
void formatted_string::gotoxy(int x, int y)
{
ops.push_back( fs_op(x, y) );
}
void formatted_string::movexy(int x, int y)
{
ops.push_back( fs_op(x, y, true) );
}
int formatted_string::find_last_colour() const
{
if (!ops.empty())
{
for (int i = ops.size() - 1; i >= 0; --i)
{
if (ops[i].type == FSOP_COLOUR)
return (ops[i].x);
}
}
return (LIGHTGREY);
}
void formatted_string::add_glyph(const item_def *item)
{
const int last_col = find_last_colour();
unsigned short ch, col;
get_item_glyph(item, &ch, &col);
this->textcolor(col);
this->cprintf("%c", ch);
this->textcolor(last_col);
}
void formatted_string::add_glyph(const monsters *mons)
{
const int last_col = find_last_colour();
unsigned short ch, col;
get_mons_glyph(mons, &ch, &col);
this->textcolor(col);
this->cprintf("%c", ch);
this->textcolor(last_col);
}
void formatted_string::textcolor(int color)
{
if (!ops.empty() && ops[ ops.size() - 1 ].type == FSOP_COLOUR)
ops.erase( ops.end() - 1 );
ops.push_back(color);
}
void formatted_string::clear()
{
ops.clear();
}
void formatted_string::cprintf(const char *s, ...)
{
char buf[1000];
va_list args;
va_start(args, s);
vsnprintf(buf, sizeof buf, s, args);
va_end(args);
cprintf(std::string(buf));
}
void formatted_string::cprintf(const std::string &s)
{
ops.push_back(s);
}
void formatted_string::fs_op::display() const
{
switch (type)
{
case FSOP_CURSOR:
{
int cx = x, cy = y;
if (relative)
{
cx += wherex();
cy += wherey();
}
else
{
if (cx == -1)
cx = wherex();
if (cy == -1)
cy = wherey();
}
::gotoxy(cx, cy);
break;
}
case FSOP_COLOUR:
::textattr(x);
break;
case FSOP_TEXT:
::cprintf("%s", text.c_str());
break;
}
}
#ifndef __FORMAT_H__
#define __FORMAT_H__
#include <string>
#include <vector>
#include "externs.h"
// Definitions for formatted_string
enum fs_op_type
{
FSOP_COLOUR,
FSOP_CURSOR,
FSOP_TEXT
};
class formatted_string
{
public:
formatted_string(int init_colour = 0);
formatted_string(const std::string &s, int init_colour = 0);
operator std::string() const;
void display(int start = 0, int end = -1) const;
std::string tostring(int start = 0, int end = -1) const;
void cprintf(const char *s, ...);
void cprintf(const std::string &s);
void gotoxy(int x, int y);
void movexy(int delta_x, int delta_y);
void add_glyph(const monsters *mons);
void add_glyph(const item_def *item);
void textcolor(int color);
void clear();
std::string::size_type length() const;
const formatted_string &operator += (const formatted_string &other);
public:
static formatted_string parse_string(
const std::string &s,
bool eol_ends_format = true,
bool (*process_tag)(const std::string &tag) = NULL );
static int get_colour(const std::string &tag);
private:
int find_last_colour() const;
public:
struct fs_op
{
fs_op_type type;
int x, y;
bool relative;
std::string text;
fs_op(int color)
: type(FSOP_COLOUR), x(color), y(-1), relative(false), text()
{
}
fs_op(int cx, int cy, bool rel = false)
: type(FSOP_CURSOR), x(cx), y(cy), relative(rel), text()
{
}
fs_op(const std::string &s)
: type(FSOP_TEXT), x(-1), y(-1), relative(false), text(s)
{
}
operator fs_op_type () const
{
return type;
}
void display() const;
};
std::vector<fs_op> ops;
};
#endif
#include "AppHdr.h"
#include "initfile.h"
#include "format.h"
#include "view.h"
formatted_string::formatted_string(int init_colour)
: ops()
{
if (init_colour)
textcolor(init_colour);
}
formatted_string::formatted_string(const std::string &s, int init_colour)
: ops()
{
if (init_colour)
textcolor(init_colour);
cprintf(s);
}
int formatted_string::get_colour(const std::string &tag)
{
if (tag == "h")
return (YELLOW);
if (tag == "w")
return (WHITE);
const int colour = str_to_colour(tag);
return (colour != -1? colour : LIGHTGREY);
}
formatted_string formatted_string::parse_string(
const std::string &s,
bool eol_ends_format,
bool (*process)(const std::string &tag))
{
// FIXME This is a lame mess, just good enough for the task on hand
// (keyboard help).
formatted_string fs;
std::string::size_type tag = std::string::npos;
std::string::size_type length = s.length();
std::string currs;
int curr_colour = LIGHTGREY;
bool masked = false;
for (tag = 0; tag < length; ++tag)
{
bool invert_colour = false;
std::string::size_type endpos = std::string::npos;
if (s[tag] != '<' || tag >= length - 2)
{
if (!masked)
currs += s[tag];
continue;
}
// Is this a << escape?
if (s[tag + 1] == '<')
{
if (!masked)
currs += s[tag];
tag++;
continue;
}
endpos = s.find('>', tag + 1);
// No closing >?
if (endpos == std::string::npos)
{
if (!masked)
currs += s[tag];
continue;
}
std::string tagtext = s.substr(tag + 1, endpos - tag - 1);
if (tagtext.empty() || tagtext == "/")
{
if (!masked)
currs += s[tag];
continue;
}
if (tagtext[0] == '/')
{
invert_colour = true;
tagtext = tagtext.substr(1);
tag++;
}
if (tagtext[0] == '?')
{
if (tagtext.length() == 1)
masked = false;
else if (process && !process(tagtext.substr(1)))
masked = true;
tag += tagtext.length() + 1;
continue;
}
const int new_colour = invert_colour? LIGHTGREY : get_colour(tagtext);
if (new_colour != curr_colour)
{
fs.cprintf(currs);
currs.clear();
fs.textcolor( curr_colour = new_colour );
}
tag += tagtext.length() + 1;
}
if (currs.length())
fs.cprintf(currs);
if (eol_ends_format && curr_colour != LIGHTGREY)
fs.textcolor(LIGHTGREY);
return (fs);
}
formatted_string::operator std::string() const
{
std::string s;
for (unsigned i = 0, size = ops.size(); i < size; ++i)
{
if (ops[i] == FSOP_TEXT)
s += ops[i].text;
}
return (s);
}
const formatted_string &
formatted_string::operator += (const formatted_string &other)
{
ops.insert(ops.end(), other.ops.begin(), other.ops.end());
return (*this);
}
std::string::size_type formatted_string::length() const
{
// Just add up the individual string lengths.
std::string::size_type len = 0;
for (unsigned i = 0, size = ops.size(); i < size; ++i)
if (ops[i] == FSOP_TEXT)
len += ops[i].text.length();
return (len);
}
inline void cap(int &i, int max)
{
if (i < 0 && -i <= max)
i += max;
if (i >= max)
i = max - 1;
if (i < 0)
i = 0;
}
std::string formatted_string::tostring(int s, int e) const
{
std::string st;
int size = ops.size();
cap(s, size);
cap(e, size);
for (int i = s; i <= e && i < size; ++i)
{
if (ops[i] == FSOP_TEXT)
st += ops[i].text;
}
return st;
}
void formatted_string::display(int s, int e) const
{
int size = ops.size();
if (!size)
return;
cap(s, size);
cap(e, size);
for (int i = s; i <= e && i < size; ++i)
ops[i].display();
}
void formatted_string::gotoxy(int x, int y)
{
ops.push_back( fs_op(x, y) );
}
void formatted_string::movexy(int x, int y)
{
ops.push_back( fs_op(x, y, true) );
}
int formatted_string::find_last_colour() const
{
if (!ops.empty())
{
for (int i = ops.size() - 1; i >= 0; --i)
{
if (ops[i].type == FSOP_COLOUR)
return (ops[i].x);
}
}
return (LIGHTGREY);
}
void formatted_string::add_glyph(const item_def *item)
{
const int last_col = find_last_colour();
unsigned short ch, col;
get_item_glyph(item, &ch, &col);
this->textcolor(col);
this->cprintf("%c", ch);
this->textcolor(last_col);
}
void formatted_string::add_glyph(const monsters *mons)
{
const int last_col = find_last_colour();
unsigned short ch, col;
get_mons_glyph(mons, &ch, &col);
this->textcolor(col);
this->cprintf("%c", ch);
this->textcolor(last_col);
}
void formatted_string::textcolor(int color)
{
if (!ops.empty() && ops[ ops.size() - 1 ].type == FSOP_COLOUR)
ops.erase( ops.end() - 1 );
ops.push_back(color);
}
void formatted_string::clear()
{
ops.clear();
}
void formatted_string::cprintf(const char *s, ...)
{
char buf[1000];
va_list args;
va_start(args, s);
vsnprintf(buf, sizeof buf, s, args);
va_end(args);
cprintf(std::string(buf));
}
void formatted_string::cprintf(const std::string &s)
{
ops.push_back(s);
}
void formatted_string::fs_op::display() const
{
switch (type)
{
case FSOP_CURSOR:
{
int cx = x, cy = y;
if (relative)
{
cx += wherex();
cy += wherey();
}
else
{
if (cx == -1)
cx = wherex();
if (cy == -1)
cy = wherey();
}
::gotoxy(cx, cy);
break;
}
case FSOP_COLOUR:
::textattr(x);
break;
case FSOP_TEXT:
::cprintf("%s", text.c_str());
break;
}
}