/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech 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.
QElectroTech 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 QElectroTech. If not, see .
*/
#include "mirrorselectioncommand.h"
#include "../QPropertyUndoCommand/qpropertyundocommand.h"
#include "../diagram.h"
#include "../qetgraphicsitem/element.h"
/**
@brief MirrorSelectionCommand::MirrorSelectionCommand
Mirror the elements selected in @p diagram; the other selected items
are left as they are. See the other constructor.
@param diagram : the diagram whose selection is mirrored
@param orientation : Qt::Horizontal swaps left and right,
Qt::Vertical swaps top and bottom
@param parent : parent undo command
*/
MirrorSelectionCommand::MirrorSelectionCommand(Diagram *diagram,
Qt::Orientation orientation,
QUndoCommand *parent) :
MirrorSelectionCommand(selectedElements(diagram), orientation, parent)
{}
/**
@brief MirrorSelectionCommand::MirrorSelectionCommand
The mirrors of an element are about its own axes, before it is rotated
(Element::setMirror()). Turned by 0 or 180 degrees, the element's axes
are the folio's, so a horizontal mirror on the folio is the element's
own horizontal mirror; turned by 90 or 270 degrees, they are swapped,
so it is the element's vertical mirror. The rotation never changes.
Each element is mirrored in place: its centre stays where it was.
@param elements : the elements to mirror
@param orientation : Qt::Horizontal swaps left and right on the folio,
Qt::Vertical swaps top and bottom
@param parent : parent undo command
*/
MirrorSelectionCommand::MirrorSelectionCommand(const QList &elements,
Qt::Orientation orientation,
QUndoCommand *parent) :
QUndoCommand(parent)
{
setText(orientation == Qt::Horizontal
? QObject::tr("Miroir horizontal")
: QObject::tr("Miroir vertical"));
for (Element *element : elements)
{
if (!element)
continue;
const bool turned = element->orientation() % 2;
const bool horizontal = (orientation == Qt::Horizontal) != turned;
bool new_horizontal = element->hasHorizontalMirror();
bool new_vertical = element->hasVerticalMirror();
if (horizontal)
{
new_horizontal = !new_horizontal;
new QPropertyUndoCommand(element, "horizontalMirror",
!new_horizontal, new_horizontal, this);
}
else
{
new_vertical = !new_vertical;
new QPropertyUndoCommand(element, "verticalMirror",
!new_vertical, new_vertical, this);
}
//The mirror is about the element's hotspot, which is often a
//corner of the symbol: move it so that it stays where it was,
//centre on centre, and on the grid
QPointF centre = element->boundingRect().center();
centre = QTransform::fromScale(new_horizontal ? -1 : 1, new_vertical ? -1 : 1)
.map(centre);
centre = QTransform().rotate(element->rotation()).map(centre);
const QPointF old_pos = element->pos();
const QPointF new_pos = Diagram::snapToGrid(
element->mapToScene(element->boundingRect().center()) - centre);
if (new_pos != old_pos)
new QPropertyUndoCommand(element, "pos", old_pos, new_pos, this);
}
}
/**
@brief MirrorSelectionCommand::selectedElements
@param diagram
@return the elements selected in @p diagram, none if it is read only
*/
QList MirrorSelectionCommand::selectedElements(const Diagram *diagram)
{
QList elements;
if (!diagram || diagram->isReadOnly())
return elements;
const QList items = diagram->selectedItems();
for (QGraphicsItem *item : items)
if (Element *element = qgraphicsitem_cast(item))
elements << element;
return elements;
}
/**
@brief MirrorSelectionCommand::isValid
@return true if at least one element is mirrored by this command
*/
bool MirrorSelectionCommand::isValid() const
{
return childCount() > 0;
}