diff --git a/Robot.pro b/Robot.pro new file mode 100644 index 0000000..1e8feca --- /dev/null +++ b/Robot.pro @@ -0,0 +1,39 @@ +#Enabled the qt modules. +QT += core gui widgets + +#Enabled c++ 11 syntax. +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + ground.cpp \ + robot.cpp \ + panel.cpp \ + menubar.cpp \ + robotmanagement.cpp \ + paneldock.cpp \ + robotaddwidget.cpp \ + groundpreviewwidget.cpp \ + generateground.cpp \ + groundeditor.cpp \ + generategroundbase.cpp \ + barrackseditor.cpp \ + barrackseditorbase.cpp + +HEADERS += \ + mainwindow.h \ + ground.h \ + robot.h \ + panel.h \ + groundbase.h \ + menubar.h \ + robotmanagement.h \ + paneldock.h \ + robotaddwidget.h \ + groundpreviewwidget.h \ + generateground.h \ + groundeditor.h \ + generategroundbase.h \ + barrackseditor.h \ + barrackseditorbase.h diff --git a/barrackseditor.cpp b/barrackseditor.cpp new file mode 100644 index 0000000..5d8a4d2 --- /dev/null +++ b/barrackseditor.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "barrackseditor.h" + +BarracksEditor::BarracksEditor(QWidget *parent) : + BarracksEditorBase(parent) +{ +} diff --git a/barrackseditor.h b/barrackseditor.h new file mode 100644 index 0000000..9a6f9c6 --- /dev/null +++ b/barrackseditor.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BARRACKSEDITOR_H +#define BARRACKSEDITOR_H + +#include "barrackseditorbase.h" + +class BarracksEditor : public BarracksEditorBase +{ + Q_OBJECT +public: + explicit BarracksEditor(QWidget *parent = 0); + +signals: + +public slots: + +}; + +#endif // BARRACKSEDITOR_H diff --git a/barrackseditorbase.cpp b/barrackseditorbase.cpp new file mode 100644 index 0000000..09504e6 --- /dev/null +++ b/barrackseditorbase.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "barrackseditorbase.h" + +BarracksEditorBase::BarracksEditorBase(QWidget *parent) : + QWidget(parent) +{ +} diff --git a/barrackseditorbase.h b/barrackseditorbase.h new file mode 100644 index 0000000..ee22c06 --- /dev/null +++ b/barrackseditorbase.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BARRACKSEDITORBASE_H +#define BARRACKSEDITORBASE_H + +#include + +class BarracksEditorBase : public QWidget +{ + Q_OBJECT +public: + explicit BarracksEditorBase(QWidget *parent = 0); + +signals: + +public slots: + +}; + +#endif // BARRACKSEDITORBASE_H diff --git a/generateground.cpp b/generateground.cpp new file mode 100644 index 0000000..b0171b8 --- /dev/null +++ b/generateground.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include + +#include "groundeditor.h" +#include "barrackseditor.h" + +#include "generateground.h" + +GenerateGround::GenerateGround(QWidget *parent) : + GenerateGroundBase(parent), + m_tabManager(new QTabWidget(this)), + m_groundEditor(new GroundEditor(this)), + m_barracksEditor(new BarracksEditor(this)), + m_okay(new QPushButton(this)), + m_cancel(new QPushButton(this)) +{ + //Set properties. +#ifdef Q_OS_MACX + setWindowFlags(Qt::Sheet); +#endif + + //Configure buttons. + m_cancel->setShortcut(QKeySequence(Qt::Key_Escape)); + connect(m_cancel, + static_cast(&QPushButton::clicked), + [=] + { + close(); + }); + + //Initial the layout. + QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::LeftToRight, + this); + setLayout(mainLayout); + + mainLayout->addWidget(m_tabManager, 1); + + m_tabManager->addTab(m_groundEditor, ""); + m_tabManager->addTab(m_barracksEditor, ""); + + QBoxLayout *buttonLayout=new QBoxLayout(QBoxLayout::TopToBottom, + mainLayout->widget()); + mainLayout->addLayout(buttonLayout); + buttonLayout->addWidget(m_okay); + buttonLayout->addWidget(m_cancel); + buttonLayout->addStretch(); + + retranslate(); +} + +void GenerateGround::retranslate() +{ + m_okay->setText(tr("Ok")); + m_cancel->setText(tr("Cancel")); + + m_tabManager->setTabText(0, tr("Ground")); + m_tabManager->setTabText(1, tr("Barracks")); +} diff --git a/generateground.h b/generateground.h new file mode 100644 index 0000000..12013b0 --- /dev/null +++ b/generateground.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GENERATEGROUND_H +#define GENERATEGROUND_H + +#include "generategroundbase.h" + +class QPushButton; +class QTabWidget; +class GroundEditor; +class BarracksEditor; +/*! + * \brief The GenerateGround class is a default realization of + * GenerateGroundBase. + */ +class GenerateGround : public GenerateGroundBase +{ + Q_OBJECT +public: + /*! + * \brief Construct ground generator widget. + * \param parent The parent widget. + */ + explicit GenerateGround(QWidget *parent = 0); + +signals: + +public slots: + +private slots: + void retranslate(); + +private: + QTabWidget *m_tabManager; + GroundEditor *m_groundEditor; + BarracksEditor *m_barracksEditor; + QPushButton *m_okay, *m_cancel; +}; + +#endif // GENERATEGROUND_H diff --git a/generategroundbase.cpp b/generategroundbase.cpp new file mode 100644 index 0000000..a4c401b --- /dev/null +++ b/generategroundbase.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "generategroundbase.h" + +GenerateGroundBase::GenerateGroundBase(QWidget *parent) : + QDialog(parent) +{ +} diff --git a/generategroundbase.h b/generategroundbase.h new file mode 100644 index 0000000..1949875 --- /dev/null +++ b/generategroundbase.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GENERATEGROUNDBASE_H +#define GENERATEGROUNDBASE_H + +#include + +/*! + * \brief The GenerateGround class is a widget which can help user to generate + * the border and barracks. + */ +class GenerateGroundBase : public QDialog +{ + Q_OBJECT +public: + /*! + * \brief Construct a GenerateGroundBase dialog. + * \param parent Set the parent widget. + */ + explicit GenerateGroundBase(QWidget *parent = 0); + +signals: + +public slots: + +}; + +#endif // GENERATEGROUNDBASE_H diff --git a/ground.cpp b/ground.cpp new file mode 100644 index 0000000..98c50ad --- /dev/null +++ b/ground.cpp @@ -0,0 +1,744 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "robot.h" +#include "menubar.h" +#include "generategroundbase.h" + +#include "ground.h" + +#include + +Ground::Ground(QWidget *parent) : + GroundBase(parent), + m_border(QPolygonF()), + m_barracks(QPolygonF()), + m_borderColor(QColor(0,0,255)), + m_barracksColor(QColor(255,127,0)), + m_referenceLineColor(QColor(200,200,200)), + m_filePath(QString()), + m_fileName(QString()), + m_changed(false), + m_timeline(new QTimer(this)), + m_generator(nullptr) +{ + setContentsMargins(0,0,0,0); + //Configure the timer. + m_timeline->setInterval(16); //This will update the image for 60fps. + connect(m_timeline, &QTimer::timeout, + this, &Ground::onActionUpdateRobot); + + //Initial the actions. + for(int i=0; isetShortcut(QKeySequence(Qt::CTRL+Qt::Key_N)); + m_actions[Open]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_O)); + m_actions[Save]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_S)); + m_actions[SaveAs]->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_S)); + m_actions[Close]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_W)); + + connect(m_actions[New], static_cast(&QAction::triggered), + [=]{onActionNew();}); + connect(m_actions[Open], static_cast(&QAction::triggered), + [=]{onActionOpen();}); + connect(m_actions[Save], static_cast(&QAction::triggered), + [=]{onActionSave();}); + connect(m_actions[SaveAs], static_cast(&QAction::triggered), + [=]{onActionSaveAs();}); + connect(m_actions[Close], static_cast(&QAction::triggered), + [=]{onActionClose();}); + + retranslate(); + + //-----Example----- +// QPolygonF debugBorder, debugBarracks; +// //Set a default border. +// debugBorder << QPointF(30, 60) << QPointF(120, 20) +// << QPointF(400, 45) << QPointF(415, 280) +// << QPointF(180, 340) << QPointF(15, 210); +// setBorder(debugBorder); + +// //Set a default barracks. +// debugBarracks << QPointF(200, 200) << QPointF(200, 275) +// << QPointF(275, 275) << QPointF(275, 200); +// setBarracks(debugBarracks); + +// //Set some robots. +// addRobot(new Robot(203, 203)); +// addRobot(new Robot(210, 210)); +// addRobot(new Robot(210, 220)); +// addRobot(new Robot(203, 210)); +// addRobot(new Robot(210, 203)); +// addRobot(new Robot(203, 250)); +// addRobot(new Robot(209, 250)); +// addRobot(new Robot(250, 210)); +// addRobot(new Robot(203, 207)); +// addRobot(new Robot(204, 207)); +} + +Ground::~Ground() +{ + //Recover all the memory of the robot. + qDeleteAll(m_robotList); +} + +QPolygonF Ground::border() const +{ + return m_border; +} + +void Ground::setBorder(const QPolygonF &border) +{ + //The border should be at least a triangle, if it's only a line or nothing, + //ignore the request. + if(border.size()<3) + { + return; + } + //Save the border, and clear the barracks. + m_border = border; + m_barracks = QPolygonF(); + //Set the changed flag. + m_changed=true; + //Update the border lines. + m_borderLines.clear(); + for(int i=0; ipaintRobot(&painter); + } +} + +void Ground::retranslate() +{ + m_actions[New]->setText(tr("New")); + m_actions[Open]->setText(tr("Open")); + m_actions[Save]->setText(tr("Save")); + m_actions[SaveAs]->setText(tr("Save As")); + m_actions[Close]->setText(tr("Close")); +} + +void Ground::onActionUpdateRobot() +{ + QList::iterator beforeLastRobot=m_robotList.end()-1; + //Give all the robot the detect information. + for(QList::iterator robot=m_robotList.begin(); + robot!=beforeLastRobot; + ++robot) + { + for(QList::iterator target=robot+1; + target!=m_robotList.end(); + ++target) + { + //Ignore the current robot. + if(robot==target) + { + continue; + } + //If we have detected one of another robot, add them into the both + //detect list. + if(inDetectRange(*robot, *target)) + { + (*robot)->addToDetectList(*target); + (*target)->addToDetectList(*robot); + } + else + { + //Or else remove them from each other's detect list. + (*robot)->removeFromDetectList(*target); + (*target)->removeFromDetectList(*robot); + } + } + } + + //Update all the robot. + for(Robot *robot : m_robotList) + { + //If the robot is still don't have a line to guard, + if(!robot->hasGuardianLine()) + { + //Detect if the robot is in the border, if the robot is out of the + //border. + if(!m_border.containsPoint(robot->nextStep(), + Qt::OddEvenFill)) + { + //Find the line of the robot should guard, the robot should + //guard the most recent line. + //Appoint the robot to guard that line. + appointGuardianLine(robot); + } + } + //Update the direction of the robot. + robot->updateDirection(); + } + //Ask all the robot to move one step. + for(Robot *robot : m_robotList) + { + //Move the robot. + robot->moveOneStep(); + } + //Update the image. + update(); +} + +void Ground::onActionNew() +{ + //Stop the time line. + m_timeline->stop(); + //Close the current file. + if(!onActionClose()) + { + return; + } + //Should call generate ground widget here, and then judge it's success or + //failed. If success, set the ground information, or else abandon. + if(m_generator) + { + m_generator->exec(); + } +} + +bool Ground::onActionOpen() +{ + //Stop the time line. + m_timeline->stop(); + + //Close the current file. + if(!onActionClose()) + { + return false; + } + //Get the session file path. + QString sessionFilePath=QFileDialog::getOpenFileName(this, + tr("Open session")); + if(sessionFilePath.isEmpty()) + { + return false; + } + //Read the session file. + return readGroundData(sessionFilePath); +} + +bool Ground::onActionSave() +{ + //If the file don't need to save, then return false. + if(!m_changed) + { + return false; + } + //Check the file path is empty or not, if it's empty, call the save as. + if(m_filePath.isEmpty()) + { + return onActionSaveAs(); + } + //Or else, just write the data to the file. + m_changed=!writeGroundData(); + return !m_changed; +} + +bool Ground::onActionSaveAs() +{ + //Get the new file path. + QString preferFilePath=QFileDialog::getSaveFileName(this, + tr("Save session")); + if(preferFilePath.isEmpty()) + { + return false; + } + //Set session file information. + m_filePath=preferFilePath; + QFileInfo sessionFileInfo(m_filePath); + m_fileName=sessionFileInfo.fileName(); + //Save the data to session file. + m_changed=!writeGroundData(); + return !m_changed; +} + +bool Ground::onActionClose() +{ + //Stop the time line. + m_timeline->stop(); + + //Check if the current state is already close. + if(m_filePath.isEmpty() && !m_changed) + { + //Treat this as close successful. + return true; + } + + //Check the current session has been saved or not. + const int buttonSave=0, buttonCancel=1, buttonAbandon=2; + if(m_changed) + { + //There's a session which is modified but not save. + int result=QMessageBox::question(this, + tr("Close unsaved session"), + tr("Do you want to save the changes you made in the document \"%1\"?").arg( + m_fileName.isEmpty()?tr("Untitled"):m_fileName), + tr("Save"), + tr("Cancel"), + tr("Don't Save"), + buttonSave, + buttonCancel); + switch(result) + { + case buttonSave: + //If we saved fail, then we can't close the document. + if(!onActionSave()) + { + return false; + } + case buttonCancel: + //If user cancel close, then stop to close. + return false; + case buttonAbandon: + //Continue close the file. + break; + default: + //You must kidding me if goes here. + return false; + } + } + //Clear the ground data. + clearGroundData(); + //Reset the file status data. + m_filePath=QString(); + m_fileName=QString(); + m_changed=false; + //Update the panel. + update(); + return true; +} + +void Ground::clearGroundData() +{ + //Clear the border, border information, and barracks. + m_border=QPolygon(); + m_borderLines.clear(); + m_barracks=QPolygon(); + //Remove all the robot datas. + qDeleteAll(m_robotList); + m_robotList.clear(); + m_robotInitialAngle.clear(); + m_robotInitialPosition.clear(); + //Resize ground. + setFixedSize(0,0); +} + +bool Ground::readGroundData(const QString &filePath) +{ + //Try to open the file. + QFile sessionFile(filePath); + if(sessionFile.open(QIODevice::ReadOnly)) + { + //Read the data from the file. + QTextStream sessionStream(&sessionFile); + sessionStream.setCodec("UTF-8"); + //Read and parse the json. + QJsonObject sessionObject= + QJsonDocument::fromJson(sessionStream.readAll().toUtf8()).object(); + sessionFile.close(); + + //Generate the border. + QJsonArray borderData=sessionObject.value("Border").toArray(); + //Check if the border is vaild or not. + if(borderData.size()<3) //Simplified than a triangle. + { + return false; + } + QPolygonF border; + for(QJsonArray::iterator i=borderData.begin(); + i!=borderData.end(); + ++i) + { + QJsonArray pointData=(*i).toArray(); + //The array must contains only x() and y() data of the point. + if(pointData.size()!=2) + { + return false; + } + border.append(QPointF(pointData.at(0).toDouble(), + pointData.at(1).toDouble())); + } + + //Generate the barracks. + QJsonArray barracksData=sessionObject.value("Barracks").toArray(); + //Check if the barracks is vaild or not. + if(barracksData.size()<3) //Simlified than a triangle. + { + return false; + } + QPolygonF barracks; + for(QJsonArray::iterator i=barracksData.begin(); + i!=barracksData.end(); + ++i) + { + QJsonArray pointData=(*i).toArray(); + //The array must contains only x() and y() data of the point. + if(pointData.size()!=2) + { + return false; + } + //Check the point is vaild or not. + QPointF barracksPoint=QPointF(pointData.at(0).toDouble(), + pointData.at(1).toDouble()); + if(!border.containsPoint(barracksPoint, Qt::OddEvenFill)) + { + return false; + } + barracks.append(barracksPoint); + } + + //Generate the robot list. + QList robotList; + QJsonArray robotsData=sessionObject.value("Robots").toArray(); + for(QJsonArray::iterator i=robotsData.begin(); + i!=robotsData.end(); + ++i) + { + //Generate the robot. + QJsonObject robotData=(*i).toObject(); + QJsonArray robotPosition=robotData.value("Position").toArray(); + if(robotPosition.size()!=2) + { + //Clear the robots that has been genereated. + qDeleteAll(robotList); + return false; + } + Robot *robot=new Robot(robotPosition.at(0).toDouble(), + robotPosition.at(1).toDouble()); + robot->setAngle(robotData.value("Angle").toDouble()); + + robotList.append(robot); + } + //If we can go here, then all the data should be ok. + //Set the border, barracks and robots. + setBorder(border); + setBarracks(barracks); + addRobots(robotList); + //Change the file information and flags. + QFileInfo sessionFileInfo(sessionFile); + m_filePath=sessionFileInfo.absoluteFilePath(); + m_fileName=sessionFileInfo.fileName(); + m_changed=false; + //Update the image. + update(); + return true; + } + return false; +} + +bool Ground::writeGroundData() +{ + QFile sessionFile(m_filePath); + if(sessionFile.open(QIODevice::WriteOnly)) + { + //Generate the json object. + QJsonObject sessionObject; + QJsonArray border, barracks, robots; + //Write the border data to session object. + for(QPointF borderPoint : m_border) + { + QJsonArray point; + point.append(borderPoint.x()); + point.append(borderPoint.y()); + border.append(point); + } + sessionObject.insert("Border", border); + //Write barracks data to session object. + for(QPointF barracksPoint : m_barracks) + { + QJsonArray point; + point.append(barracksPoint.x()); + point.append(barracksPoint.y()); + barracks.append(point); + } + sessionObject.insert("Barracks", barracks); + //Write robot initial data to session object. + for(int i=0; ipos(), to->pos()).length()pos(), line, currentFoot); + //Check the distance. + if(minimalDistance<0.0 || currentDistancesetGuardianLine(guardianLine, footPoint); +} + +inline qreal Ground::getDistance(const QPointF &point, + const QLineF &line, + QPointF &footPoint) +{ + //The line whose angle is 90.0 or 270.0 has no gradient. + //The distance will be the absolute of the difference of x. + if(line.angle()==90.0 || line.angle()==270.0) + { + footPoint=QPointF(line.p1().x(), point.y()); + return qAbs(line.p1().x()-point.x()); + } + //Calculate the gradient. + qreal k=(line.p2().y()-line.p1().y())/(line.p2().x()-line.p1().x()); + //Get the foot point. + qreal footX=(k*k*line.p1().x()+k*(point.y()-line.p1().y())+point.x())/ + (k*k+1); + footPoint=QPointF(footX, k*(footX-line.p1().x())+line.p1().y()); + //Get the distance. + return QLineF(point, footPoint).length(); +} + +QPolygonF Ground::barracks() const +{ + return m_barracks; +} + +QColor Ground::barracksColor() const +{ + return m_barracksColor; +} + +bool Ground::addRobot(Robot *robot) +{ + //Check the robot. + //If the position of the robot is outside barracks, or there's already have + //a robot, you can't add this robot. + if(!m_barracks.containsPoint(robot->pos(), Qt::OddEvenFill) || + m_robotInitialPosition.contains(robot->pos())) + { + //Delete the robot. + delete robot; + return false; + } + //Add the available robot to list. + m_robotList.append(robot); + //Set the changed flag. + m_changed=true; + //Add the robot to initial position. + m_robotInitialPosition.append(robot->pos()); + m_robotInitialAngle.append(robot->angle()); + return true; +} + +void Ground::addRobots(const QList &robots) +{ + //Add the robot one by one. + for(QList::const_iterator i=robots.begin(); + i!=robots.end(); + ++i) + { + addRobot(*i); + } +} + +void Ground::setMenuBar(MenuBar *menuBar) +{ + menuBar->addCategoryAction(MenuBar::File, m_actions[New]); + menuBar->addCategoryAction(MenuBar::File, m_actions[Open]); + menuBar->addCategoryAction(MenuBar::File, m_actions[Save]); + menuBar->addCategoryAction(MenuBar::File, m_actions[SaveAs]); + menuBar->addCategoryAction(MenuBar::File, m_actions[Close]); +} + +void Ground::setGenerator(GenerateGroundBase *generator) +{ + //Save the generator. + m_generator=generator; +} + +void Ground::setBarracks(const QPolygonF &barracks) +{ + //Check if the barracks is all in the border. + //If there's any point is not in the border, ignore the set request. + for(QPolygonF::const_iterator i=barracks.begin(); + i!=barracks.end(); + ++i) + { + if(!m_border.containsPoint(*i, Qt::OddEvenFill)) + { + return; + } + } + //Save the barracks. + m_barracks = barracks; + //Set the changed flag. + m_changed=true; + //Update widget. + update(); + //Emit the barracks changed signal. + emit barracksChanged(); +} + +QColor Ground::borderColor() const +{ + return m_borderColor; +} + +void Ground::setBorderColor(const QColor &borderColor) +{ + m_borderColor = borderColor; + //Update the widget. + update(); +} + +void Ground::pause() +{ + //Stop the timer. + m_timeline->stop(); +} + +void Ground::start() +{ + //Start the time line. + m_timeline->start(); +} + +void Ground::nextFrame() +{ + //When the time line is running, ignore the request. + if(m_timeline->isActive()) + { + return; + } + //Call update robot once. + onActionUpdateRobot(); +} + +void Ground::reset() +{ + //Stop the time line. + m_timeline->stop(); + //Reset all the robot. + for(int i=0; iresetGuardianLine(); + //Reset the robot position and angle. + robot->setPos(m_robotInitialPosition.at(i)); + robot->setAngle(m_robotInitialAngle.at(i)); + } + //Update the ground. + update(); +} diff --git a/ground.h b/ground.h new file mode 100644 index 0000000..8f3b9c7 --- /dev/null +++ b/ground.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GROUND_H +#define GROUND_H + +#include "groundbase.h" + +class QTimer; +/*! + * \brief The Ground class a default realization of the GroundBase class. + */ +class Ground : public GroundBase +{ + Q_OBJECT +public: + /*! + * \brief Construct Ground class with the given parent. + * \param parent The parent widget of the Ground class. + */ + explicit Ground(QWidget *parent = 0); + ~Ground(); + + /*! + * \brief Reimplemented from GroundBase::border(). + */ + QPolygonF border() const; + + /*! + * \brief Reimplemented from GroundBase::borderColor(). + */ + QColor borderColor() const; + + /*! + * \brief Reimplemented from GroundBase::barracks(). + */ + QPolygonF barracks() const; + + /*! + * \brief Reimplemented from GroundBase::barracksColor(). + */ + QColor barracksColor() const; + + /*! + * \brief Reimplemented from GroundBase::addRobot(). + */ + bool addRobot(Robot *robot); + + /*! + * \brief Reimplemented from GroundBase::addRobots(). + */ + void addRobots(const QList &robots); + + /*! + * \brief Reimplemented from GroundBase::setMenuBar(). + */ + void setMenuBar(MenuBar *menuBar); + + /*! + * \brief Reimplemented from GroundBase::setGenerator(). + */ + void setGenerator(GenerateGroundBase *generator); +signals: + +public slots: + /*! + * \brief Reimplemented from GroundBase::setBorder(const QPolygonF &). + */ + void setBorder(const QPolygonF &border); + + /*! + * \brief Reimplemented from GroundBase::setBarracks(const QPolygonF &). + */ + void setBarracks(const QPolygonF &barracks); + + /*! + * \brief Reimplemented from GroundBase::setBorderColor(const QColor &). + */ + void setBorderColor(const QColor &borderColor); + + /*! + * \brief Reimplemented from GroundBase::pause(). + */ + void pause(); + + /*! + * \brief Reimplemented from GroundBase::start(). + */ + void start(); + + /*! + * \brief Reimplemented from GroundBase::nextFrame(). + */ + void nextFrame(); + + /*! + * \brief Reimplemented from GroundBase::reset(). + */ + void reset(); + +protected: + /*! + * \brief This event handler can be reimplemented in a subclass to receive + * paint events passed in event. \n + * Draw all the elements of the ground, included: robots, border and + * barracks.\n + * Reimplemented from QWidget::paintEvent(). + * \param event The event handle. + */ + void paintEvent(QPaintEvent *event); + +private slots: + void retranslate(); + void onActionUpdateRobot(); + + void onActionNew(); + bool onActionOpen(); + bool onActionSave(); + bool onActionSaveAs(); + bool onActionClose(); + +private: + inline void clearGroundData(); + inline bool readGroundData(const QString &filePath); + inline bool writeGroundData(); + inline bool inDetectRange(Robot *from, Robot *to); + inline void appointGuardianLine(Robot *robot); + inline qreal getDistance(const QPointF &point, + const QLineF &line, + QPointF &footPoint); + enum GroundActions + { + New, + Open, + Save, + SaveAs, + Close, + GroundActionsCount + }; + QAction *m_actions[GroundActionsCount]; + + QPolygonF m_border, m_barracks; + QColor m_borderColor, m_barracksColor, m_referenceLineColor; + QList m_robotList; + + //Project file status. + QString m_filePath, m_fileName; + bool m_changed; + + //Initial data recorder. + QList m_robotInitialPosition; + QList m_robotInitialAngle; + + QList m_borderLines; + + QTimer *m_timeline; + GenerateGroundBase *m_generator; +}; + +#endif // GROUND_H diff --git a/groundbase.h b/groundbase.h new file mode 100644 index 0000000..4ee0da9 --- /dev/null +++ b/groundbase.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GROUNDBASE_H +#define GROUNDBASE_H + +#include + +#include + +class Robot; +class MenuBar; +class GenerateGroundBase; +/*! + * \brief This is the abstraction class of the ground. It contains all the + * interfaces which a ground class should be realized.\n + * A Ground class is the widget which is going to show up the robots, + * borders and barracks. It has to detected all the robots and set the + * information to all the robots. The Ground class should contains all the + * environmental information. + */ +class GroundBase : public QWidget +{ + Q_OBJECT +public: + /*! + * \brief Construct Ground class with the given parent. + * \param parent The parent widget of the Ground class. + */ + GroundBase(QWidget *parent = 0):QWidget(parent){} + + /*! + * \brief The outside border which all the robots is going to guard. + * \return The border QPolygonF class of the border. + */ + virtual QPolygonF border() const=0; + + /*! + * \brief Get the color of the border. + * \return The QColor of the border. + */ + virtual QColor borderColor() const=0; + + /*! + * \brief The barracks border which all the robots is going to be set at + * beginning. + * \return The border QPolygonF class of the barracks. + */ + virtual QPolygonF barracks() const=0; + + /*! + * \brief Get the color of the barracks border. + * \return The QColor of the barracks border. + */ + virtual QColor barracksColor() const=0; + + /*! + * \brief Add a robot to the ground. It will detect the start position of + * the robot. If the robot is out side the barracks, will delete the robot. + * \param robot The robot class which is going to be added. + * \return If add the robot sucessfully, return true, or else return false. + */ + virtual bool addRobot(Robot *robot)=0; + + /*! + * \brief Add a lots of robots to the ground. It will call addRobot() + * function for several times. + * \param robots + */ + virtual void addRobots(const QList &robots)=0; + + /*! + * \brief Set the menu bar to add control actions. + * \param menuBar The menu bar. + */ + virtual void setMenuBar(MenuBar *menuBar)=0; + + /*! + * \brief Set a ground generator. + * \param generator The ground generator. + */ + virtual void setGenerator(GenerateGroundBase *generator)=0; + +signals: + /*! + * \brief When the user change the border, this signal will be emitted. + */ + void borderChanged(); + + /*! + * \brief When the user change the barracks border, this signal will be + * emitted. + */ + void barracksChanged(); + +public slots: + /*! + * \brief Sets the border for the ground to border. \n + * The border must be at least a triangle, if it's not a more complex + * polygon than a triangle, the border will not be set.\n + * When the new border has been set, the barracks will be reset to empty. + * \param border The target border QPolygonF. + */ + virtual void setBorder(const QPolygonF &border)=0; + + /*! + * \brief Sets the border for the barracks of robots.\n + * If there's any point which is not in the sets border, this barracks will + * not be set. + * \param barracks The target barracks QPolygonF. + */ + virtual void setBarracks(const QPolygonF &barracks)=0; + + /*! + * \brief Sets the color of the border. + * \param borderColor The prefer color of the border. + */ + virtual void setBorderColor(const QColor &borderColor)=0; + + /*! + * \brief Pause the main time line. + */ + virtual void pause()=0; + + /*! + * \brief Continue running the main time line. + */ + virtual void start()=0; + + /*! + * \brief Reset all the robot at the start position.\n + * All the robot's guardian line will be removed, and the position and + * direction will be also reset. + */ + virtual void reset()=0; + + /*! + * \brief Ask all the robot move only once.\n + * Notice that this function only available when the main time line is + * paused. + */ + virtual void nextFrame()=0; +}; + +#endif // GROUNDBASE_H diff --git a/groundeditor.cpp b/groundeditor.cpp new file mode 100644 index 0000000..3fe17a1 --- /dev/null +++ b/groundeditor.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include + +#include "groundeditor.h" + +GroundEditor::GroundEditor(QWidget *parent) : + QWidget(parent), + m_groundPoints(new QTableWidget(this)) +{ + //Configure the ground points editor. + m_groundPoints->setColumnCount(2); + + //Initial the layout. + QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::TopToBottom, + this); + mainLayout->setSpacing(0); + setLayout(mainLayout); + + //Initial the actions. + QBoxLayout *actionLayout=new QBoxLayout(QBoxLayout::LeftToRight, + mainLayout->widget()); + for(int i=0; iaddWidget(m_actions[i]); + } + //Set key sequence. + m_actions[AddPoint]->setShortcut(QKeySequence(Qt::Key_Plus)); + actionLayout->addStretch(); + + mainLayout->addWidget(m_groundPoints, 1); + mainLayout->addLayout(actionLayout); + + retranslate(); +} + +void GroundEditor::retranslate() +{ + //Update ground points header. + QStringList groundHeader; + groundHeader << tr("X") << tr("Y"); + m_groundPoints->setHorizontalHeaderLabels(groundHeader); + + //Set the text. + m_actions[AddPoint]->setText("+"); + m_actions[RemovePoint]->setText("-"); +} diff --git a/groundeditor.h b/groundeditor.h new file mode 100644 index 0000000..33f6692 --- /dev/null +++ b/groundeditor.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GROUNDEDITOR_H +#define GROUNDEDITOR_H + +#include + +class QToolButton; +class QTableWidget; +/*! + * \brief The GroundEditor class can edit a ground-guard-bordor, and set the new + * border to that ground. + */ +class GroundEditor : public QWidget +{ + Q_OBJECT +public: + /*! + * \brief Construct Ground Editor. + * \param parent The parent widget. + */ + explicit GroundEditor(QWidget *parent = 0); + +signals: + +public slots: + +private slots: + void retranslate(); + +private: + enum GroundEditActions + { + AddPoint, + RemovePoint, + GroundEditActionsCount + }; + QToolButton *m_actions[GroundEditActionsCount]; + + QTableWidget *m_groundPoints; +}; + +#endif // GROUNDEDITOR_H diff --git a/groundpreviewwidget.cpp b/groundpreviewwidget.cpp new file mode 100644 index 0000000..892f7a3 --- /dev/null +++ b/groundpreviewwidget.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include "groundbase.h" +#include "robot.h" + +#include "groundpreviewwidget.h" + +#include + +GroundPreviewWidget::GroundPreviewWidget(QWidget *parent) : + QWidget(parent), + m_ground(nullptr), + m_previewGround(QPolygonF()), + m_previewBarracks(QPolygonF()), + m_xOffset(0), + m_yOffset(0), + m_groundParameter(1.0), + m_showPreviewPoint(false), + m_previewRobot(new Robot) +{ + setFixedSize(200,200); +} + +GroundPreviewWidget::~GroundPreviewWidget() +{ + delete m_previewRobot; +} + +void GroundPreviewWidget::setGround(GroundBase *ground) +{ + //Save the ground. + m_ground=ground; + //Link the ground. + connect(m_ground, &GroundBase::borderChanged, + this, &GroundPreviewWidget::onActionBorderChanged); + connect(m_ground, &GroundBase::barracksChanged, + this, &GroundPreviewWidget::onActionBarracksChanged); +} + +void GroundPreviewWidget::previewRobot(QPointF position, qreal angle) +{ + //Save the preview data. + m_previewRobot->setPos(pointFromGround(position)); + m_previewRobot->setAngle(angle); + //Update the preivew. + update(); +} + +void GroundPreviewWidget::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); + //Check if we have a ground. + if(m_ground==nullptr) + { + return; + } + //Initial the painter. + QPainter painter(this); + painter.setRenderHints(QPainter::Antialiasing | + QPainter::TextAntialiasing | + QPainter::SmoothPixmapTransform, true); + //Paint the border. + painter.setPen(m_ground->borderColor()); + painter.drawPolygon(m_previewGround); + //Paint the barracks. + painter.setPen(m_ground->barracksColor()); + painter.drawPolygon(m_previewBarracks); + //If display the preview robot. + if(m_showPreviewPoint) + { + //Paint the preview robot. + m_previewRobot->paintRobot(&painter); + } +} + +void GroundPreviewWidget::onActionBorderChanged() +{ + //Check if the ground is available. + if(m_ground==nullptr) + { + return; + } + QPolygonF groundBorder=m_ground->border(), + previewGroundBorder; + //Update the ground height and width. + qreal groundHeight=m_ground->size().height(), + groundWidth=m_ground->size().width(); + //Update the offset. + if(groundHeightbarracks(), + previewBarracksBorder; + //Gernerate the preview border, will zoom the original ground. + for(QPointF borderPoint : barracksBorder) + { + previewBarracksBorder.append(pointFromGround(borderPoint)); + } + //Save the preview border. + m_previewBarracks=previewBarracksBorder; + //Update the widget. + update(); +} + +inline QPointF GroundPreviewWidget::pointFromGround(const QPointF &groundPoint) +{ + return QPointF((groundPoint.x()+m_xOffset)/m_groundParameter*width(), + (groundPoint.y()+m_yOffset)/m_groundParameter*height()); +} +bool GroundPreviewWidget::showPreviewPoint() const +{ + return m_showPreviewPoint; +} + +void GroundPreviewWidget::setShowPreviewPoint(bool showPreviewPoint) +{ + m_showPreviewPoint = showPreviewPoint; +} + diff --git a/groundpreviewwidget.h b/groundpreviewwidget.h new file mode 100644 index 0000000..46db57c --- /dev/null +++ b/groundpreviewwidget.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GROUNDPREVIEWWIDGET_H +#define GROUNDPREVIEWWIDGET_H + +#include + +class GroundBase; +class Robot; +/*! + * \brief The GroundPreviewWidget class provides the basic information of a + * ground. It will display the border and barracks, automatically zoom it to + * specific size. + */ +class GroundPreviewWidget : public QWidget +{ + Q_OBJECT +public: + /*! + * \brief Construct a Ground preview widget. + * \param parent The parent widget. + */ + explicit GroundPreviewWidget(QWidget *parent = 0); + ~GroundPreviewWidget(); + + /*! + * \brief The widget will display or hide the preview robot. + * \return If display the preview robot, will return true, or else false. + */ + bool showPreviewPoint() const; + +signals: + +public slots: + /*! + * \brief Set the rendering Ground class. + * \param ground The render ground. + */ + void setGround(GroundBase *ground); + + /*! + * \brief Make the preview widget to display the preview robot or not. + * \param showPreviewPoint The preview enabled value. + */ + void setShowPreviewPoint(bool showPreviewPoint); + + /*! + * \brief Will display a robot on the preview map. + * \param position + * \param angle + */ + void previewRobot(QPointF position, qreal angle); + +protected: + void paintEvent(QPaintEvent *event); + +private slots: + void onActionBorderChanged(); + void onActionBarracksChanged(); + +private: + inline QPointF pointFromGround(const QPointF &groundPoint); + GroundBase *m_ground; + QPolygonF m_previewGround, m_previewBarracks; + + qreal m_xOffset, m_yOffset, m_groundParameter; + bool m_showPreviewPoint; + Robot *m_previewRobot; +}; + +#endif // GROUNDPREVIEWWIDGET_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..6fea83b --- /dev/null +++ b/main.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "mainwindow.h" + +#include + +/*! + * \brief Initial the main window of the application. + * \param argc Argument count. + * \param argv Argument values. + * \return + */ +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + //Set application information. + QApplication::setApplicationName("Robot Emulator"); + QApplication::setApplicationDisplayName("Robot Emulator"); + //Conrtruct main window. + MainWindow mainWindow; + mainWindow.show(); + //Expand the event loop. + return app.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..4dec181 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include "ground.h" +#include "paneldock.h" +#include "menubar.h" +#include "robotmanagement.h" +#include "generateground.h" + +#include "mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + m_ground(new Ground(this)), + m_panel(new PanelDock(this)), + m_menuBar(new MenuBar(this)), + m_robotManagement(new RobotManagement(this)), + m_groundGenerator(new GenerateGround(this)) +{ + //A hack, using box layout to make the ground the center. + QWidget *container=new QWidget(this); + //Set the central widget. + setCentralWidget(container); + QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::LeftToRight, + container); + container->setLayout(mainLayout); + //Add ground and panel to layout. + mainLayout->addWidget(m_ground, 1, Qt::AlignCenter); + mainLayout->addWidget(m_panel); + + //Set the ground generator. + m_ground->setGenerator(m_groundGenerator); + + //Give the ground to elements. + m_panel->setGround(m_ground); + m_robotManagement->setGround(m_ground); + + //Give the menu bar to elements. + m_ground->setMenuBar(m_menuBar); + m_panel->setMenuBar(m_menuBar); + m_robotManagement->setMenuBar(m_menuBar); + + //Add panel to bottom dock area. + addDockWidget(Qt::RightDockWidgetArea, m_panel); + m_panel->setAllowedAreas(Qt::LeftDockWidgetArea | + Qt::RightDockWidgetArea); +#ifdef Q_OS_MACX + setWindowTitle("Robot Emulator"); +#else + setMenuBar(m_menuBar); +#endif +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..f5a59ca --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +class QScrollArea; +class Ground; +class PanelDock; +class MenuBar; +class RobotManagement; +class GenerateGround; +/*! + * \brief The MainWindow class is the top widget of all the visible widget. The + * only mission of MainWindow is going to show the Ground widget and take the + * fully management of the Ground widget. + */ +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + /*! + * \brief Constructs the MainWindow with the given parent. This class should + * only be constructed by main() function. + * \param parent The parent widget. + */ + explicit MainWindow(QWidget *parent = 0); + +signals: + +public slots: + +private: + Ground *m_ground; + PanelDock *m_panel; + MenuBar *m_menuBar; + RobotManagement *m_robotManagement; + GenerateGround *m_groundGenerator; +}; + +#endif // MAINWINDOW_H diff --git a/menubar.cpp b/menubar.cpp new file mode 100644 index 0000000..b6aba7b --- /dev/null +++ b/menubar.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include "menubar.h" + +MenuBar::MenuBar(QWidget *parent) : + QMenuBar(parent) +{ + //Initial all the menu and add to menu bar. + for(int i=0; i-1 && categoryaddAction(action); + } +} + +void MenuBar::retranslate() +{ + m_categoryMenu[File]->setTitle(tr("File")); + m_categoryMenu[View]->setTitle(tr("View")); + m_categoryMenu[Ground]->setTitle(tr("Ground")); + m_categoryMenu[Robot]->setTitle(tr("Robot")); + m_categoryMenu[TimeLine]->setTitle(tr("Time Line")); + m_categoryMenu[Help]->setTitle(tr("Help")); +} diff --git a/menubar.h b/menubar.h new file mode 100644 index 0000000..1b52c62 --- /dev/null +++ b/menubar.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef MENUBAR_H +#define MENUBAR_H + +#include + +/*! + * \brief The MenuBar class contains the menu for all the categories. + */ +class MenuBar : public QMenuBar +{ + Q_OBJECT +public: + enum ActionCategories + { + File, + View, + Ground, + Robot, + TimeLine, + Help, + ActionCategoriesCount + }; + /*! + * \brief Contruct the MenuBar. + * \param parent The parent widget. + */ + explicit MenuBar(QWidget *parent = 0); + /*! + * \brief Add actions to the specific category menu. + * \param category The category menu index. + * \param action The action which is waiting to add. + */ + void addCategoryAction(int category, QAction *action); + +signals: + +public slots: + +private slots: + void retranslate(); + +private: + QMenu *m_categoryMenu[ActionCategoriesCount]; +}; + +#endif // MENUBAR_H diff --git a/panel.cpp b/panel.cpp new file mode 100644 index 0000000..811910a --- /dev/null +++ b/panel.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include + +#include "panel.h" +#include "menubar.h" +#include "groundbase.h" + +Panel::Panel(QWidget *parent) : + QWidget(parent), + m_mainLayout(new QBoxLayout(QBoxLayout::TopToBottom, this)) +{ + //Set the main layout. + m_mainLayout->setContentsMargins(0,0,0,0); + m_mainLayout->setSpacing(2); + setLayout(m_mainLayout); + + //Add the buttons and actions. + for(int i=0; iaddWidget(m_commands[i]); + //Initial the actions. + m_commandActions[i]=new QAction(this); + //Link the actions to the button. + connect(m_commandActions[i], SIGNAL(triggered()), + m_commands[i], SLOT(click())); + } + m_mainLayout->addStretch(); + + //Set shortcuts. + m_commandActions[Start]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_R)); + m_commandActions[Pause]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_E)); + m_commandActions[Reset]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_T)); + m_commandActions[NextFrame]->setShortcut(QKeySequence(Qt::CTRL+ + Qt::SHIFT+ + Qt::Key_M)); + + retranslate(); +} + +void Panel::setGround(GroundBase *ground) +{ + connect(m_commands[Start], + static_cast(&QPushButton::clicked), + [=]{ground->start();}); + connect(m_commands[Pause], + static_cast(&QPushButton::clicked), + [=]{ground->pause();}); + connect(m_commands[Reset], + static_cast(&QPushButton::clicked), + [=]{ground->reset();}); + connect(m_commands[NextFrame], + static_cast(&QPushButton::clicked), + [=]{ground->nextFrame();}); + connect(m_commands[SaveScreenshot], + static_cast(&QPushButton::clicked), + [=] + { + if(ground->size().isNull() || ground->size().isEmpty()) + { + return; + } + //Get the snapshot. + QPixmap snapshot(ground->size()); + ground->render(&snapshot); + //If we get nothing, then no image will be save. + if(snapshot.isNull()) + { + return; + } + //Get the image path. + QString snapshotPath=QFileDialog::getSaveFileName(this, + tr("Save snapshot"), + QString(), + tr("Portable Network Graphic Format(*.png)")); + if(!snapshotPath.isEmpty()) + { + //Save the file. + snapshot.save(snapshotPath, "png"); + } + }); +} + +void Panel::setMenuBar(MenuBar *menuBar) +{ + //Add all the controls to timeline menu. + for(int i=0; iaddCategoryAction(MenuBar::TimeLine, m_commandActions[i]); + } +} + +void Panel::retranslate() +{ + QString actionCaptions[ControlCommandCount]; + actionCaptions[Start]=tr("Start"); + actionCaptions[Pause]=tr("Pause"); + actionCaptions[Reset]=tr("Reset"); + actionCaptions[NextFrame]=tr("Next Frame"); + actionCaptions[SaveScreenshot]=tr("Save current status"); + + //Update the command buttons and actions. + for(int i=0; isetText(actionCaptions[i]); + m_commandActions[i]->setText(actionCaptions[i]); + } +} diff --git a/panel.h b/panel.h new file mode 100644 index 0000000..711a9b3 --- /dev/null +++ b/panel.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PANEL_H +#define PANEL_H + +#include + +class QBoxLayout; +class QPushButton; +class GroundBase; +class MenuBar; +/*! + * \brief The Panel class is the control panel of the ground, it can control the + * time line of the Ground class. + */ +class Panel : public QWidget +{ + Q_OBJECT +public: + /*! + * \brief Construct a timeline control panel. + * \param parent The parent widget. + */ + explicit Panel(QWidget *parent = 0); + +signals: + +public slots: + /*! + * \brief Set the controlled GroundBase class to the panel, it will + * automatcially link the the signal and the slots. + * \param ground The controlled ground class. + */ + void setGround(GroundBase *ground); + /*! + * \brief Set the menu bar to add control actions. + * \param menuBar The menu bar. + */ + void setMenuBar(MenuBar *menuBar); + +private slots: + void retranslate(); + +private: + enum ControlCommands + { + Start, + Pause, + Reset, + NextFrame, + SaveScreenshot, + ControlCommandCount, + }; + QPushButton *m_commands[ControlCommandCount]; + QAction *m_commandActions[ControlCommandCount]; + + QBoxLayout *m_mainLayout; +}; + +#endif // PANEL_H diff --git a/paneldock.cpp b/paneldock.cpp new file mode 100644 index 0000000..9673661 --- /dev/null +++ b/paneldock.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include "panel.h" +#include "menubar.h" + +#include "paneldock.h" + +PanelDock::PanelDock(QWidget *parent) : + QDockWidget(parent), + m_panel(new Panel(this)), + m_dockVisible(new QAction(this)) +{ + //Set the widget. + setWidget(m_panel); + //Set the action. + m_dockVisible->setCheckable(true); + connect(m_dockVisible, + static_cast(&QAction::triggered), + [=]{isVisible()?hide():show();}); + + retranslate(); +} + +void PanelDock::setGround(GroundBase *ground) +{ + m_panel->setGround(ground); +} + +void PanelDock::setMenuBar(MenuBar *menuBar) +{ + m_panel->setMenuBar(menuBar); + //Add dock visible action to menu bar. + menuBar->addCategoryAction(MenuBar::View, m_dockVisible); +} + +void PanelDock::hideEvent(QHideEvent *event) +{ + //Hide the dock. + QDockWidget::hideEvent(event); + //Update the action. + m_dockVisible->setChecked(false); +} + +void PanelDock::showEvent(QShowEvent *event) +{ + //Hide the dock. + QDockWidget::showEvent(event); + //Update the action. + m_dockVisible->setChecked(true); +} + +void PanelDock::retranslate() +{ + m_dockVisible->setText(tr("Control Dock")); +} diff --git a/paneldock.h b/paneldock.h new file mode 100644 index 0000000..bcafb49 --- /dev/null +++ b/paneldock.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PANELDOCK_H +#define PANELDOCK_H + +#include + +class Panel; +class GroundBase; +class MenuBar; +class PanelDock : public QDockWidget +{ + Q_OBJECT +public: + /*! + * \brief Contruct a Panel dock widget. + * \param parent The main windows of the dock. + */ + explicit PanelDock(QWidget *parent = 0); + +signals: + +public slots: + /*! + * \brief The proxy set function of the panel widget. + * \param ground The controlled ground class. + */ + void setGround(GroundBase *ground); + /*! + * \brief The proxy set function of the panel widget. + * \param menuBar The menu bar. + */ + void setMenuBar(MenuBar *menuBar); + +protected: + void hideEvent(QHideEvent *event); + void showEvent(QShowEvent *event); + +private slots: + void retranslate(); + +private: + Panel *m_panel; + QAction *m_dockVisible; +}; + +#endif // PANELDOCK_H diff --git a/robot.cpp b/robot.cpp new file mode 100644 index 0000000..9cdd163 --- /dev/null +++ b/robot.cpp @@ -0,0 +1,448 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include "robot.h" + +#include + +Robot::Robot() : + m_angle(0.0), + m_hasGuardianLine(false), + m_guardianLine(QPointF(0,0), QPointF(0,0)), + m_toP1Distance(0.0), + m_movingSpeed(1.0) +{ + setPos(QPointF(0, 0)); +} + +Robot::Robot(QPointF pos) : + Robot() +{ + setPos(pos); +} + +Robot::Robot(qreal x, qreal y) : + Robot() +{ + setPos(x, y); +} + +QPointF Robot::pos() const +{ + return m_pos; +} + +void Robot::setPos(const QPointF &pos) +{ + m_pos = pos; +} + +void Robot::paintRobot(QPainter *painter) +{ + //Draw the direction of the robot. + QLineF directionLine(m_pos, m_pos+QPointF(m_detectRadius, 0)); + directionLine.setAngle(m_angle); + painter->setPen(m_directionLineColor); + painter->drawLine(directionLine); + + //Draw the detect radius. + painter->setPen(m_detectRadiusColor); + painter->drawEllipse(m_pos, m_detectRadius, m_detectRadius); + + //Draw the robot. + painter->setPen(m_robotColor); + painter->drawEllipse(m_pos, m_robotSize, m_robotSize); +} + +int Robot::m_robotSize=2; + +int Robot::robotSize() +{ + return m_robotSize; +} + +void Robot::setRobotSize(int robotSize) +{ + m_robotSize = robotSize; +} + +int Robot::m_detectRadius=20; + +int Robot::detectRadius() +{ + return m_detectRadius; +} + +void Robot::setDetectRadius(int detectRadius) +{ + m_detectRadius = detectRadius; +} + +QColor Robot::m_robotColor=QColor(255,0,255); + +void Robot::setRobotColor(const QColor &robotColor) +{ + m_robotColor=robotColor; +} + +QColor Robot::robotColor() +{ + return m_robotColor; +} + +QColor Robot::m_detectRadiusColor=QColor(127,0,255); + +QColor Robot::detectRadiusColor() +{ + return m_detectRadiusColor; +} + +void Robot::setDetectRadiusColor(const QColor &detectRadiusColor) +{ + m_detectRadiusColor = detectRadiusColor; +} + +qreal Robot::angle() const +{ + return m_angle; +} + +void Robot::setAngle(const qreal &angle) +{ + m_angle = angle; + //Change the angle. + while(m_angle>360.0) + { + m_angle-=360.0; + } + while(m_angle<0.0) + { + m_angle+=360.0; + } +} + +QColor Robot::m_directionLineColor=QColor(127, 127, 0); + +QColor Robot::directionLineColor() +{ + return m_directionLineColor; +} + +void Robot::setDirectionLineColor(const QColor &detectLineColor) +{ + m_directionLineColor = detectLineColor; +} + +void Robot::addToDetectList(Robot *robot) +{ + //Check the robot whether has already be in the list. + if(!m_detectedRobotList.contains(robot)) + { + m_detectedRobotList.append(robot); + } +} + +void Robot::removeFromDetectList(Robot *robot) +{ + //Remove all the robot from the list. + m_detectedRobotList.removeOne(robot); +} + +void Robot::moveOneStep() +{ + //Get the next step and set the position. + setPos(nextStep()); + //If this robot has a guardian line, change the toP1Distance. + if(m_hasGuardianLine) + { + m_toP1Distance+=m_movingSpeed; + } +} + +QPointF Robot::nextStep() const +{ + //If the robot has the guardian line, calculate the next step on the line. + if(m_hasGuardianLine) + { + //Get the next position. + qreal robotPosition= (m_toP1Distance + m_movingSpeed) / + m_guardianLine.length(); + return m_guardianLine.pointAt(robotPosition); + } + //If not have a guardian line, then move to the direction. + //Generate the direction line. + QLineF directionLine(m_pos, m_pos+QPointF(m_detectRadius, 0)); + directionLine.setAngle(m_angle); + directionLine.setLength(1.0); + //The p2 is the next step position. + return directionLine.p2(); +} + +void Robot::updateDirection() +{ + //----Magic! Don't touch!--- + //If the detected list is empty, then keep the direction. + if(m_detectedRobotList.isEmpty()) + { + //If the robot has a guardian line, + if(m_hasGuardianLine) + { + //Check if the robot reach one side of the line. + if(m_toP1Distance<=0.9) + { + //Move to the guardian line angle. + m_movingSpeed=1.0; + m_angle=m_guardianLine.angle(); + return; + } + if(m_toP1Distance>=m_guardianLine.length()) + { + //Move to the opposite angle of the guardian line. + m_movingSpeed=-1.0; + m_angle=m_oppositeGuardianLine.angle(); + return; + } + } + //Or else keep the direction. + return; + } + //Now the detected robot list cannot be empty. + //If the robot has a line to guard. + if(m_hasGuardianLine) + { + //Check if the robot reach one side of the line. + if(m_toP1Distance<=0.9 || m_toP1Distance>=m_guardianLine.length()-0.9) + { + //Move to the different direction. + if(m_movingSpeed>0) + { + m_movingSpeed=-1.0; + m_angle=m_oppositeGuardianLine.angle(); + } + else + { + m_movingSpeed=1.0; + m_angle=m_guardianLine.angle(); + } + return; + } + //Or else, we should have move the robot to opposite direction of the + //nearest robot. + //The nearest robot have three kind of types: + // 1. It doesn't have a guardian line. + // 2. It has a guardian line, but it's not the same as mine. + // 3. It has the same guardian line. + //For the first type, ignore it. + //For the second and third type, there's one rule: the robot should + //move to the direction which should leave that robot away. + QList statusList; + for(Robot *robot : m_detectedRobotList) + { + RobotStatus currentStatus; + currentStatus.robot=robot; + currentStatus.distance=QLineF(m_pos, robot->pos()).angle(); + statusList.append(currentStatus); + } + qSort(statusList); + //Get the nearest robot, . + RobotStatus nearestStatus=statusList.takeFirst(); + while(!nearestStatus.robot->hasGuardianLine() && !statusList.isEmpty()) + { + nearestStatus=statusList.takeFirst(); + } + //Check the nearest status. + if(!nearestStatus.robot->hasGuardianLine()) + { + //All the robot in the detect range don't has a guardian line. + //They will move away from this point. + return; + } + //So now, we get the nearest point which contains a guardian line. + Robot *nearestRobot=nearestStatus.robot; + //If these two robot has the same guardian line, and they are getting + //closer(have the different speed), move to the other direction. + //If these two robots have the different speed. + //For this kinds of type, + //p1 this + //| | + //+---*><*---------------------- + // | + // nearest + // + //Or for this kinds of type, + // + // this p2 + // | | + //-----------------*><*----+ + // | + // nearest + // + //We have to change the direction. + // + //So now, there is an ugly thing we have to met.(What the fuck!) + //The nearest point is not at the same line, but according to the + //context, this line must be the neighbouring line. Like the following: + // + // --------+ + // | + // | + // + //We have change the direction when both of these robots are moving to + //the same point, and that point is pretty interesting. It's the p1 for + //the second line and the p2 for the first line. So: + // + // this p2(for this) + // | | + // -----*>-+-p1(for nearest) + // | + // ^ + // * + // | + // + //At this time, the moving speed of this and nearest will be different + //(this is 1.0 and nearest is -1.0). + //For another case, it will be like this: + // + // p1(for this) p1 + // | | + // p2(for nearest)-+-<*------- + // | + // ^ + // * + // | + // + //At this time, the moving speed of this and nearest will be different + //as well(this is -1.0 and nearest is 1.0). + //We have to change the direction in these two cases. + + if(nearestRobot->movingSpeed()!=m_movingSpeed) + { + if(nearestRobot->guardianLine()==m_guardianLine) + { + if((m_movingSpeed>0 && + m_toP1DistancetoP1Distance()) || + (m_movingSpeed<0 && + m_toP1Distance>nearestRobot->toP1Distance())) + { + //Move to the different direction. + moveToOppositeDirection(); + //Ask the robot move to the differect direction as well. + nearestRobot->moveToOppositeDirection(); + } + } + else + { + if((m_movingSpeed>0 && + m_toP1Distance>nearestRobot->toP1Distance()) || + (m_movingSpeed<0 && + m_toP1DistancetoP1Distance())) + { + //Move to the different direction. + moveToOppositeDirection(); + //Ask the robot move to the differect direction as well. + nearestRobot->moveToOppositeDirection(); + } + } + } + //Or else, keep moving. + return; + } + //The prefer direction is to link all the detected robots, calculate the + //average angle of the robot lists. + qreal angleSum=0.0; + for(Robot *robot : m_detectedRobotList) + { + angleSum+=QLineF(m_pos, robot->pos()).angle(); + } + angleSum/=m_detectedRobotList.size(); + //Set the angle to the opposite angle. + setAngle(angleSum+180.0); +} + +bool Robot::hasGuardianLine() const +{ + return m_hasGuardianLine; +} + +void Robot::setGuardianLine(const QLineF &line, + const QPointF &footPoint) +{ + //Clear the previous data. + resetGuardianLine(); + //Check the length of the line. + if(line.length()==0.0) + { + return; + } + //Set has guardian line flag. + m_hasGuardianLine=true; + //Save the guardian line. + m_guardianLine=line; + //Get the opposite guardian line. + m_oppositeGuardianLine=QLineF(m_guardianLine.p2(), m_guardianLine.p1()); + QLineF directionAngle=QLineF(QPointF(0.0, 0.0), QPointF(10.0, 0)); + directionAngle.setAngle(m_angle); + //If the current angle is nearly to the angle, then the moving speed will be + //1.0(follow the direction of the line), or -1.0(reverse direction of the + //line) + if(m_oppositeGuardianLine.angleTo(directionAngle) < + m_guardianLine.angleTo(directionAngle)) + { + m_movingSpeed=1.0; + m_angle=m_guardianLine.angle(); + } + else + { + m_movingSpeed=-1.0; + m_angle=m_oppositeGuardianLine.angle(); + } + //Move the robot to the foot point. + setPos(footPoint); + //Save the initial distance to p1. + m_toP1Distance=pointDistance(m_guardianLine.p1(), footPoint); +} + +void Robot::resetGuardianLine() +{ + m_hasGuardianLine=false; + m_guardianLine=QLineF(); + m_oppositeGuardianLine=QLineF(); + m_toP1Distance=0.0; + m_movingSpeed=1.0; +} + +void Robot::moveToOppositeDirection() +{ + if(!m_hasGuardianLine) + { + return; + } + //If the robot is moving along the line, change the direction back. + if(m_movingSpeed>0) + { + m_movingSpeed=-1.0; + m_angle=m_oppositeGuardianLine.angle(); + } + else + { + m_movingSpeed=1.0; + m_angle=m_guardianLine.angle(); + } +} + diff --git a/robot.h b/robot.h new file mode 100644 index 0000000..3530ba2 --- /dev/null +++ b/robot.h @@ -0,0 +1,295 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ROBOT_H +#define ROBOT_H + +#include +#include +#include +#include + +class QPainter; +/*! + * \brief The Robot class contains all the information and description of a + * robot, it contains the position, moving speed and direction of a robot. \n + * You can set the start position of a robot at any position you want. \n + * You have to recover the memory yourself. It don't have a parent. \n + * This is not a QObject for memory reduce, so there's no signal and slots. + */ +class Robot +{ +public: + /*! + * \brief Construct the robot. The start position of this type of construct + * will be QPointF(0, 0); + */ + Robot(); + + /*! + * \brief Construct the robot with the give position. + * \param pos The start position of the robot. + */ + Robot(QPointF pos); + + /*! + * \brief Construct the robot with the give position. + * \param x The start x position of the robot. + * \param y The start y position of the robot. + */ + Robot(qreal x, qreal y); + + /*! + * \brief The position of the robot. + * \return The QPointF format robot position. + */ + QPointF pos() const; + + /*! + * \brief Set the position of a robot. + * \param pos The position of the robot. + */ + void setPos(const QPointF &pos); + + /*! + * \brief This is an overloaded function.\n + * Set the position of a robot. + * \param x The x position of the robot. + * \param y The y position of the robot. + */ + inline void setPos(qreal x, qreal y) + { + setPos(QPointF(x, y)); + } + + /*! + * \brief Paint the robot with the specific painter. + * \param painter + */ + void paintRobot(QPainter *painter); + + /*! + * \brief Get the size of all the robots. + * \return The size of all robots. + */ + static int robotSize(); + + /*! + * \brief Change the size of all the robots. + * \param robotSize The new size of all robots. + */ + static void setRobotSize(int robotSize); + + /*! + * \brief Get the detect radius of all the robots. + * \return The detect radius of all robots. + */ + static int detectRadius(); + + /*! + * \brief Change all the detect radius of all the robots. + * \param detectRadius The new detect radius of all the robots. + */ + static void setDetectRadius(int detectRadius); + + /*! + * \brief Sets the color of the robot. + * \param robotColor The prefer color of all robots. + */ + static void setRobotColor(const QColor &robotColor); + + /*! + * \brief Get the color of all robots. + * \return The QColor of the robots. + */ + static QColor robotColor(); + + /*! + * \brief Get the color of the detection radius border of the robots. + * \return The QColor of the detection radius border of the robots. + */ + static QColor detectRadiusColor(); + + /*! + * \brief Change the color of the robot detection radius border. + * \param robotColor The prefer color of all the detection radius border of + * robots. + */ + static void setDetectRadiusColor(const QColor &detectRadiusColor); + + /*! + * \brief Get the moving angle of the robot. \n + * The default angle of the robot is 0 (3'o clock position). + * \return The angle of the robot. + */ + qreal angle() const; + + /*! + * \brief Change the moving angle of the robot, the value should be ranged + * from 0 degrees to 360 degrees. The program will automatically change the + * value. + * \param angle The prefer angle of the robot. + */ + void setAngle(const qreal &angle); + + /*! + * \brief Get the color the all the direction line color of the robots. + * \return The color of the direction line. + */ + static QColor directionLineColor(); + + /*! + * \brief Change the color of the direction line. + * \param directionLineColor The direction line color. + */ + static void setDirectionLineColor(const QColor &directionLineColor); + + /*! + * \brief Add a detected robot to the detection list. \n + * If the robot has been in the detect list, it won't add it twice. + * \param robot The robot which has been detected. + */ + void addToDetectList(Robot *robot); + + /*! + * \brief Remove one robot from the detect list. + * If the robot is not in the list, nothing will happened. + * \param robot The robot which should be removed. + */ + void removeFromDetectList(Robot *robot); + + /*! + * \brief Call this function will make the robot move 1 pixel length to the + * direction. + */ + void moveOneStep(); + + /*! + * \brief Get the next step of the robot is going to be. + * \return The next step position. + */ + QPointF nextStep() const; + + /*! + * \brief Update the direction of the robot according to the detected list. + */ + void updateDirection(); + + /*! + * \brief Get whether the robot has got a line to guard, each robot should + * guard one line. + * \return If the robot has a line to guard, return true, or else false. + */ + bool hasGuardianLine() const; + + /*! + * \brief Set a guardian line of to the robot. If the lenght of the line is + * 0, will remove the guardian state of the robot. + * \param line The guardian line of the robot. + */ + void setGuardianLine(const QLineF &line, const QPointF &footPoint); + + /*! + * \brief Clear the guardian line state data. + */ + void resetGuardianLine(); + + /*! + * \brief This function only available when there's a guardian line.\n + * Move to the opposite direction of the line. + */ + void moveToOppositeDirection(); + + /*! + * \brief The moving speed is only available when the robot got a guardian + * line, return the moving speed.\n + * This vale should be whether 1.0 or -1.0. + * \return The moving speed on a guardian line. + */ + qreal movingSpeed() const + { + return m_movingSpeed; + } + + /*! + * \brief This function is only available when the robot has a guardian + * line. It's a parameter for changing the direction. + * \return The robot distance to the p1 point of the guardian line. + */ + qreal toP1Distance() const + { + return m_toP1Distance; + } + + /*! + * \brief Get the guardian line of the current robot. + * \return The guardian line in QLineF format. + */ + QLineF guardianLine() const + { + return m_guardianLine; + } + + /*! + * \brief Calculate the distance of two point. + * \param p1 The first point. + * \param p2 The second point. + * \return The distance of two point. + */ + static qreal pointDistance(const QPointF p1, const QPointF p2) + { + return QLineF(p1, p2).length(); + } + + bool isDetectedListEmpty() + { + return m_detectedRobotList.isEmpty(); + } + +private: + struct RobotStatus + { + Robot *robot; + qreal distance; + RobotStatus(): + robot(nullptr), + distance(0.0) + { + ; + } + friend bool operator < (const RobotStatus &status1, + const RobotStatus &status2) + { + return status1.distance < status2.distance; + } + }; + + static int m_robotSize, m_detectRadius; + QPointF m_pos; + QList m_detectedRobotList; + + static QColor m_robotColor, m_detectRadiusColor, m_directionLineColor; + qreal m_angle; + + //Gardian line information + bool m_hasGuardianLine; + QLineF m_guardianLine, m_oppositeGuardianLine; + qreal m_toP1Distance, m_movingSpeed; +}; + +#endif // ROBOT_H diff --git a/robotaddwidget.cpp b/robotaddwidget.cpp new file mode 100644 index 0000000..6c92b5d --- /dev/null +++ b/robotaddwidget.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include + +#include "robotaddwidget.h" + +RobotAddWidget::RobotAddWidget(QWidget *parent) : + QWidget(parent), + m_okay(new QPushButton(this)), + m_cancel(new QPushButton(this)), + m_xData(new QSpinBox(this)), + m_yData(new QSpinBox(this)), + m_angleData(new QSlider(Qt::Horizontal, this)) +{ + //Intial labels. + for(int i=0; i<3; i++) + { + m_labels[i]=new QLabel(this); + } + //Initial the angle data. + m_angleData->setRange(0, 360); + m_xData->setRange(0, 0); + m_yData->setRange(0, 0); + + //Link edit widget. + connect(m_xData, SIGNAL(valueChanged(int)), + this, SLOT(onActionParameterChange())); + connect(m_yData, SIGNAL(valueChanged(int)), + this, SLOT(onActionParameterChange())); + connect(m_angleData, SIGNAL(valueChanged(int)), + this, SLOT(onActionParameterChange())); + + //Initial layouts. + QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::LeftToRight, + this); + mainLayout->setContentsMargins(0,0,0,0); + setLayout(mainLayout); + + //Generate the control layout. + QBoxLayout *controlLayout=new QBoxLayout(QBoxLayout::TopToBottom, + mainLayout->widget()); + controlLayout->setSpacing(2); + mainLayout->addLayout(controlLayout); + + QBoxLayout *positionLayout=new QBoxLayout(QBoxLayout::LeftToRight, + mainLayout->widget()); + positionLayout->setSpacing(5); + positionLayout->addWidget(m_labels[0]); + positionLayout->addWidget(m_xData, 1); + positionLayout->addSpacing(10); + positionLayout->addWidget(m_labels[1]); + positionLayout->addWidget(m_yData, 1); + controlLayout->addLayout(positionLayout); + QBoxLayout *angleLayout=new QBoxLayout(QBoxLayout::LeftToRight, + mainLayout->widget()); + angleLayout->addWidget(m_labels[2]); + angleLayout->addWidget(m_angleData, 1); + controlLayout->addLayout(angleLayout); + controlLayout->addStretch(); + + //Generate the button layout. + QBoxLayout *buttonLayout=new QBoxLayout(QBoxLayout::TopToBottom, + mainLayout->widget()); + buttonLayout->setSpacing(2); + buttonLayout->addWidget(m_okay); + buttonLayout->addWidget(m_cancel); + buttonLayout->addStretch(); + mainLayout->addLayout(buttonLayout); + + connect(m_okay, + static_cast(&QPushButton::clicked), + [=]{emit requireAddRobot(QPointF(m_xData->text().toDouble(), + m_yData->text().toDouble()), + m_angleData->value());}); + connect(m_cancel, + static_cast(&QPushButton::clicked), + [=]{emit requireClose();}); + + retranslate(); +} + +void RobotAddWidget::updateXAndYRange(const int &minX, const int &minY, + const int &maxX, const int &maxY) +{ + m_xData->setRange(minX, maxX); + m_yData->setRange(minY, maxY); +} + +void RobotAddWidget::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + //Reset the data. + m_xData->setValue(m_xData->minimum()); + m_yData->setValue(m_yData->minimum()); + m_angleData->setValue(0); + //Update the preview. + onActionParameterChange(); +} + +void RobotAddWidget::retranslate() +{ + m_okay->setText(tr("Ok")); + m_cancel->setText(tr("Cancel")); + + m_labels[0]->setText(tr("X:")); + m_labels[1]->setText(tr("Y:")); + m_labels[2]->setText(tr("Angle:")); +} + +void RobotAddWidget::onActionParameterChange() +{ + emit requirePreviewRobot(QPointF(m_xData->text().toDouble(), + m_yData->text().toDouble()), + m_angleData->value()); +} diff --git a/robotaddwidget.h b/robotaddwidget.h new file mode 100644 index 0000000..8c84e13 --- /dev/null +++ b/robotaddwidget.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ROBOTADDWIDGET_H +#define ROBOTADDWIDGET_H + +#include + +class QPushButton; +class QSpinBox; +class QSlider; +class QLabel; +class GroundBase; +/*! + * \brief The RobotAddWidget class is a widget for user to generate a robot in a + * user friend way. The user can set the initial position and the initial angle + * of the robot. The user can preview the robot state on the map. + */ +class RobotAddWidget : public QWidget +{ + Q_OBJECT +public: + /*! + * \brief Construct the RobotAddWidget class. + * \param parent The parent widget class. + */ + explicit RobotAddWidget(QWidget *parent = 0); + + /*! + * \brief Update the X position And Y position range. + * \param minX The minimal X coordinate value. + * \param minY The minimal Y coordinate value. + * \param maxX The maximum X coordinate value. + * \param maxY The maximum Y coordinate value. + */ + void updateXAndYRange(const int &minX, const int &minY, + const int &maxX, const int &maxY); + +signals: + /*! + * \brief When this signal is emitted, the robot management dialog will be + * closed. + */ + void requireClose(); + + /*! + * \brief When this signal is emitted, will ask the preview widget to draw a + * preview robot on the widget. + * \param position The preview robot position. + * \param angle The preview robot angle. + */ + void requirePreviewRobot(QPointF position, + qreal angle); + + /*! + * \brief This signal will ask the parent to try to add robot. + * \param position The prefer robot position. + * \param angle The prefer robot angle. + */ + void requireAddRobot(QPointF position, + qreal angle); + +public slots: + +protected: + /*! + * \brief Reimplemented from QWidget::showEvent(). + */ + void showEvent(QShowEvent *event); + +private slots: + void retranslate(); + void onActionParameterChange(); + +private: + QPushButton *m_okay, *m_cancel; + QLabel *m_labels[3]; + QSpinBox *m_xData, *m_yData; + QSlider *m_angleData; +}; + +#endif // ROBOTADDWIDGET_H diff --git a/robotmanagement.cpp b/robotmanagement.cpp new file mode 100644 index 0000000..a6fb09c --- /dev/null +++ b/robotmanagement.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include "ground.h" +#include "robot.h" +#include "menubar.h" +#include "robotaddwidget.h" +#include "groundpreviewwidget.h" + +#include "robotmanagement.h" + +#include + +RobotManagement::RobotManagement(QWidget *parent) : + QWidget(parent), + m_ground(nullptr), + m_groundPreview(new GroundPreviewWidget(this)), + m_stackLayout(new QStackedLayout), + m_robotAdd(new RobotAddWidget(this)) +{ + QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::LeftToRight, + this); + setLayout(mainLayout); + mainLayout->addWidget(m_groundPreview); + mainLayout->addLayout(m_stackLayout, 1); + //If we are using Mac OS X, using the sheet window flag. +#ifdef Q_OS_MACX + setWindowFlags(Qt::Sheet); +#else + setWindowFlags(Qt::Dialog); +#endif + + //Initial the actions. + for(int i=0; isetShortcut(QKeySequence(Qt::CTRL+Qt::Key_D)); + m_actions[ManageRobot]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_A)); + + //Link the slots. + connect(m_actions[AddRobot], + static_cast(&QAction::triggered), + [=]{addRobot();}); + connect(m_actions[ManageRobot], + static_cast(&QAction::triggered), + [=]{manageRobot();}); + + //Generate the add robot widget. + connect(m_robotAdd, &RobotAddWidget::requireClose, + this, &RobotManagement::close); + connect(m_robotAdd, &RobotAddWidget::requirePreviewRobot, + m_groundPreview, &GroundPreviewWidget::previewRobot); + connect(m_robotAdd, &RobotAddWidget::requireAddRobot, + this, &RobotManagement::onActionAddRobot); + m_stackLayout->addWidget(m_robotAdd); + + //Retranslate. + retranslate(); +} + +GroundBase *RobotManagement::ground() +{ + return m_ground; +} + +void RobotManagement::addRobot() +{ + //Show the add robot widget. + m_stackLayout->setCurrentWidget(m_robotAdd); + //Make the preview show the preview robot. + m_groundPreview->setShowPreviewPoint(true); + //Update the range. + QRectF barracksBoundingRect=m_ground->barracks().boundingRect(); + m_robotAdd->updateXAndYRange(barracksBoundingRect.left(), + barracksBoundingRect.top(), + barracksBoundingRect.right(), + barracksBoundingRect.bottom()); + //Show the dialog. + show(); +} + +void RobotManagement::manageRobot() +{ + //Hide the preview robot. + m_groundPreview->setShowPreviewPoint(false); + //Show the dialog. + show(); +} + +void RobotManagement::setGround(GroundBase *ground) +{ + //Save the ground. + m_ground = ground; + //Give the ground to the preview. + m_groundPreview->setGround(m_ground); +} + +void RobotManagement::setMenuBar(MenuBar *menuBar) +{ + menuBar->addCategoryAction(MenuBar::Robot, m_actions[AddRobot]); + menuBar->addCategoryAction(MenuBar::Robot, m_actions[ManageRobot]); +} + +void RobotManagement::retranslate() +{ + m_actions[AddRobot]->setText(tr("Add robot")); + m_actions[ManageRobot]->setText(tr("Manage robots")); +} + +void RobotManagement::onActionAddRobot(const QPointF &position, + const qreal &angle) +{ + //Generate a robot. + Robot *robot=new Robot(position); + robot->setAngle(angle); + //Try to add the robot, if sucessful, close the dialog. + if(m_ground->addRobot(robot)) + { + close(); + return; + } + //Or else, display an error information. + QMessageBox::warning(this, + tr("Add Robot Failed"), + tr("The robot is not in the barracks, you cannot add this robot")); +} diff --git a/robotmanagement.h b/robotmanagement.h new file mode 100644 index 0000000..d0c0332 --- /dev/null +++ b/robotmanagement.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) Kreogist Dev Team + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ROBOTMANAGEMENT_H +#define ROBOTMANAGEMENT_H + +#include + +class QStackedLayout; +class GroundBase; +class MenuBar; +class RobotAddWidget; +class GroundPreviewWidget; +/*! + * \brief The RobotManagement class is the dialog for robot add, modify and + * multi-robot remove. + */ +class RobotManagement : public QWidget +{ + Q_OBJECT +public: + /*! + * \brief Construct a robot management dialog. + * \param parent The parent widget. + */ + explicit RobotManagement(QWidget *parent = 0); + + /*! + * \brief Get the managing Ground class. + * \return The managing Ground class. + */ + GroundBase *ground(); + +signals: + +public slots: + /*! + * \brief Show add robot dialog. + */ + void addRobot(); + + /*! + * \brief Show the robots management dialog. + */ + void manageRobot(); + + /*! + * \brief Set the Ground class for signal robot management. + * \param ground The Ground class. + */ + void setGround(GroundBase *ground); + + /*! + * \brief Set the menu bar for action adding. + * \param menuBar The menu bar. + */ + void setMenuBar(MenuBar *menuBar); + +private slots: + void retranslate(); + void onActionAddRobot(const QPointF &position, + const qreal &angle); + +private: + enum RobotManagementActions + { + AddRobot, + ManageRobot, + RobotManagementActionsCount + }; + QAction *m_actions[RobotManagementActionsCount]; + + GroundBase *m_ground; + GroundPreviewWidget *m_groundPreview; + QStackedLayout *m_stackLayout; + RobotAddWidget *m_robotAdd; +}; + +#endif // ROBOTMANAGEMENT_H