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 attachDocument(app::Document* document) { detachDocument(); m_document = document; if (!document) return; DocumentUndo* history = m_document->undoHistory(); history->addObserver(this); refillList(history); }
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; }
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::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); }
// 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::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::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; }
// 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); }
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::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::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::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::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::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::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::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::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 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); }
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 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); }
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); }
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"); } }
// 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); } } } }