Refactor AngelScript code
Split huge source files
This commit is contained in:
parent
604d82eee4
commit
8e7cf01492
204
Resources/Scripts/Gui/Client/ChatLogWindow.as
Normal file
204
Resources/Scripts/Gui/Client/ChatLogWindow.as
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "ChatSayWindow.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class ChatLogSayWindow: ClientChatWindow {
|
||||||
|
ChatLogWindow@ owner;
|
||||||
|
|
||||||
|
ChatLogSayWindow(ChatLogWindow@ own, bool isTeamChat) {
|
||||||
|
super(own.ui, isTeamChat);
|
||||||
|
@owner = own;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close() {
|
||||||
|
owner.SayWindowClosed();
|
||||||
|
@this.Parent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChatLogWindow: spades::ui::UIElement {
|
||||||
|
|
||||||
|
float contentsTop, contentsHeight;
|
||||||
|
|
||||||
|
ClientUI@ ui;
|
||||||
|
private ClientUIHelper@ helper;
|
||||||
|
|
||||||
|
private spades::ui::TextViewer@ viewer;
|
||||||
|
ChatLogSayWindow@ sayWindow;
|
||||||
|
|
||||||
|
private spades::ui::UIElement@ sayButton1;
|
||||||
|
private spades::ui::UIElement@ sayButton2;
|
||||||
|
|
||||||
|
ChatLogWindow(ClientUI@ ui) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@this.helper = ui.helper;
|
||||||
|
|
||||||
|
@Font = Manager.RootElement.Font;
|
||||||
|
this.Bounds = Manager.RootElement.Bounds;
|
||||||
|
|
||||||
|
float contentsWidth = 700.f;
|
||||||
|
float contentsLeft = (Manager.Renderer.ScreenWidth - contentsWidth) * 0.5f;
|
||||||
|
contentsHeight = Manager.Renderer.ScreenHeight - 200.f;
|
||||||
|
contentsTop = (Manager.Renderer.ScreenHeight - contentsHeight - 106.f) * 0.5f;
|
||||||
|
{
|
||||||
|
spades::ui::Label label(Manager);
|
||||||
|
label.BackgroundColor = Vector4(0, 0, 0, 0.4f);
|
||||||
|
label.Bounds = Bounds;
|
||||||
|
AddChild(label);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Label label(Manager);
|
||||||
|
label.BackgroundColor = Vector4(0, 0, 0, 0.8f);
|
||||||
|
label.Bounds = AABB2(0.f, contentsTop - 13.f, Size.x, contentsHeight + 27.f);
|
||||||
|
AddChild(label);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Close");
|
||||||
|
button.Bounds = AABB2(
|
||||||
|
contentsLeft + contentsWidth - 150.f,
|
||||||
|
contentsTop + contentsHeight - 30.f
|
||||||
|
, 150.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnOkPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Say Global");
|
||||||
|
button.Bounds = AABB2(
|
||||||
|
contentsLeft,
|
||||||
|
contentsTop + contentsHeight - 30.f
|
||||||
|
, 150.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnGlobalChat);
|
||||||
|
AddChild(button);
|
||||||
|
@this.sayButton1 = button;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Say Team");
|
||||||
|
button.Bounds = AABB2(
|
||||||
|
contentsLeft + 155.f,
|
||||||
|
contentsTop + contentsHeight - 30.f
|
||||||
|
, 150.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnTeamChat);
|
||||||
|
AddChild(button);
|
||||||
|
@this.sayButton2 = button;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::TextViewer viewer(Manager);
|
||||||
|
AddChild(viewer);
|
||||||
|
viewer.Bounds = AABB2(contentsLeft, contentsTop, contentsWidth, contentsHeight - 40.f);
|
||||||
|
@this.viewer = viewer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollToEnd() {
|
||||||
|
viewer.Layout();
|
||||||
|
viewer.ScrollToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close() {
|
||||||
|
@ui.ActiveUI = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SayWindowClosed() {
|
||||||
|
@sayWindow = null;
|
||||||
|
sayButton1.Enable = true;
|
||||||
|
sayButton2.Enable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnOkPressed(spades::ui::UIElement@ sender) {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTeamChat(spades::ui::UIElement@ sender) {
|
||||||
|
if(sayWindow !is null) {
|
||||||
|
sayWindow.IsTeamChat = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sayButton1.Enable = false;
|
||||||
|
sayButton2.Enable = false;
|
||||||
|
ChatLogSayWindow wnd(this, true);
|
||||||
|
AddChild(wnd);
|
||||||
|
wnd.Bounds = this.Bounds;
|
||||||
|
@this.sayWindow = wnd;
|
||||||
|
@Manager.ActiveElement = wnd.field;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGlobalChat(spades::ui::UIElement@ sender) {
|
||||||
|
if(sayWindow !is null) {
|
||||||
|
sayWindow.IsTeamChat = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sayButton1.Enable = false;
|
||||||
|
sayButton2.Enable = false;
|
||||||
|
ChatLogSayWindow wnd(this, false);
|
||||||
|
AddChild(wnd);
|
||||||
|
wnd.Bounds = this.Bounds;
|
||||||
|
@this.sayWindow = wnd;
|
||||||
|
@Manager.ActiveElement = wnd.field;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotKey(string key) {
|
||||||
|
if(sayWindow !is null) {
|
||||||
|
UIElement::HotKey(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(IsEnabled and (key == "Escape")) {
|
||||||
|
Close();
|
||||||
|
} else if(IsEnabled and (key == "y")) {
|
||||||
|
OnTeamChat(this);
|
||||||
|
} else if(IsEnabled and (key == "t")) {
|
||||||
|
OnGlobalChat(this);
|
||||||
|
} else {
|
||||||
|
UIElement::HotKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Record(string text, Vector4 color) {
|
||||||
|
viewer.AddLine(text, this.IsVisible, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Renderer@ r = Manager.Renderer;
|
||||||
|
Image@ img = r.RegisterImage("Gfx/White.tga");
|
||||||
|
|
||||||
|
r.ColorNP = Vector4(1, 1, 1, 0.08f);
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + contentsTop - 15.f, size.x, 1.f));
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + contentsTop + contentsHeight + 15.f, size.x, 1.f));
|
||||||
|
r.ColorNP = Vector4(1, 1, 1, 0.2f);
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + contentsTop - 14.f, size.x, 1.f));
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + contentsTop + contentsHeight + 14.f, size.x, 1.f));
|
||||||
|
|
||||||
|
UIElement::Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
318
Resources/Scripts/Gui/Client/ChatSayWindow.as
Normal file
318
Resources/Scripts/Gui/Client/ChatSayWindow.as
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "FieldWithHistory.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
uint StringCommonPrefixLength(string a, string b) {
|
||||||
|
for(uint i = 0, ln = Min(a.length, b.length); i < ln; i++) {
|
||||||
|
if(ToLower(a[i]) != ToLower(b[i])) return i;
|
||||||
|
}
|
||||||
|
return Min(a.length, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shows cvar's current value when user types something like "/cg_foobar" */
|
||||||
|
class CommandFieldConfigValueView: spades::ui::UIElement {
|
||||||
|
string[]@ configNames;
|
||||||
|
string[] configValues;
|
||||||
|
CommandFieldConfigValueView(spades::ui::UIManager@ manager, string[] configNames) {
|
||||||
|
super(manager);
|
||||||
|
for(uint i = 0, len = configNames.length; i < len; i++) {
|
||||||
|
configValues.insertLast(ConfigItem(configNames[i]).StringValue);
|
||||||
|
}
|
||||||
|
@this.configNames = configNames;
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
float maxNameLen = 0.f;
|
||||||
|
float maxValueLen = 20.f;
|
||||||
|
Font@ font = this.Font;
|
||||||
|
Renderer@ renderer = this.Manager.Renderer;
|
||||||
|
float rowHeight = 25.f;
|
||||||
|
|
||||||
|
for(uint i = 0, len = configNames.length; i < len; i++) {
|
||||||
|
maxNameLen = Max(maxNameLen, font.Measure(configNames[i]).x);
|
||||||
|
maxValueLen = Max(maxValueLen, font.Measure(configValues[i]).x);
|
||||||
|
}
|
||||||
|
Vector2 pos = this.ScreenPosition;
|
||||||
|
pos.y -= float(configNames.length) * rowHeight + 10.f;
|
||||||
|
|
||||||
|
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, 0.5f);
|
||||||
|
renderer.DrawImage(null,
|
||||||
|
AABB2(pos.x, pos.y, maxNameLen + maxValueLen + 20.f,
|
||||||
|
float(configNames.length) * rowHeight + 10.f));
|
||||||
|
|
||||||
|
for(uint i = 0, len = configNames.length; i < len; i++) {
|
||||||
|
font.DrawShadow(configNames[i],
|
||||||
|
pos + Vector2(5.f, 8.f + float(i) * rowHeight),
|
||||||
|
1.f, Vector4(1,1,1,0.7), Vector4(0,0,0,0.3f));
|
||||||
|
font.DrawShadow(configValues[i],
|
||||||
|
pos + Vector2(15.f + maxNameLen, 8.f + float(i) * rowHeight),
|
||||||
|
1.f, Vector4(1,1,1,1), Vector4(0,0,0,0.4f));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommandField: FieldWithHistory {
|
||||||
|
CommandFieldConfigValueView@ valueView;
|
||||||
|
|
||||||
|
CommandField(spades::ui::UIManager@ manager, array<spades::ui::CommandHistoryItem@>@ history) {
|
||||||
|
super(manager, history);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnChanged() {
|
||||||
|
FieldWithHistory::OnChanged();
|
||||||
|
|
||||||
|
if(valueView !is null) {
|
||||||
|
@valueView.Parent = null;
|
||||||
|
}
|
||||||
|
if(Text.substr(0, 1) == "/" &&
|
||||||
|
Text.substr(1, 1) != " ") {
|
||||||
|
int whitespace = Text.findFirst(" ");
|
||||||
|
if(whitespace < 0) {
|
||||||
|
whitespace = int(Text.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
string input = Text.substr(1, whitespace - 1);
|
||||||
|
if(input.length >= 2) {
|
||||||
|
string[]@ names = GetAllConfigNames();
|
||||||
|
string[] filteredNames;
|
||||||
|
for(uint i = 0, len = names.length; i < len; i++) {
|
||||||
|
if (
|
||||||
|
StringCommonPrefixLength(input, names[i]) == input.length &&
|
||||||
|
!ConfigItem(names[i]).IsUnknown
|
||||||
|
) {
|
||||||
|
filteredNames.insertLast(names[i]);
|
||||||
|
if(filteredNames.length >= 8) {
|
||||||
|
// too many
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(filteredNames.length > 0) {
|
||||||
|
@valueView = CommandFieldConfigValueView(this.Manager, filteredNames);
|
||||||
|
valueView.Bounds = AABB2(0.f, -15.f, 0.f, 0.f);
|
||||||
|
@valueView.Parent = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyDown(string key) {
|
||||||
|
if(key == "Tab") {
|
||||||
|
if(SelectionLength == 0 &&
|
||||||
|
SelectionStart == int(Text.length) &&
|
||||||
|
Text.substr(0, 1) == "/" &&
|
||||||
|
Text.findFirst(" ") < 0) {
|
||||||
|
// config variable auto completion
|
||||||
|
string input = Text.substr(1);
|
||||||
|
string[]@ names = GetAllConfigNames();
|
||||||
|
string commonPart;
|
||||||
|
bool foundOne = false;
|
||||||
|
for(uint i = 0, len = names.length; i < len; i++) {
|
||||||
|
if (
|
||||||
|
StringCommonPrefixLength(input, names[i]) == input.length &&
|
||||||
|
!ConfigItem(names[i]).IsUnknown
|
||||||
|
) {
|
||||||
|
if(!foundOne) {
|
||||||
|
commonPart = names[i];
|
||||||
|
foundOne = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint commonLen = StringCommonPrefixLength(commonPart, names[i]);
|
||||||
|
commonPart = commonPart.substr(0, commonLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(commonPart.length > input.length) {
|
||||||
|
Text = "/" + commonPart;
|
||||||
|
Select(Text.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
FieldWithHistory::KeyDown(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClientChatWindow: spades::ui::UIElement {
|
||||||
|
private ClientUI@ ui;
|
||||||
|
private ClientUIHelper@ helper;
|
||||||
|
|
||||||
|
CommandField@ field;
|
||||||
|
spades::ui::Button@ sayButton;
|
||||||
|
spades::ui::SimpleButton@ teamButton;
|
||||||
|
spades::ui::SimpleButton@ globalButton;
|
||||||
|
|
||||||
|
bool isTeamChat;
|
||||||
|
|
||||||
|
ClientChatWindow(ClientUI@ ui, bool isTeamChat) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@this.helper = ui.helper;
|
||||||
|
this.isTeamChat = isTeamChat;
|
||||||
|
|
||||||
|
float winW = Manager.Renderer.ScreenWidth * 0.7f, winH = 66.f;
|
||||||
|
float winX = (Manager.Renderer.ScreenWidth - winW) * 0.5f;
|
||||||
|
float winY = (Manager.Renderer.ScreenHeight - winH) - 20.f;
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
spades::ui::Label label(Manager);
|
||||||
|
label.BackgroundColor = Vector4(0, 0, 0, 0.5f);
|
||||||
|
label.Bounds = Bounds;
|
||||||
|
AddChild(label);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::Label label(Manager);
|
||||||
|
label.BackgroundColor = Vector4(0, 0, 0, 0.5f);
|
||||||
|
label.Bounds = AABB2(winX - 8.f, winY - 8.f, winW + 16.f, winH + 16.f);
|
||||||
|
AddChild(label);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Say");
|
||||||
|
button.Bounds = AABB2(winX + winW - 244.f, winY + 36.f, 120.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnSay);
|
||||||
|
AddChild(button);
|
||||||
|
@sayButton = button;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Cancel");
|
||||||
|
button.Bounds = AABB2(winX + winW - 120.f, winY + 36.f, 120.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnCancel);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@field = CommandField(Manager, ui.chatHistory);
|
||||||
|
field.Bounds = AABB2(winX, winY, winW, 30.f);
|
||||||
|
field.Placeholder = _Tr("Client", "Chat Text");
|
||||||
|
@field.Changed = spades::ui::EventHandler(this.OnFieldChanged);
|
||||||
|
AddChild(field);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@globalButton = spades::ui::SimpleButton(Manager);
|
||||||
|
globalButton.Toggle = true;
|
||||||
|
globalButton.Toggled = isTeamChat == false;
|
||||||
|
globalButton.Caption = _Tr("Client", "Global");
|
||||||
|
globalButton.Bounds = AABB2(winX, winY + 36.f, 70.f, 30.f);
|
||||||
|
@globalButton.Activated = spades::ui::EventHandler(this.OnSetGlobal);
|
||||||
|
AddChild(globalButton);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@teamButton = spades::ui::SimpleButton(Manager);
|
||||||
|
teamButton.Toggle = true;
|
||||||
|
teamButton.Toggled = isTeamChat == true;
|
||||||
|
teamButton.Caption = _Tr("Client", "Team");
|
||||||
|
teamButton.Bounds = AABB2(winX + 70.f, winY + 36.f, 70.f, 30.f);
|
||||||
|
@teamButton.Activated = spades::ui::EventHandler(this.OnSetTeam);
|
||||||
|
AddChild(teamButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateState() {
|
||||||
|
sayButton.Enable = field.Text.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsTeamChat {
|
||||||
|
get final { return isTeamChat; }
|
||||||
|
set {
|
||||||
|
if(isTeamChat == value) return;
|
||||||
|
isTeamChat = value;
|
||||||
|
teamButton.Toggled = isTeamChat;
|
||||||
|
globalButton.Toggled = not isTeamChat;
|
||||||
|
UpdateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSetGlobal(spades::ui::UIElement@ sender) {
|
||||||
|
IsTeamChat = false;
|
||||||
|
}
|
||||||
|
private void OnSetTeam(spades::ui::UIElement@ sender) {
|
||||||
|
IsTeamChat = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFieldChanged(spades::ui::UIElement@ sender) {
|
||||||
|
UpdateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Close() {
|
||||||
|
@ui.ActiveUI = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCancel(spades::ui::UIElement@ sender) {
|
||||||
|
field.Cancelled();
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckAndSetConfigVariable() {
|
||||||
|
string text = field.Text;
|
||||||
|
if(text.substr(0, 1) != "/") return false;
|
||||||
|
int idx = text.findFirst(" ");
|
||||||
|
if(idx < 2) return false;
|
||||||
|
|
||||||
|
// find variable
|
||||||
|
string varname = text.substr(1, idx - 1);
|
||||||
|
string[] vars = GetAllConfigNames();
|
||||||
|
|
||||||
|
for(uint i = 0, len = vars.length; i < len; i++) {
|
||||||
|
if(vars[i].length == varname.length &&
|
||||||
|
StringCommonPrefixLength(vars[i], varname) == vars[i].length) {
|
||||||
|
// match
|
||||||
|
string val = text.substr(idx + 1);
|
||||||
|
ConfigItem item(vars[i]);
|
||||||
|
item.StringValue = val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSay(spades::ui::UIElement@ sender) {
|
||||||
|
field.CommandSent();
|
||||||
|
if(!CheckAndSetConfigVariable()) {
|
||||||
|
if(isTeamChat)
|
||||||
|
ui.helper.SayTeam(field.Text);
|
||||||
|
else
|
||||||
|
ui.helper.SayGlobal(field.Text);
|
||||||
|
}
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotKey(string key) {
|
||||||
|
if(IsEnabled and key == "Escape") {
|
||||||
|
OnCancel(this);
|
||||||
|
}else if(IsEnabled and key == "Enter") {
|
||||||
|
if(field.Text.length == 0) {
|
||||||
|
OnCancel(this);
|
||||||
|
}else{
|
||||||
|
OnSay(this);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UIElement::HotKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
164
Resources/Scripts/Gui/Client/ClientUI.as
Normal file
164
Resources/Scripts/Gui/Client/ClientUI.as
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "Menu.as"
|
||||||
|
#include "FieldWithHistory.as"
|
||||||
|
#include "ChatLogWindow.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class ClientUI {
|
||||||
|
private Renderer@ renderer;
|
||||||
|
private AudioDevice@ audioDevice;
|
||||||
|
FontManager@ fontManager;
|
||||||
|
ClientUIHelper@ helper;
|
||||||
|
|
||||||
|
spades::ui::UIManager@ manager;
|
||||||
|
spades::ui::UIElement@ activeUI;
|
||||||
|
|
||||||
|
ChatLogWindow@ chatLogWindow;
|
||||||
|
|
||||||
|
ClientMenu@ clientMenu;
|
||||||
|
|
||||||
|
array<spades::ui::CommandHistoryItem@> chatHistory;
|
||||||
|
|
||||||
|
bool shouldExit = false;
|
||||||
|
|
||||||
|
private float time = -1.f;
|
||||||
|
|
||||||
|
ClientUI(Renderer@ renderer, AudioDevice@ audioDevice, FontManager@ fontManager, ClientUIHelper@ helper) {
|
||||||
|
@this.renderer = renderer;
|
||||||
|
@this.audioDevice = audioDevice;
|
||||||
|
@this.fontManager = fontManager;
|
||||||
|
@this.helper = helper;
|
||||||
|
|
||||||
|
@manager = spades::ui::UIManager(renderer, audioDevice);
|
||||||
|
@manager.RootElement.Font = fontManager.GuiFont;
|
||||||
|
|
||||||
|
@clientMenu = ClientMenu(this);
|
||||||
|
clientMenu.Bounds = manager.RootElement.Bounds;
|
||||||
|
|
||||||
|
@chatLogWindow = ChatLogWindow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseEvent(float x, float y) {
|
||||||
|
manager.MouseEvent(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WheelEvent(float x, float y) {
|
||||||
|
manager.WheelEvent(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyEvent(string key, bool down) {
|
||||||
|
manager.KeyEvent(key, down);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputEvent(string text) {
|
||||||
|
manager.TextInputEvent(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextEditingEvent(string text, int start, int len) {
|
||||||
|
manager.TextEditingEvent(text, start, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AcceptsTextInput() {
|
||||||
|
return manager.AcceptsTextInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB2 GetTextInputRect() {
|
||||||
|
return manager.TextInputRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunFrame(float dt) {
|
||||||
|
if(time < 0.f) {
|
||||||
|
time = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.RunFrame(dt);
|
||||||
|
if(activeUI !is null){
|
||||||
|
manager.Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
time += Min(dt, 0.05f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Closing() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WantsClientToBeClosed() {
|
||||||
|
return shouldExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NeedsInput() {
|
||||||
|
return activeUI !is null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_ActiveUI(spades::ui::UIElement@ value) {
|
||||||
|
if(activeUI !is null) {
|
||||||
|
manager.RootElement.RemoveChild(activeUI);
|
||||||
|
}
|
||||||
|
@activeUI = value;
|
||||||
|
if(activeUI !is null) {
|
||||||
|
activeUI.Bounds = manager.RootElement.Bounds;
|
||||||
|
manager.RootElement.AddChild(activeUI);
|
||||||
|
}
|
||||||
|
manager.KeyPanic();
|
||||||
|
}
|
||||||
|
spades::ui::UIElement@ get_ActiveUI(){
|
||||||
|
return activeUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterClientMenu() {
|
||||||
|
@ActiveUI = clientMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterTeamChatWindow() {
|
||||||
|
ClientChatWindow wnd(this, true);
|
||||||
|
@ActiveUI = wnd;
|
||||||
|
@manager.ActiveElement = wnd.field;
|
||||||
|
}
|
||||||
|
void EnterGlobalChatWindow() {
|
||||||
|
ClientChatWindow wnd(this, false);
|
||||||
|
@ActiveUI = wnd;
|
||||||
|
@manager.ActiveElement = wnd.field;
|
||||||
|
}
|
||||||
|
void EnterCommandWindow() {
|
||||||
|
ClientChatWindow wnd(this, true);
|
||||||
|
wnd.field.Text = "/";
|
||||||
|
wnd.field.Select(1, 0);
|
||||||
|
wnd.UpdateState();
|
||||||
|
@ActiveUI = wnd;
|
||||||
|
@manager.ActiveElement = wnd.field;
|
||||||
|
}
|
||||||
|
void CloseUI() {
|
||||||
|
@ActiveUI = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordChatLog(string text, Vector4 color) {
|
||||||
|
chatLogWindow.Record(text, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientUI@ CreateClientUI(Renderer@ renderer, AudioDevice@ audioDevice,
|
||||||
|
FontManager@ fontManager, ClientUIHelper@ helper) {
|
||||||
|
return ClientUI(renderer, audioDevice, fontManager, helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
104
Resources/Scripts/Gui/Client/FieldWithHistory.as
Normal file
104
Resources/Scripts/Gui/Client/FieldWithHistory.as
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "../UIFramework/Field.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class CommandHistoryItem {
|
||||||
|
string text;
|
||||||
|
int selStart;
|
||||||
|
int selEnd;
|
||||||
|
CommandHistoryItem() {}
|
||||||
|
CommandHistoryItem(string text, int selStart, int selEnd) {
|
||||||
|
this.text = text;
|
||||||
|
this.selStart = selStart;
|
||||||
|
this.selEnd = selEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field with bash-like history support
|
||||||
|
class FieldWithHistory: spades::ui::Field {
|
||||||
|
array<spades::ui::CommandHistoryItem@>@ cmdhistory;
|
||||||
|
CommandHistoryItem@ temporalLastHistory;
|
||||||
|
uint currentHistoryIndex;
|
||||||
|
|
||||||
|
FieldWithHistory(spades::ui::UIManager@ manager, array<spades::ui::CommandHistoryItem@>@ history) {
|
||||||
|
super(manager);
|
||||||
|
|
||||||
|
@this.cmdhistory = history;
|
||||||
|
currentHistoryIndex = history.length;
|
||||||
|
@temporalLastHistory = this.CommandHistoryItemRep;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandHistoryItem@ CommandHistoryItemRep {
|
||||||
|
get {
|
||||||
|
return CommandHistoryItem(this.Text, this.SelectionStart, this.SelectionEnd);
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this.Text = value.text;
|
||||||
|
this.Select(value.selStart, value.selEnd - value.selStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OverwriteItem() {
|
||||||
|
if(currentHistoryIndex < cmdhistory.length) {
|
||||||
|
@cmdhistory[currentHistoryIndex] = this.CommandHistoryItemRep;
|
||||||
|
}else if(currentHistoryIndex == cmdhistory.length) {
|
||||||
|
@temporalLastHistory = this.CommandHistoryItemRep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadItem() {
|
||||||
|
if(currentHistoryIndex < cmdhistory.length) {
|
||||||
|
@this.CommandHistoryItemRep = cmdhistory[currentHistoryIndex];
|
||||||
|
}else if(currentHistoryIndex == cmdhistory.length) {
|
||||||
|
@this.CommandHistoryItemRep = temporalLastHistory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyDown(string key) {
|
||||||
|
if(key == "Up") {
|
||||||
|
if(currentHistoryIndex > 0) {
|
||||||
|
OverwriteItem();
|
||||||
|
currentHistoryIndex--;
|
||||||
|
LoadItem();
|
||||||
|
}
|
||||||
|
}else if(key == "Down") {
|
||||||
|
if(currentHistoryIndex < cmdhistory.length) {
|
||||||
|
OverwriteItem();
|
||||||
|
currentHistoryIndex++;
|
||||||
|
LoadItem();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Field::KeyDown(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandSent() {
|
||||||
|
cmdhistory.insertLast(this.CommandHistoryItemRep);
|
||||||
|
currentHistoryIndex = cmdhistory.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cancelled() {
|
||||||
|
OverwriteItem();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
108
Resources/Scripts/Gui/Client/Menu.as
Normal file
108
Resources/Scripts/Gui/Client/Menu.as
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "ClientUI.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class ClientMenu: spades::ui::UIElement {
|
||||||
|
private ClientUI@ ui;
|
||||||
|
private ClientUIHelper@ helper;
|
||||||
|
|
||||||
|
ClientMenu(ClientUI@ ui) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@this.helper = ui.helper;
|
||||||
|
|
||||||
|
float winW = 180.f, winH = 32.f * 4.f - 2.f;
|
||||||
|
float winX = (Manager.Renderer.ScreenWidth - winW) * 0.5f;
|
||||||
|
float winY = (Manager.Renderer.ScreenHeight - winH) * 0.5f;
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::Label label(Manager);
|
||||||
|
label.BackgroundColor = Vector4(0, 0, 0, 0.5f);
|
||||||
|
label.Bounds = AABB2(0.f, 0.f,
|
||||||
|
Manager.Renderer.ScreenWidth, Manager.Renderer.ScreenHeight);
|
||||||
|
AddChild(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::Label label(Manager);
|
||||||
|
label.BackgroundColor = Vector4(0, 0, 0, 0.5f);
|
||||||
|
label.Bounds = AABB2(winX - 8.f, winY - 8.f, winW + 16.f, winH + 16.f);
|
||||||
|
AddChild(label);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Back to Game");
|
||||||
|
button.Bounds = AABB2(winX, winY, winW, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnBackToGame);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Chat Log");
|
||||||
|
button.Bounds = AABB2(winX, winY + 32.f, winW, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnChatLog);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Setup");
|
||||||
|
button.Bounds = AABB2(winX, winY + 64.f, winW, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnSetup);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("Client", "Disconnect");
|
||||||
|
button.Bounds = AABB2(winX, winY + 96.f, winW, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnDisconnect);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBackToGame(spades::ui::UIElement@ sender) {
|
||||||
|
@ui.ActiveUI = null;
|
||||||
|
}
|
||||||
|
private void OnSetup(spades::ui::UIElement@ sender) {
|
||||||
|
PreferenceViewOptions opt;
|
||||||
|
opt.GameActive = true;
|
||||||
|
|
||||||
|
PreferenceView al(this, opt, ui.fontManager);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
private void OnChatLog(spades::ui::UIElement@ sender) {
|
||||||
|
@ui.ActiveUI = @ui.chatLogWindow;
|
||||||
|
ui.chatLogWindow.ScrollToEnd();
|
||||||
|
}
|
||||||
|
private void OnDisconnect(spades::ui::UIElement@ sender) {
|
||||||
|
ui.shouldExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotKey(string key) {
|
||||||
|
if(IsEnabled and key == "Escape") {
|
||||||
|
@ui.ActiveUI = null;
|
||||||
|
} else {
|
||||||
|
UIElement::HotKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,799 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2013 yvt
|
|
||||||
|
|
||||||
This file is part of OpenSpades.
|
|
||||||
|
|
||||||
OpenSpades is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenSpades is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
namespace spades {
|
|
||||||
|
|
||||||
class CommandHistoryItem {
|
|
||||||
string text;
|
|
||||||
int selStart;
|
|
||||||
int selEnd;
|
|
||||||
CommandHistoryItem() {}
|
|
||||||
CommandHistoryItem(string text, int selStart, int selEnd) {
|
|
||||||
this.text = text;
|
|
||||||
this.selStart = selStart;
|
|
||||||
this.selEnd = selEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClientUI {
|
|
||||||
private Renderer@ renderer;
|
|
||||||
private AudioDevice@ audioDevice;
|
|
||||||
FontManager@ fontManager;
|
|
||||||
ClientUIHelper@ helper;
|
|
||||||
|
|
||||||
spades::ui::UIManager@ manager;
|
|
||||||
spades::ui::UIElement@ activeUI;
|
|
||||||
|
|
||||||
ChatLogWindow@ chatLogWindow;
|
|
||||||
|
|
||||||
ClientMenu@ clientMenu;
|
|
||||||
|
|
||||||
array<spades::ui::CommandHistoryItem@> chatHistory;
|
|
||||||
|
|
||||||
bool shouldExit = false;
|
|
||||||
|
|
||||||
private float time = -1.f;
|
|
||||||
|
|
||||||
ClientUI(Renderer@ renderer, AudioDevice@ audioDevice, FontManager@ fontManager, ClientUIHelper@ helper) {
|
|
||||||
@this.renderer = renderer;
|
|
||||||
@this.audioDevice = audioDevice;
|
|
||||||
@this.fontManager = fontManager;
|
|
||||||
@this.helper = helper;
|
|
||||||
|
|
||||||
@manager = spades::ui::UIManager(renderer, audioDevice);
|
|
||||||
@manager.RootElement.Font = fontManager.GuiFont;
|
|
||||||
|
|
||||||
@clientMenu = ClientMenu(this);
|
|
||||||
clientMenu.Bounds = manager.RootElement.Bounds;
|
|
||||||
|
|
||||||
@chatLogWindow = ChatLogWindow(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseEvent(float x, float y) {
|
|
||||||
manager.MouseEvent(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WheelEvent(float x, float y) {
|
|
||||||
manager.WheelEvent(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyEvent(string key, bool down) {
|
|
||||||
manager.KeyEvent(key, down);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextInputEvent(string text) {
|
|
||||||
manager.TextInputEvent(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextEditingEvent(string text, int start, int len) {
|
|
||||||
manager.TextEditingEvent(text, start, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AcceptsTextInput() {
|
|
||||||
return manager.AcceptsTextInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
AABB2 GetTextInputRect() {
|
|
||||||
return manager.TextInputRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunFrame(float dt) {
|
|
||||||
if(time < 0.f) {
|
|
||||||
time = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
manager.RunFrame(dt);
|
|
||||||
if(activeUI !is null){
|
|
||||||
manager.Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
time += Min(dt, 0.05f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Closing() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WantsClientToBeClosed() {
|
|
||||||
return shouldExit;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NeedsInput() {
|
|
||||||
return activeUI !is null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_ActiveUI(spades::ui::UIElement@ value) {
|
|
||||||
if(activeUI !is null) {
|
|
||||||
manager.RootElement.RemoveChild(activeUI);
|
|
||||||
}
|
|
||||||
@activeUI = value;
|
|
||||||
if(activeUI !is null) {
|
|
||||||
activeUI.Bounds = manager.RootElement.Bounds;
|
|
||||||
manager.RootElement.AddChild(activeUI);
|
|
||||||
}
|
|
||||||
manager.KeyPanic();
|
|
||||||
}
|
|
||||||
spades::ui::UIElement@ get_ActiveUI(){
|
|
||||||
return activeUI;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnterClientMenu() {
|
|
||||||
@ActiveUI = clientMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnterTeamChatWindow() {
|
|
||||||
ClientChatWindow wnd(this, true);
|
|
||||||
@ActiveUI = wnd;
|
|
||||||
@manager.ActiveElement = wnd.field;
|
|
||||||
}
|
|
||||||
void EnterGlobalChatWindow() {
|
|
||||||
ClientChatWindow wnd(this, false);
|
|
||||||
@ActiveUI = wnd;
|
|
||||||
@manager.ActiveElement = wnd.field;
|
|
||||||
}
|
|
||||||
void EnterCommandWindow() {
|
|
||||||
ClientChatWindow wnd(this, true);
|
|
||||||
wnd.field.Text = "/";
|
|
||||||
wnd.field.Select(1, 0);
|
|
||||||
wnd.UpdateState();
|
|
||||||
@ActiveUI = wnd;
|
|
||||||
@manager.ActiveElement = wnd.field;
|
|
||||||
}
|
|
||||||
void CloseUI() {
|
|
||||||
@ActiveUI = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RecordChatLog(string text, Vector4 color) {
|
|
||||||
chatLogWindow.Record(text, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClientMenu: spades::ui::UIElement {
|
|
||||||
private ClientUI@ ui;
|
|
||||||
private ClientUIHelper@ helper;
|
|
||||||
|
|
||||||
ClientMenu(ClientUI@ ui) {
|
|
||||||
super(ui.manager);
|
|
||||||
@this.ui = ui;
|
|
||||||
@this.helper = ui.helper;
|
|
||||||
|
|
||||||
float winW = 180.f, winH = 32.f * 4.f - 2.f;
|
|
||||||
float winX = (Manager.Renderer.ScreenWidth - winW) * 0.5f;
|
|
||||||
float winY = (Manager.Renderer.ScreenHeight - winH) * 0.5f;
|
|
||||||
|
|
||||||
{
|
|
||||||
spades::ui::Label label(Manager);
|
|
||||||
label.BackgroundColor = Vector4(0, 0, 0, 0.5f);
|
|
||||||
label.Bounds = AABB2(0.f, 0.f,
|
|
||||||
Manager.Renderer.ScreenWidth, Manager.Renderer.ScreenHeight);
|
|
||||||
AddChild(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
spades::ui::Label label(Manager);
|
|
||||||
label.BackgroundColor = Vector4(0, 0, 0, 0.5f);
|
|
||||||
label.Bounds = AABB2(winX - 8.f, winY - 8.f, winW + 16.f, winH + 16.f);
|
|
||||||
AddChild(label);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Back to Game");
|
|
||||||
button.Bounds = AABB2(winX, winY, winW, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnBackToGame);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Chat Log");
|
|
||||||
button.Bounds = AABB2(winX, winY + 32.f, winW, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnChatLog);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Setup");
|
|
||||||
button.Bounds = AABB2(winX, winY + 64.f, winW, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnSetup);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Disconnect");
|
|
||||||
button.Bounds = AABB2(winX, winY + 96.f, winW, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnDisconnect);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBackToGame(spades::ui::UIElement@ sender) {
|
|
||||||
@ui.ActiveUI = null;
|
|
||||||
}
|
|
||||||
private void OnSetup(spades::ui::UIElement@ sender) {
|
|
||||||
PreferenceViewOptions opt;
|
|
||||||
opt.GameActive = true;
|
|
||||||
|
|
||||||
PreferenceView al(this, opt, ui.fontManager);
|
|
||||||
al.Run();
|
|
||||||
}
|
|
||||||
private void OnChatLog(spades::ui::UIElement@ sender) {
|
|
||||||
@ui.ActiveUI = @ui.chatLogWindow;
|
|
||||||
ui.chatLogWindow.ScrollToEnd();
|
|
||||||
}
|
|
||||||
private void OnDisconnect(spades::ui::UIElement@ sender) {
|
|
||||||
ui.shouldExit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HotKey(string key) {
|
|
||||||
if(IsEnabled and key == "Escape") {
|
|
||||||
@ui.ActiveUI = null;
|
|
||||||
} else {
|
|
||||||
UIElement::HotKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Field with bash-like history support
|
|
||||||
class FieldWithHistory: spades::ui::Field {
|
|
||||||
array<spades::ui::CommandHistoryItem@>@ cmdhistory;
|
|
||||||
CommandHistoryItem@ temporalLastHistory;
|
|
||||||
uint currentHistoryIndex;
|
|
||||||
|
|
||||||
FieldWithHistory(spades::ui::UIManager@ manager, array<spades::ui::CommandHistoryItem@>@ history) {
|
|
||||||
super(manager);
|
|
||||||
|
|
||||||
@this.cmdhistory = history;
|
|
||||||
currentHistoryIndex = history.length;
|
|
||||||
@temporalLastHistory = this.CommandHistoryItemRep;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CommandHistoryItem@ CommandHistoryItemRep {
|
|
||||||
get {
|
|
||||||
return CommandHistoryItem(this.Text, this.SelectionStart, this.SelectionEnd);
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
this.Text = value.text;
|
|
||||||
this.Select(value.selStart, value.selEnd - value.selStart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OverwriteItem() {
|
|
||||||
if(currentHistoryIndex < cmdhistory.length) {
|
|
||||||
@cmdhistory[currentHistoryIndex] = this.CommandHistoryItemRep;
|
|
||||||
}else if(currentHistoryIndex == cmdhistory.length) {
|
|
||||||
@temporalLastHistory = this.CommandHistoryItemRep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadItem() {
|
|
||||||
if(currentHistoryIndex < cmdhistory.length) {
|
|
||||||
@this.CommandHistoryItemRep = cmdhistory[currentHistoryIndex];
|
|
||||||
}else if(currentHistoryIndex == cmdhistory.length) {
|
|
||||||
@this.CommandHistoryItemRep = temporalLastHistory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyDown(string key) {
|
|
||||||
if(key == "Up") {
|
|
||||||
if(currentHistoryIndex > 0) {
|
|
||||||
OverwriteItem();
|
|
||||||
currentHistoryIndex--;
|
|
||||||
LoadItem();
|
|
||||||
}
|
|
||||||
}else if(key == "Down") {
|
|
||||||
if(currentHistoryIndex < cmdhistory.length) {
|
|
||||||
OverwriteItem();
|
|
||||||
currentHistoryIndex++;
|
|
||||||
LoadItem();
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
Field::KeyDown(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandSent() {
|
|
||||||
cmdhistory.insertLast(this.CommandHistoryItemRep);
|
|
||||||
currentHistoryIndex = cmdhistory.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cancelled() {
|
|
||||||
OverwriteItem();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
uint StringCommonPrefixLength(string a, string b) {
|
|
||||||
for(uint i = 0, ln = Min(a.length, b.length); i < ln; i++) {
|
|
||||||
if(ToLower(a[i]) != ToLower(b[i])) return i;
|
|
||||||
}
|
|
||||||
return Min(a.length, b.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Shows cvar's current value when user types something like "/cg_foobar" */
|
|
||||||
class CommandFieldConfigValueView: spades::ui::UIElement {
|
|
||||||
string[]@ configNames;
|
|
||||||
string[] configValues;
|
|
||||||
CommandFieldConfigValueView(spades::ui::UIManager@ manager, string[] configNames) {
|
|
||||||
super(manager);
|
|
||||||
for(uint i = 0, len = configNames.length; i < len; i++) {
|
|
||||||
configValues.insertLast(ConfigItem(configNames[i]).StringValue);
|
|
||||||
}
|
|
||||||
@this.configNames = configNames;
|
|
||||||
}
|
|
||||||
void Render() {
|
|
||||||
float maxNameLen = 0.f;
|
|
||||||
float maxValueLen = 20.f;
|
|
||||||
Font@ font = this.Font;
|
|
||||||
Renderer@ renderer = this.Manager.Renderer;
|
|
||||||
float rowHeight = 25.f;
|
|
||||||
|
|
||||||
for(uint i = 0, len = configNames.length; i < len; i++) {
|
|
||||||
maxNameLen = Max(maxNameLen, font.Measure(configNames[i]).x);
|
|
||||||
maxValueLen = Max(maxValueLen, font.Measure(configValues[i]).x);
|
|
||||||
}
|
|
||||||
Vector2 pos = this.ScreenPosition;
|
|
||||||
pos.y -= float(configNames.length) * rowHeight + 10.f;
|
|
||||||
|
|
||||||
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, 0.5f);
|
|
||||||
renderer.DrawImage(null,
|
|
||||||
AABB2(pos.x, pos.y, maxNameLen + maxValueLen + 20.f,
|
|
||||||
float(configNames.length) * rowHeight + 10.f));
|
|
||||||
|
|
||||||
for(uint i = 0, len = configNames.length; i < len; i++) {
|
|
||||||
font.DrawShadow(configNames[i],
|
|
||||||
pos + Vector2(5.f, 8.f + float(i) * rowHeight),
|
|
||||||
1.f, Vector4(1,1,1,0.7), Vector4(0,0,0,0.3f));
|
|
||||||
font.DrawShadow(configValues[i],
|
|
||||||
pos + Vector2(15.f + maxNameLen, 8.f + float(i) * rowHeight),
|
|
||||||
1.f, Vector4(1,1,1,1), Vector4(0,0,0,0.4f));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CommandField: FieldWithHistory {
|
|
||||||
CommandFieldConfigValueView@ valueView;
|
|
||||||
|
|
||||||
CommandField(spades::ui::UIManager@ manager, array<spades::ui::CommandHistoryItem@>@ history) {
|
|
||||||
super(manager, history);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnChanged() {
|
|
||||||
FieldWithHistory::OnChanged();
|
|
||||||
|
|
||||||
if(valueView !is null) {
|
|
||||||
@valueView.Parent = null;
|
|
||||||
}
|
|
||||||
if(Text.substr(0, 1) == "/" &&
|
|
||||||
Text.substr(1, 1) != " ") {
|
|
||||||
int whitespace = Text.findFirst(" ");
|
|
||||||
if(whitespace < 0) {
|
|
||||||
whitespace = int(Text.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
string input = Text.substr(1, whitespace - 1);
|
|
||||||
if(input.length >= 2) {
|
|
||||||
string[]@ names = GetAllConfigNames();
|
|
||||||
string[] filteredNames;
|
|
||||||
for(uint i = 0, len = names.length; i < len; i++) {
|
|
||||||
if (
|
|
||||||
StringCommonPrefixLength(input, names[i]) == input.length &&
|
|
||||||
!ConfigItem(names[i]).IsUnknown
|
|
||||||
) {
|
|
||||||
filteredNames.insertLast(names[i]);
|
|
||||||
if(filteredNames.length >= 8) {
|
|
||||||
// too many
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(filteredNames.length > 0) {
|
|
||||||
@valueView = CommandFieldConfigValueView(this.Manager, filteredNames);
|
|
||||||
valueView.Bounds = AABB2(0.f, -15.f, 0.f, 0.f);
|
|
||||||
@valueView.Parent = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyDown(string key) {
|
|
||||||
if(key == "Tab") {
|
|
||||||
if(SelectionLength == 0 &&
|
|
||||||
SelectionStart == int(Text.length) &&
|
|
||||||
Text.substr(0, 1) == "/" &&
|
|
||||||
Text.findFirst(" ") < 0) {
|
|
||||||
// config variable auto completion
|
|
||||||
string input = Text.substr(1);
|
|
||||||
string[]@ names = GetAllConfigNames();
|
|
||||||
string commonPart;
|
|
||||||
bool foundOne = false;
|
|
||||||
for(uint i = 0, len = names.length; i < len; i++) {
|
|
||||||
if (
|
|
||||||
StringCommonPrefixLength(input, names[i]) == input.length &&
|
|
||||||
!ConfigItem(names[i]).IsUnknown
|
|
||||||
) {
|
|
||||||
if(!foundOne) {
|
|
||||||
commonPart = names[i];
|
|
||||||
foundOne = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint commonLen = StringCommonPrefixLength(commonPart, names[i]);
|
|
||||||
commonPart = commonPart.substr(0, commonLen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(commonPart.length > input.length) {
|
|
||||||
Text = "/" + commonPart;
|
|
||||||
Select(Text.length, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
FieldWithHistory::KeyDown(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClientChatWindow: spades::ui::UIElement {
|
|
||||||
private ClientUI@ ui;
|
|
||||||
private ClientUIHelper@ helper;
|
|
||||||
|
|
||||||
CommandField@ field;
|
|
||||||
spades::ui::Button@ sayButton;
|
|
||||||
spades::ui::SimpleButton@ teamButton;
|
|
||||||
spades::ui::SimpleButton@ globalButton;
|
|
||||||
|
|
||||||
bool isTeamChat;
|
|
||||||
|
|
||||||
ClientChatWindow(ClientUI@ ui, bool isTeamChat) {
|
|
||||||
super(ui.manager);
|
|
||||||
@this.ui = ui;
|
|
||||||
@this.helper = ui.helper;
|
|
||||||
this.isTeamChat = isTeamChat;
|
|
||||||
|
|
||||||
float winW = Manager.Renderer.ScreenWidth * 0.7f, winH = 66.f;
|
|
||||||
float winX = (Manager.Renderer.ScreenWidth - winW) * 0.5f;
|
|
||||||
float winY = (Manager.Renderer.ScreenHeight - winH) - 20.f;
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
spades::ui::Label label(Manager);
|
|
||||||
label.BackgroundColor = Vector4(0, 0, 0, 0.5f);
|
|
||||||
label.Bounds = Bounds;
|
|
||||||
AddChild(label);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
{
|
|
||||||
spades::ui::Label label(Manager);
|
|
||||||
label.BackgroundColor = Vector4(0, 0, 0, 0.5f);
|
|
||||||
label.Bounds = AABB2(winX - 8.f, winY - 8.f, winW + 16.f, winH + 16.f);
|
|
||||||
AddChild(label);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Say");
|
|
||||||
button.Bounds = AABB2(winX + winW - 244.f, winY + 36.f, 120.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnSay);
|
|
||||||
AddChild(button);
|
|
||||||
@sayButton = button;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Cancel");
|
|
||||||
button.Bounds = AABB2(winX + winW - 120.f, winY + 36.f, 120.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnCancel);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@field = CommandField(Manager, ui.chatHistory);
|
|
||||||
field.Bounds = AABB2(winX, winY, winW, 30.f);
|
|
||||||
field.Placeholder = _Tr("Client", "Chat Text");
|
|
||||||
@field.Changed = spades::ui::EventHandler(this.OnFieldChanged);
|
|
||||||
AddChild(field);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@globalButton = spades::ui::SimpleButton(Manager);
|
|
||||||
globalButton.Toggle = true;
|
|
||||||
globalButton.Toggled = isTeamChat == false;
|
|
||||||
globalButton.Caption = _Tr("Client", "Global");
|
|
||||||
globalButton.Bounds = AABB2(winX, winY + 36.f, 70.f, 30.f);
|
|
||||||
@globalButton.Activated = spades::ui::EventHandler(this.OnSetGlobal);
|
|
||||||
AddChild(globalButton);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@teamButton = spades::ui::SimpleButton(Manager);
|
|
||||||
teamButton.Toggle = true;
|
|
||||||
teamButton.Toggled = isTeamChat == true;
|
|
||||||
teamButton.Caption = _Tr("Client", "Team");
|
|
||||||
teamButton.Bounds = AABB2(winX + 70.f, winY + 36.f, 70.f, 30.f);
|
|
||||||
@teamButton.Activated = spades::ui::EventHandler(this.OnSetTeam);
|
|
||||||
AddChild(teamButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateState() {
|
|
||||||
sayButton.Enable = field.Text.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsTeamChat {
|
|
||||||
get final { return isTeamChat; }
|
|
||||||
set {
|
|
||||||
if(isTeamChat == value) return;
|
|
||||||
isTeamChat = value;
|
|
||||||
teamButton.Toggled = isTeamChat;
|
|
||||||
globalButton.Toggled = not isTeamChat;
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSetGlobal(spades::ui::UIElement@ sender) {
|
|
||||||
IsTeamChat = false;
|
|
||||||
}
|
|
||||||
private void OnSetTeam(spades::ui::UIElement@ sender) {
|
|
||||||
IsTeamChat = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnFieldChanged(spades::ui::UIElement@ sender) {
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Close() {
|
|
||||||
@ui.ActiveUI = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCancel(spades::ui::UIElement@ sender) {
|
|
||||||
field.Cancelled();
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckAndSetConfigVariable() {
|
|
||||||
string text = field.Text;
|
|
||||||
if(text.substr(0, 1) != "/") return false;
|
|
||||||
int idx = text.findFirst(" ");
|
|
||||||
if(idx < 2) return false;
|
|
||||||
|
|
||||||
// find variable
|
|
||||||
string varname = text.substr(1, idx - 1);
|
|
||||||
string[] vars = GetAllConfigNames();
|
|
||||||
|
|
||||||
for(uint i = 0, len = vars.length; i < len; i++) {
|
|
||||||
if(vars[i].length == varname.length &&
|
|
||||||
StringCommonPrefixLength(vars[i], varname) == vars[i].length) {
|
|
||||||
// match
|
|
||||||
string val = text.substr(idx + 1);
|
|
||||||
ConfigItem item(vars[i]);
|
|
||||||
item.StringValue = val;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSay(spades::ui::UIElement@ sender) {
|
|
||||||
field.CommandSent();
|
|
||||||
if(!CheckAndSetConfigVariable()) {
|
|
||||||
if(isTeamChat)
|
|
||||||
ui.helper.SayTeam(field.Text);
|
|
||||||
else
|
|
||||||
ui.helper.SayGlobal(field.Text);
|
|
||||||
}
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HotKey(string key) {
|
|
||||||
if(IsEnabled and key == "Escape") {
|
|
||||||
OnCancel(this);
|
|
||||||
}else if(IsEnabled and key == "Enter") {
|
|
||||||
if(field.Text.length == 0) {
|
|
||||||
OnCancel(this);
|
|
||||||
}else{
|
|
||||||
OnSay(this);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
UIElement::HotKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatLogSayWindow: ClientChatWindow {
|
|
||||||
ChatLogWindow@ owner;
|
|
||||||
|
|
||||||
ChatLogSayWindow(ChatLogWindow@ own, bool isTeamChat) {
|
|
||||||
super(own.ui, isTeamChat);
|
|
||||||
@owner = own;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close() {
|
|
||||||
owner.SayWindowClosed();
|
|
||||||
@this.Parent = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatLogWindow: spades::ui::UIElement {
|
|
||||||
|
|
||||||
float contentsTop, contentsHeight;
|
|
||||||
|
|
||||||
ClientUI@ ui;
|
|
||||||
private ClientUIHelper@ helper;
|
|
||||||
|
|
||||||
private spades::ui::TextViewer@ viewer;
|
|
||||||
ChatLogSayWindow@ sayWindow;
|
|
||||||
|
|
||||||
private spades::ui::UIElement@ sayButton1;
|
|
||||||
private spades::ui::UIElement@ sayButton2;
|
|
||||||
|
|
||||||
ChatLogWindow(ClientUI@ ui) {
|
|
||||||
super(ui.manager);
|
|
||||||
@this.ui = ui;
|
|
||||||
@this.helper = ui.helper;
|
|
||||||
|
|
||||||
@Font = Manager.RootElement.Font;
|
|
||||||
this.Bounds = Manager.RootElement.Bounds;
|
|
||||||
|
|
||||||
float contentsWidth = 700.f;
|
|
||||||
float contentsLeft = (Manager.Renderer.ScreenWidth - contentsWidth) * 0.5f;
|
|
||||||
contentsHeight = Manager.Renderer.ScreenHeight - 200.f;
|
|
||||||
contentsTop = (Manager.Renderer.ScreenHeight - contentsHeight - 106.f) * 0.5f;
|
|
||||||
{
|
|
||||||
spades::ui::Label label(Manager);
|
|
||||||
label.BackgroundColor = Vector4(0, 0, 0, 0.4f);
|
|
||||||
label.Bounds = Bounds;
|
|
||||||
AddChild(label);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Label label(Manager);
|
|
||||||
label.BackgroundColor = Vector4(0, 0, 0, 0.8f);
|
|
||||||
label.Bounds = AABB2(0.f, contentsTop - 13.f, Size.x, contentsHeight + 27.f);
|
|
||||||
AddChild(label);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Close");
|
|
||||||
button.Bounds = AABB2(
|
|
||||||
contentsLeft + contentsWidth - 150.f,
|
|
||||||
contentsTop + contentsHeight - 30.f
|
|
||||||
, 150.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnOkPressed);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Say Global");
|
|
||||||
button.Bounds = AABB2(
|
|
||||||
contentsLeft,
|
|
||||||
contentsTop + contentsHeight - 30.f
|
|
||||||
, 150.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnGlobalChat);
|
|
||||||
AddChild(button);
|
|
||||||
@this.sayButton1 = button;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("Client", "Say Team");
|
|
||||||
button.Bounds = AABB2(
|
|
||||||
contentsLeft + 155.f,
|
|
||||||
contentsTop + contentsHeight - 30.f
|
|
||||||
, 150.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnTeamChat);
|
|
||||||
AddChild(button);
|
|
||||||
@this.sayButton2 = button;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::TextViewer viewer(Manager);
|
|
||||||
AddChild(viewer);
|
|
||||||
viewer.Bounds = AABB2(contentsLeft, contentsTop, contentsWidth, contentsHeight - 40.f);
|
|
||||||
@this.viewer = viewer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScrollToEnd() {
|
|
||||||
viewer.Layout();
|
|
||||||
viewer.ScrollToEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close() {
|
|
||||||
@ui.ActiveUI = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SayWindowClosed() {
|
|
||||||
@sayWindow = null;
|
|
||||||
sayButton1.Enable = true;
|
|
||||||
sayButton2.Enable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnOkPressed(spades::ui::UIElement@ sender) {
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTeamChat(spades::ui::UIElement@ sender) {
|
|
||||||
if(sayWindow !is null) {
|
|
||||||
sayWindow.IsTeamChat = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sayButton1.Enable = false;
|
|
||||||
sayButton2.Enable = false;
|
|
||||||
ChatLogSayWindow wnd(this, true);
|
|
||||||
AddChild(wnd);
|
|
||||||
wnd.Bounds = this.Bounds;
|
|
||||||
@this.sayWindow = wnd;
|
|
||||||
@Manager.ActiveElement = wnd.field;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGlobalChat(spades::ui::UIElement@ sender) {
|
|
||||||
if(sayWindow !is null) {
|
|
||||||
sayWindow.IsTeamChat = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sayButton1.Enable = false;
|
|
||||||
sayButton2.Enable = false;
|
|
||||||
ChatLogSayWindow wnd(this, false);
|
|
||||||
AddChild(wnd);
|
|
||||||
wnd.Bounds = this.Bounds;
|
|
||||||
@this.sayWindow = wnd;
|
|
||||||
@Manager.ActiveElement = wnd.field;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HotKey(string key) {
|
|
||||||
if(sayWindow !is null) {
|
|
||||||
UIElement::HotKey(key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(IsEnabled and (key == "Escape")) {
|
|
||||||
Close();
|
|
||||||
} else if(IsEnabled and (key == "y")) {
|
|
||||||
OnTeamChat(this);
|
|
||||||
} else if(IsEnabled and (key == "t")) {
|
|
||||||
OnGlobalChat(this);
|
|
||||||
} else {
|
|
||||||
UIElement::HotKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Record(string text, Vector4 color) {
|
|
||||||
viewer.AddLine(text, this.IsVisible, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Render() {
|
|
||||||
Vector2 pos = ScreenPosition;
|
|
||||||
Vector2 size = Size;
|
|
||||||
Renderer@ r = Manager.Renderer;
|
|
||||||
Image@ img = r.RegisterImage("Gfx/White.tga");
|
|
||||||
|
|
||||||
r.ColorNP = Vector4(1, 1, 1, 0.08f);
|
|
||||||
r.DrawImage(img,
|
|
||||||
AABB2(pos.x, pos.y + contentsTop - 15.f, size.x, 1.f));
|
|
||||||
r.DrawImage(img,
|
|
||||||
AABB2(pos.x, pos.y + contentsTop + contentsHeight + 15.f, size.x, 1.f));
|
|
||||||
r.ColorNP = Vector4(1, 1, 1, 0.2f);
|
|
||||||
r.DrawImage(img,
|
|
||||||
AABB2(pos.x, pos.y + contentsTop - 14.f, size.x, 1.f));
|
|
||||||
r.DrawImage(img,
|
|
||||||
AABB2(pos.x, pos.y + contentsTop + contentsHeight + 14.f, size.x, 1.f));
|
|
||||||
|
|
||||||
UIElement::Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientUI@ CreateClientUI(Renderer@ renderer, AudioDevice@ audioDevice,
|
|
||||||
FontManager@ fontManager, ClientUIHelper@ helper) {
|
|
||||||
return ClientUI(renderer, audioDevice, fontManager, helper);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +1,26 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2013 yvt
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
This file is part of OpenSpades.
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
OpenSpades is free software: you can redistribute it and/or modify
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
OpenSpades is distributed in the hope that it will be useful,
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "UIFramework.as"
|
#include "UIFramework/UIFramework.as"
|
||||||
#include "UIControls.as"
|
|
||||||
#include "MessageBox.as"
|
#include "MessageBox.as"
|
||||||
#include "MainScreen.as"
|
#include "MainScreen/MainScreenUI.as"
|
||||||
#include "StartupScreen.as"
|
#include "StartupScreen/StartupScreenUI.as"
|
||||||
#include "Preferences.as"
|
#include "Preferences.as"
|
||||||
#include "ClientUI.as"
|
#include "Client/ClientUI.as"
|
||||||
|
@ -1,838 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2013 yvt
|
|
||||||
|
|
||||||
This file is part of OpenSpades.
|
|
||||||
|
|
||||||
OpenSpades is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
OpenSpades is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Flags.as"
|
|
||||||
#include "CreateProfileScreen.as"
|
|
||||||
|
|
||||||
namespace spades {
|
|
||||||
|
|
||||||
|
|
||||||
class MainScreenUI {
|
|
||||||
private Renderer@ renderer;
|
|
||||||
private AudioDevice@ audioDevice;
|
|
||||||
FontManager@ fontManager;
|
|
||||||
MainScreenHelper@ helper;
|
|
||||||
|
|
||||||
spades::ui::UIManager@ manager;
|
|
||||||
|
|
||||||
MainScreenMainMenu@ mainMenu;
|
|
||||||
|
|
||||||
bool shouldExit = false;
|
|
||||||
|
|
||||||
private float time = -1.f;
|
|
||||||
|
|
||||||
private ConfigItem cg_playerName("cg_playerName");
|
|
||||||
private ConfigItem cg_playerNameIsSet("cg_playerNameIsSet", "0");
|
|
||||||
|
|
||||||
MainScreenUI(Renderer@ renderer, AudioDevice@ audioDevice, FontManager@ fontManager, MainScreenHelper@ helper) {
|
|
||||||
@this.renderer = renderer;
|
|
||||||
@this.audioDevice = audioDevice;
|
|
||||||
@this.fontManager = fontManager;
|
|
||||||
@this.helper = helper;
|
|
||||||
|
|
||||||
SetupRenderer();
|
|
||||||
|
|
||||||
@manager = spades::ui::UIManager(renderer, audioDevice);
|
|
||||||
@manager.RootElement.Font = fontManager.GuiFont;
|
|
||||||
|
|
||||||
@mainMenu = MainScreenMainMenu(this);
|
|
||||||
mainMenu.Bounds = manager.RootElement.Bounds;
|
|
||||||
manager.RootElement.AddChild(mainMenu);
|
|
||||||
|
|
||||||
// Let the new player choose their IGN
|
|
||||||
if (cg_playerName.StringValue != "" &&
|
|
||||||
cg_playerName.StringValue != "Deuce") {
|
|
||||||
cg_playerNameIsSet.IntValue = 1;
|
|
||||||
}
|
|
||||||
if (cg_playerNameIsSet.IntValue == 0) {
|
|
||||||
CreateProfileScreen al(mainMenu);
|
|
||||||
al.Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupRenderer() {
|
|
||||||
// load map
|
|
||||||
@renderer.GameMap = GameMap("Maps/Title.vxl");
|
|
||||||
renderer.FogColor = Vector3(0.1f, 0.10f, 0.1f);
|
|
||||||
renderer.FogDistance = 128.f;
|
|
||||||
time = -1.f;
|
|
||||||
|
|
||||||
// returned from the client game, so reload the server list.
|
|
||||||
if(mainMenu !is null)
|
|
||||||
mainMenu.LoadServerList();
|
|
||||||
|
|
||||||
if(manager !is null)
|
|
||||||
manager.KeyPanic();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseEvent(float x, float y) {
|
|
||||||
manager.MouseEvent(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WheelEvent(float x, float y) {
|
|
||||||
manager.WheelEvent(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyEvent(string key, bool down) {
|
|
||||||
manager.KeyEvent(key, down);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextInputEvent(string text) {
|
|
||||||
manager.TextInputEvent(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextEditingEvent(string text, int start, int len) {
|
|
||||||
manager.TextEditingEvent(text, start, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AcceptsTextInput() {
|
|
||||||
return manager.AcceptsTextInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
AABB2 GetTextInputRect() {
|
|
||||||
return manager.TextInputRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SceneDefinition SetupCamera(SceneDefinition sceneDef,
|
|
||||||
Vector3 eye, Vector3 at, Vector3 up, float fov) {
|
|
||||||
Vector3 dir = (at - eye).Normalized;
|
|
||||||
Vector3 side = Cross(dir, up).Normalized;
|
|
||||||
up = -Cross(dir, side);
|
|
||||||
sceneDef.viewOrigin = eye;
|
|
||||||
sceneDef.viewAxisX = side;
|
|
||||||
sceneDef.viewAxisY = up;
|
|
||||||
sceneDef.viewAxisZ = dir;
|
|
||||||
sceneDef.fovY = fov * 3.141592654f / 180.f;
|
|
||||||
sceneDef.fovX = atan(tan(sceneDef.fovY * 0.5f) * renderer.ScreenWidth / renderer.ScreenHeight) * 2.f;
|
|
||||||
return sceneDef;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunFrame(float dt) {
|
|
||||||
if(time < 0.f) {
|
|
||||||
time = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
SceneDefinition sceneDef;
|
|
||||||
float cameraX = time;
|
|
||||||
cameraX -= floor(cameraX / 512.f) * 512.f;
|
|
||||||
cameraX = 512.f - cameraX;
|
|
||||||
sceneDef = SetupCamera(sceneDef,
|
|
||||||
Vector3(cameraX, 256.f, 12.f), Vector3(cameraX + .1f, 257.f, 12.5f), Vector3(0.f, 0.f, -1.f),
|
|
||||||
30.f);
|
|
||||||
sceneDef.zNear = 0.1f;
|
|
||||||
sceneDef.zFar = 222.f;
|
|
||||||
sceneDef.time = int(time * 1000.f);
|
|
||||||
sceneDef.viewportWidth = int(renderer.ScreenWidth);
|
|
||||||
sceneDef.viewportHeight = int(renderer.ScreenHeight);
|
|
||||||
sceneDef.denyCameraBlur = true;
|
|
||||||
sceneDef.depthOfFieldFocalLength = 100.f;
|
|
||||||
sceneDef.skipWorld = false;
|
|
||||||
|
|
||||||
// fade the map
|
|
||||||
float fade = Clamp((time - 1.f) / 2.2f, 0.f, 1.f);
|
|
||||||
sceneDef.globalBlur = Clamp((1.f - (time - 1.f) / 2.5f), 0.f, 1.f);
|
|
||||||
if(!mainMenu.IsEnabled) {
|
|
||||||
sceneDef.globalBlur = Max(sceneDef.globalBlur, 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer.StartScene(sceneDef);
|
|
||||||
renderer.EndScene();
|
|
||||||
|
|
||||||
// fade the map (draw)
|
|
||||||
if(fade < 1.f) {
|
|
||||||
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, 1.f - fade);
|
|
||||||
renderer.DrawImage(renderer.RegisterImage("Gfx/White.tga"),
|
|
||||||
AABB2(0.f, 0.f, renderer.ScreenWidth, renderer.ScreenHeight));
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw title logo
|
|
||||||
Image@ img = renderer.RegisterImage("Gfx/Title/Logo.png");
|
|
||||||
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 1.f);
|
|
||||||
renderer.DrawImage(img, Vector2((renderer.ScreenWidth - img.Width) * 0.5f, 64.f));
|
|
||||||
|
|
||||||
manager.RunFrame(dt);
|
|
||||||
manager.Render();
|
|
||||||
|
|
||||||
renderer.FrameDone();
|
|
||||||
renderer.Flip();
|
|
||||||
time += Min(dt, 0.05f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Closing() {
|
|
||||||
shouldExit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WantsToBeClosed() {
|
|
||||||
return shouldExit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ServerListItem: spades::ui::ButtonBase {
|
|
||||||
MainScreenServerItem@ item;
|
|
||||||
FlagIconRenderer@ flagIconRenderer;
|
|
||||||
ServerListItem(spades::ui::UIManager@ manager, MainScreenServerItem@ item){
|
|
||||||
super(manager);
|
|
||||||
@this.item = item;
|
|
||||||
@flagIconRenderer = FlagIconRenderer(manager.Renderer);
|
|
||||||
}
|
|
||||||
void Render() {
|
|
||||||
Renderer@ renderer = Manager.Renderer;
|
|
||||||
Vector2 pos = ScreenPosition;
|
|
||||||
Vector2 size = Size;
|
|
||||||
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
|
||||||
|
|
||||||
Vector4 bgcolor = Vector4(1.f, 1.f, 1.f, 0.0f);
|
|
||||||
Vector4 fgcolor = Vector4(1.f, 1.f, 1.f, 1.f);
|
|
||||||
if(item.Favorite) {
|
|
||||||
bgcolor = Vector4(0.3f, 0.3f, 1.f, 0.1f);
|
|
||||||
fgcolor = Vector4(220.f/255.f,220.f/255.f,0,1);
|
|
||||||
}
|
|
||||||
if(Pressed && Hover) {
|
|
||||||
bgcolor.w += 0.3;
|
|
||||||
} else if(Hover) {
|
|
||||||
bgcolor.w += 0.15;
|
|
||||||
}
|
|
||||||
renderer.ColorNP = bgcolor;
|
|
||||||
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
|
||||||
|
|
||||||
Font.Draw(item.Name, ScreenPosition + Vector2(4.f, 2.f), 1.f, fgcolor);
|
|
||||||
string playersStr = ToString(item.NumPlayers) + "/" + ToString(item.MaxPlayers);
|
|
||||||
Vector4 col(1,1,1,1);
|
|
||||||
if(item.NumPlayers >= item.MaxPlayers) col = Vector4(1,0.7f,0.7f,1);
|
|
||||||
else if(item.NumPlayers >= item.MaxPlayers * 3 / 4) col = Vector4(1,1,0.7f,1);
|
|
||||||
else if(item.NumPlayers == 0) col = Vector4(0.7f,0.7f,1,1);
|
|
||||||
Font.Draw(playersStr, ScreenPosition + Vector2(340.f-Font.Measure(playersStr).x * 0.5f, 2.f), 1.f, col);
|
|
||||||
Font.Draw(item.MapName, ScreenPosition + Vector2(400.f, 2.f), 1.f, Vector4(1,1,1,1));
|
|
||||||
Font.Draw(item.GameMode, ScreenPosition + Vector2(550.f, 2.f), 1.f, Vector4(1,1,1,1));
|
|
||||||
Font.Draw(item.Protocol, ScreenPosition + Vector2(630.f, 2.f), 1.f, Vector4(1,1,1,1));
|
|
||||||
if(not flagIconRenderer.DrawIcon(item.Country, ScreenPosition + Vector2(700.f, size.y * 0.5f))) {
|
|
||||||
Font.Draw(item.Country, ScreenPosition + Vector2(680.f, 2.f), 1.f, Vector4(1,1,1,1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
funcdef void ServerListItemEventHandler(ServerListModel@ sender, MainScreenServerItem@ item);
|
|
||||||
|
|
||||||
class ServerListModel: spades::ui::ListViewModel {
|
|
||||||
spades::ui::UIManager@ manager;
|
|
||||||
MainScreenServerItem@[]@ list;
|
|
||||||
|
|
||||||
ServerListItemEventHandler@ ItemActivated;
|
|
||||||
ServerListItemEventHandler@ ItemDoubleClicked;
|
|
||||||
ServerListItemEventHandler@ ItemRightClicked;
|
|
||||||
|
|
||||||
ServerListModel(spades::ui::UIManager@ manager, MainScreenServerItem@[]@ list) {
|
|
||||||
@this.manager = manager;
|
|
||||||
@this.list = list;
|
|
||||||
}
|
|
||||||
int NumRows {
|
|
||||||
get { return int(list.length); }
|
|
||||||
}
|
|
||||||
private void OnItemClicked(spades::ui::UIElement@ sender){
|
|
||||||
ServerListItem@ item = cast<ServerListItem>(sender);
|
|
||||||
if(ItemActivated !is null) {
|
|
||||||
ItemActivated(this, item.item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void OnItemDoubleClicked(spades::ui::UIElement@ sender){
|
|
||||||
ServerListItem@ item = cast<ServerListItem>(sender);
|
|
||||||
if(ItemDoubleClicked !is null) {
|
|
||||||
ItemDoubleClicked(this, item.item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void OnItemRightClicked(spades::ui::UIElement@ sender){
|
|
||||||
ServerListItem@ item = cast<ServerListItem>(sender);
|
|
||||||
if(ItemRightClicked !is null) {
|
|
||||||
ItemRightClicked(this, item.item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spades::ui::UIElement@ CreateElement(int row) {
|
|
||||||
ServerListItem i(manager, list[row]);
|
|
||||||
@i.Activated = spades::ui::EventHandler(this.OnItemClicked);
|
|
||||||
@i.DoubleClicked = spades::ui::EventHandler(this.OnItemDoubleClicked);
|
|
||||||
@i.RightClicked = spades::ui::EventHandler(this.OnItemRightClicked);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
void RecycleElement(spades::ui::UIElement@ elem) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ServerListHeader: spades::ui::ButtonBase {
|
|
||||||
string Text;
|
|
||||||
ServerListHeader(spades::ui::UIManager@ manager){
|
|
||||||
super(manager);
|
|
||||||
}
|
|
||||||
void OnActivated() {
|
|
||||||
ButtonBase::OnActivated();
|
|
||||||
}
|
|
||||||
void Render() {
|
|
||||||
Renderer@ renderer = Manager.Renderer;
|
|
||||||
Vector2 pos = ScreenPosition;
|
|
||||||
Vector2 size = Size;
|
|
||||||
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
|
||||||
if(Pressed && Hover) {
|
|
||||||
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.3f);
|
|
||||||
} else if(Hover) {
|
|
||||||
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.15f);
|
|
||||||
} else {
|
|
||||||
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.0f);
|
|
||||||
}
|
|
||||||
renderer.DrawImage(img, AABB2(pos.x - 2.f, pos.y, size.x, size.y));
|
|
||||||
|
|
||||||
Font.Draw(Text, ScreenPosition + Vector2(0.f, 2.f), 1.f, Vector4(1,1,1,1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class RefreshButton: spades::ui::SimpleButton {
|
|
||||||
RefreshButton(spades::ui::UIManager@ manager){
|
|
||||||
super(manager);
|
|
||||||
}
|
|
||||||
void Render() {
|
|
||||||
SimpleButton::Render();
|
|
||||||
|
|
||||||
Renderer@ renderer = Manager.Renderer;
|
|
||||||
Vector2 pos = ScreenPosition;
|
|
||||||
Vector2 size = Size;
|
|
||||||
Image@ img = renderer.RegisterImage("Gfx/UI/Refresh.png");
|
|
||||||
renderer.DrawImage(img, pos + (size - Vector2(16.f, 16.f)) * 0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProtocolButton: spades::ui::SimpleButton {
|
|
||||||
ProtocolButton(spades::ui::UIManager@ manager){
|
|
||||||
super(manager);
|
|
||||||
Toggle = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 ToLower(uint8 c) {
|
|
||||||
if(c >= uint8(0x41) and c <= uint8(0x5a)) {
|
|
||||||
return uint8(c - 0x41 + 0x61);
|
|
||||||
} else {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool StringContainsCaseInsensitive(string text, string pattern) {
|
|
||||||
for(int i = text.length - 1; i >= 0; i--)
|
|
||||||
text[i] = ToLower(text[i]);
|
|
||||||
for(int i = pattern.length - 1; i >= 0; i--)
|
|
||||||
pattern[i] = ToLower(pattern[i]);
|
|
||||||
return text.findFirst(pattern) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MainScreenMainMenu: spades::ui::UIElement {
|
|
||||||
|
|
||||||
MainScreenUI@ ui;
|
|
||||||
MainScreenHelper@ helper;
|
|
||||||
spades::ui::Field@ addressField;
|
|
||||||
|
|
||||||
spades::ui::Button@ protocol3Button;
|
|
||||||
spades::ui::Button@ protocol4Button;
|
|
||||||
|
|
||||||
spades::ui::Button@ filterProtocol3Button;
|
|
||||||
spades::ui::Button@ filterProtocol4Button;
|
|
||||||
spades::ui::Button@ filterEmptyButton;
|
|
||||||
spades::ui::Button@ filterFullButton;
|
|
||||||
spades::ui::Field@ filterField;
|
|
||||||
|
|
||||||
spades::ui::ListView@ serverList;
|
|
||||||
MainScreenServerListLoadingView@ loadingView;
|
|
||||||
MainScreenServerListErrorView@ errorView;
|
|
||||||
bool loading = false, loaded = false;
|
|
||||||
|
|
||||||
private ConfigItem cg_protocolVersion("cg_protocolVersion", "3");
|
|
||||||
private ConfigItem cg_lastQuickConnectHost("cg_lastQuickConnectHost", "127.0.0.1");
|
|
||||||
private ConfigItem cg_serverlistSort("cg_serverlistSort", "16385");
|
|
||||||
|
|
||||||
MainScreenMainMenu(MainScreenUI@ ui) {
|
|
||||||
super(ui.manager);
|
|
||||||
@this.ui = ui;
|
|
||||||
@this.helper = ui.helper;
|
|
||||||
|
|
||||||
float contentsWidth = 750.f;
|
|
||||||
float contentsLeft = (Manager.Renderer.ScreenWidth - contentsWidth) * 0.5f;
|
|
||||||
float footerPos = Manager.Renderer.ScreenHeight - 50.f;
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("MainScreen", "Connect");
|
|
||||||
button.Bounds = AABB2(contentsLeft + contentsWidth - 150.f, 200.f, 150.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnConnectPressed);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@addressField = spades::ui::Field(Manager);
|
|
||||||
addressField.Bounds = AABB2(contentsLeft, 200, contentsWidth - 240.f, 30.f);
|
|
||||||
addressField.Placeholder = _Tr("MainScreen", "Quick Connect");
|
|
||||||
addressField.Text = cg_lastQuickConnectHost.StringValue;
|
|
||||||
@addressField.Changed = spades::ui::EventHandler(this.OnAddressChanged);
|
|
||||||
AddChild(addressField);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@protocol3Button = ProtocolButton(Manager);
|
|
||||||
protocol3Button.Bounds = AABB2(contentsLeft + contentsWidth - 240.f + 6.f, 200,
|
|
||||||
40.f, 30.f);
|
|
||||||
protocol3Button.Caption = _Tr("MainScreen", "0.75");
|
|
||||||
@protocol3Button.Activated = spades::ui::EventHandler(this.OnProtocol3Pressed);
|
|
||||||
protocol3Button.Toggle = true;
|
|
||||||
protocol3Button.Toggled = cg_protocolVersion.IntValue == 3;
|
|
||||||
AddChild(protocol3Button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@protocol4Button = ProtocolButton(Manager);
|
|
||||||
protocol4Button.Bounds = AABB2(contentsLeft + contentsWidth - 200.f + 6.f, 200,
|
|
||||||
40.f, 30.f);
|
|
||||||
protocol4Button.Caption = _Tr("MainScreen", "0.76");
|
|
||||||
@protocol4Button.Activated = spades::ui::EventHandler(this.OnProtocol4Pressed);
|
|
||||||
protocol4Button.Toggle = true;
|
|
||||||
protocol4Button.Toggled = cg_protocolVersion.IntValue == 4;
|
|
||||||
AddChild(protocol4Button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("MainScreen", "Quit");
|
|
||||||
button.Bounds = AABB2(contentsLeft + contentsWidth - 100.f, footerPos, 100.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnQuitPressed);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("MainScreen", "Credits");
|
|
||||||
button.Bounds = AABB2(contentsLeft + contentsWidth - 202.f, footerPos, 100.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnCreditsPressed);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Button button(Manager);
|
|
||||||
button.Caption = _Tr("MainScreen", "Setup");
|
|
||||||
button.Bounds = AABB2(contentsLeft + contentsWidth - 304.f, footerPos, 100.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnSetupPressed);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
RefreshButton button(Manager);
|
|
||||||
button.Bounds = AABB2(contentsLeft + contentsWidth - 364.f, footerPos, 30.f, 30.f);
|
|
||||||
@button.Activated = spades::ui::EventHandler(this.OnRefreshServerListPressed);
|
|
||||||
AddChild(button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
spades::ui::Label label(Manager);
|
|
||||||
label.Text = _Tr("MainScreen", "Filter");
|
|
||||||
label.Bounds = AABB2(contentsLeft, footerPos, 50.f, 30.f);
|
|
||||||
label.Alignment = Vector2(0.f, 0.5f);
|
|
||||||
AddChild(label);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@filterProtocol3Button = ProtocolButton(Manager);
|
|
||||||
filterProtocol3Button.Bounds = AABB2(contentsLeft + 50.f, footerPos,
|
|
||||||
40.f, 30.f);
|
|
||||||
filterProtocol3Button.Caption = _Tr("MainScreen", "0.75");
|
|
||||||
@filterProtocol3Button.Activated = spades::ui::EventHandler(this.OnFilterProtocol3Pressed);
|
|
||||||
filterProtocol3Button.Toggle = true;
|
|
||||||
AddChild(filterProtocol3Button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@filterProtocol4Button = ProtocolButton(Manager);
|
|
||||||
filterProtocol4Button.Bounds = AABB2(contentsLeft + 90.f, footerPos,
|
|
||||||
40.f, 30.f);
|
|
||||||
filterProtocol4Button.Caption = _Tr("MainScreen", "0.76");
|
|
||||||
@filterProtocol4Button.Activated = spades::ui::EventHandler(this.OnFilterProtocol4Pressed);
|
|
||||||
filterProtocol4Button.Toggle = true;
|
|
||||||
AddChild(filterProtocol4Button);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@filterEmptyButton = ProtocolButton(Manager);
|
|
||||||
filterEmptyButton.Bounds = AABB2(contentsLeft + 135.f, footerPos,
|
|
||||||
50.f, 30.f);
|
|
||||||
filterEmptyButton.Caption = _Tr("MainScreen", "Empty");
|
|
||||||
@filterEmptyButton.Activated = spades::ui::EventHandler(this.OnFilterEmptyPressed);
|
|
||||||
filterEmptyButton.Toggle = true;
|
|
||||||
AddChild(filterEmptyButton);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@filterFullButton = ProtocolButton(Manager);
|
|
||||||
filterFullButton.Bounds = AABB2(contentsLeft + 185.f, footerPos,
|
|
||||||
70.f, 30.f);
|
|
||||||
filterFullButton.Caption = _Tr("MainScreen", "Not Full");
|
|
||||||
@filterFullButton.Activated = spades::ui::EventHandler(this.OnFilterFullPressed);
|
|
||||||
filterFullButton.Toggle = true;
|
|
||||||
AddChild(filterFullButton);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@filterField = spades::ui::Field(Manager);
|
|
||||||
filterField.Bounds = AABB2(contentsLeft + 260.f, footerPos, 120.f, 30.f);
|
|
||||||
filterField.Placeholder = _Tr("MainScreen", "Filter");
|
|
||||||
@filterField.Changed = spades::ui::EventHandler(this.OnFilterTextChanged);
|
|
||||||
AddChild(filterField);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@serverList = spades::ui::ListView(Manager);
|
|
||||||
serverList.Bounds = AABB2(contentsLeft, 270.f, contentsWidth, footerPos - 280.f);
|
|
||||||
AddChild(serverList);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ServerListHeader header(Manager);
|
|
||||||
header.Bounds = AABB2(contentsLeft + 2.f, 240.f, 300.f - 2.f, 30.f);
|
|
||||||
header.Text = _Tr("MainScreen", "Server Name");
|
|
||||||
@header.Activated = spades::ui::EventHandler(this.SortServerListByName);
|
|
||||||
AddChild(header);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ServerListHeader header(Manager);
|
|
||||||
header.Bounds = AABB2(contentsLeft + 300.f, 240.f, 100.f, 30.f);
|
|
||||||
header.Text = _Tr("MainScreen", "Players");
|
|
||||||
@header.Activated = spades::ui::EventHandler(this.SortServerListByNumPlayers);
|
|
||||||
AddChild(header);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ServerListHeader header(Manager);
|
|
||||||
header.Bounds = AABB2(contentsLeft + 400.f, 240.f, 150.f, 30.f);
|
|
||||||
header.Text = _Tr("MainScreen", "Map Name");
|
|
||||||
@header.Activated = spades::ui::EventHandler(this.SortServerListByMapName);
|
|
||||||
AddChild(header);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ServerListHeader header(Manager);
|
|
||||||
header.Bounds = AABB2(contentsLeft + 550.f, 240.f, 80.f, 30.f);
|
|
||||||
header.Text = _Tr("MainScreen", "Game Mode");
|
|
||||||
@header.Activated = spades::ui::EventHandler(this.SortServerListByGameMode);
|
|
||||||
AddChild(header);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ServerListHeader header(Manager);
|
|
||||||
header.Bounds = AABB2(contentsLeft + 630.f, 240.f, 50.f, 30.f);
|
|
||||||
header.Text = _Tr("MainScreen", "Ver.");
|
|
||||||
@header.Activated = spades::ui::EventHandler(this.SortServerListByProtocol);
|
|
||||||
AddChild(header);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ServerListHeader header(Manager);
|
|
||||||
header.Bounds = AABB2(contentsLeft + 680.f, 240.f, 50.f, 30.f);
|
|
||||||
header.Text = _Tr("MainScreen", "Loc.");
|
|
||||||
@header.Activated = spades::ui::EventHandler(this.SortServerListByCountry);
|
|
||||||
AddChild(header);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@loadingView = MainScreenServerListLoadingView(Manager);
|
|
||||||
loadingView.Bounds = AABB2(contentsLeft, 240.f, contentsWidth, 100.f);
|
|
||||||
loadingView.Visible = false;
|
|
||||||
AddChild(loadingView);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
@errorView = MainScreenServerListErrorView(Manager);
|
|
||||||
errorView.Bounds = AABB2(contentsLeft, 240.f, contentsWidth, 100.f);
|
|
||||||
errorView.Visible = false;
|
|
||||||
AddChild(errorView);
|
|
||||||
}
|
|
||||||
LoadServerList();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadServerList() {
|
|
||||||
if(loading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loaded = false;
|
|
||||||
loading = true;
|
|
||||||
@serverList.Model = spades::ui::ListViewModel(); // empty
|
|
||||||
errorView.Visible = false;
|
|
||||||
loadingView.Visible = true;
|
|
||||||
helper.StartQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerListItemActivated(ServerListModel@ sender, MainScreenServerItem@ item) {
|
|
||||||
addressField.Text = item.Address;
|
|
||||||
cg_lastQuickConnectHost = addressField.Text;
|
|
||||||
if(item.Protocol == "0.75") {
|
|
||||||
SetProtocolVersion(3);
|
|
||||||
}else if(item.Protocol == "0.76") {
|
|
||||||
SetProtocolVersion(4);
|
|
||||||
}
|
|
||||||
addressField.SelectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerListItemDoubleClicked(ServerListModel@ sender, MainScreenServerItem@ item) {
|
|
||||||
ServerListItemActivated(sender, item);
|
|
||||||
|
|
||||||
// Double-click to connect
|
|
||||||
Connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerListItemRightClicked(ServerListModel@ sender, MainScreenServerItem@ item) {
|
|
||||||
helper.SetServerFavorite(item.Address, !item.Favorite);
|
|
||||||
UpdateServerList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SortServerListByPing(spades::ui::UIElement@ sender) {
|
|
||||||
SortServerList(0);
|
|
||||||
}
|
|
||||||
private void SortServerListByNumPlayers(spades::ui::UIElement@ sender) {
|
|
||||||
SortServerList(1);
|
|
||||||
}
|
|
||||||
private void SortServerListByName(spades::ui::UIElement@ sender) {
|
|
||||||
SortServerList(2);
|
|
||||||
}
|
|
||||||
private void SortServerListByMapName(spades::ui::UIElement@ sender) {
|
|
||||||
SortServerList(3);
|
|
||||||
}
|
|
||||||
private void SortServerListByGameMode(spades::ui::UIElement@ sender) {
|
|
||||||
SortServerList(4);
|
|
||||||
}
|
|
||||||
private void SortServerListByProtocol(spades::ui::UIElement@ sender) {
|
|
||||||
SortServerList(5);
|
|
||||||
}
|
|
||||||
private void SortServerListByCountry(spades::ui::UIElement@ sender) {
|
|
||||||
SortServerList(6);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SortServerList(int keyId) {
|
|
||||||
int sort = cg_serverlistSort.IntValue;
|
|
||||||
if(int(sort & 0xfff) == keyId) {
|
|
||||||
sort ^= int(0x4000);
|
|
||||||
} else {
|
|
||||||
sort = keyId;
|
|
||||||
}
|
|
||||||
cg_serverlistSort = sort;
|
|
||||||
UpdateServerList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateServerList() {
|
|
||||||
string key = "";
|
|
||||||
switch(cg_serverlistSort.IntValue & 0xfff) {
|
|
||||||
case 0: key = "Ping"; break;
|
|
||||||
case 1: key = "NumPlayers"; break;
|
|
||||||
case 2: key = "Name"; break;
|
|
||||||
case 3: key = "MapName"; break;
|
|
||||||
case 4: key = "GameMode"; break;
|
|
||||||
case 5: key = "Protocol"; break;
|
|
||||||
case 6: key = "Country"; break;
|
|
||||||
}
|
|
||||||
MainScreenServerItem@[]@ list = helper.GetServerList(key,
|
|
||||||
(cg_serverlistSort.IntValue & 0x4000) != 0);
|
|
||||||
if((list is null) or (loading)){
|
|
||||||
@serverList.Model = spades::ui::ListViewModel(); // empty
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// filter the server list
|
|
||||||
bool filterProtocol3 = filterProtocol3Button.Toggled;
|
|
||||||
bool filterProtocol4 = filterProtocol4Button.Toggled;
|
|
||||||
bool filterEmpty = filterEmptyButton.Toggled;
|
|
||||||
bool filterFull = filterFullButton.Toggled;
|
|
||||||
string filterText = filterField.Text;
|
|
||||||
MainScreenServerItem@[]@ list2 = array<spades::MainScreenServerItem@>();
|
|
||||||
for(int i = 0, count = list.length; i < count; i++) {
|
|
||||||
MainScreenServerItem@ item = list[i];
|
|
||||||
if(filterProtocol3 and (item.Protocol != "0.75")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(filterProtocol4 and (item.Protocol != "0.76")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(filterEmpty and (item.NumPlayers > 0)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(filterFull and (item.NumPlayers >= item.MaxPlayers)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(filterText.length > 0) {
|
|
||||||
if(not (StringContainsCaseInsensitive(item.Name, filterText) or
|
|
||||||
StringContainsCaseInsensitive(item.MapName, filterText) or
|
|
||||||
StringContainsCaseInsensitive(item.GameMode, filterText))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list2.insertLast(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerListModel model(Manager, list2);
|
|
||||||
@serverList.Model = model;
|
|
||||||
@model.ItemActivated = ServerListItemEventHandler(this.ServerListItemActivated);
|
|
||||||
@model.ItemDoubleClicked = ServerListItemEventHandler(this.ServerListItemDoubleClicked);
|
|
||||||
@model.ItemRightClicked = ServerListItemEventHandler(this.ServerListItemRightClicked);
|
|
||||||
serverList.ScrollToTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckServerList() {
|
|
||||||
if(helper.PollServerListState()) {
|
|
||||||
MainScreenServerItem@[]@ list = helper.GetServerList("", false);
|
|
||||||
if(list is null or list.length == 0) {
|
|
||||||
// failed.
|
|
||||||
// FIXME: show error message?
|
|
||||||
loaded = false; loading = false;
|
|
||||||
errorView.Visible = true;
|
|
||||||
loadingView.Visible = false;
|
|
||||||
@serverList.Model = spades::ui::ListViewModel(); // empty
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading = false;
|
|
||||||
loaded = true;
|
|
||||||
errorView.Visible = false;
|
|
||||||
loadingView.Visible = false;
|
|
||||||
UpdateServerList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAddressChanged(spades::ui::UIElement@ sender) {
|
|
||||||
cg_lastQuickConnectHost = addressField.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetProtocolVersion(int ver) {
|
|
||||||
protocol3Button.Toggled = (ver == 3);
|
|
||||||
protocol4Button.Toggled = (ver == 4);
|
|
||||||
cg_protocolVersion = ver;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnProtocol3Pressed(spades::ui::UIElement@ sender) {
|
|
||||||
SetProtocolVersion(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnProtocol4Pressed(spades::ui::UIElement@ sender) {
|
|
||||||
SetProtocolVersion(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnFilterProtocol3Pressed(spades::ui::UIElement@ sender) {
|
|
||||||
filterProtocol4Button.Toggled = false;
|
|
||||||
UpdateServerList();
|
|
||||||
}
|
|
||||||
private void OnFilterProtocol4Pressed(spades::ui::UIElement@ sender) {
|
|
||||||
filterProtocol3Button.Toggled = false;
|
|
||||||
UpdateServerList();
|
|
||||||
}
|
|
||||||
private void OnFilterFullPressed(spades::ui::UIElement@ sender) {
|
|
||||||
filterEmptyButton.Toggled = false;
|
|
||||||
UpdateServerList();
|
|
||||||
}
|
|
||||||
private void OnFilterEmptyPressed(spades::ui::UIElement@ sender) {
|
|
||||||
filterFullButton.Toggled = false;
|
|
||||||
UpdateServerList();
|
|
||||||
}
|
|
||||||
private void OnFilterTextChanged(spades::ui::UIElement@ sender) {
|
|
||||||
UpdateServerList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRefreshServerListPressed(spades::ui::UIElement@ sender) {
|
|
||||||
LoadServerList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnQuitPressed(spades::ui::UIElement@ sender) {
|
|
||||||
ui.shouldExit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCreditsPressed(spades::ui::UIElement@ sender) {
|
|
||||||
AlertScreen al(this, ui.helper.Credits, Min(500.f, Manager.Renderer.ScreenHeight - 100.f));
|
|
||||||
al.Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSetupPressed(spades::ui::UIElement@ sender) {
|
|
||||||
PreferenceView al(this, PreferenceViewOptions(), ui.fontManager);
|
|
||||||
al.Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Connect() {
|
|
||||||
string msg = helper.ConnectServer(addressField.Text, cg_protocolVersion.IntValue);
|
|
||||||
if(msg.length > 0) {
|
|
||||||
// failde to initialize client.
|
|
||||||
AlertScreen al(this, msg);
|
|
||||||
al.Run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnConnectPressed(spades::ui::UIElement@ sender) {
|
|
||||||
Connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HotKey(string key) {
|
|
||||||
if(IsEnabled and key == "Enter") {
|
|
||||||
Connect();
|
|
||||||
} else if(IsEnabled and key == "Escape") {
|
|
||||||
ui.shouldExit = true;
|
|
||||||
} else {
|
|
||||||
UIElement::HotKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Render() {
|
|
||||||
CheckServerList();
|
|
||||||
UIElement::Render();
|
|
||||||
|
|
||||||
// check for client error message.
|
|
||||||
if(IsEnabled) {
|
|
||||||
string msg = helper.GetPendingErrorMessage();
|
|
||||||
if(msg.length > 0) {
|
|
||||||
// try to maek the "disconnected" message more friendly.
|
|
||||||
if(msg.findFirst("Disconnected:") >= 0) {
|
|
||||||
int ind1 = msg.findFirst("Disconnected:");
|
|
||||||
int ind2 = msg.findFirst("\n", ind1);
|
|
||||||
if(ind2 < 0) ind2 = msg.length;
|
|
||||||
ind1 += "Disconnected:".length;
|
|
||||||
msg = msg.substr(ind1, ind2 - ind1);
|
|
||||||
msg = _Tr("MainScreen", "You were disconnected from the server because of the following reason:\n\n{0}", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// failed to connect.
|
|
||||||
AlertScreen al(this, msg);
|
|
||||||
al.Run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MainScreenServerListLoadingView: spades::ui::UIElement {
|
|
||||||
MainScreenServerListLoadingView(spades::ui::UIManager@ manager) {
|
|
||||||
super(manager);
|
|
||||||
}
|
|
||||||
void Render() {
|
|
||||||
Renderer@ renderer = Manager.Renderer;
|
|
||||||
Vector2 pos = ScreenPosition;
|
|
||||||
Vector2 size = Size;
|
|
||||||
Font@ font = this.Font;
|
|
||||||
string text = _Tr("MainScreen", "Loading...");
|
|
||||||
Vector2 txtSize = font.Measure(text);
|
|
||||||
Vector2 txtPos;
|
|
||||||
txtPos = pos + (size - txtSize) * 0.5f;
|
|
||||||
|
|
||||||
font.Draw(text, txtPos, 1.f, Vector4(1,1,1,0.8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MainScreenServerListErrorView: spades::ui::UIElement {
|
|
||||||
MainScreenServerListErrorView(spades::ui::UIManager@ manager) {
|
|
||||||
super(manager);
|
|
||||||
}
|
|
||||||
void Render() {
|
|
||||||
Renderer@ renderer = Manager.Renderer;
|
|
||||||
Vector2 pos = ScreenPosition;
|
|
||||||
Vector2 size = Size;
|
|
||||||
Font@ font = this.Font;
|
|
||||||
string text = _Tr("MainScreen", "Failed to fetch the server list.");
|
|
||||||
Vector2 txtSize = font.Measure(text);
|
|
||||||
Vector2 txtPos;
|
|
||||||
txtPos = pos + (size - txtSize) * 0.5f;
|
|
||||||
|
|
||||||
font.Draw(text, txtPos, 1.f, Vector4(1,1,1,0.8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MainScreenUI@ CreateMainScreenUI(Renderer@ renderer, AudioDevice@ audioDevice,
|
|
||||||
FontManager@ fontManager, MainScreenHelper@ helper) {
|
|
||||||
return MainScreenUI(renderer, audioDevice, fontManager, helper);
|
|
||||||
}
|
|
||||||
}
|
|
519
Resources/Scripts/Gui/MainScreen/MainMenu.as
Normal file
519
Resources/Scripts/Gui/MainScreen/MainMenu.as
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CreateProfileScreen.as"
|
||||||
|
#include "ServerList.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class RefreshButton: spades::ui::SimpleButton {
|
||||||
|
RefreshButton(spades::ui::UIManager@ manager){
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
SimpleButton::Render();
|
||||||
|
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/UI/Refresh.png");
|
||||||
|
renderer.DrawImage(img, pos + (size - Vector2(16.f, 16.f)) * 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProtocolButton: spades::ui::SimpleButton {
|
||||||
|
ProtocolButton(spades::ui::UIManager@ manager){
|
||||||
|
super(manager);
|
||||||
|
Toggle = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 ToLower(uint8 c) {
|
||||||
|
if(c >= uint8(0x41) and c <= uint8(0x5a)) {
|
||||||
|
return uint8(c - 0x41 + 0x61);
|
||||||
|
} else {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool StringContainsCaseInsensitive(string text, string pattern) {
|
||||||
|
for(int i = text.length - 1; i >= 0; i--)
|
||||||
|
text[i] = ToLower(text[i]);
|
||||||
|
for(int i = pattern.length - 1; i >= 0; i--)
|
||||||
|
pattern[i] = ToLower(pattern[i]);
|
||||||
|
return text.findFirst(pattern) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainScreenMainMenu: spades::ui::UIElement {
|
||||||
|
|
||||||
|
MainScreenUI@ ui;
|
||||||
|
MainScreenHelper@ helper;
|
||||||
|
spades::ui::Field@ addressField;
|
||||||
|
|
||||||
|
spades::ui::Button@ protocol3Button;
|
||||||
|
spades::ui::Button@ protocol4Button;
|
||||||
|
|
||||||
|
spades::ui::Button@ filterProtocol3Button;
|
||||||
|
spades::ui::Button@ filterProtocol4Button;
|
||||||
|
spades::ui::Button@ filterEmptyButton;
|
||||||
|
spades::ui::Button@ filterFullButton;
|
||||||
|
spades::ui::Field@ filterField;
|
||||||
|
|
||||||
|
spades::ui::ListView@ serverList;
|
||||||
|
MainScreenServerListLoadingView@ loadingView;
|
||||||
|
MainScreenServerListErrorView@ errorView;
|
||||||
|
bool loading = false, loaded = false;
|
||||||
|
|
||||||
|
private ConfigItem cg_protocolVersion("cg_protocolVersion", "3");
|
||||||
|
private ConfigItem cg_lastQuickConnectHost("cg_lastQuickConnectHost", "127.0.0.1");
|
||||||
|
private ConfigItem cg_serverlistSort("cg_serverlistSort", "16385");
|
||||||
|
|
||||||
|
MainScreenMainMenu(MainScreenUI@ ui) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@this.helper = ui.helper;
|
||||||
|
|
||||||
|
float contentsWidth = 750.f;
|
||||||
|
float contentsLeft = (Manager.Renderer.ScreenWidth - contentsWidth) * 0.5f;
|
||||||
|
float footerPos = Manager.Renderer.ScreenHeight - 50.f;
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("MainScreen", "Connect");
|
||||||
|
button.Bounds = AABB2(contentsLeft + contentsWidth - 150.f, 200.f, 150.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnConnectPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@addressField = spades::ui::Field(Manager);
|
||||||
|
addressField.Bounds = AABB2(contentsLeft, 200, contentsWidth - 240.f, 30.f);
|
||||||
|
addressField.Placeholder = _Tr("MainScreen", "Quick Connect");
|
||||||
|
addressField.Text = cg_lastQuickConnectHost.StringValue;
|
||||||
|
@addressField.Changed = spades::ui::EventHandler(this.OnAddressChanged);
|
||||||
|
AddChild(addressField);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@protocol3Button = ProtocolButton(Manager);
|
||||||
|
protocol3Button.Bounds = AABB2(contentsLeft + contentsWidth - 240.f + 6.f, 200,
|
||||||
|
40.f, 30.f);
|
||||||
|
protocol3Button.Caption = _Tr("MainScreen", "0.75");
|
||||||
|
@protocol3Button.Activated = spades::ui::EventHandler(this.OnProtocol3Pressed);
|
||||||
|
protocol3Button.Toggle = true;
|
||||||
|
protocol3Button.Toggled = cg_protocolVersion.IntValue == 3;
|
||||||
|
AddChild(protocol3Button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@protocol4Button = ProtocolButton(Manager);
|
||||||
|
protocol4Button.Bounds = AABB2(contentsLeft + contentsWidth - 200.f + 6.f, 200,
|
||||||
|
40.f, 30.f);
|
||||||
|
protocol4Button.Caption = _Tr("MainScreen", "0.76");
|
||||||
|
@protocol4Button.Activated = spades::ui::EventHandler(this.OnProtocol4Pressed);
|
||||||
|
protocol4Button.Toggle = true;
|
||||||
|
protocol4Button.Toggled = cg_protocolVersion.IntValue == 4;
|
||||||
|
AddChild(protocol4Button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("MainScreen", "Quit");
|
||||||
|
button.Bounds = AABB2(contentsLeft + contentsWidth - 100.f, footerPos, 100.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnQuitPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("MainScreen", "Credits");
|
||||||
|
button.Bounds = AABB2(contentsLeft + contentsWidth - 202.f, footerPos, 100.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnCreditsPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("MainScreen", "Setup");
|
||||||
|
button.Bounds = AABB2(contentsLeft + contentsWidth - 304.f, footerPos, 100.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnSetupPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RefreshButton button(Manager);
|
||||||
|
button.Bounds = AABB2(contentsLeft + contentsWidth - 364.f, footerPos, 30.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnRefreshServerListPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Label label(Manager);
|
||||||
|
label.Text = _Tr("MainScreen", "Filter");
|
||||||
|
label.Bounds = AABB2(contentsLeft, footerPos, 50.f, 30.f);
|
||||||
|
label.Alignment = Vector2(0.f, 0.5f);
|
||||||
|
AddChild(label);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@filterProtocol3Button = ProtocolButton(Manager);
|
||||||
|
filterProtocol3Button.Bounds = AABB2(contentsLeft + 50.f, footerPos,
|
||||||
|
40.f, 30.f);
|
||||||
|
filterProtocol3Button.Caption = _Tr("MainScreen", "0.75");
|
||||||
|
@filterProtocol3Button.Activated = spades::ui::EventHandler(this.OnFilterProtocol3Pressed);
|
||||||
|
filterProtocol3Button.Toggle = true;
|
||||||
|
AddChild(filterProtocol3Button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@filterProtocol4Button = ProtocolButton(Manager);
|
||||||
|
filterProtocol4Button.Bounds = AABB2(contentsLeft + 90.f, footerPos,
|
||||||
|
40.f, 30.f);
|
||||||
|
filterProtocol4Button.Caption = _Tr("MainScreen", "0.76");
|
||||||
|
@filterProtocol4Button.Activated = spades::ui::EventHandler(this.OnFilterProtocol4Pressed);
|
||||||
|
filterProtocol4Button.Toggle = true;
|
||||||
|
AddChild(filterProtocol4Button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@filterEmptyButton = ProtocolButton(Manager);
|
||||||
|
filterEmptyButton.Bounds = AABB2(contentsLeft + 135.f, footerPos,
|
||||||
|
50.f, 30.f);
|
||||||
|
filterEmptyButton.Caption = _Tr("MainScreen", "Empty");
|
||||||
|
@filterEmptyButton.Activated = spades::ui::EventHandler(this.OnFilterEmptyPressed);
|
||||||
|
filterEmptyButton.Toggle = true;
|
||||||
|
AddChild(filterEmptyButton);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@filterFullButton = ProtocolButton(Manager);
|
||||||
|
filterFullButton.Bounds = AABB2(contentsLeft + 185.f, footerPos,
|
||||||
|
70.f, 30.f);
|
||||||
|
filterFullButton.Caption = _Tr("MainScreen", "Not Full");
|
||||||
|
@filterFullButton.Activated = spades::ui::EventHandler(this.OnFilterFullPressed);
|
||||||
|
filterFullButton.Toggle = true;
|
||||||
|
AddChild(filterFullButton);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@filterField = spades::ui::Field(Manager);
|
||||||
|
filterField.Bounds = AABB2(contentsLeft + 260.f, footerPos, 120.f, 30.f);
|
||||||
|
filterField.Placeholder = _Tr("MainScreen", "Filter");
|
||||||
|
@filterField.Changed = spades::ui::EventHandler(this.OnFilterTextChanged);
|
||||||
|
AddChild(filterField);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@serverList = spades::ui::ListView(Manager);
|
||||||
|
serverList.Bounds = AABB2(contentsLeft, 270.f, contentsWidth, footerPos - 280.f);
|
||||||
|
AddChild(serverList);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ServerListHeader header(Manager);
|
||||||
|
header.Bounds = AABB2(contentsLeft + 2.f, 240.f, 300.f - 2.f, 30.f);
|
||||||
|
header.Text = _Tr("MainScreen", "Server Name");
|
||||||
|
@header.Activated = spades::ui::EventHandler(this.SortServerListByName);
|
||||||
|
AddChild(header);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ServerListHeader header(Manager);
|
||||||
|
header.Bounds = AABB2(contentsLeft + 300.f, 240.f, 100.f, 30.f);
|
||||||
|
header.Text = _Tr("MainScreen", "Players");
|
||||||
|
@header.Activated = spades::ui::EventHandler(this.SortServerListByNumPlayers);
|
||||||
|
AddChild(header);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ServerListHeader header(Manager);
|
||||||
|
header.Bounds = AABB2(contentsLeft + 400.f, 240.f, 150.f, 30.f);
|
||||||
|
header.Text = _Tr("MainScreen", "Map Name");
|
||||||
|
@header.Activated = spades::ui::EventHandler(this.SortServerListByMapName);
|
||||||
|
AddChild(header);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ServerListHeader header(Manager);
|
||||||
|
header.Bounds = AABB2(contentsLeft + 550.f, 240.f, 80.f, 30.f);
|
||||||
|
header.Text = _Tr("MainScreen", "Game Mode");
|
||||||
|
@header.Activated = spades::ui::EventHandler(this.SortServerListByGameMode);
|
||||||
|
AddChild(header);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ServerListHeader header(Manager);
|
||||||
|
header.Bounds = AABB2(contentsLeft + 630.f, 240.f, 50.f, 30.f);
|
||||||
|
header.Text = _Tr("MainScreen", "Ver.");
|
||||||
|
@header.Activated = spades::ui::EventHandler(this.SortServerListByProtocol);
|
||||||
|
AddChild(header);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ServerListHeader header(Manager);
|
||||||
|
header.Bounds = AABB2(contentsLeft + 680.f, 240.f, 50.f, 30.f);
|
||||||
|
header.Text = _Tr("MainScreen", "Loc.");
|
||||||
|
@header.Activated = spades::ui::EventHandler(this.SortServerListByCountry);
|
||||||
|
AddChild(header);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@loadingView = MainScreenServerListLoadingView(Manager);
|
||||||
|
loadingView.Bounds = AABB2(contentsLeft, 240.f, contentsWidth, 100.f);
|
||||||
|
loadingView.Visible = false;
|
||||||
|
AddChild(loadingView);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
@errorView = MainScreenServerListErrorView(Manager);
|
||||||
|
errorView.Bounds = AABB2(contentsLeft, 240.f, contentsWidth, 100.f);
|
||||||
|
errorView.Visible = false;
|
||||||
|
AddChild(errorView);
|
||||||
|
}
|
||||||
|
LoadServerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadServerList() {
|
||||||
|
if(loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loaded = false;
|
||||||
|
loading = true;
|
||||||
|
@serverList.Model = spades::ui::ListViewModel(); // empty
|
||||||
|
errorView.Visible = false;
|
||||||
|
loadingView.Visible = true;
|
||||||
|
helper.StartQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerListItemActivated(ServerListModel@ sender, MainScreenServerItem@ item) {
|
||||||
|
addressField.Text = item.Address;
|
||||||
|
cg_lastQuickConnectHost = addressField.Text;
|
||||||
|
if(item.Protocol == "0.75") {
|
||||||
|
SetProtocolVersion(3);
|
||||||
|
}else if(item.Protocol == "0.76") {
|
||||||
|
SetProtocolVersion(4);
|
||||||
|
}
|
||||||
|
addressField.SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerListItemDoubleClicked(ServerListModel@ sender, MainScreenServerItem@ item) {
|
||||||
|
ServerListItemActivated(sender, item);
|
||||||
|
|
||||||
|
// Double-click to connect
|
||||||
|
Connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerListItemRightClicked(ServerListModel@ sender, MainScreenServerItem@ item) {
|
||||||
|
helper.SetServerFavorite(item.Address, !item.Favorite);
|
||||||
|
UpdateServerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SortServerListByPing(spades::ui::UIElement@ sender) {
|
||||||
|
SortServerList(0);
|
||||||
|
}
|
||||||
|
private void SortServerListByNumPlayers(spades::ui::UIElement@ sender) {
|
||||||
|
SortServerList(1);
|
||||||
|
}
|
||||||
|
private void SortServerListByName(spades::ui::UIElement@ sender) {
|
||||||
|
SortServerList(2);
|
||||||
|
}
|
||||||
|
private void SortServerListByMapName(spades::ui::UIElement@ sender) {
|
||||||
|
SortServerList(3);
|
||||||
|
}
|
||||||
|
private void SortServerListByGameMode(spades::ui::UIElement@ sender) {
|
||||||
|
SortServerList(4);
|
||||||
|
}
|
||||||
|
private void SortServerListByProtocol(spades::ui::UIElement@ sender) {
|
||||||
|
SortServerList(5);
|
||||||
|
}
|
||||||
|
private void SortServerListByCountry(spades::ui::UIElement@ sender) {
|
||||||
|
SortServerList(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SortServerList(int keyId) {
|
||||||
|
int sort = cg_serverlistSort.IntValue;
|
||||||
|
if(int(sort & 0xfff) == keyId) {
|
||||||
|
sort ^= int(0x4000);
|
||||||
|
} else {
|
||||||
|
sort = keyId;
|
||||||
|
}
|
||||||
|
cg_serverlistSort = sort;
|
||||||
|
UpdateServerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateServerList() {
|
||||||
|
string key = "";
|
||||||
|
switch(cg_serverlistSort.IntValue & 0xfff) {
|
||||||
|
case 0: key = "Ping"; break;
|
||||||
|
case 1: key = "NumPlayers"; break;
|
||||||
|
case 2: key = "Name"; break;
|
||||||
|
case 3: key = "MapName"; break;
|
||||||
|
case 4: key = "GameMode"; break;
|
||||||
|
case 5: key = "Protocol"; break;
|
||||||
|
case 6: key = "Country"; break;
|
||||||
|
}
|
||||||
|
MainScreenServerItem@[]@ list = helper.GetServerList(key,
|
||||||
|
(cg_serverlistSort.IntValue & 0x4000) != 0);
|
||||||
|
if((list is null) or (loading)){
|
||||||
|
@serverList.Model = spades::ui::ListViewModel(); // empty
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter the server list
|
||||||
|
bool filterProtocol3 = filterProtocol3Button.Toggled;
|
||||||
|
bool filterProtocol4 = filterProtocol4Button.Toggled;
|
||||||
|
bool filterEmpty = filterEmptyButton.Toggled;
|
||||||
|
bool filterFull = filterFullButton.Toggled;
|
||||||
|
string filterText = filterField.Text;
|
||||||
|
MainScreenServerItem@[]@ list2 = array<spades::MainScreenServerItem@>();
|
||||||
|
for(int i = 0, count = list.length; i < count; i++) {
|
||||||
|
MainScreenServerItem@ item = list[i];
|
||||||
|
if(filterProtocol3 and (item.Protocol != "0.75")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(filterProtocol4 and (item.Protocol != "0.76")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(filterEmpty and (item.NumPlayers > 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(filterFull and (item.NumPlayers >= item.MaxPlayers)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(filterText.length > 0) {
|
||||||
|
if(not (StringContainsCaseInsensitive(item.Name, filterText) or
|
||||||
|
StringContainsCaseInsensitive(item.MapName, filterText) or
|
||||||
|
StringContainsCaseInsensitive(item.GameMode, filterText))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list2.insertLast(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerListModel model(Manager, list2);
|
||||||
|
@serverList.Model = model;
|
||||||
|
@model.ItemActivated = ServerListItemEventHandler(this.ServerListItemActivated);
|
||||||
|
@model.ItemDoubleClicked = ServerListItemEventHandler(this.ServerListItemDoubleClicked);
|
||||||
|
@model.ItemRightClicked = ServerListItemEventHandler(this.ServerListItemRightClicked);
|
||||||
|
serverList.ScrollToTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckServerList() {
|
||||||
|
if(helper.PollServerListState()) {
|
||||||
|
MainScreenServerItem@[]@ list = helper.GetServerList("", false);
|
||||||
|
if(list is null or list.length == 0) {
|
||||||
|
// failed.
|
||||||
|
// FIXME: show error message?
|
||||||
|
loaded = false; loading = false;
|
||||||
|
errorView.Visible = true;
|
||||||
|
loadingView.Visible = false;
|
||||||
|
@serverList.Model = spades::ui::ListViewModel(); // empty
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loading = false;
|
||||||
|
loaded = true;
|
||||||
|
errorView.Visible = false;
|
||||||
|
loadingView.Visible = false;
|
||||||
|
UpdateServerList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAddressChanged(spades::ui::UIElement@ sender) {
|
||||||
|
cg_lastQuickConnectHost = addressField.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetProtocolVersion(int ver) {
|
||||||
|
protocol3Button.Toggled = (ver == 3);
|
||||||
|
protocol4Button.Toggled = (ver == 4);
|
||||||
|
cg_protocolVersion = ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnProtocol3Pressed(spades::ui::UIElement@ sender) {
|
||||||
|
SetProtocolVersion(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnProtocol4Pressed(spades::ui::UIElement@ sender) {
|
||||||
|
SetProtocolVersion(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFilterProtocol3Pressed(spades::ui::UIElement@ sender) {
|
||||||
|
filterProtocol4Button.Toggled = false;
|
||||||
|
UpdateServerList();
|
||||||
|
}
|
||||||
|
private void OnFilterProtocol4Pressed(spades::ui::UIElement@ sender) {
|
||||||
|
filterProtocol3Button.Toggled = false;
|
||||||
|
UpdateServerList();
|
||||||
|
}
|
||||||
|
private void OnFilterFullPressed(spades::ui::UIElement@ sender) {
|
||||||
|
filterEmptyButton.Toggled = false;
|
||||||
|
UpdateServerList();
|
||||||
|
}
|
||||||
|
private void OnFilterEmptyPressed(spades::ui::UIElement@ sender) {
|
||||||
|
filterFullButton.Toggled = false;
|
||||||
|
UpdateServerList();
|
||||||
|
}
|
||||||
|
private void OnFilterTextChanged(spades::ui::UIElement@ sender) {
|
||||||
|
UpdateServerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRefreshServerListPressed(spades::ui::UIElement@ sender) {
|
||||||
|
LoadServerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnQuitPressed(spades::ui::UIElement@ sender) {
|
||||||
|
ui.shouldExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCreditsPressed(spades::ui::UIElement@ sender) {
|
||||||
|
AlertScreen al(this, ui.helper.Credits, Min(500.f, Manager.Renderer.ScreenHeight - 100.f));
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSetupPressed(spades::ui::UIElement@ sender) {
|
||||||
|
PreferenceView al(this, PreferenceViewOptions(), ui.fontManager);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Connect() {
|
||||||
|
string msg = helper.ConnectServer(addressField.Text, cg_protocolVersion.IntValue);
|
||||||
|
if(msg.length > 0) {
|
||||||
|
// failde to initialize client.
|
||||||
|
AlertScreen al(this, msg);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnConnectPressed(spades::ui::UIElement@ sender) {
|
||||||
|
Connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotKey(string key) {
|
||||||
|
if(IsEnabled and key == "Enter") {
|
||||||
|
Connect();
|
||||||
|
} else if(IsEnabled and key == "Escape") {
|
||||||
|
ui.shouldExit = true;
|
||||||
|
} else {
|
||||||
|
UIElement::HotKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
CheckServerList();
|
||||||
|
UIElement::Render();
|
||||||
|
|
||||||
|
// check for client error message.
|
||||||
|
if(IsEnabled) {
|
||||||
|
string msg = helper.GetPendingErrorMessage();
|
||||||
|
if(msg.length > 0) {
|
||||||
|
// try to maek the "disconnected" message more friendly.
|
||||||
|
if(msg.findFirst("Disconnected:") >= 0) {
|
||||||
|
int ind1 = msg.findFirst("Disconnected:");
|
||||||
|
int ind2 = msg.findFirst("\n", ind1);
|
||||||
|
if(ind2 < 0) ind2 = msg.length;
|
||||||
|
ind1 += "Disconnected:".length;
|
||||||
|
msg = msg.substr(ind1, ind2 - ind1);
|
||||||
|
msg = _Tr("MainScreen", "You were disconnected from the server because of the following reason:\n\n{0}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// failed to connect.
|
||||||
|
AlertScreen al(this, msg);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
195
Resources/Scripts/Gui/MainScreen/MainScreenUI.as
Normal file
195
Resources/Scripts/Gui/MainScreen/MainScreenUI.as
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MainMenu.as"
|
||||||
|
#include "CreateProfileScreen.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class MainScreenUI {
|
||||||
|
private Renderer@ renderer;
|
||||||
|
private AudioDevice@ audioDevice;
|
||||||
|
FontManager@ fontManager;
|
||||||
|
MainScreenHelper@ helper;
|
||||||
|
|
||||||
|
spades::ui::UIManager@ manager;
|
||||||
|
|
||||||
|
MainScreenMainMenu@ mainMenu;
|
||||||
|
|
||||||
|
bool shouldExit = false;
|
||||||
|
|
||||||
|
private float time = -1.f;
|
||||||
|
|
||||||
|
private ConfigItem cg_playerName("cg_playerName");
|
||||||
|
private ConfigItem cg_playerNameIsSet("cg_playerNameIsSet", "0");
|
||||||
|
|
||||||
|
MainScreenUI(Renderer@ renderer, AudioDevice@ audioDevice, FontManager@ fontManager, MainScreenHelper@ helper) {
|
||||||
|
@this.renderer = renderer;
|
||||||
|
@this.audioDevice = audioDevice;
|
||||||
|
@this.fontManager = fontManager;
|
||||||
|
@this.helper = helper;
|
||||||
|
|
||||||
|
SetupRenderer();
|
||||||
|
|
||||||
|
@manager = spades::ui::UIManager(renderer, audioDevice);
|
||||||
|
@manager.RootElement.Font = fontManager.GuiFont;
|
||||||
|
|
||||||
|
@mainMenu = MainScreenMainMenu(this);
|
||||||
|
mainMenu.Bounds = manager.RootElement.Bounds;
|
||||||
|
manager.RootElement.AddChild(mainMenu);
|
||||||
|
|
||||||
|
// Let the new player choose their IGN
|
||||||
|
if (cg_playerName.StringValue != "" &&
|
||||||
|
cg_playerName.StringValue != "Deuce") {
|
||||||
|
cg_playerNameIsSet.IntValue = 1;
|
||||||
|
}
|
||||||
|
if (cg_playerNameIsSet.IntValue == 0) {
|
||||||
|
CreateProfileScreen al(mainMenu);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupRenderer() {
|
||||||
|
// load map
|
||||||
|
@renderer.GameMap = GameMap("Maps/Title.vxl");
|
||||||
|
renderer.FogColor = Vector3(0.1f, 0.10f, 0.1f);
|
||||||
|
renderer.FogDistance = 128.f;
|
||||||
|
time = -1.f;
|
||||||
|
|
||||||
|
// returned from the client game, so reload the server list.
|
||||||
|
if(mainMenu !is null)
|
||||||
|
mainMenu.LoadServerList();
|
||||||
|
|
||||||
|
if(manager !is null)
|
||||||
|
manager.KeyPanic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseEvent(float x, float y) {
|
||||||
|
manager.MouseEvent(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WheelEvent(float x, float y) {
|
||||||
|
manager.WheelEvent(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyEvent(string key, bool down) {
|
||||||
|
manager.KeyEvent(key, down);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputEvent(string text) {
|
||||||
|
manager.TextInputEvent(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextEditingEvent(string text, int start, int len) {
|
||||||
|
manager.TextEditingEvent(text, start, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AcceptsTextInput() {
|
||||||
|
return manager.AcceptsTextInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB2 GetTextInputRect() {
|
||||||
|
return manager.TextInputRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SceneDefinition SetupCamera(SceneDefinition sceneDef,
|
||||||
|
Vector3 eye, Vector3 at, Vector3 up, float fov) {
|
||||||
|
Vector3 dir = (at - eye).Normalized;
|
||||||
|
Vector3 side = Cross(dir, up).Normalized;
|
||||||
|
up = -Cross(dir, side);
|
||||||
|
sceneDef.viewOrigin = eye;
|
||||||
|
sceneDef.viewAxisX = side;
|
||||||
|
sceneDef.viewAxisY = up;
|
||||||
|
sceneDef.viewAxisZ = dir;
|
||||||
|
sceneDef.fovY = fov * 3.141592654f / 180.f;
|
||||||
|
sceneDef.fovX = atan(tan(sceneDef.fovY * 0.5f) * renderer.ScreenWidth / renderer.ScreenHeight) * 2.f;
|
||||||
|
return sceneDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunFrame(float dt) {
|
||||||
|
if(time < 0.f) {
|
||||||
|
time = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneDefinition sceneDef;
|
||||||
|
float cameraX = time;
|
||||||
|
cameraX -= floor(cameraX / 512.f) * 512.f;
|
||||||
|
cameraX = 512.f - cameraX;
|
||||||
|
sceneDef = SetupCamera(sceneDef,
|
||||||
|
Vector3(cameraX, 256.f, 12.f), Vector3(cameraX + .1f, 257.f, 12.5f), Vector3(0.f, 0.f, -1.f),
|
||||||
|
30.f);
|
||||||
|
sceneDef.zNear = 0.1f;
|
||||||
|
sceneDef.zFar = 222.f;
|
||||||
|
sceneDef.time = int(time * 1000.f);
|
||||||
|
sceneDef.viewportWidth = int(renderer.ScreenWidth);
|
||||||
|
sceneDef.viewportHeight = int(renderer.ScreenHeight);
|
||||||
|
sceneDef.denyCameraBlur = true;
|
||||||
|
sceneDef.depthOfFieldFocalLength = 100.f;
|
||||||
|
sceneDef.skipWorld = false;
|
||||||
|
|
||||||
|
// fade the map
|
||||||
|
float fade = Clamp((time - 1.f) / 2.2f, 0.f, 1.f);
|
||||||
|
sceneDef.globalBlur = Clamp((1.f - (time - 1.f) / 2.5f), 0.f, 1.f);
|
||||||
|
if(!mainMenu.IsEnabled) {
|
||||||
|
sceneDef.globalBlur = Max(sceneDef.globalBlur, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.StartScene(sceneDef);
|
||||||
|
renderer.EndScene();
|
||||||
|
|
||||||
|
// fade the map (draw)
|
||||||
|
if(fade < 1.f) {
|
||||||
|
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, 1.f - fade);
|
||||||
|
renderer.DrawImage(renderer.RegisterImage("Gfx/White.tga"),
|
||||||
|
AABB2(0.f, 0.f, renderer.ScreenWidth, renderer.ScreenHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw title logo
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/Title/Logo.png");
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 1.f);
|
||||||
|
renderer.DrawImage(img, Vector2((renderer.ScreenWidth - img.Width) * 0.5f, 64.f));
|
||||||
|
|
||||||
|
manager.RunFrame(dt);
|
||||||
|
manager.Render();
|
||||||
|
|
||||||
|
renderer.FrameDone();
|
||||||
|
renderer.Flip();
|
||||||
|
time += Min(dt, 0.05f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Closing() {
|
||||||
|
shouldExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WantsToBeClosed() {
|
||||||
|
return shouldExit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entry point of the main screen.
|
||||||
|
*/
|
||||||
|
MainScreenUI@ CreateMainScreenUI(Renderer@ renderer, AudioDevice@ audioDevice,
|
||||||
|
FontManager@ fontManager, MainScreenHelper@ helper) {
|
||||||
|
return MainScreenUI(renderer, audioDevice, fontManager, helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
177
Resources/Scripts/Gui/MainScreen/ServerList.as
Normal file
177
Resources/Scripts/Gui/MainScreen/ServerList.as
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CountryFlags.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class ServerListItem: spades::ui::ButtonBase {
|
||||||
|
MainScreenServerItem@ item;
|
||||||
|
FlagIconRenderer@ flagIconRenderer;
|
||||||
|
ServerListItem(spades::ui::UIManager@ manager, MainScreenServerItem@ item){
|
||||||
|
super(manager);
|
||||||
|
@this.item = item;
|
||||||
|
@flagIconRenderer = FlagIconRenderer(manager.Renderer);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
|
||||||
|
Vector4 bgcolor = Vector4(1.f, 1.f, 1.f, 0.0f);
|
||||||
|
Vector4 fgcolor = Vector4(1.f, 1.f, 1.f, 1.f);
|
||||||
|
if(item.Favorite) {
|
||||||
|
bgcolor = Vector4(0.3f, 0.3f, 1.f, 0.1f);
|
||||||
|
fgcolor = Vector4(220.f/255.f,220.f/255.f,0,1);
|
||||||
|
}
|
||||||
|
if(Pressed && Hover) {
|
||||||
|
bgcolor.w += 0.3;
|
||||||
|
} else if(Hover) {
|
||||||
|
bgcolor.w += 0.15;
|
||||||
|
}
|
||||||
|
renderer.ColorNP = bgcolor;
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
|
||||||
|
Font.Draw(item.Name, ScreenPosition + Vector2(4.f, 2.f), 1.f, fgcolor);
|
||||||
|
string playersStr = ToString(item.NumPlayers) + "/" + ToString(item.MaxPlayers);
|
||||||
|
Vector4 col(1,1,1,1);
|
||||||
|
if(item.NumPlayers >= item.MaxPlayers) col = Vector4(1,0.7f,0.7f,1);
|
||||||
|
else if(item.NumPlayers >= item.MaxPlayers * 3 / 4) col = Vector4(1,1,0.7f,1);
|
||||||
|
else if(item.NumPlayers == 0) col = Vector4(0.7f,0.7f,1,1);
|
||||||
|
Font.Draw(playersStr, ScreenPosition + Vector2(340.f-Font.Measure(playersStr).x * 0.5f, 2.f), 1.f, col);
|
||||||
|
Font.Draw(item.MapName, ScreenPosition + Vector2(400.f, 2.f), 1.f, Vector4(1,1,1,1));
|
||||||
|
Font.Draw(item.GameMode, ScreenPosition + Vector2(550.f, 2.f), 1.f, Vector4(1,1,1,1));
|
||||||
|
Font.Draw(item.Protocol, ScreenPosition + Vector2(630.f, 2.f), 1.f, Vector4(1,1,1,1));
|
||||||
|
if(not flagIconRenderer.DrawIcon(item.Country, ScreenPosition + Vector2(700.f, size.y * 0.5f))) {
|
||||||
|
Font.Draw(item.Country, ScreenPosition + Vector2(680.f, 2.f), 1.f, Vector4(1,1,1,1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
funcdef void ServerListItemEventHandler(ServerListModel@ sender, MainScreenServerItem@ item);
|
||||||
|
|
||||||
|
class ServerListModel: spades::ui::ListViewModel {
|
||||||
|
spades::ui::UIManager@ manager;
|
||||||
|
MainScreenServerItem@[]@ list;
|
||||||
|
|
||||||
|
ServerListItemEventHandler@ ItemActivated;
|
||||||
|
ServerListItemEventHandler@ ItemDoubleClicked;
|
||||||
|
ServerListItemEventHandler@ ItemRightClicked;
|
||||||
|
|
||||||
|
ServerListModel(spades::ui::UIManager@ manager, MainScreenServerItem@[]@ list) {
|
||||||
|
@this.manager = manager;
|
||||||
|
@this.list = list;
|
||||||
|
}
|
||||||
|
int NumRows {
|
||||||
|
get { return int(list.length); }
|
||||||
|
}
|
||||||
|
private void OnItemClicked(spades::ui::UIElement@ sender){
|
||||||
|
ServerListItem@ item = cast<ServerListItem>(sender);
|
||||||
|
if(ItemActivated !is null) {
|
||||||
|
ItemActivated(this, item.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void OnItemDoubleClicked(spades::ui::UIElement@ sender){
|
||||||
|
ServerListItem@ item = cast<ServerListItem>(sender);
|
||||||
|
if(ItemDoubleClicked !is null) {
|
||||||
|
ItemDoubleClicked(this, item.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void OnItemRightClicked(spades::ui::UIElement@ sender){
|
||||||
|
ServerListItem@ item = cast<ServerListItem>(sender);
|
||||||
|
if(ItemRightClicked !is null) {
|
||||||
|
ItemRightClicked(this, item.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spades::ui::UIElement@ CreateElement(int row) {
|
||||||
|
ServerListItem i(manager, list[row]);
|
||||||
|
@i.Activated = spades::ui::EventHandler(this.OnItemClicked);
|
||||||
|
@i.DoubleClicked = spades::ui::EventHandler(this.OnItemDoubleClicked);
|
||||||
|
@i.RightClicked = spades::ui::EventHandler(this.OnItemRightClicked);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
void RecycleElement(spades::ui::UIElement@ elem) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ServerListHeader: spades::ui::ButtonBase {
|
||||||
|
string Text;
|
||||||
|
ServerListHeader(spades::ui::UIManager@ manager){
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
void OnActivated() {
|
||||||
|
ButtonBase::OnActivated();
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
if(Pressed && Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.3f);
|
||||||
|
} else if(Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.15f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.0f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x - 2.f, pos.y, size.x, size.y));
|
||||||
|
|
||||||
|
Font.Draw(Text, ScreenPosition + Vector2(0.f, 2.f), 1.f, Vector4(1,1,1,1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainScreenServerListLoadingView: spades::ui::UIElement {
|
||||||
|
MainScreenServerListLoadingView(spades::ui::UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Font@ font = this.Font;
|
||||||
|
string text = _Tr("MainScreen", "Loading...");
|
||||||
|
Vector2 txtSize = font.Measure(text);
|
||||||
|
Vector2 txtPos;
|
||||||
|
txtPos = pos + (size - txtSize) * 0.5f;
|
||||||
|
|
||||||
|
font.Draw(text, txtPos, 1.f, Vector4(1,1,1,0.8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainScreenServerListErrorView: spades::ui::UIElement {
|
||||||
|
MainScreenServerListErrorView(spades::ui::UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Font@ font = this.Font;
|
||||||
|
string text = _Tr("MainScreen", "Failed to fetch the server list.");
|
||||||
|
Vector2 txtSize = font.Measure(text);
|
||||||
|
Vector2 txtPos;
|
||||||
|
txtPos = pos + (size - txtSize) * 0.5f;
|
||||||
|
|
||||||
|
font.Draw(text, txtPos, 1.f, Vector4(1,1,1,0.8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
754
Resources/Scripts/Gui/StartupScreen/ConfigViewFramework.as
Normal file
754
Resources/Scripts/Gui/StartupScreen/ConfigViewFramework.as
Normal file
@ -0,0 +1,754 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../UIFramework/UIControls.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
funcdef void HelpTextHandler(string text);
|
||||||
|
class ChainedEventHandler {
|
||||||
|
spades::ui::EventHandler@ h;
|
||||||
|
spades::ui::EventHandler@ h2;
|
||||||
|
ChainedEventHandler(spades::ui::EventHandler@ h, spades::ui::EventHandler@ h2) {
|
||||||
|
@this.h = h;
|
||||||
|
@this.h2 = h2;
|
||||||
|
}
|
||||||
|
void Handler(spades::ui::UIElement@ e) {
|
||||||
|
h(e); h2(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class HelpHandler {
|
||||||
|
private HelpTextHandler@ handler;
|
||||||
|
private spades::ui::TextViewer@ helpView;
|
||||||
|
private string text;
|
||||||
|
HelpHandler(spades::ui::TextViewer@ helpView, string text) {
|
||||||
|
this.text = text;
|
||||||
|
@this.helpView = helpView;
|
||||||
|
}
|
||||||
|
HelpHandler(HelpTextHandler@ handler, string text) {
|
||||||
|
this.text = text;
|
||||||
|
@this.handler = handler;
|
||||||
|
}
|
||||||
|
private void OnMouseHover(spades::ui::UIElement@ elm) {
|
||||||
|
if(helpView !is null) {
|
||||||
|
helpView.Text = text;
|
||||||
|
}
|
||||||
|
if(handler !is null) {
|
||||||
|
handler(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Watch(spades::ui::UIElement@ elm) {
|
||||||
|
@elm.MouseEntered = spades::ui::EventHandler(this.OnMouseHover);
|
||||||
|
}
|
||||||
|
void WatchDeep(spades::ui::UIElement@ elm) {
|
||||||
|
if(elm.MouseEntered !is null) {
|
||||||
|
ChainedEventHandler chain(elm.MouseEntered, spades::ui::EventHandler(this.OnMouseHover));
|
||||||
|
@elm.MouseEntered = spades::ui::EventHandler(chain.Handler);
|
||||||
|
}else{
|
||||||
|
Watch(elm);
|
||||||
|
}
|
||||||
|
spades::ui::UIElementIterator it(elm);
|
||||||
|
while(it.MoveNext()) {
|
||||||
|
WatchDeep(it.Current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin class LabelAddable {
|
||||||
|
|
||||||
|
private void AddLabel(float x, float y, float h, string text) {
|
||||||
|
spades::ui::Label label(Manager);
|
||||||
|
Font@ font = ui.fontManager.GuiFont;
|
||||||
|
Vector2 siz = font.Measure(text);
|
||||||
|
label.Text = text;
|
||||||
|
label.Alignment = Vector2(0.f, 0.5f);
|
||||||
|
label.Bounds = AABB2(x, y, siz.x, h);
|
||||||
|
AddChild(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenConfigViewModel: spades::ui::ListViewModel {
|
||||||
|
spades::ui::UIElement@[] items;
|
||||||
|
spades::ui::UIElement@[]@ items2;
|
||||||
|
StartupScreenConfigViewModel() {
|
||||||
|
}
|
||||||
|
int NumRows {
|
||||||
|
get {
|
||||||
|
if(items2 !is null)
|
||||||
|
return int(items2.length);
|
||||||
|
return int(items.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Filter(string text) {
|
||||||
|
if(text.length == 0) {
|
||||||
|
@items2 = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spades::ui::UIElement@[] newItems;
|
||||||
|
for(uint i = 0, count = items.length; i < count; i++) {
|
||||||
|
StartupScreenConfigItemEditor@ editor =
|
||||||
|
cast<StartupScreenConfigItemEditor>(items[i]);
|
||||||
|
if(editor is null) continue;
|
||||||
|
string label = editor.GetLabel();
|
||||||
|
if(StringContainsCaseInsensitive(label, text)) {
|
||||||
|
newItems.insertLast(items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@items2 = newItems;
|
||||||
|
}
|
||||||
|
spades::ui::UIElement@ CreateElement(int row) {
|
||||||
|
if(items2 !is null)
|
||||||
|
return items2[row];
|
||||||
|
return items[row];
|
||||||
|
}
|
||||||
|
void RecycleElement(spades::ui::UIElement@ elem) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StartupScreenGenericConfig {
|
||||||
|
string GetValue();
|
||||||
|
void SetValue(string);
|
||||||
|
/** Returns an empty string when there's no problem. */
|
||||||
|
string CheckValueCapability(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenConfig: StartupScreenGenericConfig {
|
||||||
|
private StartupScreenUI@ ui;
|
||||||
|
private ConfigItem@ cfg;
|
||||||
|
private string cfgName;
|
||||||
|
StartupScreenConfig(StartupScreenUI@ ui, string cfg) {
|
||||||
|
@this.ui = ui;
|
||||||
|
@this.cfg = ConfigItem(cfg);
|
||||||
|
cfgName = cfg;
|
||||||
|
}
|
||||||
|
string GetValue() {
|
||||||
|
return cfg.StringValue;
|
||||||
|
}
|
||||||
|
void SetValue(string v) {
|
||||||
|
cfg.StringValue = v;
|
||||||
|
}
|
||||||
|
string CheckValueCapability(string v) {
|
||||||
|
return ui.helper.CheckConfigCapability(cfgName, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenConfigSetter {
|
||||||
|
StartupScreenGenericConfig@ c;
|
||||||
|
string value;
|
||||||
|
StartupScreenConfigSetter(StartupScreenGenericConfig@ c, string value) {
|
||||||
|
@this.c = c;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
void Set(spades::ui::UIElement@) {
|
||||||
|
c.SetValue(this.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StartupScreenConfigItemEditor {
|
||||||
|
void LoadConfig();
|
||||||
|
StartupScreenGenericConfig@ GetConfig();
|
||||||
|
void SetHelpTextHandler(HelpTextHandler@);
|
||||||
|
string GetLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class StartupScreenConfigSelectItemEditor: spades::ui::UIElement, LabelAddable, StartupScreenConfigItemEditor, StartupScreenConfigItemEditor {
|
||||||
|
|
||||||
|
protected StartupScreenUI@ ui;
|
||||||
|
private string[]@ descs;
|
||||||
|
private string[]@ values;
|
||||||
|
protected StartupScreenGenericConfig@ config;
|
||||||
|
protected spades::ui::RadioButton@[] buttons;
|
||||||
|
private string label;
|
||||||
|
|
||||||
|
StartupScreenConfigSelectItemEditor(StartupScreenUI@ ui,
|
||||||
|
StartupScreenGenericConfig@ cfg,
|
||||||
|
string values, string descs) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@this.descs = descs.split("|");
|
||||||
|
@config = cfg;
|
||||||
|
@this.values = values.split("|");
|
||||||
|
|
||||||
|
{
|
||||||
|
string desc = this.descs[0];
|
||||||
|
int idx = desc.findFirst(":");
|
||||||
|
if(idx >= 0) {
|
||||||
|
desc = desc.substr(0, idx);
|
||||||
|
}
|
||||||
|
AddLabel(0, 0, 24.f, desc);
|
||||||
|
this.label = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(uint i = 0; i < this.values.length; i++) {
|
||||||
|
spades::ui::RadioButton b(Manager);
|
||||||
|
string desc = this.descs[i + 1];
|
||||||
|
int idx = desc.findFirst(":");
|
||||||
|
if(idx >= 0) {
|
||||||
|
desc = desc.substr(0, idx);
|
||||||
|
}
|
||||||
|
b.Caption = desc;
|
||||||
|
|
||||||
|
b.GroupName = "hoge";
|
||||||
|
StartupScreenConfigSetter setter(config, this.values[i]);
|
||||||
|
@b.Activated = spades::ui::EventHandler(setter.Set);
|
||||||
|
buttons.insertLast(b);
|
||||||
|
this.AddChild(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string GetLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
string val = config.GetValue();
|
||||||
|
for(uint i = 0, count = values.length; i < count; i++) {
|
||||||
|
buttons[i].Toggled = (values[i] == val);
|
||||||
|
buttons[i].Enable = CheckValueCapability(values[i]).length == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string CheckValueCapability(string v) {
|
||||||
|
return config.CheckValueCapability(v);
|
||||||
|
}
|
||||||
|
StartupScreenGenericConfig@ GetConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
void SetHelpTextHandler(HelpTextHandler@ handler) {
|
||||||
|
for(uint i = 0, count = values.length; i < count; i++) {
|
||||||
|
string desc = descs[i + 1];
|
||||||
|
int idx = desc.findFirst(":");
|
||||||
|
if(idx < 0) {
|
||||||
|
desc = descs[0];
|
||||||
|
idx = desc.findFirst(":");
|
||||||
|
}
|
||||||
|
desc = desc.substr(uint(idx + 1));
|
||||||
|
HelpHandler(handler, desc).Watch(buttons[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_Bounds(AABB2 v) {
|
||||||
|
UIElement::set_Bounds(v);
|
||||||
|
Vector2 size = this.Size;
|
||||||
|
float h = 24.f;
|
||||||
|
float x = size.x;
|
||||||
|
for(uint i = buttons.length; i > 0; i--) {
|
||||||
|
spades::ui::RadioButton@ b = buttons[i - 1];
|
||||||
|
float w = ui.fontManager.GuiFont.Measure(b.Caption).x + 26.f;
|
||||||
|
x -= w + 2.f;
|
||||||
|
b.Bounds = AABB2(x, 0.f, w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenConfigCheckItemEditor: spades::ui::UIElement, StartupScreenConfigItemEditor {
|
||||||
|
|
||||||
|
protected StartupScreenUI@ ui;
|
||||||
|
private string desc;
|
||||||
|
private string valueOff;
|
||||||
|
private string valueOn;
|
||||||
|
private StartupScreenGenericConfig@ config;
|
||||||
|
private spades::ui::CheckBox@ button;
|
||||||
|
private string label;
|
||||||
|
|
||||||
|
StartupScreenConfigCheckItemEditor(StartupScreenUI@ ui,
|
||||||
|
StartupScreenGenericConfig@ cfg,
|
||||||
|
string valueOff, string valueOn, string label, string desc) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@config = cfg;
|
||||||
|
this.valueOff = valueOff;
|
||||||
|
this.valueOn = valueOn;
|
||||||
|
this.desc = desc;
|
||||||
|
|
||||||
|
spades::ui::CheckBox b(Manager);
|
||||||
|
b.Caption = label;
|
||||||
|
this.label = label;
|
||||||
|
@b.Activated = spades::ui::EventHandler(this.StateChanged);
|
||||||
|
@button = b;
|
||||||
|
this.AddChild(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
string GetLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
string val = config.GetValue();
|
||||||
|
button.Toggled = (val != valueOff);
|
||||||
|
button.Enable = CheckValueCapability(valueOn).length == 0;
|
||||||
|
}
|
||||||
|
string CheckValueCapability(string v) {
|
||||||
|
return config.CheckValueCapability(v);
|
||||||
|
}
|
||||||
|
StartupScreenGenericConfig@ GetConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
private void StateChanged(spades::ui::UIElement@) {
|
||||||
|
config.SetValue(button.Toggled ? valueOn : valueOff);
|
||||||
|
}
|
||||||
|
void SetHelpTextHandler(HelpTextHandler@ handler) {
|
||||||
|
HelpHandler(handler, desc).Watch(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_Bounds(AABB2 v) {
|
||||||
|
UIElement::set_Bounds(v);
|
||||||
|
Vector2 size = this.Size;
|
||||||
|
float h = 24.f;
|
||||||
|
button.Bounds = AABB2(0.f, 0.f, size.x, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenConfigSliderItemEditor: spades::ui::UIElement, StartupScreenConfigItemEditor, LabelAddable {
|
||||||
|
|
||||||
|
private StartupScreenUI@ ui;
|
||||||
|
private string desc;
|
||||||
|
private double stepSize;
|
||||||
|
private StartupScreenGenericConfig@ config;
|
||||||
|
private spades::ui::Slider@ slider;
|
||||||
|
private spades::ui::Label@ valueLabel;
|
||||||
|
private ConfigNumberFormatter@ formatter;
|
||||||
|
private string label;
|
||||||
|
|
||||||
|
StartupScreenConfigSliderItemEditor(StartupScreenUI@ ui,
|
||||||
|
StartupScreenGenericConfig@ cfg,
|
||||||
|
double minValue, double maxValue, double stepSize, string label, string desc,
|
||||||
|
ConfigNumberFormatter@ formatter) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@config = cfg;
|
||||||
|
this.desc = desc;
|
||||||
|
this.stepSize = stepSize;
|
||||||
|
this.label = label;
|
||||||
|
|
||||||
|
AddLabel(0, 0, 24.f, label);
|
||||||
|
|
||||||
|
spades::ui::Slider b(Manager);
|
||||||
|
b.MinValue = minValue;
|
||||||
|
b.MaxValue = maxValue;
|
||||||
|
|
||||||
|
// compute large change
|
||||||
|
int steps = int((maxValue - minValue) / stepSize);
|
||||||
|
steps = (steps + 9) / 10;
|
||||||
|
b.LargeChange = float(steps) * stepSize;
|
||||||
|
b.SmallChange = stepSize;
|
||||||
|
|
||||||
|
@b.Changed = spades::ui::EventHandler(this.StateChanged);
|
||||||
|
@slider = b;
|
||||||
|
this.AddChild(b);
|
||||||
|
|
||||||
|
spades::ui::Label l(Manager);
|
||||||
|
@valueLabel = l;
|
||||||
|
l.Alignment = Vector2(1.f, 0.5f);
|
||||||
|
this.AddChild(l);
|
||||||
|
|
||||||
|
@this.formatter = formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLabel() {
|
||||||
|
double v = slider.Value;
|
||||||
|
string s = formatter.Format(v);
|
||||||
|
valueLabel.Text = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
string GetLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
string val = config.GetValue();
|
||||||
|
double v = ParseDouble(val);
|
||||||
|
// don't use `ScrollTo` here; this calls `Changed` so
|
||||||
|
// out-of-range value will be clamped and saved back
|
||||||
|
slider.Value = Clamp(v, slider.MinValue, slider.MaxValue);
|
||||||
|
// FIXME: button.Enable = CheckValueCapability(valueOn).length == 0;
|
||||||
|
UpdateLabel();
|
||||||
|
}
|
||||||
|
string CheckValueCapability(string v) {
|
||||||
|
return ""; //FIXME: config.CheckValueCapability(v);
|
||||||
|
}
|
||||||
|
StartupScreenGenericConfig@ GetConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoRounding() {
|
||||||
|
double v = double(slider.Value - slider.MinValue);
|
||||||
|
v = floor((v / stepSize) + 0.5) * stepSize;
|
||||||
|
v += double(slider.MinValue);
|
||||||
|
slider.Value = v;
|
||||||
|
}
|
||||||
|
private void StateChanged(spades::ui::UIElement@) {
|
||||||
|
DoRounding();
|
||||||
|
config.SetValue(ToString(slider.Value));
|
||||||
|
UpdateLabel();
|
||||||
|
}
|
||||||
|
void SetHelpTextHandler(HelpTextHandler@ handler) {
|
||||||
|
HelpHandler(handler, desc).WatchDeep(slider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_Bounds(AABB2 v) {
|
||||||
|
UIElement::set_Bounds(v);
|
||||||
|
Vector2 size = this.Size;
|
||||||
|
float h = 24.f;
|
||||||
|
slider.Bounds = AABB2(100.f, 2.f, size.x - 180.f, h - 4.f);
|
||||||
|
valueLabel.Bounds = AABB2(size.x - 80.f, 0.f, 80.f, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class StartupScreenConfigFieldItemEditor: spades::ui::UIElement, StartupScreenConfigItemEditor, LabelAddable {
|
||||||
|
|
||||||
|
private StartupScreenUI@ ui;
|
||||||
|
private string desc;
|
||||||
|
private double stepSize;
|
||||||
|
private StartupScreenGenericConfig@ config;
|
||||||
|
private spades::ui::Field@ field;
|
||||||
|
private string label;
|
||||||
|
|
||||||
|
StartupScreenConfigFieldItemEditor(StartupScreenUI@ ui,
|
||||||
|
StartupScreenGenericConfig@ cfg,
|
||||||
|
string label, string desc) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@config = cfg;
|
||||||
|
this.desc = desc;
|
||||||
|
this.label = label;
|
||||||
|
|
||||||
|
AddLabel(0, 0, 24.f, label);
|
||||||
|
|
||||||
|
spades::ui::Field b(Manager);
|
||||||
|
|
||||||
|
@b.Changed = spades::ui::EventHandler(this.StateChanged);
|
||||||
|
@field = b;
|
||||||
|
this.AddChild(b);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
string GetLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
string val = config.GetValue();
|
||||||
|
field.Text = val;
|
||||||
|
}
|
||||||
|
string CheckValueCapability(string v) {
|
||||||
|
return config.CheckValueCapability(v);
|
||||||
|
}
|
||||||
|
StartupScreenGenericConfig@ GetConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StateChanged(spades::ui::UIElement@) {
|
||||||
|
config.SetValue(field.Text);
|
||||||
|
}
|
||||||
|
void SetHelpTextHandler(HelpTextHandler@ handler) {
|
||||||
|
HelpHandler(handler, desc).WatchDeep(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_Bounds(AABB2 v) {
|
||||||
|
UIElement::set_Bounds(v);
|
||||||
|
Vector2 size = this.Size;
|
||||||
|
float h = 24.f;
|
||||||
|
field.Bounds = AABB2(240.f, 0.f, size.x - 240.f, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps multiple configs to {"0", "1", ...} or "custom"
|
||||||
|
class StartupScreenComplexConfig: StartupScreenGenericConfig {
|
||||||
|
StartupScreenConfigItemEditor@[] editors;
|
||||||
|
StartupScreenComplexConfigPreset@[] presets;
|
||||||
|
|
||||||
|
void AddEditor(StartupScreenConfigItemEditor@ editor) {
|
||||||
|
Assert(presets.length == 0);
|
||||||
|
editors.insertLast(editor);
|
||||||
|
}
|
||||||
|
void AddPreset(StartupScreenComplexConfigPreset@ preset) {
|
||||||
|
Assert(preset.Values.length == editors.length);
|
||||||
|
presets.insertLast(preset);
|
||||||
|
}
|
||||||
|
|
||||||
|
string GetValue() {
|
||||||
|
string[] values;
|
||||||
|
|
||||||
|
for(uint i = 0; i < editors.length; i++) {
|
||||||
|
values.insertLast(editors[i].GetConfig().GetValue());
|
||||||
|
}
|
||||||
|
for(uint i = 0; i < presets.length; i++) {
|
||||||
|
string[]@ pval = presets[i].Values;
|
||||||
|
uint j = 0;
|
||||||
|
uint jc = pval.length;
|
||||||
|
for(; j < jc; j++) {
|
||||||
|
if(values[j] != pval[j]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(j == jc) {
|
||||||
|
return ToString(int(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "custom";
|
||||||
|
}
|
||||||
|
void SetValue(string v) {
|
||||||
|
if(v == "custom") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint pId = uint(ParseInt(v));
|
||||||
|
string[]@ pval = presets[pId].Values;
|
||||||
|
for(uint i = 0; i < pval.length; i++) {
|
||||||
|
editors[i].GetConfig().SetValue(pval[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string CheckValueCapability(string v) {
|
||||||
|
if(v == "custom") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
uint pId = uint(ParseInt(v));
|
||||||
|
string[]@ pval = presets[pId].Values;
|
||||||
|
string ret = "";
|
||||||
|
for(uint i = 0; i < pval.length; i++) {
|
||||||
|
ret += editors[i].GetConfig().CheckValueCapability(pval[i]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for StartupScreenConfigSelectItemEditor's ctor param
|
||||||
|
string GetValuesString() {
|
||||||
|
string[] lst;
|
||||||
|
for(uint i = 0; i < presets.length; i++) {
|
||||||
|
lst.insertLast(ToString(int(i)));
|
||||||
|
}
|
||||||
|
lst.insertLast("custom");
|
||||||
|
return join(lst, "|");
|
||||||
|
}
|
||||||
|
// used for StartupScreenConfigSelectItemEditor's ctor param
|
||||||
|
string GetDescriptionsString() {
|
||||||
|
string[] lst;
|
||||||
|
for(uint i = 0; i < presets.length; i++) {
|
||||||
|
lst.insertLast(presets[i].Name);
|
||||||
|
}
|
||||||
|
lst.insertLast(_Tr("StartupScreen", "Custom"));
|
||||||
|
return join(lst, "|");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenComplexConfigPreset {
|
||||||
|
string Name;
|
||||||
|
string[] Values;
|
||||||
|
StartupScreenComplexConfigPreset(string name, string values) {
|
||||||
|
Name = name;
|
||||||
|
Values = values.split("|");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenConfigComplexItemEditor: StartupScreenConfigSelectItemEditor {
|
||||||
|
private string dlgTitle;
|
||||||
|
|
||||||
|
StartupScreenConfigComplexItemEditor(StartupScreenUI@ ui,
|
||||||
|
StartupScreenComplexConfig@ cfg,
|
||||||
|
string label, string desc) {
|
||||||
|
super(ui, cfg, cfg.GetValuesString(),
|
||||||
|
label + ":" + desc + "|" + cfg.GetDescriptionsString());
|
||||||
|
dlgTitle = label;
|
||||||
|
@buttons[buttons.length - 1].Activated = spades::ui::EventHandler(this.CustomClicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CustomClicked(spades::ui::UIElement@) {
|
||||||
|
RunDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DialogDone(spades::ui::UIElement@) {
|
||||||
|
LoadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunDialog() {
|
||||||
|
StartupScreenComplexConfigDialog dlg(ui.manager, cast<StartupScreenComplexConfig>(config));
|
||||||
|
@dlg.DialogDone = spades::ui::EventHandler(this.DialogDone);
|
||||||
|
dlg.Title = dlgTitle;
|
||||||
|
dlg.RunDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenConfigView: spades::ui::ListViewBase {
|
||||||
|
private StartupScreenConfigViewModel vmodel;
|
||||||
|
|
||||||
|
StartupScreenConfigView(spades::ui::UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
this.RowHeight = 30.f;
|
||||||
|
}
|
||||||
|
void Finalize() {
|
||||||
|
@this.Model = vmodel;
|
||||||
|
}
|
||||||
|
void AddRow(spades::ui::UIElement@ elm) {
|
||||||
|
vmodel.items.insertLast(elm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Filter(string text) {
|
||||||
|
vmodel.Filter(text);
|
||||||
|
Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHelpTextHandler(HelpTextHandler@ handler) {
|
||||||
|
spades::ui::UIElement@[]@ elms = vmodel.items;
|
||||||
|
for(uint i = 0; i < elms.length; i++) {
|
||||||
|
StartupScreenConfigItemEditor@ item = cast<StartupScreenConfigItemEditor>(elms[i]);
|
||||||
|
if(item !is null) {
|
||||||
|
item.SetHelpTextHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void LoadConfig() {
|
||||||
|
spades::ui::UIElement@[]@ elms = vmodel.items;
|
||||||
|
for(uint i = 0; i < elms.length; i++) {
|
||||||
|
StartupScreenConfigItemEditor@ item = cast<StartupScreenConfigItemEditor>(elms[i]);
|
||||||
|
if(item !is null) {
|
||||||
|
item.LoadConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenComplexConfigDialog: spades::ui::UIElement {
|
||||||
|
StartupScreenComplexConfig@ config;
|
||||||
|
float ContentsTop = 50.f;
|
||||||
|
float ContentsHeight;
|
||||||
|
string Title;
|
||||||
|
|
||||||
|
spades::ui::TextViewer@ helpView;
|
||||||
|
StartupScreenConfigView@ configView;
|
||||||
|
|
||||||
|
spades::ui::EventHandler@ DialogDone;
|
||||||
|
|
||||||
|
private spades::ui::UIElement@ oldRoot;
|
||||||
|
|
||||||
|
StartupScreenComplexConfigDialog(spades::ui::UIManager@ manager,
|
||||||
|
StartupScreenComplexConfig@ config) {
|
||||||
|
super(manager);
|
||||||
|
@this.config = config;
|
||||||
|
Vector2 size = manager.RootElement.Size;
|
||||||
|
ContentsHeight = size.y - ContentsTop * 2.f;
|
||||||
|
|
||||||
|
float mainWidth = size.x - 250.f;
|
||||||
|
{
|
||||||
|
spades::ui::TextViewer e(Manager);
|
||||||
|
e.Bounds = AABB2(mainWidth, ContentsTop + 30.f, size.x - mainWidth - 10.f, ContentsHeight - 60.f);
|
||||||
|
AddChild(e);
|
||||||
|
@helpView = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenConfigView cfg(Manager);
|
||||||
|
|
||||||
|
StartupScreenConfigItemEditor@[]@ editors = config.editors;
|
||||||
|
|
||||||
|
for(uint i = 0; i < editors.length; i++)
|
||||||
|
cfg.AddRow(cast<spades::ui::UIElement>(editors[i]));
|
||||||
|
|
||||||
|
cfg.Finalize();
|
||||||
|
cfg.SetHelpTextHandler(HelpTextHandler(this.HandleHelpText));
|
||||||
|
cfg.Bounds = AABB2(10.f, ContentsTop + 30.f, mainWidth - 20.f, ContentsHeight - 60.f);
|
||||||
|
AddChild(cfg);
|
||||||
|
@configView = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("StartupScreen", "Close");
|
||||||
|
button.Bounds = AABB2(size.x - 160.f, ContentsTop + ContentsHeight - 30.f, 150.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.CloseActivated);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseActivated(spades::ui::UIElement@) {
|
||||||
|
if(oldRoot !is null) {
|
||||||
|
oldRoot.Enable = true;
|
||||||
|
@oldRoot = null;
|
||||||
|
}
|
||||||
|
@this.Parent = null;
|
||||||
|
DialogDone(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleHelpText(string s) {
|
||||||
|
helpView.Text = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunDialog() {
|
||||||
|
spades::ui::UIElement@ root = Manager.RootElement;
|
||||||
|
|
||||||
|
spades::ui::UIElementIterator iterator(root);
|
||||||
|
while(iterator.MoveNext()) {
|
||||||
|
spades::ui::UIElement@ e = iterator.Current;
|
||||||
|
if(e.Enable and e.Visible) {
|
||||||
|
@oldRoot = e;
|
||||||
|
e.Enable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Bounds = root.Bounds;
|
||||||
|
root.AddChild(this);
|
||||||
|
|
||||||
|
configView.LoadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Renderer@ r = Manager.Renderer;
|
||||||
|
Image@ img = r.RegisterImage("Gfx/White.tga");
|
||||||
|
|
||||||
|
r.ColorNP = Vector4(0, 0, 0, 0.8f);
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y, size.x, ContentsTop - 15.f));
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, ContentsTop + ContentsHeight + 15.f, size.x, ContentsTop - 15.f));
|
||||||
|
|
||||||
|
r.ColorNP = Vector4(0, 0, 0, 0.95f);
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, ContentsTop - 15.f, size.x, ContentsHeight + 30.f));
|
||||||
|
|
||||||
|
r.ColorNP = Vector4(1, 1, 1, 0.08f);
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + ContentsTop - 15.f, size.x, 1.f));
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + ContentsTop + ContentsHeight + 15.f, size.x, 1.f));
|
||||||
|
r.ColorNP = Vector4(1, 1, 1, 0.2f);
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + ContentsTop - 14.f, size.x, 1.f));
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + ContentsTop + ContentsHeight + 14.f, size.x, 1.f));
|
||||||
|
|
||||||
|
Font@ font = Font;
|
||||||
|
r.ColorNP = Vector4(0.8f, 0.8f, 0.8f, 1.f);
|
||||||
|
r.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + ContentsTop, size.x, 20.f));
|
||||||
|
font.Draw(Title, Vector2(pos.x + 10.f, pos.y + ContentsTop), 1.f, Vector4(0.f, 0.f, 0.f, 1.f));
|
||||||
|
|
||||||
|
UIElement::Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
868
Resources/Scripts/Gui/StartupScreen/ConfigViewTabs.as
Normal file
868
Resources/Scripts/Gui/StartupScreen/ConfigViewTabs.as
Normal file
@ -0,0 +1,868 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ConfigViewFramework.as"
|
||||||
|
#include "../UIFramework/DropDownList.as"
|
||||||
|
#include "../MessageBox.as"
|
||||||
|
#include "UpdateCheckView.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class StartupScreenGraphicsTab: spades::ui::UIElement, LabelAddable {
|
||||||
|
StartupScreenUI@ ui;
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
|
||||||
|
StartupScreenGraphicsDisplayResolutionEditor@ resEdit;
|
||||||
|
|
||||||
|
spades::ui::CheckBox@ fullscreenCheck;
|
||||||
|
spades::ui::RadioButton@ driverOpenGL;
|
||||||
|
spades::ui::RadioButton@ driverSoftware;
|
||||||
|
|
||||||
|
spades::ui::TextViewer@ helpView;
|
||||||
|
StartupScreenConfigView@ configViewGL;
|
||||||
|
StartupScreenConfigView@ configViewSoftware;
|
||||||
|
|
||||||
|
private ConfigItem r_renderer("r_renderer");
|
||||||
|
private ConfigItem r_fullscreen("r_fullscreen");
|
||||||
|
|
||||||
|
StartupScreenGraphicsTab(StartupScreenUI@ ui, Vector2 size) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@helper = ui.helper;
|
||||||
|
|
||||||
|
float mainWidth = size.x - 250.f;
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::TextViewer e(Manager);
|
||||||
|
e.Bounds = AABB2(mainWidth + 10.f, 0.f, size.x - mainWidth - 10.f, size.y);
|
||||||
|
@e.Font = ui.fontManager.GuiFont;
|
||||||
|
e.Text = _Tr("StartupScreen", "Graphics Settings");
|
||||||
|
AddChild(e);
|
||||||
|
@helpView = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLabel(0.f, 0.f, 24.f, _Tr("StartupScreen", "Resolution"));
|
||||||
|
{
|
||||||
|
StartupScreenGraphicsDisplayResolutionEditor e(ui);
|
||||||
|
e.Bounds = AABB2(100.f, 0.f, 124.f, 24.f);
|
||||||
|
AddChild(e);
|
||||||
|
@resEdit = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::CheckBox e(Manager);
|
||||||
|
e.Caption = _Tr("StartupScreen", "Fullscreen Mode");
|
||||||
|
e.Bounds = AABB2(230.f, 0.f, 200.f, 24.f);
|
||||||
|
HelpHandler(helpView,
|
||||||
|
_Tr("StartupScreen", "By running in fullscreen mode OpenSpades occupies the "
|
||||||
|
"screen, making it easier for you to concentrate on playing the game.")).Watch(e);
|
||||||
|
@e.Activated = spades::ui::EventHandler(this.OnFullscreenCheck);
|
||||||
|
AddChild(e);
|
||||||
|
@fullscreenCheck = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLabel(0.f, 30.f, 24.f, _Tr("StartupScreen", "Backend"));
|
||||||
|
{
|
||||||
|
spades::ui::RadioButton e(Manager);
|
||||||
|
e.Caption = _Tr("StartupScreen", "OpenGL");
|
||||||
|
e.Bounds = AABB2(100.f, 30.f, 140.f, 24.f);
|
||||||
|
e.GroupName = "driver";
|
||||||
|
HelpHandler(helpView,
|
||||||
|
_Tr("StartupScreen", "OpenGL renderer uses your computer's graphics "
|
||||||
|
"accelerator to generate the game screen.")).Watch(e);
|
||||||
|
@e.Activated = spades::ui::EventHandler(this.OnDriverOpenGL);
|
||||||
|
AddChild(e);
|
||||||
|
@driverOpenGL = e;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::RadioButton e(Manager);
|
||||||
|
e.Caption = _Tr("StartupScreen", "Software");
|
||||||
|
e.Bounds = AABB2(250.f, 30.f, 140.f, 24.f);
|
||||||
|
e.GroupName = "driver";
|
||||||
|
HelpHandler(helpView,
|
||||||
|
_Tr("StartupScreen", "Software renderer uses CPU to generate the game "
|
||||||
|
"screen. Its quality and performance might be inferior to OpenGL "
|
||||||
|
"renderer, but it works even with an unsupported GPU.")).Watch(e);
|
||||||
|
@e.Activated = spades::ui::EventHandler(this.OnDriverSoftware);
|
||||||
|
AddChild(e);
|
||||||
|
@driverSoftware = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenConfigView cfg(Manager);
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigSelectItemEditor(ui,
|
||||||
|
StartupScreenGraphicsAntialiasConfig(ui), "0|2|4|fxaa",
|
||||||
|
_Tr("StartupScreen",
|
||||||
|
"Antialias:Enables a technique to improve the appearance of high-contrast edges.\n\n"
|
||||||
|
"MSAA: Performs antialiasing by generating an intermediate high-resolution image. "
|
||||||
|
"Looks best, but doesn't cope with some settings.\n\n"
|
||||||
|
"FXAA: Performs antialiasing by smoothing artifacts out as a post-process.|"
|
||||||
|
"Off|MSAA 2x|4x|FXAA")));
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_radiosity"), "0", "1", _Tr("StartupScreen", "Global Illumination"),
|
||||||
|
_Tr("StartupScreen",
|
||||||
|
"Enables a physically based simulation of light path for more realistic lighting.")));
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_hdr"), "0", "1", _Tr("StartupScreen", "Linear HDR Rendering"),
|
||||||
|
_Tr("StartupScreen",
|
||||||
|
"Uses a number representation which allows wider dynamic range during rendering process. "
|
||||||
|
"Additionally, this allows color calculation whose value is in linear correspondence with actual energy, "
|
||||||
|
"that is, physically accurate blending can be achieved.")));
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenComplexConfig cplx;
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_cameraBlur"), "0", "1", _Tr("StartupScreen", "Camera Blur"),
|
||||||
|
_Tr("StartupScreen", "Blurs the screen when you turn quickly.")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_lens"), "0", "1", _Tr("StartupScreen", "Lens Effect"),
|
||||||
|
_Tr("StartupScreen", "Simulates distortion caused by a real camera lens.")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_bloom"), "0", "1", _Tr("StartupScreen", "Lens Scattering Filter"),
|
||||||
|
_Tr("StartupScreen", "Simulates light being scattered by dust on the camera lens.")));
|
||||||
|
// r_lens is currently no-op
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_lensFlare"), "0", "1", _Tr("StartupScreen", "Lens Flare"),
|
||||||
|
_Tr("StartupScreen", "The Sun causes lens flare.")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_lensFlareDynamic"), "0", "1", _Tr("StartupScreen", "Flares for Dynamic Lights"),
|
||||||
|
_Tr("StartupScreen", "Enables lens flare for light sources other than the Sun.")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_colorCorrection"), "0", "1", _Tr("StartupScreen", "Color Correction"),
|
||||||
|
_Tr("StartupScreen", "Applies cinematic color correction to make the image look better.")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_depthOfField"), "0", "1", _Tr("StartupScreen", "Depth of Field"),
|
||||||
|
_Tr("StartupScreen", "Blurs out-of-focus objects.")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_ssao"), "0", "1", _Tr("StartupScreen", "Screen Space Ambient Occlusion"),
|
||||||
|
_Tr("StartupScreen", "Simulates soft shadows that occur between nearby objects.")));
|
||||||
|
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "Low"), "0|0|0|0|0|0|0|0"));
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "Medium"), "1|0|0|1|0|1|0|0"));
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "High"), "1|1|1|1|1|1|1|0"));
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "Ultra"), "1|1|1|1|1|1|1|1"));
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigComplexItemEditor(ui, cplx,
|
||||||
|
_Tr("StartupScreen", "Post-process"),
|
||||||
|
_Tr("StartupScreen", "Post-process modifies the image to make it look better and "
|
||||||
|
"more realistic.")));
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigSelectItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_softParticles"), "0|1|2",
|
||||||
|
_Tr("StartupScreen",
|
||||||
|
"Particles|"
|
||||||
|
"Low:Artifact occurs when a particle intersects other objects.|"
|
||||||
|
"Medium:Particle intersects objects smoothly.|"
|
||||||
|
"High:Particle intersects objects smoothly, and some objects casts "
|
||||||
|
"their shadow to particles.")));
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenComplexConfig cplx;
|
||||||
|
// r_mapSoftShadow is currently no-op
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_dlights"), "0", "1", _Tr("StartupScreen", "Dynamic Lights"),
|
||||||
|
_Tr("StartupScreen",
|
||||||
|
"Gives some objects an ability to emit light to give them "
|
||||||
|
"an energy-emitting impression.")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_modelShadows"), "0", "1", _Tr("StartupScreen", "Shadows"),
|
||||||
|
_Tr("StartupScreen", "Non-static object casts a shadow.")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_fogShadow"), "0", "1", _Tr("StartupScreen", "Volumetric Fog"),
|
||||||
|
_Tr("StartupScreen", "Simulates shadow being casted to the fog particles using a "
|
||||||
|
"super highly computationally demanding algorithm. ")));
|
||||||
|
cplx.AddEditor(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_physicalLighting"), "0", "1", _Tr("StartupScreen", "Physically Based Lighting"),
|
||||||
|
_Tr("StartupScreen", "Uses more accurate approximation techniques to decide the brightness of objects.")));
|
||||||
|
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "Low"), "1|0|0|0"));
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "Medium"), "1|1|0|0"));
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "High"), "1|1|0|1"));
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigComplexItemEditor(ui, cplx,
|
||||||
|
_Tr("StartupScreen", "Direct Lights"),
|
||||||
|
_Tr("StartupScreen", "Controls how light encounting a material and atmosphere directly "
|
||||||
|
"affects its appearance.")));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenComplexConfig cplx;
|
||||||
|
|
||||||
|
cplx.AddEditor(StartupScreenConfigSelectItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_water"), "0|1|2|3",
|
||||||
|
_Tr("StartupScreen",
|
||||||
|
"Water Shader|"
|
||||||
|
"None:Water is rendered in the same way that normal blocks are done.|"
|
||||||
|
"Level 1:Refraction and the reflected Sun are simulated.|"
|
||||||
|
"Level 2:Waving water is simulated as well as reflection and refraction.|"
|
||||||
|
"Level 3:Reflections and refractions are rendered at the highest quality using screen-space techniques.")));
|
||||||
|
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "Low"), "0"));
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "Med"), "1"));
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "High"), "2"));
|
||||||
|
cplx.AddPreset(StartupScreenComplexConfigPreset(_Tr("StartupScreen", "Ultra"), "3"));
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigComplexItemEditor(ui, cplx,
|
||||||
|
_Tr("StartupScreen", "Shader Effects"), _Tr("StartupScreen", "Special effects.")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cfg.Finalize();
|
||||||
|
cfg.SetHelpTextHandler(HelpTextHandler(this.HandleHelpText));
|
||||||
|
cfg.Bounds = AABB2(0.f, 60.f, mainWidth, size.y - 60.f);
|
||||||
|
AddChild(cfg);
|
||||||
|
@configViewGL = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenConfigView cfg(Manager);
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigSelectItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "r_swUndersampling"), "0|1|2",
|
||||||
|
_Tr("StartupScreen",
|
||||||
|
"Fast Mode:Reduces the image resolution to make the rendering faster.|"
|
||||||
|
"Off|2x|4x")));
|
||||||
|
|
||||||
|
|
||||||
|
cfg.Finalize();
|
||||||
|
cfg.SetHelpTextHandler(HelpTextHandler(this.HandleHelpText));
|
||||||
|
cfg.Bounds = AABB2(0.f, 60.f, mainWidth, size.y - 60.f);
|
||||||
|
AddChild(cfg);
|
||||||
|
@configViewSoftware = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleHelpText(string text) {
|
||||||
|
helpView.Text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDriverOpenGL(spades::ui::UIElement@){ r_renderer.StringValue = "gl"; LoadConfig(); }
|
||||||
|
private void OnDriverSoftware(spades::ui::UIElement@){ r_renderer.StringValue = "sw"; LoadConfig(); }
|
||||||
|
|
||||||
|
private void OnFullscreenCheck(spades::ui::UIElement@)
|
||||||
|
{ r_fullscreen.IntValue = fullscreenCheck.Toggled ? 1 : 0; }
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
resEdit.LoadConfig();
|
||||||
|
if(r_renderer.StringValue == "sw") {
|
||||||
|
driverSoftware.Check();
|
||||||
|
configViewGL.Visible = false;
|
||||||
|
configViewSoftware.Visible = true;
|
||||||
|
}else{
|
||||||
|
driverOpenGL.Check();
|
||||||
|
configViewGL.Visible = true;
|
||||||
|
configViewSoftware.Visible = false;
|
||||||
|
}
|
||||||
|
fullscreenCheck.Toggled = r_fullscreen.IntValue != 0;
|
||||||
|
driverOpenGL.Enable = ui.helper.CheckConfigCapability("r_renderer", "gl").length == 0;
|
||||||
|
driverSoftware.Enable = ui.helper.CheckConfigCapability("r_renderer", "sw").length == 0;
|
||||||
|
configViewGL.LoadConfig();
|
||||||
|
configViewSoftware.LoadConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenComboBoxDropdownButton: spades::ui::SimpleButton {
|
||||||
|
StartupScreenComboBoxDropdownButton(spades::ui::UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
SimpleButton::Render();
|
||||||
|
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Image@ image = renderer.RegisterImage("Gfx/UI/ScrollArrow.png");
|
||||||
|
AABB2 bnd = ScreenBounds;
|
||||||
|
Vector2 p = (bnd.min + bnd.max) * 0.5f + Vector2(-8.f, 8.f);
|
||||||
|
renderer.DrawImage(image, AABB2(p.x, p.y, 16.f, -16.f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenGraphicsDisplayResolutionEditor: spades::ui::UIElement {
|
||||||
|
spades::ui::Field@ widthField;
|
||||||
|
spades::ui::Field@ heightField;
|
||||||
|
spades::ui::Button@ dropdownButton;
|
||||||
|
private ConfigItem r_videoWidth("r_videoWidth");
|
||||||
|
private ConfigItem r_videoHeight("r_videoHeight");
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
|
||||||
|
StartupScreenGraphicsDisplayResolutionEditor(StartupScreenUI@ ui) {
|
||||||
|
super(ui.manager);
|
||||||
|
@helper = ui.helper;
|
||||||
|
{
|
||||||
|
spades::ui::Field e(Manager);
|
||||||
|
AddChild(e);
|
||||||
|
e.Bounds = AABB2(0, 0, 45.f, 24.f);
|
||||||
|
e.DenyNonAscii = true;
|
||||||
|
@e.Changed = spades::ui::EventHandler(this.ValueEditHandler);
|
||||||
|
@widthField = e;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Field e(Manager);
|
||||||
|
AddChild(e);
|
||||||
|
e.Bounds = AABB2(53, 0, 45.f, 24.f);
|
||||||
|
e.DenyNonAscii = true;
|
||||||
|
@e.Changed = spades::ui::EventHandler(this.ValueEditHandler);
|
||||||
|
@heightField = e;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
StartupScreenComboBoxDropdownButton e(Manager);
|
||||||
|
AddChild(e);
|
||||||
|
e.Bounds = AABB2(100, 0, 24.f, 24.f);
|
||||||
|
@e.Activated = spades::ui::EventHandler(this.ShowDropdown);
|
||||||
|
@dropdownButton = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
widthField.Text = ToString(r_videoWidth.IntValue);
|
||||||
|
heightField.Text = ToString(r_videoHeight.IntValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveConfig() {
|
||||||
|
int w = ParseInt(widthField.Text);
|
||||||
|
int h = ParseInt(heightField.Text);
|
||||||
|
if(w < 640 or h < 480 or w > 8192 or h > 8192) return;
|
||||||
|
r_videoWidth.IntValue = w;
|
||||||
|
r_videoHeight.IntValue = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValueEditHandler(spades::ui::UIElement@) {
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DropdownHandler(int index) {
|
||||||
|
if(index >= 0) {
|
||||||
|
widthField.Text = ToString(helper.GetVideoModeWidth(index));
|
||||||
|
heightField.Text = ToString(helper.GetVideoModeHeight(index));
|
||||||
|
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowDropdown(spades::ui::UIElement@) {
|
||||||
|
string[] items = {};
|
||||||
|
int cnt = helper.GetNumVideoModes();
|
||||||
|
for(int i = 0; i < cnt; i++) {
|
||||||
|
int w = helper.GetVideoModeWidth(i);
|
||||||
|
int h = helper.GetVideoModeHeight(i);
|
||||||
|
string s = ToString(w) + "x" + ToString(h);
|
||||||
|
items.insertLast(s);
|
||||||
|
}
|
||||||
|
spades::ui::ShowDropDownList(this, items, spades::ui::DropDownListHandler(this.DropdownHandler));
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Font@ font = this.Font;
|
||||||
|
font.Draw("x", Vector2(45.f, 0.f) + ScreenPosition, 1.f, Vector4(1.f, 1.f, 1.f, 1.f));
|
||||||
|
UIElement::Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenGraphicsAntialiasConfig: StartupScreenGenericConfig {
|
||||||
|
private StartupScreenUI@ ui;
|
||||||
|
private ConfigItem@ msaaConfig;
|
||||||
|
private ConfigItem@ fxaaConfig;
|
||||||
|
StartupScreenGraphicsAntialiasConfig(StartupScreenUI@ ui) {
|
||||||
|
@this.ui = ui;
|
||||||
|
@msaaConfig = ConfigItem("r_multisamples");
|
||||||
|
@fxaaConfig = ConfigItem("r_fxaa");
|
||||||
|
}
|
||||||
|
string GetValue() {
|
||||||
|
if(fxaaConfig.IntValue != 0) {
|
||||||
|
return "fxaa";
|
||||||
|
}else{
|
||||||
|
int v = msaaConfig.IntValue;
|
||||||
|
if(v < 2) return "0";
|
||||||
|
else return msaaConfig.StringValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SetValue(string v) {
|
||||||
|
if(v == "fxaa") {
|
||||||
|
msaaConfig.StringValue = "0";
|
||||||
|
fxaaConfig.StringValue = "1";
|
||||||
|
} else if (v == "0" || v == "1") {
|
||||||
|
msaaConfig.StringValue = "0";
|
||||||
|
fxaaConfig.StringValue = "0";
|
||||||
|
} else {
|
||||||
|
msaaConfig.StringValue = v;
|
||||||
|
fxaaConfig.StringValue = "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string CheckValueCapability(string v) {
|
||||||
|
if(v == "fxaa") {
|
||||||
|
return ui.helper.CheckConfigCapability("r_multisamples", "0") +
|
||||||
|
ui.helper.CheckConfigCapability("r_fxaa", "1");
|
||||||
|
} else if (v == "0" || v == "1") {
|
||||||
|
return ui.helper.CheckConfigCapability("r_multisamples", "0") +
|
||||||
|
ui.helper.CheckConfigCapability("r_fxaa", "0");
|
||||||
|
} else {
|
||||||
|
return ui.helper.CheckConfigCapability("r_multisamples", v) +
|
||||||
|
ui.helper.CheckConfigCapability("r_fxaa", "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class StartupScreenAudioTab: spades::ui::UIElement, LabelAddable {
|
||||||
|
StartupScreenUI@ ui;
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
|
||||||
|
spades::ui::RadioButton@ driverOpenAL;
|
||||||
|
spades::ui::RadioButton@ driverYSR;
|
||||||
|
spades::ui::RadioButton@ driverNull;
|
||||||
|
|
||||||
|
spades::ui::TextViewer@ helpView;
|
||||||
|
StartupScreenConfigView@ configViewOpenAL;
|
||||||
|
StartupScreenConfigView@ configViewYSR;
|
||||||
|
|
||||||
|
private ConfigItem s_audioDriver("s_audioDriver");
|
||||||
|
private ConfigItem s_eax("s_eax");
|
||||||
|
|
||||||
|
StartupScreenAudioTab(StartupScreenUI@ ui, Vector2 size) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@helper = ui.helper;
|
||||||
|
|
||||||
|
float mainWidth = size.x - 250.f;
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::TextViewer e(Manager);
|
||||||
|
e.Bounds = AABB2(mainWidth + 10.f, 0.f, size.x - mainWidth - 10.f, size.y);
|
||||||
|
@e.Font = ui.fontManager.GuiFont;
|
||||||
|
e.Text = _Tr("StartupScreen", "Audio Settings");
|
||||||
|
AddChild(e);
|
||||||
|
@helpView = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddLabel(0.f, 0.f, 24.f, _Tr("StartupScreen", "Backend"));
|
||||||
|
{
|
||||||
|
spades::ui::RadioButton e(Manager);
|
||||||
|
e.Caption = _Tr("StartupScreen", "OpenAL");
|
||||||
|
e.Bounds = AABB2(100.f, 0.f, 100.f, 24.f);
|
||||||
|
e.GroupName = "driver";
|
||||||
|
HelpHandler(helpView,
|
||||||
|
_Tr("StartupScreen", "Uses an OpenAL-capable sound card to process sound. "
|
||||||
|
"In most cases where there isn't such a sound card, software emulation is "
|
||||||
|
"used.")).Watch(e);
|
||||||
|
@e.Activated = spades::ui::EventHandler(this.OnDriverOpenAL);
|
||||||
|
AddChild(e);
|
||||||
|
@driverOpenAL = e;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::RadioButton e(Manager);
|
||||||
|
e.Caption = _Tr("StartupScreen", "YSR");
|
||||||
|
e.Bounds = AABB2(210.f, 0.f, 100.f, 24.f);
|
||||||
|
e.GroupName = "driver";
|
||||||
|
HelpHandler(helpView,
|
||||||
|
_Tr("StartupScreen", "YSR is an experimental 3D HDR sound engine optimized "
|
||||||
|
"for OpenSpades. It features several enhanced features including "
|
||||||
|
"automatic load control, dynamics compressor, HRTF-based "
|
||||||
|
"3D audio, and high quality reverb.")).Watch(e);
|
||||||
|
@e.Activated = spades::ui::EventHandler(this.OnDriverYSR);
|
||||||
|
AddChild(e);
|
||||||
|
@driverYSR = e;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::RadioButton e(Manager);
|
||||||
|
//! The name of audio driver that outputs no audio.
|
||||||
|
e.Caption = _Tr("StartupScreen", "Null");
|
||||||
|
e.Bounds = AABB2(320.f, 0.f, 100.f, 24.f);
|
||||||
|
e.GroupName = "driver";
|
||||||
|
HelpHandler(helpView,
|
||||||
|
_Tr("StartupScreen", "Disables audio output.")).Watch(e);
|
||||||
|
@e.Activated = spades::ui::EventHandler(this.OnDriverNull);
|
||||||
|
AddChild(e);
|
||||||
|
@driverNull = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenConfigView cfg(Manager);
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigSliderItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "s_maxPolyphonics"), 16.0, 256.0, 8.0,
|
||||||
|
_Tr("StartupScreen", "Polyphonics"), _Tr("StartupScreen",
|
||||||
|
"Specifies how many sounds can be played simultaneously. "
|
||||||
|
"Higher value needs more processing power, so setting this too high might "
|
||||||
|
"cause an overload (especially with a software emulation)."),
|
||||||
|
ConfigNumberFormatter(0, " poly")));
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigCheckItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "s_eax"), "0", "1",
|
||||||
|
_Tr("StartupScreen", "EAX"), _Tr("StartupScreen",
|
||||||
|
"Enables extended features provided by the OpenAL driver to create "
|
||||||
|
"more ambience.")));
|
||||||
|
|
||||||
|
cfg.Finalize();
|
||||||
|
cfg.SetHelpTextHandler(HelpTextHandler(this.HandleHelpText));
|
||||||
|
cfg.Bounds = AABB2(0.f, 30.f, mainWidth, size.y - 30.f);
|
||||||
|
AddChild(cfg);
|
||||||
|
@configViewOpenAL = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenConfigView cfg(Manager);
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigSliderItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, "s_maxPolyphonics"), 16.0, 256.0, 8.0,
|
||||||
|
_Tr("StartupScreen", "Polyphonics"), _Tr("StartupScreen",
|
||||||
|
"Specifies how many sounds can be played simultaneously. "
|
||||||
|
"No matter what value is set, YSR might reduce the number of sounds "
|
||||||
|
"when an overload is detected."),
|
||||||
|
ConfigNumberFormatter(0, " poly")));
|
||||||
|
|
||||||
|
|
||||||
|
cfg.Finalize();
|
||||||
|
cfg.SetHelpTextHandler(HelpTextHandler(this.HandleHelpText));
|
||||||
|
cfg.Bounds = AABB2(0.f, 30.f, mainWidth, size.y - 30.f);
|
||||||
|
AddChild(cfg);
|
||||||
|
@configViewYSR = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleHelpText(string text) {
|
||||||
|
helpView.Text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDriverOpenAL(spades::ui::UIElement@){ s_audioDriver.StringValue = "openal"; LoadConfig(); }
|
||||||
|
private void OnDriverYSR(spades::ui::UIElement@){ s_audioDriver.StringValue = "ysr"; LoadConfig(); }
|
||||||
|
private void OnDriverNull(spades::ui::UIElement@){ s_audioDriver.StringValue = "null"; LoadConfig(); }
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
if(s_audioDriver.StringValue == "ysr") {
|
||||||
|
driverYSR.Check();
|
||||||
|
configViewOpenAL.Visible = false;
|
||||||
|
configViewYSR.Visible = true;
|
||||||
|
}else if(s_audioDriver.StringValue == "openal"){
|
||||||
|
driverOpenAL.Check();
|
||||||
|
configViewOpenAL.Visible = true;
|
||||||
|
configViewYSR.Visible = false;
|
||||||
|
}else if(s_audioDriver.StringValue == "null"){
|
||||||
|
driverNull.Check();
|
||||||
|
configViewOpenAL.Visible = false;
|
||||||
|
configViewYSR.Visible = false;
|
||||||
|
}
|
||||||
|
driverOpenAL.Enable = ui.helper.CheckConfigCapability("s_audioDriver", "openal").length == 0;
|
||||||
|
driverYSR.Enable = ui.helper.CheckConfigCapability("s_audioDriver", "ysr").length == 0;
|
||||||
|
driverNull.Enable = ui.helper.CheckConfigCapability("s_audioDriver", "null").length == 0;
|
||||||
|
configViewOpenAL.LoadConfig();
|
||||||
|
configViewYSR.LoadConfig();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenGenericTab: spades::ui::UIElement, LabelAddable {
|
||||||
|
StartupScreenUI@ ui;
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
|
||||||
|
StartupScreenLocaleEditor@ locale;
|
||||||
|
|
||||||
|
StartupScreenGenericTab(StartupScreenUI@ ui, Vector2 size) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@helper = ui.helper;
|
||||||
|
|
||||||
|
string label = _Tr("StartupScreen", "Language");
|
||||||
|
if (label != "Language") {
|
||||||
|
label += " (Language)";
|
||||||
|
}
|
||||||
|
AddLabel(0.f, 0.f, 24.f, _Tr("StartupScreen", label));
|
||||||
|
{
|
||||||
|
StartupScreenLocaleEditor e(ui);
|
||||||
|
AddChild(e);
|
||||||
|
e.Bounds = AABB2(160.f, 0.f, 400.f, 24.f);
|
||||||
|
@locale = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLabel(0.f, 30.f, 30.f, _Tr("StartupScreen", "Tools"));
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("StartupScreen", "Reset All Settings");
|
||||||
|
button.Bounds = AABB2(160.f, 30.f, 350.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnResetSettingsPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
string osType = helper.OperatingSystemType;
|
||||||
|
if (osType == "Windows") {
|
||||||
|
button.Caption = _Tr("StartupScreen", "Open Config Folder in Explorer");
|
||||||
|
} else if (osType == "Mac") {
|
||||||
|
button.Caption = _Tr("StartupScreen", "Reveal Config Folder in Finder");
|
||||||
|
} else {
|
||||||
|
button.Caption = _Tr("StartupScreen", "Browse Config Folder");
|
||||||
|
}
|
||||||
|
button.Bounds = AABB2(160.f, 66.f, 350.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnBrowseUserDirectoryPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
locale.LoadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBrowseUserDirectoryPressed(spades::ui::UIElement@) {
|
||||||
|
if (helper.BrowseUserDirectory()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string msg = _Tr("StartupScreen", "An unknown error has occurred while opening the config directory.");
|
||||||
|
AlertScreen al(Parent, msg, 100.f);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnResetSettingsPressed(spades::ui::UIElement@) {
|
||||||
|
string msg = _Tr("StartupScreen", "Are you sure to reset all settings? They include (but are not limited to):") + "\n" +
|
||||||
|
"- " + _Tr("StartupScreen", "All graphics/audio settings") + "\n" +
|
||||||
|
"- " + _Tr("StartupScreen", "All key bindings") + "\n" +
|
||||||
|
"- " + _Tr("StartupScreen", "Your player name") + "\n" +
|
||||||
|
"- " + _Tr("StartupScreen", "Other advanced settings only accessible through '{0}' tab and in-game commands",
|
||||||
|
_Tr("StartupScreen", "Advanced"));
|
||||||
|
ConfirmScreen al(Parent, msg, 200.f);
|
||||||
|
@al.Closed = spades::ui::EventHandler(OnResetSettingsConfirmed);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnResetSettingsConfirmed(spades::ui::UIElement@ sender) {
|
||||||
|
if (!cast<ConfirmScreen>(sender).Result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetAllSettings();
|
||||||
|
|
||||||
|
// Reload the startup screen so the language config takes effect
|
||||||
|
ui.Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetAllSettings() {
|
||||||
|
string[]@ names = GetAllConfigNames();
|
||||||
|
|
||||||
|
for(uint i = 0, count = names.length; i < count; i++) {
|
||||||
|
ConfigItem item(names[i]);
|
||||||
|
item.StringValue = item.DefaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some of default values may be infeasible for the user's system.
|
||||||
|
helper.FixConfigs();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenDropdownListDropdownButton: spades::ui::SimpleButton {
|
||||||
|
StartupScreenDropdownListDropdownButton(spades::ui::UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
Alignment = Vector2(0.f, 0.5f);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
SimpleButton::Render();
|
||||||
|
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Image@ arrowImg = renderer.RegisterImage("Gfx/UI/ScrollArrow.png");
|
||||||
|
|
||||||
|
AABB2 bnd = ScreenBounds;
|
||||||
|
Vector2 p = (bnd.min + bnd.max) * 0.5f + Vector2(-8.f, 8.f);
|
||||||
|
renderer.DrawImage(arrowImg, AABB2(bnd.max.x - 16.f, p.y, 16.f, -16.f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenLocaleEditor: spades::ui::UIElement, LabelAddable {StartupScreenUI@ ui;
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
private ConfigItem core_locale("core_locale");
|
||||||
|
|
||||||
|
spades::ui::Button@ dropdownButton;
|
||||||
|
|
||||||
|
StartupScreenLocaleEditor(StartupScreenUI@ ui) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@helper = ui.helper;
|
||||||
|
{
|
||||||
|
StartupScreenDropdownListDropdownButton e(Manager);
|
||||||
|
AddChild(e);
|
||||||
|
e.Bounds = AABB2(0.f, 0.f, 400.f, 24.f);
|
||||||
|
@e.Activated = spades::ui::EventHandler(this.ShowDropdown);
|
||||||
|
@dropdownButton = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
string locale = core_locale.StringValue;
|
||||||
|
string name = _Tr("StartupScreen", "Unknown ({0})", locale);
|
||||||
|
if (locale == "") {
|
||||||
|
name = _Tr("StartupScreen", "System default");
|
||||||
|
}
|
||||||
|
|
||||||
|
int cnt = helper.GetNumLocales();
|
||||||
|
for(int i = 0; i < cnt; i++) {
|
||||||
|
if (locale == helper.GetLocale(i)) {
|
||||||
|
name = helper.GetLocaleDescriptionNative(i) + " / " + helper.GetLocaleDescriptionEnglish(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dropdownButton.Caption = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowDropdown(spades::ui::UIElement@) {
|
||||||
|
string[] items = {_Tr("StartupScreen", "System default")};
|
||||||
|
int cnt = helper.GetNumLocales();
|
||||||
|
for(int i = 0; i < cnt; i++) {
|
||||||
|
string s = helper.GetLocaleDescriptionNative(i) + " / " + helper.GetLocaleDescriptionEnglish(i);
|
||||||
|
items.insertLast(s);
|
||||||
|
}
|
||||||
|
spades::ui::ShowDropDownList(this, items, spades::ui::DropDownListHandler(this.DropdownHandler));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DropdownHandler(int index) {
|
||||||
|
if(index >= 0) {
|
||||||
|
if (index == 0) {
|
||||||
|
core_locale = "";
|
||||||
|
} else {
|
||||||
|
core_locale = helper.GetLocale(index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload the startup screen so the language config takes effect
|
||||||
|
ui.Reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenSystemInfoTab: spades::ui::UIElement, LabelAddable {
|
||||||
|
StartupScreenUI@ ui;
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
|
||||||
|
spades::ui::TextViewer@ helpView;
|
||||||
|
|
||||||
|
StartupScreenSystemInfoTab(StartupScreenUI@ ui, Vector2 size) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@helper = ui.helper;
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::TextViewer e(Manager);
|
||||||
|
e.Bounds = AABB2(0.f, 0.f, size.x, size.y - 30.f);
|
||||||
|
@e.Font = ui.fontManager.GuiFont;
|
||||||
|
AddChild(e);
|
||||||
|
for(int i = 0, count = helper.GetNumReportLines(); i < count; i++) {
|
||||||
|
string text = helper.GetReportLineText(i);
|
||||||
|
Vector4 col = helper.GetReportLineColor(i);
|
||||||
|
e.AddLine(text, true, col);
|
||||||
|
}
|
||||||
|
@helpView = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("StartupScreen", "Copy to Clipboard");
|
||||||
|
button.Bounds = AABB2(size.x - 180.f, size.y - 30.f, 180.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnCopyReport);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private void OnCopyReport(spades::ui::UIElement@){
|
||||||
|
Manager.Copy(helper.GetReport());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class StartupScreenAdvancedTab: spades::ui::UIElement, LabelAddable {
|
||||||
|
StartupScreenUI@ ui;
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
|
||||||
|
spades::ui::Field@ filter;
|
||||||
|
|
||||||
|
spades::ui::TextViewer@ helpView;
|
||||||
|
StartupScreenConfigView@ configView;
|
||||||
|
|
||||||
|
StartupScreenAdvancedTab(StartupScreenUI@ ui, Vector2 size) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@helper = ui.helper;
|
||||||
|
|
||||||
|
float mainWidth = size.x - 250.f;
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::TextViewer e(Manager);
|
||||||
|
e.Bounds = AABB2(mainWidth + 10.f, 0.f, size.x - mainWidth - 10.f, size.y);
|
||||||
|
@e.Font = ui.fontManager.GuiFont;
|
||||||
|
e.Text = _Tr("StartupScreen", "Advanced Settings");
|
||||||
|
e.Visible = false;
|
||||||
|
AddChild(e);
|
||||||
|
@helpView = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::Field e(Manager);
|
||||||
|
e.Placeholder = _Tr("StartupScreen", "Filter");
|
||||||
|
e.Bounds = AABB2(0.f, 0.f, size.x, 24.f);
|
||||||
|
@e.Changed = spades::ui::EventHandler(this.OnFilterChanged);
|
||||||
|
AddChild(e);
|
||||||
|
@filter = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
StartupScreenConfigView cfg(Manager);
|
||||||
|
|
||||||
|
string[]@ names = GetAllConfigNames();
|
||||||
|
|
||||||
|
for(uint i = 0, count = names.length; i < count; i++) {
|
||||||
|
|
||||||
|
cfg.AddRow(StartupScreenConfigFieldItemEditor(ui,
|
||||||
|
StartupScreenConfig(ui, names[i]), names[i], ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Finalize();
|
||||||
|
cfg.SetHelpTextHandler(HelpTextHandler(this.HandleHelpText));
|
||||||
|
cfg.Bounds = AABB2(0.f, 30.f, size.x, size.y - 30.f);
|
||||||
|
AddChild(cfg);
|
||||||
|
@configView = cfg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleHelpText(string text) {
|
||||||
|
helpView.Text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFilterChanged(spades::ui::UIElement@){
|
||||||
|
configView.Filter(filter.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
configView.LoadConfig();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
226
Resources/Scripts/Gui/StartupScreen/MainMenu.as
Normal file
226
Resources/Scripts/Gui/StartupScreen/MainMenu.as
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UpdateCheckView.as"
|
||||||
|
#include "ConfigViewTabs.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
class StartupScreenMainMenuState {
|
||||||
|
int ActiveTabIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartupScreenMainMenu: spades::ui::UIElement {
|
||||||
|
|
||||||
|
StartupScreenUI@ ui;
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
|
||||||
|
spades::ui::ListView@ serverList;
|
||||||
|
spades::ui::CheckBox@ bypassStartupWindowCheck;
|
||||||
|
|
||||||
|
StartupScreenGraphicsTab@ graphicsTab;
|
||||||
|
StartupScreenAudioTab@ audioTab;
|
||||||
|
StartupScreenGenericTab@ genericTab;
|
||||||
|
StartupScreenSystemInfoTab@ systemInfoTab;
|
||||||
|
StartupScreenAdvancedTab@ advancedTab;
|
||||||
|
|
||||||
|
private ConfigItem cl_showStartupWindow("cl_showStartupWindow", "-1");
|
||||||
|
private bool advancedTabVisible = false;
|
||||||
|
|
||||||
|
StartupScreenMainMenu(StartupScreenUI@ ui) {
|
||||||
|
super(ui.manager);
|
||||||
|
@this.ui = ui;
|
||||||
|
@this.helper = ui.helper;
|
||||||
|
|
||||||
|
@this.Font = ui.fontManager.GuiFont;
|
||||||
|
|
||||||
|
float width = Manager.Renderer.ScreenWidth;
|
||||||
|
float height = Manager.Renderer.ScreenHeight;
|
||||||
|
{
|
||||||
|
spades::ui::Button button(Manager);
|
||||||
|
button.Caption = _Tr("StartupScreen", "Start");
|
||||||
|
button.Bounds = AABB2(width - 170.f, 20.f, 150.f, 30.f);
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnStartPressed);
|
||||||
|
AddChild(button);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
spades::ui::CheckBox button(Manager);
|
||||||
|
button.Caption = _Tr("StartupScreen", "Skip this screen next time");
|
||||||
|
button.Bounds = AABB2(360.f, 62.f, width - 380.f, 20.f); // note: this is updated later soon
|
||||||
|
AddChild(button);
|
||||||
|
@bypassStartupWindowCheck = button;
|
||||||
|
@button.Activated = spades::ui::EventHandler(this.OnBypassStartupWindowCheckChanged);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
UpdateCheckView view(Manager, ui.helper.PackageUpdateManager);
|
||||||
|
view.Bounds = AABB2(0.f, height - 40.f, width, 40.f);
|
||||||
|
@view.OpenUpdateInfoURL = spades::ui::EventHandler(this.OnShowUpdateDetailsPressed);
|
||||||
|
AddChild(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB2 clientArea(10.f, 100.f, width - 20.f, height - 150.f);
|
||||||
|
StartupScreenGraphicsTab graphicsTab(ui, clientArea.max - clientArea.min);
|
||||||
|
StartupScreenAudioTab audioTab(ui, clientArea.max - clientArea.min);
|
||||||
|
StartupScreenGenericTab genericTab(ui, clientArea.max - clientArea.min);
|
||||||
|
StartupScreenSystemInfoTab profileTab(ui, clientArea.max - clientArea.min);
|
||||||
|
StartupScreenAdvancedTab advancedTab(ui, clientArea.max - clientArea.min);
|
||||||
|
graphicsTab.Bounds = clientArea;
|
||||||
|
audioTab.Bounds = clientArea;
|
||||||
|
genericTab.Bounds = clientArea;
|
||||||
|
profileTab.Bounds = clientArea;
|
||||||
|
advancedTab.Bounds = clientArea;
|
||||||
|
AddChild(graphicsTab);
|
||||||
|
AddChild(audioTab);
|
||||||
|
AddChild(genericTab);
|
||||||
|
AddChild(profileTab);
|
||||||
|
AddChild(advancedTab);
|
||||||
|
audioTab.Visible = false;
|
||||||
|
profileTab.Visible = false;
|
||||||
|
genericTab.Visible = false;
|
||||||
|
advancedTab.Visible = false;
|
||||||
|
|
||||||
|
@this.graphicsTab = graphicsTab;
|
||||||
|
@this.audioTab = audioTab;
|
||||||
|
@this.advancedTab = advancedTab;
|
||||||
|
@this.systemInfoTab = profileTab;
|
||||||
|
@this.genericTab = genericTab;
|
||||||
|
|
||||||
|
{
|
||||||
|
spades::ui::SimpleTabStrip tabStrip(Manager);
|
||||||
|
AddChild(tabStrip);
|
||||||
|
tabStrip.Bounds = AABB2(10.f, 70.f, width - 20.f, 24.f);
|
||||||
|
tabStrip.AddItem(_Tr("StartupScreen", "Graphics"), graphicsTab);
|
||||||
|
tabStrip.AddItem(_Tr("StartupScreen", "Audio"), audioTab);
|
||||||
|
tabStrip.AddItem(_Tr("StartupScreen", "Generic"), genericTab);
|
||||||
|
tabStrip.AddItem(_Tr("StartupScreen", "System Info"), profileTab);
|
||||||
|
tabStrip.AddItem(_Tr("StartupScreen", "Advanced"), advancedTab);
|
||||||
|
@tabStrip.Changed = spades::ui::EventHandler(this.OnTabChanged);
|
||||||
|
|
||||||
|
// Reposition the "Skip this screen next time" check box
|
||||||
|
spades::ui::UIElement@[]@ tabStripItems = tabStrip.GetChildren();
|
||||||
|
float right = tabStripItems[tabStripItems.length - 1].Bounds.max.x +
|
||||||
|
tabStrip.Bounds.min.x + 10.f;
|
||||||
|
bypassStartupWindowCheck.Bounds = AABB2(right, 62.f, width - right - 20.f, 20.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTabChanged(spades::ui::UIElement@) {
|
||||||
|
bool v = advancedTab.Visible;
|
||||||
|
if(advancedTabVisible and not v) {
|
||||||
|
LoadConfig();
|
||||||
|
}
|
||||||
|
advancedTabVisible = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadConfig() {
|
||||||
|
switch(cl_showStartupWindow.IntValue) {
|
||||||
|
case -1:
|
||||||
|
bypassStartupWindowCheck.Toggled = false;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
bypassStartupWindowCheck.Toggled = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bypassStartupWindowCheck.Toggled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.graphicsTab.LoadConfig();
|
||||||
|
this.audioTab.LoadConfig();
|
||||||
|
this.genericTab.LoadConfig();
|
||||||
|
this.advancedTab.LoadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
StartupScreenMainMenuState@ GetState() {
|
||||||
|
StartupScreenMainMenuState state;
|
||||||
|
if (this.graphicsTab.Visible) {
|
||||||
|
state.ActiveTabIndex = 0;
|
||||||
|
} else if (this.audioTab.Visible) {
|
||||||
|
state.ActiveTabIndex = 1;
|
||||||
|
} else if (this.genericTab.Visible) {
|
||||||
|
state.ActiveTabIndex = 2;
|
||||||
|
} else if (this.systemInfoTab.Visible) {
|
||||||
|
state.ActiveTabIndex = 3;
|
||||||
|
} else if (this.advancedTab.Visible) {
|
||||||
|
state.ActiveTabIndex = 4;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetState(StartupScreenMainMenuState@ state) {
|
||||||
|
this.graphicsTab.Visible = state.ActiveTabIndex == 0;
|
||||||
|
this.audioTab.Visible = state.ActiveTabIndex == 1;
|
||||||
|
this.genericTab.Visible = state.ActiveTabIndex == 2;
|
||||||
|
this.systemInfoTab.Visible = state.ActiveTabIndex == 3;
|
||||||
|
this.advancedTab.Visible = state.ActiveTabIndex == 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBypassStartupWindowCheckChanged(spades::ui::UIElement@ sender) {
|
||||||
|
cl_showStartupWindow.IntValue = (bypassStartupWindowCheck.Toggled ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnShowUpdateDetailsPressed(spades::ui::UIElement@ sender) {
|
||||||
|
if (ui.helper.OpenUpdateInfoURL()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string msg = _Tr("StartupScreen", "An unknown error has occurred while opening the update info website.");
|
||||||
|
msg += "\n\n" + ui.helper.PackageUpdateManager.LatestVersionInfoPageURL;
|
||||||
|
AlertScreen al(Parent, msg, 100.f);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnQuitPressed(spades::ui::UIElement@ sender) {
|
||||||
|
ui.shouldExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSetupPressed(spades::ui::UIElement@ sender) {
|
||||||
|
PreferenceView al(this, PreferenceViewOptions(), ui.fontManager);
|
||||||
|
al.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Start() {
|
||||||
|
helper.Start();
|
||||||
|
ui.shouldExit = true; // we have to exit from the startup screen to start the game
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStartPressed(spades::ui::UIElement@ sender) {
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotKey(string key) {
|
||||||
|
if(IsEnabled and key == "Enter") {
|
||||||
|
Start();
|
||||||
|
} else if(IsEnabled and key == "Escape") {
|
||||||
|
ui.shouldExit = true;
|
||||||
|
} else {
|
||||||
|
UIElement::HotKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
UIElement::Render();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
131
Resources/Scripts/Gui/StartupScreen/StartupScreenUI.as
Normal file
131
Resources/Scripts/Gui/StartupScreen/StartupScreenUI.as
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MainMenu.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
|
||||||
|
|
||||||
|
class StartupScreenUI {
|
||||||
|
private Renderer@ renderer;
|
||||||
|
private AudioDevice@ audioDevice;
|
||||||
|
FontManager@ fontManager;
|
||||||
|
StartupScreenHelper@ helper;
|
||||||
|
|
||||||
|
spades::ui::UIManager@ manager;
|
||||||
|
|
||||||
|
StartupScreenMainMenu@ mainMenu;
|
||||||
|
|
||||||
|
bool shouldExit = false;
|
||||||
|
|
||||||
|
StartupScreenUI(Renderer@ renderer, AudioDevice@ audioDevice, FontManager@ fontManager, StartupScreenHelper@ helper) {
|
||||||
|
@this.renderer = renderer;
|
||||||
|
@this.audioDevice = audioDevice;
|
||||||
|
@this.fontManager = fontManager;
|
||||||
|
@this.helper = helper;
|
||||||
|
|
||||||
|
SetupRenderer();
|
||||||
|
|
||||||
|
@manager = spades::ui::UIManager(renderer, audioDevice);
|
||||||
|
@manager.RootElement.Font = fontManager.GuiFont;
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init() {
|
||||||
|
@mainMenu = StartupScreenMainMenu(this);
|
||||||
|
mainMenu.Bounds = manager.RootElement.Bounds;
|
||||||
|
manager.RootElement.AddChild(mainMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reload() {
|
||||||
|
// Delete StartupScreenMainMenu
|
||||||
|
@manager.RootElement.GetChildren()[0].Parent = null;
|
||||||
|
|
||||||
|
// Reload entire the startup screen while preserving the state as much as possible
|
||||||
|
auto@ state = mainMenu.GetState();
|
||||||
|
Init();
|
||||||
|
mainMenu.SetState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupRenderer() {
|
||||||
|
if(manager !is null)
|
||||||
|
manager.KeyPanic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseEvent(float x, float y) {
|
||||||
|
manager.MouseEvent(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WheelEvent(float x, float y) {
|
||||||
|
manager.WheelEvent(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyEvent(string key, bool down) {
|
||||||
|
manager.KeyEvent(key, down);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputEvent(string text) {
|
||||||
|
manager.TextInputEvent(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextEditingEvent(string text, int start, int len) {
|
||||||
|
manager.TextEditingEvent(text, start, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AcceptsTextInput() {
|
||||||
|
return manager.AcceptsTextInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB2 GetTextInputRect() {
|
||||||
|
return manager.TextInputRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunFrame(float dt) {
|
||||||
|
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, 1.f);
|
||||||
|
renderer.DrawImage(renderer.RegisterImage("Gfx/White.tga"),
|
||||||
|
AABB2(0.f, 0.f, renderer.ScreenWidth, renderer.ScreenHeight));
|
||||||
|
|
||||||
|
// draw title logo
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/Title/LogoSmall.png");
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 1.f);
|
||||||
|
renderer.DrawImage(img, AABB2(10.f, 10.f, img.Width, img.Height));
|
||||||
|
|
||||||
|
manager.RunFrame(dt);
|
||||||
|
manager.Render();
|
||||||
|
|
||||||
|
renderer.FrameDone();
|
||||||
|
renderer.Flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Closing() {
|
||||||
|
shouldExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WantsToBeClosed() {
|
||||||
|
return shouldExit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StartupScreenUI@ CreateStartupScreenUI(Renderer@ renderer, AudioDevice@ audioDevice,
|
||||||
|
FontManager@ fontManager, StartupScreenHelper@ helper) {
|
||||||
|
return StartupScreenUI(renderer, audioDevice, fontManager, helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "UIControls.as"
|
#include "../UIFramework/UIControls.as"
|
||||||
|
|
||||||
namespace spades {
|
namespace spades {
|
||||||
class UpdateCheckView: spades::ui::UIElement {
|
class UpdateCheckView: spades::ui::UIElement {
|
||||||
@ -150,4 +150,4 @@ namespace spades {
|
|||||||
OpenUpdateInfoURL(this);
|
OpenUpdateInfoURL(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
368
Resources/Scripts/Gui/UIFramework/Button.as
Normal file
368
Resources/Scripts/Gui/UIFramework/Button.as
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UIFramework.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class ButtonBase: UIElement {
|
||||||
|
bool Pressed = false;
|
||||||
|
bool Hover = false;
|
||||||
|
bool Toggled = false;
|
||||||
|
|
||||||
|
bool Toggle = false;
|
||||||
|
bool Repeat = false;
|
||||||
|
bool ActivateOnMouseDown = false;
|
||||||
|
|
||||||
|
EventHandler@ Activated;
|
||||||
|
EventHandler@ DoubleClicked;
|
||||||
|
EventHandler@ RightClicked;
|
||||||
|
string Caption;
|
||||||
|
string ActivateHotKey;
|
||||||
|
|
||||||
|
private Timer@ repeatTimer;
|
||||||
|
|
||||||
|
// for double click detection
|
||||||
|
private float lastActivate = -1.f;
|
||||||
|
private Vector2 lastActivatePosition = Vector2();
|
||||||
|
|
||||||
|
ButtonBase(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
IsMouseInteractive = true;
|
||||||
|
@repeatTimer = Timer(Manager);
|
||||||
|
@repeatTimer.Tick = TimerTickEventHandler(this.RepeatTimerFired);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayMouseEnterSound() {
|
||||||
|
Manager.PlaySound("Sounds/Feedback/Limbo/Hover.opus");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayActivateSound() {
|
||||||
|
Manager.PlaySound("Sounds/Feedback/Limbo/Select.opus");
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnActivated() {
|
||||||
|
if(Activated !is null) {
|
||||||
|
Activated(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDoubleClicked() {
|
||||||
|
if(DoubleClicked !is null) {
|
||||||
|
DoubleClicked(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnRightClicked() {
|
||||||
|
if(RightClicked !is null) {
|
||||||
|
RightClicked(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RepeatTimerFired(Timer@ timer) {
|
||||||
|
OnActivated();
|
||||||
|
timer.Interval = 0.1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseDown(MouseButton button, Vector2 clientPosition) {
|
||||||
|
if(button != spades::ui::MouseButton::LeftMouseButton &&
|
||||||
|
button != spades::ui::MouseButton::RightMouseButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayActivateSound();
|
||||||
|
if (button == spades::ui::MouseButton::RightMouseButton) {
|
||||||
|
OnRightClicked();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pressed = true;
|
||||||
|
Hover = true;
|
||||||
|
|
||||||
|
if(Repeat or ActivateOnMouseDown) {
|
||||||
|
OnActivated();
|
||||||
|
if(Repeat) {
|
||||||
|
repeatTimer.Interval = 0.3f;
|
||||||
|
repeatTimer.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MouseMove(Vector2 clientPosition) {
|
||||||
|
if(Pressed) {
|
||||||
|
bool newHover = AABB2(Vector2(0.f, 0.f), Size).Contains(clientPosition);
|
||||||
|
if(newHover != Hover) {
|
||||||
|
if(Repeat) {
|
||||||
|
if(newHover) {
|
||||||
|
OnActivated();
|
||||||
|
repeatTimer.Interval = 0.3f;
|
||||||
|
repeatTimer.Start();
|
||||||
|
} else {
|
||||||
|
repeatTimer.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Hover = newHover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MouseUp(MouseButton button, Vector2 clientPosition) {
|
||||||
|
if(button != spades::ui::MouseButton::LeftMouseButton &&
|
||||||
|
button != spades::ui::MouseButton::RightMouseButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(Pressed) {
|
||||||
|
Pressed = false;
|
||||||
|
if(Hover and not (Repeat or ActivateOnMouseDown)) {
|
||||||
|
if(Toggle) {
|
||||||
|
Toggled = not Toggled;
|
||||||
|
}
|
||||||
|
OnActivated();
|
||||||
|
if (Manager.Time < lastActivate + 0.35 &&
|
||||||
|
(clientPosition - lastActivatePosition).ManhattanLength < 10.0f) {
|
||||||
|
OnDoubleClicked();
|
||||||
|
}
|
||||||
|
lastActivate = Manager.Time;
|
||||||
|
lastActivatePosition = clientPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Repeat and Hover){
|
||||||
|
repeatTimer.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MouseEnter() {
|
||||||
|
Hover = true;
|
||||||
|
if(not Pressed) {
|
||||||
|
PlayMouseEnterSound();
|
||||||
|
}
|
||||||
|
UIElement::MouseEnter();
|
||||||
|
}
|
||||||
|
void MouseLeave() {
|
||||||
|
Hover = false;
|
||||||
|
UIElement::MouseLeave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyDown(string key) {
|
||||||
|
if(key == " ") {
|
||||||
|
OnActivated();
|
||||||
|
}
|
||||||
|
UIElement::KeyDown(key);
|
||||||
|
}
|
||||||
|
void KeyUp(string key) {
|
||||||
|
UIElement::KeyUp(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotKey(string key) {
|
||||||
|
if(key == ActivateHotKey) {
|
||||||
|
OnActivated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleButton: spades::ui::Button {
|
||||||
|
SimpleButton(spades::ui::UIManager@ manager){
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
if((Pressed && Hover) || Toggled) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.2f);
|
||||||
|
} else if(Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.12f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.07f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
if((Pressed && Hover) || Toggled) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.1f);
|
||||||
|
} else if(Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.07f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.03f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, 1.f, size.y));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, 1.f));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x+size.x-1.f, pos.y, 1.f, size.y));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y+size.y-1.f, size.x, 1.f));
|
||||||
|
Vector2 txtSize = Font.Measure(Caption);
|
||||||
|
float margin = 4.f;
|
||||||
|
Font.DrawShadow(Caption, pos + Vector2(margin, margin) +
|
||||||
|
(size - txtSize - Vector2(margin * 2.f, margin * 2.f)) * Alignment,
|
||||||
|
1.f, Vector4(1,1,1,1), Vector4(0,0,0,0.4f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CheckBox: spades::ui::Button {
|
||||||
|
CheckBox(spades::ui::UIManager@ manager){
|
||||||
|
super(manager);
|
||||||
|
this.Toggle = true;
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
if(Pressed && Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.2f);
|
||||||
|
} else if(Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.12f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.00f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
Vector2 txtSize = Font.Measure(Caption);
|
||||||
|
Font.DrawShadow(Caption, pos + (size - txtSize) * Vector2(0.f, 0.5f) + Vector2(16.f, 0.f),
|
||||||
|
1.f, Vector4(1,1,1,1), Vector4(0,0,0,0.2f));
|
||||||
|
|
||||||
|
@img = renderer.RegisterImage("Gfx/UI/CheckBox.png");
|
||||||
|
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, Toggled ? .9f : 0.6f);
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y + (size.y - 16.f) * 0.5f, 16.f, 16.f),
|
||||||
|
AABB2(Toggled ? 16.f : 0.f, 0.f, 16.f, 16.f));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RadioButton: spades::ui::Button {
|
||||||
|
string GroupName;
|
||||||
|
|
||||||
|
RadioButton(spades::ui::UIManager@ manager){
|
||||||
|
super(manager);
|
||||||
|
this.Toggle = true;
|
||||||
|
}
|
||||||
|
void Check() {
|
||||||
|
this.Toggled = true;
|
||||||
|
|
||||||
|
// uncheck others
|
||||||
|
if(GroupName.length > 0) {
|
||||||
|
UIElement@[]@ children = this.Parent.GetChildren();
|
||||||
|
for(uint i = 0, count = children.length; i < children.length; i++) {
|
||||||
|
RadioButton@ btn = cast<RadioButton>(children[i]);
|
||||||
|
if(btn is this) continue;
|
||||||
|
if(btn !is null) {
|
||||||
|
if(GroupName == btn.GroupName) {
|
||||||
|
btn.Toggled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void OnActivated() {
|
||||||
|
Check();
|
||||||
|
|
||||||
|
Button::OnActivated();
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
if(!this.Enable) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.07f);
|
||||||
|
} else if((Pressed && Hover) || Toggled) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.2f);
|
||||||
|
} else if(Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.12f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.07f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
if(!this.Enable) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.03f);
|
||||||
|
} if((Pressed && Hover) || Toggled) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.1f);
|
||||||
|
} else if(Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.07f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.03f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, 1.f, size.y));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, 1.f));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x+size.x-1.f, pos.y, 1.f, size.y));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y+size.y-1.f, size.x, 1.f));
|
||||||
|
Vector2 txtSize = Font.Measure(Caption);
|
||||||
|
Font.DrawShadow(Caption, pos + (size - txtSize) * 0.5f + Vector2(8.f, 0.f), 1.f,
|
||||||
|
Vector4(1,1,1,this.Enable ? 1.f : 0.4f), Vector4(0,0,0,0.4f));
|
||||||
|
|
||||||
|
if(Toggled) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.6f);
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x + 4.f, pos.y + (size.y - 8.f) * 0.5f, 8.f, 8.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Button: ButtonBase {
|
||||||
|
private Image@ image;
|
||||||
|
Vector2 Alignment = Vector2(0.5f, 0.5f);
|
||||||
|
|
||||||
|
Button(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
@image = renderer.RegisterImage("Gfx/UI/Button.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
|
||||||
|
Vector4 color = Vector4(0.2f, 0.2f, 0.2f, 0.5f);
|
||||||
|
if(Toggled or (Pressed and Hover)) {
|
||||||
|
color = Vector4(0.7f, 0.7f, 0.7f, 0.9f);
|
||||||
|
}else if(Hover) {
|
||||||
|
color = Vector4(0.4f, 0.4f, 0.4f, 0.7f);
|
||||||
|
}
|
||||||
|
if(!IsEnabled) {
|
||||||
|
color.w *= 0.5f;
|
||||||
|
}
|
||||||
|
renderer.ColorNP = color;
|
||||||
|
|
||||||
|
DrawSliceImage(renderer, image, pos.x, pos.y, size.x, size.y, 12.f);
|
||||||
|
|
||||||
|
Font@ font = this.Font;
|
||||||
|
string text = this.Caption;
|
||||||
|
Vector2 txtSize = font.Measure(text);
|
||||||
|
Vector2 txtPos;
|
||||||
|
pos += Vector2(8.f, 8.f);
|
||||||
|
size -= Vector2(16.f, 16.f);
|
||||||
|
txtPos = pos + (size - txtSize) * Alignment;
|
||||||
|
|
||||||
|
if(IsEnabled){
|
||||||
|
font.DrawShadow(text, txtPos, 1.f,
|
||||||
|
Vector4(1.f, 1.f, 1.f, 1.f), Vector4(0.f, 0.f, 0.f, 0.4f));
|
||||||
|
}else{
|
||||||
|
font.DrawShadow(text, txtPos, 1.f,
|
||||||
|
Vector4(1.f, 1.f, 1.f, 0.5f), Vector4(0.f, 0.f, 0.f, 0.1f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
504
Resources/Scripts/Gui/UIFramework/Field.as
Normal file
504
Resources/Scripts/Gui/UIFramework/Field.as
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Label.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class FieldCommand {
|
||||||
|
int index;
|
||||||
|
string oldString;
|
||||||
|
string newString;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FieldBase: UIElement {
|
||||||
|
bool Dragging = false;
|
||||||
|
EventHandler@ Changed;
|
||||||
|
string Placeholder;
|
||||||
|
int MarkPosition = 0;
|
||||||
|
int CursorPosition = 0;
|
||||||
|
int MaxLength = 255;
|
||||||
|
bool DenyNonAscii = false;
|
||||||
|
|
||||||
|
private string text;
|
||||||
|
private FieldCommand@[] history;
|
||||||
|
private int historyPos = 0; // index to insert next command
|
||||||
|
|
||||||
|
Vector4 TextColor = Vector4(1.f, 1.f, 1.f, 1.f);
|
||||||
|
Vector4 DisabledTextColor = Vector4(1.f, 1.f, 1.f, 0.3f);
|
||||||
|
Vector4 PlaceholderColor = Vector4(1.f, 1.f, 1.f, 0.5f);
|
||||||
|
Vector4 HighlightColor = Vector4(1.f, 1.f, 1.f, 0.3f);
|
||||||
|
|
||||||
|
Vector2 TextOrigin = Vector2(0.f, 0.f);
|
||||||
|
float TextScale = 1.f;
|
||||||
|
|
||||||
|
FieldBase(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
IsMouseInteractive = true;
|
||||||
|
AcceptsFocus = true;
|
||||||
|
@this.Cursor = Cursor(Manager, manager.Renderer.RegisterImage("Gfx/UI/IBeam.png"), Vector2(16.f, 16.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
string Text {
|
||||||
|
get { return text; }
|
||||||
|
set {
|
||||||
|
text = value;
|
||||||
|
EraseUndoHistory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EraseUndoHistory() {
|
||||||
|
history.length = 0;
|
||||||
|
historyPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckCharType(string s) {
|
||||||
|
if(DenyNonAscii) {
|
||||||
|
for(uint i = 0, len = s.length; i < len; i++) {
|
||||||
|
int c = s[i];
|
||||||
|
if((c & 0x80) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnChanged() {
|
||||||
|
if(Changed !is null) {
|
||||||
|
Changed(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SelectionStart {
|
||||||
|
get final { return Min(MarkPosition, CursorPosition); }
|
||||||
|
set {
|
||||||
|
Select(value, SelectionEnd - value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SelectionEnd {
|
||||||
|
get final {
|
||||||
|
return Max(MarkPosition, CursorPosition);
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
Select(SelectionStart, value - SelectionStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SelectionLength {
|
||||||
|
get final {
|
||||||
|
return SelectionEnd - SelectionStart;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
Select(SelectionStart, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string SelectedText {
|
||||||
|
get final {
|
||||||
|
return Text.substr(SelectionStart, SelectionLength);
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if(!CheckCharType(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FieldCommand cmd;
|
||||||
|
cmd.oldString = this.SelectedText;
|
||||||
|
if(cmd.oldString == value) return; // no change
|
||||||
|
cmd.newString = value;
|
||||||
|
cmd.index = this.SelectionStart;
|
||||||
|
RunFieldCommand(cmd, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunFieldCommand(FieldCommand@ cmd, bool autoSelect, bool addHistory) {
|
||||||
|
text = text.substr(0, cmd.index) + cmd.newString +
|
||||||
|
text.substr(cmd.index + cmd.oldString.length);
|
||||||
|
if(autoSelect)
|
||||||
|
Select(cmd.index, cmd.newString.length);
|
||||||
|
|
||||||
|
if(addHistory) {
|
||||||
|
history.length = historyPos;
|
||||||
|
history.insertLast(cmd);
|
||||||
|
historyPos += 1;
|
||||||
|
// limit history length
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UndoFieldCommand(FieldCommand@ cmd, bool autoSelect) {
|
||||||
|
text = text.substr(0, cmd.index) + cmd.oldString +
|
||||||
|
text.substr(cmd.index + cmd.newString.length);
|
||||||
|
if(autoSelect)
|
||||||
|
Select(cmd.index, cmd.oldString.length);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetHistoryPos(int index) {
|
||||||
|
int p = historyPos;
|
||||||
|
FieldCommand@[]@ h = history;
|
||||||
|
while(p < index) {
|
||||||
|
RunFieldCommand(h[p], true, false);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
while(p > index) {
|
||||||
|
p--;
|
||||||
|
UndoFieldCommand(h[p], true);
|
||||||
|
}
|
||||||
|
historyPos = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Undo() {
|
||||||
|
if(historyPos == 0) return false;
|
||||||
|
SetHistoryPos(historyPos - 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Redo() {
|
||||||
|
if(historyPos >= int(history.length)) return false;
|
||||||
|
SetHistoryPos(historyPos + 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB2 TextInputRect {
|
||||||
|
get {
|
||||||
|
Vector2 textPos = TextOrigin;
|
||||||
|
Vector2 siz = this.Size;
|
||||||
|
string text = Text;
|
||||||
|
int cursorPos = CursorPosition;
|
||||||
|
Font@ font = this.Font;
|
||||||
|
float width = font.Measure(text.substr(0, cursorPos)).x;
|
||||||
|
float fontHeight = font.Measure("A").y;
|
||||||
|
return AABB2(textPos.x + width, textPos.y,
|
||||||
|
siz.x - textPos.x - width, fontHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int PointToCharIndex(float x) {
|
||||||
|
x -= TextOrigin.x;
|
||||||
|
if(x < 0.f) return 0;
|
||||||
|
x /= TextScale;
|
||||||
|
string text = Text;
|
||||||
|
int len = text.length;
|
||||||
|
float lastWidth = 0.f;
|
||||||
|
Font@ font = this.Font;
|
||||||
|
// FIXME: use binary search for better performance?
|
||||||
|
int idx = 0;
|
||||||
|
for(int i = 1; i <= len; i++) {
|
||||||
|
int lastIdx = idx;
|
||||||
|
idx = GetByteIndexForString(text, 1, idx);
|
||||||
|
float width = font.Measure(text.substr(0, idx)).x;
|
||||||
|
if(width > x) {
|
||||||
|
if(x < (lastWidth + width) * 0.5f) {
|
||||||
|
return lastIdx;
|
||||||
|
} else {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastWidth = width;
|
||||||
|
if(idx >= len) {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
int PointToCharIndex(Vector2 pt) {
|
||||||
|
return PointToCharIndex(pt.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClampCursorPosition(int pos) {
|
||||||
|
return Clamp(pos, 0, Text.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Select(int start, int length = 0) {
|
||||||
|
MarkPosition = ClampCursorPosition(start);
|
||||||
|
CursorPosition = ClampCursorPosition(start + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAll() {
|
||||||
|
Select(0, Text.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackSpace() {
|
||||||
|
if(SelectionLength > 0) {
|
||||||
|
SelectedText = "";
|
||||||
|
} else {
|
||||||
|
int pos = CursorPosition;
|
||||||
|
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||||
|
int bIdx = GetByteIndexForString(Text, cIdx - 1);
|
||||||
|
Select(bIdx, pos - bIdx);
|
||||||
|
SelectedText = "";
|
||||||
|
}
|
||||||
|
OnChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Delete() {
|
||||||
|
if(SelectionLength > 0) {
|
||||||
|
SelectedText = "";
|
||||||
|
} else if(CursorPosition < int(Text.length)) {
|
||||||
|
int pos = CursorPosition;
|
||||||
|
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||||
|
int bIdx = GetByteIndexForString(Text, cIdx + 1);
|
||||||
|
Select(bIdx, pos - bIdx);
|
||||||
|
SelectedText = "";
|
||||||
|
}
|
||||||
|
OnChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Insert(string text) {
|
||||||
|
if(!CheckCharType(text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string oldText = SelectedText;
|
||||||
|
SelectedText = text;
|
||||||
|
|
||||||
|
// if text overflows, deny the insertion
|
||||||
|
if((not FitsInBox(Text)) or (int(Text.length) > MaxLength)) {
|
||||||
|
SelectedText = oldText;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Select(SelectionEnd);
|
||||||
|
OnChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyDown(string key) {
|
||||||
|
if(key == "BackSpace") {
|
||||||
|
BackSpace();
|
||||||
|
}else if(key == "Delete") {
|
||||||
|
Delete();
|
||||||
|
}else if(key == "Left") {
|
||||||
|
if(Manager.IsShiftPressed) {
|
||||||
|
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||||
|
CursorPosition = ClampCursorPosition(GetByteIndexForString(Text, cIdx - 1));
|
||||||
|
}else {
|
||||||
|
if(SelectionLength == 0) {
|
||||||
|
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||||
|
Select(GetByteIndexForString(Text, cIdx - 1));
|
||||||
|
} else {
|
||||||
|
Select(SelectionStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}else if(key == "Right") {
|
||||||
|
if(Manager.IsShiftPressed) {
|
||||||
|
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||||
|
CursorPosition = ClampCursorPosition(GetByteIndexForString(Text, cIdx + 1));
|
||||||
|
}else {
|
||||||
|
if(SelectionLength == 0) {
|
||||||
|
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||||
|
Select(GetByteIndexForString(Text, cIdx + 1));
|
||||||
|
} else {
|
||||||
|
Select(SelectionEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(Manager.IsControlPressed or
|
||||||
|
Manager.IsMetaPressed /* for OSX; Cmd + [a-z] */) {
|
||||||
|
if(key == "A") {
|
||||||
|
SelectAll();
|
||||||
|
return;
|
||||||
|
}else if(key == "V") {
|
||||||
|
Manager.Paste(PasteClipboardEventHandler(this.Insert));
|
||||||
|
}else if(key == "C") {
|
||||||
|
Manager.Copy(this.SelectedText);
|
||||||
|
}else if(key == "X") {
|
||||||
|
Manager.Copy(this.SelectedText);
|
||||||
|
this.SelectedText = "";
|
||||||
|
OnChanged();
|
||||||
|
}else if(key == "Z") {
|
||||||
|
if(Manager.IsShiftPressed){
|
||||||
|
if(Redo()) OnChanged();
|
||||||
|
}else{
|
||||||
|
if(Undo()) OnChanged();
|
||||||
|
}
|
||||||
|
}else if(key == "W") {
|
||||||
|
if(Redo()) {
|
||||||
|
OnChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Manager.ProcessHotKey(key);
|
||||||
|
}
|
||||||
|
void KeyUp(string key) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyPress(string text) {
|
||||||
|
if(!(Manager.IsControlPressed or
|
||||||
|
Manager.IsMetaPressed)) {
|
||||||
|
Insert(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MouseDown(MouseButton button, Vector2 clientPosition) {
|
||||||
|
if(button != spades::ui::MouseButton::LeftMouseButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Dragging = true;
|
||||||
|
if(Manager.IsShiftPressed) {
|
||||||
|
MouseMove(clientPosition);
|
||||||
|
} else {
|
||||||
|
Select(PointToCharIndex(clientPosition));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MouseMove(Vector2 clientPosition) {
|
||||||
|
if(Dragging) {
|
||||||
|
CursorPosition = PointToCharIndex(clientPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MouseUp(MouseButton button, Vector2 clientPosition) {
|
||||||
|
if(button != spades::ui::MouseButton::LeftMouseButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FitsInBox(string text) {
|
||||||
|
return Font.Measure(text).x * TextScale < Size.x - TextOrigin.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawHighlight(float x, float y, float w, float h) {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.2f);
|
||||||
|
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
renderer.DrawImage(img, AABB2(x, y, w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawBeam(float x, float y, float h) {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
float pulse = sin(Manager.Time * 5.f);
|
||||||
|
pulse = abs(pulse);
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, pulse);
|
||||||
|
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
renderer.DrawImage(img, AABB2(x - 1.f, y, 2, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawEditingLine(float x, float y, float w, float h) {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, .3f);
|
||||||
|
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
renderer.DrawImage(img, AABB2(x, y + h, w, 2.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Font@ font = this.Font;
|
||||||
|
Vector2 textPos = TextOrigin + pos;
|
||||||
|
string text = Text;
|
||||||
|
|
||||||
|
string composition = this.EditingText;
|
||||||
|
int editStart = this.TextEditingRangeStart;
|
||||||
|
int editLen = this.TextEditingRangeLength;
|
||||||
|
|
||||||
|
int markStart = SelectionStart;
|
||||||
|
int markEnd = SelectionEnd;
|
||||||
|
|
||||||
|
if(composition.length > 0){
|
||||||
|
this.SelectedText = "";
|
||||||
|
markStart = SelectionStart + editStart;
|
||||||
|
markEnd = markStart + editLen;
|
||||||
|
text = text.substr(0, SelectionStart) + composition + text.substr(SelectionStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(text.length == 0){
|
||||||
|
if(IsEnabled) {
|
||||||
|
font.Draw(Placeholder, textPos, TextScale, PlaceholderColor);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
font.Draw(text, textPos, TextScale, IsEnabled ? TextColor : DisabledTextColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IsFocused){
|
||||||
|
float fontHeight = font.Measure("A").y;
|
||||||
|
|
||||||
|
// draw selection
|
||||||
|
int start = markStart;
|
||||||
|
int end = markEnd;
|
||||||
|
if(end == start) {
|
||||||
|
float x = font.Measure(text.substr(0, start)).x;
|
||||||
|
DrawBeam(x + textPos.x, textPos.y, fontHeight);
|
||||||
|
} else {
|
||||||
|
float x1 = font.Measure(text.substr(0, start)).x;
|
||||||
|
float x2 = font.Measure(text.substr(0, end)).x;
|
||||||
|
DrawHighlight(textPos.x + x1, textPos.y, x2 - x1, fontHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw composition underline
|
||||||
|
if(composition.length > 0) {
|
||||||
|
start = SelectionStart;
|
||||||
|
end = start + composition.length;
|
||||||
|
float x1 = font.Measure(text.substr(0, start)).x;
|
||||||
|
float x2 = font.Measure(text.substr(0, end)).x;
|
||||||
|
DrawEditingLine(textPos.x + x1, textPos.y, x2 - x1, fontHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UIElement::Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Field: FieldBase {
|
||||||
|
private bool hover;
|
||||||
|
Field(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
TextOrigin = Vector2(2.f, 2.f);
|
||||||
|
}
|
||||||
|
void MouseEnter() {
|
||||||
|
hover = true;
|
||||||
|
FieldBase::MouseEnter();
|
||||||
|
}
|
||||||
|
void MouseLeave() {
|
||||||
|
hover = false;
|
||||||
|
FieldBase::MouseLeave();
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
// render background
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, IsFocused ? 0.3f : 0.1f);
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
|
||||||
|
if(IsFocused) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.2f);
|
||||||
|
}else if(hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.1f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.06f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, 1.f));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y + size.y - 1.f, size.x, 1.f));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y + 1.f, 1.f, size.y - 2.f));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x + size.x - 1.f, pos.y + 1.f, 1.f, size.y - 2.f));
|
||||||
|
|
||||||
|
FieldBase::Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
60
Resources/Scripts/Gui/UIFramework/Label.as
Normal file
60
Resources/Scripts/Gui/UIFramework/Label.as
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UIFramework.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class Label: UIElement {
|
||||||
|
string Text;
|
||||||
|
Vector4 BackgroundColor = Vector4(0, 0, 0, 0);
|
||||||
|
Vector4 TextColor = Vector4(1, 1, 1, 1);
|
||||||
|
Vector2 Alignment = Vector2(0.f, 0.0f);
|
||||||
|
float TextScale = 1.f;
|
||||||
|
|
||||||
|
Label(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
|
||||||
|
if(BackgroundColor.w > 0.f) {
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
renderer.ColorNP = BackgroundColor;
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Text.length > 0) {
|
||||||
|
Font@ font = this.Font;
|
||||||
|
string text = this.Text;
|
||||||
|
Vector2 txtSize = font.Measure(text) * TextScale;
|
||||||
|
Vector2 txtPos;
|
||||||
|
txtPos = pos + (size - txtSize) * Alignment;
|
||||||
|
|
||||||
|
font.Draw(text, txtPos, TextScale, TextColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
212
Resources/Scripts/Gui/UIFramework/ListView.as
Normal file
212
Resources/Scripts/Gui/UIFramework/ListView.as
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Label.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class ListViewModel {
|
||||||
|
int NumRows { get { return 0; } }
|
||||||
|
UIElement@ CreateElement(int row) { return null; }
|
||||||
|
void RecycleElement(UIElement@ elem) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Simple virtual stack panel implementation. */
|
||||||
|
class ListViewBase: UIElement {
|
||||||
|
private ScrollBar@ scrollBar;
|
||||||
|
private ListViewModel@ model;
|
||||||
|
float RowHeight = 24.f;
|
||||||
|
float ScrollBarWidth = 16.f;
|
||||||
|
private UIElementDeque items;
|
||||||
|
private int loadedStartIndex = 0;
|
||||||
|
|
||||||
|
ListViewBase(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
@scrollBar = ScrollBar(Manager);
|
||||||
|
scrollBar.Bounds = AABB2();
|
||||||
|
AddChild(scrollBar);
|
||||||
|
IsMouseInteractive = true;
|
||||||
|
|
||||||
|
@scrollBar.Changed = EventHandler(this.OnScrolled);
|
||||||
|
@model = ListViewModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScrolled(UIElement@ sender) {
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
int NumVisibleRows {
|
||||||
|
get final {
|
||||||
|
return int(floor(Size.y / RowHeight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MaxTopRowIndex {
|
||||||
|
get final {
|
||||||
|
return Max(0, model.NumRows - NumVisibleRows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TopRowIndex {
|
||||||
|
get final {
|
||||||
|
int idx = int(floor(scrollBar.Value + 0.5));
|
||||||
|
return Clamp(idx, 0, MaxTopRowIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnResized() {
|
||||||
|
Layout();
|
||||||
|
UIElement::OnResized();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout() {
|
||||||
|
scrollBar.MaxValue = double(MaxTopRowIndex);
|
||||||
|
scrollBar.ScrollTo(scrollBar.Value); // ensures value is in range
|
||||||
|
scrollBar.LargeChange = double(NumVisibleRows);
|
||||||
|
|
||||||
|
int numRows = model.NumRows;
|
||||||
|
|
||||||
|
// load items
|
||||||
|
int visibleStart = TopRowIndex;
|
||||||
|
int visibleEnd = Min(visibleStart + NumVisibleRows, numRows);
|
||||||
|
int loadedStart = loadedStartIndex;
|
||||||
|
int loadedEnd = loadedStartIndex + items.Count;
|
||||||
|
|
||||||
|
if(items.Count == 0 or visibleStart >= loadedEnd or visibleEnd <= loadedStart) {
|
||||||
|
// full reload
|
||||||
|
UnloadAll();
|
||||||
|
for(int i = visibleStart; i < visibleEnd; i++) {
|
||||||
|
items.PushBack(model.CreateElement(i));
|
||||||
|
AddChild(items.Back);
|
||||||
|
}
|
||||||
|
loadedStartIndex = visibleStart;
|
||||||
|
} else {
|
||||||
|
while(loadedStart < visibleStart) {
|
||||||
|
RemoveChild(items.Front);
|
||||||
|
model.RecycleElement(items.Front);
|
||||||
|
items.PopFront();
|
||||||
|
loadedStart++;
|
||||||
|
}
|
||||||
|
while(loadedEnd > visibleEnd) {
|
||||||
|
RemoveChild(items.Back);
|
||||||
|
model.RecycleElement(items.Back);
|
||||||
|
items.PopBack();
|
||||||
|
loadedEnd--;
|
||||||
|
}
|
||||||
|
while(visibleStart < loadedStart) {
|
||||||
|
loadedStart--;
|
||||||
|
items.PushFront(model.CreateElement(loadedStart));
|
||||||
|
AddChild(items.Front);
|
||||||
|
}
|
||||||
|
while(visibleEnd > loadedEnd) {
|
||||||
|
items.PushBack(model.CreateElement(loadedEnd));
|
||||||
|
AddChild(items.Back);
|
||||||
|
loadedEnd++;
|
||||||
|
}
|
||||||
|
loadedStartIndex = loadedStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// relayout items
|
||||||
|
UIElementDeque@ items = this.items;
|
||||||
|
int count = items.Count;
|
||||||
|
float y = 0.f;
|
||||||
|
float w = ItemWidth;
|
||||||
|
for(int i = 0; i < count; i++){
|
||||||
|
items[i].Bounds = AABB2(0.f, y, w, RowHeight);
|
||||||
|
y += RowHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move scroll bar
|
||||||
|
scrollBar.Bounds = AABB2(Size.x - ScrollBarWidth, 0.f, ScrollBarWidth, Size.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ItemWidth {
|
||||||
|
get {
|
||||||
|
return Size.x - ScrollBarWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseWheel(float delta) {
|
||||||
|
scrollBar.ScrollBy(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reload() {
|
||||||
|
UnloadAll();
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnloadAll() {
|
||||||
|
UIElementDeque@ items = this.items;
|
||||||
|
int count = items.Count;
|
||||||
|
for(int i = 0; i < count; i++){
|
||||||
|
RemoveChild(items[i]);
|
||||||
|
model.RecycleElement(items[i]);
|
||||||
|
}
|
||||||
|
items.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ListViewModel@ Model {
|
||||||
|
get final { return model; }
|
||||||
|
set {
|
||||||
|
if(model is value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UnloadAll();
|
||||||
|
@model = value;
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollToTop() {
|
||||||
|
scrollBar.ScrollTo(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollToEnd() {
|
||||||
|
scrollBar.ScrollTo(scrollBar.MaxValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ListView: ListViewBase {
|
||||||
|
ListView(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
void Render() {
|
||||||
|
// render background
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, 0.2f);
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.06f);
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, 1.f));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y + size.y - 1.f, size.x, 1.f));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y + 1.f, 1.f, size.y - 2.f));
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x + size.x - 1.f, pos.y + 1.f, 1.f, size.y - 2.f));
|
||||||
|
|
||||||
|
ListViewBase::Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
362
Resources/Scripts/Gui/UIFramework/ScrollBar.as
Normal file
362
Resources/Scripts/Gui/UIFramework/ScrollBar.as
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UIFramework.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
enum ScrollBarOrientation {
|
||||||
|
Horizontal,
|
||||||
|
Vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScrollBarBase: UIElement {
|
||||||
|
double MinValue = 0.0;
|
||||||
|
double MaxValue = 100.0;
|
||||||
|
double Value = 0.0;
|
||||||
|
double SmallChange = 1.0;
|
||||||
|
double LargeChange = 20.0;
|
||||||
|
EventHandler@ Changed;
|
||||||
|
|
||||||
|
ScrollBarBase(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollBy(double delta) {
|
||||||
|
ScrollTo(Value + delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollTo(double val) {
|
||||||
|
val = Clamp(val, MinValue, MaxValue);
|
||||||
|
if(val == Value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Value = val;
|
||||||
|
OnChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnChanged() {
|
||||||
|
if(Changed !is null) {
|
||||||
|
Changed(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollBarOrientation Orientation {
|
||||||
|
get {
|
||||||
|
if(Size.x > Size.y) {
|
||||||
|
return spades::ui::ScrollBarOrientation::Horizontal;
|
||||||
|
} else {
|
||||||
|
return spades::ui::ScrollBarOrientation::Vertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScrollBarTrackBar: UIElement {
|
||||||
|
private ScrollBar@ scrollBar;
|
||||||
|
private bool dragging = false;
|
||||||
|
private double startValue;
|
||||||
|
private float startCursorPos;
|
||||||
|
private bool hover = false;
|
||||||
|
|
||||||
|
ScrollBarTrackBar(ScrollBar@ scrollBar) {
|
||||||
|
super(scrollBar.Manager);
|
||||||
|
@this.scrollBar = scrollBar;
|
||||||
|
IsMouseInteractive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetCursorPos(Vector2 pos) {
|
||||||
|
if(scrollBar.Orientation == spades::ui::ScrollBarOrientation::Horizontal) {
|
||||||
|
return pos.x + Position.x;
|
||||||
|
} else {
|
||||||
|
return pos.y + Position.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseDown(MouseButton button, Vector2 clientPosition) {
|
||||||
|
if(button != spades::ui::MouseButton::LeftMouseButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(scrollBar.TrackBarMovementRange < 0.0001f) {
|
||||||
|
// immobile
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dragging = true;
|
||||||
|
startValue = scrollBar.Value;
|
||||||
|
startCursorPos = GetCursorPos(clientPosition);
|
||||||
|
}
|
||||||
|
void MouseMove(Vector2 clientPosition) {
|
||||||
|
if(dragging) {
|
||||||
|
double val = startValue;
|
||||||
|
float delta = GetCursorPos(clientPosition) - startCursorPos;
|
||||||
|
val += delta * (scrollBar.MaxValue - scrollBar.MinValue) /
|
||||||
|
double(scrollBar.TrackBarMovementRange);
|
||||||
|
scrollBar.ScrollTo(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MouseUp(MouseButton button, Vector2 clientPosition) {
|
||||||
|
if(button != spades::ui::MouseButton::LeftMouseButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dragging = false;
|
||||||
|
}
|
||||||
|
void MouseEnter() {
|
||||||
|
hover = true;
|
||||||
|
UIElement::MouseEnter();
|
||||||
|
}
|
||||||
|
void MouseLeave() {
|
||||||
|
hover = false;
|
||||||
|
UIElement::MouseLeave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
|
||||||
|
if(scrollBar.Orientation == spades::ui::ScrollBarOrientation::Horizontal) {
|
||||||
|
pos.y += 4.f; size.y -= 8.f;
|
||||||
|
} else {
|
||||||
|
pos.x += 4.f; size.x -= 8.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dragging) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.4f);
|
||||||
|
} else if (hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.2f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.1f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScrollBarFill: ButtonBase {
|
||||||
|
private ScrollBarBase@ scrollBar;
|
||||||
|
private bool up;
|
||||||
|
|
||||||
|
ScrollBarFill(ScrollBarBase@ scrollBar, bool up) {
|
||||||
|
super(scrollBar.Manager);
|
||||||
|
@this.scrollBar = scrollBar;
|
||||||
|
IsMouseInteractive = true;
|
||||||
|
Repeat = true;
|
||||||
|
this.up = up;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayMouseEnterSound() {
|
||||||
|
// suppress
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayActivateSound() {
|
||||||
|
// suppress
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
// nothing to draw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScrollBarButton: ButtonBase {
|
||||||
|
private ScrollBar@ scrollBar;
|
||||||
|
private bool up;
|
||||||
|
private Image@ image;
|
||||||
|
|
||||||
|
ScrollBarButton(ScrollBar@ scrollBar, bool up) {
|
||||||
|
super(scrollBar.Manager);
|
||||||
|
@this.scrollBar = scrollBar;
|
||||||
|
IsMouseInteractive = true;
|
||||||
|
Repeat = true;
|
||||||
|
this.up = up;
|
||||||
|
@image = Manager.Renderer.RegisterImage("Gfx/UI/ScrollArrow.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayMouseEnterSound() {
|
||||||
|
// suppress
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayActivateSound() {
|
||||||
|
// suppress
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Renderer@ r = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
pos += size * 0.5f;
|
||||||
|
float siz = image.Width * 0.5f;
|
||||||
|
AABB2 srcRect(0.f, 0.f, image.Width, image.Height);
|
||||||
|
|
||||||
|
if(Pressed and Hover) {
|
||||||
|
r.ColorNP = Vector4(1.f, 1.f, 1.f, 0.6f);
|
||||||
|
} else if (Hover) {
|
||||||
|
r.ColorNP = Vector4(1.f, 1.f, 1.f, 0.4f);
|
||||||
|
} else {
|
||||||
|
r.ColorNP = Vector4(1.f, 1.f, 1.f, 0.2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(scrollBar.Orientation == spades::ui::ScrollBarOrientation::Horizontal) {
|
||||||
|
if(up) {
|
||||||
|
r.DrawImage(image,
|
||||||
|
Vector2(pos.x + siz, pos.y - siz), Vector2(pos.x + siz, pos.y + siz), Vector2(pos.x - siz, pos.y - siz),
|
||||||
|
srcRect);
|
||||||
|
} else {
|
||||||
|
r.DrawImage(image,
|
||||||
|
Vector2(pos.x - siz, pos.y + siz), Vector2(pos.x - siz, pos.y - siz), Vector2(pos.x + siz, pos.y + siz),
|
||||||
|
srcRect);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(up) {
|
||||||
|
r.DrawImage(image,
|
||||||
|
Vector2(pos.x + siz, pos.y + siz), Vector2(pos.x - siz, pos.y + siz), Vector2(pos.x + siz, pos.y - siz),
|
||||||
|
srcRect);
|
||||||
|
} else {
|
||||||
|
r.DrawImage(image,
|
||||||
|
Vector2(pos.x - siz, pos.y - siz), Vector2(pos.x + siz, pos.y - siz), Vector2(pos.x - siz, pos.y + siz),
|
||||||
|
srcRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScrollBar: ScrollBarBase {
|
||||||
|
|
||||||
|
private ScrollBarTrackBar@ trackBar;
|
||||||
|
private ScrollBarFill@ fill1;
|
||||||
|
private ScrollBarFill@ fill2;
|
||||||
|
private ScrollBarButton@ button1;
|
||||||
|
private ScrollBarButton@ button2;
|
||||||
|
|
||||||
|
private float ButtonSize = 16.f;
|
||||||
|
|
||||||
|
ScrollBar(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
|
||||||
|
@trackBar = ScrollBarTrackBar(this);
|
||||||
|
AddChild(trackBar);
|
||||||
|
|
||||||
|
@fill1 = ScrollBarFill(this, false);
|
||||||
|
@fill1.Activated = EventHandler(this.LargeDown);
|
||||||
|
AddChild(fill1);
|
||||||
|
@fill2 = ScrollBarFill(this, true);
|
||||||
|
@fill2.Activated = EventHandler(this.LargeUp);
|
||||||
|
AddChild(fill2);
|
||||||
|
|
||||||
|
@button1 = ScrollBarButton(this, false);
|
||||||
|
@button1.Activated = EventHandler(this.SmallDown);
|
||||||
|
AddChild(button1);
|
||||||
|
@button2 = ScrollBarButton(this, true);
|
||||||
|
@button2.Activated = EventHandler(this.SmallUp);
|
||||||
|
AddChild(button2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LargeDown(UIElement@ e) {
|
||||||
|
ScrollBy(-LargeChange);
|
||||||
|
}
|
||||||
|
private void LargeUp(UIElement@ e) {
|
||||||
|
ScrollBy(LargeChange);
|
||||||
|
}
|
||||||
|
private void SmallDown(UIElement@ e) {
|
||||||
|
ScrollBy(-SmallChange);
|
||||||
|
}
|
||||||
|
private void SmallUp(UIElement@ e) {
|
||||||
|
ScrollBy(SmallChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnChanged() {
|
||||||
|
Layout();
|
||||||
|
ScrollBarBase::OnChanged();
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout() {
|
||||||
|
Vector2 size = Size;
|
||||||
|
float tPos = TrackBarPosition;
|
||||||
|
float tLen = TrackBarLength;
|
||||||
|
if(Orientation == spades::ui::ScrollBarOrientation::Horizontal) {
|
||||||
|
button1.Bounds = AABB2(0.f, 0.f, ButtonSize, size.y);
|
||||||
|
button2.Bounds = AABB2(size.x - ButtonSize, 0.f, ButtonSize, size.y);
|
||||||
|
fill1.Bounds = AABB2(ButtonSize, 0.f, tPos - ButtonSize, size.y);
|
||||||
|
fill2.Bounds = AABB2(tPos + tLen, 0.f, size.x - ButtonSize - tPos - tLen, size.y);
|
||||||
|
trackBar.Bounds = AABB2(tPos, 0.f, tLen, size.y);
|
||||||
|
} else {
|
||||||
|
button1.Bounds = AABB2(0.f, 0.f, size.x, ButtonSize);
|
||||||
|
button2.Bounds = AABB2(0.f, size.y - ButtonSize, size.x, ButtonSize);
|
||||||
|
fill1.Bounds = AABB2(0.f, ButtonSize, size.x, tPos - ButtonSize);
|
||||||
|
fill2.Bounds = AABB2(0.f, tPos + tLen, size.x, size.y - ButtonSize - tPos - tLen);
|
||||||
|
trackBar.Bounds = AABB2(0.f, tPos, size.x, tLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnResized() {
|
||||||
|
Layout();
|
||||||
|
UIElement::OnResized();
|
||||||
|
}
|
||||||
|
|
||||||
|
float Length {
|
||||||
|
get {
|
||||||
|
if(Orientation == spades::ui::ScrollBarOrientation::Horizontal) {
|
||||||
|
return Size.x;
|
||||||
|
} else {
|
||||||
|
return Size.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrackBarAreaLength {
|
||||||
|
get {
|
||||||
|
return Length - ButtonSize - ButtonSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrackBarLength {
|
||||||
|
get {
|
||||||
|
return Max(TrackBarAreaLength *
|
||||||
|
(LargeChange / (MaxValue - MinValue + LargeChange)), 40.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrackBarMovementRange {
|
||||||
|
get {
|
||||||
|
return TrackBarAreaLength - TrackBarLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrackBarPosition {
|
||||||
|
get {
|
||||||
|
if(MaxValue == MinValue) {
|
||||||
|
return ButtonSize;
|
||||||
|
}
|
||||||
|
return float((Value - MinValue) / (MaxValue - MinValue) * TrackBarMovementRange) + ButtonSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Layout();
|
||||||
|
|
||||||
|
ScrollBarBase::Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
208
Resources/Scripts/Gui/UIFramework/Slider.as
Normal file
208
Resources/Scripts/Gui/UIFramework/Slider.as
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScrollBar.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class SliderKnob: UIElement {
|
||||||
|
private Slider@ slider;
|
||||||
|
private bool dragging = false;
|
||||||
|
private double startValue;
|
||||||
|
private float startCursorPos;
|
||||||
|
private bool hover = false;
|
||||||
|
|
||||||
|
SliderKnob(Slider@ slider) {
|
||||||
|
super(slider.Manager);
|
||||||
|
@this.slider = slider;
|
||||||
|
IsMouseInteractive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetCursorPos(Vector2 pos) {
|
||||||
|
return pos.x + Position.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseDown(MouseButton button, Vector2 clientPosition) {
|
||||||
|
if(button != spades::ui::MouseButton::LeftMouseButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dragging = true;
|
||||||
|
startValue = slider.Value;
|
||||||
|
startCursorPos = GetCursorPos(clientPosition);
|
||||||
|
}
|
||||||
|
void MouseMove(Vector2 clientPosition) {
|
||||||
|
if(dragging) {
|
||||||
|
double val = startValue;
|
||||||
|
float delta = GetCursorPos(clientPosition) - startCursorPos;
|
||||||
|
val += delta * (slider.MaxValue - slider.MinValue) /
|
||||||
|
double(slider.TrackBarMovementRange);
|
||||||
|
slider.ScrollTo(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MouseUp(MouseButton button, Vector2 clientPosition) {
|
||||||
|
if(button != spades::ui::MouseButton::LeftMouseButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dragging = false;
|
||||||
|
}
|
||||||
|
void MouseEnter() {
|
||||||
|
hover = true;
|
||||||
|
UIElement::MouseEnter();
|
||||||
|
}
|
||||||
|
void MouseLeave() {
|
||||||
|
hover = false;
|
||||||
|
UIElement::MouseLeave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
|
||||||
|
if (hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.5f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.3f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img,
|
||||||
|
AABB2(pos.x + size.x * 0.5f - 3.f, pos.y,
|
||||||
|
6.f, size.y));
|
||||||
|
|
||||||
|
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, 0.6f);
|
||||||
|
renderer.DrawImage(img,
|
||||||
|
AABB2(pos.x + size.x * 0.5f - 2.f, pos.y + 1.f,
|
||||||
|
4.f, size.y - 2.f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Slider: ScrollBarBase {
|
||||||
|
|
||||||
|
private SliderKnob@ knob;
|
||||||
|
private ScrollBarFill@ fill1;
|
||||||
|
private ScrollBarFill@ fill2;
|
||||||
|
|
||||||
|
Slider(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
|
||||||
|
@knob = SliderKnob(this);
|
||||||
|
AddChild(knob);
|
||||||
|
|
||||||
|
@fill1 = ScrollBarFill(this, false);
|
||||||
|
@fill1.Activated = EventHandler(this.LargeDown);
|
||||||
|
AddChild(fill1);
|
||||||
|
@fill2 = ScrollBarFill(this, true);
|
||||||
|
@fill2.Activated = EventHandler(this.LargeUp);
|
||||||
|
AddChild(fill2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LargeDown(UIElement@ e) {
|
||||||
|
ScrollBy(-LargeChange);
|
||||||
|
}
|
||||||
|
private void LargeUp(UIElement@ e) {
|
||||||
|
ScrollBy(LargeChange);
|
||||||
|
}/*
|
||||||
|
private void SmallDown(UIElement@ e) {
|
||||||
|
ScrollBy(-SmallChange);
|
||||||
|
}
|
||||||
|
private void SmallUp(UIElement@ e) {
|
||||||
|
ScrollBy(SmallChange);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void OnChanged() {
|
||||||
|
Layout();
|
||||||
|
ScrollBarBase::OnChanged();
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout() {
|
||||||
|
Vector2 size = Size;
|
||||||
|
float tPos = TrackBarPosition;
|
||||||
|
float tLen = TrackBarLength;
|
||||||
|
fill1.Bounds = AABB2(0.f, 0.f, tPos, size.y);
|
||||||
|
fill2.Bounds = AABB2(tPos + tLen, 0.f, size.x - tPos - tLen, size.y);
|
||||||
|
knob.Bounds = AABB2(tPos, 0.f, tLen, size.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnResized() {
|
||||||
|
Layout();
|
||||||
|
UIElement::OnResized();
|
||||||
|
}
|
||||||
|
|
||||||
|
float Length {
|
||||||
|
get {
|
||||||
|
if(Orientation == spades::ui::ScrollBarOrientation::Horizontal) {
|
||||||
|
return Size.x;
|
||||||
|
} else {
|
||||||
|
return Size.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrackBarAreaLength {
|
||||||
|
get {
|
||||||
|
return Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrackBarLength {
|
||||||
|
get {
|
||||||
|
return 16.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrackBarMovementRange {
|
||||||
|
get {
|
||||||
|
return TrackBarAreaLength - TrackBarLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrackBarPosition {
|
||||||
|
get {
|
||||||
|
return float((Value - MinValue) / (MaxValue - MinValue) * TrackBarMovementRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
Layout();
|
||||||
|
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.1f);
|
||||||
|
renderer.DrawImage(img,
|
||||||
|
AABB2(pos.x, pos.y + size.y * 0.5f - 3.f,
|
||||||
|
size.x, 6.f));
|
||||||
|
|
||||||
|
renderer.ColorNP = Vector4(0.f, 0.f, 0.f, 0.2f);
|
||||||
|
renderer.DrawImage(img,
|
||||||
|
AABB2(pos.x + 1.f, pos.y + size.y * 0.5f - 2.f,
|
||||||
|
size.x - 2.f, 4.f));
|
||||||
|
|
||||||
|
ScrollBarBase::Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
115
Resources/Scripts/Gui/UIFramework/TabStrip.as
Normal file
115
Resources/Scripts/Gui/UIFramework/TabStrip.as
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Button.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class SimpleTabStripItem: ButtonBase {
|
||||||
|
UIElement@ linkedElement;
|
||||||
|
|
||||||
|
SimpleTabStripItem(UIManager@ manager, UIElement@ linkedElement) {
|
||||||
|
super(manager);
|
||||||
|
@this.linkedElement = linkedElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseDown(MouseButton button, Vector2 clientPosition) {
|
||||||
|
PlayActivateSound();
|
||||||
|
OnActivated();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
this.Toggled = linkedElement.Visible;
|
||||||
|
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Vector4 textColor(0.9f, 0.9f, 0.9f, 1.0f);
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
if(Toggled) {
|
||||||
|
renderer.ColorNP = Vector4(0.9f, 0.9f, 0.9f, 1.0f);
|
||||||
|
textColor = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
} else if(Hover) {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.3f);
|
||||||
|
} else {
|
||||||
|
renderer.ColorNP = Vector4(1.f, 1.f, 1.f, 0.0f);
|
||||||
|
}
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y, size.x, size.y));
|
||||||
|
|
||||||
|
Vector2 txtSize = Font.Measure(Caption);
|
||||||
|
Font.Draw(Caption, pos + (size - txtSize) * 0.5f, 1.f, textColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleTabStrip: UIElement {
|
||||||
|
private float nextX = 0.f;
|
||||||
|
|
||||||
|
EventHandler@ Changed;
|
||||||
|
|
||||||
|
SimpleTabStrip(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChanged() {
|
||||||
|
if(Changed !is null) {
|
||||||
|
Changed(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnItemActivated(UIElement@ sender) {
|
||||||
|
SimpleTabStripItem@ item = cast<SimpleTabStripItem>(sender);
|
||||||
|
UIElement@ linked = item.linkedElement;
|
||||||
|
UIElement@[]@ children = this.GetChildren();
|
||||||
|
for(uint i = 0, count = children.length; i < count; i++) {
|
||||||
|
SimpleTabStripItem@ otherItem = cast<SimpleTabStripItem>(children[i]);
|
||||||
|
otherItem.linkedElement.Visible = (otherItem.linkedElement is linked);
|
||||||
|
}
|
||||||
|
OnChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddItem(string title, UIElement@ linkedElement) {
|
||||||
|
SimpleTabStripItem item(this.Manager, linkedElement);
|
||||||
|
item.Caption = title;
|
||||||
|
float w = this.Font.Measure(title).x + 18.f;
|
||||||
|
item.Bounds = AABB2(nextX, 0.f, w, 24.f);
|
||||||
|
nextX += w + 4.f;
|
||||||
|
|
||||||
|
@item.Activated = EventHandler(this.OnItemActivated);
|
||||||
|
|
||||||
|
this.AddChild(item);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
UIElement::Render();
|
||||||
|
|
||||||
|
Renderer@ renderer = Manager.Renderer;
|
||||||
|
Vector2 pos = ScreenPosition;
|
||||||
|
Vector2 size = Size;
|
||||||
|
Image@ img = renderer.RegisterImage("Gfx/White.tga");
|
||||||
|
renderer.ColorNP = Vector4(0.9f, 0.9f, 0.9f, 1.0f);
|
||||||
|
renderer.DrawImage(img, AABB2(pos.x, pos.y + 24.f, size.x, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
138
Resources/Scripts/Gui/UIFramework/TextViewer.as
Normal file
138
Resources/Scripts/Gui/UIFramework/TextViewer.as
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Label.as"
|
||||||
|
|
||||||
|
namespace spades {
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class TextViewerModel: ListViewModel {
|
||||||
|
UIManager@ manager;
|
||||||
|
string[]@ lines = array<string>();
|
||||||
|
Vector4[]@ colors = array<spades::Vector4>();
|
||||||
|
Font@ font;
|
||||||
|
float width;
|
||||||
|
void AddLine(string text, Vector4 color) {
|
||||||
|
int startPos = 0;
|
||||||
|
if(font.Measure(text).x <= width) {
|
||||||
|
lines.insertLast(text);
|
||||||
|
colors.insertLast(color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
int len = int(text.length);
|
||||||
|
bool charMode = false;
|
||||||
|
while(startPos < len) {
|
||||||
|
int nextPos = pos + 1;
|
||||||
|
if(charMode) {
|
||||||
|
// skip to the next UTF-8 character boundary
|
||||||
|
while(nextPos < len && ((text[nextPos] & 0x80) != 0) &&
|
||||||
|
((text[nextPos] & 0xc0) != 0xc0))
|
||||||
|
nextPos++;
|
||||||
|
} else {
|
||||||
|
while(nextPos < len && text[nextPos] != 0x20)
|
||||||
|
nextPos++;
|
||||||
|
}
|
||||||
|
if(font.Measure(text.substr(startPos, nextPos - startPos)).x > width) {
|
||||||
|
if(pos == startPos) {
|
||||||
|
if(charMode) {
|
||||||
|
pos = nextPos;
|
||||||
|
}else{
|
||||||
|
charMode = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}else{
|
||||||
|
lines.insertLast(text.substr(startPos, pos - startPos));
|
||||||
|
colors.insertLast(color);
|
||||||
|
startPos = pos;
|
||||||
|
while(startPos < len && text[startPos] == 0x20)
|
||||||
|
startPos++;
|
||||||
|
pos = startPos;
|
||||||
|
charMode = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
pos = nextPos;
|
||||||
|
if(nextPos >= len) {
|
||||||
|
lines.insertLast(text.substr(startPos, nextPos - startPos));
|
||||||
|
colors.insertLast(color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
TextViewerModel(UIManager@ manager, string text, Font@ font, float width) {
|
||||||
|
@this.manager = manager;
|
||||||
|
@this.font = font;
|
||||||
|
this.width = width;
|
||||||
|
string[]@ lines = text.split("\n");
|
||||||
|
for(uint i = 0; i < lines.length; i++)
|
||||||
|
AddLine(lines[i], Vector4(1.f, 1.f, 1.f, 1.f));
|
||||||
|
}
|
||||||
|
int NumRows { get { return int(lines.length); } }
|
||||||
|
UIElement@ CreateElement(int row) {
|
||||||
|
Label i(manager);
|
||||||
|
i.Text = lines[row];
|
||||||
|
i.TextColor = colors[row];
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
void RecycleElement(UIElement@ elem) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextViewer: ListViewBase {
|
||||||
|
private string text;
|
||||||
|
private TextViewerModel@ textmodel;
|
||||||
|
|
||||||
|
TextViewer(UIManager@ manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the displayed text. Ensure TextViewer.Font is not null before setting this proeprty. */
|
||||||
|
string Text {
|
||||||
|
get final { return text; }
|
||||||
|
set {
|
||||||
|
text = value;
|
||||||
|
@textmodel = TextViewerModel(Manager, text, Font, ItemWidth);
|
||||||
|
@Model = textmodel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddLine(string line, bool autoscroll = false, Vector4 color = Vector4(1.f, 1.f, 1.f, 1.f)) {
|
||||||
|
if(textmodel is null) {
|
||||||
|
this.Text = "";
|
||||||
|
}
|
||||||
|
if(autoscroll){
|
||||||
|
this.Layout();
|
||||||
|
if(this.scrollBar.Value < this.scrollBar.MaxValue) {
|
||||||
|
autoscroll = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textmodel.AddLine(line, color);
|
||||||
|
if(autoscroll) {
|
||||||
|
this.Layout();
|
||||||
|
this.ScrollToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
28
Resources/Scripts/Gui/UIFramework/UIControls.as
Normal file
28
Resources/Scripts/Gui/UIFramework/UIControls.as
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 yvt
|
||||||
|
|
||||||
|
This file is part of OpenSpades.
|
||||||
|
|
||||||
|
OpenSpades is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenSpades is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Button.as"
|
||||||
|
#include "Field.as"
|
||||||
|
#include "Label.as"
|
||||||
|
#include "ListView.as"
|
||||||
|
#include "ScrollBar.as"
|
||||||
|
#include "Slider.as"
|
||||||
|
#include "TabStrip.as"
|
||||||
|
#include "TextViewer.as"
|
Loading…
x
Reference in New Issue
Block a user