void DocumentApi::deselectMask() { DocumentUndo* undo = m_document->getUndo(); if (undo->isEnabled()) m_undoers->pushUndoer(new undoers::SetMask(getObjects(), m_document)); m_document->setMaskVisible(false); }
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(); }
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 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(); }
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); }
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); }
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); }
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); }
// 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; }
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); }
// 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; }
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; }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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"); }
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; }
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; }
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); }
void DocumentApi::flattenLayers(Sprite* sprite, int bgcolor) { Image* cel_image; Cel* cel; DocumentUndo* undo = m_document->getUndo(); // Create a temporary image. UniquePtr<Image> image_wrap(Image::create(sprite->getPixelFormat(), sprite->getWidth(), sprite->getHeight())); Image* image = image_wrap.get(); // Get the background layer from the sprite. LayerImage* background = sprite->getBackgroundLayer(); if (!background) { // If there aren't a background layer we must to create the background. background = new LayerImage(sprite); addLayer(sprite->getFolder(), background, NULL); configureLayerAsBackground(background); } // Copy all frames to the background. for (FrameNumber frame(0); frame<sprite->getTotalFrames(); ++frame) { // Clear the image and render this frame. image_clear(image, bgcolor); layer_render(sprite->getFolder(), image, 0, 0, frame); cel = background->getCel(frame); if (cel) { cel_image = sprite->getStock()->getImage(cel->getImage()); ASSERT(cel_image != NULL); // We have to save the current state of `cel_image' in the undo. if (undo->isEnabled()) { Dirty* dirty = new Dirty(cel_image, image); dirty->saveImagePixels(cel_image); m_undoers->pushUndoer(new undoers::DirtyArea( getObjects(), cel_image, dirty)); delete dirty; } } else { // If there aren't a cel in this frame in the background, we // have to create a copy of the image for the new cel. cel_image = Image::createCopy(image); // TODO error handling: if createCopy throws // Here we create the new cel (with the new image `cel_image'). cel = new Cel(frame, sprite->getStock()->addImage(cel_image)); // TODO error handling: if new Cel throws // And finally we add the cel in the background. background->addCel(cel); } image_copy(cel_image, image, 0, 0); } // Delete old layers. LayerList layers = sprite->getFolder()->getLayersList(); LayerIterator it = layers.begin(); LayerIterator end = layers.end(); for (; it != end; ++it) if (*it != background) removeLayer(*it); }
void DocumentApi::backgroundFromLayer(LayerImage* layer, int bgcolor) { ASSERT(layer); ASSERT(layer->isImage()); ASSERT(layer->isReadable()); ASSERT(layer->isWritable()); ASSERT(layer->getSprite() != NULL); ASSERT(layer->getSprite()->getBackgroundLayer() == NULL); DocumentUndo* undo = m_document->getUndo(); Sprite* sprite = layer->getSprite(); // create a temporary image to draw each frame of the new // `Background' layer UniquePtr<Image> bg_image_wrap(Image::create(sprite->getPixelFormat(), sprite->getWidth(), sprite->getHeight())); Image* bg_image = bg_image_wrap.get(); CelIterator it = layer->getCelBegin(); CelIterator end = layer->getCelEnd(); for (; it != end; ++it) { Cel* cel = *it; ASSERT((cel->getImage() > 0) && (cel->getImage() < sprite->getStock()->size())); // get the image from the sprite's stock of images Image* cel_image = sprite->getStock()->getImage(cel->getImage()); ASSERT(cel_image); image_clear(bg_image, bgcolor); image_merge(bg_image, cel_image, cel->getX(), cel->getY(), MID(0, cel->getOpacity(), 255), layer->getBlendMode()); // now we have to copy the new image (bg_image) to the cel... setCelPosition(sprite, cel, 0, 0); // same size of cel-image and bg-image if (bg_image->w == cel_image->w && bg_image->h == cel_image->h) { if (undo->isEnabled()) m_undoers->pushUndoer(new undoers::ImageArea(getObjects(), cel_image, 0, 0, cel_image->w, cel_image->h)); image_copy(cel_image, bg_image, 0, 0); } else { replaceStockImage(sprite, cel->getImage(), Image::createCopy(bg_image)); } } // Fill all empty cels with a flat-image filled with bgcolor for (FrameNumber frame(0); frame<sprite->getTotalFrames(); ++frame) { Cel* cel = layer->getCel(frame); if (!cel) { Image* cel_image = Image::create(sprite->getPixelFormat(), sprite->getWidth(), sprite->getHeight()); image_clear(cel_image, bgcolor); // Add the new image in the stock int image_index = addImageInStock(sprite, cel_image); // Create the new cel and add it to the new background layer cel = new Cel(frame, image_index); addCel(layer, cel); } } configureLayerAsBackground(layer); }
// 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); } } } }
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"); } }
void DocumentApi::setPixelFormat(Sprite* sprite, PixelFormat newFormat, DitheringMethod dithering_method) { Image* old_image; Image* new_image; int c; if (sprite->getPixelFormat() == newFormat) return; // Change pixel format of the stock of images. DocumentUndo* undo = m_document->getUndo(); if (undo->isEnabled()) m_undoers->pushUndoer(new undoers::SetStockPixelFormat(getObjects(), sprite->getStock())); sprite->getStock()->setPixelFormat(newFormat); // TODO Review this, why we use the palette in frame 0? FrameNumber frame(0); // Use the rgbmap for the specified sprite const RgbMap* rgbmap = sprite->getRgbMap(frame); for (c=0; c<sprite->getStock()->size(); c++) { old_image = sprite->getStock()->getImage(c); if (!old_image) continue; new_image = quantization::convert_pixel_format (old_image, newFormat, dithering_method, rgbmap, sprite->getPalette(frame), sprite->getBackgroundLayer() != NULL); replaceStockImage(sprite, c, new_image); } // Change sprite's pixel format. if (undo->isEnabled()) m_undoers->pushUndoer(new undoers::SetSpritePixelFormat(getObjects(), sprite)); sprite->setPixelFormat(newFormat); // Regenerate extras m_document->destroyExtraCel(); // When we are converting to grayscale color mode, we've to destroy // all palettes and put only one grayscaled-palette at the first // frame. if (newFormat == IMAGE_GRAYSCALE) { // Add undoers to revert all palette changes. if (undo->isEnabled()) { PalettesList palettes = sprite->getPalettes(); for (PalettesList::iterator it = palettes.begin(); it != palettes.end(); ++it) { Palette* palette = *it; m_undoers->pushUndoer(new undoers::RemovePalette( getObjects(), sprite, palette->getFrame())); } m_undoers->pushUndoer(new undoers::AddPalette( getObjects(), sprite, FrameNumber(0))); } // It's a UniquePtr because setPalette'll create a copy of "graypal". UniquePtr<Palette> graypal(Palette::createGrayscale()); sprite->resetPalettes(); sprite->setPalette(graypal, true); } }