Example #1
0
void DocumentApi::deselectMask()
{
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::SetMask(getObjects(),
        m_document));

  m_document->setMaskVisible(false);
}
Example #2
0
void DocumentApi::setMaskPosition(int x, int y)
{
  ASSERT(m_document->getMask());

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::SetMaskPosition(getObjects(), m_document));

  m_document->getMask()->setOrigin(x, y);
  m_document->resetTransformation();
}
Example #3
0
void DocumentApi::copyToCurrentMask(Mask* mask)
{
  ASSERT(m_document->getMask());
  ASSERT(mask);

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::SetMask(getObjects(),
        m_document));

  m_document->getMask()->copyFrom(mask);
}
  void attachDocument(app::Document* document) {
    detachDocument();

    m_document = document;
    if (!document)
      return;

    DocumentUndo* history = m_document->undoHistory();
    history->addObserver(this);

    refillList(history);
  }
Example #5
0
void PaletteEntryEditor::updateCurrentSpritePalette(const char* operationName)
{
    if (UIContext::instance()->activeDocument() &&
            UIContext::instance()->activeDocument()->sprite()) {
        try {
            ContextWriter writer(UIContext::instance());
            Document* document(writer.document());
            Sprite* sprite(writer.sprite());
            Palette* newPalette = get_current_palette(); // System current pal
            frame_t frame = writer.frame();
            Palette* currentSpritePalette = sprite->palette(frame); // Sprite current pal
            int from, to;

            // Check differences between current sprite palette and current system palette
            from = to = -1;
            currentSpritePalette->countDiff(newPalette, &from, &to);

            if (from >= 0 && to >= from) {
                DocumentUndo* undo = document->undoHistory();
                Cmd* cmd = new cmd::SetPalette(sprite, frame, newPalette);

                // Add undo information to save the range of pal entries that will be modified.
                if (m_implantChange &&
                        undo->lastExecutedCmd() &&
                        undo->lastExecutedCmd()->label() == operationName) {
                    // Implant the cmd in the last CmdSequence if it's
                    // related about color palette modifications
                    ASSERT(dynamic_cast<CmdSequence*>(undo->lastExecutedCmd()));
                    static_cast<CmdSequence*>(undo->lastExecutedCmd())->add(cmd);
                    cmd->execute(UIContext::instance());
                }
                else {
                    Transaction transaction(writer.context(), operationName, ModifyDocument);
                    transaction.execute(cmd);
                    transaction.commit();
                }
            }
        }
        catch (base::Exception& e) {
            Console::showException(e);
        }
    }

    PaletteView* palette_editor = ColorBar::instance()->getPaletteView();
    palette_editor->invalidate();

    if (!m_redrawTimer.isRunning())
        m_redrawTimer.start();

    m_redrawAll = false;
    m_implantChange = true;
}
Example #6
0
void DocumentApi::configureLayerAsBackground(LayerImage* layer)
{
  // Add undoers.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled()) {
    m_undoers->pushUndoer(new undoers::SetLayerFlags(getObjects(), layer));
    m_undoers->pushUndoer(new undoers::SetLayerName(getObjects(), layer));
    m_undoers->pushUndoer(new undoers::MoveLayer(getObjects(), layer));
  }

  // Do the action.
  layer->configureAsBackground();
}
Example #7
0
void DocumentApi::restackLayerAfter(Layer* layer, Layer* afterThis)
{
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::MoveLayer(getObjects(), layer));

  layer->getParent()->stackLayer(layer, afterThis);

  DocumentEvent ev(m_document);
  ev.sprite(layer->getSprite());
  ev.layer(layer);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onLayerRestacked, ev);
}
Example #8
0
void DocumentApi::setConstantFrameRate(Sprite* sprite, int msecs)
{
  // Add undoers.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled()) {
    for (FrameNumber fr(0); fr<sprite->getTotalFrames(); ++fr)
      m_undoers->pushUndoer(new undoers::SetFrameDuration(
          getObjects(), sprite, fr));
  }

  // Do the action.
  sprite->setDurationForAllFrames(msecs);
}
Example #9
0
void DocumentApi::flipImage(Image* image,
                                const gfx::Rect& bounds,
                                raster::algorithm::FlipType flipType)
{
  // Insert the undo operation.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled()) {
    m_undoers->pushUndoer
      (new undoers::FlipImage
       (getObjects(), image, bounds, flipType));
  }

  // Flip the portion of the bitmap.
  raster::algorithm::flip_image(image, bounds, flipType);
}
Example #10
0
// Removes and destroys the specified image in the stock.
void DocumentApi::removeImageFromStock(Sprite* sprite, int imageIndex)
{
  ASSERT(imageIndex >= 0);

  Image* image = sprite->getStock()->getImage(imageIndex);
  ASSERT(image);

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::RemoveImage(getObjects(),
        sprite->getStock(), imageIndex));

  sprite->getStock()->removeImage(image);
  delete image;
}
Example #11
0
void DocumentApi::setCelPosition(Sprite* sprite, Cel* cel, int x, int y)
{
  ASSERT(cel);

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::SetCelPosition(getObjects(), cel));

  cel->setPosition(x, y);

  DocumentEvent ev(m_document);
  ev.sprite(sprite);
  ev.cel(cel);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onCelPositionChanged, ev);
}
Example #12
0
void DocumentApi::replaceStockImage(Sprite* sprite, int imageIndex, Image* newImage)
{
  // Get the current image in the 'image_index' position.
  Image* oldImage = sprite->getStock()->getImage(imageIndex);
  ASSERT(oldImage);

  // Replace the image in the stock.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::ReplaceImage(getObjects(),
        sprite->getStock(), imageIndex));

  sprite->getStock()->replaceImage(imageIndex, newImage);
  delete oldImage;
}
Example #13
0
// Adds a new image in the stock. Returns the image index in the
// stock.
int DocumentApi::addImageInStock(Sprite* sprite, Image* image)
{
  ASSERT(image != NULL);

  // Do the action.
  int imageIndex = sprite->getStock()->addImage(image);

  // Add undoers.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::AddImage(getObjects(),
        sprite->getStock(), imageIndex));

  return imageIndex;
}
Example #14
0
void DocumentApi::setSpriteSize(Sprite* sprite, int w, int h)
{
  ASSERT(w > 0);
  ASSERT(h > 0);

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::SetSpriteSize(getObjects(), sprite));

  sprite->setSize(w, h);

  DocumentEvent ev(m_document);
  ev.sprite(sprite);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onSpriteSizeChanged, ev);
}
Example #15
0
void DocumentApi::setCelFramePosition(Sprite* sprite, Cel* cel, FrameNumber frame)
{
  ASSERT(cel);
  ASSERT(frame >= 0);

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::SetCelFrame(getObjects(), cel));

  cel->setFrame(frame);

  DocumentEvent ev(m_document);
  ev.sprite(sprite);
  ev.cel(cel);
  ev.frame(frame);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onCelFrameChanged, ev);
}
Example #16
0
void DocumentApi::setFrameDuration(Sprite* sprite, FrameNumber frame, int msecs)
{
  // Add undoers.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::SetFrameDuration(
        getObjects(), sprite, frame));

  // Do the action.
  sprite->setFrameDuration(frame, msecs);

  // Notify observers.
  DocumentEvent ev(m_document);
  ev.sprite(sprite);
  ev.frame(frame);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onFrameDurationChanged, ev);
}
Example #17
0
void DocumentApi::addCel(LayerImage* layer, Cel* cel)
{
  ASSERT(layer);
  ASSERT(cel);

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::AddCel(getObjects(), layer, cel));

  layer->addCel(cel);

  DocumentEvent ev(m_document);
  ev.sprite(layer->getSprite());
  ev.layer(layer);
  ev.cel(cel);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onAddCel, ev);
}
Example #18
0
void DocumentApi::addLayer(LayerFolder* folder, Layer* newLayer, Layer* afterThis)
{
  // Add undoers.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::AddLayer(getObjects(),
                                                m_document, newLayer));

  // Do the action.
  folder->addLayer(newLayer);
  folder->stackLayer(newLayer, afterThis);

  // Notify observers.
  DocumentEvent ev(m_document);
  ev.sprite(folder->getSprite());
  ev.layer(newLayer);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onAddLayer, ev);
}
Example #19
0
void DocumentApi::setTotalFrames(Sprite* sprite, FrameNumber frames)
{
  ASSERT(frames >= 1);

  // Add undoers.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::SetTotalFrames(getObjects(), m_document, sprite));

  // Do the action.
  sprite->setTotalFrames(frames);

  // Notify observers.
  DocumentEvent ev(m_document);
  ev.sprite(sprite);
  ev.frame(frames);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onTotalFramesChanged, ev);
}
Example #20
0
void DocumentApi::addFrame(Sprite* sprite, FrameNumber newFrame)
{
  // Move cels, and create copies of the cels in the given "newFrame".
  addFrameForLayer(sprite->getFolder(), newFrame);

  // Add the frame in the sprite structure, it adjusts the total
  // number of frames in the sprite.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::AddFrame(getObjects(), m_document, sprite, newFrame));

  sprite->addFrame(newFrame);

  // Notify observers about the new frame.
  DocumentEvent ev(m_document);
  ev.sprite(sprite);
  ev.frame(newFrame);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onAddFrame, ev);
}
Example #21
0
void DocumentApi::flipImageWithMask(Image* image, const Mask* mask, raster::algorithm::FlipType flipType, int bgcolor)
{
  UniquePtr<Image> flippedImage((Image::createCopy(image)));

  // Flip the portion of the bitmap.
  raster::algorithm::flip_image_with_mask(flippedImage, mask, flipType, bgcolor);

  // Insert the undo operation.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled()) {
    UniquePtr<Dirty> dirty((new Dirty(image, flippedImage)));
    dirty->saveImagePixels(image);

    m_undoers->pushUndoer(new undoers::DirtyArea(getObjects(), image, dirty));
  }

  // Copy the flipped image into the image specified as argument.
  image_copy(image, flippedImage, 0, 0);
}
Example #22
0
void DocumentApi::removeLayer(Layer* layer)
{
  ASSERT(layer != NULL);

  // Notify observers that a layer will be removed (e.g. an Editor can
  // select another layer if the removed layer is the active one).
  DocumentEvent ev(m_document);
  ev.sprite(layer->getSprite());
  ev.layer(layer);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onRemoveLayer, ev);

  // Add undoers.
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::RemoveLayer(getObjects(), m_document, layer));

  // Do the action.
  layer->getParent()->removeLayer(layer);
  delete layer;
}
Example #23
0
void DocumentApi::layerFromBackground(Layer* layer)
{
  ASSERT(layer != NULL);
  ASSERT(layer->isImage());
  ASSERT(layer->isReadable());
  ASSERT(layer->isWritable());
  ASSERT(layer->isBackground());
  ASSERT(layer->getSprite() != NULL);
  ASSERT(layer->getSprite()->getBackgroundLayer() != NULL);

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled()) {
    m_undoers->pushUndoer(new undoers::SetLayerFlags(getObjects(), layer));
    m_undoers->pushUndoer(new undoers::SetLayerName(getObjects(), layer));
  }

  layer->setBackground(false);
  layer->setMoveable(true);
  layer->setName("Layer 0");
}
Example #24
0
void DocumentApi::removeCel(LayerImage* layer, Cel* cel)
{
  ASSERT(layer);
  ASSERT(cel);

  Sprite* sprite = layer->getSprite();

  DocumentEvent ev(m_document);
  ev.sprite(sprite);
  ev.layer(layer);
  ev.cel(cel);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onRemoveCel, ev);

  // find if the image that use the cel to remove, is used by
  // another cels
  bool used = false;
  for (FrameNumber frame(0); frame<sprite->getTotalFrames(); ++frame) {
    Cel* it = layer->getCel(frame);
    if (it && it != cel && it->getImage() == cel->getImage()) {
      used = true;
      break;
    }
  }

  // if the image is only used by this cel,
  // we can remove the image from the stock
  if (!used)
    removeImageFromStock(sprite, cel->getImage());

  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::RemoveCel(getObjects(),
        layer, cel));

  // remove the cel from the layer
  layer->removeCel(cel);

  // and here we destroy the cel
  delete cel;
}
Example #25
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);
}
Example #26
0
void DocumentApi::removeFrame(Sprite* sprite, FrameNumber frame)
{
  ASSERT(frame >= 0);

  // Remove cels from this frame (and displace one position backward
  // all next frames)
  removeFrameOfLayer(sprite->getFolder(), frame);

  // Add undoers to restore the removed frame from the sprite (to
  // restore the number and durations of frames).
  DocumentUndo* undo = m_document->getUndo();
  if (undo->isEnabled())
    m_undoers->pushUndoer(new undoers::RemoveFrame(getObjects(), m_document, sprite, frame));

  // Remove the frame from the sprite. This is the low level
  // operation, it modifies the number and duration of frames.
  sprite->removeFrame(frame);

  // Notify observers.
  DocumentEvent ev(m_document);
  ev.sprite(sprite);
  ev.frame(frame);
  m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onRemoveFrame, ev);
}
Example #27
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);
}
Example #28
0
void UndoCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  DocumentUndo* undo = document->undoHistory();
  Sprite* sprite = document->sprite();
  SpritePosition spritePosition;
  const bool gotoModified =
    Preferences::instance().undo.gotoModified();

  if (gotoModified) {
    SpritePosition currentPosition(writer.site()->layerIndex(),
                                   writer.site()->frame());

    if (m_type == Undo)
      spritePosition = undo->nextUndoSpritePosition();
    else
      spritePosition = undo->nextRedoSpritePosition();

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

      // 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())));

      current_editor->manager()->flipDisplay();
      base::this_thread::sleep_for(0.01);
    }
  }

  StatusBar* statusbar = StatusBar::instance();
  if (statusbar)
    statusbar->showTip(1000, "%s %s",
      (m_type == Undo ? "Undid": "Redid"),
      (m_type == Undo ?
        undo->nextUndoLabel().c_str():
        undo->nextRedoLabel().c_str()));

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

  // After redo/undo, we retry to change the current SpritePosition
  // (because new frames/layers could be added, positions that we
  // weren't able to reach before the undo).
  if (gotoModified) {
    SpritePosition currentPosition(
      writer.site()->layerIndex(),
      writer.site()->frame());

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

  document->generateMaskBoundaries();
  document->setExtraCel(ExtraCelRef(nullptr));

  update_screen_for_document(document);
  set_current_palette(writer.palette(), false);
}
Example #29
0
void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, Layer* destLayer0) const
{
  DocumentUndo* undo = destDoc->getUndo();

  // Copy the layer name
  destLayer0->setName(sourceLayer0->getName());

  if (sourceLayer0->isImage() && destLayer0->isImage()) {
    const LayerImage* sourceLayer = static_cast<const LayerImage*>(sourceLayer0);
    LayerImage* destLayer = static_cast<LayerImage*>(destLayer0);

    // copy cels
    CelConstIterator it = sourceLayer->getCelBegin();
    CelConstIterator end = sourceLayer->getCelEnd();

    for (; it != end; ++it) {
      const Cel* sourceCel = *it;
      UniquePtr<Cel> newCel(new Cel(*sourceCel));

      ASSERT((sourceCel->getImage() >= 0) &&
             (sourceCel->getImage() < sourceLayer->getSprite()->getStock()->size()));

      const Image* sourceImage = sourceLayer->getSprite()->getStock()->getImage(sourceCel->getImage());
      ASSERT(sourceImage != NULL);

      Image* newImage = Image::createCopy(sourceImage);
      newCel->setImage(destLayer->getSprite()->getStock()->addImage(newImage));

      if (undo->isEnabled()) {
        undo->pushUndoer(new undoers::AddImage(undo->getObjects(),
            destLayer->getSprite()->getStock(),
            newCel->getImage()));
      }

      destLayer->addCel(newCel);
      newCel.release();
    }
  }
  else if (sourceLayer0->isFolder() && destLayer0->isFolder()) {
    const LayerFolder* sourceLayer = static_cast<const LayerFolder*>(sourceLayer0);
    LayerFolder* destLayer = static_cast<LayerFolder*>(destLayer0);

    LayerConstIterator it = sourceLayer->getLayerBegin();
    LayerConstIterator end = sourceLayer->getLayerEnd();

    for (; it != end; ++it) {
      Layer* sourceChild = *it;
      UniquePtr<Layer> destChild(NULL);

      if (sourceChild->isImage()) {
        destChild.reset(new LayerImage(destLayer->getSprite()));
        copyLayerContent(sourceChild, destDoc, destChild);
      }
      else if (sourceChild->isFolder()) {
        destChild.reset(new LayerFolder(destLayer->getSprite()));
        copyLayerContent(sourceChild, destDoc, destChild);
      }
      else {
        ASSERT(false);
      }

      ASSERT(destChild != NULL);

      // Add the new layer in the sprite.
      destDoc->getApi().addLayer(destLayer,
                                 destChild.release(),
                                 destLayer->getLastLayer());
    }
  }
  else  {
    ASSERT(false && "Trying to copy two incompatible layers");
  }
}
Example #30
0
// Clears the mask region in the current sprite with the specified background color.
void DocumentApi::clearMask(Layer* layer, Cel* cel, int bgcolor)
{
  Image* image = getCelImage(layer->getSprite(), cel);
  if (!image)
    return;

  Mask* mask = m_document->getMask();
  DocumentUndo* undo = m_document->getUndo();

  // If the mask is empty or is not visible then we have to clear the
  // entire image in the cel.
  if (!m_document->isMaskVisible()) {
    // If the layer is the background then we clear the image.
    if (layer->isBackground()) {
      if (undo->isEnabled())
        m_undoers->pushUndoer(new undoers::ImageArea(getObjects(),
            image, 0, 0, image->w, image->h));

      // clear all
      image_clear(image, bgcolor);
    }
    // If the layer is transparent we can remove the cel (and its
    // associated image).
    else {
      ASSERT(layer->isImage());
      removeCel(static_cast<LayerImage*>(layer), cel);
    }
  }
  else {
    int offset_x = mask->getBounds().x-cel->getX();
    int offset_y = mask->getBounds().y-cel->getY();
    int u, v, putx, puty;
    int x1 = MAX(0, offset_x);
    int y1 = MAX(0, offset_y);
    int x2 = MIN(image->w-1, offset_x+mask->getBounds().w-1);
    int y2 = MIN(image->h-1, offset_y+mask->getBounds().h-1);

    // Do nothing
    if (x1 > x2 || y1 > y2)
      return;

    if (undo->isEnabled())
      m_undoers->pushUndoer(new undoers::ImageArea(getObjects(),
          image, x1, y1, x2-x1+1, y2-y1+1));

    // Clear the masked zones
    for (v=0; v<mask->getBounds().h; v++) {
      div_t d = div(0, 8);
      uint8_t* address = ((uint8_t**)mask->getBitmap()->line)[v]+d.quot;

      for (u=0; u<mask->getBounds().w; u++) {
        if ((*address & (1<<d.rem))) {
          putx = u + offset_x;
          puty = v + offset_y;
          image_putpixel(image, putx, puty, bgcolor);
        }

        _image_bitmap_next_bit(d, address);
      }
    }
  }
}