mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-11-17 21:11:39 +00:00
parent
cae892cda2
commit
9cea16c0ea
4 changed files with 364 additions and 592 deletions
|
@ -188,7 +188,7 @@ void WorldEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
if (mouseEvent->button() == Qt::LeftButton)
|
if (mouseEvent->button() == Qt::LeftButton)
|
||||||
{
|
{
|
||||||
// Create new sub-points
|
// Create new sub-points
|
||||||
// Call method mousePressEvent for point located under mouse
|
// Call method mousePressEvent for sub-point located under mouse
|
||||||
LandscapeEditor::LandscapeSceneBase::mousePressEvent(mouseEvent);
|
LandscapeEditor::LandscapeSceneBase::mousePressEvent(mouseEvent);
|
||||||
|
|
||||||
if ((!m_editedSelectedItems && m_selectedPoints.isEmpty()) ||
|
if ((!m_editedSelectedItems && m_selectedPoints.isEmpty()) ||
|
||||||
|
@ -205,7 +205,7 @@ void WorldEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
m_selectedPoints.clear();
|
m_selectedPoints.clear();
|
||||||
|
|
||||||
// Delete sub-points if it located under mouse
|
// Delete sub-points if it located under mouse
|
||||||
// Call method mousePressEvent for point located under mouse
|
// Call method mousePressEvent for sub-point located under mouse
|
||||||
LandscapeEditor::LandscapeSceneBase::mousePressEvent(mouseEvent);
|
LandscapeEditor::LandscapeSceneBase::mousePressEvent(mouseEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,119 +232,35 @@ void WorldEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
|
|
||||||
if (m_mode == WorldEditorScene::SelectMode)
|
if (m_mode == WorldEditorScene::SelectMode)
|
||||||
m_selectionArea.setTopLeft(mouseEvent->scenePos());
|
m_selectionArea.setTopLeft(mouseEvent->scenePos());
|
||||||
|
|
||||||
// if (m_selectedItems.isEmpty())
|
|
||||||
// m_selectionArea.setTopLeft(mouseEvent->scenePos());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
void WorldEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
{
|
{
|
||||||
if (QApplication::mouseButtons() == Qt::LeftButton)
|
if (QApplication::mouseButtons() == Qt::LeftButton)
|
||||||
{
|
{
|
||||||
QPointF offset(mouseEvent->scenePos() - mouseEvent->lastScenePos());
|
|
||||||
|
|
||||||
m_selectionArea.setBottomRight(mouseEvent->scenePos());
|
m_selectionArea.setBottomRight(mouseEvent->scenePos());
|
||||||
|
|
||||||
switch (m_mode)
|
switch (m_mode)
|
||||||
{
|
{
|
||||||
case WorldEditorScene::SelectMode:
|
case WorldEditorScene::SelectMode:
|
||||||
break;
|
break;
|
||||||
case WorldEditorScene::MoveMode:
|
case WorldEditorScene::MoveMode:
|
||||||
{
|
updateWorldItemsMove(mouseEvent);
|
||||||
if (m_pointsMode)
|
|
||||||
{
|
|
||||||
Q_FOREACH(QGraphicsItem *item, m_selectedPoints)
|
|
||||||
{
|
|
||||||
item->moveBy(offset.x(), offset.y());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
|
|
||||||
{
|
|
||||||
item->moveBy(offset.x(), offset.y());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case WorldEditorScene::RotateMode:
|
case WorldEditorScene::RotateMode:
|
||||||
{
|
updateWorldItemsRotate(mouseEvent);
|
||||||
// Caluculate angle between two line
|
|
||||||
QLineF firstLine(m_pivot, mouseEvent->lastScenePos());
|
|
||||||
QLineF secondLine(m_pivot, mouseEvent->scenePos());
|
|
||||||
qreal angle = secondLine.angleTo(firstLine);
|
|
||||||
|
|
||||||
m_angle += angle;
|
|
||||||
|
|
||||||
if (m_pointsMode)
|
|
||||||
{
|
|
||||||
Q_FOREACH(QGraphicsItem *item, m_selectedPoints)
|
|
||||||
{
|
|
||||||
qgraphicsitem_cast<WorldItemSubPoint *>(item)->rotateOn(m_pivot, angle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
|
|
||||||
{
|
|
||||||
qgraphicsitem_cast<AbstractWorldItem *>(item)->rotateOn(m_pivot, angle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case WorldEditorScene::ScaleMode:
|
case WorldEditorScene::ScaleMode:
|
||||||
{
|
updateWorldItemsScale(mouseEvent);
|
||||||
// Calculate scale factor
|
|
||||||
if (offset.x() > 0)
|
|
||||||
offset.setX(1.0 + (offset.x() / 5000));
|
|
||||||
else
|
|
||||||
offset.setX(1.0 / (1.0 + (-offset.x() / 5000)));
|
|
||||||
|
|
||||||
if (offset.y() < 0)
|
|
||||||
offset.setY(1.0 + (-offset.y() / 5000));
|
|
||||||
else
|
|
||||||
offset.setY(1.0 / (1.0 + (offset.y() / 5000)));
|
|
||||||
|
|
||||||
m_scaleFactor.setX(offset.x() * m_scaleFactor.x());
|
|
||||||
m_scaleFactor.setY(offset.y() * m_scaleFactor.y());
|
|
||||||
|
|
||||||
if (m_pointsMode)
|
|
||||||
{
|
|
||||||
Q_FOREACH(QGraphicsItem *item, m_selectedPoints)
|
|
||||||
{
|
|
||||||
qgraphicsitem_cast<WorldItemSubPoint *>(item)->scaleOn(m_pivot, offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
|
|
||||||
{
|
|
||||||
qgraphicsitem_cast<AbstractWorldItem *>(item)->scaleOn(m_pivot, offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case WorldEditorScene::TurnMode:
|
case WorldEditorScene::TurnMode:
|
||||||
{
|
updateWorldItemsTurn(mouseEvent);
|
||||||
// Caluculate angle between two line
|
|
||||||
QLineF firstLine(m_pivot, mouseEvent->lastScenePos());
|
|
||||||
QLineF secondLine(m_pivot, mouseEvent->scenePos());
|
|
||||||
qreal angle = secondLine.angleTo(firstLine);
|
|
||||||
|
|
||||||
m_angle += angle;
|
|
||||||
|
|
||||||
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
|
|
||||||
{
|
|
||||||
qgraphicsitem_cast<AbstractWorldItem *>(item)->turnOn(angle);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case WorldEditorScene::RadiusMode:
|
case WorldEditorScene::RadiusMode:
|
||||||
|
updateWorldItemsRadius(mouseEvent);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (m_pointsMode)
|
if (isEnabledEditPoints())
|
||||||
{
|
{
|
||||||
if ((editMode() != WorldEditorScene::SelectMode) && (!m_selectedPoints.isEmpty()))
|
if ((editMode() != WorldEditorScene::SelectMode) && (!m_selectedPoints.isEmpty()))
|
||||||
m_editedSelectedItems = true;
|
m_editedSelectedItems = true;
|
||||||
|
@ -358,7 +274,7 @@ void WorldEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
else
|
else
|
||||||
m_editedSelectedItems = false;
|
m_editedSelectedItems = false;
|
||||||
}
|
}
|
||||||
|
// Update render
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,10 +286,9 @@ void WorldEditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
if (mouseEvent->button() == Qt::MidButton)
|
if (mouseEvent->button() == Qt::MidButton)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_pointsMode)
|
|
||||||
{
|
|
||||||
if (mouseEvent->button() == Qt::LeftButton)
|
if (mouseEvent->button() == Qt::LeftButton)
|
||||||
{
|
{
|
||||||
|
// Update selection
|
||||||
if ((m_selectionArea.left() != 0) && (m_selectionArea.right() != 0))
|
if ((m_selectionArea.left() != 0) && (m_selectionArea.right() != 0))
|
||||||
{
|
{
|
||||||
QList<QGraphicsItem *> listItems;
|
QList<QGraphicsItem *> listItems;
|
||||||
|
@ -382,100 +297,52 @@ void WorldEditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
updateSelectedPointItems(false);
|
updateSelectedPointItems(false);
|
||||||
m_selectedPoints.clear();
|
m_selectedPoints.clear();
|
||||||
|
|
||||||
|
// Return list of selected items
|
||||||
if (m_selectionArea.left() < m_selectionArea.right())
|
if (m_selectionArea.left() < m_selectionArea.right())
|
||||||
listItems = items(m_selectionArea, Qt::IntersectsItemShape, Qt::AscendingOrder);
|
listItems = items(m_selectionArea, Qt::IntersectsItemShape, Qt::AscendingOrder);
|
||||||
else
|
else
|
||||||
listItems = items(m_selectionArea, Qt::ContainsItemShape, Qt::AscendingOrder);
|
listItems = items(m_selectionArea, Qt::ContainsItemShape, Qt::AscendingOrder);
|
||||||
|
|
||||||
|
if (isEnabledEditPoints())
|
||||||
|
{
|
||||||
Q_FOREACH(QGraphicsItem *item, listItems)
|
Q_FOREACH(QGraphicsItem *item, listItems)
|
||||||
{
|
{
|
||||||
if (qgraphicsitem_cast<WorldItemSubPoint *>(item) == 0)
|
if (qgraphicsitem_cast<WorldItemSubPoint *>(item) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_selectedPoints.push_back(item);
|
m_selectedPoints.push_back(item);
|
||||||
}
|
}
|
||||||
updateSelectedPointItems(true);
|
updateSelectedPointItems(true);
|
||||||
m_selectionArea = QRectF();
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((!m_editedSelectedItems) && (!m_firstSelection))
|
|
||||||
updatePickSelectionPoints(mouseEvent->scenePos());
|
|
||||||
else
|
|
||||||
m_firstSelection = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkUndo();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (mouseEvent->button() != Qt::LeftButton)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_editedSelectedItems)
|
|
||||||
{
|
|
||||||
switch (m_mode)
|
|
||||||
{
|
|
||||||
case WorldEditorScene::SelectMode:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WorldEditorScene::MoveMode:
|
|
||||||
{
|
|
||||||
QPointF offset = mouseEvent->scenePos() - m_firstPick;
|
|
||||||
m_undoStack->push(new MoveWorldItemsCommand(m_selectedItems, offset, this, m_model));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WorldEditorScene::RotateMode:
|
|
||||||
m_undoStack->push(new RotateWorldItemsCommand(m_selectedItems, m_angle, m_pivot, this, m_model));
|
|
||||||
break;
|
|
||||||
case WorldEditorScene::ScaleMode:
|
|
||||||
m_undoStack->push(new ScaleWorldItemsCommand(m_selectedItems, m_scaleFactor, m_pivot, this, m_model));
|
|
||||||
break;
|
|
||||||
case WorldEditorScene::TurnMode:
|
|
||||||
m_undoStack->push(new TurnWorldItemsCommand(m_selectedItems, m_angle, this, m_model));
|
|
||||||
break;
|
|
||||||
case WorldEditorScene::RadiusMode:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m_selectionArea.left() != 0) && (m_selectionArea.right() != 0))
|
|
||||||
{
|
|
||||||
QList<QGraphicsItem *> listItems;
|
|
||||||
|
|
||||||
// Clear selection
|
|
||||||
updateSelectedWorldItems(false);
|
|
||||||
m_selectedItems.clear();
|
|
||||||
|
|
||||||
if (m_selectionArea.left() < m_selectionArea.right())
|
|
||||||
listItems = items(m_selectionArea, Qt::IntersectsItemShape, Qt::AscendingOrder);
|
|
||||||
else
|
|
||||||
listItems = items(m_selectionArea, Qt::ContainsItemShape, Qt::AscendingOrder);
|
|
||||||
|
|
||||||
Q_FOREACH(QGraphicsItem *item, listItems)
|
Q_FOREACH(QGraphicsItem *item, listItems)
|
||||||
{
|
{
|
||||||
if (qgraphicsitem_cast<AbstractWorldItem *>(item) == 0)
|
if (qgraphicsitem_cast<AbstractWorldItem *>(item) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_selectedItems.push_back(item);
|
m_selectedItems.push_back(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_EMIT updateSelectedItems(m_selectedItems);
|
Q_EMIT updateSelectedItems(m_selectedItems);
|
||||||
|
|
||||||
updateSelectedWorldItems(true);
|
updateSelectedWorldItems(true);
|
||||||
|
}
|
||||||
m_selectionArea = QRectF();
|
m_selectionArea = QRectF();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((!m_editedSelectedItems) && (!m_firstSelection))
|
if ((!m_editedSelectedItems) && (!m_firstSelection))
|
||||||
|
{
|
||||||
|
if (isEnabledEditPoints())
|
||||||
|
updatePickSelectionPoints(mouseEvent->scenePos());
|
||||||
|
else
|
||||||
updatePickSelection(mouseEvent->scenePos());
|
updatePickSelection(mouseEvent->scenePos());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
m_firstSelection = false;
|
m_firstSelection = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if (isEnabledEditPoints())
|
||||||
|
checkUndoPointsMode();
|
||||||
|
}
|
||||||
m_selectionArea = QRectF();
|
m_selectionArea = QRectF();
|
||||||
LandscapeEditor::LandscapeSceneBase::mouseReleaseEvent(mouseEvent);
|
LandscapeEditor::LandscapeSceneBase::mouseReleaseEvent(mouseEvent);
|
||||||
}
|
}
|
||||||
|
@ -596,6 +463,32 @@ void WorldEditorScene::updatePickSelectionPoints(const QPointF &point)
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldEditorScene::checkUndo()
|
void WorldEditorScene::checkUndo()
|
||||||
|
{
|
||||||
|
if (m_editedSelectedItems)
|
||||||
|
{
|
||||||
|
switch (m_mode)
|
||||||
|
{
|
||||||
|
case WorldEditorScene::SelectMode:
|
||||||
|
break;
|
||||||
|
case WorldEditorScene::MoveMode:
|
||||||
|
m_undoStack->push(new MoveWorldItemsCommand(m_selectedItems, m_offset, this, m_model));
|
||||||
|
break;
|
||||||
|
case WorldEditorScene::RotateMode:
|
||||||
|
m_undoStack->push(new RotateWorldItemsCommand(m_selectedItems, m_angle, m_pivot, this, m_model));
|
||||||
|
break;
|
||||||
|
case WorldEditorScene::ScaleMode:
|
||||||
|
m_undoStack->push(new ScaleWorldItemsCommand(m_selectedItems, m_scaleFactor, m_pivot, this, m_model));
|
||||||
|
break;
|
||||||
|
case WorldEditorScene::TurnMode:
|
||||||
|
m_undoStack->push(new TurnWorldItemsCommand(m_selectedItems, m_angle, this, m_model));
|
||||||
|
break;
|
||||||
|
case WorldEditorScene::RadiusMode:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldEditorScene::checkUndoPointsMode()
|
||||||
{
|
{
|
||||||
if (m_pointsMode)
|
if (m_pointsMode)
|
||||||
{
|
{
|
||||||
|
@ -611,7 +504,6 @@ void WorldEditorScene::checkUndo()
|
||||||
worldItem->setShapeChanged(false);
|
worldItem->setShapeChanged(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!items.isEmpty())
|
if (!items.isEmpty())
|
||||||
{
|
{
|
||||||
m_undoStack->push(new ShapeWorldItemsCommand(items, polygons, this, m_model));
|
m_undoStack->push(new ShapeWorldItemsCommand(items, polygons, this, m_model));
|
||||||
|
@ -620,4 +512,89 @@ void WorldEditorScene::checkUndo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldEditorScene::updateWorldItemsMove(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
|
{
|
||||||
|
QPointF offset(mouseEvent->scenePos() - mouseEvent->lastScenePos());
|
||||||
|
if (m_pointsMode)
|
||||||
|
Q_FOREACH(QGraphicsItem *item, m_selectedPoints)
|
||||||
|
{
|
||||||
|
item->moveBy(offset.x(), offset.y());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
|
||||||
|
{
|
||||||
|
item->moveBy(offset.x(), offset.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldEditorScene::updateWorldItemsScale(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
|
{
|
||||||
|
QPointF offset(mouseEvent->scenePos() - mouseEvent->lastScenePos());
|
||||||
|
|
||||||
|
qreal scaleRatio = 5000;
|
||||||
|
|
||||||
|
// Calculate scale factor
|
||||||
|
if (offset.x() > 0)
|
||||||
|
offset.setX(1.0 + (offset.x() / scaleRatio));
|
||||||
|
else
|
||||||
|
offset.setX(1.0 / (1.0 + (-offset.x() / scaleRatio)));
|
||||||
|
|
||||||
|
if (offset.y() < 0)
|
||||||
|
offset.setY(1.0 - (offset.y() / scaleRatio));
|
||||||
|
else
|
||||||
|
offset.setY(1.0 / (1.0 + (offset.y() / scaleRatio)));
|
||||||
|
|
||||||
|
m_scaleFactor.setX(offset.x() * m_scaleFactor.x());
|
||||||
|
m_scaleFactor.setY(offset.y() * m_scaleFactor.y());
|
||||||
|
|
||||||
|
if (m_pointsMode)
|
||||||
|
Q_FOREACH(QGraphicsItem *item, m_selectedPoints)
|
||||||
|
{
|
||||||
|
qgraphicsitem_cast<WorldItemSubPoint *>(item)->scaleOn(m_pivot, offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
|
||||||
|
{
|
||||||
|
qgraphicsitem_cast<AbstractWorldItem *>(item)->scaleOn(m_pivot, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldEditorScene::updateWorldItemsRotate(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
|
{
|
||||||
|
// Caluculate angle between two line
|
||||||
|
QLineF firstLine(m_pivot, mouseEvent->lastScenePos());
|
||||||
|
QLineF secondLine(m_pivot, mouseEvent->scenePos());
|
||||||
|
qreal angle = secondLine.angleTo(firstLine);
|
||||||
|
m_angle += angle;
|
||||||
|
|
||||||
|
if (m_pointsMode)
|
||||||
|
Q_FOREACH(QGraphicsItem *item, m_selectedPoints)
|
||||||
|
{
|
||||||
|
qgraphicsitem_cast<WorldItemSubPoint *>(item)->rotateOn(m_pivot, angle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
|
||||||
|
{
|
||||||
|
qgraphicsitem_cast<AbstractWorldItem *>(item)->rotateOn(m_pivot, angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldEditorScene::updateWorldItemsTurn(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
|
{
|
||||||
|
// Caluculate angle between two line
|
||||||
|
QLineF firstLine(m_pivot, mouseEvent->lastScenePos());
|
||||||
|
QLineF secondLine(m_pivot, mouseEvent->scenePos());
|
||||||
|
qreal angle = secondLine.angleTo(firstLine);
|
||||||
|
m_angle += angle;
|
||||||
|
|
||||||
|
Q_FOREACH(QGraphicsItem *item, m_selectedItems)
|
||||||
|
{
|
||||||
|
qgraphicsitem_cast<AbstractWorldItem *>(item)->turnOn(angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldEditorScene::updateWorldItemsRadius(QGraphicsSceneMouseEvent *mouseEvent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace WorldEditor */
|
} /* namespace WorldEditor */
|
||||||
|
|
|
@ -105,20 +105,30 @@ private:
|
||||||
void updateSelectedWorldItem(QGraphicsItem *item, bool value);
|
void updateSelectedWorldItem(QGraphicsItem *item, bool value);
|
||||||
void updateSelectedPointItems(bool value);
|
void updateSelectedPointItems(bool value);
|
||||||
void updateSelectedPointItem(QGraphicsItem *item, bool value);
|
void updateSelectedPointItem(QGraphicsItem *item, bool value);
|
||||||
|
|
||||||
void updatePickSelection(const QPointF &point);
|
void updatePickSelection(const QPointF &point);
|
||||||
void updatePickSelectionPoints(const QPointF &point);
|
void updatePickSelectionPoints(const QPointF &point);
|
||||||
|
|
||||||
void checkUndo();
|
void checkUndo();
|
||||||
|
void checkUndoPointsMode();
|
||||||
|
|
||||||
|
void updateWorldItemsMove(QGraphicsSceneMouseEvent *mouseEvent);
|
||||||
|
void updateWorldItemsScale(QGraphicsSceneMouseEvent *mouseEvent);
|
||||||
|
void updateWorldItemsRotate(QGraphicsSceneMouseEvent *mouseEvent);
|
||||||
|
void updateWorldItemsTurn(QGraphicsSceneMouseEvent *mouseEvent);
|
||||||
|
void updateWorldItemsRadius(QGraphicsSceneMouseEvent *mouseEvent);
|
||||||
|
|
||||||
QPen m_greenPen, m_purplePen;
|
QPen m_greenPen, m_purplePen;
|
||||||
QBrush m_greenBrush, m_purpleBrush;
|
QBrush m_greenBrush, m_purpleBrush;
|
||||||
|
|
||||||
QPointF m_firstPick, m_scaleFactor, m_pivot;
|
QPointF m_firstPick, m_scaleFactor, m_pivot, m_offset;
|
||||||
QRectF m_selectionArea;
|
QRectF m_selectionArea;
|
||||||
qreal m_firstPickX, m_firstPickY, m_angle;
|
qreal m_firstPickX, m_firstPickY, m_angle;
|
||||||
|
|
||||||
QList<QGraphicsItem *> m_selectedItems;
|
QList<QGraphicsItem *> m_selectedItems;
|
||||||
QList<QGraphicsItem *> m_selectedPoints;
|
QList<QGraphicsItem *> m_selectedPoints;
|
||||||
QList<QPolygonF> m_polygons;
|
QList<QPolygonF> m_polygons;
|
||||||
|
|
||||||
bool m_editedSelectedItems, m_firstSelection;
|
bool m_editedSelectedItems, m_firstSelection;
|
||||||
uint m_lastPickedPrimitive;
|
uint m_lastPickedPrimitive;
|
||||||
ModeEdit m_mode;
|
ModeEdit m_mode;
|
||||||
|
|
|
@ -180,6 +180,8 @@ void WorldItemPoint::radiusOn(const qreal radius)
|
||||||
{
|
{
|
||||||
if (m_radius == 0)
|
if (m_radius == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldItemPoint::setColor(const QColor &color)
|
void WorldItemPoint::setColor(const QColor &color)
|
||||||
|
@ -240,9 +242,6 @@ QRectF WorldItemPoint::boundingRect() const
|
||||||
|
|
||||||
void WorldItemPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
|
void WorldItemPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
|
||||||
{
|
{
|
||||||
// Here comes the magic:
|
|
||||||
//painter->setClipRect(option->exposedRect);
|
|
||||||
|
|
||||||
painter->setPen(m_pen);
|
painter->setPen(m_pen);
|
||||||
|
|
||||||
// Draw circle
|
// Draw circle
|
||||||
|
@ -256,353 +255,59 @@ void WorldItemPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *op
|
||||||
painter->drawLines(m_arrow);
|
painter->drawLines(m_arrow);
|
||||||
|
|
||||||
painter->setPen(Qt::NoPen);
|
painter->setPen(Qt::NoPen);
|
||||||
// if (option->state & QStyle::State_Selected)
|
|
||||||
if (isActived())
|
if (isActived())
|
||||||
{
|
|
||||||
painter->setBrush(m_selectedBrush);
|
painter->setBrush(m_selectedBrush);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
painter->setBrush(m_brush);
|
painter->setBrush(m_brush);
|
||||||
}
|
|
||||||
|
|
||||||
// Draw point
|
// Draw point
|
||||||
painter->drawRect(m_rect);
|
painter->drawRect(m_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldItemPath::WorldItemPath(const QPolygonF &polygon, QGraphicsItem *parent)
|
BaseWorldItemPolyline::BaseWorldItemPolyline(const QPolygonF &polygon, QGraphicsItem *parent)
|
||||||
: AbstractWorldItem(parent),
|
: AbstractWorldItem(parent),
|
||||||
m_polygon(polygon),
|
m_polyline(polygon),
|
||||||
m_pointEdit(false)
|
m_pointEdit(false)
|
||||||
{
|
{
|
||||||
//setFlag(ItemIsSelectable);
|
//setFlag(ItemIsSelectable);
|
||||||
|
QPointF center = m_polyline.boundingRect().center();
|
||||||
setZValue(WORLD_PATH_LAYER);
|
m_polyline.translate(-center);
|
||||||
|
|
||||||
m_pen.setColor(Qt::black);
|
|
||||||
m_pen.setWidth(3);
|
|
||||||
m_pen.setJoinStyle(Qt::MiterJoin);
|
|
||||||
|
|
||||||
m_selectedPen.setColor(Qt::white);
|
|
||||||
m_selectedPen.setWidth(3);
|
|
||||||
m_selectedPen.setJoinStyle(Qt::MiterJoin);
|
|
||||||
|
|
||||||
QPointF center = m_polygon.boundingRect().center();
|
|
||||||
m_polygon.translate(-center);
|
|
||||||
setPos(center);
|
setPos(center);
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldItemPath::~WorldItemPath()
|
BaseWorldItemPolyline::~BaseWorldItemPolyline()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldItemPath::rotateOn(const QPointF &pivot, const qreal deltaAngle)
|
void BaseWorldItemPolyline::rotateOn(const QPointF &pivot, const qreal deltaAngle)
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
||||||
QPolygonF rotatedPolygon(m_polygon);
|
QPolygonF rotatedPolygon(m_polyline);
|
||||||
rotatedPolygon.translate(pos() - pivot);
|
rotatedPolygon.translate(pos() - pivot);
|
||||||
|
|
||||||
QTransform trans;
|
QTransform trans;
|
||||||
trans = trans.rotate(deltaAngle);
|
trans = trans.rotate(deltaAngle);
|
||||||
m_polygon = trans.map(rotatedPolygon);
|
m_polyline = trans.map(rotatedPolygon);
|
||||||
|
|
||||||
m_polygon.translate(pivot - pos());
|
m_polyline.translate(pivot - pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldItemPath::scaleOn(const QPointF &pivot, const QPointF &factor)
|
void BaseWorldItemPolyline::scaleOn(const QPointF &pivot, const QPointF &factor)
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
||||||
QPolygonF scaledPolygon(m_polygon);
|
QPolygonF scaledPolygon(m_polyline);
|
||||||
scaledPolygon.translate(pos() - pivot);
|
scaledPolygon.translate(pos() - pivot);
|
||||||
|
|
||||||
QTransform trans;
|
QTransform trans;
|
||||||
trans = trans.scale(factor.x(), factor.y());
|
trans = trans.scale(factor.x(), factor.y());
|
||||||
m_polygon = trans.map(scaledPolygon);
|
m_polyline = trans.map(scaledPolygon);
|
||||||
|
|
||||||
m_polygon.translate(pivot - pos());
|
m_polyline.translate(pivot - pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldItemPath::setColor(const QColor &color)
|
void BaseWorldItemPolyline::setEnabledSubPoints(bool enabled)
|
||||||
{
|
|
||||||
m_pen.setColor(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void WorldItemPath::setEnabledSubPoints(bool enabled)
|
|
||||||
{
|
|
||||||
m_pointEdit = enabled;
|
|
||||||
if (m_pointEdit)
|
|
||||||
createSubPoints();
|
|
||||||
else
|
|
||||||
removeSubPoints();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemPath::moveSubPoint(WorldItemSubPoint *subPoint)
|
|
||||||
{
|
|
||||||
prepareGeometryChange();
|
|
||||||
|
|
||||||
QPolygonF polygon;
|
|
||||||
|
|
||||||
// Update polygon
|
|
||||||
Q_FOREACH(WorldItemSubPoint *node, m_listItems)
|
|
||||||
{
|
|
||||||
polygon << node->pos();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update middle points
|
|
||||||
for (int i = 0; i < m_listLines.size(); ++i)
|
|
||||||
m_listLines.at(i).itemPoint->setPos((m_listLines.at(i).lineItem.first->pos() + m_listLines.at(i).lineItem.second->pos()) / 2);
|
|
||||||
|
|
||||||
m_polygon = polygon;
|
|
||||||
setShapeChanged(true);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemPath::addSubPoint(WorldItemSubPoint *subPoint)
|
|
||||||
{
|
|
||||||
prepareGeometryChange();
|
|
||||||
|
|
||||||
for (int i = 0; i < m_listLines.size(); ++i)
|
|
||||||
{
|
|
||||||
if (subPoint == m_listLines.at(i).itemPoint)
|
|
||||||
{
|
|
||||||
LineStruct oldLineItem = m_listLines[i];
|
|
||||||
|
|
||||||
// Create the first middle sub-point
|
|
||||||
WorldItemSubPoint *firstItem = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this);
|
|
||||||
firstItem->setPos((oldLineItem.lineItem.first->pos() + subPoint->pos()) / 2);
|
|
||||||
|
|
||||||
// Create the second middle sub-point
|
|
||||||
WorldItemSubPoint *secondItem = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this);
|
|
||||||
secondItem->setPos((oldLineItem.lineItem.second->pos() + subPoint->pos()) / 2);
|
|
||||||
|
|
||||||
// Add first line in the list
|
|
||||||
LineStruct firstNewLineItem;
|
|
||||||
firstNewLineItem.itemPoint = firstItem;
|
|
||||||
firstNewLineItem.lineItem = LineItem(oldLineItem.lineItem.first, subPoint);
|
|
||||||
m_listLines.push_back(firstNewLineItem);
|
|
||||||
|
|
||||||
// Add second line in the list
|
|
||||||
LineStruct secondNewLineItem;
|
|
||||||
secondNewLineItem.itemPoint = secondItem;
|
|
||||||
secondNewLineItem.lineItem = LineItem(subPoint, oldLineItem.lineItem.second);
|
|
||||||
m_listLines.push_back(secondNewLineItem);
|
|
||||||
|
|
||||||
m_listLines.removeAt(i);
|
|
||||||
|
|
||||||
int pos = m_listItems.indexOf(oldLineItem.lineItem.second);
|
|
||||||
m_listItems.insert(pos, subPoint);
|
|
||||||
subPoint->setFlag(ItemSendsScenePositionChanges);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setShapeChanged(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WorldItemPath::removeSubPoint(WorldItemSubPoint *subPoint)
|
|
||||||
{
|
|
||||||
int pos = m_listItems.indexOf(subPoint);
|
|
||||||
|
|
||||||
// First and second points can not be removed
|
|
||||||
if ((pos == 0) || (pos == m_listItems.size() - 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
prepareGeometryChange();
|
|
||||||
|
|
||||||
m_listItems.takeAt(pos);
|
|
||||||
|
|
||||||
LineStruct newLineItem;
|
|
||||||
|
|
||||||
newLineItem.itemPoint = subPoint;
|
|
||||||
|
|
||||||
// Delete first line
|
|
||||||
for (int i = 0; i < m_listLines.size(); ++i)
|
|
||||||
{
|
|
||||||
if (subPoint == m_listLines.at(i).lineItem.first)
|
|
||||||
{
|
|
||||||
// Saving second point for new line
|
|
||||||
newLineItem.lineItem.second = m_listLines.at(i).lineItem.second;
|
|
||||||
delete m_listLines.at(i).itemPoint;
|
|
||||||
m_listLines.removeAt(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete second line
|
|
||||||
for (int i = 0; i < m_listLines.size(); ++i)
|
|
||||||
{
|
|
||||||
if (subPoint == m_listLines.at(i).lineItem.second)
|
|
||||||
{
|
|
||||||
// Saving first point for new line
|
|
||||||
newLineItem.lineItem.first = m_listLines.at(i).lineItem.first;
|
|
||||||
delete m_listLines.at(i).itemPoint;
|
|
||||||
m_listLines.removeAt(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subPoint->setPos((newLineItem.lineItem.first->pos() + newLineItem.lineItem.second->pos()) / 2);
|
|
||||||
m_listLines.push_back(newLineItem);
|
|
||||||
subPoint->setFlag(ItemSendsScenePositionChanges, false);
|
|
||||||
setShapeChanged(true);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemPath::setPolygon(const QPolygonF &polygon)
|
|
||||||
{
|
|
||||||
prepareGeometryChange();
|
|
||||||
|
|
||||||
m_polygon = polygon;
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
QPolygonF WorldItemPath::polygon() const
|
|
||||||
{
|
|
||||||
return m_polygon;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPainterPath WorldItemPath::shape() const
|
|
||||||
{
|
|
||||||
QPainterPath path;
|
|
||||||
|
|
||||||
path.moveTo(m_polygon.first());
|
|
||||||
for (int i = 1; i < m_polygon.count(); ++i)
|
|
||||||
path.lineTo(m_polygon.at(i));
|
|
||||||
|
|
||||||
return qt_graphicsItem_shapeFromPath(path, m_pen);
|
|
||||||
}
|
|
||||||
|
|
||||||
QRectF WorldItemPath::boundingRect() const
|
|
||||||
{
|
|
||||||
return m_polygon.boundingRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemPath::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
|
|
||||||
{
|
|
||||||
// Here comes the magic:
|
|
||||||
//painter->setClipRect(option->exposedRect);
|
|
||||||
|
|
||||||
//if (option->state & QStyle::State_Selected)
|
|
||||||
if (isActived())
|
|
||||||
painter->setPen(m_selectedPen);
|
|
||||||
else
|
|
||||||
painter->setPen(m_pen);
|
|
||||||
|
|
||||||
painter->drawPolyline(m_polygon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemPath::createSubPoints()
|
|
||||||
{
|
|
||||||
WorldItemSubPoint *firstPoint;
|
|
||||||
firstPoint = new WorldItemSubPoint(WorldItemSubPoint::EdgeType, this);
|
|
||||||
firstPoint->setPos(m_polygon.front());
|
|
||||||
firstPoint->setFlag(ItemSendsScenePositionChanges);
|
|
||||||
m_listItems.push_back(firstPoint);
|
|
||||||
|
|
||||||
for (int i = 1; i < m_polygon.count(); ++i)
|
|
||||||
{
|
|
||||||
WorldItemSubPoint *secondPoint = new WorldItemSubPoint(WorldItemSubPoint::EdgeType, this);
|
|
||||||
secondPoint->setPos(m_polygon.at(i));
|
|
||||||
secondPoint->setFlag(ItemSendsScenePositionChanges);
|
|
||||||
|
|
||||||
WorldItemSubPoint *middlePoint = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this);
|
|
||||||
middlePoint->setPos((firstPoint->pos() + secondPoint->pos()) / 2);
|
|
||||||
|
|
||||||
LineStruct newLineItem;
|
|
||||||
newLineItem.itemPoint = middlePoint;
|
|
||||||
newLineItem.lineItem = LineItem(firstPoint, secondPoint);
|
|
||||||
m_listLines.push_back(newLineItem);
|
|
||||||
|
|
||||||
firstPoint = secondPoint;
|
|
||||||
m_listItems.push_back(firstPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemPath::removeSubPoints()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < m_listLines.count(); ++i)
|
|
||||||
delete m_listLines.at(i).itemPoint;
|
|
||||||
|
|
||||||
for (int i = 0; i < m_listItems.count(); ++i)
|
|
||||||
delete m_listItems.at(i);
|
|
||||||
|
|
||||||
m_listItems.clear();
|
|
||||||
m_listLines.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
WorldItemZone::WorldItemZone(const QPolygonF &polygon, QGraphicsItem *parent)
|
|
||||||
: AbstractWorldItem(parent),
|
|
||||||
m_polygon(polygon),
|
|
||||||
m_pointEdit(false)
|
|
||||||
{
|
|
||||||
//setFlag(ItemIsSelectable);
|
|
||||||
|
|
||||||
setZValue(WORLD_ZONE_LAYER);
|
|
||||||
|
|
||||||
m_pen.setColor(QColor(20, 100, 255));
|
|
||||||
m_pen.setWidth(0);
|
|
||||||
|
|
||||||
m_selectedPen.setColor(Qt::white);
|
|
||||||
m_selectedPen.setWidth(0);
|
|
||||||
|
|
||||||
m_brush.setColor(QColor(20, 100, 255, TRANSPARENCY));
|
|
||||||
m_brush.setStyle(Qt::SolidPattern);
|
|
||||||
|
|
||||||
m_selectedBrush.setColor(QColor(255, 255, 255, 100));
|
|
||||||
m_selectedBrush.setStyle(Qt::SolidPattern);
|
|
||||||
|
|
||||||
QPointF center = m_polygon.boundingRect().center();
|
|
||||||
m_polygon.translate(-center);
|
|
||||||
setPos(center);
|
|
||||||
}
|
|
||||||
|
|
||||||
WorldItemZone::~WorldItemZone()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemZone::rotateOn(const QPointF &pivot, const qreal deltaAngle)
|
|
||||||
{
|
|
||||||
prepareGeometryChange();
|
|
||||||
|
|
||||||
QPolygonF rotatedPolygon(m_polygon);
|
|
||||||
rotatedPolygon.translate(pos() - pivot);
|
|
||||||
|
|
||||||
QTransform trans;
|
|
||||||
trans = trans.rotate(deltaAngle);
|
|
||||||
m_polygon = trans.map(rotatedPolygon);
|
|
||||||
|
|
||||||
m_polygon.translate(pivot - pos());
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemZone::scaleOn(const QPointF &pivot, const QPointF &factor)
|
|
||||||
{
|
|
||||||
prepareGeometryChange();
|
|
||||||
|
|
||||||
QPolygonF scaledPolygon(m_polygon);
|
|
||||||
scaledPolygon.translate(pos() - pivot);
|
|
||||||
|
|
||||||
QTransform trans;
|
|
||||||
trans = trans.scale(factor.x(), factor.y());
|
|
||||||
m_polygon = trans.map(scaledPolygon);
|
|
||||||
|
|
||||||
m_polygon.translate(pivot - pos());
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemZone::setColor(const QColor &color)
|
|
||||||
{
|
|
||||||
m_pen.setColor(color);
|
|
||||||
|
|
||||||
QColor brushColor(color);
|
|
||||||
brushColor.setAlpha(TRANSPARENCY);
|
|
||||||
|
|
||||||
m_brush.setColor(brushColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemZone::setEnabledSubPoints(bool enabled)
|
|
||||||
{
|
{
|
||||||
m_pointEdit = enabled;
|
m_pointEdit = enabled;
|
||||||
if (m_pointEdit)
|
if (m_pointEdit)
|
||||||
|
@ -613,7 +318,7 @@ void WorldItemZone::setEnabledSubPoints(bool enabled)
|
||||||
setShapeChanged(false);
|
setShapeChanged(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldItemZone::moveSubPoint(WorldItemSubPoint *subPoint)
|
void BaseWorldItemPolyline::moveSubPoint(WorldItemSubPoint *subPoint)
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
||||||
|
@ -629,13 +334,12 @@ void WorldItemZone::moveSubPoint(WorldItemSubPoint *subPoint)
|
||||||
for (int i = 0; i < m_listLines.size(); ++i)
|
for (int i = 0; i < m_listLines.size(); ++i)
|
||||||
m_listLines.at(i).itemPoint->setPos((m_listLines.at(i).lineItem.first->pos() + m_listLines.at(i).lineItem.second->pos()) / 2);
|
m_listLines.at(i).itemPoint->setPos((m_listLines.at(i).lineItem.first->pos() + m_listLines.at(i).lineItem.second->pos()) / 2);
|
||||||
|
|
||||||
m_polygon = polygon;
|
m_polyline = polygon;
|
||||||
update();
|
|
||||||
|
|
||||||
setShapeChanged(true);
|
setShapeChanged(true);
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldItemZone::addSubPoint(WorldItemSubPoint *subPoint)
|
void BaseWorldItemPolyline::addSubPoint(WorldItemSubPoint *subPoint)
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
||||||
|
@ -677,18 +381,13 @@ void WorldItemZone::addSubPoint(WorldItemSubPoint *subPoint)
|
||||||
setShapeChanged(true);
|
setShapeChanged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldItemZone::removeSubPoint(WorldItemSubPoint *subPoint)
|
bool BaseWorldItemPolyline::removeSubPoint(WorldItemSubPoint *subPoint)
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
||||||
if (m_listItems.size() < 4)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int pos = m_listItems.indexOf(subPoint);
|
int pos = m_listItems.indexOf(subPoint);
|
||||||
m_listItems.takeAt(pos);
|
m_listItems.takeAt(pos);
|
||||||
|
|
||||||
LineStruct newLineItem;
|
LineStruct newLineItem;
|
||||||
|
|
||||||
newLineItem.itemPoint = subPoint;
|
newLineItem.itemPoint = subPoint;
|
||||||
|
|
||||||
// Delete first line
|
// Delete first line
|
||||||
|
@ -716,70 +415,42 @@ bool WorldItemZone::removeSubPoint(WorldItemSubPoint *subPoint)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_listLines.push_back(newLineItem);
|
|
||||||
subPoint->setPos((newLineItem.lineItem.first->pos() + newLineItem.lineItem.second->pos()) / 2);
|
subPoint->setPos((newLineItem.lineItem.first->pos() + newLineItem.lineItem.second->pos()) / 2);
|
||||||
|
m_listLines.push_back(newLineItem);
|
||||||
subPoint->setFlag(ItemSendsScenePositionChanges, false);
|
subPoint->setFlag(ItemSendsScenePositionChanges, false);
|
||||||
|
|
||||||
setShapeChanged(true);
|
setShapeChanged(true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldItemZone::setPolygon(const QPolygonF &polygon)
|
void BaseWorldItemPolyline::setPolygon(const QPolygonF &polygon)
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
m_polyline = polygon;
|
||||||
m_polygon = polygon;
|
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPolygonF WorldItemZone::polygon() const
|
QPolygonF BaseWorldItemPolyline::polygon() const
|
||||||
{
|
{
|
||||||
return m_polygon;
|
return m_polyline;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF WorldItemZone::boundingRect() const
|
QRectF BaseWorldItemPolyline::boundingRect() const
|
||||||
{
|
{
|
||||||
return m_polygon.boundingRect();
|
return m_polyline.boundingRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPainterPath WorldItemZone::shape() const
|
void BaseWorldItemPolyline::createSubPoints()
|
||||||
{
|
|
||||||
QPainterPath path;
|
|
||||||
path.addPolygon(m_polygon);
|
|
||||||
return qt_graphicsItem_shapeFromPath(path, m_pen);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
|
|
||||||
{
|
|
||||||
// if (option->state & QStyle::State_Selected)
|
|
||||||
if (isActived())
|
|
||||||
{
|
|
||||||
painter->setPen(m_selectedPen);
|
|
||||||
painter->setBrush(m_selectedBrush);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
painter->setPen(m_pen);
|
|
||||||
painter->setBrush(m_brush);
|
|
||||||
}
|
|
||||||
|
|
||||||
painter->drawPolygon(m_polygon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldItemZone::createSubPoints()
|
|
||||||
{
|
{
|
||||||
WorldItemSubPoint *firstPoint;
|
WorldItemSubPoint *firstPoint;
|
||||||
firstPoint = new WorldItemSubPoint(WorldItemSubPoint::EdgeType, this);
|
firstPoint = new WorldItemSubPoint(WorldItemSubPoint::EdgeType, this);
|
||||||
firstPoint->setPos(m_polygon.front());
|
firstPoint->setPos(m_polyline.front());
|
||||||
firstPoint->setFlag(ItemSendsScenePositionChanges);
|
firstPoint->setFlag(ItemSendsScenePositionChanges);
|
||||||
m_listItems.push_back(firstPoint);
|
m_listItems.push_back(firstPoint);
|
||||||
|
|
||||||
for (int i = 1; i < m_polygon.count(); ++i)
|
for (int i = 1; i < m_polyline.count(); ++i)
|
||||||
{
|
{
|
||||||
WorldItemSubPoint *secondPoint = new WorldItemSubPoint(WorldItemSubPoint::EdgeType, this);
|
WorldItemSubPoint *secondPoint = new WorldItemSubPoint(WorldItemSubPoint::EdgeType, this);
|
||||||
secondPoint->setPos(m_polygon.at(i));
|
secondPoint->setPos(m_polyline.at(i));
|
||||||
secondPoint->setFlag(ItemSendsScenePositionChanges);
|
secondPoint->setFlag(ItemSendsScenePositionChanges);
|
||||||
|
|
||||||
WorldItemSubPoint *middlePoint = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this);
|
WorldItemSubPoint *middlePoint = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this);
|
||||||
|
@ -793,15 +464,9 @@ void WorldItemZone::createSubPoints()
|
||||||
firstPoint = secondPoint;
|
firstPoint = secondPoint;
|
||||||
m_listItems.push_back(firstPoint);
|
m_listItems.push_back(firstPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
LineStruct endLineItem;
|
|
||||||
endLineItem.itemPoint = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this);
|
|
||||||
endLineItem.itemPoint->setPos((m_listItems.first()->pos() + m_listItems.last()->pos()) / 2);
|
|
||||||
endLineItem.lineItem = LineItem(m_listItems.last(), m_listItems.first());
|
|
||||||
m_listLines.push_back(endLineItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldItemZone::removeSubPoints()
|
void BaseWorldItemPolyline::removeSubPoints()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_listLines.count(); ++i)
|
for (int i = 0; i < m_listLines.count(); ++i)
|
||||||
delete m_listLines.at(i).itemPoint;
|
delete m_listLines.at(i).itemPoint;
|
||||||
|
@ -813,6 +478,131 @@ void WorldItemZone::removeSubPoints()
|
||||||
m_listLines.clear();
|
m_listLines.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WorldItemPath::WorldItemPath(const QPolygonF &polygon, QGraphicsItem *parent)
|
||||||
|
: BaseWorldItemPolyline(polygon, parent)
|
||||||
|
{
|
||||||
|
setZValue(WORLD_PATH_LAYER);
|
||||||
|
|
||||||
|
m_pen.setColor(Qt::black);
|
||||||
|
m_pen.setWidth(3);
|
||||||
|
m_pen.setJoinStyle(Qt::MiterJoin);
|
||||||
|
|
||||||
|
m_selectedPen.setColor(Qt::white);
|
||||||
|
m_selectedPen.setWidth(3);
|
||||||
|
m_selectedPen.setJoinStyle(Qt::MiterJoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldItemPath::~WorldItemPath()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldItemPath::setColor(const QColor &color)
|
||||||
|
{
|
||||||
|
m_pen.setColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldItemPath::removeSubPoint(WorldItemSubPoint *subPoint)
|
||||||
|
{
|
||||||
|
int pos = m_listItems.indexOf(subPoint);
|
||||||
|
|
||||||
|
// First and second points can not be removed
|
||||||
|
if ((pos == 0) || (pos == m_listItems.size() - 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return BaseWorldItemPolyline::removeSubPoint(subPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath WorldItemPath::shape() const
|
||||||
|
{
|
||||||
|
QPainterPath path;
|
||||||
|
|
||||||
|
path.moveTo(m_polyline.first());
|
||||||
|
for (int i = 1; i < m_polyline.count(); ++i)
|
||||||
|
path.lineTo(m_polyline.at(i));
|
||||||
|
|
||||||
|
return qt_graphicsItem_shapeFromPath(path, m_pen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldItemPath::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
|
||||||
|
{
|
||||||
|
if (isActived())
|
||||||
|
painter->setPen(m_selectedPen);
|
||||||
|
else
|
||||||
|
painter->setPen(m_pen);
|
||||||
|
|
||||||
|
painter->drawPolyline(m_polyline);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WorldItemZone::WorldItemZone(const QPolygonF &polygon, QGraphicsItem *parent)
|
||||||
|
: BaseWorldItemPolyline(polygon, parent)
|
||||||
|
{
|
||||||
|
setZValue(WORLD_ZONE_LAYER);
|
||||||
|
|
||||||
|
m_pen.setColor(QColor(20, 100, 255));
|
||||||
|
m_pen.setWidth(0);
|
||||||
|
m_selectedPen.setColor(Qt::white);
|
||||||
|
m_selectedPen.setWidth(0);
|
||||||
|
m_brush.setColor(QColor(20, 100, 255, TRANSPARENCY));
|
||||||
|
m_brush.setStyle(Qt::SolidPattern);
|
||||||
|
m_selectedBrush.setColor(QColor(255, 255, 255, 100));
|
||||||
|
m_selectedBrush.setStyle(Qt::SolidPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldItemZone::~WorldItemZone()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldItemZone::setColor(const QColor &color)
|
||||||
|
{
|
||||||
|
m_pen.setColor(color);
|
||||||
|
QColor brushColor(color);
|
||||||
|
brushColor.setAlpha(TRANSPARENCY);
|
||||||
|
m_brush.setColor(brushColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldItemZone::removeSubPoint(WorldItemSubPoint *subPoint)
|
||||||
|
{
|
||||||
|
if (m_listItems.size() < 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return BaseWorldItemPolyline::removeSubPoint(subPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath WorldItemZone::shape() const
|
||||||
|
{
|
||||||
|
QPainterPath path;
|
||||||
|
path.addPolygon(m_polyline);
|
||||||
|
return qt_graphicsItem_shapeFromPath(path, m_pen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldItemZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
|
||||||
|
{
|
||||||
|
if (isActived())
|
||||||
|
{
|
||||||
|
painter->setPen(m_selectedPen);
|
||||||
|
painter->setBrush(m_selectedBrush);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
painter->setPen(m_pen);
|
||||||
|
painter->setBrush(m_brush);
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->drawPolygon(m_polyline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldItemZone::createSubPoints()
|
||||||
|
{
|
||||||
|
BaseWorldItemPolyline::createSubPoints();
|
||||||
|
|
||||||
|
LineStruct endLineItem;
|
||||||
|
endLineItem.itemPoint = new WorldItemSubPoint(WorldItemSubPoint::MiddleType, this);
|
||||||
|
endLineItem.itemPoint->setPos((m_listItems.first()->pos() + m_listItems.last()->pos()) / 2);
|
||||||
|
endLineItem.lineItem = LineItem(m_listItems.last(), m_listItems.first());
|
||||||
|
m_listLines.push_back(endLineItem);
|
||||||
|
}
|
||||||
|
|
||||||
//*******************************************
|
//*******************************************
|
||||||
|
|
||||||
WorldItemSubPoint::WorldItemSubPoint(SubPointType pointType, AbstractWorldItem *parent)
|
WorldItemSubPoint::WorldItemSubPoint(SubPointType pointType, AbstractWorldItem *parent)
|
||||||
|
@ -859,8 +649,6 @@ void WorldItemSubPoint::rotateOn(const QPointF &pivot, const qreal deltaAngle)
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
||||||
QPolygonF rotatedPolygon(m_rect);
|
QPolygonF rotatedPolygon(m_rect);
|
||||||
|
|
||||||
// TODO
|
|
||||||
rotatedPolygon.translate(scenePos() - pivot);
|
rotatedPolygon.translate(scenePos() - pivot);
|
||||||
|
|
||||||
QTransform trans;
|
QTransform trans;
|
||||||
|
@ -876,8 +664,6 @@ void WorldItemSubPoint::scaleOn(const QPointF &pivot, const QPointF &factor)
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
||||||
QPolygonF scaledPolygon(m_rect);
|
QPolygonF scaledPolygon(m_rect);
|
||||||
|
|
||||||
// TODO
|
|
||||||
scaledPolygon.translate(scenePos() - pivot);
|
scaledPolygon.translate(scenePos() - pivot);
|
||||||
|
|
||||||
QTransform trans;
|
QTransform trans;
|
||||||
|
@ -896,7 +682,6 @@ QRectF WorldItemSubPoint::boundingRect() const
|
||||||
void WorldItemSubPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
void WorldItemSubPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||||
{
|
{
|
||||||
painter->setPen(Qt::NoPen);
|
painter->setPen(Qt::NoPen);
|
||||||
|
|
||||||
if (m_type == WorldItemSubPoint::EdgeType)
|
if (m_type == WorldItemSubPoint::EdgeType)
|
||||||
{
|
{
|
||||||
if (isActived())
|
if (isActived())
|
||||||
|
@ -905,9 +690,7 @@ void WorldItemSubPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem
|
||||||
painter->setBrush(m_brush);
|
painter->setBrush(m_brush);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
painter->setBrush(m_brushMiddle);
|
painter->setBrush(m_brushMiddle);
|
||||||
}
|
|
||||||
|
|
||||||
// Draw point
|
// Draw point
|
||||||
painter->drawRect(m_rect);
|
painter->drawRect(m_rect);
|
||||||
|
|
|
@ -66,21 +66,21 @@ public:
|
||||||
enum { Type = QGraphicsItem::UserType + 1 };
|
enum { Type = QGraphicsItem::UserType + 1 };
|
||||||
|
|
||||||
/// Rotate item around @pivot point on &deltaAngle (deg).
|
/// Rotate item around @pivot point on &deltaAngle (deg).
|
||||||
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle) {};
|
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle) {}
|
||||||
|
|
||||||
/// Scales item relatively @pivot point
|
/// Scales item relatively @pivot point
|
||||||
// TODO: add modes: IgnoreAspectRatio, KeepAspectRatio
|
// TODO: add modes: IgnoreAspectRatio, KeepAspectRatio
|
||||||
virtual void scaleOn(const QPointF &pivot, const QPointF &factor) {};
|
virtual void scaleOn(const QPointF &pivot, const QPointF &factor) {}
|
||||||
|
|
||||||
/// Rotate arrow on angle (deg). (only for WorldItemPoint)
|
/// Rotate arrow on angle (deg). (only for WorldItemPoint)
|
||||||
virtual void turnOn(const qreal angle) {};
|
virtual void turnOn(const qreal angle) {}
|
||||||
virtual void radiusOn(const qreal radius) {};
|
virtual void radiusOn(const qreal radius) {}
|
||||||
|
|
||||||
/// Change color
|
/// Change color
|
||||||
virtual void setColor(const QColor &color) = 0;
|
virtual void setColor(const QColor &color) {}
|
||||||
|
|
||||||
/// Enable/disable the mode edit shape (only for WorldItemPath and WorldItemPath)
|
/// Enable/disable the mode edit shape (only for WorldItemPath and WorldItemPath)
|
||||||
virtual void setEnabledSubPoints(bool enabled) = 0;
|
virtual void setEnabledSubPoints(bool enabled) {}
|
||||||
|
|
||||||
virtual void moveSubPoint(WorldItemSubPoint *subPoint) {}
|
virtual void moveSubPoint(WorldItemSubPoint *subPoint) {}
|
||||||
virtual void addSubPoint(WorldItemSubPoint *subPoint) {}
|
virtual void addSubPoint(WorldItemSubPoint *subPoint) {}
|
||||||
|
@ -156,22 +156,20 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@class WorldItemPath
|
@class BaseWorldItemPolyline
|
||||||
@brief WorldItemPath class provides a polyline item that you can add to a WorldEditorScene.
|
@brief
|
||||||
@details
|
@details
|
||||||
*/
|
*/
|
||||||
class WorldItemPath: public AbstractWorldItem
|
class BaseWorldItemPolyline: public AbstractWorldItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WorldItemPath(const QPolygonF &polygon, QGraphicsItem *parent = 0);
|
BaseWorldItemPolyline(const QPolygonF &polygon, QGraphicsItem *parent = 0);
|
||||||
virtual ~WorldItemPath();
|
virtual ~BaseWorldItemPolyline();
|
||||||
|
|
||||||
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle);
|
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle);
|
||||||
virtual void scaleOn(const QPointF &pivot, const QPointF &factor);
|
virtual void scaleOn(const QPointF &pivot, const QPointF &factor);
|
||||||
|
|
||||||
virtual void setColor(const QColor &color);
|
|
||||||
virtual void setEnabledSubPoints(bool enabled);
|
virtual void setEnabledSubPoints(bool enabled);
|
||||||
|
|
||||||
virtual void moveSubPoint(WorldItemSubPoint *subPoint);
|
virtual void moveSubPoint(WorldItemSubPoint *subPoint);
|
||||||
virtual void addSubPoint(WorldItemSubPoint *subPoint);
|
virtual void addSubPoint(WorldItemSubPoint *subPoint);
|
||||||
virtual bool removeSubPoint(WorldItemSubPoint *subPoint);
|
virtual bool removeSubPoint(WorldItemSubPoint *subPoint);
|
||||||
|
@ -180,19 +178,38 @@ public:
|
||||||
virtual QPolygonF polygon() const;
|
virtual QPolygonF polygon() const;
|
||||||
|
|
||||||
virtual QRectF boundingRect() const;
|
virtual QRectF boundingRect() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void createSubPoints();
|
||||||
|
virtual void removeSubPoints();
|
||||||
|
|
||||||
|
bool m_pointEdit;
|
||||||
|
QPolygonF m_polyline;
|
||||||
|
QPen m_pen, m_selectedPen;
|
||||||
|
|
||||||
|
QList<WorldItemSubPoint *> m_listItems;
|
||||||
|
QList<LineStruct> m_listLines;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
@class WorldItemPath
|
||||||
|
@brief WorldItemPath class provides a polyline item that you can add to a WorldEditorScene.
|
||||||
|
@details
|
||||||
|
*/
|
||||||
|
class WorldItemPath: public BaseWorldItemPolyline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WorldItemPath(const QPolygonF &polygon, QGraphicsItem *parent = 0);
|
||||||
|
virtual ~WorldItemPath();
|
||||||
|
|
||||||
|
virtual void setColor(const QColor &color);
|
||||||
|
virtual bool removeSubPoint(WorldItemSubPoint *subPoint);
|
||||||
virtual QPainterPath shape() const;
|
virtual QPainterPath shape() const;
|
||||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createSubPoints();
|
|
||||||
void removeSubPoints();
|
|
||||||
|
|
||||||
QPen m_pen, m_selectedPen;
|
QPen m_pen, m_selectedPen;
|
||||||
QPolygonF m_polygon;
|
|
||||||
bool m_pointEdit;
|
|
||||||
|
|
||||||
QList<WorldItemSubPoint *> m_listItems;
|
|
||||||
QList<LineStruct> m_listLines;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -200,42 +217,27 @@ private:
|
||||||
@brief The WorldItemZone class provides a polygon item that you can add to a WorldEditorScene.
|
@brief The WorldItemZone class provides a polygon item that you can add to a WorldEditorScene.
|
||||||
@details
|
@details
|
||||||
*/
|
*/
|
||||||
class WorldItemZone: public AbstractWorldItem
|
class WorldItemZone: public BaseWorldItemPolyline
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WorldItemZone(const QPolygonF &polygon, QGraphicsItem *parent = 0);
|
WorldItemZone(const QPolygonF &polygon, QGraphicsItem *parent = 0);
|
||||||
virtual ~WorldItemZone();
|
virtual ~WorldItemZone();
|
||||||
|
|
||||||
virtual void rotateOn(const QPointF &pivot, const qreal deltaAngle);
|
|
||||||
virtual void scaleOn(const QPointF &pivot, const QPointF &factor);
|
|
||||||
|
|
||||||
virtual void setColor(const QColor &color);
|
virtual void setColor(const QColor &color);
|
||||||
virtual void setEnabledSubPoints(bool enabled);
|
|
||||||
|
|
||||||
virtual void moveSubPoint(WorldItemSubPoint *subPoint);
|
|
||||||
virtual void addSubPoint(WorldItemSubPoint *subPoint);
|
|
||||||
virtual bool removeSubPoint(WorldItemSubPoint *subPoint);
|
virtual bool removeSubPoint(WorldItemSubPoint *subPoint);
|
||||||
|
|
||||||
virtual void setPolygon(const QPolygonF &polygon);
|
|
||||||
virtual QPolygonF polygon() const;
|
|
||||||
|
|
||||||
virtual QRectF boundingRect() const;
|
|
||||||
virtual QPainterPath shape() const;
|
virtual QPainterPath shape() const;
|
||||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void createSubPoints();
|
virtual void createSubPoints();
|
||||||
void removeSubPoints();
|
|
||||||
|
|
||||||
|
private:
|
||||||
static const int TRANSPARENCY = 38;
|
static const int TRANSPARENCY = 38;
|
||||||
|
|
||||||
QPen m_pen, m_selectedPen;
|
QPen m_pen, m_selectedPen;
|
||||||
QBrush m_brush, m_selectedBrush;
|
QBrush m_brush, m_selectedBrush;
|
||||||
QPolygonF m_polygon;
|
|
||||||
bool m_pointEdit;
|
|
||||||
|
|
||||||
QList<WorldItemSubPoint *> m_listItems;
|
|
||||||
QList<LineStruct> m_listLines;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue