added a ruler for measuring

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
This commit is contained in:
2017-03-10 13:44:17 +01:00
parent 2297a76c53
commit f40fc9a823
32 changed files with 809 additions and 198 deletions

View File

@@ -4,9 +4,10 @@
#include "../mapview/model/MMFloorObstacleLine.h"
#include "../mapview/model/MMFloorOutlinePolygon.h"
#include "../mapview/model/IHasMAC.h"
#include "../mapview/model/IHasFile.h"
#include "../mapview/model/IHasParams.h"
#include "../mapview/model/IHasEditableMeta.h"
#include "MetaEditWidget.h"
#include <Indoor/floorplan/v2/Floorplan.h>
@@ -138,13 +139,15 @@ void ElementParamWidget::refresh() {
lay->addWidget(cmb,r,1);
cmb->setCurrentIndex((int)elem->getMethod());
connect(cmb, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [elem, cmb] (int idx) {
(void) idx;
elem->setMethod( (Floorplan::OutlineMethod) cmb->currentData().toInt() );
});
++r;
}
}
{
{ // does the element have "parameters" ?
IHasParams* elem = dynamic_cast<IHasParams*>(el);
if (elem) {
@@ -160,6 +163,9 @@ void ElementParamWidget::refresh() {
switch(param.type) {
case ParamType::NOT_AVAILABLE:
break;
case ParamType::BOOL: {
QCheckBox* chk = new QCheckBox( );
chk->setChecked(value.toBool());
@@ -216,6 +222,7 @@ void ElementParamWidget::refresh() {
QPushButton* btn = new QPushButton("<");
btn->setMaximumSize(32,32);
connect(btn, &QPushButton::clicked, [i,elem,lblFile] (const bool checked) {
(void) checked;
QString res = QFileDialog::getOpenFileName();
elem->setParamValue(i, ParamValue(res.toStdString()));
lblFile->setText(res);
@@ -235,6 +242,7 @@ void ElementParamWidget::refresh() {
laySub->addWidget(txtY,0,1);
lay->addWidget(subWidget,r,1);
auto onChange = [i,elem,txtX,txtY] (const QString& str) {
(void) str;
elem->setParamValue(i, ParamValue( Point2(txtX->text().toFloat(), txtY->text().toFloat()) ));
};
connect(txtX, &QLineEdit::textChanged, onChange);
@@ -269,6 +277,23 @@ void ElementParamWidget::refresh() {
}
}
{ // does the element have editable metadata?
IHasEditableMeta* elem = dynamic_cast<IHasEditableMeta*>(el);
if (elem) {
QPushButton* btn = new QPushButton("edit");
connect(btn, &QPushButton::clicked, [elem] (const bool checked) {
(void) checked;
if (!elem->getMeta()) {elem->setMeta(new Floorplan::Meta());} // ensure meta-object is present
MetaEditWidget* mew = new MetaEditWidget(elem->getMeta()); // edit
mew->show();
});
lay->addWidget(new QLabel("Meta"),r,0);
lay->addWidget(btn,r,1);
}
}
}
//setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
@@ -294,23 +319,3 @@ void ElementParamWidget::onObstacleTypeChange() {
IHasObstacleType* el = dynamic_cast<IHasObstacleType*>(this->curElement);
if (el) {el->setObstacleType((Floorplan::ObstacleType) obstacleType.cmb->currentData().toInt() );}
}
//void ElementParamWidget::onNameChange() {
// IHasName* el = dynamic_cast<IHasName*>(this->curElement);
// if (el) {el->setName(name.txt->text().toStdString());}
//}
//void ElementParamWidget::onOutlineMethodChange() {
// MMFloorOutlinePolygon* el = dynamic_cast<MMFloorOutlinePolygon*>(this->curElement);
// if (el) {el->setMethod( (Floorplan::OutlineMethod) outlineMethod.cmb->currentData().toInt() );}
//}
//void ElementParamWidget::onMACChanged() {
// dynamic_cast<IHasMAC*>(curElement)->setMAC(mac.txt->text().toStdString());
//}
//void ElementParamWidget::onSelectFileName() {
// QString res = QFileDialog::getOpenFileName(this);
// dynamic_cast<IHasFile*>(curElement)->setFileName(res.toStdString());
// fileName.txt->setText(res);
//}

87
params/MetaEditModel.cpp Normal file
View File

@@ -0,0 +1,87 @@
#include "MetaEditModel.h"
MetaEditModel::MetaEditModel(QObject* parent) : QAbstractTableModel(parent) {
setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
}
void MetaEditModel::setSource(Floorplan::Meta* meta) {
beginResetModel();
this->meta = meta;
endResetModel();
}
int MetaEditModel::rowCount(const QModelIndex &parent) const {
return (meta) ? (meta->size()) : (0);
}
int MetaEditModel::columnCount(const QModelIndex &parent) const {
return 2;
}
QVariant MetaEditModel::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) {
switch(index.column()) {
case 0: return meta->getKey(index.row()).c_str();
case 1: return meta->getVal(index.row()).c_str();
}
}
return QVariant();
}
bool MetaEditModel::setData(const QModelIndex & index, const QVariant &value, int role) {
if (role == Qt::EditRole) {
switch(index.column()) {
case 0: meta->setKey(index.row(), value.toString().toStdString()); return true;
case 1: meta->setVal(index.row(), value.toString().toStdString()); return true;
}
}
return false;
}
void MetaEditModel::deleteEntry(const int idx) {
beginResetModel();
meta->deleteEntry(idx);
endResetModel();
}
void MetaEditModel::addEntry() {
beginResetModel();
meta->add("key", "val");
endResetModel();
}
Qt::ItemFlags MetaEditModel::flags(const QModelIndex &index) const {
if (!index.isValid()) {return Qt::ItemIsEnabled;}
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}
QVariant MetaEditModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (role == Qt::DisplayRole) {
if(orientation == Qt::Horizontal) {
if (section == 0) {return "key";}
if (section == 1) {return "value";}
} else {
return QString::number(section);
}
}
return QVariant();
}

41
params/MetaEditModel.h Normal file
View File

@@ -0,0 +1,41 @@
#ifndef METAEDITMODEL_H
#define METAEDITMODEL_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include <QAbstractTableModel>
class MetaEditModel : public QAbstractTableModel {
Q_OBJECT
private:
Floorplan::Meta* meta = nullptr;
public:
MetaEditModel(QObject* parent = nullptr);
/** delete the idx-th entry */
void deleteEntry(const int idx);
/** add a new entry at the end */
void addEntry();
void setSource(Floorplan::Meta* meta);
int rowCount(const QModelIndex& parent) const override;
int columnCount(const QModelIndex& parent) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
bool setData(const QModelIndex & index, const QVariant &value, int role = Qt::EditRole) override;
};
#endif // METAEDITMODEL_H

67
params/MetaEditWidget.cpp Normal file
View File

@@ -0,0 +1,67 @@
#include "MetaEditWidget.h"
#include "MetaEditModel.h"
#include <QTableView>
#include <QGridLayout>
#include <QKeyEvent>
#include <QPushButton>
MetaEditWidget::MetaEditWidget(Floorplan::Meta* meta) : QWidget(nullptr), metaOrig(meta) {
// local copy. for the abort button [orig is unchanged]
metaCopy.params = metaOrig->params;
QGridLayout* lay = new QGridLayout(this);
tbl = new QTableView();
lay->addWidget(tbl, 0, 0, 1, 3);
model = new MetaEditModel();
model->setSource(&metaCopy); // we edit the copy
tbl->setModel(model);
tbl->setSelectionBehavior(QAbstractItemView::SelectRows);
tbl->setSelectionMode(QAbstractItemView::SingleSelection);
// events
QPushButton* btnAdd = new QPushButton("add entry");
lay->addWidget(btnAdd, 1, 0);
btnAdd->connect(btnAdd, &QPushButton::clicked, [this] (const bool) {
model->addEntry();
});
btnAdd->setToolTip("add a new, empty entry. delete an entry using the keyboard");
QPushButton* btnCancel = new QPushButton("abort");
lay->addWidget(btnCancel, 1, 1);
btnCancel->connect(btnCancel, &QPushButton::clicked, [this] (const bool) {
// do not apply changes. juts close
close();
});
btnCancel->setToolTip("close the dialog without committing the changes");
QPushButton* btnOK = new QPushButton("OK");
lay->addWidget(btnOK, 1, 2);
btnOK->connect(btnOK, &QPushButton::clicked, [this] (const bool) {
metaOrig->params = metaCopy.params; // apply changed
close();
});
btnOK->setToolTip("commit the changes and close the dialog");
// sizing
resize(500,400);
}
void MetaEditWidget::keyPressEvent(QKeyEvent* e) {
if (e->key() == Qt::Key_Delete) {
QModelIndexList indices = tbl->selectionModel()->selectedIndexes();
for (const QModelIndex& idx : indices) {
model->deleteEntry(idx.row());
break; // the list contains one entry per column!
}
}
}

35
params/MetaEditWidget.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef METAEDITWIDGET_H
#define METAEDITWIDGET_H
#include <QWidget>
#include <Indoor/floorplan/v2/Floorplan.h>
class MetaEditModel;
class QTableView;
/**
* helper class to edit the Floorplan::Meta
* key value attribute
*/
class MetaEditWidget : public QWidget {
Q_OBJECT
private:
Floorplan::Meta* metaOrig;
Floorplan::Meta metaCopy; // used for the abort button
MetaEditModel* model;
QTableView* tbl;
public:
MetaEditWidget(Floorplan::Meta* meta);
void keyPressEvent(QKeyEvent* e);
};
#endif // METAEDITWIDGET_H

View File

@@ -13,8 +13,19 @@
#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;
@@ -30,6 +41,16 @@ ToolBoxWidget::ToolBoxWidget(MapView2D* view, QWidget *parent) : QWidget(parent)
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"), "");
@@ -63,6 +84,10 @@ ToolBoxWidget::ToolBoxWidget(MapView2D* view, QWidget *parent) : QWidget(parent)
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);
@@ -342,116 +367,25 @@ public:
};
//struct NewLineTool : public Tool {
// /** add another line after this one? */
// bool multiple = true;
// /** register this tool into the given tools-queue */
// Tools& tools;
// /** the layer to add the new line to */
// MapLayer* layer;
// /** currently edited line */
// Floorplan::FloorObstacleLine* foLine;
// MMFloorObstacleLine* mmLine;
// /** new line type */
// Floorplan::ObstacleType type;
// /** new line material */
// Floorplan::Material mat;
// /** currently edited line node (has 2) */
// int idx = 0;
// NewLineTool(Tools& tools, MapLayer* layer, Floorplan::ObstacleType type, Floorplan::Material mat) : tools(tools), layer(layer), type(type), mat(mat) {
// createEmptyLine();
// tools.addFront(this);
// }
// virtual bool mousePressEvent(MapView2D* m, QMouseEvent* e) override {
// (void) m; (void) e;
// return true;
// }
// 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);
// if (idx == 0) { foLine->from = onMap; foLine->to = onMap; }
// if (idx == 1) { foLine->to = onMap; }
// return true;
// }
// virtual bool mouseReleaseEvent(MapView2D* m, QMouseEvent* e) override {
// (void) m; (void) e;
// ++idx;
// if (idx == 2) {
// finalizeLine();
// if (multiple) {
// idx = 0;
// createEmptyLine();
// } else {
// disableMe();
// }
// }
// return true;
// }
// virtual bool keyPressEvent(MapView2D* m, QKeyEvent* e) override {
// (void) m;
// if (e->key() == Qt::Key_Escape) {
// if (mmLine) {mmLine->deleteMe();}
// disableMe(); return true;
// }
// return false;
// }
//private:
// /** finalize the current line */
// void finalizeLine() {
// if (!mmLine) {return;}
// mmLine->getMV2D()->unfocus();
// mmLine = nullptr;
// }
// /** stop creating new lines */
// void disableMe() {
// finalizeLine();
// tools.remove(this);
// delete this;
// }
// /** create a new, empty line */
// void createEmptyLine() {
// foLine = new Floorplan::FloorObstacleLine(type, mat, Point2(0, 0), Point2(0, 0));
// MMFloorObstacles* obs = (MMFloorObstacles*)layer;
// mmLine = obs->createLine(foLine);
// mmLine->getMV2D()->focus();
// }
//};
void ToolBoxWidget::onSelect() {
}
void ToolBoxWidget::onMeasure() {
new ToolMeasure(view->getTools());
}
void ToolBoxWidget::onNewWall() {
new NewWallTool(view->getTools(), curLayer);
//view->getModel()->reselect();
}
void ToolBoxWidget::onNewPillar() {
@@ -476,21 +410,6 @@ void ToolBoxWidget::onNewDoor() {
new NewDoorTool(view->getTools(), curLayer);
// const Point2 center = view->getScaler().getCenter();
// float s = view->getScaler().sm(50);
// Floorplan::FloorObstacleDoor* door = new Floorplan::FloorObstacleDoor(
// Floorplan::DoorType::SWING,
// Floorplan::Material::WOOD,
// Point2(center.x-s, center.y),
// Point2(center.x+s, center.y)
// );
// MMFloorObstacles* obs = (MMFloorObstacles*)curLayer;
// obs->createDoor(door);
//view->getModel()->reselect();
}
void ToolBoxWidget::onNewStair() {

View File

@@ -8,7 +8,9 @@ class QPushButton;
class MapView2D;
/**
* gui element with actions to perform
* the toolbox on the left of the map.
* gui element with actions to perform.
* add new elements, etc.
*/
class ToolBoxWidget : public QWidget {
@@ -32,6 +34,7 @@ private:
int r = 0;
QPushButton* btnSelect;
QPushButton* btnMeasure;
QPushButton* btnGround;
QPushButton* btnWall;
@@ -49,6 +52,7 @@ private:
private slots:
void onSelect();
void onMeasure();
void onNewGround();
void onNewWall();