void NewLayerCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document(writer.document()); Sprite* sprite(writer.sprite()); std::string name; // Default name (m_name is a name specified in params) if (!m_name.empty()) name = m_name; else name = get_unique_layer_name(sprite); // If params specify to ask the user about the name... if (m_ask) { // We open the window to ask the name base::UniquePtr<Window> window(app::load_widget<Window>("new_layer.xml", "new_layer")); Widget* name_widget = app::find_widget<Widget>(window, "name"); name_widget->setText(name.c_str()); name_widget->setMinSize(gfx::Size(128, 0)); window->openWindowInForeground(); if (window->closer() != window->findChild("ok")) return; name = window->findChild("name")->text(); } Layer* activeLayer = writer.layer(); Layer* layer; { Transaction transaction(writer.context(), "New Layer"); DocumentApi api = document->getApi(transaction); layer = api.newLayer(sprite, name); // If "top" parameter is false, create the layer above the active // one. if (activeLayer && !m_top) api.restackLayerAfter(layer, activeLayer); transaction.commit(); } update_screen_for_document(document); StatusBar::instance()->invalidate(); StatusBar::instance()->showTip(1000, "Layer `%s' created", name.c_str()); App::instance()->getMainWindow()->popTimeline(); }
static DocumentRange drop_range_op( Document* doc, Op op, const DocumentRange& from, DocumentRangePlace place, const DocumentRange& to) { if (place != kDocumentRangeBefore && place != kDocumentRangeAfter) { ASSERT(false); throw std::invalid_argument("Invalid 'place' argument"); } Sprite* sprite = doc->sprite(); // Check noop/trivial/do nothing cases, i.e., move a range to the same place. // Also check invalid cases, like moving a Background layer. switch (from.type()) { case DocumentRange::kCels: if (from == to) return from; break; case DocumentRange::kFrames: if (op == Move) { if ((to.frameBegin() >= from.frameBegin() && to.frameEnd() <= from.frameEnd()) || (place == kDocumentRangeBefore && to.frameBegin() == from.frameEnd()+1) || (place == kDocumentRangeAfter && to.frameEnd() == from.frameBegin()-1)) return from; } break; case DocumentRange::kLayers: if (op == Move) { if ((to.layerBegin() >= from.layerBegin() && to.layerEnd() <= from.layerEnd()) || (place == kDocumentRangeBefore && to.layerBegin() == from.layerEnd()+1) || (place == kDocumentRangeAfter && to.layerEnd() == from.layerBegin()-1)) return from; // We cannot move the background for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) if (sprite->indexToLayer(i)->isBackground()) throw std::runtime_error("The background layer cannot be moved"); // Before background if (place == kDocumentRangeBefore) { Layer* background = sprite->indexToLayer(to.layerBegin()); if (background && background->isBackground()) throw std::runtime_error("You cannot move something below the background layer"); } } break; } const char* undoLabel = NULL; switch (op) { case Move: undoLabel = "Move Range"; break; case Copy: undoLabel = "Copy Range"; break; default: ASSERT(false); throw std::invalid_argument("Invalid 'op' argument"); } DocumentRange resultRange; { const app::Context* context = static_cast<app::Context*>(doc->context()); const ContextReader reader(context); ContextWriter writer(reader); Transaction transaction(writer.context(), undoLabel, ModifyDocument); DocumentApi api = doc->getApi(transaction); // TODO Try to add the range with just one call to DocumentApi // methods, to avoid generating a lot of SetCelFrame undoers (see // DocumentApi::setCelFramePosition). switch (from.type()) { case DocumentRange::kCels: { std::vector<Layer*> layers; sprite->getLayersList(layers); int srcLayerBegin, srcLayerStep, srcLayerEnd; int dstLayerBegin, dstLayerStep; frame_t srcFrameBegin, srcFrameStep, srcFrameEnd; frame_t dstFrameBegin, dstFrameStep; if (to.layerBegin() <= from.layerBegin()) { srcLayerBegin = from.layerBegin(); srcLayerStep = 1; srcLayerEnd = from.layerEnd()+1; dstLayerBegin = to.layerBegin(); dstLayerStep = 1; } else { srcLayerBegin = from.layerEnd(); srcLayerStep = -1; srcLayerEnd = from.layerBegin()-1; dstLayerBegin = to.layerEnd(); dstLayerStep = -1; } if (to.frameBegin() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(1); srcFrameEnd = from.frameEnd()+1; dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameEnd(); dstFrameStep = frame_t(-1); } for (int srcLayerIdx = srcLayerBegin, dstLayerIdx = dstLayerBegin; srcLayerIdx != srcLayerEnd; ) { for (frame_t srcFrame = srcFrameBegin, dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) { LayerImage* srcLayer = static_cast<LayerImage*>(layers[srcLayerIdx]); LayerImage* dstLayer = static_cast<LayerImage*>(layers[dstLayerIdx]); switch (op) { case Move: api.moveCel(srcLayer, srcFrame, dstLayer, dstFrame); break; case Copy: api.copyCel(srcLayer, srcFrame, dstLayer, dstFrame); break; } srcFrame += srcFrameStep; dstFrame += dstFrameStep; } srcLayerIdx += srcLayerStep; dstLayerIdx += dstLayerStep; } resultRange = to; } break; case DocumentRange::kFrames: { frame_t srcFrameBegin = 0, srcFrameStep, srcFrameEnd = 0; frame_t dstFrameBegin = 0, dstFrameStep; switch (op) { case Move: if (place == kDocumentRangeBefore) { if (to.frameBegin() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(1); srcFrameEnd = from.frameEnd()+1; dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(-1); } } else if (place == kDocumentRangeAfter) { if (to.frameEnd() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(1); srcFrameEnd = from.frameEnd()+1; dstFrameBegin = to.frameEnd()+1; dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameEnd()+1; dstFrameStep = frame_t(-1); } } break; case Copy: if (place == kDocumentRangeBefore) { if (to.frameBegin() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(2); srcFrameEnd = from.frameBegin() + 2*from.frames(); dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(0); } } else if (place == kDocumentRangeAfter) { if (to.frameEnd() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(2); srcFrameEnd = from.frameBegin() + 2*from.frames(); dstFrameBegin = to.frameEnd()+1; dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameEnd()+1; dstFrameStep = frame_t(0); } } break; } for (frame_t srcFrame = srcFrameBegin, dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) { switch (op) { case Move: api.moveFrame(sprite, srcFrame, dstFrame); break; case Copy: api.copyFrame(sprite, srcFrame, dstFrame); break; } srcFrame += srcFrameStep; dstFrame += dstFrameStep; } if (place == kDocumentRangeBefore) { resultRange.startRange(LayerIndex::NoLayer, frame_t(to.frameBegin()), from.type()); resultRange.endRange(LayerIndex::NoLayer, frame_t(to.frameBegin()+from.frames()-1)); } else if (place == kDocumentRangeAfter) { resultRange.startRange(LayerIndex::NoLayer, frame_t(to.frameEnd()+1), from.type()); resultRange.endRange(LayerIndex::NoLayer, frame_t(to.frameEnd()+1+from.frames()-1)); } if (op == Move && from.frameBegin() < to.frameBegin()) resultRange.displace(0, -from.frames()); } break; case DocumentRange::kLayers: { std::vector<Layer*> layers; sprite->getLayersList(layers); if (layers.empty()) break; switch (op) { case Move: if (place == kDocumentRangeBefore) { for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) { api.restackLayerBefore( layers[i], layers[to.layerBegin()]); } } else if (place == kDocumentRangeAfter) { for (LayerIndex i = from.layerEnd(); i >= from.layerBegin(); --i) { api.restackLayerAfter( layers[i], layers[to.layerEnd()]); } } break; case Copy: if (place == kDocumentRangeBefore) { for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) { api.duplicateLayerBefore( layers[i], layers[to.layerBegin()]); } } else if (place == kDocumentRangeAfter) { for (LayerIndex i = from.layerEnd(); i >= from.layerBegin(); --i) { api.duplicateLayerAfter( layers[i], layers[to.layerEnd()]); } } break; } if (place == kDocumentRangeBefore) { resultRange.startRange(LayerIndex(to.layerBegin()), frame_t(-1), from.type()); resultRange.endRange(LayerIndex(to.layerBegin()+from.layers()-1), frame_t(-1)); } else if (place == kDocumentRangeAfter) { resultRange.startRange(LayerIndex(to.layerEnd()+1), frame_t(-1), from.type()); resultRange.endRange(LayerIndex(to.layerEnd()+1+from.layers()-1), frame_t(-1)); } if (op == Move && from.layerBegin() < to.layerBegin()) resultRange.displace(-from.layers(), 0); } break; } transaction.commit(); } return resultRange; }