added support for meta-data editing improved element selection changed zooming fixed some issues with layer events fixed issue with 3D outline fixed loading issue for old maps some interface changes
487 lines
12 KiB
C++
487 lines
12 KiB
C++
#include "ToolBoxWidget.h"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QGridLayout>
|
|
|
|
#include <QPushButton>
|
|
#include <QPixmap>
|
|
|
|
#include "../mapview/model/MapLayers.h"
|
|
|
|
#include "../mapview/2D/MapView2D.h"
|
|
#include "../mapview/model/MapModel.h"
|
|
#include "../mapview/model/MMFloorAccessPoint.h"
|
|
#include "../mapview/model/MMFloorBeacon.h"
|
|
|
|
#include "../mapview/2D/tools/ToolMeasure.h"
|
|
|
|
#include "../UIHelper.h"
|
|
|
|
QSplitter* getSplitter() {
|
|
|
|
QSplitter* splt = new QSplitter();
|
|
splt->setStyleSheet("background-color:black;");
|
|
splt->setMinimumHeight(1);
|
|
return splt;
|
|
|
|
}
|
|
|
|
ToolBoxWidget::ToolBoxWidget(MapView2D* view, QWidget *parent) : QWidget(parent), view(view) {
|
|
|
|
const int s = 32;
|
|
setMaximumWidth(48);
|
|
setMinimumWidth(48);
|
|
|
|
QGridLayout* lay = new QGridLayout(this);
|
|
|
|
// SELECTION
|
|
btnSelect = new QPushButton(UIHelper::getIcon("cursor"), "");
|
|
btnSelect->setMinimumSize(s,s);
|
|
lay->addWidget(btnSelect, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnSelect, SIGNAL(clicked(bool)), this, SLOT(onSelect()));
|
|
|
|
|
|
// MEASURE
|
|
btnMeasure = new QPushButton(UIHelper::getIcon("ruler"), "");
|
|
btnMeasure->setMinimumSize(s,s);
|
|
lay->addWidget(btnMeasure, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnMeasure, SIGNAL(clicked(bool)), this, SLOT(onMeasure()));
|
|
|
|
|
|
// splitter
|
|
lay->addWidget(getSplitter(), r++, 0, 1,1,Qt::AlignTop);
|
|
|
|
|
|
// OBSTACLES
|
|
btnGround = new QPushButton(UIHelper::getIcon("floor"), "");
|
|
btnGround->setMinimumSize(s,s);
|
|
lay->addWidget(btnGround, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnGround, SIGNAL(clicked(bool)), this, SLOT(onNewGround()));
|
|
|
|
btnWall = new QPushButton(UIHelper::getIcon("wall"), "");
|
|
btnWall->setMinimumSize(s,s);
|
|
lay->addWidget(btnWall, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnWall, SIGNAL(clicked(bool)), this, SLOT(onNewWall()));
|
|
|
|
btnPillar = new QPushButton(UIHelper::getIcon("pillar"), "");
|
|
btnPillar->setMinimumSize(s,s);
|
|
lay->addWidget(btnPillar, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnPillar, SIGNAL(clicked(bool)), this, SLOT(onNewPillar()));
|
|
|
|
btnDoor = new QPushButton(UIHelper::getIcon("door"), "");
|
|
btnDoor->setMinimumSize(s,s);
|
|
lay->addWidget(btnDoor, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnDoor, SIGNAL(clicked(bool)), this, SLOT(onNewDoor()));
|
|
|
|
btnStair = new QPushButton(UIHelper::getIcon("stair"), "");
|
|
btnStair->setMinimumSize(s,s);
|
|
lay->addWidget(btnStair, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnStair, SIGNAL(clicked(bool)), this, SLOT(onNewStair()));
|
|
|
|
btnElevator = new QPushButton(UIHelper::getIcon("elevator"), "");
|
|
btnElevator->setMinimumSize(s,s);
|
|
lay->addWidget(btnElevator, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnElevator, SIGNAL(clicked(bool)), this, SLOT(onNewElevator()));
|
|
|
|
|
|
// splitter
|
|
lay->addWidget(getSplitter(), r++, 0, 1,1,Qt::AlignTop);
|
|
|
|
|
|
// TRANSMITTERS
|
|
btnWifi = new QPushButton(UIHelper::getIcon("wifi"), "");
|
|
btnWifi->setMinimumSize(s,s);
|
|
lay->addWidget(btnWifi, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnWifi, SIGNAL(clicked(bool)), this, SLOT(onNewAccessPoint()));
|
|
|
|
btnBeacon = new QPushButton(UIHelper::getIcon("beacon"), "");
|
|
btnBeacon->setMinimumSize(s,s);
|
|
lay->addWidget(btnBeacon, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnBeacon, SIGNAL(clicked(bool)), this, SLOT(onNewBeacon()));
|
|
|
|
// IMAGES
|
|
btnImage = new QPushButton(UIHelper::getIcon("image"), "");
|
|
btnImage->setMinimumSize(s,s);
|
|
lay->addWidget(btnImage, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnImage, SIGNAL(clicked(bool)), this, SLOT(onNewImage()));
|
|
|
|
// POI
|
|
btnPOI = new QPushButton(UIHelper::getIcon("poi"), "");
|
|
btnPOI->setMinimumSize(s,s);
|
|
lay->addWidget(btnPOI, r++, 0, 1,1,Qt::AlignTop);
|
|
connect(btnPOI, SIGNAL(clicked(bool)), this, SLOT(onNewPOI()));
|
|
|
|
// FILL
|
|
lay->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), r, 0);
|
|
|
|
// start empty
|
|
setSelectedLayer(nullptr);
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::setSelectedLayer(MapLayer *ml) {
|
|
|
|
this->curLayer = ml;
|
|
|
|
btnGround->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_GROUND));
|
|
|
|
btnWall->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_OBSTACLES));
|
|
btnPillar->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_OBSTACLES));
|
|
btnDoor->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_OBSTACLES));
|
|
|
|
btnStair->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_STAIRS));
|
|
btnElevator->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_ELEVATORS));
|
|
|
|
btnWifi->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_ACCESS_POINTS));
|
|
btnBeacon->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_BEACONS));
|
|
btnPOI->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_POIS));
|
|
|
|
btnImage->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_UNDERLAYS));
|
|
|
|
}
|
|
|
|
|
|
void ToolBoxWidget::onNewGround() {
|
|
|
|
const Point2 center = view->getScaler().getCenter();
|
|
float s = view->getScaler().sm(50);
|
|
|
|
Floorplan::FloorOutlinePolygon* poly = new Floorplan::FloorOutlinePolygon();
|
|
poly->name = "new";
|
|
poly->poly.points.push_back(Point2(center.x-s, center.y-s));
|
|
poly->poly.points.push_back(Point2(center.x+s, center.y-s));
|
|
poly->poly.points.push_back(Point2(center.x, center.y+s));
|
|
|
|
|
|
MMFloorOutline* ml = (MMFloorOutline*)curLayer;
|
|
ml->create(poly);
|
|
|
|
view->getModel()->reselect();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FloorplanElement, typename MapModelElement> class NewElementTool : public Tool {
|
|
|
|
protected:
|
|
|
|
/** add another line after this one? */
|
|
bool addAnother = true;
|
|
|
|
/** register this tool into the given tools-queue */
|
|
Tools& tools;
|
|
Tool* oldMainTool;
|
|
|
|
/** the layer to add the new element to */
|
|
MapLayer* layer = nullptr;
|
|
|
|
/** currently edited element */
|
|
FloorplanElement* foEL = nullptr;
|
|
MapModelElement* mmEL = nullptr;
|
|
|
|
public:
|
|
|
|
NewElementTool(Tools& tools, MapLayer* layer) : tools(tools), layer(layer) {
|
|
oldMainTool = tools.getMain(); // keep the current tool to reset it later
|
|
tools.setMain(this);
|
|
}
|
|
|
|
virtual ~NewElementTool() {
|
|
tools.setMain(oldMainTool); // reset to the previous tool
|
|
}
|
|
|
|
virtual bool mousePressEvent(MapView2D* m, QMouseEvent* e) override {
|
|
if (e->button() == Qt::MouseButton::LeftButton) {
|
|
(void) m; (void) e;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
virtual bool mouseMoveEvent(MapView2D* m, QMouseEvent* e) override {
|
|
const Point2 onScreen(e->x(), e->y());
|
|
Point2 onMap = m->getScaler().sm(onScreen);
|
|
onMap = m->getScaler().snap(onMap);
|
|
moving(onMap);
|
|
return true;
|
|
}
|
|
|
|
virtual bool mouseReleaseEvent(MapView2D* m, QMouseEvent* e) override {
|
|
if (e->button() == Qt::MouseButton::LeftButton) {
|
|
(void) m; (void) e;
|
|
next();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
virtual bool keyPressEvent(MapView2D* m, QKeyEvent* e) override {
|
|
(void) m;
|
|
if (e->key() == Qt::Key_Escape) {
|
|
deleteCurrent();
|
|
disableMe();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected:
|
|
|
|
/** all subclasses must create a new, empty element here */
|
|
virtual void createEmptyElement() = 0;
|
|
|
|
/** mouse is currently moved */
|
|
virtual void moving(const Point2 mapPoint) = 0;
|
|
|
|
/** next pont */
|
|
virtual void next() = 0;
|
|
|
|
protected:
|
|
|
|
void create() {
|
|
createEmptyElement();
|
|
mmEL->getMV2D()->focus();
|
|
}
|
|
|
|
/** delete the currently edited element */
|
|
void deleteCurrent() {
|
|
if (mmEL) {mmEL->deleteMe();}
|
|
}
|
|
|
|
/** finalize the current element (if any) */
|
|
void finalizeCurrent() {
|
|
if (!mmEL) {return;}
|
|
mmEL->getMV2D()->unfocus();
|
|
mmEL = nullptr;
|
|
}
|
|
|
|
/** finish creating new elements */
|
|
void disableMe() {
|
|
finalizeCurrent();
|
|
delete this; // see dtor!
|
|
}
|
|
|
|
};
|
|
|
|
class NewWallTool : public NewElementTool<Floorplan::FloorObstacleLine, MMFloorObstacleLine> {
|
|
|
|
private:
|
|
|
|
/** currently edited line node (has 2) */
|
|
int idx = 0;
|
|
|
|
public:
|
|
|
|
NewWallTool(Tools& tools, MapLayer* layer) : NewElementTool(tools, layer) {
|
|
create();
|
|
}
|
|
|
|
const std::string getName() const override {
|
|
return "new Wall";
|
|
}
|
|
|
|
void createEmptyElement() override {
|
|
|
|
foEL = new Floorplan::FloorObstacleLine(Floorplan::ObstacleType::WALL, Floorplan::Material::DRYWALL, Point2(0, 0), Point2(0, 0));
|
|
MMFloorObstacles* obs = (MMFloorObstacles*)layer;
|
|
mmEL = obs->createLine(foEL);
|
|
|
|
}
|
|
|
|
/** mouse is currently moved */
|
|
void moving(const Point2 mapPoint) override {
|
|
|
|
if (idx == 0) { foEL->from = mapPoint; foEL->to = mapPoint; }
|
|
if (idx == 1) { foEL->to = mapPoint; }
|
|
|
|
}
|
|
|
|
/** next pont */
|
|
void next() override {
|
|
|
|
if (++idx == 2) {
|
|
finalizeCurrent();
|
|
if (addAnother) {
|
|
idx = 0;
|
|
create();
|
|
} else {
|
|
disableMe();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
class NewDoorTool : public NewElementTool<Floorplan::FloorObstacleDoor, MMFloorObstacleDoor> {
|
|
|
|
private:
|
|
|
|
/** currently edited line node (has 2) */
|
|
int idx = 0;
|
|
|
|
public:
|
|
|
|
NewDoorTool(Tools& tools, MapLayer* layer) : NewElementTool(tools, layer) {
|
|
create();
|
|
}
|
|
|
|
const std::string getName() const override {
|
|
return "new Door";
|
|
}
|
|
|
|
void createEmptyElement() override {
|
|
|
|
foEL = new Floorplan::FloorObstacleDoor(Floorplan::DoorType::SWING, Floorplan::Material::WOOD, Point2(0, 0), Point2(0, 0));
|
|
MMFloorObstacles* obs = (MMFloorObstacles*)layer;
|
|
mmEL = obs->createDoor(foEL);
|
|
|
|
}
|
|
|
|
/** mouse is currently moved */
|
|
void moving(const Point2 mapPoint) override {
|
|
|
|
if (idx == 0) { foEL->from = mapPoint; foEL->to = mapPoint; }
|
|
if (idx == 1) { foEL->to = mapPoint; }
|
|
|
|
}
|
|
|
|
/** next pont */
|
|
void next() override {
|
|
|
|
if (++idx == 2) {
|
|
finalizeCurrent();
|
|
if (addAnother) {
|
|
idx = 0;
|
|
create();
|
|
} else {
|
|
disableMe();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
void ToolBoxWidget::onSelect() {
|
|
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onMeasure() {
|
|
|
|
new ToolMeasure(view->getTools());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ToolBoxWidget::onNewWall() {
|
|
|
|
new NewWallTool(view->getTools(), curLayer);
|
|
//view->getModel()->reselect();
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onNewPillar() {
|
|
|
|
const Point2 center = view->getScaler().getCenter();
|
|
float s = view->getScaler().sm(50);
|
|
|
|
Floorplan::FloorObstacleCircle* pillar = new Floorplan::FloorObstacleCircle(
|
|
Floorplan::Material::DRYWALL,
|
|
Point2(center.x-s, center.y),
|
|
s
|
|
);
|
|
|
|
MMFloorObstacles* obs = (MMFloorObstacles*)curLayer;
|
|
obs->createCircle(pillar);
|
|
|
|
//view->getModel()->reselect();
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onNewDoor() {
|
|
|
|
new NewDoorTool(view->getTools(), curLayer);
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onNewStair() {
|
|
|
|
const Point2 center = view->getScaler().getCenter();
|
|
|
|
Floorplan::StairFreeform* stair = new Floorplan::StairFreeform();
|
|
Floorplan::StairPart part(Point3(center.x-3, center.y, 0), Point3(center.x+3, center.y, 3), 3);
|
|
stair->parts.push_back( part );
|
|
|
|
MMFloorStairs* stairs = (MMFloorStairs*)curLayer;
|
|
stairs->create(stair);
|
|
|
|
//view->getModel()->reselect();
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onNewElevator() {
|
|
|
|
const Point2 center = view->getScaler().getCenter();
|
|
|
|
Floorplan::Elevator* elevator = new Floorplan::Elevator(center);
|
|
|
|
MMFloorElevators* elevators = (MMFloorElevators*)curLayer;
|
|
elevators->create(elevator);
|
|
|
|
//view->getModel()->reselect();
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onNewAccessPoint() {
|
|
|
|
const Point2 center = view->getScaler().getCenter();
|
|
Floorplan::AccessPoint* ap = new Floorplan::AccessPoint(
|
|
"noname", "00:00:00:00:00:00", Point3(center.x, center.y, 0)
|
|
);
|
|
|
|
MMFloorAccessPoints* aps = (MMFloorAccessPoints*) curLayer;
|
|
aps->createAP(ap);
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onNewBeacon() {
|
|
|
|
const Point2 center = view->getScaler().getCenter();
|
|
Floorplan::Beacon* b = new Floorplan::Beacon(
|
|
"noname", "00:00:00:00:00:00", Point3(center.x, center.y, 0)
|
|
);
|
|
|
|
MMFloorBeacons* beacons = (MMFloorBeacons*) curLayer;
|
|
beacons->createBeacon(b);
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onNewPOI() {
|
|
|
|
const Point2 center = view->getScaler().getCenter();
|
|
Floorplan::POI* poi = new Floorplan::POI(
|
|
Floorplan::POIType::ROOM, "noname", Point2(center.x, center.y)
|
|
);
|
|
|
|
MMFloorPOIs* pois = (MMFloorPOIs*) curLayer;
|
|
pois->createPOI(poi);
|
|
|
|
}
|
|
|
|
void ToolBoxWidget::onNewImage() {
|
|
|
|
const Point2 center = view->getScaler().getCenter();
|
|
|
|
MMFloorUnderlays* underlays = (MMFloorUnderlays*) curLayer;
|
|
underlays->createImage(center);
|
|
|
|
}
|