#include "descr.h" #include #include #include #include #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 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 pages; Font &font; int spaceWidth; int charHeight; std::map 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 WidgetsList; WidgetsList widgets; CursorCommand *prevCmd; // Sobytie na nazhatie knopki CursorCommand *nextCmd; // Sobytie na nazhatie knopki Area area; // Mesto gde risovat' //std::vector 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 ili 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::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::iterator i = pages.begin(); i != pages.end(); i++) delete *i; for (std::map::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]; }