Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
import tabs.tabbar;
|
||||
import elements.GuiBlueprint;
|
||||
import elements.GuiMarkupText;
|
||||
import elements.GuiSkinElement;
|
||||
import elements.GuiText;
|
||||
import elements.GuiTextbox;
|
||||
import elements.GuiButton;
|
||||
import elements.GuiPanel;
|
||||
import elements.MarkupTooltip;
|
||||
import dialogs.MessageDialog;
|
||||
import dialogs.QuestionDialog;
|
||||
import util.design_export;
|
||||
import icons;
|
||||
from tabs.DesignEditorTab import createDesignEditorTab;
|
||||
from community.DesignPage import createCommunityDesignPage;
|
||||
|
||||
class DesignElement : BaseGuiElement {
|
||||
GuiDownloadedBlueprint@ bp;
|
||||
GuiMarkupText@ description;
|
||||
GuiMarkupText@ curLine;
|
||||
const Design@ dsg;
|
||||
|
||||
GuiButton@ downloadProfile;
|
||||
GuiButton@ downloadEmpire;
|
||||
GuiButton@ editButton;
|
||||
|
||||
bool Hovered = false;
|
||||
|
||||
DesignElement(IGuiElement@ parent, Alignment@ align) {
|
||||
super(parent, align);
|
||||
updateAbsolutePosition();
|
||||
_();
|
||||
}
|
||||
|
||||
DesignElement(IGuiElement@ parent, const recti& pos) {
|
||||
super(parent, pos);
|
||||
updateAbsolutePosition();
|
||||
_();
|
||||
}
|
||||
|
||||
void _() {
|
||||
@bp = GuiDownloadedBlueprint(this, recti());
|
||||
@description = GuiMarkupText(this, recti());
|
||||
description.flexHeight = false;
|
||||
@curLine = GuiMarkupText(this, recti());
|
||||
|
||||
@downloadEmpire = GuiButton(this, Alignment(Right-42, Top+8, Width=34, Height=34));
|
||||
downloadEmpire.style = SS_IconButton;
|
||||
downloadEmpire.setIcon(icons::Add);
|
||||
setMarkupTooltip(downloadEmpire, locale::TT_DOWNLOAD_TO_EMPIRE, width=400);
|
||||
|
||||
@downloadProfile = GuiButton(this, Alignment(Right-42, Top+8+40, Width=34, Height=34));
|
||||
downloadProfile.style = SS_IconButton;
|
||||
downloadProfile.setIcon(icons::Import);
|
||||
setMarkupTooltip(downloadProfile, locale::TT_DOWNLOAD_TO_PROFILE, width=400);
|
||||
|
||||
@editButton = GuiButton(this, Alignment(Right-42, Top+8+40+40, Width=34, Height=34));
|
||||
editButton.style = SS_IconButton;
|
||||
editButton.setIcon(icons::Edit);
|
||||
editButton.allowOtherButtons = true;
|
||||
setMarkupTooltip(editButton, locale::TT_DOWNLOAD_EDIT, width=400);
|
||||
}
|
||||
|
||||
void load(int id) {
|
||||
bp.load(id);
|
||||
}
|
||||
|
||||
void updateAbsolutePosition() {
|
||||
BaseGuiElement::updateAbsolutePosition();
|
||||
if(bp !is null) {
|
||||
int unit = min(size.height-8, size.width-8);
|
||||
bp.rect = recti_area(vec2i(4,4), vec2i(unit, unit));
|
||||
description.rect = recti_area(vec2i(12+unit, 4), vec2i(size.width-unit-24-42, size.height-42));
|
||||
curLine.rect = recti_area(vec2i(12+unit, size.height-34), vec2i(size.width-unit-24-42, 30));
|
||||
}
|
||||
}
|
||||
|
||||
void finishLoad(JSONNode@ root) {
|
||||
bp.finishLoad(root);
|
||||
}
|
||||
|
||||
void update() {
|
||||
@dsg = bp.dsg;
|
||||
if(dsg !is null) {
|
||||
string author = bp.author;
|
||||
if(author.length > 20)
|
||||
author = author.substr(0,17)+"...";
|
||||
string specLine = format(locale::COMMUNITY_DESIGN_SPEC, toString(dsg.size,0),
|
||||
bbescape(author), bbescape(bp.ctime));
|
||||
|
||||
string desc = bp.description;
|
||||
string name = dsg.name;
|
||||
uint len = 100;
|
||||
if(size.height > 150)
|
||||
len = 200;
|
||||
if(desc.length > len) {
|
||||
desc = desc.substr(0,len);
|
||||
desc += "...";
|
||||
}
|
||||
if(name.length > 36) {
|
||||
name = name.substr(0,36);
|
||||
name += "...";
|
||||
}
|
||||
|
||||
description.text = format("[font=Medium][color=$1]$2[/color][/font]\n"
|
||||
"[b]$3[/b]\n[i][color=#aaa]$4[/color][/i]",
|
||||
toString(dsg.color), bbescape(name),
|
||||
specLine, bbescape(desc, true));
|
||||
|
||||
curLine.text = format(locale::COMMUNITY_DESIGN_CURLINE, toString(bp.upvotes), toString(bp.commentCount));
|
||||
|
||||
updateAbsolutePosition();
|
||||
|
||||
downloadEmpire.disabled = dsg.hasFatalErrors();
|
||||
if(dsg.hasFatalErrors()) {
|
||||
string errors = locale::TT_DOWNLOAD_ERRORS;
|
||||
for(uint i = 0, cnt = dsg.errorCount; i < cnt; ++i)
|
||||
errors += "\n\n"+dsg.errors[i].text;
|
||||
setMarkupTooltip(downloadEmpire, errors, width=400);
|
||||
}
|
||||
else {
|
||||
setMarkupTooltip(downloadEmpire, locale::TT_DOWNLOAD_TO_EMPIRE, width=400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showPage(bool bg) {
|
||||
if(bg)
|
||||
newTab(createCommunityDesignPage(bp.designId));
|
||||
else
|
||||
browseTab(ActiveTab, createCommunityDesignPage(bp.designId), true);
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& evt) {
|
||||
switch(evt.type) {
|
||||
case GUI_Mouse_Entered:
|
||||
if(evt.caller is this)
|
||||
Hovered = true;
|
||||
break;
|
||||
case GUI_Mouse_Left:
|
||||
if(evt.caller is this)
|
||||
Hovered = false;
|
||||
break;
|
||||
case GUI_Clicked:
|
||||
if(evt.caller is downloadEmpire) {
|
||||
if(dsg !is null) {
|
||||
auto@ cls = playerEmpire.getDesignClass(locale::DOWNLOAD_DESIGN_CLASS, true);
|
||||
auto@ prev = playerEmpire.getDesign(dsg.name);
|
||||
if(prev !is null)
|
||||
playerEmpire.changeDesign(prev, dsg, cls);
|
||||
else
|
||||
playerEmpire.addDesign(cls, dsg);
|
||||
message(locale::SUCCESS_DOWNLOAD_TO_EMPIRE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is downloadProfile) {
|
||||
string fname = path_join(modProfile["designs"], dsg.name+".design");
|
||||
write_design(dsg, fname);
|
||||
message(locale::SUCCESS_DOWNLOAD_TO_PROFILE);
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is editButton) {
|
||||
if(dsg !is null) {
|
||||
if(ctrlKey || evt.value == 2)
|
||||
newTab(createDesignEditorTab(dsg));
|
||||
else
|
||||
browseTab(ActiveTab, createDesignEditorTab(dsg), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return BaseGuiElement::onGuiEvent(evt);
|
||||
}
|
||||
|
||||
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
|
||||
if(source is this || source.isChildOf(this)) {
|
||||
switch(event.type) {
|
||||
case MET_Button_Down:
|
||||
if(event.button == 0 || event.button == 2)
|
||||
return true;
|
||||
break;
|
||||
case MET_Button_Up:
|
||||
if(event.button == 0 || event.button == 2) {
|
||||
showPage(ctrlKey || event.button == 2);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return BaseGuiElement::onMouseEvent(event, source);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
Color color;
|
||||
if(bp.dsg !is null)
|
||||
color = bp.dsg.color;
|
||||
if(bp.dsg !is dsg)
|
||||
update();
|
||||
|
||||
skin.draw(SS_PatternBox, SF_Normal, AbsolutePosition, color);
|
||||
if(Hovered)
|
||||
skin.draw(SS_SubtleGlow, SF_Normal, AbsolutePosition, color);
|
||||
BaseGuiElement::draw();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,194 @@
|
||||
import tabs.tabbar;
|
||||
import elements.GuiBlueprint;
|
||||
import community.DesignElement;
|
||||
import elements.GuiMarkupText;
|
||||
import elements.GuiSkinElement;
|
||||
import elements.GuiText;
|
||||
import elements.GuiButton;
|
||||
import elements.GuiPanel;
|
||||
import elements.MarkupTooltip;
|
||||
import icons;
|
||||
|
||||
class CommunityDesignList : Tab {
|
||||
WebData query;
|
||||
string listSpec;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
GuiButton@ backButton;
|
||||
GuiText@ titleBox;
|
||||
|
||||
GuiButton@ prevButton;
|
||||
GuiButton@ nextButton;
|
||||
|
||||
GuiPanel@ panel;
|
||||
array<DesignElement@> elements;
|
||||
|
||||
bool loaded = true;
|
||||
bool loading = false;
|
||||
bool hasNextPage = false;
|
||||
int elementsInPage = 10;
|
||||
|
||||
CommunityDesignList(const string& spec) {
|
||||
@backButton = GuiButton(this, Alignment(Left+8, Top+8, Left+144, Height=50), locale::BACK);
|
||||
backButton.buttonIcon = icons::Back;
|
||||
|
||||
@titleBox = GuiText(this, Alignment(Left+164, Top+8, Right-8, Top+60));
|
||||
titleBox.font = FT_Medium;
|
||||
titleBox.stroke = colors::Black;
|
||||
|
||||
@prevButton = GuiButton(this, Alignment(Left+0.5f-152, Bottom-60, Left+0.5f-2, Bottom-8), locale::PREVIOUS);
|
||||
prevButton.disabled = true;
|
||||
prevButton.setIcon(icons::Previous);
|
||||
|
||||
@nextButton = GuiButton(this, Alignment(Left+0.5f+2, Bottom-60, Left+0.5f+152, Bottom-8), locale::NEXT);
|
||||
nextButton.disabled = true;
|
||||
nextButton.setIcon(icons::Next);
|
||||
|
||||
@panel = GuiPanel(this, Alignment(Left, Top+64, Right, Bottom-64));
|
||||
|
||||
updateAbsolutePosition();
|
||||
listSpec = spec;
|
||||
}
|
||||
|
||||
void reload() {
|
||||
load(listSpec);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for(uint i = 0, cnt = elements.length; i < cnt; ++i)
|
||||
elements[i].remove();
|
||||
elements.length = 0;
|
||||
}
|
||||
|
||||
void load(const string& spec) {
|
||||
listSpec = spec;
|
||||
|
||||
if(!loading) {
|
||||
title = format(locale::COMMUNITY_TITLE, listSpec);
|
||||
titleBox.text = title;
|
||||
|
||||
int limit = getListCount();
|
||||
int page = offset / limit;
|
||||
webAPICall(format("$1?page=$2&limit=$3", spec, toString(page), toString(limit)), query);
|
||||
|
||||
loading = true;
|
||||
loaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
void show() {
|
||||
if(!loading)
|
||||
reload();
|
||||
Tab::show();
|
||||
}
|
||||
|
||||
void tick(double time) {
|
||||
backButton.disabled = previous is null;
|
||||
prevButton.disabled = offset == 0 || loading;
|
||||
nextButton.disabled = hasNextPage || loading;
|
||||
|
||||
if(loading && !loaded && query.completed)
|
||||
finish();
|
||||
}
|
||||
|
||||
void finish() {
|
||||
loaded = true;
|
||||
loading = false;
|
||||
|
||||
for(uint i = 0, cnt = elements.length; i < cnt; ++i)
|
||||
elements[i].remove();
|
||||
elements.length = 0;
|
||||
|
||||
JSONTree tree;
|
||||
tree.parse(query.result);
|
||||
|
||||
if(!tree.root.isArray())
|
||||
return;
|
||||
|
||||
hasNextPage = tree.root.size() <= getListCount();
|
||||
elementsInPage = getListCount();
|
||||
prevButton.disabled = offset == 0;
|
||||
nextButton.disabled = hasNextPage;
|
||||
|
||||
int startx = (size.width - elemsPerRow*712) / 2;
|
||||
int y = 12;
|
||||
int x = startx;
|
||||
for(uint i = 0, cnt = min(tree.root.size(), getListCount()); i < cnt; ++i) {
|
||||
auto@ mem = tree.root[i];
|
||||
if(mem !is null && mem.isObject()) {
|
||||
DesignElement elem(panel, recti_area(x,y, 700,160));
|
||||
elem.finishLoad(mem);
|
||||
elements.insertLast(elem);
|
||||
|
||||
x += 712;
|
||||
if(x+712 >= size.width) {
|
||||
x = startx;
|
||||
y += 168;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Color get_activeColor() {
|
||||
return Color(0xff83bcff);
|
||||
}
|
||||
|
||||
Color get_inactiveColor() {
|
||||
return Color(0xff0077ff);
|
||||
}
|
||||
|
||||
Color get_seperatorColor() {
|
||||
return Color(0x8d4969ff);
|
||||
}
|
||||
|
||||
TabCategory get_category() {
|
||||
return TC_Wiki;
|
||||
}
|
||||
|
||||
Sprite get_icon() {
|
||||
return Sprite(material::TabWiki);
|
||||
}
|
||||
|
||||
int get_elemsPerRow() {
|
||||
return size.width / 712;
|
||||
}
|
||||
|
||||
uint getListCount() {
|
||||
int rows = (size.height - 64 - 64 - 24) / 168;
|
||||
return clamp(elemsPerRow * rows, 3, 50);
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& evt) {
|
||||
if(evt.type == GUI_Clicked) {
|
||||
if(evt.caller is backButton) {
|
||||
popTab(this);
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is prevButton) {
|
||||
offset = max(0, offset-elementsInPage);
|
||||
clear();
|
||||
reload();
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is nextButton) {
|
||||
offset += elements.length;
|
||||
clear();
|
||||
reload();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Tab::onGuiEvent(evt);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
skin.draw(SS_WikiBG, SF_Normal, AbsolutePosition);
|
||||
skin.draw(SS_PlainBox, SF_Normal, recti(AbsolutePosition.topLeft,
|
||||
vec2i(AbsolutePosition.botRight.x, AbsolutePosition.topLeft.y+64)));
|
||||
Tab::draw();
|
||||
}
|
||||
};
|
||||
|
||||
Tab@ createCommunityDesignList(const string& spec = "designs/recent") {
|
||||
return CommunityDesignList(spec);
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
import tabs.tabbar;
|
||||
import elements.GuiBlueprint;
|
||||
import elements.GuiMarkupText;
|
||||
import elements.GuiSkinElement;
|
||||
import elements.GuiText;
|
||||
import elements.GuiTextbox;
|
||||
import elements.GuiButton;
|
||||
import elements.GuiPanel;
|
||||
import elements.MarkupTooltip;
|
||||
import dialogs.MessageDialog;
|
||||
import dialogs.QuestionDialog;
|
||||
import util.design_export;
|
||||
import icons;
|
||||
from tabs.DesignEditorTab import createDesignEditorTab;
|
||||
from tabs.WikiTab import LinkableMarkupText;
|
||||
|
||||
class CommunityDesign : Tab, QuestionDialogCallback {
|
||||
GuiDownloadedBlueprint@ bp;
|
||||
GuiText@ titleBox;
|
||||
GuiPanel@ headerPanel;
|
||||
GuiMarkupText@ header;
|
||||
GuiText@ linkTip;
|
||||
const Design@ dsg;
|
||||
|
||||
GuiButton@ backButton;
|
||||
GuiButton@ downloadProfile;
|
||||
GuiButton@ downloadEmpire;
|
||||
GuiButton@ editButton;
|
||||
|
||||
GuiButton@ votesButton;
|
||||
GuiButton@ commentsButton;
|
||||
|
||||
GuiButton@ deleteButton;
|
||||
|
||||
GuiSkinElement@ commentsBox;
|
||||
GuiPanel@ commentsPanel;
|
||||
GuiMarkupText@ comments;
|
||||
|
||||
GuiTextbox@ commentText;
|
||||
GuiButton@ commentSubmit;
|
||||
|
||||
WebData@ waitReload;
|
||||
|
||||
CommunityDesign(int id) {
|
||||
@bp = GuiDownloadedBlueprint(this, Alignment().fill());
|
||||
bp.showStats = true;
|
||||
bp.padding = recti(0,136,0,0);
|
||||
bp.load(id);
|
||||
bp.bp.hoverArcs = true;
|
||||
|
||||
@backButton = GuiButton(this, Alignment(Left+8, Top+8, Left+144, Height=50), locale::BACK);
|
||||
backButton.buttonIcon = icons::Back;
|
||||
|
||||
@downloadEmpire = GuiButton(this, Alignment(Right-208-260, Top+8, Right-264, Height=38), locale::DOWNLOAD_TO_EMPIRE);
|
||||
downloadEmpire.setIcon(icons::Add);
|
||||
setMarkupTooltip(downloadEmpire, locale::TT_DOWNLOAD_TO_EMPIRE, width=400);
|
||||
|
||||
@downloadProfile = GuiButton(this, Alignment(Right-208-260, Top+8+40, Right-264, Height=38), locale::DOWNLOAD_TO_PROFILE);
|
||||
downloadProfile.setIcon(icons::Import);
|
||||
setMarkupTooltip(downloadProfile, locale::TT_DOWNLOAD_TO_PROFILE, width=400);
|
||||
|
||||
@editButton = GuiButton(this, Alignment(Right-208-260, Top+8+40+40, Right-264, Height=38), locale::DOWNLOAD_EDIT);
|
||||
editButton.setIcon(icons::Edit);
|
||||
editButton.allowOtherButtons = true;
|
||||
setMarkupTooltip(editButton, locale::TT_DOWNLOAD_EDIT, width=400);
|
||||
|
||||
@deleteButton = GuiButton(this, Alignment(Left+8, Top+8+40+40, Left+144, Height=38), locale::DELETE);
|
||||
deleteButton.color = colors::Red;
|
||||
deleteButton.setIcon(icons::Delete);
|
||||
deleteButton.visible = false;
|
||||
|
||||
@headerPanel = GuiPanel(this, Alignment(Left+154, Top+8, Right-264-208-208, Top+135));
|
||||
headerPanel.horizType = ST_Never;
|
||||
|
||||
@titleBox = GuiText(headerPanel, Alignment(Left, Top, Right, Top+38));
|
||||
titleBox.font = FT_Big;
|
||||
titleBox.stroke = colors::Black;
|
||||
titleBox.vertAlign = 0.15;
|
||||
|
||||
@header = LinkableMarkupText(headerPanel, recti());
|
||||
@linkTip = GuiText(headerPanel, recti());
|
||||
linkTip.font = FT_Italic;
|
||||
linkTip.color = Color(0x8888aaff);
|
||||
|
||||
@votesButton = GuiButton(this, Alignment(Right-208-260-208+50, Top+20, Width=100, Height=50), locale::VOTES_BUTTON);
|
||||
votesButton.font = FT_Medium;
|
||||
votesButton.textColor = colors::Green;
|
||||
votesButton.setIcon(icons::Upvote);
|
||||
setMarkupTooltip(votesButton, locale::TT_VOTES_BUTTON);
|
||||
|
||||
@commentsBox = GuiSkinElement(this, Alignment(Right-250-500, Top+136, Right-250, Bottom), SS_PlainBox);
|
||||
commentsBox.visible = false;
|
||||
|
||||
@commentsPanel = GuiPanel(commentsBox, Alignment(Left, Top, Right, Bottom-100));
|
||||
|
||||
@comments = LinkableMarkupText(commentsPanel, recti_area(6,6,472,100));
|
||||
|
||||
@commentText = GuiTextbox(commentsBox, Alignment(Left+4, Bottom-100, Right-4, Bottom-40));
|
||||
commentText.emptyText = locale::COMMENT_TEXT;
|
||||
commentText.multiLine = true;
|
||||
|
||||
@commentSubmit = GuiButton(commentsBox, Alignment(Right-200, Bottom-38, Right-4, Bottom-4), locale::COMMENT_SUBMIT);
|
||||
commentSubmit.buttonIcon = icons::Chat;
|
||||
|
||||
@commentsButton = GuiButton(this, Alignment(Right-208-260-208, Top+8+40+40, Width=200, Height=38),
|
||||
locale::COMMENTS_BUTTON);
|
||||
commentsButton.font = FT_Bold;
|
||||
commentsButton.toggleButton = true;
|
||||
commentsButton.setIcon(icons::Chat);
|
||||
|
||||
updateAbsolutePosition();
|
||||
}
|
||||
|
||||
void updateAbsolutePosition() {
|
||||
Tab::updateAbsolutePosition();
|
||||
if(header !is null)
|
||||
header.rect = recti_area(vec2i(0,36), vec2i(headerPanel.size.width-20, header.size.height));
|
||||
if(linkTip !is null)
|
||||
linkTip.rect = recti_area(vec2i(0, header.rect.botRight.y), vec2i(headerPanel.size.width, 26));
|
||||
}
|
||||
|
||||
Color get_activeColor() {
|
||||
return Color(0xff83bcff);
|
||||
}
|
||||
|
||||
Color get_inactiveColor() {
|
||||
return Color(0xff0077ff);
|
||||
}
|
||||
|
||||
Color get_seperatorColor() {
|
||||
return Color(0x8d4969ff);
|
||||
}
|
||||
|
||||
TabCategory get_category() {
|
||||
return TC_Wiki;
|
||||
}
|
||||
|
||||
Sprite get_icon() {
|
||||
return Sprite(material::TabWiki);
|
||||
}
|
||||
|
||||
void reload() {
|
||||
bp.load(bp.designId);
|
||||
}
|
||||
|
||||
void tick(double time) {
|
||||
if(waitReload !is null && waitReload.completed) {
|
||||
reload();
|
||||
@waitReload = null;
|
||||
}
|
||||
|
||||
backButton.disabled = previous is null;
|
||||
commentsBox.visible = commentsButton.pressed;
|
||||
commentSubmit.disabled = commentText.text.length == 0;
|
||||
bp.update();
|
||||
|
||||
if(dsg !is bp.dsg) {
|
||||
@dsg = bp.dsg;
|
||||
|
||||
if(dsg !is null) {
|
||||
title = format(locale::COMMUNITY_TITLE, dsg.name);
|
||||
titleBox.text = dsg.name;
|
||||
titleBox.color = dsg.color;
|
||||
|
||||
votesButton.text = format(locale::VOTES_BUTTON, toString(bp.upvotes));
|
||||
votesButton.disabled = bp.hasUpvoted;
|
||||
if(votesButton.disabled)
|
||||
setMarkupTooltip(votesButton, "");
|
||||
else
|
||||
setMarkupTooltip(votesButton, locale::TT_VOTES_BUTTON);
|
||||
|
||||
string hstr = format(locale::COMMUNITY_DESIGN_SPEC, toString(dsg.size,0), bbescape(bp.author), bbescape(bp.ctime));
|
||||
hstr = format("[b]$1[/b]\n[i][color=#aaa]", hstr);
|
||||
hstr += bbescape(bp.description, true);
|
||||
hstr += "[/color][/i]";
|
||||
header.text = hstr;
|
||||
|
||||
linkTip.text = format(locale::DESIGN_LINK_TIP, toString(bp.designId));
|
||||
|
||||
downloadEmpire.disabled = dsg.hasFatalErrors();
|
||||
if(dsg.hasFatalErrors()) {
|
||||
string errors = locale::TT_DOWNLOAD_ERRORS;
|
||||
for(uint i = 0, cnt = dsg.errorCount; i < cnt; ++i)
|
||||
errors += "\n\n"+dsg.errors[i].text;
|
||||
setMarkupTooltip(downloadEmpire, errors, width=400);
|
||||
}
|
||||
else {
|
||||
setMarkupTooltip(downloadEmpire, locale::TT_DOWNLOAD_TO_EMPIRE, width=400);
|
||||
}
|
||||
|
||||
deleteButton.visible = bp.isMine;
|
||||
|
||||
commentsButton.text = format(locale::COMMENTS_BUTTON, toString(bp.commentCount));
|
||||
string cstr;
|
||||
for(uint i = 0, cnt = bp.comments.length; i < cnt; ++i) {
|
||||
auto@ c = bp.comments[i];
|
||||
cstr += format("[font=Subtitle]$1[color=#aaa] on $2[/color][/font]\n[vspace=6/][offset=20]",
|
||||
bbescape(c.author), bbescape(c.ctime));
|
||||
cstr += bbescape(c.content, true);
|
||||
cstr += "[/offset]\n\n";
|
||||
}
|
||||
|
||||
comments.text = cstr;
|
||||
updateAbsolutePosition();
|
||||
}
|
||||
else {
|
||||
titleBox.text = "---";
|
||||
title = "---";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void questionCallback(QuestionDialog@ dialog, int answer) {
|
||||
if(answer == QA_Yes) {
|
||||
WebData dat;
|
||||
dat.addPost("delete", "true");
|
||||
webAPICall("design/"+bp.designId+"/delete", dat);
|
||||
while(!dat.completed)
|
||||
sleep(100);
|
||||
popTab(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& evt) {
|
||||
if(evt.type == GUI_Clicked) {
|
||||
if(evt.caller is backButton) {
|
||||
popTab(this);
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is votesButton) {
|
||||
WebData dat;
|
||||
dat.addPost("vote", "true");
|
||||
webAPICall("design/"+bp.designId+"/vote", dat);
|
||||
|
||||
votesButton.text = format(locale::VOTES_BUTTON, toString(bp.upvotes+1));
|
||||
votesButton.disabled = true;
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is deleteButton) {
|
||||
question(locale::COMMUNITY_CONFIRM_DELETE_DESIGN, this);
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is commentSubmit) {
|
||||
if(commentText.text.length > 0 ){
|
||||
WebData dat;
|
||||
dat.addPost("author", settings::sNickname);
|
||||
dat.addPost("content", commentText.text);
|
||||
webAPICall("design/"+bp.designId+"/comment", dat);
|
||||
|
||||
commentText.text = "";
|
||||
@waitReload = dat;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is downloadEmpire) {
|
||||
if(dsg !is null) {
|
||||
auto@ cls = playerEmpire.getDesignClass(locale::DOWNLOAD_DESIGN_CLASS, true);
|
||||
auto@ prev = playerEmpire.getDesign(dsg.name);
|
||||
if(prev !is null)
|
||||
playerEmpire.changeDesign(prev, dsg, cls);
|
||||
else
|
||||
playerEmpire.addDesign(cls, dsg);
|
||||
message(locale::SUCCESS_DOWNLOAD_TO_EMPIRE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is downloadProfile) {
|
||||
string fname = path_join(modProfile["designs"], dsg.name+".design");
|
||||
write_design(dsg, fname);
|
||||
message(locale::SUCCESS_DOWNLOAD_TO_PROFILE);
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is editButton) {
|
||||
if(dsg !is null) {
|
||||
if(ctrlKey || evt.value == 2)
|
||||
newTab(createDesignEditorTab(dsg));
|
||||
else
|
||||
browseTab(this, createDesignEditorTab(dsg), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Tab::onGuiEvent(evt);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
skin.draw(SS_WikiBG, SF_Normal, AbsolutePosition);
|
||||
skin.draw(SS_PlainBox, SF_Normal, recti(AbsolutePosition.topLeft,
|
||||
vec2i(AbsolutePosition.botRight.x-250, AbsolutePosition.topLeft.y+136)));
|
||||
Tab::draw();
|
||||
}
|
||||
};
|
||||
|
||||
Tab@ createCommunityDesignPage(int id) {
|
||||
return CommunityDesign(id);
|
||||
}
|
||||
|
||||
class CommunityDesignCommand : ConsoleCommand {
|
||||
void execute(const string& args) {
|
||||
auto@ page = createCommunityDesignPage(toInt(args));
|
||||
newTab(page);
|
||||
switchToTab(page);
|
||||
}
|
||||
};
|
||||
|
||||
void init() {
|
||||
addConsoleCommand("design_page", CommunityDesignCommand());
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
import tabs.tabbar;
|
||||
import elements.GuiBlueprint;
|
||||
import community.DesignElement;
|
||||
import elements.GuiMarkupText;
|
||||
import elements.GuiSkinElement;
|
||||
import elements.GuiDropdown;
|
||||
import elements.GuiText;
|
||||
import elements.GuiTextbox;
|
||||
import elements.GuiButton;
|
||||
import elements.GuiSprite;
|
||||
import elements.GuiPanel;
|
||||
import elements.GuiBackgroundPanel;
|
||||
import elements.MarkupTooltip;
|
||||
import dialogs.Dialog;
|
||||
import util.formatting;
|
||||
from tabs.WikiTab import LinkableMarkupText;
|
||||
from community.DesignList import createCommunityDesignList;
|
||||
from community.DesignPage import createCommunityDesignPage;
|
||||
import icons;
|
||||
|
||||
class CommunityHome : Tab {
|
||||
WebData query;
|
||||
WebData wiki;
|
||||
string listSpec;
|
||||
|
||||
BaseGuiElement@ container;
|
||||
|
||||
GuiBackgroundPanel@ designBG;
|
||||
GuiPanel@ panel;
|
||||
array<DesignElement@> elements;
|
||||
|
||||
GuiBackgroundPanel@ wikiBG;
|
||||
GuiPanel@ wikiPanel;
|
||||
LinkableMarkupText@ wikiText;
|
||||
|
||||
GuiButton@ uploadButton;
|
||||
GuiButton@ recentDesigns;
|
||||
GuiButton@ topratedDesigns;
|
||||
GuiTextbox@ searchDesigns;
|
||||
GuiButton@ internetButton;
|
||||
|
||||
bool loaded = true;
|
||||
bool loading = false;
|
||||
|
||||
CommunityHome() {
|
||||
title = locale::COMMUNITY_HOME_TITLE;
|
||||
|
||||
@container = BaseGuiElement(this, Alignment().fill());
|
||||
@internetButton = GuiButton(this, Alignment(Left+0.5f-200, Top+0.5f-30, Left+0.5f+200, Top+0.5f+30), locale::ENABLE_INTERNET);
|
||||
internetButton.visible = false;
|
||||
|
||||
@designBG = GuiBackgroundPanel(container, Alignment(Left+29, Top+35, Left+35+600+48, Bottom-80));
|
||||
designBG.title = locale::FEATURED_DESIGNS;
|
||||
designBG.titleColor = colors::FTL;
|
||||
designBG.titleHeight = 42;
|
||||
designBG.titleFont = FT_Big;
|
||||
|
||||
@panel = GuiPanel(designBG, Alignment(Left+4, Top+42, Right-4, Bottom-8));
|
||||
|
||||
@uploadButton = GuiButton(container, Alignment(Left+34+600+48-200, Bottom-72, Width=200, Height=52), locale::UPLOAD_DESIGN);
|
||||
uploadButton.font = FT_Bold;
|
||||
uploadButton.setIcon(icons::Export);
|
||||
|
||||
@recentDesigns = GuiButton(container, Alignment(Left+30+600+48-424, Bottom-75, Width=200, Height=30), locale::RECENT_DESIGNS);
|
||||
|
||||
@topratedDesigns = GuiButton(container, Alignment(Left+30+600+48-424, Bottom-75+32, Width=200, Height=30), locale::TOPRATED_DESIGNS);
|
||||
|
||||
@searchDesigns = GuiTextbox(container, Alignment(Left+30, Bottom-69, Width=200, Height=46));
|
||||
searchDesigns.emptyText = locale::SEARCH_DESIGNS_PROMPT;
|
||||
|
||||
@wikiBG = GuiBackgroundPanel(container, Alignment(Left+30+600+48+30, Top+30, Right-30, Bottom-30));
|
||||
wikiBG.title = locale::COMMUNITY_WIKI;
|
||||
wikiBG.titleColor = colors::Research;
|
||||
wikiBG.titleHeight = 42;
|
||||
wikiBG.titleFont = FT_Big;
|
||||
|
||||
@wikiPanel = GuiPanel(wikiBG, Alignment(Left+4, Top+42, Right-4, Bottom-12));
|
||||
|
||||
@wikiText = LinkableMarkupText(wikiPanel, recti_area(12,12, 100,100), true);
|
||||
|
||||
if(cloud::isActive)
|
||||
settings::bEnableInternet = true;
|
||||
|
||||
updateAbsolutePosition();
|
||||
listSpec = "designs/featured";
|
||||
}
|
||||
|
||||
void updateAbsolutePosition() {
|
||||
Tab::updateAbsolutePosition();
|
||||
if(wikiText.size.width != wikiPanel.size.width-44) {
|
||||
wikiText.size = vec2i(wikiPanel.size.width-44, wikiText.size.height);
|
||||
wikiText.updateAbsolutePosition();
|
||||
}
|
||||
}
|
||||
|
||||
void reload() {
|
||||
if(settings::bEnableInternet) {
|
||||
container.visible = true;
|
||||
internetButton.visible = false;
|
||||
|
||||
load(listSpec);
|
||||
}
|
||||
else {
|
||||
container.visible = false;
|
||||
internetButton.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
void load(const string& spec) {
|
||||
listSpec = spec;
|
||||
webAPICall(spec, query);
|
||||
|
||||
getWikiPage("Main Page", wiki);
|
||||
|
||||
loading = true;
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
void show() {
|
||||
if(!loading)
|
||||
reload();
|
||||
Tab::show();
|
||||
}
|
||||
|
||||
void tick(double time) {
|
||||
if(loading && !loaded && query.completed && wiki.completed)
|
||||
finish();
|
||||
}
|
||||
|
||||
void finish() {
|
||||
loaded = true;
|
||||
loading = false;
|
||||
|
||||
wikiText.text = wiki.result;
|
||||
|
||||
for(uint i = 0, cnt = elements.length; i < cnt; ++i)
|
||||
elements[i].remove();
|
||||
elements.length = 0;
|
||||
|
||||
JSONTree tree;
|
||||
tree.parse(query.result);
|
||||
|
||||
if(!tree.root.isArray())
|
||||
return;
|
||||
|
||||
int y = 12;
|
||||
for(uint i = 0, cnt = min(tree.root.size(), panel.size.height / 138); i < cnt; ++i) {
|
||||
auto@ mem = tree.root[i];
|
||||
if(mem !is null && mem.isObject()) {
|
||||
DesignElement elem(panel, recti_area(20,y, 600,130));
|
||||
elem.finishLoad(mem);
|
||||
elements.insertLast(elem);
|
||||
y += 138;
|
||||
}
|
||||
}
|
||||
|
||||
updateAbsolutePosition();
|
||||
}
|
||||
|
||||
Color get_activeColor() {
|
||||
return Color(0xff83bcff);
|
||||
}
|
||||
|
||||
Color get_inactiveColor() {
|
||||
return Color(0xff0077ff);
|
||||
}
|
||||
|
||||
Color get_seperatorColor() {
|
||||
return Color(0x8d4969ff);
|
||||
}
|
||||
|
||||
TabCategory get_category() {
|
||||
return TC_Wiki;
|
||||
}
|
||||
|
||||
Sprite get_icon() {
|
||||
return Sprite(material::TabWiki);
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& evt) {
|
||||
if(evt.type == GUI_Clicked) {
|
||||
if(evt.caller is recentDesigns) {
|
||||
browseTab(this, createCommunityDesignList("designs/recent"), true);
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is topratedDesigns) {
|
||||
browseTab(this, createCommunityDesignList("designs/toprated"), true);
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is uploadButton) {
|
||||
UploadDialog(this);
|
||||
return true;
|
||||
}
|
||||
else if(evt.caller is internetButton) {
|
||||
settings::bEnableInternet = true;
|
||||
saveSettings();
|
||||
reload();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(evt.type == GUI_Confirmed) {
|
||||
if(evt.caller is searchDesigns) {
|
||||
browseTab(this, createCommunityDesignList("designs/search/"+searchDesigns.text), true);
|
||||
searchDesigns.text = "";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Tab::onGuiEvent(evt);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
skin.draw(SS_WikiBG, SF_Normal, AbsolutePosition);
|
||||
Tab::draw();
|
||||
}
|
||||
};
|
||||
|
||||
class UploadDialog : Dialog {
|
||||
GuiDropdown@ design;
|
||||
GuiTextbox@ description;
|
||||
|
||||
GuiButton@ accept;
|
||||
GuiButton@ cancel;
|
||||
|
||||
array<const Design@> designs;
|
||||
|
||||
UploadDialog(IGuiElement@ bind) {
|
||||
super(bind, bindInside=true);
|
||||
width = 600;
|
||||
height = 200;
|
||||
|
||||
@accept = GuiButton(bg, recti());
|
||||
accept.text = locale::UPLOAD;
|
||||
accept.tabIndex = 100;
|
||||
accept.disabled = true;
|
||||
@accept.callback = this;
|
||||
accept.color = colors::Green;
|
||||
|
||||
@cancel = GuiButton(bg, recti());
|
||||
cancel.text = locale::CANCEL;
|
||||
cancel.tabIndex = 101;
|
||||
@cancel.callback = this;
|
||||
cancel.color = colors::Red;
|
||||
|
||||
@design = GuiDropdown(bg, Alignment(Left+12, Top+40, Right-12, Top+76));
|
||||
|
||||
ReadLock lck(playerEmpire.designMutex);
|
||||
uint cnt = playerEmpire.designCount;
|
||||
designs.reserve(cnt);
|
||||
designs.length = 0;
|
||||
design.addItem(locale::DESIGN_CHOOSE_PROMPT);
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
const Design@ other = playerEmpire.designs[i];
|
||||
if(other.obsolete || other.newest() !is other)
|
||||
continue;
|
||||
design.addItem(formatShipName(other));
|
||||
designs.insertLast(other);
|
||||
}
|
||||
|
||||
@description = GuiTextbox(bg, Alignment(Left+12, Top+80, Right-12, Bottom-46));
|
||||
description.multiLine = true;
|
||||
description.emptyText = locale::DESIGN_DESCRIPTION_PROMPT;
|
||||
|
||||
addTitle(locale::UPLOAD_DESIGN, color=colors::FTL);
|
||||
|
||||
alignAcceptButtons(accept, cancel);
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void update() {
|
||||
accept.disabled = design.selected < 1;
|
||||
}
|
||||
|
||||
void close() {
|
||||
close(false);
|
||||
}
|
||||
|
||||
void close(bool accepted) {
|
||||
if(accepted && design.selected >= 1) {
|
||||
int id = upload_design(designs[design.selected-1], description.text, waitId=true);
|
||||
if(id > 0)
|
||||
browseTab(ActiveTab, createCommunityDesignPage(id), true);
|
||||
}
|
||||
Dialog::close();
|
||||
}
|
||||
|
||||
void confirmDialog() {
|
||||
close(true);
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& event) {
|
||||
if(Closed)
|
||||
return false;
|
||||
if(event.type == GUI_Clicked && (event.caller is accept || event.caller is cancel)) {
|
||||
close(event.caller is accept);
|
||||
return true;
|
||||
}
|
||||
else if(event.type == GUI_Changed) {
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
return Dialog::onGuiEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
Tab@ createCommunityHome() {
|
||||
return CommunityHome();
|
||||
}
|
||||
Reference in New Issue
Block a user