RichText label (used for MOTD), fixes #123

This commit is contained in:
Simon Robertshaw 2012-08-17 16:08:03 +01:00
parent 6500923aa5
commit 614a90cfc6
5 changed files with 236 additions and 2 deletions

View File

@ -31,6 +31,7 @@
#include "interface/Keys.h"
#include "client/GameSave.h"
#include "client/SaveFile.h"
#include "simulation/SaveRenderer.h"
#include "client/Client.h"
#include "Misc.h"

183
src/interface/RichLabel.cpp Normal file
View File

@ -0,0 +1,183 @@
#include <vector>
#include <exception>
#include "RichLabel.h"
#include "Misc.h"
#include "interface/Point.h"
#include "interface/Component.h"
#include "graphics/Graphics.h"
using namespace ui;
struct RichTextParseException: public std::exception {
std::string message;
public:
RichTextParseException(std::string message_ = "Parse error"): message(message_) {}
const char * what() const throw()
{
return message.c_str();
}
~RichTextParseException() throw() {};
};
RichLabel::RichLabel(Point position, Point size, std::string labelText):
Component(position, size),
textSource(labelText)
{
updateRichText();
}
RichLabel::~RichLabel()
{
}
void RichLabel::updateRichText()
{
regions.clear();
enum State { ReadText, ReadData, ReadRegion, ReadDataStart };
State state = ReadText;
int currentDataPos = 0;
char * currentData = new char[textSource.length()+1];
int finalTextPos = 0;
char * finalText = new char[textSource.length()+1];
int originalTextPos = 0;
char * originalText = new char[textSource.length()+1];
std::copy(textSource.begin(), textSource.end(), originalText);
int stackPos = -1;
RichTextRegion * regionsStack = new RichTextRegion[256];
try
{
while(originalText[originalTextPos])
{
char current = originalText[originalTextPos];
if(state == ReadText)
{
if(current == '{')
{
if(stackPos > 255)
throw RichTextParseException("Too many nested regions");
stackPos++;
regionsStack[stackPos].start = finalTextPos;
regionsStack[stackPos].finish = finalTextPos;
state = ReadRegion;
}
else if(current == '}')
{
if(stackPos >= 0)
{
currentData[currentDataPos] = 0;
regionsStack[stackPos].actionData = std::string(currentData);
regions.push_back(regionsStack[stackPos]);
stackPos--;
}
else
{
throw RichTextParseException("Unexpected '}'");
}
}
else
{
finalText[finalTextPos++] = current;
if(stackPos >= 0)
{
regionsStack[stackPos].finish = finalTextPos;
}
}
}
else if(state == ReadData)
{
if(current == '|')
{
state = ReadText;
}
else
{
currentData[currentDataPos++] = current;
}
}
else if(state == ReadDataStart)
{
if(current != ':')
{
throw RichTextParseException("Expected ':'");
}
state = ReadData;
currentDataPos = 0;
}
else if(state == ReadRegion)
{
if(stackPos >= 0)
{
regionsStack[stackPos].action = current;
state = ReadDataStart;
}
else
{
throw RichTextParseException();
}
}
originalTextPos++;
}
finalText[finalTextPos] = 0;
displayText = std::string(finalText);
}
catch (const RichTextParseException & e)
{
displayText = "[Parse exception: " + std::string(e.what()) + "]";
}
delete[] currentData;
delete[] finalText;
delete[] originalText;
delete[] regionsStack;
TextPosition(displayText);
}
void RichLabel::SetText(std::string text)
{
textSource = text;
updateRichText();
}
std::string RichLabel::GetDisplayText()
{
return displayText;
}
std::string RichLabel::GetText()
{
return textSource;
}
void RichLabel::Draw(const Point& screenPos)
{
Graphics * g = ui::Engine::Ref().g;
ui::Colour textColour = Appearance.TextInactive;
g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, displayText, textColour.Red, textColour.Green, textColour.Blue, 255);
}
void RichLabel::OnMouseClick(int x, int y, unsigned button)
{
int cursorPosition = Graphics::CharIndexAtPosition((char*)displayText.c_str(), x-textPosition.X, y-textPosition.Y);
for(std::vector<RichTextRegion>::iterator iter = regions.begin(), end = regions.end(); iter != end; ++iter)
{
if((*iter).start <= cursorPosition && (*iter).finish >= cursorPosition)
{
switch((*iter).action)
{
case 'a':
OpenURI((*iter).actionData);
break;
}
}
}
}

39
src/interface/RichLabel.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <string>
#include "Component.h"
#include "Colour.h"
namespace ui
{
class RichLabel : public Component
{
public:
struct RichTextRegion
{
int start;
int finish;
int action;
std::string actionData;
};
RichLabel(Point position, Point size, std::string richText);
virtual ~RichLabel();
virtual void SetText(std::string text);
virtual std::string GetDisplayText();
virtual std::string GetText();
virtual void Draw(const Point& screenPos);
virtual void OnMouseClick(int x, int y, unsigned button);
protected:
std::string textSource;
std::string displayText;
std::vector<RichTextRegion> regions;
void updateRichText();
};
}

View File

@ -5,6 +5,7 @@
#include "interface/Keys.h"
#include "interface/SaveButton.h"
#include "interface/Label.h"
#include "interface/RichLabel.h"
#include "interface/Textbox.h"
#include "Misc.h"
@ -21,7 +22,7 @@ SearchView::SearchView():
previousButton = new ui::Button(ui::Point(1, YRES+MENUSIZE-18), ui::Point(50, 16), "\x96 Prev");
infoLabel = new ui::Label(ui::Point(51, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-102, 16), "Loading...");
tagsLabel = new ui::Label(ui::Point(51, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-102, 16), "\boPopular Tags:");
motdLabel = new ui::Label(ui::Point(51, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-102, 16), Client::Ref().GetMessageOfTheDay());
motdLabel = new ui::RichLabel(ui::Point(51, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-102, 16), Client::Ref().GetMessageOfTheDay());
class SearchAction : public ui::TextboxAction
{

View File

@ -12,6 +12,16 @@
using namespace std;
namespace ui
{
class RichLabel;
class SaveButton;
class Button;
class Label;
class Spinner;
class Textbox;
}
class SearchModel;
class SearchController;
@ -28,7 +38,7 @@ private:
ui::Textbox * searchField;
ui::Label * infoLabel;
ui::Label * tagsLabel;
ui::Label * motdLabel;
ui::RichLabel * motdLabel;
ui::Button * sortButton;
ui::Button * ownButton;
ui::Spinner * loadingSpinner;