368 lines
9.5 KiB
C++
368 lines
9.5 KiB
C++
#include "descr.h"
|
|
|
|
#include <string>
|
|
#include <list>
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
#include "widgets.h"
|
|
#include "unicode.h"
|
|
#include "messages.h"
|
|
#include "convert.h"
|
|
#include "utils.h"
|
|
#include "tokenizer.h"
|
|
|
|
|
|
#define WIDTH 600
|
|
#define HEIGHT 500
|
|
#define CLIENT_WIDTH 570
|
|
#define CLIENT_HEIGHT 390
|
|
#define START_X 115
|
|
#define START_Y 100
|
|
|
|
|
|
class TextPage
|
|
{
|
|
private:
|
|
std::vector<Widget*> widgets;
|
|
|
|
public:
|
|
TextPage() { };
|
|
~TextPage();
|
|
|
|
public:
|
|
Widget* getWidget(int no) { return widgets[no]; };
|
|
int getWidgetsCount() const { return widgets.size(); };
|
|
void add(Widget *widget) { widgets.push_back(widget); };
|
|
bool isEmpty() const { return ! widgets.size(); };
|
|
};
|
|
|
|
|
|
class TextParser
|
|
{
|
|
private:
|
|
Tokenizer tokenizer;
|
|
std::vector<TextPage*> pages;
|
|
Font &font;
|
|
int spaceWidth;
|
|
int charHeight;
|
|
std::map<std::wstring, SDL_Surface*> images;
|
|
int offsetX;
|
|
int offsetY;
|
|
int pageWidth;
|
|
int pageHeight;
|
|
|
|
public:
|
|
TextParser(const std::wstring &text, Font &font,
|
|
int x, int y, int width, int height);
|
|
~TextParser();
|
|
|
|
public:
|
|
TextPage* getPage(unsigned int no);
|
|
|
|
private:
|
|
void addLine(TextPage *page, std::wstring &line, int &curPosY,
|
|
int &lineWidth);
|
|
void parseNextPage();
|
|
bool isImage(const std::wstring &name);
|
|
std::wstring keywordToImage(const std::wstring &name);
|
|
SDL_Surface* getImage(const std::wstring &name);
|
|
};
|
|
|
|
|
|
class CursorCommand;
|
|
|
|
|
|
// Otobrazhaet pravila igry na ekran
|
|
class Description
|
|
{
|
|
private:
|
|
typedef std::list<Widget *> WidgetsList;
|
|
WidgetsList widgets;
|
|
|
|
CursorCommand *prevCmd; // Sobytie na nazhatie knopki <PREV>
|
|
CursorCommand *nextCmd; // Sobytie na nazhatie knopki <PREV>
|
|
|
|
Area area; // Mesto gde risovat'
|
|
//std::vector<RulesPage *> pages; // Spisok stranits teksta
|
|
unsigned int currentPage; // Tekuschaja stranitsa dlja prosmotra
|
|
|
|
Font *titleFont; // Shrift dlja risovanija zagolovka okna
|
|
Font *buttonFont; // Shrift dlja risovanija knopok v okne
|
|
Font *textFont; // Shrift dlja risovanija teksta
|
|
|
|
unsigned int textHeight; // Vysota stroki teksta
|
|
TextParser *text;
|
|
|
|
public:
|
|
Description(Area *parentArea);
|
|
~Description();
|
|
|
|
public:
|
|
void run();
|
|
void updateInfo(); // Vyvodit informatsiju na stranitsu
|
|
TextPage *getPage(unsigned int no) { return text->getPage(no); };
|
|
|
|
private:
|
|
void printPage(); // Vyvodit tekuschuju stranitsu pravil
|
|
void deleteWidgets(); // Udaljaet neispol'zuemye metki i kartinki iz oblasti vyvoda informatsii (Area)
|
|
};
|
|
|
|
|
|
//Nuzhen pri nazhatii na knopku <NEXT> ili <PREV> v dialoge spiska pravil
|
|
class CursorCommand: public Command
|
|
{
|
|
private:
|
|
int step; // Cherez skol'ko stranits listat'
|
|
Description &description; // Ukazatel' na ob"ekt Description
|
|
unsigned int *value; // Ukazatel' na tekuschij nomer stranitsy
|
|
|
|
public:
|
|
CursorCommand(int step, Description &d, unsigned int *v);
|
|
virtual ~CursorCommand() { };
|
|
|
|
public:
|
|
virtual void doAction(); // Obrabatyvaet sobytija
|
|
};
|
|
|
|
|
|
|
|
void showDescription(Area *parentArea)
|
|
{
|
|
Description d(parentArea);
|
|
d.run();
|
|
}
|
|
|
|
|
|
|
|
Description::Description(Area *parentArea)
|
|
{
|
|
currentPage = 0;
|
|
//area.add(parentArea, false);
|
|
titleFont = new Font(L"nova.ttf", 26);
|
|
buttonFont = new Font(L"laudcn2.ttf", 14);
|
|
textFont = new Font(L"laudcn2.ttf", 16);
|
|
textHeight = (int)(textFont->getHeight(L"A") * 1.0);
|
|
text = new TextParser(msg(L"rulesText"), *textFont, START_X, START_Y,
|
|
CLIENT_WIDTH, CLIENT_HEIGHT);
|
|
prevCmd = new CursorCommand(-1, *this, ¤tPage);
|
|
nextCmd = new CursorCommand(1, *this, ¤tPage);
|
|
}
|
|
|
|
Description::~Description()
|
|
{
|
|
deleteWidgets();
|
|
delete text;
|
|
delete titleFont;
|
|
delete buttonFont;
|
|
delete textFont;
|
|
}
|
|
|
|
|
|
void Description::deleteWidgets()
|
|
{
|
|
for (WidgetsList::iterator i = widgets.begin();
|
|
i != widgets.end(); i++)
|
|
area.remove(*i);
|
|
widgets.clear();
|
|
}
|
|
|
|
|
|
void Description::updateInfo()
|
|
{
|
|
deleteWidgets();
|
|
printPage();
|
|
area.draw();
|
|
}
|
|
|
|
void Description::run()
|
|
{
|
|
area.add(new Window(100, 50, WIDTH, HEIGHT, L"blue.bmp"));
|
|
area.add(new Label(titleFont, 250, 60, 300, 40, Label::ALIGN_CENTER, Label::ALIGN_MIDDLE, 255, 255, 0, msg(L"rules")));
|
|
area.add(new Button(110, 515, 80, 25, buttonFont, 255, 255, 0, L"blue.bmp", msg(L"prev"), prevCmd));
|
|
area.add(new Button(200, 515, 80, 25, buttonFont, 255, 255, 0, L"blue.bmp", msg(L"next"), nextCmd));
|
|
ExitCommand exitCmd(area);
|
|
area.add(new Button(610, 515, 80, 25, buttonFont, 255, 255, 0, L"blue.bmp", msg(L"close"), &exitCmd));
|
|
area.add(new KeyAccel(SDLK_ESCAPE, &exitCmd));
|
|
printPage();
|
|
area.run();
|
|
}
|
|
|
|
void Description::printPage()
|
|
{
|
|
TextPage *page = text->getPage(currentPage);
|
|
if (! page)
|
|
return;
|
|
int len = page->getWidgetsCount();
|
|
for (int i = 0; i < len; i++) {
|
|
Widget *w = page->getWidget(i);
|
|
if (w) {
|
|
widgets.push_back(w);
|
|
area.add(w);
|
|
}
|
|
}
|
|
}
|
|
|
|
CursorCommand::CursorCommand(int s, Description &d, unsigned int *v):
|
|
description(d)
|
|
{
|
|
step = s;
|
|
value = v;
|
|
}
|
|
|
|
void CursorCommand::doAction()
|
|
{
|
|
if ((! *value) && (0 > step))
|
|
return;
|
|
unsigned int newPageNo = *value + step;
|
|
TextPage *page = description.getPage(newPageNo);
|
|
if (page) {
|
|
*value = newPageNo;
|
|
description.updateInfo();
|
|
}
|
|
}
|
|
|
|
|
|
TextPage::~TextPage()
|
|
{
|
|
for (std::vector<Widget*>::iterator i = widgets.begin();
|
|
i != widgets.end(); i++)
|
|
delete *i;
|
|
}
|
|
|
|
|
|
TextParser::TextParser(const std::wstring &text, Font &font,
|
|
int x, int y, int width, int height): tokenizer(text), font(font)
|
|
{
|
|
spaceWidth = font.getWidth(L' ');
|
|
charHeight = font.getWidth(L'A');
|
|
offsetX = x;
|
|
offsetY = y;
|
|
pageWidth = width;
|
|
pageHeight = height;
|
|
}
|
|
|
|
|
|
TextParser::~TextParser()
|
|
{
|
|
for (std::vector<TextPage*>::iterator i = pages.begin();
|
|
i != pages.end(); i++)
|
|
delete *i;
|
|
for (std::map<std::wstring, SDL_Surface*>::iterator i = images.begin();
|
|
i != images.end(); i++)
|
|
delete (*i).second;
|
|
}
|
|
|
|
|
|
void TextParser::addLine(TextPage *page, std::wstring &line, int &curPosY,
|
|
int &lineWidth)
|
|
{
|
|
if (0 < line.length()) {
|
|
page->add(new Label(&font, offsetX, offsetY + curPosY,
|
|
255,255,255, line, false));
|
|
line.clear();
|
|
curPosY += 10 + charHeight;
|
|
lineWidth = 0;
|
|
}
|
|
}
|
|
|
|
bool TextParser::isImage(const std::wstring &name)
|
|
{
|
|
int len = name.length();
|
|
return (3 < len) && (L'$' == name[0]) && (L'$' == name[len - 1]);
|
|
}
|
|
|
|
std::wstring TextParser::keywordToImage(const std::wstring &name)
|
|
{
|
|
return name.substr(1, name.length() - 2);
|
|
}
|
|
|
|
SDL_Surface* TextParser::getImage(const std::wstring &name)
|
|
{
|
|
SDL_Surface *img = images[name];
|
|
if (! img) {
|
|
img = loadImage(name);
|
|
images[name] = img;
|
|
}
|
|
return img;
|
|
}
|
|
|
|
void TextParser::parseNextPage()
|
|
{
|
|
if (tokenizer.isFinished())
|
|
return;
|
|
|
|
int curPosY = 0;
|
|
int lineWidth = 0;
|
|
TextPage *page = new TextPage();
|
|
std::wstring line;
|
|
|
|
while (true) {
|
|
Token t = tokenizer.getNextToken();
|
|
if (Token::Eof == t.getType())
|
|
break;
|
|
if (Token::Para == t.getType()) {
|
|
if (0 < line.length())
|
|
addLine(page, line, curPosY, lineWidth);
|
|
if (! page->isEmpty())
|
|
curPosY += 10;
|
|
} else if (Token::Word == t.getType()) {
|
|
const std::wstring &word = t.getContent();
|
|
if (isImage(word)) {
|
|
addLine(page, line, curPosY, lineWidth);
|
|
SDL_Surface *image = getImage(keywordToImage(word));
|
|
if ((image->h + curPosY < pageHeight) || page->isEmpty()) {
|
|
int x = offsetX + (pageWidth - image->w) / 2;
|
|
page->add(new Picture(x, offsetY + curPosY, image));
|
|
curPosY += image->h;
|
|
} else {
|
|
tokenizer.unget(t);
|
|
break;
|
|
}
|
|
} else {
|
|
int width = font.getWidth(word);
|
|
if (lineWidth + width > pageWidth) {
|
|
if (! lineWidth) {
|
|
line = word;
|
|
addLine(page, line, curPosY, lineWidth);
|
|
} else {
|
|
addLine(page, line, curPosY, lineWidth);
|
|
if (curPosY >= pageHeight) {
|
|
tokenizer.unget(t);
|
|
break;
|
|
}
|
|
line = word;
|
|
lineWidth = width;
|
|
}
|
|
} else {
|
|
lineWidth += width;
|
|
if (line.size()) {
|
|
line += L' ';
|
|
lineWidth += spaceWidth;
|
|
}
|
|
line += word;
|
|
}
|
|
}
|
|
}
|
|
if (curPosY >= pageHeight)
|
|
break;
|
|
}
|
|
addLine(page, line, curPosY, lineWidth);
|
|
if (! page->isEmpty())
|
|
pages.push_back(page);
|
|
else
|
|
delete page;
|
|
}
|
|
|
|
|
|
TextPage* TextParser::getPage(unsigned int no)
|
|
{
|
|
while ((! tokenizer.isFinished()) && (pages.size() <= no))
|
|
parseNextPage();
|
|
if (pages.size() <= no)
|
|
return NULL;
|
|
else
|
|
return pages[no];
|
|
}
|
|
|