1384 lines
35 KiB
ActionScript
1384 lines
35 KiB
ActionScript
import elements.BaseGuiElement;
|
|
import elements.GuiPanel;
|
|
import util.formatting;
|
|
|
|
#section game
|
|
from hooks import Targets, TargetType;
|
|
import orbitals;
|
|
import buildings;
|
|
import resources;
|
|
import void drawResource(const ResourceType@ type, const recti& pos) from "elements.GuiResources";
|
|
import void drawSmallResource(const ResourceType@ type, const Resource@ r, const recti& pos, Object@ drawFrom = null, bool onPlanet = false) from "elements.GuiResources";
|
|
import void drawObjectIcon(Object@ obj, const recti& pos) from "util.icon_view";
|
|
#section all
|
|
|
|
from gui import gui_root;
|
|
|
|
export MarkupRenderer, GuiMarkupText;
|
|
|
|
const Color LINK_COLOR(0x98bbf5ff);
|
|
const Color LINK_HOVER_BG(0xffffff20);
|
|
const string strSemicolon(";"), NO_ANCHOR("");
|
|
const string PAR_SEP("\r");
|
|
const string LINE_SEP("\n");
|
|
|
|
enum TagType {
|
|
TT_Text,
|
|
TT_Font,
|
|
TT_Color,
|
|
TT_Stroke,
|
|
TT_SkinColor,
|
|
TT_HSpace,
|
|
TT_VSpace,
|
|
TT_VBlock,
|
|
TT_Offset,
|
|
TT_Padding,
|
|
TT_Locale,
|
|
TT_Bold,
|
|
TT_Italic,
|
|
TT_BR,
|
|
TT_NL,
|
|
TT_Data,
|
|
TT_DLC
|
|
};
|
|
|
|
enum MarkupMode {
|
|
MM_Draw,
|
|
MM_Layout,
|
|
};
|
|
|
|
class MarkupData {
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) {
|
|
}
|
|
|
|
bool contains(const Skin@ skin, MarkupState@ state, const vec2i& pos) {
|
|
return false;
|
|
}
|
|
|
|
void set_hovered(bool value) {
|
|
}
|
|
|
|
string get_tooltip() {
|
|
return "";
|
|
}
|
|
|
|
const string& get_anchor() {
|
|
return NO_ANCHOR;
|
|
}
|
|
|
|
int get_anchorPosition() {
|
|
return -1;
|
|
}
|
|
|
|
bool onClick(GuiMarkupText@ elem, int button, bool pressed) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
final class MarkupObjectIcon : MarkupData {
|
|
uint objId;
|
|
vec2i size;
|
|
int offset;
|
|
|
|
#section game
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
state.checkLine(size.x);
|
|
if(mode == MM_Draw) {
|
|
auto@ obj = getObjectByID(objId);
|
|
if(obj !is null)
|
|
drawObjectIcon(obj, recti_area(state.pos + vec2i(0, offset), size));
|
|
}
|
|
state.pos.x += size.x;
|
|
|
|
if(tag.childCount > 0) {
|
|
int prevPos = state.area.topLeft.x;
|
|
state.area.topLeft.x = state.pos.x + 14;
|
|
state.pos.x = state.area.topLeft.x;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.area.topLeft.x = prevPos;
|
|
state.linebreak();
|
|
}
|
|
else {
|
|
if(size.y+offset*2 > state.lineHeight)
|
|
state.lineHeight = size.y+offset*2;
|
|
}
|
|
}
|
|
#section all
|
|
};
|
|
|
|
final class MarkupImage : MarkupData {
|
|
Sprite spr;
|
|
Color color;
|
|
vec2i size;
|
|
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
state.checkLine(size.x);
|
|
if(mode == MM_Draw)
|
|
spr.draw(recti_area(state.pos, size), color);
|
|
state.pos.x += size.x;
|
|
|
|
if(tag.childCount > 0) {
|
|
int prevPos = state.area.topLeft.x;
|
|
state.area.topLeft.x = state.pos.x + 14;
|
|
state.pos.x = state.area.topLeft.x;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.area.topLeft.x = prevPos;
|
|
state.linebreak();
|
|
}
|
|
else {
|
|
if(size.y > state.lineHeight)
|
|
state.lineHeight = size.y;
|
|
}
|
|
}
|
|
};
|
|
|
|
final class MarkupAlign : MarkupData {
|
|
double align = 0.5;
|
|
double width = -1;
|
|
double widthSpec = -1;
|
|
int loffset = 0;
|
|
int roffset = 0;
|
|
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
if(mode == MM_Draw) {
|
|
state.clearLine();
|
|
int startPos = state.pos.x;
|
|
state.area.topLeft.x += loffset;
|
|
state.area.botRight.x -= roffset;
|
|
state.pos.x += loffset;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.clearLine();
|
|
state.area.topLeft.x -= loffset;
|
|
state.area.botRight.x += roffset;
|
|
state.pos.x = startPos+width;
|
|
state.linebreak();
|
|
}
|
|
else if(mode == MM_Layout) {
|
|
state.clearLine();
|
|
if(widthSpec <= 0)
|
|
width = state.area.width;
|
|
else if(widthSpec <= 1)
|
|
width = double(state.area.width) * widthSpec;
|
|
|
|
vec2i start = state.pos;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
vec2i end = state.pos;
|
|
|
|
double diff = double(width) - double(end.x - start.x);
|
|
loffset = diff * align;
|
|
roffset = diff * (1.0 - align);
|
|
|
|
state.pos = start;
|
|
state.area.topLeft.x += loffset;
|
|
state.area.botRight.x -= roffset;
|
|
state.pos.x += loffset;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.clearLine();
|
|
state.area.topLeft.x -= loffset;
|
|
state.area.botRight.x += roffset;
|
|
state.pos.x = start.x+width;
|
|
state.linebreak();
|
|
}
|
|
}
|
|
};
|
|
|
|
final class MarkupLine : MarkupData {
|
|
Color color(0xaaaaaaff);
|
|
int width = 1;
|
|
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
state.checkLine(state.area.width - 1);
|
|
if(mode == MM_Draw)
|
|
drawRectangle(recti_area(state.pos+vec2i(0, 3), vec2i(state.area.width - 12, width)), color);
|
|
state.pos.y += 8;
|
|
}
|
|
};
|
|
|
|
const array<FontType> HeadingFonts = {FT_Medium, FT_Subtitle, FT_Bold};
|
|
const array<uint> HeadingOffsets = {16, 10, 0};
|
|
final class MarkupHeading : MarkupData {
|
|
string name;
|
|
FontType font;
|
|
int position = 0;
|
|
int offset;
|
|
|
|
MarkupHeading(uint level, BBTag@ tag) {
|
|
font = HeadingFonts[clamp(level-1, 0, 2)];
|
|
offset = HeadingOffsets[clamp(level-1, 0, 2)];
|
|
bbToPlainText(tag, name);
|
|
}
|
|
|
|
const string& get_anchor() {
|
|
return name;
|
|
}
|
|
|
|
int get_anchorPosition() {
|
|
return position;
|
|
}
|
|
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
if(state.pos.y > state.area.topLeft.y)
|
|
state.pos.y += offset;
|
|
const Font@ prev = state.font;
|
|
@state.font = skin.getFont(font);
|
|
position = state.pos.y - state.absArea.topLeft.y;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
@state.font = prev;
|
|
state.linebreak();
|
|
}
|
|
};
|
|
|
|
final class MarkupLink : MarkupData {
|
|
string link;
|
|
string text;
|
|
recti relPos;
|
|
bool Hovered = false;
|
|
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
if(mode == MM_Draw) {
|
|
state.checkLine(relPos.width);
|
|
state.lineHeight = max(state.lineHeight, state.font.getLineHeight());
|
|
|
|
if(Hovered)
|
|
drawRectangle(relPos.padded(-2) + state.absArea.topLeft, LINK_HOVER_BG);
|
|
state.font.draw(relPos + state.absArea.topLeft,
|
|
text, locale::ELLIPSIS, LINK_COLOR, 0.0, 0.5);
|
|
state.pos.x += relPos.width;
|
|
}
|
|
else if(mode == MM_Layout) {
|
|
state.lineHeight = max(state.lineHeight, state.font.getLineHeight());
|
|
|
|
vec2i dim = state.font.getDimension(text);
|
|
dim.y = state.lineHeight;
|
|
relPos = recti_area(state.pos - state.absArea.topLeft, dim);
|
|
state.pos.x += relPos.width;
|
|
|
|
state.checkLine(relPos.width);
|
|
}
|
|
}
|
|
|
|
bool contains(const Skin@ skin, MarkupState@ state, const vec2i& pos) override {
|
|
return relPos.contains(pos - state.absArea.topLeft);
|
|
}
|
|
|
|
void set_hovered(bool value) override {
|
|
Hovered = value;
|
|
}
|
|
|
|
bool onClick(GuiMarkupText@ elem, int button, bool pressed) override {
|
|
if(!pressed)
|
|
elem.onLinkClicked(link, button);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class MarkupGuiElement : MarkupData {
|
|
IGuiElement@ element;
|
|
|
|
MarkupGuiElement(IGuiElement@ elem) {
|
|
@element = elem;
|
|
@element.parent = gui_root;
|
|
}
|
|
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
vec2i size = element.size;
|
|
state.checkLine(size.width);
|
|
state.lineHeight = max(state.lineHeight, size.height);
|
|
element.position = state.pos;
|
|
}
|
|
};
|
|
|
|
final class MarkupTemplate : MarkupData {
|
|
BBCode code;
|
|
|
|
MarkupTemplate(const string& text, MarkupState@ state) {
|
|
code.parse(text);
|
|
|
|
BBTag@ root = code.root;
|
|
for(uint i = 0, cnt = root.childCount; i < cnt; ++i) {
|
|
BBTag@ tag = root.children[i];
|
|
markupParse(tag, state);
|
|
}
|
|
}
|
|
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
BBTag@ root = code.root;
|
|
for(uint i = 0, cnt = root.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, root.children[i], mode);
|
|
}
|
|
};
|
|
|
|
class MarkupReference : MarkupData {
|
|
Sprite icon;
|
|
string name;
|
|
string ttip;
|
|
recti relPos;
|
|
Color background(0x00000000);
|
|
int refSize = -1;
|
|
|
|
MarkupReference() {
|
|
}
|
|
|
|
MarkupReference(const Sprite& sprt, const string& tip) {
|
|
icon = sprt;
|
|
ttip = tip;
|
|
}
|
|
|
|
MarkupReference(const Sprite& sprt, const string& tip, const string& txt, const Color& bg, int sz = -1) {
|
|
icon = sprt;
|
|
ttip = tip;
|
|
name = txt;
|
|
background = bg;
|
|
refSize = sz;
|
|
}
|
|
|
|
string get_tooltip() {
|
|
return ttip;
|
|
}
|
|
|
|
bool contains(const Skin@ skin, MarkupState@ state, const vec2i& pos) override {
|
|
return relPos.contains(pos - state.absArea.topLeft);
|
|
}
|
|
|
|
void drawIcon(const recti& pos) {
|
|
icon.draw(pos);
|
|
}
|
|
|
|
void comp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) override {
|
|
vec2i isize = icon.size;
|
|
if(refSize != -1)
|
|
isize = vec2i(int(double(refSize) * icon.aspect), refSize);
|
|
else if(isize.y == 0)
|
|
isize.y = 22;
|
|
|
|
vec2i size = isize;
|
|
vec2i tsize;
|
|
if(name.length != 0) {
|
|
tsize = state.font.getDimension(name);
|
|
size.x += tsize.x + 8;
|
|
}
|
|
|
|
state.checkLine(size.x);
|
|
if(mode == MM_Draw) {
|
|
if(background.a != 0)
|
|
drawRectangle(recti_area(state.pos, size), background);
|
|
drawIcon(recti_area(state.pos, isize));
|
|
if(name.length != 0) {
|
|
int yOff = (state.font.getLineHeight() - state.font.getBaseline()) / 2;
|
|
yOff += (isize.y-(tsize.y+yOff))/2;
|
|
state.font.draw(state.pos + vec2i(isize.x+4, yOff), name, state.color);
|
|
}
|
|
}
|
|
relPos = recti_area(state.pos - state.absArea.topLeft, size);
|
|
if(size.y > state.lineHeight)
|
|
state.lineHeight = size.y;
|
|
state.pos.x += size.x;
|
|
}
|
|
};
|
|
|
|
#section game
|
|
class MarkupLargeResource : MarkupReference {
|
|
const ResourceType@ resource;
|
|
|
|
MarkupLargeResource(const ResourceType& type) {
|
|
@resource = type;
|
|
icon = type.icon;
|
|
name = type.name;
|
|
ttip = getResourceTooltip(type);
|
|
background = Color(0xffffff10);
|
|
}
|
|
|
|
void drawIcon(const recti& pos) override {
|
|
drawResource(resource, pos);
|
|
}
|
|
};
|
|
|
|
class MarkupSmallResource : MarkupReference {
|
|
const ResourceType@ resource;
|
|
|
|
MarkupSmallResource(const ResourceType& type) {
|
|
@resource = type;
|
|
icon = type.smallIcon;
|
|
name = type.name;
|
|
ttip = getResourceTooltip(type);
|
|
background = Color(0xffffff10);
|
|
}
|
|
|
|
void drawIcon(const recti& pos) override {
|
|
drawSmallResource(resource, null, pos);
|
|
}
|
|
};
|
|
#section all
|
|
|
|
final class MarkupState {
|
|
bool expandWidth = false;
|
|
bool paragraphize = false;
|
|
recti absArea;
|
|
recti area;
|
|
vec2i pos;
|
|
const Font@ font;
|
|
Color color;
|
|
Color stroke;
|
|
int lineHeight;
|
|
int maxWidth = 0;
|
|
bool wasPrintable = false;
|
|
MarkupData@ contains;
|
|
MarkupData@[] data;
|
|
|
|
#section game
|
|
Targets@ targets;
|
|
#section all
|
|
|
|
void checkLine(int width) {
|
|
if(pos.x + width > area.botRight.x)
|
|
linebreak();
|
|
}
|
|
|
|
int getLineHeight() {
|
|
return max(font.getLineHeight(), lineHeight);
|
|
}
|
|
|
|
void linebreak() {
|
|
maxWidth = max(maxWidth, pos.x - absArea.topLeft.x);
|
|
pos.x = area.topLeft.x;
|
|
pos.y += max(font.getLineHeight(), lineHeight);
|
|
lineHeight = -1;
|
|
}
|
|
|
|
void clearLine() {
|
|
if(pos.x > area.topLeft.x)
|
|
linebreak();
|
|
}
|
|
|
|
void reset(const Skin@ skin, const recti& Area, FontType defaultFont, const Color& defaultColor, const Color& defaultStroke) {
|
|
area = Area;
|
|
absArea = Area;
|
|
pos = area.topLeft;
|
|
@font = skin.getFont(defaultFont);
|
|
color = defaultColor;
|
|
stroke = defaultStroke;
|
|
lineHeight = 0;
|
|
maxWidth = 0;
|
|
}
|
|
};
|
|
|
|
//The parse step pre-calculates values for quick drawing
|
|
void markupParse(BBTag@ tag, MarkupState@ state){
|
|
bool setUnprintable = false;
|
|
if(tag.type == -1) {
|
|
tag.type = TT_Text;
|
|
if(state.paragraphize) {
|
|
tag.argument.paragraphize(PAR_SEP, LINE_SEP, !state.wasPrintable);
|
|
state.wasPrintable = !tag.argument.isWhitespace();
|
|
}
|
|
}
|
|
else if(tag.name == "font") {
|
|
tag.type = TT_Font;
|
|
tag.value = getFontType(tag.argument);
|
|
}
|
|
else if(tag.name == "h1") {
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(MarkupHeading(1, tag));
|
|
state.wasPrintable = false;
|
|
setUnprintable = true;
|
|
}
|
|
else if(tag.name == "h2") {
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(MarkupHeading(2, tag));
|
|
state.wasPrintable = false;
|
|
setUnprintable = true;
|
|
}
|
|
else if(tag.name == "h3") {
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(MarkupHeading(3, tag));
|
|
state.wasPrintable = false;
|
|
setUnprintable = true;
|
|
}
|
|
else if(tag.name == "br") {
|
|
tag.type = TT_BR;
|
|
state.wasPrintable = false;
|
|
}
|
|
else if(tag.name == "nl") {
|
|
tag.type = TT_NL;
|
|
state.wasPrintable = false;
|
|
}
|
|
else if(tag.name == "color") {
|
|
if(tag.argument.length > 0 && tag.argument[0] == '#') {
|
|
tag.type = TT_Color;
|
|
tag.value = toColor(tag.argument).color;
|
|
}
|
|
else if(tag.argument.length > 0 && tag.argument[0] == '$') {
|
|
tag.type = TT_Color;
|
|
tag.value = getGlobalColor("icons", "colors::"+tag.argument.substr(1)).color;
|
|
}
|
|
else {
|
|
tag.type = TT_SkinColor;
|
|
tag.value = getColorType(tag.argument);
|
|
}
|
|
}
|
|
else if(tag.name == "stroke") {
|
|
if(tag.argument.length > 0 && tag.argument[0] == '#') {
|
|
tag.type = TT_Stroke;
|
|
tag.value = toColor(tag.argument).color;
|
|
}
|
|
else if(tag.argument.length > 0 && tag.argument[0] == '$') {
|
|
tag.type = TT_Stroke;
|
|
tag.value = getGlobalColor("icons", "colors::"+tag.argument.substr(1)).color;
|
|
}
|
|
}
|
|
else if(tag.name == "hspace") {
|
|
tag.type = TT_HSpace;
|
|
tag.value = toInt(tag.argument);
|
|
state.wasPrintable = false;
|
|
}
|
|
else if(tag.name == "vspace") {
|
|
tag.type = TT_VSpace;
|
|
tag.value = toInt(tag.argument);
|
|
state.wasPrintable = false;
|
|
}
|
|
else if(tag.name == "vblock") {
|
|
tag.type = TT_VBlock;
|
|
tag.value = toInt(tag.argument);
|
|
}
|
|
else if(tag.name == "offset") {
|
|
tag.type = TT_Offset;
|
|
tag.value = toInt(tag.argument);
|
|
state.wasPrintable = false;
|
|
setUnprintable = true;
|
|
}
|
|
else if(tag.name == "padding") {
|
|
tag.type = TT_Padding;
|
|
tag.value = toInt(tag.argument);
|
|
state.wasPrintable = false;
|
|
setUnprintable = true;
|
|
}
|
|
else if(tag.name == "bbloc") {
|
|
tag.type = TT_Data;
|
|
state.data.insertLast(MarkupTemplate(localize(tag.argument), state));
|
|
tag.value = state.data.length-1; //Because MarkupTemplate can add to state.data list
|
|
|
|
state.wasPrintable = true;
|
|
}
|
|
else if(tag.name == "loc") {
|
|
tag.type = TT_Text;
|
|
|
|
string[] args;
|
|
args = tag.argument.split(strSemicolon);
|
|
|
|
switch(args.length) {
|
|
case 1:
|
|
tag.argument = localize(args[0]);
|
|
break;
|
|
case 2:
|
|
tag.argument = format(localize(args[0]), localize(args[1]));
|
|
break;
|
|
case 3:
|
|
tag.argument = format(localize(args[0]), localize(args[1]), localize(args[2]));
|
|
break;
|
|
case 4:
|
|
tag.argument = format(localize(args[0]), localize(args[1]), localize(args[2]), localize(args[3]));
|
|
break;
|
|
case 5:
|
|
tag.argument = format(localize(args[0]), localize(args[1]), localize(args[2]), localize(args[3]), localize(args[4]));
|
|
break;
|
|
default:
|
|
throw("Error parsing bbcode: [loc] tag can have no more than 5 arguments.");
|
|
break;
|
|
}
|
|
state.wasPrintable = true;
|
|
}
|
|
else if(tag.name == "b") {
|
|
tag.type = TT_Bold;
|
|
}
|
|
else if(tag.name == "i") {
|
|
tag.type = TT_Italic;
|
|
}
|
|
else if(tag.name == "sprite" || tag.name == "img") {
|
|
string[] args = tag.argument.split(strSemicolon);
|
|
|
|
MarkupImage img;
|
|
if(args.length != 0) {
|
|
uint argi = 0;
|
|
if(tag.name == "sprite") {
|
|
@img.spr.sheet = getSpriteSheet(args[argi]);
|
|
++argi;
|
|
|
|
if(args.length > argi) {
|
|
img.spr.index = toUInt(args[argi]);
|
|
++argi;
|
|
}
|
|
img.size = img.spr.size;
|
|
}
|
|
else {
|
|
if(args[argi].length != 0 && args[argi][0] == '$') {
|
|
img.spr = getGlobalSprite("icons", "icons::"+args[argi].substr(1));
|
|
img.size = img.spr.size;
|
|
++argi;
|
|
}
|
|
else {
|
|
img.spr = getSprite(args[argi]);
|
|
img.size = img.spr.size;
|
|
++argi;
|
|
}
|
|
}
|
|
|
|
if(args.length > argi) {
|
|
string[] parts = args[argi].split("x");
|
|
int w = 0, h = 0;
|
|
|
|
if(parts.length >= 1)
|
|
w = toInt(parts[0]);
|
|
if(parts.length >= 2)
|
|
h = toInt(parts[1]);
|
|
|
|
if(w != 0 || h != 0) {
|
|
if(w == 0)
|
|
w = double(h) * (double(img.size.x) / double(img.size.y));
|
|
else if(h == 0)
|
|
h = double(w) * (double(img.size.y) / double(img.size.x));
|
|
|
|
img.size.x = w;
|
|
img.size.y = h;
|
|
}
|
|
}
|
|
++argi;
|
|
|
|
if(args.length > argi)
|
|
img.color = toColor(args[argi]);
|
|
}
|
|
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(img);
|
|
state.wasPrintable = true;
|
|
}
|
|
else if(tag.name == "obj_icon") {
|
|
string[] args = tag.argument.split(strSemicolon);
|
|
|
|
if(args.length == 0)
|
|
throw("Error parsing bbcode: [obj_icon] tag need arguments.");
|
|
|
|
MarkupObjectIcon img;
|
|
uint argi = 0;
|
|
img.objId = toInt(args[argi]);
|
|
img.size = vec2i(30);
|
|
img.offset = -4;
|
|
++argi;
|
|
|
|
if(args.length > argi) {
|
|
string[] parts = args[argi].split("x");
|
|
int w = 0, h = 0;
|
|
|
|
if(parts.length >= 1)
|
|
w = toInt(parts[0]);
|
|
if(parts.length >= 2)
|
|
h = toInt(parts[1]);
|
|
|
|
if(w != 0 || h != 0) {
|
|
if(w == 0)
|
|
w = double(h) * (double(img.size.x) / double(img.size.y));
|
|
else if(h == 0)
|
|
h = double(w) * (double(img.size.y) / double(img.size.x));
|
|
|
|
img.size.x = w;
|
|
img.size.y = h;
|
|
}
|
|
}
|
|
++argi;
|
|
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(img);
|
|
state.wasPrintable = true;
|
|
}
|
|
else if(tag.name == "align") {
|
|
MarkupAlign dat;
|
|
int found = tag.argument.findFirst(strSemicolon);
|
|
if(found == -1) {
|
|
dat.align = toDouble(tag.argument);
|
|
dat.widthSpec = -1;
|
|
}
|
|
else {
|
|
dat.align = toDouble(tag.argument.substr(0, found));
|
|
dat.widthSpec = toDouble(tag.argument.substr(found+1, tag.argument.length - found - 1));
|
|
}
|
|
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(dat);
|
|
state.wasPrintable = false;
|
|
setUnprintable = true;
|
|
}
|
|
else if(tag.name == "center") {
|
|
MarkupAlign dat;
|
|
dat.align = 0.5;
|
|
|
|
if(tag.argument.length != 0)
|
|
dat.width = toDouble(tag.argument);
|
|
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(dat);
|
|
state.wasPrintable = false;
|
|
setUnprintable = true;
|
|
}
|
|
else if(tag.name == "right") {
|
|
MarkupAlign dat;
|
|
dat.align = 1.0;
|
|
|
|
if(tag.argument.length != 0)
|
|
dat.width = toDouble(tag.argument);
|
|
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(dat);
|
|
state.wasPrintable = false;
|
|
setUnprintable = true;
|
|
}
|
|
else if(tag.name == "hr") {
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(MarkupLine());
|
|
state.wasPrintable = false;
|
|
}
|
|
else if(tag.name == "levels") {
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.wasPrintable = true;
|
|
|
|
string text;
|
|
if(tag.childCount != 0)
|
|
text = tag.children[0].argument;
|
|
|
|
auto@ levs = text.split("/");
|
|
auto@ args = tag.argument.split(";");
|
|
int num = -1;
|
|
if(args.length >= 1 && args[0].length != 0 && args[0][0] != '$')
|
|
num = toInt(args[0]);
|
|
|
|
text = "";
|
|
for(uint i = 0, cnt = levs.length; i < cnt; ++i) {
|
|
if(i != 0)
|
|
text += "/";
|
|
if(num == int(i)) {
|
|
text += "[b]";
|
|
if(args.length >= 2)
|
|
text += format("[color=$1]", args[1]);
|
|
}
|
|
text += levs[i];
|
|
if(num == int(i)) {
|
|
if(args.length >= 2)
|
|
text += "[/color]";
|
|
text += "[/b]";
|
|
}
|
|
}
|
|
|
|
state.data.insertLast(MarkupTemplate(text, state));
|
|
}
|
|
else if(tag.name == "dlc") {
|
|
tag.type = TT_DLC;
|
|
}
|
|
#section game
|
|
else if(tag.name == "target") {
|
|
int found = tag.argument.findFirst(strSemicolon);
|
|
string type, arg;
|
|
|
|
if(found == -1) {
|
|
arg = tag.argument;
|
|
}
|
|
else {
|
|
type = tag.argument.substr(0, found);
|
|
arg = tag.argument.substr(found+1, tag.argument.length - found - 1);
|
|
}
|
|
|
|
Target@ targ;
|
|
if(state.targets !is null)
|
|
@targ = state.targets.get(arg);
|
|
|
|
MarkupData@ dat;
|
|
if(targ !is null) {
|
|
if(targ.type == TT_Object && targ.obj !is null) {
|
|
@dat = MarkupTemplate(formatObject(targ.obj, showIcon = true), state);
|
|
}
|
|
else if(targ.type == TT_Empire && targ.emp !is null) {
|
|
if(type.equals_nocase("race"))
|
|
@dat = MarkupTemplate(targ.emp.RaceName, state);
|
|
else
|
|
@dat = MarkupTemplate(formatEmpireName(targ.emp), state);
|
|
}
|
|
}
|
|
if(dat is null)
|
|
@dat = MarkupTemplate("[b]---[/b]", state);
|
|
|
|
state.data.insertLast(dat);
|
|
tag.value = state.data.length-1;
|
|
tag.type = TT_Data;
|
|
state.wasPrintable = true;
|
|
}
|
|
#section all
|
|
else if(tag.name == "template") {
|
|
int found = tag.argument.findFirst(strSemicolon);
|
|
string type, arg;
|
|
|
|
if(found == -1) {
|
|
type = tag.argument;
|
|
}
|
|
else {
|
|
type = tag.argument.substr(0, found);
|
|
arg = tag.argument.substr(found+1, tag.argument.length - found - 1);
|
|
}
|
|
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.wasPrintable = true;
|
|
|
|
#section game
|
|
if(type == "resource") {
|
|
const ResourceType@ r = getResource(arg);
|
|
if(r !is null) {
|
|
string code = format("[nl/][img=$1][font=Subtitle][b][color=$2]$3 [img=$5;20/][/color][/b][/font][br/]$4[/img]",
|
|
getSpriteDesc(r.icon),
|
|
toString(getResourceRarityColor(r.rarity)), r.name,
|
|
getResourceTooltip(r, null, null, false).replaced("\n", "[br/]"),
|
|
getSpriteDesc(r.smallIcon));
|
|
|
|
state.data.insertLast(MarkupTemplate(code, state));
|
|
tag.value = state.data.length-1; //Because MarkupTemplate can add to state.data list
|
|
}
|
|
else
|
|
state.data.insertLast(MarkupData());
|
|
}
|
|
else if(type == "resource_ref") {
|
|
const ResourceType@ r = getResource(arg);
|
|
if(r !is null)
|
|
state.data.insertLast(MarkupSmallResource(r));
|
|
else
|
|
state.data.insertLast(MarkupData());
|
|
}
|
|
else if(type == "orbital_ref") {
|
|
auto@ d = getOrbitalModule(arg);
|
|
if(d !is null)
|
|
state.data.insertLast(MarkupReference(d.icon, d.getTooltip(), d.name, Color(0xffffff10), 22));
|
|
else
|
|
state.data.insertLast(MarkupData());
|
|
}
|
|
else if(type == "orbital") {
|
|
auto@ d = getOrbitalModule(arg);
|
|
if(d !is null) {
|
|
string code = format("[nl/][img=$2;38]$1",
|
|
d.getTooltip().replaced("\n", "[br/]"),
|
|
getSpriteDesc(d.icon));
|
|
state.data.insertLast(MarkupTemplate(code, state));
|
|
tag.value = state.data.length-1;
|
|
}
|
|
else
|
|
state.data.insertLast(MarkupData());
|
|
}
|
|
else if(type == "building_ref") {
|
|
const BuildingType@ d = getBuildingType(arg);
|
|
if(d !is null)
|
|
state.data.insertLast(MarkupReference(d.sprite, d.getTooltip(), d.name, Color(0xffffff10), 22));
|
|
else
|
|
state.data.insertLast(MarkupData());
|
|
}
|
|
else if(type == "subsys_ref") {
|
|
auto@ s = getSubsystemDef(arg);
|
|
if(s !is null)
|
|
state.data.insertLast(MarkupReference(s.picture, format("[b]$1[/b]\n\n$2", s.name, s.description), s.name, Color(0xffffff10), 22));
|
|
else
|
|
state.data.insertLast(MarkupData());
|
|
}
|
|
else if(type == "building") {
|
|
const BuildingType@ d = getBuildingType(arg);
|
|
if(d !is null) {
|
|
string code = format("[nl/][img=$1][font=Subtitle][b]$2[/b][/font][br/]$3[/img]",
|
|
getSpriteDesc(d.sprite),
|
|
d.name,
|
|
d.getTooltip(false).replaced("\n", "[br/]"));
|
|
state.data.insertLast(MarkupTemplate(code, state));
|
|
tag.value = state.data.length-1;
|
|
}
|
|
else
|
|
state.data.insertLast(MarkupData());
|
|
}
|
|
else
|
|
#section all
|
|
{
|
|
state.data.insertLast(MarkupData());
|
|
}
|
|
}
|
|
else if(tag.name == "url") {
|
|
tag.type = TT_Data;
|
|
|
|
MarkupLink link;
|
|
link.link = tag.argument;
|
|
bbToPlainText(tag, link.text);
|
|
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(link);
|
|
state.wasPrintable = true;
|
|
}
|
|
else if(tag.name.length > 1 && tag.name[0] == '[') {
|
|
int found = tag.name.findFirst("|");
|
|
MarkupLink link;
|
|
|
|
if(found == -1) {
|
|
link.link = tag.name.substr(1, tag.name.length - 1);
|
|
link.text = link.link;
|
|
}
|
|
else {
|
|
link.link = tag.name.substr(1, found-1);
|
|
link.text = tag.name.substr(found+1, tag.argument.length - found - 1);
|
|
}
|
|
|
|
tag.type = TT_Data;
|
|
tag.value = state.data.length;
|
|
state.data.insertLast(link);
|
|
state.wasPrintable = true;
|
|
}
|
|
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupParse(tag.children[i], state);
|
|
|
|
if(setUnprintable)
|
|
state.wasPrintable = false;
|
|
}
|
|
|
|
//The draw step draws anything that doesn't need its own element to do
|
|
void markupComp(const Skin@ skin, MarkupState@ state, BBTag@ tag, MarkupMode mode) {
|
|
switch(tag.type) {
|
|
case TT_Text: {
|
|
vec2i prev = state.pos;
|
|
state.lineHeight = max(state.lineHeight, state.font.getLineHeight());
|
|
if(state.expandWidth) {
|
|
vec2i dim = state.font.getDimension(tag.argument);
|
|
if(mode == MM_Draw)
|
|
state.font.draw(state.pos, tag.argument, state.color);
|
|
state.pos.x += dim.x;
|
|
}
|
|
else {
|
|
if(mode == MM_Draw) {
|
|
state.pos = state.font.draw(
|
|
state.area, state.pos - state.area.topLeft,
|
|
state.lineHeight, tag.argument, state.color,
|
|
stroke=state.stroke);
|
|
}
|
|
else {
|
|
state.pos = state.font.getEndPosition(
|
|
state.area, state.pos - state.area.topLeft,
|
|
state.lineHeight, tag.argument);
|
|
}
|
|
}
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
if(prev.y != state.pos.y) {
|
|
if(state.pos.x == state.area.topLeft.x)
|
|
state.lineHeight = -1;
|
|
else
|
|
state.lineHeight = state.font.getLineHeight();
|
|
}
|
|
} break;
|
|
case TT_BR:
|
|
state.linebreak();
|
|
break;
|
|
case TT_NL:
|
|
if(state.pos.x != state.area.topLeft.x)
|
|
state.linebreak();
|
|
break;
|
|
case TT_Font: {
|
|
const Font@ prev = state.font;
|
|
@state.font = skin.getFont(FontType(tag.value));
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
@state.font = prev;
|
|
} break;
|
|
case TT_Bold: {
|
|
const Font@ prev = state.font;
|
|
if(prev.bold !is null)
|
|
@state.font = prev.bold;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
@state.font = prev;
|
|
} break;
|
|
case TT_Italic: {
|
|
const Font@ prev = state.font;
|
|
if(prev.italic !is null)
|
|
@state.font = prev.italic;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
@state.font = prev;
|
|
} break;
|
|
case TT_Color: {
|
|
Color prev = state.color;
|
|
state.color.color = tag.value;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.color = prev;
|
|
} break;
|
|
case TT_Stroke: {
|
|
Color prev = state.stroke;
|
|
state.stroke.color = tag.value;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.stroke = prev;
|
|
} break;
|
|
case TT_SkinColor: {
|
|
Color prev = state.color;
|
|
state.color = skin.getColor(SkinColor(tag.value));
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.color = prev;
|
|
} break;
|
|
case TT_HSpace: {
|
|
state.pos.x += tag.value;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
if(tag.childCount > 0)
|
|
state.pos.x -= tag.value;
|
|
} break;
|
|
case TT_VSpace: {
|
|
state.pos.y += tag.value;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
if(tag.childCount > 0)
|
|
state.pos.y -= tag.value;
|
|
} break;
|
|
case TT_VBlock: {
|
|
int prevY = state.pos.y;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.pos.y += max(tag.value - (state.pos.y - prevY), 0);
|
|
} break;
|
|
case TT_Offset: {
|
|
int prevStart = state.area.topLeft.x;
|
|
if(state.pos.x - state.area.topLeft.x < tag.value)
|
|
state.pos.x = tag.value + state.area.topLeft.x;
|
|
state.area.topLeft.x = state.pos.x;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.area.topLeft.x = prevStart;
|
|
} break;
|
|
case TT_Padding: {
|
|
if(state.pos.x - state.area.topLeft.x < tag.value)
|
|
state.pos.x = tag.value + state.area.topLeft.x;
|
|
state.area.topLeft.x += tag.value;
|
|
state.area.botRight.x -= tag.value;
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
state.area.topLeft.x -= tag.value;
|
|
state.area.botRight.x += tag.value;
|
|
} break;
|
|
case TT_Data: {
|
|
state.data[tag.value].comp(skin, state, tag, mode);
|
|
} break;
|
|
case TT_DLC: {
|
|
if(hasDLC(tag.argument)) {
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, tag.children[i], mode);
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
|
|
void bbToPlainText(BBTag@ tag, string& text) {
|
|
switch(tag.type) {
|
|
case -1:
|
|
case TT_Text:
|
|
text += tag.argument;
|
|
break;
|
|
}
|
|
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i)
|
|
bbToPlainText(tag.children[i], text);
|
|
}
|
|
|
|
class MarkupRenderer {
|
|
BBCode tree;
|
|
MarkupState state;
|
|
int prevWidth = -1;
|
|
int height = 100;
|
|
int width = 100;
|
|
bool prepared = false;
|
|
FontType defaultFont = FT_Normal;
|
|
Color defaultColor;
|
|
Color defaultStroke = colors::Invisible;
|
|
|
|
void clear() {
|
|
tree.clear();
|
|
}
|
|
|
|
void set_expandWidth(bool v) {
|
|
state.expandWidth = v;
|
|
}
|
|
|
|
void set_paragraphize(bool v) {
|
|
state.paragraphize = v;
|
|
}
|
|
|
|
void parse(const Skin@ skin, const string& str, const recti& pos) {
|
|
parseTree(str);
|
|
parseElements(skin, pos);
|
|
}
|
|
|
|
int getAnchor(const string& name) {
|
|
return getAnchor(name, tree.root);
|
|
}
|
|
|
|
int getAnchor(const string& name, BBTag@ tag) {
|
|
if(tag.type == TT_Data) {
|
|
MarkupData@ dat = state.data[tag.value];
|
|
if(dat.anchor == name)
|
|
return dat.anchorPosition;
|
|
}
|
|
|
|
for(uint i = 0, cnt = tag.childCount; i < cnt; ++i) {
|
|
int pos = getAnchor(name, tag.children[i]);
|
|
if(pos != -1)
|
|
return pos;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void parseTree(const string& str) {
|
|
tree.parse(str);
|
|
prevWidth = -1;
|
|
prepared = false;
|
|
}
|
|
|
|
string getPlainText(const Skin@ skin, const recti& pos) {
|
|
if(!prepared)
|
|
parseElements(skin, pos);
|
|
string text;
|
|
bbToPlainText(tree.root, text);
|
|
return text;
|
|
}
|
|
|
|
void parseElements(const Skin@ skin, const recti& pos) {
|
|
BBTag@ root = tree.root;
|
|
state.reset(skin, pos, defaultFont, defaultColor, defaultStroke);
|
|
state.data.length = 0;
|
|
for(uint i = 0, cnt = root.childCount; i < cnt; ++i)
|
|
markupParse(root.children[i], state);
|
|
prevWidth = -1;
|
|
prepared = true;
|
|
}
|
|
|
|
void update(const Skin@ skin, const recti& pos) {
|
|
if(!prepared)
|
|
parseElements(skin, pos);
|
|
if(pos.size.width != prevWidth) {
|
|
state.reset(skin, pos, defaultFont, defaultColor, defaultStroke);
|
|
BBTag@ root = tree.root;
|
|
for(uint i = 0, cnt = root.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, root.children[i], MM_Layout);
|
|
prevWidth = pos.size.width;
|
|
height = (state.pos.y - state.area.topLeft.y)+3;
|
|
if(state.pos.x > state.area.topLeft.x)
|
|
height += state.getLineHeight();
|
|
width = max(state.maxWidth, state.pos.x - state.area.topLeft.x);
|
|
}
|
|
}
|
|
|
|
void draw(const Skin@ skin, const recti& pos) {
|
|
if(pos.size.width != prevWidth)
|
|
update(skin, pos);
|
|
state.reset(skin, pos, defaultFont, defaultColor, defaultStroke);
|
|
BBTag@ root = tree.root;
|
|
for(uint i = 0, cnt = root.childCount; i < cnt; ++i)
|
|
markupComp(skin, state, root.children[i], MM_Draw);
|
|
}
|
|
};
|
|
|
|
class GuiMarkupText : BaseGuiElement {
|
|
MarkupRenderer renderer;
|
|
bool flexHeight = true;
|
|
bool fitWidth = false;
|
|
int Padding = 2;
|
|
int hovered = -1;
|
|
string text;
|
|
bool memo = false;
|
|
|
|
GuiMarkupText(IGuiElement@ ParentElement, Alignment@ Align) {
|
|
super(ParentElement, Align);
|
|
updateAbsolutePosition();
|
|
renderer.defaultColor = skin.getColor(SC_Text);
|
|
}
|
|
|
|
GuiMarkupText(IGuiElement@ ParentElement, const recti& pos) {
|
|
super(ParentElement, pos);
|
|
updateAbsolutePosition();
|
|
renderer.defaultColor = skin.getColor(SC_Text);
|
|
}
|
|
|
|
GuiMarkupText(IGuiElement@ ParentElement, Alignment@ Align, const string& txt) {
|
|
super(ParentElement, Align);
|
|
text = txt;
|
|
updateAbsolutePosition();
|
|
renderer.defaultColor = skin.getColor(SC_Text);
|
|
}
|
|
|
|
GuiMarkupText(IGuiElement@ ParentElement, const recti& pos, const string& txt) {
|
|
super(ParentElement, pos);
|
|
text = txt;
|
|
updateAbsolutePosition();
|
|
renderer.defaultColor = skin.getColor(SC_Text);
|
|
}
|
|
|
|
int getAnchor(const string& name) {
|
|
return renderer.getAnchor(name);
|
|
}
|
|
|
|
string get_plainText() {
|
|
return renderer.getPlainText(skin, AbsolutePosition.padded(Padding));
|
|
}
|
|
|
|
void clear() {
|
|
renderer.clear();
|
|
}
|
|
|
|
void set_defaultColor(Color col) {
|
|
renderer.defaultColor = col;
|
|
}
|
|
|
|
void set_defaultStroke(Color col) {
|
|
renderer.defaultStroke = col;
|
|
}
|
|
|
|
void set_defaultFont(FontType type) {
|
|
renderer.defaultFont = type;
|
|
}
|
|
|
|
void set_expandWidth(bool value) {
|
|
renderer.expandWidth = value;
|
|
}
|
|
|
|
void set_paragraphize(bool value) {
|
|
renderer.paragraphize = value;
|
|
}
|
|
|
|
int get_textWidth() {
|
|
return renderer.width;
|
|
}
|
|
|
|
void set_padding(int padd) {
|
|
Padding = padd;
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void set_text(const string& str) {
|
|
if(memo) {
|
|
if(text == str)
|
|
return;
|
|
}
|
|
renderer.parseTree(str);
|
|
if(memo)
|
|
text = str;
|
|
}
|
|
|
|
#section game
|
|
void set_targets(const Targets@ targs) {
|
|
if(targs is null) {
|
|
@renderer.state.targets = null;
|
|
}
|
|
else {
|
|
@renderer.state.targets = Targets();
|
|
renderer.state.targets = targs;
|
|
}
|
|
}
|
|
#section all
|
|
|
|
string get_tooltip() override {
|
|
if(hovered != -1 && hovered < int(renderer.state.data.length))
|
|
return renderer.state.data[hovered].tooltip;
|
|
return "";
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& event) override {
|
|
if(event.caller is this) {
|
|
switch(event.type) {
|
|
case GUI_Mouse_Left:
|
|
hovered = -1;
|
|
break;
|
|
}
|
|
}
|
|
return BaseGuiElement::onGuiEvent(event);
|
|
}
|
|
|
|
int getOffsetItem(vec2i absPos) {
|
|
for(int i = renderer.state.data.length - 1; i >= 0; --i) {
|
|
MarkupData@ dat = renderer.state.data[i];
|
|
if(dat.contains(skin, renderer.state, absPos))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) override {
|
|
if(source is this) {
|
|
switch(event.type) {
|
|
case MET_Moved: {
|
|
int prevHovered = hovered;
|
|
hovered = getOffsetItem(mousePos);
|
|
if(prevHovered != hovered) {
|
|
if(prevHovered != -1 && prevHovered < int(renderer.state.data.length))
|
|
renderer.state.data[prevHovered].hovered = false;
|
|
if(hovered != -1 && hovered < int(renderer.state.data.length))
|
|
renderer.state.data[hovered].hovered = true;
|
|
if(tooltipObject !is null)
|
|
tooltipObject.update(skin, this);
|
|
}
|
|
} break;
|
|
case MET_Button_Down:
|
|
if(hovered != -1 && hovered < int(renderer.state.data.length))
|
|
if(renderer.state.data[hovered].onClick(this, event.button, true))
|
|
return true;
|
|
break;
|
|
case MET_Button_Up:
|
|
if(hovered != -1 && hovered < int(renderer.state.data.length)) {
|
|
if(renderer.state.data[hovered].onClick(this, event.button, false))
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return BaseGuiElement::onMouseEvent(event, source);
|
|
}
|
|
|
|
void onLinkClicked(const string& link, int button) {
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
BaseGuiElement::updateAbsolutePosition();
|
|
renderer.update(skin, AbsolutePosition.padded(Padding));
|
|
if(Alignment is null) {
|
|
vec2i sz = size;
|
|
if(flexHeight)
|
|
sz = vec2i(renderer.state.expandWidth ? textWidth+6 : Position.size.width, renderer.height + Padding * 2);
|
|
if(fitWidth) {
|
|
sz.x = parent.size.width - (position.x*2);
|
|
GuiPanel@ pan = cast<GuiPanel>(parent);
|
|
if(pan !is null && pan.vert.visible)
|
|
sz.x -= pan.vert.size.width;
|
|
}
|
|
size = sz;
|
|
}
|
|
}
|
|
|
|
void draw() {
|
|
renderer.draw(skin, AbsolutePosition.padded(Padding));
|
|
if(hovered < 0 || hovered > int(renderer.state.data.length))
|
|
hovered = -1;
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|