diff --git a/editor/assets/1x1.png b/editor/assets/1x1.png new file mode 100644 index 0000000000000000000000000000000000000000..f10fe7402228f237506f91d3d581718a721d6a39 Binary files /dev/null and b/editor/assets/1x1.png differ diff --git a/editor/assets/1x2.png b/editor/assets/1x2.png new file mode 100644 index 0000000000000000000000000000000000000000..f848e8fe06d40274042a400b7a68bc74bbc46bea Binary files /dev/null and b/editor/assets/1x2.png differ diff --git a/editor/assets/2x1.png b/editor/assets/2x1.png new file mode 100644 index 0000000000000000000000000000000000000000..de7dbf57844275b568faf8dadce3d40bb92df564 Binary files /dev/null and b/editor/assets/2x1.png differ diff --git a/editor/assets/2x2.png b/editor/assets/2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..cc6bc5fdcf2f11eaa065aed061b877495a8b94d6 Binary files /dev/null and b/editor/assets/2x2.png differ diff --git a/editor/assets/cross.png b/editor/assets/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..6e94d3e39204a50ff218ada93e038b905903dcf9 Binary files /dev/null and b/editor/assets/cross.png differ diff --git a/editor/assets/custom.png b/editor/assets/custom.png new file mode 100644 index 0000000000000000000000000000000000000000..42a50a780e9ea301eaf28ab24a3923faa93ec8cd Binary files /dev/null and b/editor/assets/custom.png differ diff --git a/editor/src/CenterGrid.cpp b/editor/src/CenterGrid.cpp index 2dd8b237908fe2965f1a5313dfa4e771d21b4482..dc2ca406f703280f5bad0a65725089c20e26cfb1 100644 --- a/editor/src/CenterGrid.cpp +++ b/editor/src/CenterGrid.cpp @@ -14,13 +14,25 @@ CenterGrid::CenterGrid(QWidget* parent) view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view->setAlignment(Qt::AlignCenter | Qt::AlignCenter); + // Initialize the 2D container + const int rows = 64; + const int cols = 64; + gridItems.resize(rows); + for (int row = 0; row < rows; ++row) + { + gridItems[row].resize(cols); + } + // Create tiles const qreal tileSize = 20.0; - for (int row = 0; row < 64; ++row) { - for (int col = 0; col < 64; ++col) { + for (int row = 0; row < rows; ++row) + { + for (int col = 0; col < cols; ++col) + { GridItem* tile = new GridItem(row, col, tileSize); tile->setPos(col * tileSize, row * tileSize); scene->addItem(tile); + gridItems[row][col] = tile; connect(tile, &GridItem::clicked, this, &CenterGrid::onTileClicked); } } @@ -35,7 +47,8 @@ CenterGrid::CenterGrid(QWidget* parent) setLayout(layout); //Resize after initialization is done to fit window size - QTimer::singleShot(0, this, [this]() { + QTimer::singleShot(0, this, [this]() + { view->fitInView(scene->sceneRect(), Qt::KeepAspectRatio); }); } @@ -46,20 +59,37 @@ void CenterGrid::resizeEvent(QResizeEvent* event) view->fitInView(scene->sceneRect(), Qt::KeepAspectRatio); } -void CenterGrid::setCurrentSprite(const QString& message) +void CenterGrid::setCurrentSprite(const QPixmap pixmap) { - currentSprite = message; + m_currentSprite = pixmap; } void CenterGrid::onTileClicked(int row, int col) { - QString message = currentSprite; - QMessageBox::information(this, "Tile Clicked", message + " clickedTile: (" + QString::number(row) + "," + QString::number(col) + ")!"); + GridItem* tile = getTile(row,col); + tile->setPixmap(m_currentSprite); +} + +GridItem* CenterGrid::getTile(int row, int col) const +{ + if (row >= 0 && row < gridItems.size() && col >= 0 && col < gridItems[row].size()) + { + return gridItems[row][col]; + } + return nullptr; } void CenterGrid::drawPreset(int index) { QList<QGraphicsItem*> items = scene->items(); + for (QGraphicsItem* item : scene->items()) + { + GridItem* gridItem = dynamic_cast<GridItem*>(item); + if (gridItem) + { + gridItem->reset(); + } + } switch(index) { case(0): diff --git a/editor/src/CenterGrid.hpp b/editor/src/CenterGrid.hpp index 42d9151a8438273e189a7e7e12dd5833ab0e609b..d14d51be011abb8e4df585d70fd6e03b2b7bf140 100644 --- a/editor/src/CenterGrid.hpp +++ b/editor/src/CenterGrid.hpp @@ -6,26 +6,80 @@ #include <QVBoxLayout> #include <QMessageBox> #include <QTimer> +#include <QPixmap> #include "GridItem.hpp" namespace editor { +/** +* @brief Central widget of the Editor, contains editable grid representing a room +*/ class CenterGrid : public QWidget { Q_OBJECT public: + /** + * @brief Creates a new CenterGrid + * @param parent parent widget of CenterGrid + */ CenterGrid(QWidget* parent = nullptr); - void setCurrentSprite(const QString& message); + + /** + * @brief Setter function to update which sprite is currently selected and needs to be places when grid clicked + * @param message TEMPORARY message that is shown when tile is clicked replace with sprite data + */ + void setCurrentSprite(const QPixmap pixmap); + + /** + * @brief Function for drawing the currently selected sprite on a tile when tile is clicked + * @param row row of the clicked tile (y coordiante) + * @param col column of the clicked tile (x coordinate) + */ void onTileClicked(int row, int col); + + /** + * @brief draws room presets on the grid + * @param index index of room preset that needs to be drawn + */ void drawPreset(int index); + /** + * @brief gets GridItem by row and column + * @param row row (y coordinate) of the GridItem to return + * @param col column (x coordinate) of the GridItem to return + * @return GridItem* of the GridItem at row/col, or nullptr when out of bounds + */ + GridItem* getTile(int row, int col) const; + private: + + /** + * @brief Event that gets called when the window is resized, adjusts CenterGrid to the new size + * @param event ResizeEvent that informs about the window being resized + */ void resizeEvent(QResizeEvent* event); + + /** + * @brief QT element that provides a surface for handling 2D graphics items + */ QGraphicsScene* scene; + + /** + * @brief QT widget for displaying the contents of a QGraphicsScene + */ QGraphicsView* view; - QString currentSprite; + + /** + * @brief Pixmap of the currently selected sprite + */ + QPixmap m_currentSprite; + + /** + * @brief 2D Vector holding all GridItems, making them accessible by position on grid + */ + QVector<QVector<GridItem*>> gridItems; }; } // namespace editor \ No newline at end of file diff --git a/editor/src/EditorApp.hpp b/editor/src/EditorApp.hpp index 228f352db35ae0e0b4ad3445a19b81084f1fb895..96b4c14adea4bf159e753d6e51a3fdfa76c185f9 100644 --- a/editor/src/EditorApp.hpp +++ b/editor/src/EditorApp.hpp @@ -13,6 +13,10 @@ namespace editor class EditorApp : public QApplication { public: + + /** + * @brief Create new EditorApp + */ EditorApp(int &argc, char **argv); }; diff --git a/editor/src/GridItem.cpp b/editor/src/GridItem.cpp index aa0cf4f2902c2fca8b942fb0f1d641633392e5b4..06d051b7712f2d2c29d25a92d85c7736540c5b6d 100644 --- a/editor/src/GridItem.cpp +++ b/editor/src/GridItem.cpp @@ -14,21 +14,43 @@ QRectF GridItem::boundingRect() const return QRectF(0, 0, m_size, m_size); } -void GridItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +void GridItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { painter->setPen(QPen(Qt::black, 1)); - painter->setBrush(m_color); - painter->drawRect(boundingRect()); + + if (m_usePixmap && !m_pixmap.isNull()) + { + painter->drawPixmap(boundingRect(), m_pixmap, m_pixmap.rect()); + } else + { + painter->setBrush(m_color); + painter->drawRect(boundingRect()); + } } void GridItem::setColor(const QColor& color) { - if (m_color != color) { + if (m_color != color) + { m_color = color; update(); } } +void GridItem::setPixmap(const QPixmap& pixmap) +{ + m_pixmap = pixmap.scaled(m_size, m_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + m_usePixmap = true; + update(); +} + +void GridItem::reset() { + m_pixmap = QPixmap(); + m_usePixmap = false; + m_color = Qt::white; + update(); +} + void GridItem::mousePressEvent(QGraphicsSceneMouseEvent* event) { emit clicked(m_row, m_col); diff --git a/editor/src/GridItem.hpp b/editor/src/GridItem.hpp index 7d5c9728437d43f415abbce09b3cbc5ae87fda8d..b891b235bb8eb92bd137c349fc37777a2da1f7f8 100644 --- a/editor/src/GridItem.hpp +++ b/editor/src/GridItem.hpp @@ -7,29 +7,112 @@ namespace editor { +/** +* @brief Single element of the CenterGrid, representing the contents of a single tile of the room +*/ class GridItem : public QGraphicsObject { Q_OBJECT public: + + /** + * @brief Creates a new GridItem and places it in the CenterGrid + * @param row row to place the new item in (y coordinate) + * @param col column to place the new item in (x coordinate) + * @param size size of the grid item + * @param parent parent of the GridItem + */ GridItem(int row, int col, qreal size, QGraphicsItem* parent = nullptr); + + /** + * @brief creates a bounding rectangle for drawing the GridItem + * @return QRectF of the bounding rectangle + */ QRectF boundingRect() const override; + + /** + * @brief function for painting the GridItem + * @param painter QPainter responsible for handling the painting + * @param option parameters needed for drawing a QGraphicsItem + * @param widget optional, widget that is painted on, for us always 0 + */ void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override; + /** + * @brief returns the row (y coordinate) of the GridItem + * @return row (y coordinate) of the GridItem + */ int row() const { return m_row; } + + /** + * @brief returns the column (x coordinate) of the GridItem + * @return column (x coordiante) of the GridItem + */ int col() const { return m_col; } + + /** + * @brief sets the color to paint the GridItem with + * @param color QColor value for the color + */ void setColor(const QColor& color); + /** + * @brief sets pixmap to draw on the GridItem + * @param pixmap pixmap to draw on the GridItem + */ + void setPixmap(const QPixmap& pixmap); + + /** + * @brief reset GridItem to a default state + */ + void reset(); + signals: + /** + * @brief signal to be emitted when the GridItem gets clicked + * @param row row (y coordinate) of the GridItem + * @param col column (x coordiante) of the GridItem + */ void clicked(int row, int col); protected: + /** + * @brief handles clicks on GridItems, emits clicked()-Signal + * @param event QMouseEvent on a QGraphicsScene + */ void mousePressEvent(QGraphicsSceneMouseEvent* event) override; private: + + /** + * @brief row (y coordinate) of the GridItem + */ int m_row; + + /** + * @brief column (x coordiante) of the GridItem + */ int m_col; + + /** + * @brief size of the GridItem + */ qreal m_size; - QColor m_color; // Add color member + + /** + * @brief color of the GridItem + */ + QColor m_color; + + /** + * @brief pixmap of the GridItem + */ + QPixmap m_pixmap; + + /** + * @brief Flag whether solid color or pixmap are to be drawn + */ + bool m_usePixmap; }; } // namespace editor \ No newline at end of file diff --git a/editor/src/MainWindow.cpp b/editor/src/MainWindow.cpp index a3350c38a501eebcafd2727ab3c0a255c6c9f238..bf0ed0ad41e25abcbbe083b54dc8954fc90a5c28 100644 --- a/editor/src/MainWindow.cpp +++ b/editor/src/MainWindow.cpp @@ -28,15 +28,18 @@ MainWindow::MainWindow(DialogSelection selected, const std::filesystem::path& pa // Left section: Scrollable list TileBar* leftWidget = new TileBar(0, this); mainLayout->addWidget(leftWidget); + m_leftWidget = leftWidget; connect(leftWidget, &editor::TileBar::itemClicked, this, &MainWindow::handleTileBarClick); //temporary example, replace with real list of tileset QStringList itemsLeft; + QList<QPixmap> pixmapsLeft; for (int i = 1; i <= 100; ++i) { itemsLeft << QString("Item %1").arg(i); + pixmapsLeft << QPixmap("./editor/assets/images.png"); } - leftWidget->populateList(itemsLeft); + leftWidget->populateList(itemsLeft, pixmapsLeft); // Center grid CenterGrid* middleWidget = new CenterGrid(this); @@ -50,13 +53,20 @@ MainWindow::MainWindow(DialogSelection selected, const std::filesystem::path& pa //temporary example, replace with list of room layouts QStringList itemsRight; + QList<QPixmap> pixmapsRight; itemsRight << QString("1x1 room"); + pixmapsRight << QPixmap("./editor/assets/1x1.png"); itemsRight << QString("1x2 room"); + pixmapsRight << QPixmap("./editor/assets/1x2.png"); itemsRight << QString("2x1 room"); + pixmapsRight << QPixmap("./editor/assets/2x1.png"); itemsRight << QString("2x2 room"); + pixmapsRight << QPixmap("./editor/assets/2x2.png"); itemsRight << QString("cross"); + pixmapsRight << QPixmap("./editor/assets/cross.png"); itemsRight << QString("fully custom"); - rightWidget->populateList(itemsRight); + pixmapsRight << QPixmap("./editor/assets/custom.png"); + rightWidget->populateList(itemsRight, pixmapsRight); // Set layout to the central widget centralWidget->setLayout(mainLayout); @@ -71,10 +81,22 @@ MainWindow::MainWindow(DialogSelection selected, const std::filesystem::path& pa void MainWindow::handleTileBarClick(int index, int id) { - if (id == 0) { - //forward information on clicked sprite/tile to CenterGrid - } else { - m_centerGrid->drawPreset(index); + if (id == 0) + { + m_centerGrid->setCurrentSprite(m_leftWidget->getPixmapByIndex(index)); + } else + { + QMessageBox::StandardButton confirmationPopup; + confirmationPopup = QMessageBox::question( + this, + "Confirmation", + "Changing the preset will delete all placed sprites/tiles! Proceed?", + QMessageBox::Yes | QMessageBox::No + ); + if (confirmationPopup == QMessageBox::Yes) + { + m_centerGrid->drawPreset(index); + } } } diff --git a/editor/src/MainWindow.hpp b/editor/src/MainWindow.hpp index 913e6a4d772075936a3e0baa48bce1bca2a49ffc..de730ae106bde7d3875903baf6869a909407962f 100644 --- a/editor/src/MainWindow.hpp +++ b/editor/src/MainWindow.hpp @@ -23,19 +23,35 @@ namespace editor */ class MainWindow : public QMainWindow { - Q_OBJECT + Q_OBJECT public: + /** + * @brief Create a new MainWindow of the editor + * @param selected selection from StartupDialog (new room/edit room) + * @param path file path for loading levels + * @param parent parent element of MainWindow + */ explicit MainWindow(DialogSelection selected, const std::filesystem::path& path, QWidget* parent = nullptr); private slots: - void handleTileBarClick(int index, int id); + /** + * @brief MainWindow slot to handle TileBar-clicks + * @param index Index of the item that was clicked in the list of items + * @param id Id identifies the tile bar (left or right) in which an item was clicked + */ + void handleTileBarClick(int index, int id); private: - void addListItem(QListWidget* listWidget, const QString& imagePath, const QString& text); - - void onTileClicked(int row, int col); + /** + * @brief Pointer to the centerGrid + */ CenterGrid* m_centerGrid; + /** + * @brief Pointer to leftWidget + */ + TileBar* m_leftWidget; + }; } // editor diff --git a/editor/src/TileBar.cpp b/editor/src/TileBar.cpp index 6d6bad94c929f959c085ad729dc4694482e04cc9..ba59550224638d917b6c7fece053ccc9a4de4744 100644 --- a/editor/src/TileBar.cpp +++ b/editor/src/TileBar.cpp @@ -26,23 +26,35 @@ TileBar::TileBar(int id, QWidget *parent) }); } -void TileBar::populateList(const QStringList& items) +void TileBar::populateList(const QStringList& items, const QList<QPixmap>& pixmaps) { m_List->clear(); - for (const QString& itemText : items) - { - addListItem(m_List, "./editor/assets/images.png", itemText); + const int count = qMin(items.size(), pixmaps.size()); + for (int i = 0; i < count; ++i) { + addListItem(m_List, pixmaps[i], items[i]); } } -void TileBar::addListItem(QListWidget* listWidget, const QString& imagePath, const QString& text) +void TileBar::addListItem(QListWidget* listWidget, const QPixmap& pixmap, const QString& text) { auto* item = new QListWidgetItem(); - QPixmap pixmap(imagePath); QIcon icon(pixmap.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); item->setIcon(icon); item->setText(text); + item->setData(Qt::UserRole, pixmap); listWidget->addItem(item); } +QPixmap TileBar::getPixmapByIndex(int index) +{ + QListWidgetItem* item = m_List->item(index); + if (item) { + QPixmap pixmap = item->data(Qt::UserRole).value<QPixmap>(); + if (!pixmap.isNull()) { + return pixmap; + } + } + return QPixmap(); +} + } \ No newline at end of file diff --git a/editor/src/TileBar.hpp b/editor/src/TileBar.hpp index 835619c6e8e1c10704bb5ef3cd455c54fc61f8d2..99f37fbf04d7d80046344ccacc0ce86e6da8a87d 100644 --- a/editor/src/TileBar.hpp +++ b/editor/src/TileBar.hpp @@ -9,25 +9,72 @@ #include <QString> #include <QVBoxLayout> #include <QDebug> +#include <QPixmap> namespace editor { +/** +* @brief Scrollable list of entries that can vary in type +*/ class TileBar : public QWidget { Q_OBJECT public: + + /** + * @brief creates a new TileBar + * @param id allows handling actions from different instances of TileBars differently when created with unique IDs + * @param parent parent widget of TileBar + */ explicit TileBar(int id, QWidget *parent = nullptr); - void populateList(const QStringList& items); + + /** + * @brief populates TileBar with entries + * @param items list of items to add to show in the TileBar + * @param pixmaps list of pixmaps of the images for the items + */ + void populateList(const QStringList& items, const QList<QPixmap>& pixmaps); + + /** + * @brief get the pixmap of the entry with the given index + * @param index index of the entry to get the pixmap from + */ + QPixmap getPixmapByIndex(int index); signals: + + /** + * @brief signal when an item in a TileBar gets clicked + * @param index index of the item clicked + * @param id id of the tile bar in which the item got clicked + */ void itemClicked(int index, int id); private: + + /** + * @brief ID of the TileBar, allows identifying TileBars when created with unique numbers + */ int m_id; + + /** + * @brief QT widget that holds contents and is scrollable + */ QScrollArea *m_ScrollArea; + + /** + * @brief QT widget holding a list of items + */ QListWidget *m_List; - void addListItem(QListWidget* listWidget, const QString& imagePath, const QString& text); + + /** + * @brief adds items to the list of items shown in the TileBar + * @param listWidget QListWidget to add the items to + * @param pixmap pixmap of image to show for the item + * @param text QString with text to show for the item + */ + void addListItem(QListWidget* listWidget, const QPixmap& pixmap, const QString& text); }; } \ No newline at end of file diff --git a/editor/src/main.cpp b/editor/src/main.cpp index 572119e24a372963cfcd274ae9c4d50509d5dcea..d0f9dc1d0db95205fb29ee87b0704aeb0144fac5 100644 --- a/editor/src/main.cpp +++ b/editor/src/main.cpp @@ -2,10 +2,30 @@ #include "MainWindow.hpp" #include "StartupDialog.hpp" +#include <QStyleFactory> + int main(int argc, char *argv[]) { editor::EditorApp app(argc, argv); editor::StartupDialog startup; + //Set editor to use dark mode + app.setStyle(QStyleFactory::create("Fusion")); + QPalette darkPalette; + darkPalette.setColor(QPalette::Window, QColor(53, 53, 53)); + darkPalette.setColor(QPalette::WindowText, Qt::white); + darkPalette.setColor(QPalette::Base, QColor(25, 25, 25)); + darkPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53)); + darkPalette.setColor(QPalette::ToolTipBase, Qt::white); + darkPalette.setColor(QPalette::ToolTipText, Qt::white); + darkPalette.setColor(QPalette::Text, Qt::white); + darkPalette.setColor(QPalette::Button, QColor(53, 53, 53)); + darkPalette.setColor(QPalette::ButtonText, Qt::white); + darkPalette.setColor(QPalette::BrightText, Qt::red); + darkPalette.setColor(QPalette::Highlight, QColor(142, 45, 197)); + darkPalette.setColor(QPalette::HighlightedText, Qt::black); + app.setPalette(darkPalette); + app.setStyleSheet("QToolTip { color: #FFFFFF; background-color: #2D2D2D; border: 1px solid #404040; }"); + if (startup.exec() == QDialog::Accepted) { editor::MainWindow window(startup.getSelection(), startup.getPath());