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_stringenum 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;}}