File indexing completed on 2025-03-09 04:03:40
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2006 Thomas Zander <zander@kde.org> 0003 * SPDX-FileCopyrightText: 2006 Jan Hambrecht <jaham@gmx.net> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "KoShapeDistributeCommand.h" 0009 0010 #include "commands/KoShapeMoveCommand.h" 0011 #include "KoShape.h" 0012 #include <QMap> 0013 0014 #include <klocalizedstring.h> 0015 0016 class Q_DECL_HIDDEN KoShapeDistributeCommand::Private 0017 { 0018 public: 0019 Private() : command(0) {} 0020 ~Private() { 0021 delete command; 0022 } 0023 0024 qreal getAvailableSpace(KoShape *first, KoShape *last, qreal extent, const QRectF &boundingRect); 0025 0026 Distribute distribute; 0027 KoShapeMoveCommand *command; 0028 }; 0029 0030 KoShapeDistributeCommand::KoShapeDistributeCommand(const QList<KoShape*> &shapes, Distribute distribute, const QRectF &boundingRect, KUndo2Command *parent) 0031 : KUndo2Command(parent), 0032 d(new Private()) 0033 { 0034 d->distribute = distribute; 0035 QMap<qreal, KoShape*> sortedPos; 0036 QRectF bRect; 0037 qreal extent = 0.0; 0038 // sort by position and calculate sum of objects width/height 0039 Q_FOREACH (KoShape *shape, shapes) { 0040 bRect = shape->absoluteOutlineRect(); 0041 switch (d->distribute) { 0042 case HorizontalCenterDistribution: 0043 sortedPos[bRect.center().x()] = shape; 0044 break; 0045 case HorizontalGapsDistribution: 0046 case HorizontalLeftDistribution: 0047 sortedPos[bRect.left()] = shape; 0048 extent += bRect.width(); 0049 break; 0050 case HorizontalRightDistribution: 0051 sortedPos[bRect.right()] = shape; 0052 break; 0053 case VerticalCenterDistribution: 0054 sortedPos[bRect.center().y()] = shape; 0055 break; 0056 case VerticalGapsDistribution: 0057 case VerticalBottomDistribution: 0058 sortedPos[bRect.bottom()] = shape; 0059 extent += bRect.height(); 0060 break; 0061 case VerticalTopDistribution: 0062 sortedPos[bRect.top()] = shape; 0063 break; 0064 } 0065 } 0066 KoShape* first = sortedPos.begin().value(); 0067 KoShape* last = (--sortedPos.end()).value(); 0068 0069 // determine the available space to distribute 0070 qreal space = d->getAvailableSpace(first, last, extent, boundingRect); 0071 qreal pos = 0.0, step = space / qreal(shapes.count() - 1); 0072 0073 QList<QPointF> previousPositions; 0074 QList<QPointF> newPositions; 0075 QPointF position; 0076 QPointF delta; 0077 QMapIterator<qreal, KoShape*> it(sortedPos); 0078 while (it.hasNext()) { 0079 it.next(); 0080 position = it.value()->absolutePosition(); 0081 previousPositions << position; 0082 0083 bRect = it.value()->absoluteOutlineRect(); 0084 switch (d->distribute) { 0085 case HorizontalCenterDistribution: 0086 delta = QPointF(boundingRect.x() + first->absoluteOutlineRect().width() / 2 + pos - bRect.width() / 2, bRect.y()) - bRect.topLeft(); 0087 break; 0088 case HorizontalGapsDistribution: 0089 delta = QPointF(boundingRect.left() + pos, bRect.y()) - bRect.topLeft(); 0090 pos += bRect.width(); 0091 break; 0092 case HorizontalLeftDistribution: 0093 delta = QPointF(boundingRect.left() + pos, bRect.y()) - bRect.topLeft(); 0094 break; 0095 case HorizontalRightDistribution: 0096 delta = QPointF(boundingRect.left() + first->absoluteOutlineRect().width() + pos - bRect.width(), bRect.y()) - bRect.topLeft(); 0097 break; 0098 case VerticalCenterDistribution: 0099 delta = QPointF(bRect.x(), boundingRect.y() + first->absoluteOutlineRect().height() / 2 + pos - bRect.height() / 2) - bRect.topLeft(); 0100 break; 0101 case VerticalGapsDistribution: 0102 delta = QPointF(bRect.x(), boundingRect.top() + pos) - bRect.topLeft(); 0103 pos += bRect.height(); 0104 break; 0105 case VerticalBottomDistribution: 0106 delta = QPointF(bRect.x(), boundingRect.top() + first->absoluteOutlineRect().height() + pos - bRect.height()) - bRect.topLeft(); 0107 break; 0108 case VerticalTopDistribution: 0109 delta = QPointF(bRect.x(), boundingRect.top() + pos) - bRect.topLeft(); 0110 break; 0111 }; 0112 newPositions << position + delta; 0113 pos += step; 0114 } 0115 d->command = new KoShapeMoveCommand(sortedPos.values(), previousPositions, newPositions); 0116 0117 setText(kundo2_i18n("Distribute shapes")); 0118 } 0119 0120 KoShapeDistributeCommand::~KoShapeDistributeCommand() 0121 { 0122 delete d; 0123 } 0124 0125 void KoShapeDistributeCommand::redo() 0126 { 0127 KUndo2Command::redo(); 0128 d->command->redo(); 0129 } 0130 0131 void KoShapeDistributeCommand::undo() 0132 { 0133 KUndo2Command::undo(); 0134 d->command->undo(); 0135 } 0136 0137 qreal KoShapeDistributeCommand::Private::getAvailableSpace(KoShape *first, KoShape *last, qreal extent, const QRectF &boundingRect) 0138 { 0139 switch (distribute) { 0140 case HorizontalCenterDistribution: 0141 return boundingRect.width() - last->absoluteOutlineRect().width() / 2 - first->absoluteOutlineRect().width() / 2; 0142 break; 0143 case HorizontalGapsDistribution: 0144 return boundingRect.width() - extent; 0145 break; 0146 case HorizontalLeftDistribution: 0147 return boundingRect.width() - last->absoluteOutlineRect().width(); 0148 break; 0149 case HorizontalRightDistribution: 0150 return boundingRect.width() - first->absoluteOutlineRect().width(); 0151 break; 0152 case VerticalCenterDistribution: 0153 return boundingRect.height() - last->absoluteOutlineRect().height() / 2 - first->absoluteOutlineRect().height() / 2; 0154 break; 0155 case VerticalGapsDistribution: 0156 return boundingRect.height() - extent; 0157 break; 0158 case VerticalBottomDistribution: 0159 return boundingRect.height() - first->absoluteOutlineRect().height(); 0160 break; 0161 case VerticalTopDistribution: 0162 return boundingRect.height() - last->absoluteOutlineRect().height(); 0163 break; 0164 } 0165 return 0.0; 0166 }