RichText label (used for MOTD), fixes #123
This commit is contained in:
parent
6500923aa5
commit
614a90cfc6
@ -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
183
src/interface/RichLabel.cpp
Normal 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
39
src/interface/RichLabel.h
Normal 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();
|
||||
};
|
||||
}
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user