예제 #1
0
void ClearCelCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  {
    UndoTransaction undoTransaction(writer.context(), "Clear Cel");

    // TODO the range of selected frames should be in the DocumentLocation.
    Timeline::Range range = App::instance()->getMainWindow()->getTimeline()->range();
    if (range.enabled()) {
      Sprite* sprite = writer.sprite();

      for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
        Layer* layer = sprite->indexToLayer(layerIdx);
        if (!layer->isImage())
          continue;

        LayerImage* layerImage = static_cast<LayerImage*>(layer);

        for (FrameNumber frame = range.frameEnd(),
               begin = range.frameBegin().previous();
             frame != begin;
             frame = frame.previous()) {
          document->getApi().clearCel(layerImage, frame);
        }
      }
    }
    else {
      document->getApi().clearCel(writer.cel());
    }

    undoTransaction.commit();
  }
  update_screen_for_document(document);
}
예제 #2
0
void InvertMaskCommand::onExecute(Context* context)
{
  bool hasMask = false;
  {
    const ContextReader reader(context);
    if (reader.document()->isMaskVisible())
      hasMask = true;
  }

  // without mask?...
  if (!hasMask) {
    // so we select all
    Command* mask_all_cmd =
      CommandsModule::instance()->getCommandByName(CommandId::MaskAll);
    context->executeCommand(mask_all_cmd);
  }
  // invert the current mask
  else {
    ContextWriter writer(context);
    Document* document(writer.document());
    Sprite* sprite(writer.sprite());

    // Select all the sprite area
    base::UniquePtr<Mask> mask(new Mask());
    mask->replace(sprite->bounds());

    // Remove in the new mask the current sprite marked region
    const gfx::Rect& maskBounds = document->mask()->bounds();
    doc::fill_rect(mask->bitmap(),
      maskBounds.x, maskBounds.y,
      maskBounds.x + maskBounds.w-1,
      maskBounds.y + maskBounds.h-1, 0);

    Mask* curMask = document->mask();
    if (curMask->bitmap()) {
      // Copy the inverted region in the new mask (we just modify the
      // document's mask temporaly here)
      curMask->freeze();
      curMask->invert();
      doc::copy_image(mask->bitmap(),
        curMask->bitmap(),
        curMask->bounds().x,
        curMask->bounds().y);
      curMask->invert();
      curMask->unfreeze();
    }

    // We need only need the area inside the sprite
    mask->intersect(sprite->bounds());

    // Set the new mask
    Transaction transaction(writer.context(), "Mask Invert", DoesntModifyDocument);
    transaction.execute(new cmd::SetMask(document, mask));
    transaction.commit();

    document->generateMaskBoundaries();
    update_screen_for_document(document);
  }
}
예제 #3
0
void InvertMaskCommand::onExecute(Context* context)
{
  bool hasMask = false;
  {
    const ActiveDocumentReader document(context);
    if (document->isMaskVisible())
      hasMask = true;
  }

  // without mask?...
  if (!hasMask) {
    // so we select all
    Command* mask_all_cmd =
      CommandsModule::instance()->getCommandByName(CommandId::MaskAll);
    context->executeCommand(mask_all_cmd);
  }
  // invert the current mask
  else {
    ActiveDocumentWriter document(context);
    Sprite* sprite(document->getSprite());
    UndoTransaction undo(document, "Mask Invert", undo::DoesntModifyDocument);
    if (undo.isEnabled())
      undo.pushUndoer(new undoers::SetMask(undo.getObjects(), document));

    /* create a new mask */
    UniquePtr<Mask> mask(new Mask());

    /* select all the sprite area */
    mask->replace(0, 0, sprite->getWidth(), sprite->getHeight());

    /* remove in the new mask the current sprite marked region */
    const gfx::Rect& maskBounds = document->getMask()->getBounds();
    image_rectfill(mask->getBitmap(),
                   maskBounds.x, maskBounds.y,
                   maskBounds.x + maskBounds.w-1,
                   maskBounds.y + maskBounds.h-1, 0);

    // Invert the current mask in the sprite
    document->getMask()->invert();
    if (document->getMask()->getBitmap()) {
      // Copy the inverted region in the new mask
      image_copy(mask->getBitmap(),
                 document->getMask()->getBitmap(),
                 document->getMask()->getBounds().x,
                 document->getMask()->getBounds().y);
    }

    // We need only need the area inside the sprite
    mask->intersect(0, 0, sprite->getWidth(), sprite->getHeight());

    // Set the new mask
    document->setMask(mask);
    undo.commit();

    document->generateMaskBoundaries();
    update_screen_for_document(document);
  }
}
예제 #4
0
void PixelsMovement::setMaskColor(bool opaque, color_t mask_color)
{
  ContextWriter writer(m_reader, 1000);
  m_opaque = opaque;
  m_maskColor = mask_color;
  redrawExtraImage();

  update_screen_for_document(m_document);
}
예제 #5
0
void UndoCommand::onExecute(Context* context)
{
  ActiveDocumentWriter document(context);
  DocumentUndo* undo = document->getUndo();
  Sprite* sprite = document->getSprite();

  if (get_config_bool("Options", "UndoGotoModified", true)) {
    SpritePosition spritePosition;

    if (m_type == Undo)
      spritePosition = undo->getNextUndoSpritePosition();
    else
      spritePosition = undo->getNextRedoSpritePosition();

    if (spritePosition != sprite->getCurrentPosition()) {
      sprite->setCurrentPosition(spritePosition);

      current_editor->drawSpriteSafe(0, 0, sprite->getWidth(), sprite->getHeight());
      update_screen_for_document(document);

      ui::dirty_display_flag = true;
      gui_feedback();

      base::this_thread::sleep_for(0.01);
    }
  }

  StatusBar::instance()
    ->showTip(1000, "%s %s",
              (m_type == Undo ? "Undid": "Redid"),
              (m_type == Undo ? undo->getNextUndoLabel():
                                undo->getNextRedoLabel()));

  if (m_type == Undo)
    undo->doUndo();
  else
    undo->doRedo();

  document->generateMaskBoundaries();
  document->destroyExtraCel(); // Regenerate extras

  update_screen_for_document(document);
}
예제 #6
0
void RotateCanvasCommand::onExecute(Context* context)
{
  ActiveDocumentReader document(context);
  {
    RotateCanvasJob job(document, m_angle);
    job.startJob();
  }
  document->generateMaskBoundaries();
  update_screen_for_document(document);
}
예제 #7
0
void RotateCanvasCommand::onExecute(Context* context)
{
  ContextReader reader(context);
  {
    RotateCanvasJob job(reader, m_angle);
    job.startJob();
  }
  reader.document()->generateMaskBoundaries();
  update_screen_for_document(reader.document());
}
예제 #8
0
void FlattenLayersCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Sprite* sprite = writer.sprite();
  {
    Transaction transaction(writer.context(), "Flatten Layers");
    transaction.execute(new cmd::FlattenLayers(sprite));
    transaction.commit();
  }
  update_screen_for_document(writer.document());
}
예제 #9
0
void DeselectMaskCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Doc* document(writer.document());
  {
    Tx tx(writer.context(), "Deselect", DoesntModifyDocument);
    tx(new cmd::DeselectMask(document));
    tx.commit();
  }
  update_screen_for_document(document);
}
예제 #10
0
void PixelsMovement::copyMask()
{
  // Hide the mask (do not deselect it, it will be moved them using
  // m_transaction.setMaskPosition)
  Mask emptyMask;
  {
    ContextWriter writer(m_reader, 1000);
    m_document->generateMaskBoundaries(&emptyMask);
    update_screen_for_document(m_document);
  }
}
예제 #11
0
void LayerFromBackgroundCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  {
    Transaction transaction(writer.context(), "Layer from Background");
    document->getApi(transaction).layerFromBackground(writer.layer());
    transaction.commit();
  }
  update_screen_for_document(document);
}
예제 #12
0
void UnlinkCelCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  bool nonEditableLayers = false;
  {
    Transaction transaction(writer.context(), "Unlink Cel");

    // TODO the range of selected frames should be in doc::Site.
    auto range = App::instance()->timeline()->range();
    if (range.enabled()) {
      Sprite* sprite = writer.sprite();

      for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
        Layer* layer = sprite->indexToLayer(layerIdx);
        if (!layer->isImage())
          continue;

        LayerImage* layerImage = static_cast<LayerImage*>(layer);

        for (frame_t frame = range.frameEnd(),
               begin = range.frameBegin()-1;
             frame != begin;
             --frame) {
          Cel* cel = layerImage->cel(frame);
          if (cel && cel->links()) {
            if (layerImage->isEditable())
              transaction.execute(new cmd::UnlinkCel(cel));
            else
              nonEditableLayers = true;
          }
        }
      }
    }
    else {
      Cel* cel = writer.cel();
      if (cel && cel->links()) {
        if (cel->layer()->isEditable())
          transaction.execute(new cmd::UnlinkCel(writer.cel()));
        else
          nonEditableLayers = true;
      }
    }

    transaction.commit();
  }

  if (nonEditableLayers)
    StatusBar::instance()->showTip(1000,
      "There are locked layers");

  update_screen_for_document(document);
}
예제 #13
0
void FlattenLayersCommand::onExecute(Context* context)
{
  ActiveDocumentWriter document(context);
  Sprite* sprite = document->getSprite();
  int bgcolor = color_utils::color_for_image(app_get_colorbar()->getBgColor(), sprite->getImgType());
  {
    UndoTransaction undoTransaction(document, "Flatten Layers");
    undoTransaction.flattenLayers(bgcolor);
    undoTransaction.commit();
  }
  update_screen_for_document(document);
}
예제 #14
0
void ReverseFramesCommand::onExecute(Context* context)
{
  DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range();
  if (!range.enabled())
    return;                     // Nothing to do

  Document* doc = context->activeDocument();

  reverse_frames(doc, range);

  update_screen_for_document(doc);
}
예제 #15
0
void DeselectMaskCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  {
    Transaction transaction(writer.context(), "Deselect", DoesntModifyDocument);
    transaction.execute(new cmd::DeselectMask(document));
    transaction.commit();
  }
  document->generateMaskBoundaries();
  update_screen_for_document(document);
}
예제 #16
0
void RemoveFrameCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  Sprite* sprite(writer.sprite());
  {
    UndoTransaction undoTransaction(writer.context(), "Remove Frame");
    document->getApi().removeFrame(sprite, writer.frame());
    undoTransaction.commit();
  }
  update_screen_for_document(document);
}
예제 #17
0
void DeselectMaskCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  {
    UndoTransaction undoTransaction(writer.context(), "Mask Deselection", undo::DoesntModifyDocument);
    document->getApi().deselectMask();
    undoTransaction.commit();
  }
  document->generateMaskBoundaries();
  update_screen_for_document(document);
}
예제 #18
0
void FlattenLayersCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document = writer.document();
  Sprite* sprite = writer.sprite();
  {
    UndoTransaction undoTransaction(writer.context(), "Flatten Layers");
    document->getApi().flattenLayers(sprite);
    undoTransaction.commit();
  }
  update_screen_for_document(writer.document());
}
예제 #19
0
void LinkCelsCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  bool nonEditableLayers = false;
  {
    // TODO the range of selected frames should be in doc::Site.
    Timeline::Range range = App::instance()->getMainWindow()->getTimeline()->range();
    if (!range.enabled())
      return;

    Transaction transaction(writer.context(), friendlyName());
    Sprite* sprite = writer.sprite();
    frame_t begin = range.frameBegin();
    frame_t end = range.frameEnd();

    for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
      Layer* layer = sprite->indexToLayer(layerIdx);
      if (!layer->isImage())
        continue;

      if (!layer->isEditable()) {
        nonEditableLayers = true;
        continue;
      }

      LayerImage* layerImage = static_cast<LayerImage*>(layer);
      for (frame_t frame=begin; frame < end+1; ++frame) {
        Cel* cel = layerImage->cel(frame);
        if (cel) {
          for (frame = cel->frame()+1;
               frame < end+1; ++frame) {
            transaction.execute(
              new cmd::CopyCel(
                layerImage, cel->frame(),
                layerImage, frame,
                true));         // true = force links
          }
          break;
        }
      }
    }

    transaction.commit();
  }

  if (nonEditableLayers)
    StatusBar::instance()->showTip(1000,
      "There are locked layers");

  update_screen_for_document(document);
}
예제 #20
0
void RemoveLayerCommand::onExecute(Context* context)
{
  std::string layerName;
  ContextWriter writer(context);
  Document* document(writer.document());
  Sprite* sprite(writer.sprite());
  {
    Transaction transaction(writer.context(), "Remove Layer");
    DocumentApi api = document->getApi(transaction);

    const Site* site = writer.site();
    if (site->inTimeline() &&
        !site->selectedLayers().empty()) {
      SelectedLayers selLayers = site->selectedLayers();
      selLayers.removeChildrenIfParentIsSelected();

      layer_t deletedTopLevelLayers = 0;
      for (Layer* layer : selLayers) {
        if (layer->parent() == sprite->root())
          ++deletedTopLevelLayers;
      }

      if (deletedTopLevelLayers == sprite->root()->layersCount()) {
        ui::Alert::show("Error<<You cannot delete all layers.||&OK");
        return;
      }

      for (Layer* layer : selLayers) {
        api.removeLayer(layer);
      }
    }
    else {
      if (sprite->allLayersCount() == 1) {
        ui::Alert::show("Error<<You cannot delete the last layer.||&OK");
        return;
      }

      Layer* layer = writer.layer();
      layerName = layer->name();
      api.removeLayer(layer);
    }

    transaction.commit();
  }
  update_screen_for_document(document);

  StatusBar::instance()->invalidate();
  if (!layerName.empty())
    StatusBar::instance()->showTip(1000, "Layer '%s' removed", layerName.c_str());
  else
    StatusBar::instance()->showTip(1000, "Layers removed");
}
예제 #21
0
void PixelsMovement::onRotationAlgorithmChange()
{
  try {
    redrawExtraImage();
    redrawCurrentMask();
    updateDocumentMask();

    update_screen_for_document(m_document);
  }
  catch (const std::exception& ex) {
    Console::showException(ex);
  }
}
예제 #22
0
void AutocropSpriteCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  Sprite* sprite(writer.sprite());
  {
    Transaction transaction(writer.context(), "Trim Sprite");
    document->getApi(transaction).trimSprite(sprite);
    transaction.commit();
  }
  document->generateMaskBoundaries();
  update_screen_for_document(document);
}
예제 #23
0
void PixelsMovement::rotate(double angle)
{
  ContextWriter writer(m_reader, 1000);
  m_currentData.angle(m_currentData.angle() + PI * -angle / 180.0);

  m_document->setTransformation(m_currentData);

  redrawExtraImage();
  redrawCurrentMask();
  updateDocumentMask();

  update_screen_for_document(m_document);
}
예제 #24
0
void UndoCommand::onExecute(Context* context)
{
    ContextWriter writer(context);
    Document* document(writer.document());
    DocumentUndo* undo = document->getUndo();
    Sprite* sprite = document->sprite();

    if (context->settings()->undoGotoModified()) {
        SpritePosition spritePosition;
        SpritePosition currentPosition(writer.location()->layerIndex(),
                                       writer.location()->frame());

        if (m_type == Undo)
            spritePosition = undo->getNextUndoSpritePosition();
        else
            spritePosition = undo->getNextRedoSpritePosition();

        if (spritePosition != currentPosition) {
            current_editor->setLayer(sprite->indexToLayer(spritePosition.layerIndex()));
            current_editor->setFrame(spritePosition.frameNumber());

            // Draw the current layer/frame (which is not undone yet) so the
            // user can see the doUndo/doRedo effect.
            current_editor->drawSpriteClipped(
                gfx::Region(gfx::Rect(0, 0, sprite->width(), sprite->height())));

            ui::dirty_display_flag = true;
            gui_feedback();

            base::this_thread::sleep_for(0.01);
        }
    }

    StatusBar::instance()
    ->showTip(1000, "%s %s",
              (m_type == Undo ? "Undid": "Redid"),
              (m_type == Undo ? undo->getNextUndoLabel():
               undo->getNextRedoLabel()));

    // Effectively undo/redo.
    if (m_type == Undo)
        undo->doUndo();
    else
        undo->doRedo();

    document->generateMaskBoundaries();
    document->destroyExtraCel(); // Regenerate extras

    update_screen_for_document(document);
    set_current_palette(writer.palette(), false);
}
예제 #25
0
void AutocropSpriteCommand::onExecute(Context* context)
{
    ActiveDocumentWriter document(context);
    Sprite* sprite(document->getSprite());
    {
        int bgcolor = color_utils::color_for_image(ColorBar::instance()->getBgColor(), sprite->getPixelFormat());

        UndoTransaction undoTransaction(document, "Trim Sprite");
        undoTransaction.trimSprite(bgcolor);
        undoTransaction.commit();
    }
    document->generateMaskBoundaries();
    update_screen_for_document(document);
}
void BackgroundFromLayerCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());

  {
    Transaction transaction(writer.context(), "Background from Layer");
    document->getApi(transaction).backgroundFromLayer(
      static_cast<LayerImage*>(writer.layer()));
    transaction.commit();
  }

  update_screen_for_document(document);
}
예제 #27
0
void FlattenLayersCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document = writer.document();
  Sprite* sprite = writer.sprite();
  int bgcolor = color_utils::color_for_image(ColorBar::instance()->getBgColor(),
                                             sprite->getPixelFormat());
  {
    UndoTransaction undoTransaction(writer.context(), "Flatten Layers");
    document->getApi().flattenLayers(sprite, bgcolor);
    undoTransaction.commit();
  }
  update_screen_for_document(writer.document());
}
예제 #28
0
void UndoCommand::onExecute(Context* context)
{
  ActiveDocumentWriter document(context);

  app_get_statusbar()
    ->showTip(1000, "Undid %s",
              document->getUndoHistory()->getNextUndoLabel());

  document->getUndoHistory()->doUndo();
  document->generateMaskBoundaries();
  document->destroyExtraCel(); // Regenerate extras

  update_screen_for_document(document);
}
예제 #29
0
void LinkCelsCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Doc* document(writer.document());
  bool nonEditableLayers = false;
  {
    auto site = context->activeSite();
    if (!site.inTimeline())
      return;

    Tx tx(writer.context(), friendlyName());

    for (Layer* layer : site.selectedLayers()) {
      if (!layer->isImage())
        continue;

      if (!layer->isEditableHierarchy()) {
        nonEditableLayers = true;
        continue;
      }

      LayerImage* layerImage = static_cast<LayerImage*>(layer);

      for (auto it=site.selectedFrames().begin(), end=site.selectedFrames().end();
           it != end; ++it) {
        frame_t frame = *it;
        Cel* cel = layerImage->cel(frame);
        if (cel) {
          for (++it; it != end; ++it) {
            tx(
              new cmd::CopyCel(
                layerImage, cel->frame(),
                layerImage, *it,
                true));         // true = force links
          }
          break;
        }
      }
    }

    tx.commit();
  }

  if (nonEditableLayers)
    StatusBar::instance()->showTip(1000,
      "There are locked layers");

  update_screen_for_document(document);
}
예제 #30
0
void RotateCommand::onExecute(Context* context)
{
  {
    Site site = context->activeSite();
    CelList cels;
    bool rotateSprite = false;

    // Flip the mask or current cel
    if (m_flipMask) {
      auto range = App::instance()->timeline()->range();
      if (range.enabled())
        cels = get_unique_cels(site.sprite(), range);
      else if (site.cel()) {
        // If we want to rotate the visible mask for the current cel,
        // we can go to MovingPixelsState.
        if (static_cast<app::Document*>(site.document())->isMaskVisible()) {
          // Select marquee tool
          if (tools::Tool* tool = App::instance()->toolBox()
              ->getToolById(tools::WellKnownTools::RectangularMarquee)) {
            ToolBar::instance()->selectTool(tool);
            current_editor->startSelectionTransformation(gfx::Point(0, 0), m_angle);
            return;
          }
        }

        cels.push_back(site.cel());
      }
    }
    // Flip the whole sprite
    else if (site.sprite()) {
      for (Cel* cel : site.sprite()->uniqueCels())
        cels.push_back(cel);

      rotateSprite = true;
    }

    if (cels.empty())           // Nothing to do
      return;

    ContextReader reader(context);
    {
      RotateJob job(reader, m_angle, cels, rotateSprite);
      job.startJob();
      job.waitJob();
    }
    reader.document()->generateMaskBoundaries();
    update_screen_for_document(reader.document());
  }
}