void ButtonTaskMenu::createGroup() { QDesignerFormWindowInterface *fw = formWindow(); const ButtonList bl = buttonList(fw->cursor()); // Do we need to remove the buttons from an existing group? QUndoCommand *removeCmd = 0; if (bl.front()->group()) { removeCmd = createRemoveButtonsCommand(fw, bl); if (!removeCmd) return; } // Add cmd CreateButtonGroupCommand *addCmd = new CreateButtonGroupCommand(fw); if (!addCmd->init(bl)) { qWarning("** WARNING Failed to initialize CreateButtonGroupCommand!"); delete addCmd; return; } // Need a macro [even if we only have the add command] since the command might trigger additional commands QUndoStack *history = fw->commandHistory(); history->beginMacro(addCmd->text()); if (removeCmd) history->push(removeCmd); history->push(addCmd); history->endMacro(); }
void ButtonTaskMenu::addToGroup(QAction *a) { QButtonGroup *bg = qvariant_cast<QButtonGroup *>(a->data()); Q_ASSERT(bg); QDesignerFormWindowInterface *fw = formWindow(); const ButtonList bl = buttonList(fw->cursor()); // Do we need to remove the buttons from an existing group? QUndoCommand *removeCmd = 0; if (bl.front()->group()) { removeCmd = createRemoveButtonsCommand(fw, bl); if (!removeCmd) return; } AddButtonsToGroupCommand *addCmd = new AddButtonsToGroupCommand(fw); addCmd->init(bl, bg); QUndoStack *history = fw->commandHistory(); if (removeCmd) { history->beginMacro(addCmd->text()); history->push(removeCmd); history->push(addCmd); history->endMacro(); } else { history->push(addCmd); } }
void TilesetDock::embedTileset() { Tileset *tileset = currentTileset(); if (!tileset) return; if (!tileset->isExternal()) return; // To embed a tileset we clone it, since further changes to that tileset // should not affect the exteral tileset. SharedTileset embeddedTileset = tileset->clone(); QUndoStack *undoStack = mMapDocument->undoStack(); int mapTilesetIndex = mMapDocument->map()->tilesets().indexOf(tileset->sharedPointer()); // Tileset may not be part of the map yet if (mapTilesetIndex == -1) undoStack->push(new AddTileset(mMapDocument, embeddedTileset)); else undoStack->push(new ReplaceTileset(mMapDocument, mapTilesetIndex, embeddedTileset)); // Make sure the embedded tileset is selected int embeddedTilesetIndex = mTilesets.indexOf(embeddedTileset); if (embeddedTilesetIndex != -1) mTabBar->setCurrentIndex(embeddedTilesetIndex); }
void AddShape::performAction(Block* block) const { Node* node = static_cast<Node*>(block); GenerateShape dialog(_generator, PantinEngine::MainWindow()); if(dialog.createShape()) { K_ASSERT( node->instance()->fastInherits<Model>() ); // The instance HAS to be a model in Nigel. Only models can contain geometry. Model* model = static_cast<Model*>(node->instance()); QUndoStack* undoStack = PantinEngine::InstanceUndoStack( model ); undoStack->setActive(true); undoStack->beginMacro( tr("Adding new %1 to node %2") .arg(_generator->shape()->blockName(), node->blockName()) ); AddBlock* addGeometry = new AddBlock(model->geometries(), dialog.geometry()); undoStack->push(addGeometry); AddBlock* addReference = new AddBlock(node, dialog.geometryInstance()); undoStack->push(addReference); undoStack->endMacro(); } }
void PropertyBrowser::applyImageLayerValue(PropertyId id, const QVariant &val) { ImageLayer *imageLayer = static_cast<ImageLayer*>(mObject); QUndoStack *undoStack = mMapDocument->undoStack(); switch (id) { case ImageSourceProperty: { const QString imageSource = val.toString(); const QColor &color = imageLayer->transparentColor(); undoStack->push(new ChangeImageLayerProperties(mMapDocument, imageLayer, color, imageSource)); break; } case ColorProperty: { QColor color = val.value<QColor>(); if (color == Qt::gray) color = QColor(); const QString &imageSource = imageLayer->imageSource(); undoStack->push(new ChangeImageLayerProperties(mMapDocument, imageLayer, color, imageSource)); break; } default: break; } }
void MapDocumentActionHandler::delete_() { if (!mMapDocument) return; Layer *currentLayer = mMapDocument->currentLayer(); if (!currentLayer) return; TileLayer *tileLayer = dynamic_cast<TileLayer*>(currentLayer); const QRegion &selectedArea = mMapDocument->selectedArea(); const QList<MapObject*> &selectedObjects = mMapDocument->selectedObjects(); QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->beginMacro(tr("Delete")); if (tileLayer && !selectedArea.isEmpty()) { undoStack->push(new EraseTiles(mMapDocument, tileLayer, selectedArea)); } else if (!selectedObjects.isEmpty()) { foreach (MapObject *mapObject, selectedObjects) undoStack->push(new RemoveMapObject(mMapDocument, mapObject)); } selectNone(); undoStack->endMacro(); }
void EditPolygonTool::splitSegments() { if (mSelectedHandles.size() < 2) return; const PointIndexesByObject p = groupIndexesByObject(mSelectedHandles); QMapIterator<MapObject*, RangeSet<int> > i(p); QUndoStack *undoStack = mapDocument()->undoStack(); bool macroStarted = false; while (i.hasNext()) { MapObject *object = i.next().key(); const RangeSet<int> &indexRanges = i.value(); const bool closed = object->shape() == MapObject::Polygon; QPolygonF oldPolygon = object->polygon(); QPolygonF newPolygon = splitPolygonSegments(oldPolygon, indexRanges, closed); if (newPolygon.size() > oldPolygon.size()) { if (!macroStarted) { undoStack->beginMacro(tr("Split Segments")); macroStarted = true; } undoStack->push(new ChangePolygon(mapDocument(), object, newPolygon, oldPolygon)); } } if (macroStarted) undoStack->endMacro(); }
void PropertiesDock::pasteProperties() { auto clipboardManager = ClipboardManager::instance(); Properties pastedProperties = clipboardManager->properties(); if (pastedProperties.isEmpty()) return; const QList<Object *> objects = mDocument->currentObjects(); if (objects.isEmpty()) return; QList<QUndoCommand*> commands; for (Object *object : objects) { Properties properties = object->properties(); properties.merge(pastedProperties); if (object->properties() != properties) { commands.append(new ChangeProperties(mDocument, QString(), object, properties)); } } if (!commands.isEmpty()) { QUndoStack *undoStack = mDocument->undoStack(); undoStack->beginMacro(tr("Paste Property/Properties", nullptr, pastedProperties.size())); for (QUndoCommand *command : commands) undoStack->push(command); undoStack->endMacro(); } }
void MapPropertiesDialog::accept() { int format = mLayerDataCombo->currentIndex(); if (format == -1) { // this shouldn't happen! format = 0; } Map::LayerDataFormat newLayerDataFormat = static_cast<Map::LayerDataFormat>(format - 1); QUndoStack *undoStack = mMapDocument->undoStack(); QColor newColor = mColorButton->color(); if (newColor == Qt::darkGray) newColor = QColor(); const Map *map = mMapDocument->map(); bool localChanges = newColor != map->backgroundColor() || newLayerDataFormat != map->layerDataFormat(); if (localChanges) { undoStack->beginMacro(QCoreApplication::translate( "Undo Commands", "Change Map Properties")); undoStack->push(new ChangeMapProperties(mMapDocument, newColor, newLayerDataFormat)); } PropertiesDialog::accept(); if (localChanges) undoStack->endMacro(); }
void ImageLayerPropertiesDialog::accept() { QUndoStack *undoStack = mMapDocument->undoStack(); const QColor newColor = mColorButton->color() != Qt::gray ? mColorButton->color() : QColor(); const QString newPath = mImage->text(); const bool localChanges = newColor != mImageLayer->transparentColor() || newPath != mImageLayer->imageSource(); if (localChanges) { undoStack->beginMacro(QCoreApplication::translate( "Undo Commands", "Change Image Layer Properties")); undoStack->push(new ChangeImageLayerProperties( mMapDocument, mImageLayer, newColor, newPath)); } PropertiesDialog::accept(); if (localChanges) undoStack->endMacro(); }
void PropertiesDock::removeProperties() { Object *object = mDocument->currentObject(); if (!object) return; const QList<QtBrowserItem*> items = mPropertyBrowser->selectedItems(); if (items.isEmpty() || !mPropertyBrowser->allCustomPropertyItems(items)) return; QStringList propertyNames; for (QtBrowserItem *item : items) propertyNames.append(item->property()->propertyName()); QUndoStack *undoStack = mDocument->undoStack(); undoStack->beginMacro(tr("Remove Property/Properties", nullptr, propertyNames.size())); for (const QString &name : propertyNames) { undoStack->push(new RemoveProperty(mDocument, mDocument->currentObjects(), name)); } undoStack->endMacro(); }
void LayerModel::toggleOtherLayers(int layerIndex) { if (mMap->layerCount() <= 1) // No other layers return; bool visibility = true; for (int i = 0; i < mMap->layerCount(); i++) { if (i == layerIndex) continue; Layer *layer = mMap->layerAt(i); if (layer->isVisible()) { visibility = false; break; } } QUndoStack *undoStack = mMapDocument->undoStack(); if (visibility) undoStack->beginMacro(tr("Show Other Layers")); else undoStack->beginMacro(tr("Hide Other Layers")); for (int i = 0; i < mMap->layerCount(); i++) { if (i == layerIndex) continue; if (visibility != mMap->layerAt(i)->isVisible()) undoStack->push(new SetLayerVisible(mMapDocument, i, visibility)); } undoStack->endMacro(); }
void eraseRegionObjectGroup(MapDocument *mapDocument, ObjectGroup *layer, const QRegion &where) { QUndoStack *undo = mapDocument->undoStack(); const auto objects = layer->objects(); for (MapObject *obj : objects) { // TODO: we are checking bounds, which is only correct for rectangles and // tile objects. polygons and polylines are not covered correctly by this // erase method (we are in fact deleting too many objects) // TODO2: toAlignedRect may even break rects. // Convert the boundary of the object into tile space const QRectF objBounds = obj->boundsUseTile(); QPointF tl = mapDocument->renderer()->pixelToTileCoords(objBounds.topLeft()); QPointF tr = mapDocument->renderer()->pixelToTileCoords(objBounds.topRight()); QPointF br = mapDocument->renderer()->pixelToTileCoords(objBounds.bottomRight()); QPointF bl = mapDocument->renderer()->pixelToTileCoords(objBounds.bottomLeft()); QRectF objInTileSpace; objInTileSpace.setTopLeft(tl); objInTileSpace.setTopRight(tr); objInTileSpace.setBottomRight(br); objInTileSpace.setBottomLeft(bl); const QRect objAlignedRect = objInTileSpace.toAlignedRect(); if (where.intersects(objAlignedRect)) undo->push(new RemoveMapObject(mapDocument, obj)); } }
void TilesetDock::swapTiles(Tile *tileA, Tile *tileB) { if (!mMapDocument) return; QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new SwapTiles(mMapDocument, tileA, tileB)); }
void HydrogenTool::mousePressEvent(QGraphicsSceneMouseEvent *event) { QPointF downPos = event->buttonDownScenePos(event->button()); // Check possible targets Atom* atom = scene()->atomAt(downPos); if (!atom) return; QUndoStack *stack = scene()->stack(); if (event->button() == Qt::RightButton) { if (atom->numImplicitHydrogens() > 0) stack->push(new RemoveImplicitHydrogen(atom, tr("remove implicit hydrogen"))); } else { stack->push(new AddImplicitHydrogen(atom, tr("add implicit hydrogen"))); } }
void ReactionArrowTool::mousePressEvent(QGraphicsSceneMouseEvent *event) { QPointF downPos = event->buttonDownScenePos(event->button()); QUndoStack *stack = scene()->stack(); ReactionArrow *arrow = new ReactionArrow; stack->push(new AddItem(arrow, scene())); arrow->setPos(downPos); }
/** * Convenience method that deals with some of the logic related to pasting * a group of objects. */ void ClipboardManager::pasteObjectGroup(const ObjectGroup *objectGroup, MapDocument *mapDocument, const MapView *view, PasteFlags flags) { Layer *currentLayer = mapDocument->currentLayer(); if (!currentLayer) return; ObjectGroup *currentObjectGroup = currentLayer->asObjectGroup(); if (!currentObjectGroup) return; QPointF insertPos; if (!(flags & PasteInPlace)) { // Determine where to insert the objects const MapRenderer *renderer = mapDocument->renderer(); const QPointF center = objectGroup->objectsBoundingRect().center(); // Take the mouse position if the mouse is on the view, otherwise // take the center of the view. QPoint viewPos; if (view->underMouse()) viewPos = view->mapFromGlobal(QCursor::pos()); else viewPos = QPoint(view->width() / 2, view->height() / 2); const QPointF scenePos = view->mapToScene(viewPos); insertPos = renderer->screenToPixelCoords(scenePos) - center; SnapHelper(renderer).snap(insertPos); } QUndoStack *undoStack = mapDocument->undoStack(); QList<MapObject*> pastedObjects; pastedObjects.reserve(objectGroup->objectCount()); undoStack->beginMacro(tr("Paste Objects")); for (const MapObject *mapObject : objectGroup->objects()) { if (flags & PasteNoTileObjects && !mapObject->cell().isEmpty()) continue; MapObject *objectClone = mapObject->clone(); objectClone->resetId(); objectClone->setPosition(objectClone->position() + insertPos); pastedObjects.append(objectClone); undoStack->push(new AddMapObject(mapDocument, currentObjectGroup, objectClone)); } undoStack->endMacro(); mapDocument->setSelectedObjects(pastedObjects); }
void PropertyBrowser::applyTilesetValue(PropertyBrowser::PropertyId id, const QVariant &val) { Tileset *tileset = static_cast<Tileset*>(mObject); QUndoStack *undoStack = mMapDocument->undoStack(); switch (id) { case NameProperty: undoStack->push(new RenameTileset(mMapDocument, tileset, val.toString())); break; case TileOffsetProperty: undoStack->push(new ChangeTilesetTileOffset(mMapDocument, tileset, val.toPoint())); break; default: break; } }
void AbstractAspect::exec(QUndoCommand *cmd) { Q_CHECK_PTR(cmd); QUndoStack *stack = undoStack(); if (stack) stack->push(cmd); else { cmd->redo(); delete cmd; } }
void EditPolygonTool::deleteNodes() { if (mSelectedHandles.isEmpty()) return; PointIndexesByObject p = groupIndexesByObject(mSelectedHandles); QMapIterator<MapObject*, RangeSet<int> > i(p); QUndoStack *undoStack = mapDocument()->undoStack(); QString delText = tr("Delete %n Node(s)", "", mSelectedHandles.size()); undoStack->beginMacro(delText); while (i.hasNext()) { MapObject *object = i.next().key(); const RangeSet<int> &indexRanges = i.value(); QPolygonF oldPolygon = object->polygon(); QPolygonF newPolygon = oldPolygon; // Remove points, back to front to keep the indexes valid RangeSet<int>::Range it = indexRanges.end(); RangeSet<int>::Range begin = indexRanges.begin(); // assert: end != begin, since there is at least one entry do { --it; newPolygon.remove(it.first(), it.length()); } while (it != begin); if (newPolygon.size() < 2) { // We've removed the entire object undoStack->push(new RemoveMapObject(mapDocument(), object)); } else { undoStack->push(new ChangePolygon(mapDocument(), object, newPolygon, oldPolygon)); } } undoStack->endMacro(); }
void RaiseLowerHelper::push(const QList<QUndoCommand*> &commands, const QString &text) { if (commands.isEmpty()) return; QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->beginMacro(text); foreach (QUndoCommand *command, commands) undoStack->push(command); undoStack->endMacro(); }
void PropertyBrowser::applyTerrainValue(PropertyId id, const QVariant &val) { Terrain *terrain = static_cast<Terrain*>(mObject); if (id == NameProperty) { QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new RenameTerrain(mMapDocument, terrain->tileset(), terrain->id(), val.toString())); } }
void TilesetDock::removeTiles() { TilesetView *view = currentTilesetView(); if (!view) return; if (!view->selectionModel()->hasSelection()) return; const QModelIndexList indexes = view->selectionModel()->selectedIndexes(); const TilesetModel *model = view->tilesetModel(); QList<Tile*> tiles; for (const QModelIndex &index : indexes) if (Tile *tile = model->tileAt(index)) tiles.append(tile); auto matchesAnyTile = [&tiles] (const Cell &cell) { if (Tile *tile = cell.tile) return tiles.contains(tile); return false; }; const bool inUse = hasTileReferences(mMapDocument, matchesAnyTile); // If the tileset is in use, warn the user and confirm removal if (inUse) { QMessageBox warning(QMessageBox::Warning, tr("Remove Tiles"), tr("One or more of the tiles to be removed are " "still in use by the map!"), QMessageBox::Yes | QMessageBox::No, this); warning.setDefaultButton(QMessageBox::Yes); warning.setInformativeText(tr("Remove all references to these tiles?")); if (warning.exec() != QMessageBox::Yes) return; } QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->beginMacro(tr("Remove Tiles")); if (inUse) removeTileReferences(mMapDocument, matchesAnyTile); Tileset *tileset = view->tilesetModel()->tileset(); undoStack->push(new RemoveTiles(mMapDocument, tileset, tiles)); undoStack->endMacro(); // Clear the current tiles, will be referencing the removed tiles setCurrentTiles(nullptr); setCurrentTile(nullptr); }
void ObjectPropertiesDialog::accept() { const QString newName = mUi->name->text(); const QString newType = mUi->type->text(); const qreal newPosX = mUi->x->value(); const qreal newPosY = mUi->y->value(); const qreal newWidth = mUi->width->value(); const qreal newHeight = mUi->height->value(); bool changed = false; changed |= mMapObject->name() != newName; changed |= mMapObject->type() != newType; changed |= mMapObject->x() != newPosX; changed |= mMapObject->y() != newPosY; changed |= mMapObject->width() != newWidth; changed |= mMapObject->height() != newHeight; if (changed) { QUndoStack *undo = mMapDocument->undoStack(); undo->beginMacro(tr("Change Object")); undo->push(new ChangeMapObject(mMapDocument, mMapObject, newName, newType)); const QPointF oldPos = mMapObject->position(); mMapObject->setX(newPosX); mMapObject->setY(newPosY); undo->push(new MoveMapObject(mMapDocument, mMapObject, oldPos)); const QSizeF oldSize = mMapObject->size(); mMapObject->setWidth(newWidth); mMapObject->setHeight(newHeight); undo->push(new ResizeMapObject(mMapDocument, mMapObject, oldSize)); PropertiesDialog::accept(); // Let PropertiesDialog add its command undo->endMacro(); } else { PropertiesDialog::accept(); } }
void PropertiesDock::removeProperty() { QtBrowserItem *item = mPropertyBrowser->currentItem(); Object *object = mMapDocument->currentObject(); if (!item || !object) return; const QString name = item->property()->propertyName(); QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->push(new RemoveProperty(mMapDocument, mMapDocument->currentObjects(), name)); // TODO: Would be nice to automatically select the next property }
static void removeTileReferences(MapDocument *mapDocument, std::function<bool(const Cell &)> condition) { QUndoStack *undoStack = mapDocument->undoStack(); undoStack->beginMacro(QCoreApplication::translate("Undo Commands", "Remove Tiles")); for (Layer *layer : mapDocument->map()->layers()) { if (TileLayer *tileLayer = layer->asTileLayer()) { const QRegion refs = tileLayer->region(condition); if (!refs.isEmpty()) undoStack->push(new EraseTiles(mapDocument, tileLayer, refs)); } else if (ObjectGroup *objectGroup = layer->asObjectGroup()) { for (MapObject *object : *objectGroup) { if (condition(object->cell())) undoStack->push(new RemoveMapObject(mapDocument, object)); } } } undoStack->endMacro(); }
void TileCollisionDock::applyChanges() { if (mSynchronizing) return; ObjectGroup *objectGroup = static_cast<ObjectGroup*>(mDummyMapDocument->map()->layerAt(1)); ObjectGroup *clonedGroup = objectGroup->clone(); QUndoStack *undoStack = mTilesetDocument->undoStack(); mApplyingChanges = true; undoStack->push(new ChangeTileObjectGroup(mTilesetDocument, mTile, clonedGroup)); mApplyingChanges = false; }
void ObjectContainer::modifyCmd(const QJsonObject& data, Modifications mod) { ObjectItem* item = getItem(data["id"].toInt()); if (!item) return; QJsonObject oldData = item->data().toJsonObject(); if (oldData != data) { QUndoCommand* cmd = new ModifyObjectCmd(oldData, data, item, mod); g_undoStack.push(cmd); } }
void ObjectContainer::addCmd(const QJsonObject& data) { if (stringToObjectType(data["type"].toString().toStdString()) == ObjectType::VoxelGrid) { if (m_voxelGridAdded) { StaticLogger::logit("WARNING: Currently, multiple VoxelGrids are not supported. Creation aborted!"); return; } m_voxelGridAdded = true; } QUndoCommand* cmd = new AddObjectCmd(data, this); g_undoStack.push(cmd); }
void ButtonGroupMenu::breakGroup() { BreakButtonGroupCommand *cmd = new BreakButtonGroupCommand(m_formWindow); if (cmd->init(m_buttonGroup)) { // Need a macro since the command might trigger additional commands QUndoStack *history = m_formWindow->commandHistory(); history->beginMacro(cmd->text()); history->push(cmd); history->endMacro(); } else { qWarning("** WARNING Failed to initialize BreakButtonGroupCommand!"); delete cmd; } }