QTfrontend/ui/page/pageoptions.cpp
author sheepluva
Mon, 05 Aug 2019 00:20:45 +0200
changeset 15295 f382ec6dba11
parent 15247 647157250713
child 15283 c4fd2813b127
child 15438 e7c059ac6e54
permissions -rw-r--r--
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();
}