GCI2012: Improve Game Configuration Widget
authordag10
Mon, 14 Jan 2013 11:19:59 +0100
changeset 8377 869f80966a77
parent 8376 c11cc7246df7
child 8378 3a298d487ddd
GCI2012: Improve Game Configuration Widget - Refactored mapmodel+datamanager to have two separate map models for static and mission maps, and then three static MapInfos in MapModel for the three special maps (random, maze, drawn). - Created theme selector dialog. - Created seed view/edit dialog. - Enlarged start icon on pagemultiplayer and pagenetgame, and added Start.png. - Moved "Settings" button on pagemultiplayer and pagenetgame from middle of page to page footer. - Added "load drawing" button to mapcontainer widget. - Map preview is no longer the randomize button; The randomize functionality is now in a button of its own. - Map preview no longer grays out (isn't disabled) when in slave mode. - Seed is now viewable and copyable when in slave mode -- but not editable. - You should now use the property master (isMaster() and setMaster()) on gamecfgwidget and mapcontainer instead of the enabled property. This is because some widgets (e.g. "view/edit seed" button and map preview) shouldn't be disabled, when all other widgets should be. - Added mission map descriptions w/ locale support in INI format in mapname/desc.txt if applicable. Use '|' for line break.
QTfrontend/hedgewars.qrc
QTfrontend/hwform.cpp
QTfrontend/model/MapModel.cpp
QTfrontend/model/MapModel.h
QTfrontend/model/ThemeModel.cpp
QTfrontend/model/roomslistmodel.cpp
QTfrontend/model/roomslistmodel.h
QTfrontend/res/Start.png
QTfrontend/res/css/qt.css
QTfrontend/ui/page/AbstractPage.cpp
QTfrontend/ui/page/AbstractPage.h
QTfrontend/ui/page/pagemultiplayer.cpp
QTfrontend/ui/page/pagemultiplayer.h
QTfrontend/ui/page/pagenetgame.cpp
QTfrontend/ui/page/pagenetgame.h
QTfrontend/ui/widget/flowlayout.cpp
QTfrontend/ui/widget/flowlayout.h
QTfrontend/ui/widget/gamecfgwidget.cpp
QTfrontend/ui/widget/gamecfgwidget.h
QTfrontend/ui/widget/mapContainer.cpp
QTfrontend/ui/widget/mapContainer.h
QTfrontend/ui/widget/seedprompt.cpp
QTfrontend/ui/widget/seedprompt.h
QTfrontend/ui/widget/themeprompt.cpp
QTfrontend/ui/widget/themeprompt.h
QTfrontend/util/DataManager.cpp
QTfrontend/util/DataManager.h
share/hedgewars/Data/Maps/Basketball/CMakeLists.txt
share/hedgewars/Data/Maps/Basketball/desc.txt
share/hedgewars/Data/Maps/Basketball/map.cfg
share/hedgewars/Data/Maps/CTF_Blizzard/CMakeLists.txt
share/hedgewars/Data/Maps/CTF_Blizzard/desc.txt
share/hedgewars/Data/Maps/Control/CMakeLists.txt
share/hedgewars/Data/Maps/Control/desc.txt
share/hedgewars/Data/Maps/Control/map.cfg
share/hedgewars/Data/Maps/Knockball/CMakeLists.txt
share/hedgewars/Data/Maps/Knockball/desc.txt
share/hedgewars/Data/Maps/TrophyRace/CMakeLists.txt
share/hedgewars/Data/Maps/TrophyRace/desc.txt
--- a/QTfrontend/hedgewars.qrc	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/hedgewars.qrc	Mon Jan 14 11:19:59 2013 +0100
@@ -131,6 +131,7 @@
         <file>res/StatsMostSelfDamage.png</file>
         <file>res/StatsSelfKilled.png</file>
         <file>res/StatsSkipped.png</file>
+        <file>res/Start.png</file>
         <file>res/mapRandom.png</file>
         <file>res/mapMaze.png</file>
         <file>res/mapMissing.png</file>
--- a/QTfrontend/hwform.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/hwform.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -1714,7 +1714,7 @@
 
 void HWForm::NetGameChangeStatus(bool isMaster)
 {
-    ui.pageNetGame->pGameCFG->setEnabled(isMaster);
+    ui.pageNetGame->pGameCFG->setMaster(isMaster);
     ui.pageNetGame->pNetTeamsWidget->setInteractivity(isMaster);
 
     if (isMaster)
@@ -1729,7 +1729,7 @@
     ui.pageNetGame->restrictJoins->setChecked(false);
     ui.pageNetGame->restrictTeamAdds->setChecked(false);
     ui.pageNetGame->pGameCFG->GameSchemes->setModel(ammoSchemeModel);
-    ui.pageNetGame->pGameCFG->setEnabled(true);
+    ui.pageNetGame->pGameCFG->setMaster(true);
     ui.pageNetGame->pNetTeamsWidget->setInteractivity(true);
 
     if (hwnet)
@@ -1757,7 +1757,7 @@
 
 void HWForm::NetGameSlave()
 {
-    ui.pageNetGame->pGameCFG->setEnabled(false);
+    ui.pageNetGame->pGameCFG->setMaster(false);
     ui.pageNetGame->pNetTeamsWidget->setInteractivity(false);
 
     if (hwnet)
--- a/QTfrontend/model/MapModel.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/model/MapModel.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -22,9 +22,15 @@
  */
 
 #include "MapModel.h"
+#include "hwapplication.h"
 
+#include <QSettings>
 
-void MapModel::loadMaps()
+MapModel::MapInfo MapModel::MapInfoRandom = {MapModel::GeneratedMap, "+rnd+", "", 0, "", "", ""};
+MapModel::MapInfo MapModel::MapInfoMaze = {MapModel::GeneratedMaze, "+maze+", "", 0, "", "", ""};
+MapModel::MapInfo MapModel::MapInfoDrawn = {MapModel::HandDrawnMap, "+drawn+", "", 0, "", "", ""};
+
+void MapModel::loadMaps(MapType maptype)
 {
     // this method resets the contents of this model (important to know for views).
     beginResetModel();
@@ -39,19 +45,9 @@
     // empty list, so that we can (re)fill it
     QStandardItemModel::clear();
 
-    QList<QStandardItem *> genMaps;
-    QList<QStandardItem *> missionMaps;
-    QList<QStandardItem *> staticMaps;
-
-    // add generated/handdrawn maps to list
-    // TODO: icons for these
-
-    genMaps.append(
-        infoToItem(QIcon(), QComboBox::tr("generated map..."), GeneratedMap, "+rnd+"));
-    genMaps.append(
-        infoToItem(QIcon(), QComboBox::tr("generated maze..."), GeneratedMaze, "+maze+"));
-    genMaps.append(
-        infoToItem(QIcon(), QComboBox::tr("hand drawn map..."), HandDrawnMap, "+drawn+"));
+    //QList<QStandardItem *> staticMaps;
+    //QList<QStandardItem *> missionMaps;
+    QList<QStandardItem *> mapList;
 
     // only 2 map relate files are relevant:
     // - the cfg file that contains the settings/info of the map
@@ -64,7 +60,7 @@
     {
         mapCfgFile.setFileName(QString("physfs://Maps/%1/map.cfg").arg(map));
         mapLuaFile.setFileName(QString("physfs://Maps/%1/map.lua").arg(map));
-
+        QSettings descSettings(QString("physfs://Maps/%1/desc.txt").arg(map), QSettings::IniFormat);
 
         if (mapCfgFile.open(QFile::ReadOnly))
         {
@@ -73,25 +69,36 @@
             quint32 limit = 0;
             QString scheme;
             QString weapons;
+            QString desc;
+
             // if there is a lua file for this map, then it's a mission
             bool isMission = mapLuaFile.exists();
-            MapType type = isMission?MissionMap:StaticMap;
+            MapType type = isMission ? MissionMap : StaticMap;
+
+            // If we're supposed to ignore this type, continue
+            if (type != maptype) continue;
 
             // load map info from file
             QTextStream input(&mapCfgFile);
-            input >> theme;
-            input >> limit;
+            theme = input.readLine();
+            limit = input.readLine().toInt();
             if (isMission) { // scheme and weapons are only relevant for missions
-                input >> scheme;
-                input >> weapons;
+                scheme = input.readLine();
+                weapons = input.readLine();
             }
             mapCfgFile.close();
 
+            // Load description (if applicable)
+            if (isMission)
+            {
+                QString locale = HWApplication::keyboardInputLocale().name();
+                desc = descSettings.value(locale, QString()).toString().replace("|", "\n");
+            }
+
             // let's use some semi-sane hedgehog limit, rather than none
             if (limit == 0)
                 limit = 18;
 
-
             // the default scheme/weaponset for missions.
             // if empty we assume the map sets these internally -> locked
             if (isMission)
@@ -107,97 +114,54 @@
                     weapons.replace("_", " ");
             }
 
-            // add a mission caption prefix to missions
-            if (isMission)
-            {
-                // TODO: icon
-                caption = QComboBox::tr("Mission") + ": " + map;
-            }
-            else
-                caption = map;
+            // caption
+            caption = map;
 
             // we know everything there is about the map, let's get am item for it
-            QStandardItem * item = infoToItem(
-                QIcon(), caption, type, map, theme, limit, scheme, weapons);
+            QStandardItem * item = MapModel::infoToItem(
+                QIcon(), caption, type, map, theme, limit, scheme, weapons, desc);
 
             // append item to the list
-            if (isMission)
-                missionMaps.append(item);
-            else
-                staticMaps.append(item);
-        
+            mapList.append(item);
         }
 
     }
 
-
-    // define a separator item
-    QStandardItem separator("---");
-    separator.setData(QLatin1String("separator"), Qt::AccessibleDescriptionRole);
-    separator.setFlags(separator.flags() & ~( Qt::ItemIsEnabled | Qt::ItemIsSelectable ) );
-
-    // create list:
-    // generated+handdrawn maps, 2 saperators, missions, 1 separator, static maps
-    QList<QStandardItem * > items;
-    items.append(genMaps);
-    items.append(separator.clone());
-    items.append(separator.clone());
-    items.append(missionMaps);
-    items.append(separator.clone());
-    items.append(staticMaps);
-
-
-    // create row-index lookup table
+    // Create column-index lookup table
 
     m_mapIndexes.clear();
 
-    int count = items.size();
 
+    int count = mapList.size();
     for (int i = 0; i < count; i++)
     {
-        QStandardItem * si = items.at(i);
+        QStandardItem * si = mapList.at(i);
         QVariant v = si->data(Qt::UserRole + 1);
         if (v.canConvert<MapInfo>())
             m_mapIndexes.insert(v.value<MapInfo>().name, i);
     }
 
-
-    // store start-index and count of relevant types
-
-    m_typeLoc.insert(GeneratedMap, QPair<int,int>(0, 1));
-    m_typeLoc.insert(GeneratedMaze, QPair<int,int>(1, 1));
-    m_typeLoc.insert(HandDrawnMap, QPair<int,int>(2, 1));
-    // mission maps
-    int startIdx = genMaps.size() + 2; // start after genMaps and 2 separators
-    count = missionMaps.size();
-    m_typeLoc.insert(MissionMap, QPair<int,int>(startIdx, count));
-    // static maps
-    startIdx += count + 1; // start after missions and 2 separators
-    count = staticMaps.size();
-    m_typeLoc.insert(StaticMap, QPair<int,int>(startIdx, count));
-
-    // store list contents in the item model
-    QStandardItemModel::appendColumn(items);
-
+    QStandardItemModel::appendColumn(mapList);
 
     endResetModel();
 }
 
-
-int MapModel::randomMap(MapType type) const
+bool MapModel::mapExists(const QString & map) const
 {
-    // return a random index for this type or -1 if none available
-    QPair<int,int> loc = m_typeLoc.value(type, QPair<int,int>(-1,0));
-
-    int startIdx = loc.first;
-    int count = loc.second;
-
-    if (count < 1)
-        return -1;
-    else
-        return startIdx + (rand() % count);
+    return findMap(map) >= 0;
 }
 
+int MapModel::findMap(const QString & map) const
+{
+    return m_mapIndexes.value(map, -1);
+}
+
+QStandardItem * MapModel::getMap(const QString & map)
+{
+    int loc = findMap(map);
+    if (loc < 0) return NULL;
+    return item(loc);
+}
 
 QStandardItem * MapModel::infoToItem(
     const QIcon & icon,
@@ -207,8 +171,8 @@
     QString theme,
     quint32 limit,
     QString scheme,
-    QString weapons)
-const
+    QString weapons,
+    QString desc)
 {
     QStandardItem * item = new QStandardItem(icon, caption);
     MapInfo mapInfo;
@@ -220,17 +184,10 @@
     mapInfo.limit = limit;
     mapInfo.scheme = scheme;
     mapInfo.weapons = weapons;
-
+    mapInfo.desc = desc.isEmpty() ? tr("No description available.") : desc;
 
     qvar.setValue(mapInfo);
     item->setData(qvar, Qt::UserRole + 1);
 
     return item;
 }
-
-
-int MapModel::indexOf(const QString & map) const
-{
-    return m_mapIndexes.value(map, -1);
-}
-
--- a/QTfrontend/model/MapModel.h	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/model/MapModel.h	Mon Jan 14 11:19:59 2013 +0100
@@ -63,32 +63,49 @@
             quint32 limit; ///< The maximum allowed number of hedgehogs.
             QString scheme; ///< Default scheme name or "locked", for mission-maps.
             QString weapons; ///< Default weaponset name or "locked", for missions-maps.
+            QString desc; ///< The brief 1-2 sentence description of the mission, for mission-maps.
         };
 
         /**
-         * @brief Returns the row-index of the given map.
-         * @param map map of which to get the row-index of.
-         * @return row-index of map or -1 if not available.
+         * @brief Searches maps in model to find out if one exists
+         * @param map map of which to check existence
+         * @return true if it exists
          */
-        int indexOf(const QString & map) const;
+        bool mapExists(const QString & map) const;
+
+        /**
+         * @brief Finds a map index (column, row) for a map name
+         * @param map map of which to find index+column
+         * @return QPair<int, int> with column, index, or (-1, -1) if map not found
+         */
+        //QPair<int, int> findMap(const QString & map) const;
 
         /**
-         * @brief Returns the row-index of a random map with a specified type.
-         * @param type desired type of map.
-         * @return row-index of a map with the desired type, -1 if none found.
+         * @brief Finds a map index for a map name
+         * @param map map of which to find index
+         * @return int of index, or -1 if map not found
          */
-        int randomMap(MapType type) const;
+        int findMap(const QString & map) const;
+
+        /**
+         * @brief Finds and returns a map item for a map name
+         * @param map map
+         * @return QStandardItem of map, or NULL if map not found
+         */
+        QStandardItem * getMap(const QString & map);
+
+        // Static MapInfos for drawn and generated maps
+        static MapInfo MapInfoRandom, MapInfoMaze, MapInfoDrawn;
 
     public slots:
         /// Reloads the maps using the DataManager.
-        void loadMaps();
+        /// Accepts two map types: StaticMap or MissionMap.
+        void loadMaps(MapType maptype);
 
 
     private:
-        /// start-index and map count for each map-type.
-        QMap<MapType, QPair<int,int> > m_typeLoc;
-
-        /// map index lookup table
+        /// map index lookup table. QPair<int, int> contains: <column, index>
+        //QHash<QString, QPair<int, int> > m_mapIndexes;
         QHash<QString, int> m_mapIndexes;
 
         /**
@@ -102,9 +119,10 @@
          * @param limit the hedgehog limit of the map.
          * @param scheme mission map: default scheme name or "locked".
          * @param weapons mission map: default weaponset name or "locked".
+         * @param desc mission map: description of mission.
          * @return pointer to item representing the map info: at Qt::UserRole + 1.
          */
-        QStandardItem * infoToItem(
+        static QStandardItem * infoToItem(
             const QIcon & icon,
             const QString caption,
             MapType type = Invalid,
@@ -112,7 +130,8 @@
             QString theme = "",
             quint32 limit = 0,
             QString scheme = "",
-            QString weapons = "") const;
+            QString weapons = "",
+            QString desc = "");
 };
 
 Q_DECLARE_METATYPE(MapModel::MapInfo)
--- a/QTfrontend/model/ThemeModel.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/model/ThemeModel.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -73,11 +73,16 @@
 
         QMap<int, QVariant> dataset;
 
+        // set icon path
+        dataset.insert(Qt::UserRole + 1, iconpath);
+
         // set name
         dataset.insert(Qt::DisplayRole, theme);
 
         // load and set icon
-        QIcon icon(iconpath);
+        QIcon icon;
+        icon.addPixmap(QPixmap(iconpath), QIcon::Normal);
+        icon.addPixmap(QPixmap(iconpath), QIcon::Disabled);
 
         dataset.insert(Qt::DecorationRole, icon);
 
--- a/QTfrontend/model/roomslistmodel.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/model/roomslistmodel.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -43,7 +43,8 @@
      << tr("Rules")
      << tr("Weapons");
 
-    m_mapModel = DataManager::instance().mapModel();
+    m_staticMapModel = DataManager::instance().staticMapModel();
+    m_missionMapModel = DataManager::instance().missionMapModel();
 }
 
 
@@ -134,7 +135,8 @@
             }
 
             // prefix ? if map not available
-            if ((m_mapModel->indexOf(content) < 0))
+            if (!m_staticMapModel->mapExists(content) &&
+                !m_missionMapModel->mapExists(content))
                 return QString ("? %1").arg(content);
         }
 
@@ -144,10 +146,14 @@
     // dye map names red if map not available
     if (role == Qt::ForegroundRole)
     {
-        if ((m_mapModel->indexOf(content) < 0))
+        if (content == "+rnd+" ||
+            content == "+maze+" ||
+            content == "+drawn+" ||
+            m_staticMapModel->mapExists(content) ||
+            m_missionMapModel->mapExists(content))
+            return QVariant();
+        else
             return QBrush(QColor("darkred"));
-        else
-            return QVariant();
     }
 
     if (role == Qt::TextAlignmentRole)
--- a/QTfrontend/model/roomslistmodel.h	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/model/roomslistmodel.h	Mon Jan 14 11:19:59 2013 +0100
@@ -64,7 +64,8 @@
     const int c_nColumns;
     QList<QStringList> m_data;
     QStringList m_headerData;
-    MapModel * m_mapModel;
+    MapModel * m_staticMapModel;
+    MapModel * m_missionMapModel;
 
     QStringList roomInfo2RoomRecord(const QStringList & info);
 };
Binary file QTfrontend/res/Start.png has changed
--- a/QTfrontend/res/css/qt.css	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/res/css/qt.css	Mon Jan 14 11:19:59 2013 +0100
@@ -45,7 +45,7 @@
 QTextBrowser, QSpinBox, QToolBox, QComboBox, QPlainTextEdit,
 QComboBox QAbstractItemView, IconedGroupBox,
 .QGroupBox, GameCFGWidget, TeamSelWidget, SelWeaponWidget,
-QTabWidget::pane, QTabBar::tab {
+QTabWidget::pane, QTabBar::tab, #mapPreview {
 border: solid;
 border-width: 3px;
 border-color: #ffcc00;
@@ -56,8 +56,20 @@
 border-color: yellow;
 }
 
+QToolButton {
+background-color: #11084A;
+}
+
+QToolButton:hover {
+background-color: #150A61;
+}
+
+QToolButton:pressed {
+background-color: #100744;
+}
+
 QLineEdit, QListWidget, QListView, QTableView, QTextBrowser,
-QSpinBox, QToolBox, QPlainTextEdit {
+QSpinBox, QToolBox, QPlainTextEdit, QToolButton, #mapPreview {
 border-radius: 10px;
 }
 
@@ -97,7 +109,7 @@
 background-color: rgba(18, 42, 5, 70%);
 }
 
-QPushButton:pressed{
+QPushButton:pressed, QToolButton:pressed {
 border-color: white;
 }
 
--- a/QTfrontend/ui/page/AbstractPage.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/page/AbstractPage.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -41,9 +41,10 @@
     QGridLayout * pageLayout = new QGridLayout(this);
 
     // stretch grid space for body and footer
-    pageLayout->setColumnStretch(0,1);
-    pageLayout->setColumnStretch(1,2);
+    pageLayout->setColumnStretch(0,0);
+    pageLayout->setColumnStretch(1,0);
     pageLayout->setColumnStretch(2,1);
+    pageLayout->setColumnStretch(3,0);
     pageLayout->setRowStretch(0,1);
     pageLayout->setRowStretch(1,0);
 
@@ -53,7 +54,12 @@
     pageLayout->addWidget(btnBack, 1, 0, 1, 1, Qt::AlignLeft | Qt::AlignBottom);
 
     // add body layout as defined by the subclass
-    pageLayout->addLayout(bodyLayoutDefinition(), 0, 0, 1, 3);
+    pageLayout->addLayout(bodyLayoutDefinition(), 0, 0, 1, 4);
+
+    // add left footer layout
+    QLayout * flld = footerLayoutLeftDefinition();
+    if (flld != NULL)
+        pageLayout->addLayout(flld, 1, 1);
 
     descLabel = new QLabel();
     descLabel->setAlignment(Qt::AlignCenter);
@@ -61,12 +67,12 @@
     descLabel->setOpenExternalLinks(true);
     descLabel->setFixedHeight(50);
     descLabel->setStyleSheet("font-size: 16px");
-    pageLayout->addWidget(descLabel, 1, 1);
+    pageLayout->addWidget(descLabel, 1, 2);
 
     // add footer layout
     QLayout * fld = footerLayoutDefinition();
     if (fld != NULL)
-        pageLayout->addLayout(fld, 1, 2);
+        pageLayout->addLayout(fld, 1, 3);
 
     // connect signals
     connect(btnBack, SIGNAL(clicked()), this, SIGNAL(goBack()));
--- a/QTfrontend/ui/page/AbstractPage.h	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/page/AbstractPage.h	Mon Jan 14 11:19:59 2013 +0100
@@ -121,6 +121,17 @@
          * @brief Used during page construction.
          * You can implement this method in your subclass.
          *
+         * Use it to define layout (not behavior) of the page's footer to the left of the help text.
+         */
+        virtual QLayout * footerLayoutLeftDefinition()
+        {
+            return NULL;
+        };
+
+        /**
+         * @brief Used during page construction.
+         * You can implement this method in your subclass.
+         *
          * This is a good place to connect signals within your page in order
          * to get the desired page behavior.<br />
          * Keep in mind not to expose twidgets as public!
--- a/QTfrontend/ui/page/pagemultiplayer.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/page/pagemultiplayer.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -36,10 +36,6 @@
     gameCFG = new GameCFGWidget(this);
     pageLayout->addWidget(gameCFG, 0, 0, 1, 2);
 
-    btnSetup = new QPushButton(this);
-    btnSetup->setText(QPushButton::tr("Setup"));
-    pageLayout->addWidget(btnSetup, 1, 0, 1, 2);
-
     pageLayout->setRowStretch(2, 1);
 
     teamsSelect = new TeamSelWidget(this);
@@ -48,12 +44,30 @@
     return pageLayout;
 }
 
+QLayout * PageMultiplayer::footerLayoutLeftDefinition()
+{
+    QHBoxLayout * bottomLeftLayout = new QHBoxLayout();
+    
+    btnSetup = addButton(":/res/Settings.png", bottomLeftLayout, 0, true);
+    btnSetup->setWhatsThis(tr("Edit game preferences"));
+
+    return bottomLeftLayout;
+}
+
 QLayout * PageMultiplayer::footerLayoutDefinition()
 {
     QHBoxLayout * footerLayout = new QHBoxLayout();
 
-    BtnStartMPGame = formattedButton(tr("Start"));
-    BtnStartMPGame->setMinimumWidth(180);
+    const QIcon& lp = QIcon(":/res/Start.png");
+    QSize sz = lp.actualSize(QSize(65535, 65535));
+    BtnStartMPGame = new QPushButton();
+    BtnStartMPGame->setText(tr("Start"));
+    BtnStartMPGame->setMinimumWidth(sz.width() + 60);
+    BtnStartMPGame->setIcon(lp);
+    BtnStartMPGame->setFixedHeight(50);
+    BtnStartMPGame->setIconSize(sz);
+    BtnStartMPGame->setFlat(true);
+    BtnStartMPGame->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 
     footerLayout->addStretch();
     footerLayout->addWidget(BtnStartMPGame);
--- a/QTfrontend/ui/page/pagemultiplayer.h	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/page/pagemultiplayer.h	Mon Jan 14 11:19:59 2013 +0100
@@ -41,6 +41,7 @@
     private:
         QLayout * bodyLayoutDefinition();
         QLayout * footerLayoutDefinition();
+        QLayout * footerLayoutLeftDefinition();
         void connectSignals();
 
         QPushButton * btnSetup;
--- a/QTfrontend/ui/page/pagenetgame.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/page/pagenetgame.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -40,24 +40,31 @@
     chatWidget = new HWChatWidget(this, true);
     chatWidget->setShowFollow(false); // don't show follow in nicks' context menus
     chatWidget->setIgnoreListKick(true); // kick ignored players automatically
-    pageLayout->addWidget(chatWidget, 2, 0, 1, 2);
-    pageLayout->setRowStretch(1, 100);
-    pageLayout->setRowStretch(2, 100);
+    pageLayout->addWidget(chatWidget, 1, 0, 1, 2);
+    pageLayout->setRowStretch(0, 0);
+    pageLayout->setRowStretch(1, 0);
 
     pGameCFG = new GameCFGWidget(this);
     pageLayout->addWidget(pGameCFG, 0, 0);
 
-    btnSetup = new QPushButton(this);
-    btnSetup->setText(QPushButton::tr("Setup"));
-    pageLayout->addWidget(btnSetup, 1, 0);
-
     pNetTeamsWidget = new TeamSelWidget(this);
     pNetTeamsWidget->setAcceptOuter(true);
-    pageLayout->addWidget(pNetTeamsWidget, 0, 1, 2, 1);
+    pNetTeamsWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+    pageLayout->addWidget(pNetTeamsWidget, 0, 1, 1, 1);
 
     return pageLayout;
 }
 
+QLayout * PageNetGame::footerLayoutLeftDefinition()
+{
+    QHBoxLayout * bottomLeftLayout = new QHBoxLayout();
+    
+    btnSetup = addButton(":/res/Settings.png", bottomLeftLayout, 0, true);
+    btnSetup->setWhatsThis(tr("Edit game preferences"));
+
+    return bottomLeftLayout;
+}
+
 QLayout * PageNetGame::footerLayoutDefinition()
 {
     QHBoxLayout * bottomLayout = new QHBoxLayout;
@@ -84,7 +91,17 @@
     BtnMaster = addButton(tr("Control"), bottomLayout, 3);
     bottomLayout->insertStretch(3, 100);
 
-    BtnStart = addButton(QAction::tr("Start"), bottomLayout, 3);
+    const QIcon& lp = QIcon(":/res/Start.png");
+    QSize sz = lp.actualSize(QSize(65535, 65535));
+    BtnStart = new QPushButton();
+    BtnStart->setText(tr("Start"));
+    BtnStart->setMinimumWidth(sz.width() + 60);
+    BtnStart->setIcon(lp);
+    BtnStart->setFixedHeight(50);
+    BtnStart->setIconSize(sz);
+    BtnStart->setFlat(true);
+    BtnStart->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    bottomLayout->addWidget(BtnStart);
 
     return bottomLayout;
 }
--- a/QTfrontend/ui/page/pagenetgame.h	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/page/pagenetgame.h	Mon Jan 14 11:19:59 2013 +0100
@@ -70,6 +70,7 @@
     private:
         QLayout * bodyLayoutDefinition();
         QLayout * footerLayoutDefinition();
+        QLayout * footerLayoutLeftDefinition();
         void connectSignals();
 
         HistoryLineEdit * leRoomName;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/flowlayout.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,190 @@
+ /****************************************************************************
+ **
+ ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ ** All rights reserved.
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ **   * Redistributions of source code must retain the above copyright
+ **     notice, this list of conditions and the following disclaimer.
+ **   * Redistributions in binary form must reproduce the above copyright
+ **     notice, this list of conditions and the following disclaimer in
+ **     the documentation and/or other materials provided with the
+ **     distribution.
+ **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ **     the names of its contributors may be used to endorse or promote
+ **     products derived from this software without specific prior written
+ **     permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+ #include <QtGui>
+
+ #include "flowlayout.h"
+ 
+ FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
+     : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
+ {
+     setContentsMargins(margin, margin, margin, margin);
+ }
+
+ FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
+     : m_hSpace(hSpacing), m_vSpace(vSpacing)
+ {
+     setContentsMargins(margin, margin, margin, margin);
+ }
+
+ FlowLayout::~FlowLayout()
+ {
+     QLayoutItem *item;
+     while ((item = takeAt(0)))
+         delete item;
+ }
+
+ void FlowLayout::addItem(QLayoutItem *item)
+ {
+     itemList.append(item);
+ }
+
+ int FlowLayout::horizontalSpacing() const
+ {
+     if (m_hSpace >= 0) {
+         return m_hSpace;
+     } else {
+         return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
+     }
+ }
+
+ int FlowLayout::verticalSpacing() const
+ {
+     if (m_vSpace >= 0) {
+         return m_vSpace;
+     } else {
+         return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
+     }
+ }
+
+ int FlowLayout::count() const
+ {
+     return itemList.size();
+ }
+
+ QLayoutItem *FlowLayout::itemAt(int index) const
+ {
+     return itemList.value(index);
+ }
+
+ QLayoutItem *FlowLayout::takeAt(int index)
+ {
+     if (index >= 0 && index < itemList.size())
+         return itemList.takeAt(index);
+     else
+         return 0;
+ }
+
+ Qt::Orientations FlowLayout::expandingDirections() const
+ {
+     return 0;
+ }
+
+ bool FlowLayout::hasHeightForWidth() const
+ {
+     return true;
+ }
+
+ int FlowLayout::heightForWidth(int width) const
+ {
+     int height = doLayout(QRect(0, 0, width, 0), true);
+     return height;
+ }
+
+ void FlowLayout::setGeometry(const QRect &rect)
+ {
+     QLayout::setGeometry(rect);
+     doLayout(rect, false);
+ }
+
+ QSize FlowLayout::sizeHint() const
+ {
+     return minimumSize();
+ }
+
+ QSize FlowLayout::minimumSize() const
+ {
+     QSize size;
+     QLayoutItem *item;
+     foreach (item, itemList)
+         size = size.expandedTo(item->minimumSize());
+
+     size += QSize(2*margin(), 2*margin());
+     return size;
+ }
+
+ int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
+ {
+     int left, top, right, bottom;
+     getContentsMargins(&left, &top, &right, &bottom);
+     QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
+     int x = effectiveRect.x();
+     int y = effectiveRect.y();
+     int lineHeight = 0;
+
+     QLayoutItem *item;
+     foreach (item, itemList) {
+         QWidget *wid = item->widget();
+         int spaceX = horizontalSpacing();
+         if (spaceX == -1)
+             spaceX = wid->style()->layoutSpacing(
+                 QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
+         int spaceY = verticalSpacing();
+         if (spaceY == -1)
+             spaceY = wid->style()->layoutSpacing(
+                 QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
+         int nextX = x + item->sizeHint().width() + spaceX;
+         if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
+             x = effectiveRect.x();
+             y = y + lineHeight + spaceY;
+             nextX = x + item->sizeHint().width() + spaceX;
+             lineHeight = 0;
+         }
+
+         if (!testOnly)
+             item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
+
+         x = nextX;
+         lineHeight = qMax(lineHeight, item->sizeHint().height());
+     }
+     return y + lineHeight - rect.y() + bottom;
+ }
+ int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
+ {
+     QObject *parent = this->parent();
+     if (!parent) {
+         return -1;
+     } else if (parent->isWidgetType()) {
+         QWidget *pw = static_cast<QWidget *>(parent);
+         return pw->style()->pixelMetric(pm, 0, pw);
+     } else {
+         return static_cast<QLayout *>(parent)->spacing();
+     }
+ }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/flowlayout.h	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,77 @@
+ /****************************************************************************
+ **
+ ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ ** All rights reserved.
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ **   * Redistributions of source code must retain the above copyright
+ **     notice, this list of conditions and the following disclaimer.
+ **   * Redistributions in binary form must reproduce the above copyright
+ **     notice, this list of conditions and the following disclaimer in
+ **     the documentation and/or other materials provided with the
+ **     distribution.
+ **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ **     the names of its contributors may be used to endorse or promote
+ **     products derived from this software without specific prior written
+ **     permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+ #ifndef FLOWLAYOUT_H
+ #define FLOWLAYOUT_H
+
+ #include <QLayout>
+ #include <QRect>
+ #include <QStyle>
+ #include <QWidgetItem>
+ class FlowLayout : public QLayout
+ {
+ public:
+     FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
+     FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
+     ~FlowLayout();
+
+     void addItem(QLayoutItem *item);
+     int horizontalSpacing() const;
+     int verticalSpacing() const;
+     Qt::Orientations expandingDirections() const;
+     bool hasHeightForWidth() const;
+     int heightForWidth(int) const;
+     int count() const;
+     QLayoutItem *itemAt(int index) const;
+     QSize minimumSize() const;
+     void setGeometry(const QRect &rect);
+     QSize sizeHint() const;
+     QLayoutItem *takeAt(int index);
+
+ private:
+     int doLayout(const QRect &rect, bool testOnly) const;
+     int smartSpacing(QStyle::PixelMetric pm) const;
+
+     QList<QLayoutItem *> itemList;
+     int m_hSpace;
+     int m_vSpace;
+ };
+
+ #endif
\ No newline at end of file
--- a/QTfrontend/ui/widget/gamecfgwidget.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/widget/gamecfgwidget.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -25,6 +25,8 @@
 #include <QMessageBox>
 #include <QTableView>
 #include <QPushButton>
+#include <QDebug>
+#include <QList>
 
 #include "gamecfgwidget.h"
 #include "igbox.h"
@@ -33,6 +35,7 @@
 #include "ammoSchemeModel.h"
 #include "proto.h"
 #include "GameStyleModel.h"
+#include "themeprompt.h"
 
 GameCFGWidget::GameCFGWidget(QWidget* parent) :
     QGroupBox(parent)
@@ -40,13 +43,16 @@
     , seedRegexp("\\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\}")
 {
     mainLayout.setMargin(0);
-//  mainLayout.setSizeConstraint(QLayout::SetMinimumSize);
 
     pMapContainer = new HWMapContainer(this);
-    mainLayout.addWidget(pMapContainer, 0, 0);
+    mainLayout.addWidget(pMapContainer, 0, 0, Qt::AlignHCenter | Qt::AlignTop);
+    pMapContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    pMapContainer->setFixedSize(460, 275);
 
     IconedGroupBox *GBoxOptions = new IconedGroupBox(this);
-    GBoxOptions->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+    m_childWidgets << GBoxOptions;
+    GBoxOptions->setFixedWidth(pMapContainer->width());
+    GBoxOptions->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
     mainLayout.addWidget(GBoxOptions, 1, 0);
 
     QGridLayout *GBoxOptionsLayout = new QGridLayout(GBoxOptions);
@@ -174,7 +180,7 @@
     if (schemeData(18).toBool())
         result |= 0x00080000;       // ai survival
     if (schemeData(19).toBool())
-        result |= 0x00100000;       // infinite attacks
+        result |= 0x00100000;       // infinite attacks 
     if (schemeData(20).toBool())
         result |= 0x00200000;       // reset weaps
     if (schemeData(21).toBool())
@@ -186,7 +192,7 @@
     if (schemeData(24).toBool())
         result |= 0x02000000;       // tag team
     if (schemeData(25).toBool())
-        result |= 0x04000000;       // bottom border
+        result |= 0x04000000;       // bottom
 
     return result;
 }
@@ -235,6 +241,8 @@
     bcfg << QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter()).toUtf8();
     bcfg << QString("e$mapgen %1").arg(mapgen).toUtf8();
 
+
+
     switch (mapgen)
     {
         case MAPGEN_MAZE:
@@ -271,7 +279,7 @@
     bool illegal = ammo.size() != cDefaultAmmoStore->size();
     if (illegal)
     {
-        QMessageBox illegalMsg(this);
+        QMessageBox illegalMsg(parentWidget());
         illegalMsg.setIcon(QMessageBox::Warning);
         illegalMsg.setWindowTitle(QMessageBox::tr("Error"));
         illegalMsg.setText(QMessageBox::tr("Cannot use the ammo '%1'!").arg(name));
@@ -325,10 +333,6 @@
         if (param == "SEED")
         {
             pMapContainer->setSeed(value);
-            if (!seedRegexp.exactMatch(value))
-            {
-                pMapContainer->seedEdit->setVisible(true);
-            }
             return;
         }
         if (param == "THEME")
@@ -377,8 +381,6 @@
         if (param == "FULLMAPCONFIG")
         {
             QString seed = slValue[3];
-            if (!seedRegexp.exactMatch(seed))
-                pMapContainer->seedEdit->setVisible(true);
 
             pMapContainer->setAllMapParameters(
                 slValue[0],
@@ -586,3 +588,19 @@
             Scripts->setCurrentIndex(0);
     }
 }
+
+bool GameCFGWidget::isMaster()
+{
+    return m_master;
+}
+
+void GameCFGWidget::setMaster(bool master)
+{
+    if (master == m_master) return;
+    m_master = master;
+
+    pMapContainer->setMaster(master);
+
+    foreach (QWidget *widget, m_childWidgets)
+        widget->setEnabled(master);
+}
--- a/QTfrontend/ui/widget/gamecfgwidget.h	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/widget/gamecfgwidget.h	Mon Jan 14 11:19:59 2013 +0100
@@ -36,6 +36,8 @@
 {
         Q_OBJECT
 
+        Q_PROPERTY(bool master READ isMaster WRITE setMaster)
+
     public:
         GameCFGWidget(QWidget* parent);
         quint32 getGameFlags() const;
@@ -47,11 +49,13 @@
         HWMapContainer* pMapContainer;
         QTableView * tv;
         QVariant schemeData(int column) const;
+        bool isMaster();
 
     public slots:
         void setParam(const QString & param, const QStringList & value);
         void fullNetConfig();
         void resendSchemeData();
+        void setMaster(bool master);
 
     signals:
         void paramChanged(const QString & param, const QStringList & value);
@@ -81,6 +85,8 @@
         QString curNetAmmo;
         QRegExp seedRegexp;
         QString m_curScript;
+        bool m_master;
+        QList<QWidget *> m_childWidgets;
 
         void setNetAmmo(const QString& name, const QString& ammo);
 
--- a/QTfrontend/ui/widget/mapContainer.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/widget/mapContainer.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -30,13 +30,24 @@
 #include <QIcon>
 #include <QLineEdit>
 #include <QStringListModel>
+#include <QListWidget>
+#include <QListWidgetItem>
+#include <QDebug>
+#include <QFile>
+#include <QFileDialog>
+#include <QInputDialog>
+#include <QMessageBox>
 
 #include "hwconsts.h"
 #include "mapContainer.h"
+#include "themeprompt.h"
+#include "seedprompt.h"
 #include "igbox.h"
 #include "HWApplication.h"
 #include "ThemeModel.h"
 
+
+
 HWMapContainer::HWMapContainer(QWidget * parent) :
     QWidget(parent),
     mainLayout(this),
@@ -47,6 +58,7 @@
     hhSmall.load(":/res/hh_small.png");
     hhLimit = 18;
     templateFilter = 0;
+    m_master = true;
 
     linearGrad = QLinearGradient(QPoint(128, 0), QPoint(128, 128));
     linearGrad.setColorAt(1, QColor(0, 0, 192));
@@ -57,135 +69,192 @@
                                   HWApplication::style()->pixelMetric(QStyle::PM_LayoutRightMargin),
                                   HWApplication::style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
 
-    QWidget* mapWidget = new QWidget(this);
-    mainLayout.addWidget(mapWidget, 0, 0, Qt::AlignHCenter);
-
-    QGridLayout* mapLayout = new QGridLayout(mapWidget);
-    mapLayout->setMargin(0);
+    m_staticMapModel = DataManager::instance().staticMapModel();
+    m_missionMapModel = DataManager::instance().missionMapModel();
+    m_themeModel = DataManager::instance().themeModel();
 
-    imageButt = new QPushButton(mapWidget);
-    imageButt->setObjectName("imageButt");
-    imageButt->setFixedSize(256 + 6, 128 + 6);
-    imageButt->setFlat(true);
-    imageButt->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);//QSizePolicy::Minimum, QSizePolicy::Minimum);
-    mapLayout->addWidget(imageButt, 0, 0, 1, 2);
-    connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomMap()));
+    /* Layouts */
 
-    chooseMap = new QComboBox(mapWidget);
-    chooseMap->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-    m_mapModel = DataManager::instance().mapModel();
-    chooseMap->setEditable(false);
-    chooseMap->setModel(m_mapModel);
+    QHBoxLayout * typeLayout = new QHBoxLayout();
+    QHBoxLayout * seedLayout = new QHBoxLayout();
+    QHBoxLayout * twoColumnLayout = new QHBoxLayout();
+    QVBoxLayout * leftLayout = new QVBoxLayout();
+    QVBoxLayout * rightLayout = new QVBoxLayout();
+    twoColumnLayout->addLayout(leftLayout, 0);
+    twoColumnLayout->addStretch(1);
+    twoColumnLayout->addLayout(rightLayout, 0);
+    QVBoxLayout * drawnControls = new QVBoxLayout();
+    leftLayout->addLayout(typeLayout, 0);
+    rightLayout->addLayout(seedLayout, 0);
+
+    /* Map type combobox */
 
-    mapLayout->addWidget(chooseMap, 1, 1);
+    typeLayout->setSpacing(10);
+    typeLayout->addWidget(new QLabel(tr("Map type:")), 0);
+    cType = new QComboBox(this);
+    typeLayout->addWidget(cType, 1);
+    cType->insertItem(0, tr("Image map"), MapModel::StaticMap);
+    cType->insertItem(1, tr("Mission map"), MapModel::MissionMap);
+    cType->insertItem(2, tr("Hand-drawn"), MapModel::HandDrawnMap);
+    cType->insertItem(3, tr("Randomly generated"), MapModel::GeneratedMap);
+    cType->insertItem(4, tr("Random maze"), MapModel::GeneratedMaze);
+    connect(cType, SIGNAL(currentIndexChanged(int)), this, SLOT(mapTypeChanged(int)));
+    m_childWidgets << cType;
 
-    QLabel * lblMap = new QLabel(tr("Map"), mapWidget);
-    mapLayout->addWidget(lblMap, 1, 0);
-
-    lblFilter = new QLabel(tr("Filter"), mapWidget);
-    mapLayout->addWidget(lblFilter, 2, 0);
+    /* Randomize button */
 
-    cbTemplateFilter = new QComboBox(mapWidget);
-    cbTemplateFilter->addItem(tr("All"), 0);
-    cbTemplateFilter->addItem(tr("Small"), 1);
-    cbTemplateFilter->addItem(tr("Medium"), 2);
-    cbTemplateFilter->addItem(tr("Large"), 3);
-    cbTemplateFilter->addItem(tr("Cavern"), 4);
-    cbTemplateFilter->addItem(tr("Wacky"), 5);
-    mapLayout->addWidget(cbTemplateFilter, 2, 1);
+    seedLayout->addStretch(1);
+    const QIcon& lp = QIcon(":/res/dice.png");
+    QSize sz = lp.actualSize(QSize(65535, 65535));
+    btnRandomize = new QPushButton();
+    btnRandomize->setText(tr("Random"));
+    btnRandomize->setIcon(lp);
+    btnRandomize->setFixedHeight(30);
+    btnRandomize->setIconSize(sz);
+    btnRandomize->setFlat(true);
+    btnRandomize->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    connect(btnRandomize, SIGNAL(clicked()), this, SLOT(setRandomMap()));
+    m_childWidgets << btnRandomize;
+    btnRandomize->setStyleSheet("padding: 5px;");
+    btnRandomize->setFixedHeight(cType->height());
+    seedLayout->addWidget(btnRandomize, 1);
 
-    connect(cbTemplateFilter, SIGNAL(activated(int)), this, SLOT(setTemplateFilter(int)));
+    /* Seed button */
+    btnSeed = new QPushButton(parentWidget()->parentWidget());
+    btnSeed->setText(tr("Seed"));
+    btnSeed->setStyleSheet("padding: 5px;");
+    btnSeed->setFixedHeight(cType->height());
+    connect(btnSeed, SIGNAL(clicked()), this, SLOT(showSeedPrompt()));
+    seedLayout->addWidget(btnSeed, 0);
 
-    maze_size_label = new QLabel(tr("Type"), mapWidget);
-    mapLayout->addWidget(maze_size_label, 2, 0);
-    maze_size_label->hide();
-    cbMazeSize = new QComboBox(mapWidget);
-    cbMazeSize->addItem(tr("Small tunnels"), 0);
-    cbMazeSize->addItem(tr("Medium tunnels"), 1);
-    cbMazeSize->addItem(tr("Large tunnels"), 2);
-    cbMazeSize->addItem(tr("Small floating islands"), 3);
-    cbMazeSize->addItem(tr("Medium floating islands"), 4);
-    cbMazeSize->addItem(tr("Large floating islands"), 5);
-    cbMazeSize->setCurrentIndex(1);
+    /* Map preview label */
+
+    QLabel * lblMapPreviewText = new QLabel(this);
+    lblMapPreviewText->setText(tr("Map preview:"));
+    leftLayout->addWidget(lblMapPreviewText, 0, Qt::AlignLeft);
+
+    /* Map Preview */
 
-    mapLayout->addWidget(cbMazeSize, 2, 1);
-    cbMazeSize->hide();
-    connect(cbMazeSize, SIGNAL(activated(int)), this, SLOT(setMazeSize(int)));
+    mapPreview = new QLabel(this);
+    mapPreview->setObjectName("mapPreview");
+    mapPreview->setFixedSize(256, 128);
+    leftLayout->addWidget(mapPreview, 0);
+
+    /* Bottom-Left layout */
 
-    gbThemes = new IconedGroupBox(mapWidget);
-    gbThemes->setTitleTextPadding(80);
-    gbThemes->setContentTopPadding(15);
-    gbThemes->setTitle(tr("Themes"));
+    QVBoxLayout * bottomLeftLayout = new QVBoxLayout();
+    leftLayout->addLayout(bottomLeftLayout, 1);
+
+    /* Map list label */
+
+    lblMapList = new QLabel();
+    rightLayout->addWidget(lblMapList, 0);
+
+    /* Static maps list */
 
-    //gbThemes->setStyleSheet("padding: 0px"); // doesn't work - stylesheet is set with icon
-    mapLayout->addWidget(gbThemes, 0, 2, 3, 1);
-    // disallow row to be collapsed (so it can't get ignored when Qt applies rowSpan of gbThemes)
-    mapLayout->setRowMinimumHeight(2, 13);
-    QVBoxLayout * gbTLayout = new QVBoxLayout(gbThemes);
-    gbTLayout->setContentsMargins(0, 0, 0 ,0);
-    gbTLayout->setSpacing(0);
-    lvThemes = new QListView(mapWidget);
-    lvThemes->setMinimumHeight(30);
-    lvThemes->setFixedWidth(140);
-    m_themeModel = DataManager::instance().themeModel();
-    lvThemes->setModel(m_themeModel);
-    lvThemes->setIconSize(QSize(16, 16));
-    lvThemes->setEditTriggers(QListView::NoEditTriggers);
+    staticMapList = new QListView;
+    staticMapList->setModel(m_staticMapModel);
+    rightLayout->addWidget(staticMapList, 1);
+    staticMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    m_childWidgets << staticMapList;
+    QItemSelectionModel * staticSelectionModel = staticMapList->selectionModel();
+    connect(staticSelectionModel,
+            SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
+            this,
+            SLOT(staticMapChanged(const QModelIndex &, const QModelIndex &)));
 
-    connect(lvThemes->selectionModel(), SIGNAL(currentRowChanged( const QModelIndex &, const QModelIndex &)), this, SLOT(themeSelected( const QModelIndex &, const QModelIndex &)));
+    /* Mission maps list */
 
-    // override default style to tighten up theme scroller
-    lvThemes->setStyleSheet(QString(
-                                "QListView{"
-                                "border: solid;"
-                                "border-width: 0px;"
-                                "border-radius: 0px;"
-                                "border-color: transparent;"
-                                "background-color: #0d0544;"
-                                "color: #ffcc00;"
-                                "font: bold 13px;"
-                                "}"
-                            )
-                           );
+    missionMapList = new QListView;
+    missionMapList->setModel(m_missionMapModel);
+    missionMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    rightLayout->addWidget(missionMapList, 1);
+    m_childWidgets << missionMapList;
+    QItemSelectionModel * missionSelectionModel = missionMapList->selectionModel();
+    connect(missionSelectionModel,
+            SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
+            this,
+            SLOT(missionMapChanged(const QModelIndex &, const QModelIndex &)));
+
+    /* Map load and edit buttons */
+
+    drawnControls->addStretch(1);
 
-    gbTLayout->addWidget(lvThemes);
-    lvThemes->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
+    btnLoadMap = new QPushButton(tr("Load map drawing"));
+    btnLoadMap->setStyleSheet("padding: 20px;");
+    drawnControls->addWidget(btnLoadMap, 0);
+    m_childWidgets << btnLoadMap;
+    connect(btnLoadMap, SIGNAL(clicked()), this, SLOT(loadDrawing()));
+
+    btnEditMap = new QPushButton(tr("Edit map drawing"));
+    btnEditMap->setStyleSheet("padding: 20px;");
+    drawnControls->addWidget(btnEditMap, 0);
+    m_childWidgets << btnEditMap;
+    connect(btnEditMap, SIGNAL(clicked()), this, SIGNAL(drawMapRequested()));
+
+    drawnControls->addStretch(1);
+
+    rightLayout->addLayout(drawnControls);
+
+    /* Generator style list */
 
-    mapLayout->setSizeConstraint(QLayout::SetFixedSize);
+    generationStyles = new QListWidget();
+    new QListWidgetItem(tr("All"), generationStyles);
+    new QListWidgetItem(tr("Small"), generationStyles);
+    new QListWidgetItem(tr("Medium"), generationStyles);
+    new QListWidgetItem(tr("Large"), generationStyles);
+    new QListWidgetItem(tr("Cavern"), generationStyles);
+    new QListWidgetItem(tr("Wacky"), generationStyles);
+    connect(generationStyles, SIGNAL(currentRowChanged(int)), this, SLOT(setTemplateFilter(int)));
+    m_childWidgets << generationStyles;
+    rightLayout->addWidget(generationStyles, 1);
+
+    /* Maze style list */
 
-    QWidget* seedWidget = new QWidget(this);
-    mainLayout.addWidget(seedWidget, 1, 0);
+    mazeStyles = new QListWidget();
+    new QListWidgetItem(tr("Small tunnels"), mazeStyles);
+    new QListWidgetItem(tr("Medium tunnels"), mazeStyles);
+    new QListWidgetItem(tr("Largetunnels"), mazeStyles);
+    new QListWidgetItem(tr("Small islands"), mazeStyles);
+    new QListWidgetItem(tr("Medium islands"), mazeStyles);
+    new QListWidgetItem(tr("Large islands"), mazeStyles);
+    connect(mazeStyles, SIGNAL(currentRowChanged(int)), this, SLOT(setMazeSize(int)));
+    m_childWidgets << mazeStyles;
+    rightLayout->addWidget(mazeStyles, 1);
 
-    QGridLayout* seedLayout = new QGridLayout(seedWidget);
-    seedLayout->setMargin(0);
+    /* Mission description */
 
-    seedLabel = new QLabel(tr("Seed"), seedWidget);
-    seedLayout->addWidget(seedLabel, 3, 0);
-    seedEdit = new QLineEdit(seedWidget);
-    seedEdit->setMaxLength(54);
-    connect(seedEdit, SIGNAL(returnPressed()), this, SLOT(seedEdited()));
-    seedLayout->addWidget(seedEdit, 3, 1);
-    seedLayout->setColumnStretch(1, 5);
-    seedSet = new QPushButton(seedWidget);
-    seedSet->setText(QPushButton::tr("more"));
-    connect(seedSet, SIGNAL(clicked()), this, SLOT(seedEdited()));
-    seedLayout->setColumnStretch(2, 1);
-    seedLayout->addWidget(seedSet, 3, 2);
+    lblDesc = new QLabel();
+    lblDesc->setWordWrap(true);
+    lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    lblDesc->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+    bottomLeftLayout->addWidget(lblDesc, 100);
+
+    /* Spacing above theme chooser */
+
+    bottomLeftLayout->addStretch(1);
+
+    /* Theme chooser */
 
-    seedLabel->setVisible(false);
-    seedEdit->setVisible(false);
+    btnTheme = new QPushButton();
+    connect(btnTheme, SIGNAL(clicked()), this, SLOT(showThemePrompt()));
+    m_childWidgets << btnTheme;
+    bottomLeftLayout->addWidget(btnTheme, 1);
 
-    setRandomSeed();
-    setRandomTheme();
+    /* Add everything to main layout */
+
+    mainLayout.addLayout(twoColumnLayout, 0);
 
-    chooseMap->setCurrentIndex(0);
-    mapChanged(0);
-    // use signal "activated" rather than currentIndexChanged
-    // because index is somtimes changed a few times in a row programmatically
-    connect(chooseMap, SIGNAL(activated(int)), this, SLOT(mapChanged(int)));
+    /* Set defaults */
 
-    // update model views after model changes (to e.g. re-adjust separators)
-    connect(&DataManager::instance(), SIGNAL(updated()), this, SLOT(updateModelViews()));
+    setRandomTheme();
+    setRandomSeed();
+    setMazeSize(0);
+    setTemplateFilter(0);
+    staticMapChanged(m_staticMapModel->index(0, 0));
+    missionMapChanged(m_missionMapModel->index(0, 0));
+    updateTheme(m_themeModel->index(0, 0));
+    mapTypeChanged(0);
 }
 
 void HWMapContainer::setImage(const QImage newImage)
@@ -202,8 +271,9 @@
     p.drawPixmap(QPoint(0, 0), px);
 
     addInfoToPreview(pxres);
-    //chooseMap->setCurrentIndex(mapgen);
     pMap = 0;
+
+    cType->setEnabled(isMaster());
 }
 
 void HWMapContainer::setHHLimit(int newHHLimit)
@@ -211,70 +281,6 @@
     hhLimit = newHHLimit;
 }
 
-void HWMapContainer::mapChanged(int index)
-{
-    if (chooseMap->currentIndex() != index)
-        chooseMap->setCurrentIndex(index);
-
-    if (index < 0)
-    {
-        m_mapInfo.type = MapModel::Invalid;
-        updatePreview();
-        return;
-    }
-
-    Q_ASSERT(chooseMap->itemData(index, Qt::UserRole + 1).canConvert<MapModel::MapInfo>());
-    m_mapInfo = chooseMap->itemData(index, Qt::UserRole + 1).value<MapModel::MapInfo>();
-    m_curMap = m_mapInfo.name;
-
-    switch(m_mapInfo.type)
-    {
-        case MapModel::GeneratedMap:
-            mapgen = MAPGEN_REGULAR;
-            gbThemes->show();
-            lblFilter->show();
-            cbTemplateFilter->show();
-            maze_size_label->hide();
-            cbMazeSize->hide();
-            break;
-        case MapModel::GeneratedMaze:
-            mapgen = MAPGEN_MAZE;
-            gbThemes->show();
-            lblFilter->hide();
-            cbTemplateFilter->hide();
-            maze_size_label->show();
-            cbMazeSize->show();
-            break;
-        case MapModel::HandDrawnMap:
-            mapgen = MAPGEN_DRAWN;
-            gbThemes->show();
-            lblFilter->hide();
-            cbTemplateFilter->hide();
-            maze_size_label->hide();
-            cbMazeSize->hide();
-            break;
-        default:
-            mapgen = MAPGEN_MAP;
-            gbThemes->hide();
-            lblFilter->hide();
-            cbTemplateFilter->hide();
-            maze_size_label->hide();
-            cbMazeSize->hide();
-            m_theme = m_mapInfo.theme;
-    }
-
-    // the map has no pre-defined theme, so let's use the selected one
-    if (m_mapInfo.theme.isEmpty())
-    {
-        m_theme = lvThemes->currentIndex().data().toString();
-        emit themeChanged(m_theme);
-    }
-
-    updatePreview();
-    emit mapChanged(m_curMap);
-    emit mapgenChanged(mapgen);
-}
-
 // Should this add text to identify map size?
 void HWMapContainer::addInfoToPreview(QPixmap image)
 {
@@ -292,8 +298,7 @@
     p.drawText(image.rect().width() - hhSmall.rect().width() - 14 - (hhLimit > 9 ? 10 : 0), 18, text);
     p.drawPixmap(image.rect().width() - hhSmall.rect().width() - 5, 5, hhSmall.rect().width(), hhSmall.rect().height(), hhSmall);
 
-    imageButt->setIcon(finalImage);
-    imageButt->setIconSize(image.size());
+    mapPreview->setPixmap(finalImage);
 }
 
 void HWMapContainer::askForGeneratedPreview()
@@ -322,14 +327,8 @@
     p.drawPixmap(QPoint(x, y), waitIcon);
 
     addInfoToPreview(waitImage);
-}
 
-void HWMapContainer::themeSelected(const QModelIndex & current, const QModelIndex &)
-{
-    m_theme = current.data().toString();
-
-    gbThemes->setIcon(qVariantValue<QIcon>(current.data(Qt::UserRole)));
-    emit themeChanged(m_theme);
+    cType->setEnabled(false);
 }
 
 QString HWMapContainer::getCurrentSeed() const
@@ -339,8 +338,14 @@
 
 QString HWMapContainer::getCurrentMap() const
 {
-    if(chooseMap->currentIndex() < MAPGEN_MAP) return QString();
-    return(m_curMap);
+    switch (m_mapInfo.type)
+    {
+        case MapModel::StaticMap:
+        case MapModel::MissionMap:
+            return m_curMap;
+        default:
+            return QString();
+    }
 }
 
 QString HWMapContainer::getCurrentTheme() const
@@ -370,20 +375,17 @@
 
 quint32 HWMapContainer::getTemplateFilter() const
 {
-    return cbTemplateFilter->itemData(cbTemplateFilter->currentIndex()).toInt();
+    return generationStyles->currentRow();
 }
 
 void HWMapContainer::resizeEvent ( QResizeEvent * event )
 {
     Q_UNUSED(event);
-    //imageButt->setIconSize(imageButt->size());
 }
 
 void HWMapContainer::intSetSeed(const QString & seed)
 {
     m_seed = seed;
-    if (seed != seedEdit->text())
-        seedEdit->setText(seed);
 }
 
 void HWMapContainer::setSeed(const QString & seed)
@@ -395,11 +397,29 @@
 
 void HWMapContainer::intSetMap(const QString & map)
 {
-    m_curMap = map;
-
-    int id = m_mapModel->indexOf(map);
-
-    mapChanged(id);
+    if (map == "+rnd+")
+    {
+        changeMapType(MapModel::GeneratedMap);
+    }
+    else if (map == "+maze+")
+    {
+        changeMapType(MapModel::GeneratedMaze);
+    }
+    else if (map == "+drawn+")
+    {
+        changeMapType(MapModel::HandDrawnMap);
+    }
+    else if (m_staticMapModel->mapExists(map))
+    {
+        changeMapType(MapModel::StaticMap, m_staticMapModel->index(m_staticMapModel->findMap(map), 0));
+    }
+    else if (m_missionMapModel->mapExists(map))
+    {
+        changeMapType(MapModel::MissionMap, m_missionMapModel->index(m_missionMapModel->findMap(map), 0));
+    } else
+    {
+        qDebug() << "HWMapContainer::intSetMap: Map doesn't exist: " << map;
+    }
 }
 
 void HWMapContainer::setMap(const QString & map)
@@ -413,13 +433,11 @@
     QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), Qt::DisplayRole, theme);
 
     if(mdl.size())
-        lvThemes->setCurrentIndex(mdl.at(0));
+        updateTheme(mdl.at(0));
 }
 
 void HWMapContainer::setRandomMap()
 {
-    int idx;
-
     setRandomSeed();
     switch(m_mapInfo.type)
     {
@@ -427,17 +445,14 @@
         case MapModel::GeneratedMaze:
             setRandomTheme();
             break;
-        case MapModel::HandDrawnMap:
-            emit drawMapRequested();
+        case MapModel::MissionMap:
+            missionMapChanged(m_missionMapModel->index(rand() % m_missionMapModel->rowCount(), 0));
             break;
-        case MapModel::MissionMap:
         case MapModel::StaticMap:
-            // get random map of same type
-            idx = m_mapModel->randomMap(m_mapInfo.type);
-            mapChanged(idx);
+            staticMapChanged(m_staticMapModel->index(rand() % m_staticMapModel->rowCount(), 0));
             break;
-        case MapModel::Invalid:
-            mapChanged(0);
+        default:
+            break;
     }
 }
 
@@ -452,12 +467,12 @@
 {
     if(!m_themeModel->rowCount()) return;
     quint32 themeNum = rand() % m_themeModel->rowCount();
-    lvThemes->setCurrentIndex(m_themeModel->index(themeNum));
+    updateTheme(m_themeModel->index(themeNum));
 }
 
 void HWMapContainer::intSetTemplateFilter(int filter)
 {
-    cbTemplateFilter->setCurrentIndex(filter);
+    generationStyles->setCurrentRow(filter);
     emit newTemplateFilter(filter);
 }
 
@@ -475,12 +490,12 @@
 
 int HWMapContainer::getMazeSize(void) const
 {
-    return cbMazeSize->currentIndex();
+    return mazeStyles->currentRow();
 }
 
 void HWMapContainer::intSetMazeSize(int size)
 {
-    cbMazeSize->setCurrentIndex(size);
+    mazeStyles->setCurrentRow(size);
     emit mazeSizeChanged(size);
 }
 
@@ -521,9 +536,6 @@
                 break;
         }
 
-        if(m != MAPGEN_MAP)
-            chooseMap->setCurrentIndex(m);
-
         emit mapgenChanged(m);
     }
 }
@@ -546,23 +558,10 @@
     return drawMapScene.encode();
 }
 
-void HWMapContainer::seedEdited()
+void HWMapContainer::setNewSeed(const QString & newSeed)
 {
-    if (seedLabel->isVisible() == false )
-    {
-        seedLabel->setVisible(true);
-        seedEdit->setVisible(true);
-        seedSet->setText(tr("Set"));
-        return;
-    }
-
-    if (seedEdit->text().isEmpty())
-        seedEdit->setText(m_seed);
-    else
-    {
-        setSeed(seedEdit->text());
-        emit seedChanged(seedEdit->text());
-    }
+    setSeed(newSeed);
+    emit seedChanged(newSeed);
 }
 
 DrawMapScene * HWMapContainer::getDrawMapScene()
@@ -592,8 +591,7 @@
     {
         case MapModel::Invalid:
             failIcon = QPixmap(":/res/btnDisabled.png");
-            imageButt->setIcon(failIcon);
-            imageButt->setIconSize(failIcon.size());
+            mapPreview->setPixmap(failIcon);
             break;
         case MapModel::GeneratedMap:
             askForGeneratedPreview();
@@ -610,7 +608,7 @@
 
             if(!success)
             {
-                imageButt->setIcon(QIcon());
+                mapPreview->setPixmap(QPixmap());
                 return;
             }
 
@@ -638,13 +636,13 @@
     {
         QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), Qt::DisplayRole, m_theme);
         if (mdl.size() > 0)
-            lvThemes->setCurrentIndex(mdl.at(0));
+            updateTheme(mdl.at(0));
         else
             setRandomTheme();
     }
 
     // restore map selection
-    if ((!m_curMap.isEmpty()) && (chooseMap->currentIndex() < 0))
+    if (!m_curMap.isEmpty())
         intSetMap(m_curMap);
     else
         updatePreview();
@@ -656,3 +654,227 @@
     if (map == pMap)
         pMap = 0;
 }
+
+void HWMapContainer::mapTypeChanged(int index)
+{
+    changeMapType((MapModel::MapType)cType->itemData(index).toInt());
+}
+
+void HWMapContainer::changeMapType(MapModel::MapType type, const QModelIndex & newMap)
+{
+    staticMapList->hide();
+    missionMapList->hide();
+    lblMapList->hide();
+    generationStyles->hide();
+    mazeStyles->hide();
+    lblDesc->hide();
+    btnTheme->hide();
+    btnLoadMap->hide();
+    btnEditMap->hide();
+    btnRandomize->hide();
+
+    switch (type)
+    {
+        case MapModel::GeneratedMap:
+            mapgen = MAPGEN_REGULAR;
+            setMapInfo(MapModel::MapInfoRandom);
+            lblMapList->setText(tr("Map size:"));
+            lblMapList->show();
+            generationStyles->show();
+            btnRandomize->show();
+            btnTheme->show();
+            break;
+        case MapModel::GeneratedMaze:
+            mapgen = MAPGEN_MAZE;
+            setMapInfo(MapModel::MapInfoMaze);
+            lblMapList->setText(tr("Maze style:"));
+            lblMapList->show();
+            mazeStyles->show();
+            btnRandomize->show();
+            btnTheme->show();
+            break;
+        case MapModel::HandDrawnMap:
+            mapgen = MAPGEN_DRAWN;
+            setMapInfo(MapModel::MapInfoDrawn);
+            btnTheme->show();
+            btnLoadMap->show();
+            btnEditMap->show();
+            break;
+        case MapModel::MissionMap:
+            mapgen = MAPGEN_MAP;
+            missionMapChanged(newMap.isValid() ? newMap : missionMapList->currentIndex());
+            lblMapList->setText(tr("Mission:"));
+            lblMapList->show();
+            missionMapList->show();
+            lblDesc->setText(m_mapInfo.desc);
+            lblDesc->show();
+            btnRandomize->show();
+            emit mapChanged(m_curMap);
+            break;
+        case MapModel::StaticMap:
+            mapgen = MAPGEN_MAP;
+            staticMapChanged(newMap.isValid() ? newMap : staticMapList->currentIndex());
+            lblMapList->setText(tr("Map:"));
+            lblMapList->show();
+            staticMapList->show();
+            btnRandomize->show();
+            emit mapChanged(m_curMap);
+            break;
+        default:
+            break;
+    }
+
+    // Update cType combobox
+    for (int i = 0; i < cType->count(); i++)
+    {
+        if ((MapModel::MapType)cType->itemData(i).toInt() == type)
+        {
+            cType->setCurrentIndex(i);
+            break;
+        }
+    }
+
+    emit mapgenChanged(mapgen);
+}
+
+void HWMapContainer::showThemePrompt()
+{
+    ThemePrompt prompt(this);
+    int theme = prompt.exec() - 1; // Since 0 means canceled, so all indexes are +1'd
+    if (theme < 0) return;
+
+    QModelIndex current = m_themeModel->index(theme, 0);
+    updateTheme(current);
+    
+    emit themeChanged(m_theme);
+}
+
+void HWMapContainer::updateTheme(const QModelIndex & current)
+{
+    m_theme = selectedTheme = current.data().toString();
+    QIcon icon = qVariantValue<QIcon>(current.data(Qt::UserRole));
+    QSize iconSize = icon.actualSize(QSize(65535, 65535));
+    btnTheme->setFixedHeight(iconSize.height());
+    btnTheme->setIconSize(iconSize);
+    btnTheme->setIcon(icon);
+    btnTheme->setText(tr("Theme: ") + current.data(Qt::DisplayRole).toString());
+    emit themeChanged(m_theme);
+}
+
+void HWMapContainer::staticMapChanged(const QModelIndex & map, const QModelIndex & old)
+{
+    mapChanged(map, 0, old);
+}
+
+void HWMapContainer::missionMapChanged(const QModelIndex & map, const QModelIndex & old)
+{
+    mapChanged(map, 1, old);
+}
+
+// Type: 0 = static, 1 = mission
+void HWMapContainer::mapChanged(const QModelIndex & map, int type, const QModelIndex & old)
+{
+    QListView * mapList;
+
+    if (type == 0)      mapList = staticMapList;
+    else if (type == 1) mapList = missionMapList;
+    else                return;
+
+    // Make sure it is a valid index
+    if (!map.isValid())
+    {
+        if (old.isValid())
+        {
+            mapList->setCurrentIndex(old);
+            mapList->scrollTo(old);
+        }
+        else
+        {
+            m_mapInfo.type = MapModel::Invalid;
+            updatePreview();
+        }
+
+        return;
+    }
+
+    // If map changed, update list selection
+    if (mapList->currentIndex() != map)
+    {
+        mapList->setCurrentIndex(map);
+        mapList->scrollTo(map);
+    }
+
+    if (map.data(Qt::UserRole + 1).canConvert<MapModel::MapInfo>())
+        setMapInfo(map.data(Qt::UserRole + 1).value<MapModel::MapInfo>());
+    else
+        Q_ASSERT(false); // Houston, we have a problem.
+
+}
+
+void HWMapContainer::setMapInfo(MapModel::MapInfo mapInfo)
+{
+    m_mapInfo = mapInfo;
+    m_curMap = m_mapInfo.name;
+    m_theme = m_mapInfo.theme;
+
+    // the map has no pre-defined theme, so let's use the selected one
+    if (m_mapInfo.theme.isEmpty())
+    {
+        m_theme = selectedTheme;
+        emit themeChanged(m_theme);
+    }
+
+    lblDesc->setText(mapInfo.desc);
+
+    updatePreview();
+    emit mapChanged(m_curMap);
+}
+
+void HWMapContainer::loadDrawing()
+{
+
+
+    QString fileName = QFileDialog::getOpenFileName(NULL, tr("Load drawn map"), ".", tr("Drawn Maps") + " (*.hwmap);;" + tr("All files") + " (*)");
+
+    if(fileName.isEmpty()) return;
+
+
+
+    QFile f(fileName);
+
+    if(!f.open(QIODevice::ReadOnly))
+    {
+        QMessageBox errorMsg(parentWidget());
+        errorMsg.setIcon(QMessageBox::Warning);
+        errorMsg.setWindowTitle(QMessageBox::tr("File error"));
+        errorMsg.setText(QMessageBox::tr("Cannot open '%1' for reading").arg(fileName));
+        errorMsg.setWindowModality(Qt::WindowModal);
+        errorMsg.exec();
+    }
+    else
+    {
+        drawMapScene.decode(qUncompress(QByteArray::fromBase64(f.readAll())));
+        mapDrawingFinished();
+    }
+}
+
+void HWMapContainer::showSeedPrompt()
+{
+    SeedPrompt prompt(parentWidget()->parentWidget(), getCurrentSeed(), isMaster());
+    connect(&prompt, SIGNAL(seedSelected(const QString &)), this, SLOT(setNewSeed(const QString &)));
+    prompt.exec();
+}
+
+bool HWMapContainer::isMaster()
+{
+    return m_master;
+}
+
+void HWMapContainer::setMaster(bool master)
+{
+    if (master == m_master) return;
+    m_master = master;
+    
+    foreach (QWidget *widget, m_childWidgets)
+        widget->setEnabled(master);
+}
--- a/QTfrontend/ui/widget/mapContainer.h	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/ui/widget/mapContainer.h	Mon Jan 14 11:19:59 2013 +0100
@@ -22,6 +22,7 @@
 
 #include <QWidget>
 #include <QGridLayout>
+#include <QVBoxLayout>
 #include <QComboBox>
 #include <QLabel>
 #include <QByteArray>
@@ -37,6 +38,7 @@
 class IconedGroupBox;
 class QListView;
 class SeparatorPainter;
+class QListWidget;
 
 class MapFileErrorException
 {
@@ -46,6 +48,8 @@
 {
         Q_OBJECT
 
+        Q_PROPERTY(bool master READ isMaster WRITE setMaster)
+
     public:
         HWMapContainer(QWidget * parent=0);
         QString getCurrentSeed() const;
@@ -62,6 +66,7 @@
         DrawMapScene * getDrawMapScene();
         void mapDrawingFinished();
         QLineEdit* seedEdit;
+        bool isMaster();
 
     public slots:
         void askForGeneratedPreview();
@@ -75,6 +80,7 @@
         void setAllMapParameters(const QString & map, MapGenerator m, int mazesize, const QString & seed, int tmpl);
         void updateModelViews();
         void onPreviewMapDestroyed(QObject * map);
+        void setMaster(bool master);
 
     signals:
         void seedChanged(const QString & seed);
@@ -89,22 +95,28 @@
     private slots:
         void setImage(const QImage newImage);
         void setHHLimit(int hhLimit);
-        void mapChanged(int index);
         void setRandomSeed();
         void setRandomTheme();
         void setRandomMap();
-        void themeSelected(const QModelIndex & current, const QModelIndex &);
         void addInfoToPreview(QPixmap image);
-        void seedEdited();
+        void setNewSeed(const QString & newSeed);
+        void mapTypeChanged(int);
+        void showThemePrompt();
+        void updateTheme(const QModelIndex & current);
+        void staticMapChanged(const QModelIndex & map, const QModelIndex & old = QModelIndex());
+        void missionMapChanged(const QModelIndex & map, const QModelIndex & old = QModelIndex());
+        void loadDrawing();
+        void showSeedPrompt();
 
     protected:
         virtual void resizeEvent ( QResizeEvent * event );
 
     private:
-        QGridLayout mainLayout;
-        QPushButton* imageButt;
+        QVBoxLayout mainLayout;
+        QLabel* mapPreview;
         QComboBox* chooseMap;
-        MapModel * m_mapModel;
+        MapModel * m_staticMapModel;
+        MapModel * m_missionMapModel;
         IconedGroupBox* gbThemes;
         QListView* lvThemes;
         ThemeModel * m_themeModel;
@@ -121,12 +133,30 @@
         QComboBox *cbMazeSize;
         MapGenerator mapgen;
         DrawMapScene drawMapScene;
+        QComboBox * cType;
+        QListView * staticMapList;
+        QListView * missionMapList;
+        QListWidget * generationStyles;
+        QListWidget * mazeStyles;
+        QLabel * lblMapList;
+        QLabel * lblDesc;
+        QPushButton * btnTheme;
+        QPushButton * btnLoadMap;
+        QPushButton * btnEditMap;
+        QPushButton * btnRandomize;
+        QString selectedTheme;
+        QPushButton * btnSeed;
+        bool m_master;
+        QList<QWidget *> m_childWidgets;
 
         void intSetSeed(const QString & seed);
         void intSetMap(const QString & map);
         void intSetMapgen(MapGenerator m);
         void intSetTemplateFilter(int);
         void intSetMazeSize(int size);
+        void mapChanged(const QModelIndex & map, int type, const QModelIndex & old = QModelIndex());
+        void setMapInfo(MapModel::MapInfo mapInfo);
+        void changeMapType(MapModel::MapType type, const QModelIndex & newMap = QModelIndex());
         void updatePreview();
 
         MapModel::MapInfo m_mapInfo;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/seedprompt.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,85 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <QDialog>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QLabel>
+#include <QDebug>
+
+#include "seedprompt.h"
+
+SeedPrompt::SeedPrompt(QWidget* parent, const QString & seed, bool editable) : QDialog(parent)
+{
+	setModal(true);
+	setWindowFlags(Qt::Sheet);
+	setWindowModality(Qt::WindowModal);
+	setMinimumSize(360, 160);
+	resize(360, 160);
+	setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+	// Layout
+	QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+
+	// Label
+	QLabel * label = new QLabel(tr("The map seed is the basis for all random values generated by the game."));
+	label->setWordWrap(true);
+	dialogLayout->addWidget(label, 0);
+
+	// Input box
+	editBox = new QLineEdit();
+	editBox->setText(seed);
+	editBox->setReadOnly(!editable);
+	editBox->setStyleSheet("QLineEdit { padding: 3px; }");
+	dialogLayout->addWidget(editBox, 1);
+
+	dialogLayout->addStretch(1);
+
+	// Buttons
+	QHBoxLayout * buttonLayout = new QHBoxLayout();
+	buttonLayout->addStretch(1);
+	dialogLayout->addLayout(buttonLayout);
+	if (editable)
+	{
+		QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+		QPushButton * btnOkay = new QPushButton(tr("Set seed"));
+		connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+		connect(btnOkay, SIGNAL(clicked()), this, SLOT(accept()));
+		buttonLayout->addWidget(btnCancel);
+		buttonLayout->addWidget(btnOkay);
+		btnOkay->setDefault(true);
+	}
+	else
+	{
+		QPushButton * btnClose = new QPushButton(tr("Close"));
+		connect(btnClose, SIGNAL(clicked()), this, SLOT(reject()));
+		buttonLayout->addWidget(btnClose);
+		btnClose->setDefault(true);
+	}
+
+	setStyleSheet("QPushButton { padding: 5px; }");
+
+	connect(this, SIGNAL(accepted()), this, SLOT(setSeed()));
+}
+
+void SeedPrompt::setSeed()
+{
+	emit seedSelected(editBox->text());
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/seedprompt.h	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,43 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef SEEDPROMPT_H
+#define SEEDPROMPT_H
+
+#include <QDialog>
+
+class QLineEdit;
+
+class SeedPrompt : public QDialog
+{
+        Q_OBJECT
+
+    public:
+        SeedPrompt(QWidget* parent, const QString & seed, bool editable);
+
+    signals:
+    	void seedSelected(const QString & seed);
+
+    private slots:
+    	void setSeed();
+
+    private:
+    	QLineEdit * editBox;
+};
+
+#endif // SEEDPROMPT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/themeprompt.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,100 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <QDialog>
+#include <QVBoxLayout>
+#include <QScrollArea>
+#include <QPushButton>
+#include <QToolButton>
+#include <QWidgetItem>
+#include <QModelIndex>
+#include <QLabel>
+
+#include "flowlayout.h"
+#include "datamanager.h"
+#include "thememodel.h"
+#include "themeprompt.h"
+
+ThemePrompt::ThemePrompt(QWidget* parent) : QDialog(parent)
+{
+	setModal(true);
+	setWindowFlags(Qt::Sheet);
+	setWindowModality(Qt::WindowModal);
+	setMinimumSize(550, 430);
+	resize(550, 430);
+	setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+	// Grid
+	QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+	dialogLayout->setSpacing(0);
+
+	// Help/prompt message at top
+	QLabel * lblDesc = new QLabel(tr("Select a theme for this map"));
+    lblDesc->setStyleSheet("color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; border-top-right-radius: 10px; padding: auto 20px;");
+    lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    lblDesc->setFixedHeight(24);
+    lblDesc->setMinimumWidth(0);
+
+	// Scroll area and container for theme icons
+	QWidget * themesContainer = new QWidget();
+	FlowLayout * themesGrid = new FlowLayout();
+	themesContainer->setLayout(themesGrid);
+	QScrollArea * scrollArea = new QScrollArea();
+    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+    scrollArea->setObjectName("scrollArea");
+    scrollArea->setStyleSheet("QScrollBar, #scrollArea { background-color: #130F2A; } #scrollArea { border-color: #F6CB1C; border-width: 3px; border-top-width: 0; border-style: solid; border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; }");
+    scrollArea->setWidgetResizable(true);
+    scrollArea->setFrameShape(QFrame::NoFrame);
+    scrollArea->setWidget(themesContainer);
+
+	// Cancel button (closes dialog)
+	QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+	btnCancel->setStyleSheet("padding: 5px; margin-top: 10px;");
+	connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+	// Add elements to layouts
+	dialogLayout->addWidget(lblDesc, 0);
+	dialogLayout->addWidget(scrollArea, 1);
+	dialogLayout->addWidget(btnCancel, 0, Qt::AlignLeft);
+
+	// Tooltip label for theme name
+	lblToolTip = new QLabel(this);
+
+	// Add theme buttons
+	ThemeModel * themes = DataManager::instance().themeModel();
+	for (int i = 0; i < themes->rowCount(); i++)
+	{
+		QModelIndex index = themes->index(i, 0);
+		QToolButton * btn = new QToolButton();
+		btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+		btn->setIcon(qVariantValue<QIcon>(themes->data(index, Qt::UserRole)));
+		btn->setText(themes->data(index, Qt::DisplayRole).toString());
+		btn->setIconSize(QSize(60, 60));
+		btn->setProperty("themeID", QVariant(i));
+		btn->setStyleSheet("padding: 2px;");
+		connect(btn, SIGNAL(clicked()), this, SLOT(themeClicked()));
+		themesGrid->addWidget(btn);
+	}
+}
+
+// When a theme is selected
+void ThemePrompt::themeClicked()
+{
+	QWidget * btn = (QWidget*)sender();
+	done(btn->property("themeID").toInt() + 1); // Since returning 0 means canceled
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/themeprompt.h	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,41 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef THEMEPROMPT_H
+#define THEMEPROMPT_H
+
+#include <QWidget>
+#include <QDialog>
+
+class QLabel;
+
+class ThemePrompt : public QDialog
+{
+        Q_OBJECT
+
+    public:
+        ThemePrompt(QWidget* parent);
+
+    private:
+        QLabel * lblToolTip;
+
+    private slots:
+        void themeClicked();
+};
+
+#endif // THEMEPROMPT_H
--- a/QTfrontend/util/DataManager.cpp	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/util/DataManager.cpp	Mon Jan 14 11:19:59 2013 +0100
@@ -40,7 +40,8 @@
 DataManager::DataManager()
 {
     m_hatModel = NULL;
-    m_mapModel = NULL;
+    m_staticMapModel = NULL;
+    m_missionMapModel = NULL;
     m_themeModel = NULL;
     m_colorsModel = NULL;
     m_bindsModel = NULL;
@@ -92,13 +93,22 @@
     return m_hatModel;
 }
 
-MapModel * DataManager::mapModel()
+MapModel * DataManager::staticMapModel()
 {
-    if (m_mapModel == NULL) {
-        m_mapModel = new MapModel();
-        m_mapModel->loadMaps();
+    if (m_staticMapModel == NULL) {
+        m_staticMapModel = new MapModel();
+        m_staticMapModel->loadMaps(MapModel::StaticMap);
     }
-    return m_mapModel;
+    return m_staticMapModel;
+}
+
+MapModel * DataManager::missionMapModel()
+{
+    if (m_missionMapModel == NULL) {
+        m_missionMapModel = new MapModel();
+        m_missionMapModel->loadMaps(MapModel::MissionMap);
+    }
+    return m_missionMapModel;
 }
 
 ThemeModel * DataManager::themeModel()
--- a/QTfrontend/util/DataManager.h	Mon Jan 14 12:07:06 2013 +0400
+++ b/QTfrontend/util/DataManager.h	Mon Jan 14 11:19:59 2013 +0100
@@ -88,13 +88,22 @@
         HatModel * hatModel();
 
         /**
-         * @brief Returns pointer to a model of available maps.
+         * @brief Returns pointer to a model of available static maps.
          *
          * The model is updated automatically on data reload.
          *
          * @return map model pointer.
          */
-        MapModel * mapModel();
+        MapModel * staticMapModel();
+
+        /**
+         * @brief Returns pointer to a model of available mission maps.
+         *
+         * The model is updated automatically on data reload.
+         *
+         * @return map model pointer.
+         */
+        MapModel * missionMapModel();
 
         /**
          * @brief Returns pointer to a model of available themes.
@@ -132,7 +141,8 @@
 
         GameStyleModel * m_gameStyleModel; ///< game style model instance
         HatModel * m_hatModel; ///< hat model instance
-        MapModel * m_mapModel; ///< map model instance
+        MapModel * m_staticMapModel; ///< static map model instance
+        MapModel * m_missionMapModel; ///< mission map model instance
         ThemeModel * m_themeModel; ///< theme model instance
         QStandardItemModel * m_colorsModel;
         QStandardItemModel * m_bindsModel;
--- a/share/hedgewars/Data/Maps/Basketball/CMakeLists.txt	Mon Jan 14 12:07:06 2013 +0400
+++ b/share/hedgewars/Data/Maps/Basketball/CMakeLists.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -4,4 +4,5 @@
 	map.lua
 	mask.png
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/Basketball)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/Basketball/desc.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Please give me a description.|Multiline is supported.|See Basketball/desc.txt
\ No newline at end of file
--- a/share/hedgewars/Data/Maps/Basketball/map.cfg	Mon Jan 14 12:07:06 2013 +0400
+++ b/share/hedgewars/Data/Maps/Basketball/map.cfg	Mon Jan 14 11:19:59 2013 +0100
@@ -1,2 +1,2 @@
 Nature
-12
+12
\ No newline at end of file
--- a/share/hedgewars/Data/Maps/CTF_Blizzard/CMakeLists.txt	Mon Jan 14 12:07:06 2013 +0400
+++ b/share/hedgewars/Data/Maps/CTF_Blizzard/CMakeLists.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -2,4 +2,5 @@
 	map.cfg
 	map.lua
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/CTF_Blizzard)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/CTF_Blizzard/desc.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Please give me a description.|Multiline is supported.|See TrophyRace/desc.txt
\ No newline at end of file
--- a/share/hedgewars/Data/Maps/Control/CMakeLists.txt	Mon Jan 14 12:07:06 2013 +0400
+++ b/share/hedgewars/Data/Maps/Control/CMakeLists.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -3,4 +3,5 @@
 	map.lua
 	map.png
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/Control)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/Control/desc.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Please give me a description.|Multiline is supported.|See TrophyRace/desc.txt
\ No newline at end of file
--- a/share/hedgewars/Data/Maps/Control/map.cfg	Mon Jan 14 12:07:06 2013 +0400
+++ b/share/hedgewars/Data/Maps/Control/map.cfg	Mon Jan 14 11:19:59 2013 +0100
@@ -1,4 +1,4 @@
 Deepspace
 48
 Default
-Crazy
+Crazy
\ No newline at end of file
--- a/share/hedgewars/Data/Maps/Knockball/CMakeLists.txt	Mon Jan 14 12:07:06 2013 +0400
+++ b/share/hedgewars/Data/Maps/Knockball/CMakeLists.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -3,4 +3,5 @@
 	map.cfg
 	map.lua
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/Knockball)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/Knockball/desc.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Please give me a description.|Multiline is supported.|See TrophyRace/desc.txt
\ No newline at end of file
--- a/share/hedgewars/Data/Maps/TrophyRace/CMakeLists.txt	Mon Jan 14 12:07:06 2013 +0400
+++ b/share/hedgewars/Data/Maps/TrophyRace/CMakeLists.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -4,4 +4,5 @@
 	map.png
 	mask.png
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/TrophyRace)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/TrophyRace/desc.txt	Mon Jan 14 11:19:59 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Please give me a description.|Multiline is supported.|See TrophyRace/desc.txt
\ No newline at end of file