In hindsight my emscripten-ifdef (70d416a8f63f) is nonsense.
As fpcrtl_glShaderSource() would not be defined and lead to compiling issues.
So either it's 3 ifdefs (in pas2cRedo, pas2cSystem and misc.c),
in order to toggle between fpcrtl_ and the native function,
or alternatively have no ifdef for it at all.
I'm going with none at all,
which means emscripten will compile with the original (const) function prototype,
being wrapped by the fpcrtl_ function, same as non-emscripten builds.
/*
* Hedgewars, a free turn based strategy game
* Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
*
* This program 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; version 2 of the License
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <QGridLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QGroupBox>
#include <QComboBox>
#include <QCheckBox>
#include <QLabel>
#include <QTableWidget>
#include <QLineEdit>
#include <QSpinBox>
#include <QTextBrowser>
#include <QScrollArea>
#include <QHeaderView>
#include <QSlider>
#include <QSignalMapper>
#include <QColorDialog>
#include <QMessageBox>
#include <QStandardItemModel>
#include <QDebug>
#include "pageoptions.h"
#include "gameuiconfig.h"
#include "hwconsts.h"
#include "fpsedit.h"
#include "DataManager.h"
#include "LibavInteraction.h"
#include "AutoUpdater.h"
#include "HWApplication.h"
#include "keybinder.h"
#ifdef __APPLE__
#ifdef SPARKLE_ENABLED
#include "SparkleAutoUpdater.h"
#endif
#endif
const int OPTION_BOX_SPACING = 10;
OptionGroupBox::OptionGroupBox(const QString & iconName,
const QString & title,
QWidget * parent) : IconedGroupBox(parent)
{
setIcon(QIcon(iconName));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setTitle(title);
setMinimumWidth(300);
m_layout = new QGridLayout(this);
m_layout->setColumnStretch(0, 0);
m_layout->setColumnStretch(1, 1);
}
QGridLayout * OptionGroupBox::layout()
{
return m_layout;
}
void OptionGroupBox::addDivider()
{
QFrame * hr = new QFrame(this);
hr->setFrameStyle(QFrame::HLine);
hr->setLineWidth(3);
hr->setFixedHeight(10);
m_layout->addWidget(hr, m_layout->rowCount(), 0, 1, m_layout->columnCount());
}
// TODO cleanup
QLayout * PageOptions::bodyLayoutDefinition()
{
QVBoxLayout * pageLayout = new QVBoxLayout();
QTabWidget * tabs = new QTabWidget(this);
pageLayout->addWidget(tabs);
binder = new KeyBinder(this, tr("Select an action to change what key controls it"), tr("Reset to default"), tr("Reset all binds"));
connect(binder, SIGNAL(bindUpdate(int)), this, SLOT(bindUpdated(int)));
connect(binder, SIGNAL(resetAllBinds()), this, SLOT(resetAllBinds()));
QWidget * pageGame = new QWidget(this);
tabs->addTab(pageGame, tr("Game"));
QWidget * pageGraphics = new QWidget(this);
tabs->addTab(pageGraphics, tr("Graphics"));
QWidget * pageAudio = new QWidget(this);
tabs->addTab(pageAudio, tr("Audio"));
binderTab = tabs->addTab(binder, tr("Controls"));
#ifdef VIDEOREC
QWidget * pageVideoRec = new QWidget(this);
tabs->addTab(pageVideoRec, tr("Video Recording"));
#endif
QWidget * pageNetwork = new QWidget(this);
tabs->addTab(pageNetwork, tr("Network"));
QWidget * pageAdvanced = new QWidget(this);
tabs->addTab(pageAdvanced, tr("Advanced"));
connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tabIndexChanged(int)));
QPixmap pmNew(":/res/new.png");
QPixmap pmEdit(":/res/edit.png");
QPixmap pmDelete(":/res/delete.png");
{ // game page
QVBoxLayout * leftColumn, * rightColumn;
setupTabPage(pageGame, &leftColumn, &rightColumn);
{ // group: Teams
OptionGroupBox * groupTeams = new OptionGroupBox(":/res/teamicon.png", tr("Teams"), this);
groupTeams->setMinimumWidth(400);
rightColumn->addWidget(groupTeams);
groupTeams->layout()->setColumnStretch(0, 1);
CBTeamName = new QComboBox(groupTeams);
CBTeamName->setMaxVisibleItems(50);
CBTeamName->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
groupTeams->layout()->addWidget(CBTeamName, 0, 0);
BtnNewTeam = new QPushButton(groupTeams);
BtnNewTeam->setWhatsThis(tr("New team"));
BtnNewTeam->setIconSize(pmNew.size());
BtnNewTeam->setIcon(pmNew);
BtnNewTeam->setMaximumWidth(pmNew.width() + 6);
BtnNewTeam->setStyleSheet("padding: 0px;");
connect(BtnNewTeam, SIGNAL(clicked()), this, SIGNAL(newTeamRequested()));
groupTeams->layout()->addWidget(BtnNewTeam, 0, 1);
BtnEditTeam = new QPushButton(groupTeams);
BtnEditTeam->setWhatsThis(tr("Edit team"));
BtnEditTeam->setIconSize(pmEdit.size());
BtnEditTeam->setIcon(pmEdit);
BtnEditTeam->setMaximumWidth(pmEdit.width() + 6);
BtnEditTeam->setStyleSheet("padding: 0px;");
connect(BtnEditTeam, SIGNAL(clicked()), this, SLOT(requestEditSelectedTeam()));
groupTeams->layout()->addWidget(BtnEditTeam, 0, 2);
BtnDeleteTeam = new QPushButton(groupTeams);
BtnDeleteTeam->setWhatsThis(tr("Delete team"));
BtnDeleteTeam->setIconSize(pmDelete.size());
BtnDeleteTeam->setIcon(pmDelete);
BtnDeleteTeam->setMaximumWidth(pmDelete.width() + 6);
BtnDeleteTeam->setStyleSheet("padding: 0px;");
connect(BtnDeleteTeam, SIGNAL(clicked()), this, SLOT(requestDeleteSelectedTeam()));
groupTeams->layout()->addWidget(BtnDeleteTeam, 0, 3);
LblNoEditTeam = new QLabel(groupTeams);
LblNoEditTeam->setText(tr("You can't edit teams from team selection. Go back to main menu to add, edit or delete teams."));
LblNoEditTeam->setWordWrap(true);
LblNoEditTeam->setVisible(false);
groupTeams->layout()->addWidget(LblNoEditTeam, 1, 0, 1, 4);
}
{ // group: schemes
OptionGroupBox * groupSchemes = new OptionGroupBox(":/res/schemeicon.png", tr("Schemes"), this);
leftColumn->addWidget(groupSchemes);
groupSchemes->layout()->setColumnStretch(0, 1);
SchemesName = new QComboBox(groupSchemes);
SchemesName->setMaxVisibleItems(50);
SchemesName->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
groupSchemes->layout()->addWidget(SchemesName, 0, 0);
SchemeNew = new QPushButton(groupSchemes);
SchemeNew->setWhatsThis(tr("New scheme"));
SchemeNew->setIconSize(pmNew.size());
SchemeNew->setIcon(pmNew);
SchemeNew->setMaximumWidth(pmNew.width() + 6);
SchemeNew->setStyleSheet("padding: 0px;");
groupSchemes->layout()->addWidget(SchemeNew, 0, 1);
SchemeEdit = new QPushButton(groupSchemes);
SchemeEdit->setWhatsThis(tr("Edit scheme"));
SchemeEdit->setIconSize(pmEdit.size());
SchemeEdit->setIcon(pmEdit);
SchemeEdit->setMaximumWidth(pmEdit.width() + 6);
SchemeEdit->setStyleSheet("padding: 0px;");
groupSchemes->layout()->addWidget(SchemeEdit, 0, 2);
SchemeDelete = new QPushButton(groupSchemes);
SchemeDelete->setWhatsThis(tr("Delete scheme"));
SchemeDelete->setIconSize(pmDelete.size());
SchemeDelete->setIcon(pmDelete);
SchemeDelete->setMaximumWidth(pmDelete.width() + 6);
SchemeDelete->setStyleSheet("padding: 0px;");
groupSchemes->layout()->addWidget(SchemeDelete, 0, 3);
}
{ // group: weapons
OptionGroupBox * groupWeapons = new OptionGroupBox(":/res/weaponsicon.png", tr("Weapons"), this);
leftColumn->addWidget(groupWeapons);
groupWeapons->layout()->setColumnStretch(0, 1);
WeaponsName = new QComboBox(groupWeapons);
WeaponsName->setMaxVisibleItems(50);
WeaponsName->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
groupWeapons->layout()->addWidget(WeaponsName, 0, 0);
WeaponNew = new QPushButton(groupWeapons);
WeaponNew->setWhatsThis(tr("New weapon set"));
WeaponNew->setIconSize(pmNew.size());
WeaponNew->setIcon(pmNew);
WeaponNew->setMaximumWidth(pmNew.width() + 6);
WeaponNew->setStyleSheet("padding: 0px;");
groupWeapons->layout()->addWidget(WeaponNew, 0, 1);
WeaponEdit = new QPushButton(groupWeapons);
WeaponEdit->setWhatsThis(tr("Edit weapon set"));
WeaponEdit->setIconSize(pmEdit.size());
WeaponEdit->setIcon(pmEdit);
WeaponEdit->setMaximumWidth(pmEdit.width() + 6);
WeaponEdit->setStyleSheet("padding: 0px;");
groupWeapons->layout()->addWidget(WeaponEdit, 0, 2);
WeaponDelete = new QPushButton(groupWeapons);
WeaponDelete->setWhatsThis(tr("Delete weapon set"));
WeaponDelete->setIconSize(pmDelete.size());
WeaponDelete->setIcon(pmDelete);
WeaponDelete->setMaximumWidth(pmDelete.width() + 6);
WeaponDelete->setStyleSheet("padding: 0px;");
groupWeapons->layout()->addWidget(WeaponDelete, 0, 3);
}
leftColumn->addStretch(1);
rightColumn->addStretch(1);
}
{ // graphics page
QVBoxLayout * leftColumn, * rightColumn;
setupTabPage(pageGraphics, &leftColumn, &rightColumn);
{ // group: game
OptionGroupBox * groupGame = new OptionGroupBox(":/res/graphicsicon.png", tr("Game"), this);
leftColumn->addWidget(groupGame);
groupGame->layout()->setColumnStretch(0, 0);
groupGame->layout()->setColumnStretch(1, 0);
groupGame->layout()->setColumnStretch(2, 1);
// Fullscreen
CBFullscreen = new QCheckBox(groupGame);
groupGame->layout()->addWidget(CBFullscreen, 0, 0, 1, 2);
CBFullscreen->setText(QLabel::tr("Fullscreen"));
// Fullscreen resolution
lblFullScreenRes = new QLabel(groupGame);
lblFullScreenRes->setText(QLabel::tr("Fullscreen Resolution"));
groupGame->layout()->addWidget(lblFullScreenRes, 1, 0);
CBResolution = new QComboBox(groupGame);
CBResolution->setMaxVisibleItems(50);
CBResolution->setFixedWidth(200);
groupGame->layout()->addWidget(CBResolution, 1, 1, Qt::AlignLeft);
// Windowed resolution
lblWinScreenRes = new QLabel(groupGame);
lblWinScreenRes->setText(QLabel::tr("Windowed Resolution"));
groupGame->layout()->addWidget(lblWinScreenRes, 2, 0);
QHBoxLayout * winResLayout = new QHBoxLayout();
winResLayout->setSpacing(0);
groupGame->layout()->addLayout(winResLayout, 2, 1, 1, 3);
winLabelX = new QLabel(groupGame);
//: Multiplication sign, to be used between two numbers. Note the “x” is only a dummy character, we recommend to use “×” if your language permits it
winLabelX->setText(tr("x"));
winLabelX->setFixedWidth(40);
winLabelX->setAlignment(Qt::AlignCenter);
// TODO: less random max. also:
// make some min/max-consts, shared with engine?
windowWidthEdit = new QSpinBox(groupGame);
windowWidthEdit->setRange(640, 102400);
windowWidthEdit->setFixedSize(60, CBResolution->height());
windowHeightEdit = new QSpinBox(groupGame);
windowHeightEdit->setRange(480, 102400);
windowHeightEdit->setFixedSize(60, CBResolution->height());
winResLayout->addWidget(windowWidthEdit, 0);
winResLayout->addWidget(winLabelX, 0);
winResLayout->addWidget(windowHeightEdit, 0);
winResLayout->addStretch(1);
// Quality
QLabel * lblQuality = new QLabel(groupGame);
lblQuality->setText(QLabel::tr("Quality"));
lblQuality->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
groupGame->layout()->addWidget(lblQuality, 3, 0);
SLQuality = new QSlider(Qt::Horizontal, groupGame);
SLQuality->setTickPosition(QSlider::TicksBelow);
SLQuality->setPageStep(2);
SLQuality->setMaximum(5);
SLQuality->setMinimum(0);
SLQuality->setFixedWidth(150);
groupGame->layout()->addWidget(SLQuality, 3, 1, Qt::AlignLeft);
// Zoom
QLabel * lblZoom = new QLabel(groupGame);
lblZoom->setText(QLabel::tr("Zoom (%)"));
lblZoom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
groupGame->layout()->addWidget(lblZoom, 4, 0);
SLZoom = new QSpinBox(groupGame);
SLZoom->setSingleStep(5);
SLZoom->setMaximum(150);
SLZoom->setMinimum(50);
groupGame->layout()->addWidget(SLZoom, 4, 1, Qt::AlignLeft);
// Stereo spacing
QLabel * lblStereo = new QLabel(groupGame);
lblStereo->setText(QLabel::tr("Stereoscopy"));
groupGame->layout()->addWidget(lblStereo, 5, 0);
CBStereoMode = new QComboBox(groupGame);
CBStereoMode->setWhatsThis(QComboBox::tr("Stereoscopy creates an illusion of depth when you wear 3D glasses."));
CBStereoMode->setMaxVisibleItems(50);
CBStereoMode->addItem(QComboBox::tr("Disabled"));
CBStereoMode->addItem(QComboBox::tr("Red/Cyan"));
CBStereoMode->addItem(QComboBox::tr("Cyan/Red"));
CBStereoMode->addItem(QComboBox::tr("Red/Blue"));
CBStereoMode->addItem(QComboBox::tr("Blue/Red"));
CBStereoMode->addItem(QComboBox::tr("Red/Green"));
CBStereoMode->addItem(QComboBox::tr("Green/Red"));
CBStereoMode->addItem(QComboBox::tr("Red/Cyan grayscale"));
CBStereoMode->addItem(QComboBox::tr("Cyan/Red grayscale"));
CBStereoMode->addItem(QComboBox::tr("Red/Blue grayscale"));
CBStereoMode->addItem(QComboBox::tr("Blue/Red grayscale"));
CBStereoMode->addItem(QComboBox::tr("Red/Green grayscale"));
CBStereoMode->addItem(QComboBox::tr("Green/Red grayscale"));
CBStereoMode->addItem(QComboBox::tr("Side-by-side"));
CBStereoMode->addItem(QComboBox::tr("Top-Bottom"));
CBStereoMode->setFixedWidth(CBResolution->width());
groupGame->layout()->addWidget(CBStereoMode, 5, 1);
// Divider
groupGame->addDivider(); // row 6
// FPS limit
QHBoxLayout * fpsLayout = new QHBoxLayout();
groupGame->layout()->addLayout(fpsLayout, 7, 0, 1, 2);
QLabel * maxfps = new QLabel(groupGame);
maxfps->setText(QLabel::tr("FPS limit"));
fpsLayout->addWidget(maxfps);
fpsLayout->addSpacing(30);
fpsedit = new FPSEdit(groupGame);
fpsLayout->addWidget(fpsedit);
// Show FPS
CBShowFPS = new QCheckBox(groupGame);
CBShowFPS->setText(QCheckBox::tr("Show FPS"));
fpsLayout->addWidget(CBShowFPS);
fpsLayout->addStretch(1);
// Divider
groupGame->addDivider(); // row 8
// Alternative damage show
CBAltDamage = new QCheckBox(groupGame);
CBAltDamage->setText(QCheckBox::tr("Alternative damage show"));
groupGame->layout()->addWidget(CBAltDamage, 9, 0, 1, 2);
// Show ammo menu tooltips
WeaponTooltip = new QCheckBox(groupGame);
WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips"));
groupGame->layout()->addWidget(WeaponTooltip, 10, 0, 1, 2);
groupGame->addDivider();
lblTags = new QLabel(groupGame);
lblTags->setText(QLabel::tr("Displayed tags above hogs and translucent tags"));
groupGame->layout()->addWidget(lblTags, 12, 0, 1, 2);
tagsContainer = new QWidget();
QHBoxLayout * tagsLayout = new QHBoxLayout(tagsContainer);
tagsLayout->setSpacing(0);
groupGame->layout()->addWidget(tagsContainer, 13, 0, 1, 2);
CBTeamTag = new QCheckBox(groupGame);
CBTeamTag->setText(QCheckBox::tr("Team"));
CBTeamTag->setWhatsThis(QCheckBox::tr("Enable team tags by default"));
CBHogTag = new QCheckBox(groupGame);
CBHogTag->setText(QCheckBox::tr("Hog"));
CBHogTag->setWhatsThis(QCheckBox::tr("Enable hedgehog tags by default"));
CBHealthTag = new QCheckBox(groupGame);
CBHealthTag->setText(QCheckBox::tr("Health"));
CBHealthTag->setWhatsThis(QCheckBox::tr("Enable health tags by default"));
CBTagOpacity = new QCheckBox(groupGame);
CBTagOpacity->setText(QCheckBox::tr("Translucent"));
CBTagOpacity->setWhatsThis(QCheckBox::tr("Enable translucent tags by default"));
tagsLayout->addWidget(CBTeamTag, 0);
tagsLayout->addWidget(CBHogTag, 0);
tagsLayout->addWidget(CBHealthTag, 0);
tagsLayout->addWidget(CBTagOpacity, 0);
tagsLayout->addStretch(1);
}
{ // group: frontend
OptionGroupBox * groupFrontend = new OptionGroupBox(":/res/frontendicon.png", tr("Frontend"), this);
rightColumn->addWidget(groupFrontend);
// Fullscreen
CBFrontendFullscreen = new QCheckBox(groupFrontend);
CBFrontendFullscreen->setText(QCheckBox::tr("Fullscreen"));
groupFrontend->layout()->addWidget(CBFrontendFullscreen, 0, 0);
// Visual effects
CBFrontendEffects = new QCheckBox(groupFrontend);
CBFrontendEffects->setText(QCheckBox::tr("Visual effects"));
CBFrontendEffects->setWhatsThis(QCheckBox::tr("Enable visual effects such as animated menu transitions and falling stars"));
groupFrontend->layout()->addWidget(CBFrontendEffects, 1, 0);
}
{ // group: colors
OptionGroupBox * groupColors = new OptionGroupBox(":/res/Palette.png", tr("Custom colors"), this);
rightColumn->addWidget(groupColors);
groupColors->layout()->setColumnStretch(0, 1);
groupColors->layout()->setColumnStretch(1, 1);
groupColors->layout()->setColumnStretch(2, 1);
// Color buttons
QSignalMapper * mapper = new QSignalMapper(this);
QStandardItemModel * model = DataManager::instance().colorsModel();
connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onColorModelDataChanged(QModelIndex,QModelIndex)));
for(int i = 0; i < model->rowCount(); ++i)
{
QPushButton * btn = new QPushButton(this);
btn->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
groupColors->layout()->addWidget(btn, i / 3, i % 3);
btn->setStyleSheet(QString("background: %1").arg(model->item(i)->data().value<QColor>().name()));
m_colorButtons.append(btn);
connect(btn, SIGNAL(clicked()), mapper, SLOT(map()));
mapper->setMapping(btn, i);
}
connect(mapper, SIGNAL(mapped(int)), this, SLOT(colorButtonClicked(int)));
// Reset default colors
QPushButton * btn = new QPushButton(this);
groupColors->layout()->addWidget(btn, (model->rowCount() - 1) / 3 + 1, 0, 1, 3);
btn->setText(tr("Reset to default colors"));
connect(btn, SIGNAL(clicked()), &DataManager::instance(), SLOT(resetColors()));
}
leftColumn->addStretch(1);
rightColumn->addStretch(1);
}
{ // audio page
QVBoxLayout * leftColumn, * rightColumn;
setupTabPage(pageAudio, &leftColumn, &rightColumn);
{ // group: game
OptionGroupBox * groupGame = new OptionGroupBox(":/res/audio.png", tr("Game audio"), this);
leftColumn->addWidget(groupGame);
groupGame->layout()->setColumnStretch(1, 0);
groupGame->layout()->setColumnStretch(2, 1);
// Initial sound volume
QLabel * vol = new QLabel(groupGame);
vol->setText(QLabel::tr("Initial sound volume"));
groupGame->layout()->addWidget(vol, 0, 0);
SLVolume = new QSlider(Qt::Horizontal, groupGame);
SLVolume->setTickPosition(QSlider::TicksBelow);
SLVolume->setMaximum(100);
SLVolume->setMinimum(0);
SLVolume->setFixedWidth(150);
groupGame->layout()->addWidget(SLVolume, 0, 1, 1, 2);
lblVolumeLevel = new QLabel(groupGame);
lblVolumeLevel->setFixedWidth(40);
groupGame->layout()->addWidget(lblVolumeLevel, 0, 3);
// Sound
CBSound = new QCheckBox(groupGame);
CBSound->setText(QCheckBox::tr("Sound"));
CBSound->setWhatsThis(QCheckBox::tr("In-game sound effects"));
groupGame->layout()->addWidget(CBSound, 1, 1);
// Music
CBMusic = new QCheckBox(groupGame);
CBMusic->setText(QCheckBox::tr("Music"));
CBMusic->setWhatsThis(QCheckBox::tr("In-game music"));
groupGame->layout()->addWidget(CBMusic, 1, 2, 1, 2, Qt::AlignLeft);
// Dampen
CBDampenAudio = new QCheckBox(groupGame);
//: Checkbox text. If checked, the in-game audio volume is reduced (=dampened) when the game window loses its focus
CBDampenAudio->setText(QCheckBox::tr("Dampen when losing focus"));
CBDampenAudio->setWhatsThis(QCheckBox::tr("Reduce the game audio volume if the game window has lost its focus"));
groupGame->layout()->addWidget(CBDampenAudio, 2, 1, 1, 3, Qt::AlignLeft);
}
{ // group: frontend
OptionGroupBox * groupFrontend = new OptionGroupBox(":/res/audio.png", tr("Frontend audio"), this);
rightColumn->addWidget(groupFrontend);
CBFrontendSound = new QCheckBox(groupFrontend);
CBFrontendSound->setText(QCheckBox::tr("Sound"));
CBFrontendSound->setWhatsThis(QCheckBox::tr("Frontend sound effects"));
groupFrontend->layout()->addWidget(CBFrontendSound, 0, 0);
CBFrontendMusic = new QCheckBox(groupFrontend);
CBFrontendMusic->setText(QCheckBox::tr("Music"));
CBFrontendMusic->setWhatsThis(QCheckBox::tr("Frontend music"));
groupFrontend->layout()->addWidget(CBFrontendMusic, 0, 1);
}
leftColumn->addStretch(1);
rightColumn->addStretch(1);
}
{ // network page
QVBoxLayout * leftColumn, * rightColumn;
setupTabPage(pageNetwork, &leftColumn, &rightColumn);
{ // group: account
OptionGroupBox * groupAccount = new OptionGroupBox(":/res/teamicon.png", tr("Account"), this);
leftColumn->addWidget(groupAccount);
// Label and field for net nick
labelNN = new QLabel(groupAccount);
labelNN->setText(QLabel::tr("Nickname"));
groupAccount->layout()->addWidget(labelNN, 0, 0);
editNetNick = new QLineEdit(groupAccount);
editNetNick->setMaxLength(20);
editNetNick->setText(QLineEdit::tr("anonymous"));
groupAccount->layout()->addWidget(editNetNick, 0, 1);
// Checkbox and field for password
CBSavePassword = new QCheckBox(groupAccount);
CBSavePassword->setText(QCheckBox::tr("Save password"));
groupAccount->layout()->addWidget(CBSavePassword, 1, 0);
editNetPassword = new QLineEdit(groupAccount);
editNetPassword->setEchoMode(QLineEdit::Password);
groupAccount->layout()->addWidget(editNetPassword, 1, 1);
}
{ // group: proxy
OptionGroupBox * groupProxy = new OptionGroupBox(":/res/net.png", tr("Proxy settings"), this);
rightColumn->addWidget(groupProxy);
// Labels
QStringList sl;
sl << tr("Proxy host")
<< tr("Proxy port")
<< tr("Proxy login")
<< tr("Proxy password");
for(int i = 0; i < sl.size(); ++i)
{
QLabel * l = new QLabel(groupProxy);
l->setText(sl[i]);
groupProxy->layout()->addWidget(l, i + 1, 0);
}
// Proxy type
cbProxyType = new QComboBox(groupProxy);
cbProxyType->addItems(QStringList()
<< tr("No proxy")
<< tr("System proxy settings")
<< tr("Socks5 proxy")
<< tr("HTTP proxy"));
groupProxy->layout()->addWidget(cbProxyType, 0, 0, 1, 2);
// Proxy
leProxy = new QLineEdit(groupProxy);
groupProxy->layout()->addWidget(leProxy, 1, 1);
// Proxy
sbProxyPort = new QSpinBox(groupProxy);
sbProxyPort->setMaximum(65535);
groupProxy->layout()->addWidget(sbProxyPort, 2, 1);
leProxyLogin = new QLineEdit(groupProxy);
groupProxy->layout()->addWidget(leProxyLogin, 3, 1);
leProxyPassword = new QLineEdit(groupProxy);
leProxyPassword->setEchoMode(QLineEdit::Password);
groupProxy->layout()->addWidget(leProxyPassword, 4, 1);
connect(cbProxyType, SIGNAL(currentIndexChanged(int)), this, SLOT(onProxyTypeChanged()));
onProxyTypeChanged();
}
leftColumn->addStretch(1);
rightColumn->addStretch(1);
}
{ // advanced page
QVBoxLayout * leftColumn, * rightColumn;
setupTabPage(pageAdvanced, &leftColumn, &rightColumn);
{ // group: miscellaneous
OptionGroupBox * groupMisc = new OptionGroupBox(":/res/Settings.png", tr("Miscellaneous"), this);
leftColumn->addWidget(groupMisc);
// Language
QLabel *labelLanguage = new QLabel(groupMisc);
labelLanguage->setText(QLabel::tr("Locale"));
groupMisc->layout()->addWidget(labelLanguage, 0, 0);
CBLanguage = new QComboBox(groupMisc);
CBLanguage->setMaxVisibleItems(50);
groupMisc->layout()->addWidget(CBLanguage, 0, 1);
QStringList locs = DataManager::instance().entryList("Locale", QDir::Files, QStringList("hedgewars_*.qm"));
QStringList langnames;
CBLanguage->addItem(QComboBox::tr("(System default)"), QString());
for(int i = 0; i < locs.count(); i++)
{
QString lname = locs[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1");
QLocale loc = QLocale(lname);
QString entryName;
// If local identifier has underscore, it means the country has been specified
if(lname.contains("_"))
{
// Append country name for disambiguation
// FIXME: These brackets are hardcoded and can't be translated. Luckily, these are rarely used and work with most languages anyway
entryName = loc.nativeLanguageName() + " (" + loc.nativeCountryName() + ")";
}
else
{
// Usually, we just print the language name
entryName = loc.nativeLanguageName();
}
// Fallback code, if language name is empty for some reason. This should normally not happen
if(entryName.isEmpty())
{
// Show error and the locale identifier
//: In the case of an error, this is shown in the language selection for a language with unknown name. %1 = language code
entryName = tr("MISSING LANGUAGE NAME [%1]").arg(lname);
}
CBLanguage->addItem(entryName, lname);
}
QLabel *restartNoticeLabel = new QLabel(groupMisc);
restartNoticeLabel->setText(QLabel::tr("This setting will be effective at next restart."));
groupMisc->layout()->addWidget(restartNoticeLabel, 1, 1);
// Divider
groupMisc->addDivider(); // row 1
// Append date and time to record file name
CBNameWithDate = new QCheckBox(groupMisc);
CBNameWithDate->setText(QCheckBox::tr("Append date and time to record file name"));
CBNameWithDate->setWhatsThis(QCheckBox::tr("If enabled, Hedgewars adds the date and time in the form \"YYYY-MM-DD_hh-mm\" for automatically created demos."));
groupMisc->layout()->addWidget(CBNameWithDate, 3, 0, 1, 2);
// Associate file extensions
BtnAssociateFiles = new QPushButton(groupMisc);
BtnAssociateFiles->setText(QPushButton::tr("Associate file extensions"));
BtnAssociateFiles->setVisible(!custom_data && !custom_config);
groupMisc->layout()->addWidget(BtnAssociateFiles, 4, 0, 1, 2);
}
#ifdef __APPLE__
#ifdef SPARKLE_ENABLED
{ // group: updates
OptionGroupBox * groupUpdates = new OptionGroupBox(":/res/net.png", tr("Updates"), this);
rightColumn->addWidget(groupUpdates);
// Check for updates at startup
CBAutoUpdate = new QCheckBox(groupUpdates);
CBAutoUpdate->setText(QCheckBox::tr("Check for updates at startup"));
groupUpdates->layout()->addWidget(CBAutoUpdate, 0, 0);
// Check for updates now
btnUpdateNow = new QPushButton(groupUpdates);
connect(btnUpdateNow, SIGNAL(clicked()), this, SLOT(checkForUpdates()));
btnUpdateNow->setWhatsThis(tr("Check for updates"));
btnUpdateNow->setText(tr("Check now"));
btnUpdateNow->setFixedSize(130, 30);
groupUpdates->layout()->addWidget(btnUpdateNow, 0, 1);
}
#endif
#endif
leftColumn->addStretch(1);
rightColumn->addStretch(1);
}
#ifdef VIDEOREC
{ // video recording page
OptionGroupBox * groupVideoRec = new OptionGroupBox(":/res/camera.png", tr("Video recording options"), this);
groupVideoRec->setMinimumWidth(500);
groupVideoRec->setMaximumWidth(650);
QHBoxLayout * layoutVideoRec = new QHBoxLayout(pageVideoRec);
layoutVideoRec->addWidget(groupVideoRec, 1, Qt::AlignTop | Qt::AlignHCenter);
// label for format
QLabel *labelFormat = new QLabel(groupVideoRec);
labelFormat->setText(QLabel::tr("Format"));
groupVideoRec->layout()->addWidget(labelFormat, 0, 0);
// list of supported formats
comboAVFormats = new QComboBox(groupVideoRec);
comboAVFormats->setMaxVisibleItems(50);
groupVideoRec->layout()->addWidget(comboAVFormats, 0, 1, 1, 4);
LibavInteraction::instance().fillFormats(comboAVFormats);
// separator
QFrame * hr = new QFrame(groupVideoRec);
hr->setFrameStyle(QFrame::HLine);
hr->setLineWidth(3);
hr->setFixedHeight(10);
groupVideoRec->layout()->addWidget(hr, 1, 0, 1, 5);
// label for audio codec
QLabel *labelACodec = new QLabel(groupVideoRec);
labelACodec->setText(QLabel::tr("Audio codec"));
groupVideoRec->layout()->addWidget(labelACodec, 2, 0);
// list of supported audio codecs
comboAudioCodecs = new QComboBox(groupVideoRec);
comboAudioCodecs->setMaxVisibleItems(50);
groupVideoRec->layout()->addWidget(comboAudioCodecs, 2, 1, 1, 3);
// checkbox 'record audio'
checkRecordAudio = new QCheckBox(groupVideoRec);
checkRecordAudio->setText(QCheckBox::tr("Record audio"));
groupVideoRec->layout()->addWidget(checkRecordAudio, 2, 4);
// separator
hr = new QFrame(groupVideoRec);
hr->setFrameStyle(QFrame::HLine);
hr->setLineWidth(3);
hr->setFixedHeight(10);
groupVideoRec->layout()->addWidget(hr, 3, 0, 1, 5);
// label for video codec
QLabel *labelVCodec = new QLabel(groupVideoRec);
labelVCodec->setText(QLabel::tr("Video codec"));
groupVideoRec->layout()->addWidget(labelVCodec, 4, 0);
// list of supported video codecs
comboVideoCodecs = new QComboBox(groupVideoRec);
comboVideoCodecs->setMaxVisibleItems(50);
groupVideoRec->layout()->addWidget(comboVideoCodecs, 4, 1, 1, 4);
// label for resolution
QLabel *labelRes = new QLabel(groupVideoRec);
labelRes->setText(QLabel::tr("Resolution"));
groupVideoRec->layout()->addWidget(labelRes, 5, 0);
// width
widthEdit = new QLineEdit(groupVideoRec);
widthEdit->setValidator(new QIntValidator(this));
groupVideoRec->layout()->addWidget(widthEdit, 5, 1);
// multiplication sign
QLabel *labelX = new QLabel(groupVideoRec);
labelX->setText(tr("x"));
groupVideoRec->layout()->addWidget(labelX, 5, 2);
// height
heightEdit = new QLineEdit(groupVideoRec);
heightEdit->setValidator(new QIntValidator(groupVideoRec));
groupVideoRec->layout()->addWidget(heightEdit, 5, 3);
// checkbox 'use game resolution'
checkUseGameRes = new QCheckBox(groupVideoRec);
checkUseGameRes->setText(QCheckBox::tr("Use game resolution"));
groupVideoRec->layout()->addWidget(checkUseGameRes, 5, 4);
// label for framerate
QLabel *labelFramerate = new QLabel(groupVideoRec);
labelFramerate->setText(QLabel::tr("Framerate"));
groupVideoRec->layout()->addWidget(labelFramerate, 6, 0);
framerateBox = new QComboBox(groupVideoRec);
framerateBox->addItem(QComboBox::tr("24 FPS"), 24);
framerateBox->addItem(QComboBox::tr("25 FPS"), 25);
framerateBox->addItem(QComboBox::tr("30 FPS"), 30);
framerateBox->addItem(QComboBox::tr("50 FPS"), 50);
framerateBox->addItem(QComboBox::tr("60 FPS"), 60);
groupVideoRec->layout()->addWidget(framerateBox, 6, 1);
// label for Bitrate
QLabel *labelBitrate = new QLabel(groupVideoRec);
//: “Kibit/s” is the symbol for 1024 bits per second
labelBitrate->setText(QLabel::tr("Bitrate (Kibit/s)"));
groupVideoRec->layout()->addWidget(labelBitrate, 6, 2);
// bitrate
bitrateBox = new QSpinBox(groupVideoRec);
bitrateBox->setRange(100, 5000);
bitrateBox->setSingleStep(100);
bitrateBox->setWhatsThis(QSpinBox::tr("Specify the bitrate of recorded videos as a multiple of 1024 bits per second"));
groupVideoRec->layout()->addWidget(bitrateBox, 6, 3);
// button 'set default options'
btnDefaults = new QPushButton(groupVideoRec);
btnDefaults->setText(QPushButton::tr("Set default options"));
btnDefaults->setWhatsThis(QPushButton::tr("Restore default coding parameters"));
groupVideoRec->layout()->addWidget(btnDefaults, 7, 0, 1, 5);
}
#endif
previousQuality = this->SLQuality->value();
previousResolutionIndex = this->CBResolution->currentIndex();
previousFullscreenValue = this->CBFullscreen->isChecked();
setFullscreen(CBFullscreen->isChecked());
setVolume(SLVolume->value());
// mutually exclude window and fullscreen resolution
return pageLayout;
}
QLayout * PageOptions::footerLayoutDefinition()
{
return NULL;
}
void PageOptions::connectSignals()
{
#ifdef VIDEOREC
connect(checkUseGameRes, SIGNAL(stateChanged(int)), this, SLOT(changeUseGameRes(int)));
connect(checkRecordAudio, SIGNAL(stateChanged(int)), this, SLOT(changeRecordAudio(int)));
connect(comboAVFormats, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAVFormat(int)));
connect(btnDefaults, SIGNAL(clicked()), this, SLOT(setDefaultOptions()));
#endif
//connect(this, SIGNAL(pageEnter()), this, SLOT(setTeamOptionsEnabled()));
connect(SLVolume, SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
connect(SLQuality, SIGNAL(valueChanged(int)), this, SLOT(setQuality(int)));
connect(CBResolution, SIGNAL(currentIndexChanged(int)), this, SLOT(setResolution(int)));
connect(CBFullscreen, SIGNAL(stateChanged(int)), this, SLOT(setFullscreen(int)));
connect(CBStereoMode, SIGNAL(currentIndexChanged(int)), this, SLOT(forceFullscreen(int)));
connect(editNetNick, SIGNAL(editingFinished()), this, SLOT(trimNetNick()));
connect(CBSavePassword, SIGNAL(stateChanged(int)), this, SLOT(savePwdChanged(int)));
}
void PageOptions::setVolume(int volume)
{
lblVolumeLevel->setText(QString("%1\%").arg(volume));
}
void PageOptions::setupTabPage(QWidget * tabpage, QVBoxLayout ** leftColumn, QVBoxLayout ** rightColumn)
{
QHBoxLayout * twoColumns = new QHBoxLayout(tabpage);
twoColumns->setSpacing(0);
*leftColumn = new QVBoxLayout();
*rightColumn = new QVBoxLayout();
(*leftColumn)->setSpacing(OPTION_BOX_SPACING);
(*rightColumn)->setSpacing(OPTION_BOX_SPACING);
twoColumns->addStretch(4);
twoColumns->addLayout(*leftColumn, 0);
twoColumns->addStretch(1);
twoColumns->addLayout(*rightColumn, 0);
twoColumns->addStretch(4);
}
PageOptions::PageOptions(QWidget* parent) : AbstractPage(parent), config(0)
{
initPage();
}
void PageOptions::forceFullscreen(int index)
{
bool forced = (index == 7 || index == 8 || index == 9);
if (index != 0)
{
this->SLQuality->setValue(this->SLQuality->maximum());
this->SLQuality->setEnabled(false);
this->CBFullscreen->setChecked(forced ? true : previousFullscreenValue);
setFullscreen(forced ? true : previousFullscreenValue);
this->CBResolution->setCurrentIndex(forced ? 0 : previousResolutionIndex);
}
else
{
this->SLQuality->setEnabled(true);
this->SLQuality->setValue(previousQuality);
this->CBFullscreen->setChecked(previousFullscreenValue);
setFullscreen(previousFullscreenValue);
this->CBResolution->setCurrentIndex(previousResolutionIndex);
}
}
void PageOptions::setQuality(int value)
{
Q_UNUSED(value);
int index = this->CBStereoMode->currentIndex();
if (index == 0)
previousQuality = this->SLQuality->value();
}
void PageOptions::setFullscreen(int state)
{
Q_UNUSED(state);
lblFullScreenRes->setVisible(state);
CBResolution->setVisible(state);
lblWinScreenRes->setVisible(!state);
windowWidthEdit->setVisible(!state);
windowHeightEdit->setVisible(!state);
winLabelX->setVisible(!state);
int index = this->CBStereoMode->currentIndex();
if (index != 7 && index != 8 && index != 9)
previousFullscreenValue = this->CBFullscreen->isChecked();
}
void PageOptions::setResolution(int state)
{
Q_UNUSED(state);
int index = this->CBStereoMode->currentIndex();
if (index != 7 && index != 8 && index != 9)
previousResolutionIndex = this->CBResolution->currentIndex();
}
void PageOptions::trimNetNick()
{
editNetNick->setText(editNetNick->text().trimmed());
}
void PageOptions::savePwdChanged(int state) {
if (state == 0) {
editNetPassword->setEnabled(false);
editNetPassword->setText("");
} else
editNetPassword->setEnabled(true);
}
void PageOptions::requestEditSelectedTeam()
{
emit editTeamRequested(CBTeamName->currentText());
}
void PageOptions::requestDeleteSelectedTeam()
{
if(CBTeamName->count() > 1)
emit deleteTeamRequested(CBTeamName->currentText());
else
QMessageBox::warning(this, tr("Can't delete last team"), tr("You can't delete the last team!"));
}
void PageOptions::setTeamOptionsEnabled(bool enabled)
{
BtnNewTeam->setVisible(enabled);
BtnEditTeam->setVisible(enabled);
BtnDeleteTeam->setVisible(enabled);
CBTeamName->setVisible(enabled);
LblNoEditTeam->setVisible(!enabled);
}
void PageOptions::colorButtonClicked(int i)
{
if(i < 0 || i >= m_colorButtons.size())
return;
QPalette p = m_colorButtons[i]->palette();
QColor c = QColorDialog::getColor(p.color(QPalette::Button));
if(c.isValid())
{
DataManager::instance().colorsModel()->item(i)->setData(c);
m_colorButtons[i]->setStyleSheet(QString("background: %1").arg(c.name()));
}
}
void PageOptions::onColorModelDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight)
{
Q_UNUSED(bottomRight);
QStandardItemModel * model = DataManager::instance().colorsModel();
m_colorButtons[topLeft.row()]->setStyleSheet(QString("background: %1").arg(model->item(topLeft.row())->data().value<QColor>().name()));
}
void PageOptions::onProxyTypeChanged()
{
bool b = cbProxyType->currentIndex() != NoProxy && cbProxyType->currentIndex() != SystemProxy ;
sbProxyPort->setEnabled(b);
leProxy->setEnabled(b);
leProxyLogin->setEnabled(b);
leProxyPassword->setEnabled(b);
}
// Video Recording
void PageOptions::setConfig(GameUIConfig * config)
{
this->config = config;
}
// user changed file format, we need to update list of codecs
void PageOptions::changeAVFormat(int index)
{
// remember selected codecs
QString prevVCodec = videoCodec();
QString prevACodec = audioCodec();
// clear lists of codecs
comboVideoCodecs->clear();
comboAudioCodecs->clear();
// get list of codecs for specified format
LibavInteraction::instance().fillCodecs(comboAVFormats->itemData(index).toString(), comboVideoCodecs, comboAudioCodecs);
// disable audio if there is no audio codec
if (comboAudioCodecs->count() == 0)
{
checkRecordAudio->setChecked(false);
checkRecordAudio->setEnabled(false);
}
else
checkRecordAudio->setEnabled(true);
// restore selected codecs if possible
int iVCodec = comboVideoCodecs->findData(prevVCodec);
if (iVCodec != -1)
comboVideoCodecs->setCurrentIndex(iVCodec);
int iACodec = comboAudioCodecs->findData(prevACodec);
if (iACodec != -1)
comboAudioCodecs->setCurrentIndex(iACodec);
}
// user switched checkbox 'use game resolution'
void PageOptions::changeUseGameRes(int state)
{
if (state && config)
{
// set resolution to game resolution
QRect resolution = config->vid_Resolution();
widthEdit->setText(QString::number(resolution.width()));
heightEdit->setText(QString::number(resolution.height()));
}
widthEdit->setEnabled(!state);
heightEdit->setEnabled(!state);
}
// user switched checkbox 'record audio'
void PageOptions::changeRecordAudio(int state)
{
comboAudioCodecs->setEnabled(!!state);
}
void PageOptions::setDefaultCodecs()
{
// VLC should be able to handle any of these configurations
// Quicktime X only opens the first one
// Windows Media Player TODO
if (tryCodecs("mp4", "libx264", "aac"))
return;
if (tryCodecs("mp4", "libx264", "libfaac"))
return;
if (tryCodecs("mp4", "libx264", "libmp3lame"))
return;
if (tryCodecs("mp4", "libx264", "mp2"))
return;
if (tryCodecs("avi", "libxvid", "libmp3lame"))
return;
if (tryCodecs("avi", "libxvid", "ac3_fixed"))
return;
if (tryCodecs("avi", "libxvid", "mp2"))
return;
if (tryCodecs("avi", "mpeg4", "libmp3lame"))
return;
if (tryCodecs("avi", "mpeg4", "ac3_fixed"))
return;
if (tryCodecs("avi", "mpeg4", "mp2"))
return;
// this shouldn't happen, just in case
if (tryCodecs("ogg", "libtheora", "libvorbis"))
return;
tryCodecs("ogg", "libtheora", "flac");
}
void PageOptions::setDefaultOptions()
{
framerateBox->setCurrentIndex(2);
bitrateBox->setValue(1000);
checkRecordAudio->setChecked(true);
checkUseGameRes->setChecked(true);
setDefaultCodecs();
}
void PageOptions::checkForUpdates()
{
AutoUpdater *updater = NULL;
#ifdef __APPLE__
#ifdef SPARKLE_ENABLED
updater = new SparkleAutoUpdater();
#endif
#endif
if (updater)
{
updater->checkForUpdatesNow();
delete updater;
}
}
bool PageOptions::tryCodecs(const QString & format, const QString & vcodec, const QString & acodec)
{
// first we should change format
int iFormat = comboAVFormats->findData(format);
if (iFormat == -1)
return false;
comboAVFormats->setCurrentIndex(iFormat);
// format was changed, so lists of codecs were automatically updated to codecs supported by this format
// try to find video codec
int iVCodec = comboVideoCodecs->findData(vcodec);
if (iVCodec == -1)
return false;
comboVideoCodecs->setCurrentIndex(iVCodec);
// try to find audio codec
int iACodec = comboAudioCodecs->findData(acodec);
if (iACodec == -1 && checkRecordAudio->isChecked())
return false;
if (iACodec != -1)
comboAudioCodecs->setCurrentIndex(iACodec);
return true;
}
// When the current tab is switched
void PageOptions::tabIndexChanged(int index)
{
if (index == binderTab) // Switched to bind tab
{
binder->resetInterface();
if (!config) return;
QStandardItemModel * binds = DataManager::instance().bindsModel();
for(int i = 0; i < BINDS_NUMBER; i++)
{
QString value = config->bind(i);
QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, value, 1, Qt::MatchExactly);
if(mdl.size() == 1) binder->setBindIndex(i, mdl[0].row());
}
binder->checkConflicts();
}
currentTab = index;
}
// When a key bind combobox is changed
void PageOptions::bindUpdated(int bindID)
{
int bindIndex = binder->bindIndex(bindID);
if (bindIndex == 0) bindIndex = resetBindToDefault(bindID);
// Save bind
QStandardItemModel * binds = DataManager::instance().bindsModel();
QString strbind = binds->index(binder->bindIndex(bindID), 0).data(Qt::UserRole + 1).toString();
config->setBind(bindID, strbind);
}
// Changes a key bind (bindID) to its default value. This updates the bind's combo-box in the UI.
// Returns: The bind model index of the default.
int PageOptions::resetBindToDefault(int bindID)
{
if (QString(cbinds[bindID].action) == QString("!MULTI"))
return -1;
QStandardItemModel * binds = DataManager::instance().bindsModel();
QModelIndexList mdl = binds->match(binds->index(0, 0), Qt::UserRole + 1, cbinds[bindID].strbind, 1, Qt::MatchExactly);
if(mdl.size() == 1)
binder->setBindIndex(bindID, mdl[0].row());
return mdl[0].row();
}
// Called when "reset all binds" button is pressed
void PageOptions::resetAllBinds()
{
for (int i = 0; i < BINDS_NUMBER; i++)
{
int ret = resetBindToDefault(i);
if(ret != -1)
bindUpdated(i);
}
binder->checkConflicts();
}