+//
+// editorwidget.cpp: Game editor window widget
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who When What
+// --- ---------- ------------------------------------------------------------
+// JLH 07/01/2014 Created this file
+//
+
+#include "editorwidget.h"
+#include <unistd.h> // for usleep()
+#include <string.h>
+#include "boards.h"
+#include "gameboard.h"
+
+
+#define GRIDSIZE 40
+
+
+EditorWidget::EditorWidget(QWidget * parent/*= 0*/): QWidget(parent),
+ currentLevel(0)
+{
+// memset(¤tLevel, 0, sizeof(currentLevel));
+// currentLevel.corner.x = -1;
+// currentLevel.corner.y = -1;
+// levelStorage.push_back(currentLevel);
+// Level * b1 = &level[0];
+// memset(board, 0, sizeof(board));
+// CreateBackground();
+// score->setTextFormat(Qt::PlainText);
+
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ setFocusPolicy(Qt::StrongFocus); // Without this, it gets no keys
+ Load();
+}
+
+
+// This never gets called...!
+EditorWidget::~EditorWidget(void)
+{
+ Save();
+}
+
+
+QSize EditorWidget::sizeHint() const
+{
+ return QSize(400, 400);
+}
+
+
+void EditorWidget::paintEvent(QPaintEvent * /*event*/)
+{
+ QPainter painter(this);
+ QFont font;
+ Level & level = levelStorage[currentLevel];
+
+ for(int y=0; y<=clientArea.height()/GRIDSIZE; y++)
+ {
+ for(int x=0; x<=clientArea.width()/GRIDSIZE; x++)
+ {
+ Point current(level.corner.x + x, level.corner.y + y);
+
+ if ((current.x < 0) && (current.y < 0))
+ {
+ painter.setBrush(Qt::black);
+ painter.drawRect(x + (GRIDSIZE / 2), y + (GRIDSIZE / 2), GRIDSIZE / 2, GRIDSIZE / 2);
+ }
+ else if (current.x < 0)
+ {
+ painter.setBrush(Qt::black);
+ painter.drawRect(x + (GRIDSIZE / 2), y * GRIDSIZE, GRIDSIZE / 2, GRIDSIZE);
+ }
+ else if (current.y < 0)
+ {
+ painter.setBrush(Qt::black);
+ painter.drawRect(x * GRIDSIZE, y + (GRIDSIZE / 2), GRIDSIZE, GRIDSIZE / 2);
+ }
+ else
+ {
+ uint8_t tile = level.board[current.x][current.y];
+
+ painter.setBrush(Qt::transparent);
+ painter.setPen(Qt::black);
+ painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
+
+ if (tile & (GTWall | GTSpace | GTBox))
+ {
+ if (tile & GTWall)
+ {
+ painter.setBrush(Qt::white);
+ painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
+ }
+ else if (tile & GTBox)
+ {
+ painter.setBrush(Qt::red);
+ painter.drawRect((x * GRIDSIZE) + (GRIDSIZE * 0.1),
+ (y * GRIDSIZE) + (GRIDSIZE * 0.1), GRIDSIZE * 0.8, GRIDSIZE * 0.8);
+ }
+ }
+ else if (tile & GTNull)
+ {
+ painter.setBrush(Qt::black);
+// painter.setPen(Qt::black);
+ painter.drawRect(x * GRIDSIZE, y * GRIDSIZE, GRIDSIZE, GRIDSIZE);
+ }
+ else if (tile & GTMan)
+ {
+ painter.setBrush(Qt::yellow);
+ painter.drawEllipse((x * GRIDSIZE) + (GRIDSIZE * 0.1),
+ (y * GRIDSIZE) + (GRIDSIZE * 0.1), GRIDSIZE * 0.8, GRIDSIZE * 0.8);
+ }
+
+ if ((tile & GTBoxSpot) && !(tile & (GTWall | GTNull)))
+ {
+ painter.setBrush(Qt::magenta);
+ painter.drawRect((x * GRIDSIZE) + (GRIDSIZE / 3),
+ (y * GRIDSIZE) + (GRIDSIZE / 3), GRIDSIZE / 3, GRIDSIZE / 3);
+ }
+ }
+ }
+ }
+
+ int x = level.cursor.x - level.corner.x;
+ int y = level.cursor.y - level.corner.y;
+
+ painter.setBrush(Qt::transparent);
+ painter.setPen(Qt::darkGreen);
+ painter.drawEllipse((x * GRIDSIZE) + 4, (y * GRIDSIZE) + 4, GRIDSIZE - 8, GRIDSIZE - 8);
+}
+
+
+void EditorWidget::mousePressEvent(QMouseEvent * event)
+{
+ if (event->button() == Qt::LeftButton)
+ {
+ event->accept();
+ }
+}
+
+
+void EditorWidget::mouseMoveEvent(QMouseEvent * event)
+{
+ if (event->buttons() & Qt::LeftButton)
+ {
+ event->accept();
+ }
+}
+
+
+void EditorWidget::mouseReleaseEvent(QMouseEvent * event)
+{
+ if (event->button() == Qt::LeftButton)
+ {
+ event->accept();
+ }
+}
+
+
+void EditorWidget::mouseDoubleClickEvent(QMouseEvent * event)
+{
+ if (event->button() == Qt::LeftButton)
+ {
+ event->accept();
+ }
+}
+
+
+void EditorWidget::keyPressEvent(QKeyEvent * event)
+{
+ int key = event->key();
+ Level & level = levelStorage[currentLevel];
+ Point & cursor = level.cursor;
+ Point & corner = level.corner;
+
+ if (key == Qt::Key_Up)
+ {
+ if (cursor.y > 0)
+ cursor.y--;
+
+ if (((cursor.y - corner.y) == 0) && (corner.y > -1))
+ corner.y--;
+ }
+ else if (key == Qt::Key_Down)
+ {
+ if (cursor.y < (BOARDSIZE - 1))
+ cursor.y++;
+
+ if (cursor.y >= (range.y + corner.y - 1))
+ {
+ if (corner.y < (BOARDSIZE - range.y))
+ corner.y++;
+ }
+ }
+ else if (key == Qt::Key_Left)
+ {
+ if (cursor.x > 0)
+ cursor.x--;
+
+ if (((cursor.x - corner.x) == 0) && (corner.x > -1))
+ corner.x--;
+ }
+ else if (key == Qt::Key_Right)
+ {
+ if (cursor.x < (BOARDSIZE - 1))
+ cursor.x++;
+
+ if (cursor.x >= (range.x + corner.x - 1))
+ {
+ if (corner.x < (BOARDSIZE - range.x))
+ corner.x++;
+ }
+ }
+ else if (key == Qt::Key_Period)
+ {
+ level.board[cursor.x][cursor.y] ^= GTBoxSpot;
+ }
+ else if (key == Qt::Key_B)
+ {
+ level.board[cursor.x][cursor.y] &= ~(GTSpace | GTWall | GTBox);
+ level.board[cursor.x][cursor.y] |= GTBox;
+ }
+ else if (key == Qt::Key_W)
+ {
+ level.board[cursor.x][cursor.y] = GTWall;
+ }
+ else if (key == Qt::Key_Space)
+ {
+ level.board[cursor.x][cursor.y] &= ~(GTSpace | GTWall | GTBox);
+ level.board[cursor.x][cursor.y] |= GTSpace;
+ }
+ else if (key == Qt::Key_O)
+ {
+ // There can be only one!
+ for(int x=0; x<BOARDSIZE; x++)
+ for(int y=0; y<BOARDSIZE; y++)
+ level.board[x][y] &= ~GTMan;
+
+ // Also, he can only be on a space!
+ level.board[cursor.x][cursor.y] &= GTBoxSpot;
+ level.board[cursor.x][cursor.y] |= GTMan;
+ }
+ else if (key == Qt::Key_V)
+ {
+ level.board[cursor.x][cursor.y] = GTNull;
+ }
+ else
+ return; // Only update screen if keypress was recognized
+
+ update();
+}
+
+
+void EditorWidget::keyReleaseEvent(QKeyEvent * /*event*/)
+{
+}
+
+
+void EditorWidget::resizeEvent(QResizeEvent * /*event*/)
+{
+// QSize s = event->size();
+
+//printf("Size of window is: %i x %i\n", s.width(), s.height());
+//printf("Size of game grid is: %i x %i\n", gameBoard->width, gameBoard->height);
+ ResizeGrid();
+}
+
+
+void EditorWidget::CreateBackground(void)
+{
+#if 0
+ char BGRes[27][64] = {
+ ":/res/grfttile.bmp",
+ ":/res/cloth_6.bmp",
+ ":/res/bg_tech_3.bmp",
+ ":/res/bg_tech_2.bmp",
+ ":/res/bg_tech_1.bmp",
+ ":/res/bg_weave_3.bmp",
+ ":/res/bg_weave_2.bmp",
+ ":/res/bg_clouds_2.bmp",
+ ":/res/bg_floor_plate.bmp",
+ ":/res/bg_marble_b.bmp",
+ ":/res/bg_marble_g.bmp",
+ ":/res/bg_marble_p.bmp",
+ ":/res/bg_marble_r.bmp",
+ ":/res/bg_marble_rb.bmp",
+ ":/res/bg_money_1.bmp",
+ ":/res/bg_pinstripe2.bmp",
+ ":/res/bg_pinstripe7.bmp",
+ ":/res/bg_raindrops_large.bmp",
+ ":/res/bg_raindrops_small.bmp",
+ ":/res/bg_stucco.bmp",
+ ":/res/bg_wood_w.bmp",
+ ":/res/bg_wood_b1.bmp",
+ ":/res/bg_wood_d.bmp",
+ ":/res/bg_wood_f.bmp",
+ ":/res/bg_wood_mh.bmp",
+ ":/res/bg_wood_mv.bmp",
+ ":/res/bg_wood_ro.bmp"
+ };
+
+ QPalette pal = palette();
+ pal.setBrush(backgroundRole(), QBrush(QPixmap(BGRes[m_nBackground])));
+ setAutoFillBackground(true);
+ setPalette(pal);
+
+ return true; // Ignore errors for now...
+#else
+// QPalette pal = palette();
+// pal.setBrush(backgroundRole(), QBrush(QPixmap(":/bg_marble_g.bmp")));
+// setAutoFillBackground(true);
+// setPalette(pal);
+#endif
+}
+
+
+void EditorWidget::ClearLevel(void)
+{
+// gameBoard->ResetGame();
+// memset(board, 0, sizeof(board));
+ update();
+}
+
+
+bool EditorWidget::Load(void)
+{
+ FILE * f = fopen("./wmd-level.data", "rb");
+
+ if (f)
+ {
+ int numberOfLevels;
+ fscanf(f, "%i\n", &numberOfLevels);
+//printf("Load: Looking for %i levels...\n", numberOfLevels);
+
+ for(int i=0; i<numberOfLevels; i++)
+ {
+ Level level;
+ Point size, corner;
+ memset(&level, 0, sizeof(Level));
+
+ fscanf(f, "%i\n%i\n%i\n%i\n", &size.x, &size.y, &corner.x, &corner.y);
+ fscanf(f, "%i\n%i\n%i\n%i\n", &level.corner.x, &level.corner.y, &level.cursor.x, &level.cursor.y);
+ fread(level.name, 1, 41, f);
+//printf("Load: name=\"%s\"\n", level.name);
+//printf("Load: size=%i, %i; corner=%i, %i; level corner=%i, %i; cursor=%i, %i\n", size.x, size.y, corner.x, corner.y, level.corner.x, level.corner.y, level.cursor.x, level.cursor.y);
+
+ for(int k=0; k<size.y; k++)
+ for(int j=0; j<size.x; j++)
+ level.board[corner.x + j][corner.y + k] = fgetc(f);
+
+ levelStorage.push_back(level);
+ }
+
+ fclose(f);
+ return true;
+ }
+
+ // There is no save file, so use the internal levels
+ for(uint32_t i=0; i<NUMBER_OF_BOARDS; i++)
+ {
+ Level l;
+ memset(&l, 0, sizeof(Level));
+ l.corner.x = l.corner.y = -1;
+
+ // Create a GameBoard object for level #i (1-based)...
+ GameBoard b(i + 1);
+
+ for(int32_t x=0; x<b.width; x++)
+ for(int32_t y=0; y<b.height; y++)
+ l.board[x][y] = b.board[(y * b.width) + x];
+
+ l.board[b.playerX][b.playerY] |= GTMan;
+ strncpy(l.name, b.name, 40); // NULL is provided by the memset() above
+ levelStorage.push_back(l);
+ }
+
+ return false;
+}
+
+
+bool EditorWidget::Save(void)
+{
+ FILE * f = fopen("./wmd-level.data", "wb");
+
+ if (!f)
+ {
+ printf("Could not open 'wmd-level.data' for writing!\n");
+ return false;
+ }
+
+ fprintf(f, "%lu\n", levelStorage.size());
+
+ for(uint32_t i=0; i<levelStorage.size(); i++)
+ {
+ Level & level = levelStorage[i];
+ Point size, corner;
+ GetSizeAndCorner(&level, size, corner);
+
+ fprintf(f, "%i\n%i\n%i\n%i\n", size.x, size.y, corner.x, corner.y);
+ fprintf(f, "%i\n%i\n%i\n%i\n", level.corner.x, level.corner.y, level.cursor.x, level.cursor.y);
+ fwrite(level.name, 1, 41, f);
+
+ for(int k=0; k<size.y; k++)
+ for(int j=0; j<size.x; j++)
+ fputc(level.board[corner.x + j][corner.y + k], f);
+ }
+
+ fclose(f);
+ return true;
+}
+
+
+void EditorWidget::SetNameOnCurrentLevel(const char * newName)
+{
+ Level & level = levelStorage[currentLevel];
+ memset(level.name, 0, 41);
+ strncpy(level.name, newName, 40);
+}
+
+
+void EditorWidget::GetSizeAndCorner(Level * level, Point & size, Point & corner)
+{
+ size.x = size.y = corner.x = corner.y = 0;
+ Point min, max;
+ min.x = min.y = BOARDSIZE;
+
+ for(int x=0; x<BOARDSIZE; x++)
+ {
+ for(int y=0; y<BOARDSIZE; y++)
+ {
+ if (level->board[x][y] == 0)
+ continue;
+
+ if (min.x > x)
+ min.x = x;
+
+ if (min.y > y)
+ min.y = y;
+
+ if (max.x < x)
+ max.x = x;
+
+ if (max.y < y)
+ max.y = y;
+ }
+ }
+
+ size.x = max.x - min.x + 1;
+ size.y = max.y - min.y + 1;
+ corner.x = min.x;
+ corner.y = min.y;
+}
+
+
+void EditorWidget::ResizeGrid(void)
+{
+ clientArea = size();
+ range.x = clientArea.width() / GRIDSIZE;
+ range.y = clientArea.height() / GRIDSIZE;
+#if 0
+ QSize s = size();
+
+ // Set some room for the board title (7.5%)
+ float titleHeight = s.height() * 0.075;
+
+ // Find the constraints
+ float boxSizeX = s.width() / gameBoard->width;
+ float boxSizeY = (s.height() - titleHeight) / gameBoard->height;
+
+ maxLength = (int)(boxSizeX > boxSizeY ? boxSizeY : boxSizeX);
+
+ offsetX = (s.width() - (maxLength * gameBoard->width)) / 2;
+ offsetY = ((s.height() - titleHeight) - (maxLength * gameBoard->height)) / 2;
+ titleBox.setRect(0, offsetY, s.width(), titleHeight);
+ offsetY += titleHeight; // Add in the title's height
+#endif
+}
+
+
+//
+// Halt processing for 'count' milliseconds
+//
+void EditorWidget::Pause(int count)
+{
+// DWORD endCount = GetTickCount() + count;
+// while (GetTickCount() < endCount) {} // Still crude, but better control
+#if 1
+ usleep(count * 1000);
+#else
+ // This causes it to lock up randomly. :-/
+ QTime time;
+ time.start();
+
+ while (time.msec() < count)
+ ; // Do nothing...
+#endif
+}
+