Пример #1
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);
}
Пример #2
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);
}
Пример #3
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);
}
Пример #4
0
void UnlinkCelCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  bool nonEditableLayers = false;
  {
    Transaction transaction(writer.context(), "Unlink Cel");

    const Site* site = writer.site();
    if (site->inTimeline() &&
        !site->selectedLayers().empty()) {
      for (Layer* layer : site->selectedLayers()) {
        if (!layer->isImage())
          continue;

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

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

        for (frame_t frame : site->selectedFrames().reversed()) {
          Cel* cel = layerImage->cel(frame);
          if (cel && cel->links())
            transaction.execute(new cmd::UnlinkCel(cel));
        }
      }
    }
    else {
      Cel* cel = writer.cel();
      if (cel && cel->links()) {
        if (cel->layer()->isEditableHierarchy())
          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);
}
Пример #5
0
  DocRangeOps() {
    black = rgba(0, 0, 0, 0);
    white = rgba(255, 255, 255, 255);

    doc.reset(static_cast<app::Document*>(ctx.documents().add(4, 4)));
    sprite = doc->sprite();
    layer1 = dynamic_cast<LayerImage*>(sprite->folder()->getFirstLayer());
    layer2 = new LayerImage(sprite);
    layer3 = new LayerImage(sprite);
    layer4 = new LayerImage(sprite);
    sprite->folder()->addLayer(layer2);
    sprite->folder()->addLayer(layer3);
    sprite->folder()->addLayer(layer4);
    EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);

    layer1->setName("layer1");
    layer2->setName("layer2");
    layer3->setName("layer3");
    layer4->setName("layer4");

    sprite->setTotalFrames(frame_t(4));
    sprite->setFrameDuration(frame_t(0), 1); // These durations can be used to identify
    sprite->setFrameDuration(frame_t(1), 2); // frames after a move operation
    sprite->setFrameDuration(frame_t(2), 3);
    sprite->setFrameDuration(frame_t(3), 4);

    for (int i=0; i<4; i++) {
      LayerImage* layer = static_cast<LayerImage*>(sprite->indexToLayer(LayerIndex(i)));

      for (int j=0; j<4; j++) {
        Cel* cel = layer->cel(frame_t(j));
        ImageRef image;
        if (cel)
          image = cel->imageRef();
        else {
          image.reset(Image::create(IMAGE_RGB, 4, 4));
          cel = new Cel(frame_t(j), image);
          layer->addCel(cel);
        }

        clear_image(image.get(), black);
        put_pixel(image.get(), i, j, white);
      }
    }
  }
Пример #6
0
MovingCelState::MovingCelState(Editor* editor, MouseMessage* msg)
  : m_canceled(false)
{
  ContextWriter writer(UIContext::instance(), 500);
  Document* document = editor->document();
  auto range = App::instance()->timeline()->range();
  LayerImage* layer = static_cast<LayerImage*>(editor->layer());
  ASSERT(layer->isImage());

  Cel* currentCel = layer->cel(editor->frame());
  ASSERT(currentCel); // The cel cannot be null

  if (!range.enabled())
    range = DocumentRange(currentCel);

  // Record start positions of all cels in selected range
  for (Cel* cel : get_unique_cels(writer.sprite(), range)) {
    Layer* layer = cel->layer();
    ASSERT(layer);

    if (layer && layer->isMovable() && !layer->isBackground()) {
      m_celList.push_back(cel);
      m_celStarts.push_back(cel->position());
    }
  }

  m_cursorStart = editor->screenToEditor(msg->position());
  m_celOffset = gfx::Point(0, 0);
  editor->captureMouse();

  // Hide the mask (temporarily, until mouse-up event)
  m_maskVisible = document->isMaskVisible();
  if (m_maskVisible) {
    document->setMaskVisible(false);
    document->generateMaskBoundaries();
  }
}
Пример #7
0
void CopyCel::onExecute()
{
  LayerImage* srcLayer = static_cast<LayerImage*>(m_srcLayer.layer());
  LayerImage* dstLayer = static_cast<LayerImage*>(m_dstLayer.layer());

  ASSERT(srcLayer);
  ASSERT(dstLayer);

  Sprite* srcSprite = srcLayer->sprite();
  Sprite* dstSprite = dstLayer->sprite();
  ASSERT(srcSprite);
  ASSERT(dstSprite);
  ASSERT(m_srcFrame >= 0 && m_srcFrame < srcSprite->totalFrames());
  ASSERT(m_dstFrame >= 0);
  (void)srcSprite;              // To avoid unused variable warning on Release mode

  Cel* srcCel = srcLayer->cel(m_srcFrame);
  Cel* dstCel = dstLayer->cel(m_dstFrame);

  // Clear destination cel if it does exist. It'll be overriden by the
  // copy of srcCel.
  if (dstCel) {
    if (dstCel->links())
      executeAndAdd(new cmd::UnlinkCel(dstCel));
    executeAndAdd(new cmd::ClearCel(dstCel));
  }

  // Add empty frames until newFrame
  while (dstSprite->totalFrames() <= m_dstFrame)
    executeAndAdd(new cmd::AddFrame(dstSprite, dstSprite->totalFrames()));

  Image* srcImage = (srcCel ? srcCel->image(): NULL);
  ImageRef dstImage;
  dstCel = dstLayer->cel(m_dstFrame);
  if (dstCel)
    dstImage = dstCel->imageRef();

  bool createLink =
    (srcLayer == dstLayer && dstLayer->isContinuous());

  // For background layer
  if (dstLayer->isBackground()) {
    ASSERT(dstCel);
    ASSERT(dstImage);
    if (!dstCel || !dstImage ||
        !srcCel || !srcImage)
      return;

    if (createLink) {
      executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef()));
    }
    else {
      BlendMode blend = (srcLayer->isBackground() ?
                         BlendMode::SRC:
                         BlendMode::NORMAL);

      ImageRef tmp(Image::createCopy(dstImage.get()));
      render::composite_image(tmp.get(), srcImage,
                              srcCel->x(), srcCel->y(), 255, blend);
      executeAndAdd(new cmd::CopyRect(dstImage.get(), tmp.get(), gfx::Clip(tmp->bounds())));
    }
  }
  // For transparent layers
  else {
    if (dstCel)
      executeAndAdd(new cmd::RemoveCel(dstCel));

    if (srcCel) {
      if (createLink)
        dstCel = Cel::createLink(srcCel);
      else
        dstCel = Cel::createCopy(srcCel);
      dstCel->setFrame(m_dstFrame);

      executeAndAdd(new cmd::AddCel(dstLayer, dstCel));
    }
  }
}
Пример #8
0
/**
 * Shows the "New Sprite" dialog.
 */
void NewFileCommand::onExecute(Context* context)
{
  PixelFormat format;
  int w, h, bg, ncolors = get_default_palette()->size();
  char buf[1024];
  app::Color bg_table[] = {
    app::Color::fromMask(),
    app::Color::fromRgb(0, 0, 0),
    app::Color::fromRgb(255, 255, 255),
    app::Color::fromRgb(255, 0, 255)
  };

  // Load the window widget
  app::gen::NewSprite window;

  // Default values: Indexed, 320x240, Background color
  format = static_cast<PixelFormat>(get_config_int("NewSprite", "Type", IMAGE_INDEXED));
  // Invalid format in config file.
  if (format != IMAGE_RGB && format != IMAGE_INDEXED && format != IMAGE_GRAYSCALE) {
    format = IMAGE_INDEXED;
  }
  w = get_config_int("NewSprite", "Width", 320);
  h = get_config_int("NewSprite", "Height", 240);
  bg = get_config_int("NewSprite", "Background", 1); // Default = Black

  if (bg == 4) // Convert old default (Background color) to new default (Black)
    bg = 1;
  bg = MID(0, bg, 3);

  // If the clipboard contains an image, we can show the size of the
  // clipboard as default image size.
  gfx::Size clipboardSize;
  if (clipboard::get_image_size(clipboardSize)) {
    w = clipboardSize.w;
    h = clipboardSize.h;
  }

  window.width()->setTextf("%d", MAX(1, w));
  window.height()->setTextf("%d", MAX(1, h));

  // Select image-type
  switch (format) {
    case IMAGE_RGB:       window.rgbMode()->setSelected(true); break;
    case IMAGE_GRAYSCALE: window.grayscaleMode()->setSelected(true); break;
    case IMAGE_INDEXED:   window.indexedMode()->setSelected(true); break;
  }

  // Select background color
  window.bgBox()->selectIndex(bg);

  // Open the window
  window.openWindowInForeground();

  if (window.getKiller() == window.okButton()) {
    bool ok = false;

    // Get the options
    if (window.rgbMode()->isSelected())
      format = IMAGE_RGB;
    else if (window.grayscaleMode()->isSelected())
      format = IMAGE_GRAYSCALE;
    else if (window.indexedMode()->isSelected())
      format = IMAGE_INDEXED;

    w = window.width()->getTextInt();
    h = window.height()->getTextInt();
    bg = window.bgBox()->getSelectedIndex();

    w = MID(1, w, 65535);
    h = MID(1, h, 65535);

    // Select the color
    app::Color color = app::Color::fromMask();

    if (bg >= 0 && bg <= 3) {
      color = bg_table[bg];
      ok = true;
    }

    if (ok) {
      // Save the configuration
      set_config_int("NewSprite", "Type", format);
      set_config_int("NewSprite", "Width", w);
      set_config_int("NewSprite", "Height", h);
      set_config_int("NewSprite", "Background", bg);

      // Create the new sprite
      ASSERT(format == IMAGE_RGB || format == IMAGE_GRAYSCALE || format == IMAGE_INDEXED);
      ASSERT(w > 0 && h > 0);

      base::UniquePtr<Sprite> sprite(Sprite::createBasicSprite(format, w, h, ncolors));

      if (sprite->pixelFormat() != IMAGE_GRAYSCALE)
        get_default_palette()->copyColorsTo(sprite->palette(frame_t(0)));

      // If the background color isn't transparent, we have to
      // convert the `Layer 1' in a `Background'
      if (color.getType() != app::Color::MaskType) {
        Layer* layer = sprite->folder()->getFirstLayer();

        if (layer && layer->isImage()) {
          LayerImage* layerImage = static_cast<LayerImage*>(layer);
          layerImage->configureAsBackground();

          Image* image = layerImage->cel(frame_t(0))->image();
          doc::clear_image(image,
            color_utils::color_for_target(color,
              ColorTarget(
                ColorTarget::BackgroundLayer,
                sprite->pixelFormat(),
                sprite->transparentColor())));
        }
      }

      // Show the sprite to the user
      base::UniquePtr<Document> doc(new Document(sprite));
      sprite.release();
      sprintf(buf, "Sprite-%04d", ++_sprite_counter);
      doc->setFilename(buf);
      doc->setContext(context);
      doc.release();
    }
  }
}
Пример #9
0
void FlattenLayers::onExecute()
{
  Sprite* sprite = this->sprite();
  auto doc = static_cast<Doc*>(sprite->document());

  // Create a temporary image.
  ImageRef image(Image::create(sprite->pixelFormat(),
      sprite->width(),
      sprite->height()));

  LayerImage* flatLayer;  // The layer onto which everything will be flattened.
  color_t     bgcolor;    // The background color to use for flatLayer.

  flatLayer = sprite->backgroundLayer();
  if (flatLayer && flatLayer->isVisible()) {
    // There exists a visible background layer, so we will flatten onto that.
    bgcolor = doc->bgColor(flatLayer);
  }
  else {
    // Create a new transparent layer to flatten everything onto.
    flatLayer = new LayerImage(sprite);
    ASSERT(flatLayer->isVisible());
    executeAndAdd(new cmd::AddLayer(sprite->root(), flatLayer, nullptr));
    executeAndAdd(new cmd::SetLayerName(flatLayer, "Flattened"));
    bgcolor = sprite->transparentColor();
  }

  render::Render render;
  render.setBgType(render::BgType::NONE);

  // Copy all frames to the background.
  for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) {
    // Clear the image and render this frame.
    clear_image(image.get(), bgcolor);
    render.renderSprite(image.get(), sprite, frame);

    // TODO Keep cel links when possible

    ImageRef cel_image;
    Cel* cel = flatLayer->cel(frame);
    if (cel) {
      if (cel->links())
        executeAndAdd(new cmd::UnlinkCel(cel));

      cel_image = cel->imageRef();
      ASSERT(cel_image);

      executeAndAdd(new cmd::CopyRect(cel_image.get(), image.get(),
          gfx::Clip(0, 0, image->bounds())));
    }
    else {
      cel_image.reset(Image::createCopy(image.get()));
      cel = new Cel(frame, cel_image);
      flatLayer->addCel(cel);
    }
  }

  // Delete old layers.
  LayerList layers = sprite->root()->layers();
  for (Layer* layer : layers)
    if (layer != flatLayer)
      executeAndAdd(new cmd::RemoveLayer(layer));
}
Пример #10
0
/**
 * Shows the "New Sprite" dialog.
 */
void NewFileCommand::onExecute(Context* context)
{
  Preferences& pref = Preferences::instance();
  int ncolors = get_default_palette()->size();
  char buf[1024];
  app::Color bg_table[] = {
    app::Color::fromMask(),
    app::Color::fromRgb(255, 255, 255),
    app::Color::fromRgb(0, 0, 0),
  };

  // Load the window widget
  app::gen::NewSprite window;

  // Default values: Indexed, 320x240, Background color
  PixelFormat format = pref.newFile.colorMode();
  // Invalid format in config file.
  if (format != IMAGE_RGB &&
      format != IMAGE_INDEXED &&
      format != IMAGE_GRAYSCALE) {
    format = IMAGE_INDEXED;
  }
  int w = pref.newFile.width();
  int h = pref.newFile.height();
  int bg = pref.newFile.backgroundColor();
  bg = MID(0, bg, 2);

  // If the clipboard contains an image, we can show the size of the
  // clipboard as default image size.
  gfx::Size clipboardSize;
  if (clipboard::get_image_size(clipboardSize)) {
    w = clipboardSize.w;
    h = clipboardSize.h;
  }

  window.width()->setTextf("%d", MAX(1, w));
  window.height()->setTextf("%d", MAX(1, h));

  // Select image-type
  window.colorMode()->setSelectedItem(format);

  // Select background color
  window.bgColor()->setSelectedItem(bg);

  // Advance options
  bool advanced = pref.newFile.advanced();
  window.advancedCheck()->setSelected(advanced);
  window.advancedCheck()->Click.connect(
    base::Bind<void>(
      [&]{
        gfx::Rect bounds = window.bounds();
        window.advanced()->setVisible(window.advancedCheck()->isSelected());
        window.setBounds(gfx::Rect(window.bounds().origin(),
                                   window.sizeHint()));
        window.layout();

        window.manager()->invalidateRect(bounds);
      }));
  window.advanced()->setVisible(advanced);
  if (advanced)
    window.pixelRatio()->setValue(pref.newFile.pixelRatio());
  else
    window.pixelRatio()->setValue("1:1");

  // Open the window
  window.openWindowInForeground();

  if (window.closer() == window.okButton()) {
    bool ok = false;

    // Get the options
    format = (doc::PixelFormat)window.colorMode()->selectedItem();
    w = window.width()->textInt();
    h = window.height()->textInt();
    bg = window.bgColor()->selectedItem();

    static_assert(IMAGE_RGB == 0, "RGB pixel format should be 0");
    static_assert(IMAGE_INDEXED == 2, "Indexed pixel format should be 2");

    format = MID(IMAGE_RGB, format, IMAGE_INDEXED);
    w = MID(1, w, DOC_SPRITE_MAX_WIDTH);
    h = MID(1, h, DOC_SPRITE_MAX_HEIGHT);
    bg = MID(0, bg, 2);

    // Select the color
    app::Color color = app::Color::fromMask();

    if (bg >= 0 && bg <= 3) {
      color = bg_table[bg];
      ok = true;
    }

    if (ok) {
      // Save the configuration
      pref.newFile.width(w);
      pref.newFile.height(h);
      pref.newFile.colorMode(format);
      pref.newFile.backgroundColor(bg);
      pref.newFile.advanced(window.advancedCheck()->isSelected());
      pref.newFile.pixelRatio(window.pixelRatio()->getValue());

      // Create the new sprite
      ASSERT(format == IMAGE_RGB || format == IMAGE_GRAYSCALE || format == IMAGE_INDEXED);
      ASSERT(w > 0 && h > 0);

      std::unique_ptr<Sprite> sprite(Sprite::createBasicSprite(format, w, h, ncolors));

      if (window.advancedCheck()->isSelected()) {
        sprite->setPixelRatio(
          base::convert_to<PixelRatio>(window.pixelRatio()->getValue()));
      }

      if (sprite->pixelFormat() != IMAGE_GRAYSCALE)
        get_default_palette()->copyColorsTo(sprite->palette(frame_t(0)));

      // If the background color isn't transparent, we have to
      // convert the `Layer 1' in a `Background'
      if (color.getType() != app::Color::MaskType) {
        Layer* layer = sprite->root()->firstLayer();

        if (layer && layer->isImage()) {
          LayerImage* layerImage = static_cast<LayerImage*>(layer);
          layerImage->configureAsBackground();

          Image* image = layerImage->cel(frame_t(0))->image();

          // TODO Replace this adding a new parameter to color utils
          Palette oldPal = *get_current_palette();
          set_current_palette(get_default_palette(), false);

          doc::clear_image(image,
            color_utils::color_for_target(color,
              ColorTarget(
                ColorTarget::BackgroundLayer,
                sprite->pixelFormat(),
                sprite->transparentColor())));

          set_current_palette(&oldPal, false);
        }
      }

      // Show the sprite to the user
      std::unique_ptr<Doc> doc(new Doc(sprite.get()));
      sprite.release();
      sprintf(buf, "Sprite-%04d", ++_sprite_counter);
      doc->setFilename(buf);
      doc->setContext(context);
      doc.release();
    }
  }
}