Allow to draw maps in frontend and play them (only locally, some bugs to fix)
authorunc0rr
Mon, 13 Dec 2010 22:12:30 +0300
changeset 4520 e7882bd1a894
parent 4519 aee36896d46b
child 4521 96066d42c3f9
Allow to draw maps in frontend and play them (only locally, some bugs to fix)
QTfrontend/CMakeLists.txt
QTfrontend/drawmapscene.cpp
QTfrontend/drawmapscene.h
QTfrontend/drawmapwidget.cpp
QTfrontend/drawmapwidget.h
QTfrontend/hwform.cpp
QTfrontend/mapContainer.cpp
QTfrontend/mapContainer.h
QTfrontend/pages.cpp
QTfrontend/pages.h
QTfrontend/qaspectratiolayout.cpp
QTfrontend/qaspectratiolayout.h
--- a/QTfrontend/CMakeLists.txt	Mon Dec 13 19:26:20 2010 +0100
+++ b/QTfrontend/CMakeLists.txt	Mon Dec 13 22:12:30 2010 +0300
@@ -23,136 +23,142 @@
 include_directories(${SDL_INCLUDE_DIR})
 include_directories(${SDLMIXER_INCLUDE_DIR})
 if(UNIX)
-	# HACK: in freebsd cannot find iconv.h included via SDL.h
-	include_directories("/usr/local/include")
+    # HACK: in freebsd cannot find iconv.h included via SDL.h
+    include_directories("/usr/local/include")
 endif(UNIX)
 
 
 if(WIN32 AND NOT UNIX)
-	set(HEDGEWARS_BINDIR ".")
-	set(HEDGEWARS_DATADIR "../share/")
+    set(HEDGEWARS_BINDIR ".")
+    set(HEDGEWARS_DATADIR "../share/")
         add_definitions(-DUSE_XFIRE)
 else()
-	set(HEDGEWARS_BINDIR ${CMAKE_INSTALL_PREFIX})
-	if(DEFINED DATA_INSTALL_DIR)
-		set(HEDGEWARS_DATADIR ${DATA_INSTALL_DIR})
-	else()
-		set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/share/)
-	endif()
+    set(HEDGEWARS_BINDIR ${CMAKE_INSTALL_PREFIX})
+    if(DEFINED DATA_INSTALL_DIR)
+        set(HEDGEWARS_DATADIR ${DATA_INSTALL_DIR})
+    else()
+        set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/share/)
+    endif()
 endif()
 
 
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hwconsts.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp)
 
-set(	hwfr_src
-	game.cpp
-	main.cpp
-	hwform.cpp
-	team.cpp
-	namegen.cpp
-	teamselect.cpp
-	teamselhelper.cpp
-	frameTeam.cpp
-	vertScrollArea.cpp
-	gameuiconfig.cpp
-	ui_hwform.cpp
-	gamecfgwidget.cpp
-	pages.cpp
-	SquareLabel.cpp
-	hats.cpp
-	hedgehogerWidget.cpp
-	hwmap.cpp
-	mapContainer.cpp
-	tcpBase.cpp
-	about.cpp
-	proto.cpp
-	fpsedit.cpp
-	netserver.cpp
-	newnetclient.cpp
-	netudpserver.cpp
-	netudpwidget.cpp
-	netregister.cpp
-	netserverslist.cpp
-	chatwidget.cpp
-	binds.cpp
-	SDLs.cpp
-	playrecordpage.cpp
-	${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp
-	selectWeapon.cpp
-	itemNum.cpp
-	input_ip.cpp
-	igbox.cpp
-	weaponItem.cpp
-	statsPage.cpp
-	misc.cpp
-	ammoSchemeModel.cpp
-	togglebutton.cpp
-	bgwidget.cpp
-	achievements.cpp
-	)
+set(hwfr_src
+    game.cpp
+    main.cpp
+    hwform.cpp
+    team.cpp
+    namegen.cpp
+    teamselect.cpp
+    teamselhelper.cpp
+    frameTeam.cpp
+    vertScrollArea.cpp
+    gameuiconfig.cpp
+    ui_hwform.cpp
+    gamecfgwidget.cpp
+    pages.cpp
+    SquareLabel.cpp
+    hats.cpp
+    hedgehogerWidget.cpp
+    hwmap.cpp
+    mapContainer.cpp
+    tcpBase.cpp
+    about.cpp
+    proto.cpp
+    fpsedit.cpp
+    netserver.cpp
+    newnetclient.cpp
+    netudpserver.cpp
+    netudpwidget.cpp
+    netregister.cpp
+    netserverslist.cpp
+    chatwidget.cpp
+    binds.cpp
+    SDLs.cpp
+    playrecordpage.cpp
+    ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp
+    selectWeapon.cpp
+    itemNum.cpp
+    input_ip.cpp
+    igbox.cpp
+    weaponItem.cpp
+    statsPage.cpp
+    misc.cpp
+    ammoSchemeModel.cpp
+    togglebutton.cpp
+    bgwidget.cpp
+    achievements.cpp
+    qaspectratiolayout.cpp
+    drawmapwidget.cpp
+    drawmapscene.cpp
+    )
 
 #xfire integration
 if(WIN32)
-	set(hwfr_src ${hwfr_src} xfire.cpp ../misc/xfire/xfiregameclient.cpp)
+    set(hwfr_src ${hwfr_src} xfire.cpp ../misc/xfire/xfiregameclient.cpp)
 endif(WIN32)
 
 if(MINGW)
-	# resource compilation for mingw
-	add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o
-	COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR}
-	-i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc
-	-o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
-	set(hwfr_src ${hwfr_src} ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
+    # resource compilation for mingw
+    add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o
+    COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR}
+    -i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc
+    -o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
+    set(hwfr_src ${hwfr_src} ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
 else(MINGW)
-	set(hwfr_src ${hwfr_src} hedgewars.rc)
+    set(hwfr_src ${hwfr_src} hedgewars.rc)
 endif(MINGW)
 
-set(	hwfr_moc_hdrs
-	game.h
-	hats.h
-	hwform.h
-	teamselect.h
-	teamselhelper.h
-	frameTeam.h
-	vertScrollArea.h
-	gameuiconfig.h
-	gamecfgwidget.h
-	pages.h
-	SquareLabel.h
-	hedgehogerWidget.h
-	hwmap.h
-	mapContainer.h
-	tcpBase.h
-	about.h
-	proto.h
-	fpsedit.h
-	netserver.h
-	newnetclient.h
-	netudpserver.h
-	netudpwidget.h
-	netregister.h
-	netserverslist.h
-	chatwidget.h
-	SDLs.h
-	playrecordpage.h
-	selectWeapon.h
-	itemNum.h
-	input_ip.h
-	igbox.h
-	weaponItem.h
-	statsPage.h
-	misc.h
-	ammoSchemeModel.h
-	togglebutton.h
-	bgwidget.h
-	)
+set(hwfr_moc_hdrs
+    game.h
+    hats.h
+    hwform.h
+    teamselect.h
+    teamselhelper.h
+    frameTeam.h
+    vertScrollArea.h
+    gameuiconfig.h
+    gamecfgwidget.h
+    pages.h
+    SquareLabel.h
+    hedgehogerWidget.h
+    hwmap.h
+    mapContainer.h
+    tcpBase.h
+    about.h
+    proto.h
+    fpsedit.h
+    netserver.h
+    newnetclient.h
+    netudpserver.h
+    netudpwidget.h
+    netregister.h
+    netserverslist.h
+    chatwidget.h
+    SDLs.h
+    playrecordpage.h
+    selectWeapon.h
+    itemNum.h
+    input_ip.h
+    igbox.h
+    weaponItem.h
+    statsPage.h
+    misc.h
+    ammoSchemeModel.h
+    togglebutton.h
+    bgwidget.h
+    qaspectratiolayout.h
+    drawmapwidget.h
+    drawmapscene.h
+    )
 
-set(	hwfr_hdrs
-	binds.h
-	ui_hwform.h
-	KB.h
-	hwconsts.h
-	)
+set(hwfr_hdrs
+    binds.h
+    ui_hwform.h
+    KB.h
+    hwconsts.h
+    )
 
 set(hwfr_rez hedgewars.qrc)
 
@@ -162,45 +168,45 @@
 
 
 if(APPLE)
-	set(hwfr_src ${hwfr_src} InstallController.cpp CocoaInitializer.mm M3Panel.mm M3InstallController.m NSWorkspace_RBAdditions.m)
-	set(HW_LINK_LIBS IOKit)
+    set(hwfr_src ${hwfr_src} InstallController.cpp CocoaInitializer.mm M3Panel.mm M3InstallController.m NSWorkspace_RBAdditions.m)
+    set(HW_LINK_LIBS IOKit)
 
-	find_package(Sparkle)
-	if(SPARKLE_FOUND)
+    find_package(Sparkle)
+    if(SPARKLE_FOUND)
                 add_definitions(-DSPARKLE_ENABLED)
-		set(hwfr_src ${hwfr_src} AutoUpdater.cpp SparkleAutoUpdater.mm)
+        set(hwfr_src ${hwfr_src} AutoUpdater.cpp SparkleAutoUpdater.mm)
                 set(HW_LINK_LIBS ${SPARKLE_LIBRARY} ${HW_LINK_LIBS})
-	endif()
+    endif()
 endif()
 
 
 add_executable(hedgewars WIN32
-	${hwfr_src}
-	${hwfr_moc_srcs}
-	${hwfr_hdrs}
-	${hwfr_rez_src}
-	)
+    ${hwfr_src}
+    ${hwfr_moc_srcs}
+    ${hwfr_hdrs}
+    ${hwfr_rez_src}
+    )
 
 
-set(	HW_LINK_LIBS
-	${QT_LIBRARIES}
-	${SDL_LIBRARY}
-	${SDLMIXER_LIBRARY}
-	${HW_LINK_LIBS}
-	)
+set(HW_LINK_LIBS
+    ${QT_LIBRARIES}
+    ${SDL_LIBRARY}
+    ${SDLMIXER_LIBRARY}
+    ${HW_LINK_LIBS}
+    )
 
 if(WIN32 AND NOT UNIX)
-	if(NOT SDL_LIBRARY)
-		set(HW_LINK_LIBS ${HW_LINK_LIBS} SDL)
-	endif()
+    if(NOT SDL_LIBRARY)
+        set(HW_LINK_LIBS ${HW_LINK_LIBS} SDL)
+    endif()
 
-	set(	HW_LINK_LIBS
-		${HW_LINK_LIBS}
-		ole32
-		oleaut32
-		winspool
-		uuid
-		)
+    set(	HW_LINK_LIBS
+        ${HW_LINK_LIBS}
+        ole32
+        oleaut32
+        winspool
+        uuid
+        )
 endif()
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/drawmapscene.cpp	Mon Dec 13 22:12:30 2010 +0300
@@ -0,0 +1,178 @@
+#include <QGraphicsSceneMouseEvent>
+#include <QGraphicsPathItem>
+#include <QtEndian>
+
+#include "drawmapscene.h"
+
+template <class T> T sqr(const T & x)
+{
+    return x*x;
+}
+
+DrawMapScene::DrawMapScene(QObject *parent) :
+    QGraphicsScene(parent),
+    m_pen(Qt::yellow),
+    m_brush(Qt::yellow)
+{
+    setSceneRect(0, 0, 4096, 2048);
+
+    QLinearGradient gradient(0, 0, 0, 2048);
+    gradient.setColorAt(0, QColor(60, 60, 155));
+    gradient.setColorAt(1, QColor(155, 155, 60));
+    setBackgroundBrush(QBrush(gradient));
+
+    m_pen.setWidth(67);
+    m_pen.setJoinStyle(Qt::RoundJoin);
+    m_pen.setCapStyle(Qt::RoundCap);
+    m_currPath = 0;
+}
+
+void DrawMapScene::mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent)
+{
+    if(m_currPath && (mouseEvent->buttons() & Qt::LeftButton))
+    {
+        QPainterPath path = m_currPath->path();
+        path.lineTo(mouseEvent->scenePos());
+        paths.first().append(mouseEvent->scenePos().toPoint());
+        m_currPath->setPath(path);
+
+        emit pathChanged();
+    }
+}
+
+void DrawMapScene::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)
+{
+    m_currPath = addPath(QPainterPath(), m_pen);
+
+    QPainterPath path = m_currPath->path();
+    QPointF p = mouseEvent->scenePos();
+    p += QPointF(0.01, 0.01);
+    path.moveTo(p);
+    path.lineTo(mouseEvent->scenePos());
+    paths.prepend(QList<QPoint>() << mouseEvent->scenePos().toPoint());
+    m_currPath->setPath(path);
+
+    emit pathChanged();
+}
+
+void DrawMapScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent)
+{
+    simplifyLast();
+
+    m_currPath = 0;
+}
+
+void DrawMapScene::undo()
+{
+    if(items().size())
+    {
+        removeItem(items().first());
+        paths.removeFirst();
+
+        emit pathChanged();
+    }
+}
+
+QByteArray DrawMapScene::encode()
+{
+    QByteArray b;
+
+    foreach(QList<QPoint> points, paths)
+    {
+        int cnt = 0;
+        foreach(QPoint point, points)
+        {
+            qint16 px = qToBigEndian((qint16)point.x());
+            qint16 py = qToBigEndian((qint16)point.y());
+            quint8 flags = 2;
+            if(!cnt) flags |= 0x80;
+            b.append((const char *)&px, 2);
+            b.append((const char *)&py, 2);
+            b.append((const char *)&flags, 1);
+
+            ++cnt;
+        }
+
+    }
+
+    return b;
+}
+
+void DrawMapScene::decode(QByteArray data)
+{
+    clear();
+    paths.clear();
+
+    QList<QPoint> points;
+
+    while(data.size() >= 5)
+    {
+        qint16 px = qFromBigEndian(*(qint16 *)data.data());
+        data.remove(0, 2);
+        qint16 py = qFromBigEndian(*(qint16 *)data.data());
+        data.remove(0, 2);
+        quint8 flags = *(quint8 *)data.data();
+        data.remove(0, 1);
+
+        //last chunk or first point
+        if((data.size() < 5) || (flags & 0x80))
+        {
+            if(points.size())
+            {
+                addPath(pointsToPath(points), m_pen);
+                paths.prepend(points);
+
+                points.clear();
+            }
+        }
+
+        points.append(QPoint(px, py));
+    }
+}
+
+void DrawMapScene::simplifyLast()
+{
+    QList<QPoint> points = paths[0];
+
+    QPoint prevPoint = points.first();
+    int i = 1;
+    while(i < points.size())
+    {
+        if( (i != points.size() - 1)
+            && (sqr(prevPoint.x() - points[i].x()) + sqr(prevPoint.y() - points[i].y()) < 1000)
+          )
+            points.removeAt(i);
+        else
+        {
+            prevPoint = points[i];
+            ++i;
+        }
+    }
+
+    paths[0] = points;
+
+
+    // redraw path
+    {
+        QGraphicsPathItem * pathItem = static_cast<QGraphicsPathItem *>(items()[0]);
+        pathItem->setPath(pointsToPath(paths[0]));
+    }
+
+    emit pathChanged();
+}
+
+QPainterPath DrawMapScene::pointsToPath(const QList<QPoint> points)
+{
+    QPainterPath path;
+
+    if(points.size())
+    {
+        QPointF p = points[0] + QPointF(0.01, 0.01);
+        path.moveTo(p);
+
+        foreach(QPoint p, points)
+            path.lineTo(p);
+    }
+
+    return path;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/drawmapscene.h	Mon Dec 13 22:12:30 2010 +0300
@@ -0,0 +1,40 @@
+#ifndef DRAWMAPSCENE_H
+#define DRAWMAPSCENE_H
+
+#include <QGraphicsScene>
+#include <QPainterPath>
+
+class QGraphicsPathItem;
+
+typedef QList<QList<QPoint> > Paths;
+
+class DrawMapScene : public QGraphicsScene
+{
+Q_OBJECT
+public:
+    explicit DrawMapScene(QObject *parent = 0);
+
+    QByteArray encode();
+    void decode(QByteArray data);
+
+signals:
+    void pathChanged();
+
+public slots:
+    void undo();
+    void simplifyLast();
+
+private:
+    QPen m_pen;
+    QBrush m_brush;
+    QGraphicsPathItem  * m_currPath;
+    Paths paths;
+
+    virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent);
+    virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
+    virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent);
+
+    QPainterPath pointsToPath(const QList<QPoint> points);
+};
+
+#endif // DRAWMAPSCENE_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/drawmapwidget.cpp	Mon Dec 13 22:12:30 2010 +0300
@@ -0,0 +1,38 @@
+#include "drawmapwidget.h"
+
+DrawMapWidget::DrawMapWidget(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::DrawMapWidget)
+{
+    ui->setupUi(this);
+}
+
+DrawMapWidget::~DrawMapWidget()
+{
+    delete ui;
+}
+
+void DrawMapWidget::changeEvent(QEvent *e)
+{
+    QWidget::changeEvent(e);
+    switch (e->type()) {
+    case QEvent::LanguageChange:
+        ui->retranslateUi(this);
+        break;
+    default:
+        break;
+    }
+}
+
+void DrawMapWidget::setScene(DrawMapScene * scene)
+{
+    ui->graphicsView->setScene(scene);
+}
+
+void DrawMapWidget::resizeEvent(QResizeEvent * event)
+{
+    Q_UNUSED(event);
+
+    if(ui->graphicsView && ui->graphicsView->scene())
+        ui->graphicsView->fitInView(ui->graphicsView->scene()->sceneRect(), Qt::KeepAspectRatio);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/drawmapwidget.h	Mon Dec 13 22:12:30 2010 +0300
@@ -0,0 +1,61 @@
+#ifndef DRAWMAPWIDGET_H
+#define DRAWMAPWIDGET_H
+
+#include <QWidget>
+#include <QHBoxLayout>
+#include <QPushButton>
+#include <QGraphicsView>
+#include <QApplication>
+
+#include "qaspectratiolayout.h"
+#include "drawmapscene.h"
+
+namespace Ui {
+    class Ui_DrawMapWidget
+    {
+    public:
+        QGraphicsView *graphicsView;
+        QPushButton *pbUndo;
+
+        void setupUi(QWidget *drawMapWidget)
+        {
+            QAspectRatioLayout * arLayout = new QAspectRatioLayout(drawMapWidget);
+            arLayout->setMargin(0);
+
+            graphicsView = new QGraphicsView(drawMapWidget);
+            arLayout->addWidget(graphicsView);
+
+            retranslateUi(drawMapWidget);
+
+            QMetaObject::connectSlotsByName(drawMapWidget);
+        } // setupUi
+
+        void retranslateUi(QWidget *drawMapWidget)
+        {
+            Q_UNUSED(drawMapWidget);
+        } // retranslateUi
+
+    };
+
+    class DrawMapWidget: public Ui_DrawMapWidget {};
+}
+
+class DrawMapWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit DrawMapWidget(QWidget *parent = 0);
+    ~DrawMapWidget();
+
+    void setScene(DrawMapScene * scene);
+
+protected:
+    void changeEvent(QEvent *e);
+    virtual void resizeEvent(QResizeEvent * event);
+
+private:
+    Ui::DrawMapWidget *ui;
+};
+
+#endif // DRAWMAPWIDGET_H
--- a/QTfrontend/hwform.cpp	Mon Dec 13 19:26:20 2010 +0100
+++ b/QTfrontend/hwform.cpp	Mon Dec 13 22:12:30 2010 +0300
@@ -57,6 +57,7 @@
 #include "ammoSchemeModel.h"
 #include "bgwidget.h"
 #include "xfire.h"
+#include "drawmapwidget.h"
 
 #ifdef __APPLE__
 #include "CocoaInitializer.h"
@@ -432,6 +433,24 @@
 #ifdef USE_XFIRE
     updateXfire();
 #endif
+    if(id == ID_PAGE_DRAWMAP)
+    {
+        DrawMapScene * scene;
+        if(lastid = ID_PAGE_MULTIPLAYER)
+            scene = ui.pageMultiplayer->gameCFG->pMapContainer->getDrawMapScene();
+        else
+            scene = ui.pageNetGame->pGameCFG->pMapContainer->getDrawMapScene();
+
+        ui.pageDrawMap->drawMapWidget->setScene(scene);
+    }
+    if(lastid == ID_PAGE_DRAWMAP)
+    {
+        if(id = ID_PAGE_MULTIPLAYER)
+            ui.pageMultiplayer->gameCFG->pMapContainer->changeImage();
+        else
+            ui.pageNetGame->pGameCFG->pMapContainer->changeImage();
+    }
+
     if (id == ID_PAGE_MULTIPLAYER || id == ID_PAGE_NETGAME) {
         QStringList tmNames = config->GetTeamsList();
         TeamSelWidget* curTeamSelWidget;
--- a/QTfrontend/mapContainer.cpp	Mon Dec 13 19:26:20 2010 +0100
+++ b/QTfrontend/mapContainer.cpp	Mon Dec 13 22:12:30 2010 +0300
@@ -40,9 +40,7 @@
     mainLayout(this),
     pMap(0),
     mapgen(MAPGEN_REGULAR),
-    maze_size(0),
-    drawnMapData(QByteArray::fromBase64("BHoGw4IEegbjAgR6BuwCCnYEaIIJKwRIgglLBEgCCXgERAIJoQQ/AgnBBDsCCeUEMgIKCQQpAgopBCQCCk0ELQIKXwRIAgo/BE0CCiAEVgIJ+wRfAgnOBGgCCaoEbQIJfQRxAgldBHYCCTkEdgIJFARxAgj+BIgCCOwEqAIJEASsAgkwBJ8CCV0ElgIJhgSWAgmqBJYCCcoElgIJ7gSMAgoOBIwCCNAE2YII2QS1AgjsBJYCCPUEdgIJAgRWAgkQBDYCCScEIAIJSwQXAgl0BAkCCZgEAAIJuAP3AgncA/ICCgUD7gIKJAPlAgo/A/cCClYEDgIKbQQkAgqDBDsCCpoEUgIKrARbAghIBP6CCGgE/gIIjAT1AgixBOwCCNUE5wII9QTjAgkUBNkCCTkE0AIJWATHAgl4BMMCCZgEvgIJvAS1AgncBKwCCgAEowIKIASaAgo/BJECCl8EiAIKfwSDAgqfBHYCCscEbQIK5wRoAgr5BGQCCLUGcYIIzAaIAgjnBpoCCQcGrAIJKwa1AglUBroCCXgGvgIJmAa+Agm8Br4CCeAGvgIKAAa6AgogBrUCCj8GqAIKXwaWAgp6Bn8CCpEGaAIKnwZSAgotBZOCCjIFjwIJIgWTggk0BZwCCSsFmIIHYQeBggdhBNmCB2EFBwIHYQUrAgdhBUsCB2EFbwIHYQWqAgdhBc4CB2EF9wIHYQYgAgdhBlICB2EGegIHYQaaAgdhBswCB2EG/gIHYQcQAgZ/BimCBoMGKQIGfwaMggaDBrECBn8G1QIGfwb1AgZ/BwsCBbMFaoIFrgWKAgWqBa4CBaUF6QIFnAYSAgWYBjICBYoGbQIFfQaMAgV0BrUCBWoG3gIFagb+AgVhByICBWEHGQIEmgY2ggS+BkQCBOwGRAIFEAZEAgUwBj8CBVQGOwIFWAY7AgS1BUuCBLUFbwIErAWTAgSjBcECBJ8F+wIEkQYpAgSIBk0CBH8GegIEfwaoAgR6BrUC")
-    )
+    maze_size(0)
 {
     hhSmall.load(":/res/hh_small.png");
     hhLimit = 18;
@@ -345,7 +343,7 @@
     pMap = new HWMap();
     connect(pMap, SIGNAL(ImageReceived(const QImage)), this, SLOT(setImage(const QImage)));
     connect(pMap, SIGNAL(HHLimitReceived(int)), this, SLOT(setHHLimit(int)));
-    pMap->getImage(m_seed.toStdString(), getTemplateFilter(), mapgen, maze_size, drawnMapData);
+    pMap->getImage(m_seed.toStdString(), getTemplateFilter(), mapgen, maze_size, getDrawnMapData());
 }
 
 void HWMapContainer::themeSelected(int currentRow)
@@ -543,7 +541,7 @@
 
 QByteArray HWMapContainer::getDrawnMapData()
 {
-    return drawnMapData;
+    return drawMapScene.encode();
 }
 
 void HWMapContainer::seedEdited(const QString & seed)
@@ -556,3 +554,8 @@
         emit seedChanged(seed);
     }
 }
+
+DrawMapScene * HWMapContainer::getDrawMapScene()
+{
+    return &drawMapScene;
+}
--- a/QTfrontend/mapContainer.h	Mon Dec 13 19:26:20 2010 +0100
+++ b/QTfrontend/mapContainer.h	Mon Dec 13 22:12:30 2010 +0300
@@ -27,6 +27,7 @@
 #include <QLineEdit>
 
 #include "hwmap.h"
+#include "drawmapscene.h"
 
 class QPushButton;
 class IconedGroupBox;
@@ -53,6 +54,7 @@
   int get_maze_size(void) const;
   bool getCurrentIsMission() const;
   QByteArray getDrawnMapData();
+  DrawMapScene * getDrawMapScene();
 
  public slots:
   void changeImage();
@@ -106,9 +108,9 @@
   QLabel *maze_size_label;
   QComboBox *maze_size_selection;
   MapGenerator mapgen;
-  QByteArray drawnMapData;
   int numMissions;
   int maze_size;
+  DrawMapScene drawMapScene;
 
   void loadMap(int index);
 };
--- a/QTfrontend/pages.cpp	Mon Dec 13 19:26:20 2010 +0100
+++ b/QTfrontend/pages.cpp	Mon Dec 13 22:12:30 2010 +0300
@@ -63,6 +63,7 @@
 #include "togglebutton.h"
 #include "hwform.h"
 #include "SDLs.h"
+#include "drawmapwidget.h"
 
 PageMain::PageMain(QWidget* parent) :
   AbstractPage(parent)
@@ -2017,5 +2018,8 @@
 {
     QGridLayout * pageLayout = new QGridLayout(this);
 
-    BtnBack = addButton(":/res/Exit.png", pageLayout, 0, 0, true);
+    BtnBack = addButton(":/res/Exit.png", pageLayout, 1, 0, true);
+
+    drawMapWidget = new DrawMapWidget(this);
+    pageLayout->addWidget(drawMapWidget, 0, 0, 1, 2);
 }
--- a/QTfrontend/pages.h	Mon Dec 13 19:26:20 2010 +0100
+++ b/QTfrontend/pages.h	Mon Dec 13 22:12:30 2010 +0300
@@ -61,6 +61,8 @@
 class IconedGroupBox;
 class FreqSpinBox;
 
+class DrawMapWidget;
+
 class AbstractPage : public QWidget
 {
     Q_OBJECT
@@ -582,6 +584,7 @@
 
     QPushButton * BtnBack;
 
+    DrawMapWidget * drawMapWidget;
 };
 
 #endif // PAGES_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/qaspectratiolayout.cpp	Mon Dec 13 22:12:30 2010 +0300
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2009 Nokia Corporation.
+ */
+
+#include "qaspectratiolayout.h"
+
+QAspectRatioLayout::QAspectRatioLayout(QWidget* parent, int spacing) : QLayout(parent) {
+        init(spacing);
+}
+
+QAspectRatioLayout::QAspectRatioLayout(int spacing) {
+        init(spacing);
+}
+
+QAspectRatioLayout::~QAspectRatioLayout() {
+        delete item;
+        delete lastReceivedRect;
+        delete _geometry;
+}
+
+void QAspectRatioLayout::init(int spacing) {
+        item = 0;
+        lastReceivedRect = new QRect(0, 0, 0, 0);
+        _geometry = new QRect(0, 0, 0, 0);
+        setSpacing(spacing);
+}
+
+
+/* Adds item if place isn't already taken. */
+void QAspectRatioLayout::add(QLayoutItem* item) {
+        if(!hasItem()) {
+                replaceItem(item);
+        }
+}
+
+/* Adds item if place isn't already taken. */
+void QAspectRatioLayout::addItem(QLayoutItem* item) {
+        if(!hasItem()) {
+                replaceItem(item);
+        }
+}
+
+/* Adds widget if place isn't already taken. */
+void QAspectRatioLayout::addWidget(QWidget* widget) {
+        if(!hasItem()) {
+                replaceItem(new QWidgetItem(widget));
+        }
+}
+
+/* Returns the item pointer and dereferences it here. */
+QLayoutItem* QAspectRatioLayout::take() {
+        QLayoutItem* item = 0;
+        if(this->hasItem()) {
+                item = this->item;
+                this->item = 0;
+        }
+        return item;
+}
+
+/* Returns the item pointer and dereferences it here. */
+QLayoutItem* QAspectRatioLayout::takeAt(int index) {
+        if(index != 0) {
+                return 0;
+        }
+        return this->take();
+}
+
+/* Returns the item pointer. */
+QLayoutItem* QAspectRatioLayout::itemAt(int index) const {
+        if(index != 0) {
+                return 0;
+        }
+        if(hasItem()) {
+                return this->item;
+        }
+        return 0;
+}
+
+/* Checks if we have an item. */
+bool QAspectRatioLayout::hasItem() const {
+        return this->item != 0;
+}
+
+/* Returns the count of items which can be either 0 or 1. */
+int QAspectRatioLayout::count() const {
+        int returnValue = 0;
+        if(hasItem()) {
+                returnValue = 1;
+        }
+        return returnValue;
+}
+
+/* Replaces the item with the new and returns the old. */
+QLayoutItem* QAspectRatioLayout::replaceItem(QLayoutItem* item) {
+        QLayoutItem* old = 0;
+        if(this->hasItem()) {
+                old = this->item;
+        }
+        this->item = item;
+        setGeometry(*this->_geometry);
+        return old;
+}
+
+/* Tells which way layout expands. */
+Qt::Orientations QAspectRatioLayout::expandingDirections() const {
+        return Qt::Horizontal | Qt::Vertical;
+}
+
+/* Tells which size is preferred. */
+QSize QAspectRatioLayout::sizeHint() const {
+        return this->item->minimumSize();
+}
+
+/* Tells minimum size. */
+QSize QAspectRatioLayout::minimumSize() const {
+        return this->item->minimumSize();
+}
+
+/*
+ * Tells if heightForWidth calculations is handled.
+ * It isn't since width isn't enough to calculate
+ * proper size.
+ */
+bool QAspectRatioLayout::hasHeightForWidth() const {
+        return false;
+}
+
+/* Replaces lastReceivedRect. */
+void QAspectRatioLayout::setLastReceivedRect(const QRect& rect) {
+        QRect* oldRect = this->lastReceivedRect;
+        this->lastReceivedRect = new QRect(rect.topLeft(), rect.size());
+        delete oldRect;
+}
+
+/* Returns geometry */
+QRect QAspectRatioLayout::geometry() {
+        return QRect(*this->_geometry);
+}
+
+/* Sets geometry to given size. */
+void QAspectRatioLayout::setGeometry(const QRect& rect) {
+        /*
+         * We check if the item is set and
+         * if size is the same previously received.
+         * If either is false nothing is done.
+         */
+        if(!this->hasItem() ||
+           areRectsEqual(*this->lastReceivedRect, rect)) {
+                return;
+        }
+        /* Replace the last received rectangle. */
+        setLastReceivedRect(rect);
+        /* Calculate proper size for the item relative to the received size. */
+        QSize properSize = calculateProperSize(rect.size());
+        /* Calculate center location in the rect and with item size. */
+        QPoint properLocation = calculateCenterLocation(rect.size(), properSize);
+        /* Set items geometry */
+        this->item->setGeometry(QRect(properLocation, properSize));
+        QRect* oldRect = this->_geometry;
+        /* Cache the calculated geometry. */
+        this->_geometry = new QRect(properLocation, properSize);
+        delete oldRect;
+        /* Super classes setGeometry */
+        QLayout::setGeometry(*this->_geometry);
+}
+
+/* Takes the shortest side and creates QSize
+ * with the shortest side as width and height. */
+QSize QAspectRatioLayout::calculateProperSize(QSize from) const {
+        QSize properSize;
+        if(from.height() * 2 < from.width()) {
+                properSize.setHeight(from.height() - this->margin());
+                properSize.setWidth(from.height() * 2 - this->margin());
+        }
+        else {
+                properSize.setWidth(from.width() - this->margin());
+                properSize.setHeight(from.width() / 2 - this->margin());
+        }
+        return properSize;
+}
+
+/* Calculates center location from the given height and width for item size. */
+QPoint QAspectRatioLayout::calculateCenterLocation(QSize from,
+                                                   QSize itemSize) const {
+        QPoint centerLocation;
+        if((from.width() - itemSize.width()) > 0) {
+                centerLocation.setX((from.width() - itemSize.width())/2);
+        }
+        if((from.height() - itemSize.height()) > 0) {
+                centerLocation.setY((from.height() - itemSize.height())/2);
+        }
+        return centerLocation;
+}
+
+/* Compares if two QRects are equal. */
+bool QAspectRatioLayout::areRectsEqual(const QRect& a,
+                                       const QRect& b) const {
+        bool result = false;
+        if(a.x() == b.x() &&
+           a.y() == b.y() &&
+           a.height() == b.height() &&
+           a.width() == b.width()) {
+                result = true;
+        }
+        return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/qaspectratiolayout.h	Mon Dec 13 22:12:30 2010 +0300
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009 Nokia Corporation.
+ */
+
+#ifndef QASPECTRATIOLAYOUT_H_
+#define QASPECTRATIOLAYOUT_H_
+
+#include <QLayout>
+#include <QPointer>
+#include <QRect>
+#include <QWidgetItem>
+#include <QLayoutItem>
+
+
+class QAspectRatioLayout : public QLayout
+{
+        Q_OBJECT
+
+public:
+        QAspectRatioLayout(QWidget* parent, int spacing =-1);
+        QAspectRatioLayout(int spacing = -1);
+        ~QAspectRatioLayout();
+
+        /* Convenience method */
+        virtual void add(QLayoutItem* item);
+
+/* http://doc.trolltech.com/qlayout.html#addItem */
+        virtual void addItem(QLayoutItem* item);
+        /* http://doc.trolltech.com/qlayout.html#addWidget */
+        virtual void addWidget(QWidget* widget);
+        /* http://doc.trolltech.com/qlayout.html#takeAt */
+        virtual QLayoutItem* takeAt(int index);
+        /* http://doc.trolltech.com/qlayout.html#itemAt */
+        virtual QLayoutItem* itemAt(int index) const;
+        /* http://doc.trolltech.com/qlayout.html#count */
+        virtual int count() const;
+
+        /*
+         * These are ours since we do have only one item.
+         */
+        virtual QLayoutItem* replaceItem(QLayoutItem* item);
+        virtual QLayoutItem* take();
+        virtual bool hasItem() const;
+
+/* http://doc.trolltech.com/qlayout.html#expandingDirections */
+        virtual Qt::Orientations expandingDirections() const;
+
+        /*
+         * This method contains most of the juice of this article.
+         * http://doc.trolltech.com/qlayoutitem.html#setGeometry
+         */
+        virtual void setGeometry(const QRect& rect);
+        /* http://doc.trolltech.com/qlayoutitem.html#geometry */
+        virtual QRect geometry();
+
+        /* http://doc.trolltech.com/qlayoutitem.html#sizeHint */
+        virtual QSize sizeHint() const;
+        /* http://doc.trolltech.com/qlayout.html#minimumSize */
+        virtual QSize minimumSize() const;
+        /* http://doc.trolltech.com/qlayoutitem.html#hasHeightForWidth */
+        virtual bool hasHeightForWidth() const;
+
+private:
+        /* Saves the last received rect. */
+        void setLastReceivedRect(const QRect& rect);
+        /* Used to initialize the object. */
+        void init(int spacing);
+        /* Calculates the maximum size for the item from the assigned size. */
+        QSize calculateProperSize(QSize from) const;
+        /* Calculates the center location from the assigned size and
+         * the items size. */
+        QPoint calculateCenterLocation(QSize from, QSize itemSize) const;
+        /* Check if two QRects are equal */
+        bool areRectsEqual(const QRect& a, const QRect& b) const;
+        /* Contains item reference */
+        QLayoutItem* item;
+        /*
+         * Used for caching so we won't do calculations every time
+         * setGeometry is called.
+         */
+        QRect* lastReceivedRect;
+        /* Contains geometry */
+        QRect* _geometry;
+
+};
+
+#endif /* QASPECTRATIOLAYOUT_H_ */