Ejemplo n.º 1
0
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;
}