void NewLayerCommand::onExecute(Context* context) { ActiveDocumentWriter document(context); Sprite* sprite(document->getSprite()); std::string name; // Default name (m_name is a name specified in params) if (!m_name.empty()) name = m_name; else name = get_unique_layer_name(sprite); // If params specify to ask the user about the name... if (m_ask) { // We open the window to ask the name FramePtr window(load_widget("new_layer.xml", "new_layer")); JWidget name_widget = find_widget(window, "name"); name_widget->setText(name.c_str()); jwidget_set_min_size(name_widget, 128, 0); window->open_window_fg(); if (window->get_killer() != window->findChild("ok")) return; name = window->findChild("name")->getText(); } Layer* layer; { UndoTransaction undoTransaction(document, "New Layer"); layer = undoTransaction.newLayer(); undoTransaction.commit(); } layer->setName(name); update_screen_for_document(document); app_get_statusbar()->invalidate(); app_get_statusbar()->showTip(1000, "Layer `%s' created", name.c_str()); }
void RemoveLayerCommand::onExecute(Context* context) { std::string layer_name; ContextWriter writer(context); Document* document(writer.document()); Layer* layer(writer.layer()); { UndoTransaction undoTransaction(writer.context(), "Remove Layer"); // TODO the range of selected layer should be in the DocumentLocation. Timeline::Range range = App::instance()->getMainWindow()->getTimeline()->range(); if (range.enabled()) { Sprite* sprite = writer.sprite(); // TODO indexes in timeline are inverted!! fix that for a future release for (LayerIndex layer = sprite->countLayers() - LayerIndex(range.layerBegin()+1), end = sprite->countLayers() - LayerIndex(range.layerEnd()+2); layer != end; --layer) { document->getApi().removeLayer(sprite->indexToLayer(layer)); } } else { layer_name = layer->getName(); document->getApi().removeLayer(layer); } undoTransaction.commit(); } update_screen_for_document(document); StatusBar::instance()->invalidate(); if (!layer_name.empty()) StatusBar::instance()->showTip(1000, "Layer `%s' removed", layer_name.c_str()); else StatusBar::instance()->showTip(1000, "Layers removed"); }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_writer.context(), "Rotate Canvas"); DocumentApi api = m_document->getApi(); // get all sprite cels CelList cels; m_sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = m_sprite->getStock()->getImage(cel->getImage()); // change it location switch (m_angle) { case 180: api.setCelPosition(m_sprite, cel, m_sprite->getWidth() - cel->getX() - image->getWidth(), m_sprite->getHeight() - cel->getY() - image->getHeight()); break; case 90: api.setCelPosition(m_sprite, cel, m_sprite->getHeight() - cel->getY() - image->getHeight(), cel->getX()); break; case -90: api.setCelPosition(m_sprite, cel, cel->getY(), m_sprite->getWidth() - cel->getX() - image->getWidth()); break; } } // for each stock's image for (int i=0; i<m_sprite->getStock()->size(); ++i) { Image* image = m_sprite->getStock()->getImage(i); if (!image) continue; // rotate the image Image* new_image = Image::create(image->getPixelFormat(), m_angle == 180 ? image->getWidth(): image->getHeight(), m_angle == 180 ? image->getHeight(): image->getWidth()); raster::rotate_image(image, new_image, m_angle); api.replaceStockImage(m_sprite, i, new_image); jobProgress((float)i / m_sprite->getStock()->size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->getMask(); base::UniquePtr<Mask> new_mask(new Mask()); const gfx::Rect& origBounds = origMask->getBounds(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->getWidth() - origBounds.x - origBounds.w; y = m_sprite->getHeight() - origBounds.y - origBounds.h; break; case 90: x = m_sprite->getHeight() - origBounds.y - origBounds.h; y = origBounds.x; break; case -90: x = origBounds.y; y = m_sprite->getWidth() - origBounds.x - origBounds.w; break; } // create the new rotated mask new_mask->replace(x, y, m_angle == 180 ? origBounds.w: origBounds.h, m_angle == 180 ? origBounds.h: origBounds.w); raster::rotate_image(origMask->getBitmap(), new_mask->getBitmap(), m_angle); // Copy new mask api.copyToCurrentMask(new_mask); // Regenerate mask m_document->resetTransformation(); m_document->generateMaskBoundaries(); } // change the sprite's size if (m_angle != 180) api.setSpriteSize(m_sprite, m_sprite->getHeight(), m_sprite->getWidth()); // commit changes undoTransaction.commit(); }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_document, "Rotate Canvas"); // get all sprite cels CelList cels; m_sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = m_sprite->getStock()->getImage(cel->getImage()); // change it location switch (m_angle) { case 180: undoTransaction.setCelPosition(cel, m_sprite->getWidth() - cel->getX() - image->w, m_sprite->getHeight() - cel->getY() - image->h); break; case 90: undoTransaction.setCelPosition(cel, m_sprite->getHeight() - cel->getY() - image->h, cel->getX()); break; case -90: undoTransaction.setCelPosition(cel, cel->getY(), m_sprite->getWidth() - cel->getX() - image->w); break; } } // for each stock's image for (int i=0; i<m_sprite->getStock()->size(); ++i) { Image* image = m_sprite->getStock()->getImage(i); if (!image) continue; // rotate the image Image* new_image = image_new(image->imgtype, m_angle == 180 ? image->w: image->h, m_angle == 180 ? image->h: image->w); image_rotate(image, new_image, m_angle); undoTransaction.replaceStockImage(i, new_image); jobProgress((float)i / m_sprite->getStock()->size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->getMask(); Mask* new_mask = mask_new(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->getWidth() - origMask->x - origMask->w; y = m_sprite->getHeight() - origMask->y - origMask->h; break; case 90: x = m_sprite->getHeight() - origMask->y - origMask->h; y = origMask->x; break; case -90: x = origMask->y; y = m_sprite->getWidth() - origMask->x - origMask->w; break; } // create the new rotated mask mask_replace(new_mask, x, y, m_angle == 180 ? origMask->w: origMask->h, m_angle == 180 ? origMask->h: origMask->w); image_rotate(origMask->bitmap, new_mask->bitmap, m_angle); // copy new mask undoTransaction.copyToCurrentMask(new_mask); mask_free(new_mask); // regenerate mask m_document->generateMaskBoundaries(); } // change the sprite's size if (m_angle != 180) undoTransaction.setSpriteSize(m_sprite->getHeight(), m_sprite->getWidth()); // commit changes undoTransaction.commit(); }
void FlipCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document = writer.document(); Sprite* sprite = writer.sprite(); DocumentApi api = document->getApi(); { UndoTransaction undoTransaction(writer.context(), m_flipMask ? (m_flipType == raster::algorithm::FlipHorizontal ? "Flip Horizontal": "Flip Vertical"): (m_flipType == raster::algorithm::FlipHorizontal ? "Flip Canvas Horizontal": "Flip Canvas Vertical")); if (m_flipMask) { int x, y; Image* image = writer.image(&x, &y); if (!image) return; Mask* mask = NULL; bool alreadyFlipped = false; // This variable will be the area to be flipped inside the image. gfx::Rect bounds(image->getBounds()); // If there is some portion of sprite selected, we flip the // selected region only. If the mask isn't visible, we flip the // whole image. if (document->isMaskVisible()) { mask = document->getMask(); // Intersect the full area of the image with the mask's // bounds, so we don't request to flip an area outside the // image's bounds. bounds = bounds.createIntersect(gfx::Rect(mask->getBounds()).offset(-x, -y)); // If the mask isn't a rectangular area, we've to flip the mask too. if (mask->getBitmap() != NULL && !mask->isRectangular()) { int bgcolor = app_get_color_to_clear_layer(writer.layer()); // Flip the portion of image specified by the mask. mask->offsetOrigin(-x, -y); api.flipImageWithMask(image, mask, m_flipType, bgcolor); mask->offsetOrigin(x, y); alreadyFlipped = true; // Flip the mask. Image* maskBitmap = mask->getBitmap(); if (maskBitmap != NULL) { // Create a flipped copy of the current mask. base::UniquePtr<Mask> newMask(new Mask(*mask)); newMask->freeze(); raster::algorithm::flip_image(newMask->getBitmap(), maskBitmap->getBounds(), m_flipType); newMask->unfreeze(); // Change the current mask and generate the new boundaries. api.copyToCurrentMask(newMask); document->generateMaskBoundaries(); } } } // Flip the portion of image specified by "bounds" variable. if (!alreadyFlipped) { api.flipImage(image, bounds, m_flipType); } } else { // get all sprite cels CelList cels; sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = sprite->getStock()->getImage(cel->getImage()); api.setCelPosition (sprite, cel, (m_flipType == raster::algorithm::FlipHorizontal ? sprite->getWidth() - image->getWidth() - cel->getX(): cel->getX()), (m_flipType == raster::algorithm::FlipVertical ? sprite->getHeight() - image->getHeight() - cel->getY(): cel->getY())); api.flipImage(image, image->getBounds(), m_flipType); } } undoTransaction.commit(); } update_screen_for_document(document); }
void onImport() { // The user don't select a sheet yet. if (!m_document) { Alert::show("Import Sprite Sheet<<Select a sprite first.||&Close"); return; } // The list of frames imported from the sheet std::vector<Image*> animation; try { Sprite* sprite = m_document->getSprite(); FrameNumber currentFrame = m_context->getActiveLocation().frame(); // As first step, we cut each tile and add them into "animation" list. for (int y=m_rect.y; y<sprite->getHeight(); y += m_rect.h) { for (int x=m_rect.x; x<sprite->getWidth(); x += m_rect.w) { base::UniquePtr<Image> resultImage(Image::create(sprite->getPixelFormat(), m_rect.w, m_rect.h)); // Clear the image with mask color. image_clear(resultImage, 0); // Render the portion of sheet. sprite->render(resultImage, -x, -y, currentFrame); animation.push_back(resultImage); resultImage.release(); } } if (animation.size() == 0) { Alert::show("Import Sprite Sheet" "<<The specified rectangle does not create any tile." "<<Select a rectangle inside the sprite region." "||&OK"); return; } // The following steps modify the sprite, so we wrap all // operations in a undo-transaction. ContextWriter writer(m_context); UndoTransaction undoTransaction(writer.context(), "Import Sprite Sheet", undo::ModifyDocument); DocumentApi api = m_document->getApi(); // Add the layer in the sprite. LayerImage* resultLayer = api.newLayer(sprite); // Add all frames+cels to the new layer for (size_t i=0; i<animation.size(); ++i) { int indexInStock; // Add the image into the sprite's stock indexInStock = api.addImageInStock(sprite, animation[i]); animation[i] = NULL; // Create the cel. base::UniquePtr<Cel> resultCel(new Cel(FrameNumber(i), indexInStock)); // Add the cel in the layer. api.addCel(resultLayer, resultCel); resultCel.release(); } // Copy the list of layers (because we will modify it in the iteration). LayerList layers = sprite->getFolder()->getLayersList(); // Remove all other layers for (LayerIterator it=layers.begin(), end=layers.end(); it!=end; ++it) { if (*it != resultLayer) api.removeLayer(*it); } // Change the number of frames api.setTotalFrames(sprite, FrameNumber(animation.size())); // Set the size of the sprite to the tile size. api.setSpriteSize(sprite, m_rect.w, m_rect.h); undoTransaction.commit(); } catch (...) { for (size_t i=0; i<animation.size(); ++i) delete animation[i]; throw; } update_screen_for_document(m_document); closeWindow(NULL); }