Merge branch 'master' of git@github.com:aseprite/aseprite.git

This commit is contained in:
David Capello 2015-03-17 17:30:26 -03:00
commit b4d3e5681e
26 changed files with 338 additions and 467 deletions

View File

@ -43,6 +43,12 @@
<value id="CHECKED_4x4" value="2" />
<value id="CHECKED_2x2" value="3" />
</enum>
<enum id="SpriteSheetType">
<value id="NONE" value="0" />
<value id="HORIZONTAL_STRIP" value="1" />
<value id="VERTICAL_STRIP" value="2" />
<value id="MATRIX" value="3" />
</enum>
</types>
<global>
@ -133,6 +139,15 @@
<option id="opacity_step" type="int" default="28" migrate="Onionskin.OpacityStep" />
<option id="type" type="OnionskinType" default="OnionskinType::MERGE" migrate="Onionskin.Type" />
</section>
<section id="sprite_sheet">
<option id="type" type="SpriteSheetType" default="SpriteSheetType::NONE" />
<option id="columns" type="int" default="0" />
<option id="width" type="int" default="0" />
<option id="height" type="int" default="0" />
<option id="best_fit" type="bool" default="false" />
<option id="texture_filename" type="std::string" />
<option id="data_filename" type="std::string" />
</section>
</document>
</preferences>

View File

@ -1,5 +1,5 @@
<!-- ASEPRITE -->
<!-- Copyright (C) 2001-2014 by David Capello -->
<!-- Copyright (C) 2001-2015 by David Capello -->
<gui>
<window id="export_sprite_sheet" text="Export Sprite Sheet">
<grid columns="4">
@ -18,8 +18,11 @@
<hbox id="best_fit_filler" />
<check cell_hspan="3" id="best_fit" text="Best fit for texture" />
<label text="Export Action:" />
<combobox id="export_action" cell_hspan="3" />
<label text="Save As:" />
<button id="image_filename" cell_hspan="3" />
<check id="data_enabled" text="JSON Data:" />
<button id="data_filename" cell_hspan="3" />
<hbox cell_hspan="4">
<boxfiller />

View File

@ -32,7 +32,8 @@ namespace cmd {
void onExecute() override;
void onUndo() override;
size_t onMemSize() const override {
return sizeof(*this);
return sizeof(*this) +
(m_addCel ? m_addCel->memSize() : 0);
}
private:

View File

@ -9,32 +9,19 @@
#include "config.h"
#endif
#include "app/commands/cmd_export_sprite_sheet.h"
#include "app/commands/cmd_save_file.h"
#include "app/app.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/context.h"
#include "app/context_access.h"
#include "app/document.h"
#include "app/document_api.h"
#include "app/document_undo.h"
#include "app/ini_file.h"
#include "app/modules/editors.h"
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
#include "app/ui/editor/editor.h"
#include "app/transaction.h"
#include "app/document_exporter.h"
#include "app/file/file.h"
#include "app/file_selector.h"
#include "app/pref/preferences.h"
#include "app/ui/status_bar.h"
#include "base/bind.h"
#include "base/convert_to.h"
#include "doc/cel.h"
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/palette.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "ui/ui.h"
#include "base/path.h"
#include "generated_export_sprite_sheet.h"
@ -116,24 +103,23 @@ namespace {
class ExportSpriteSheetWindow : public app::gen::ExportSpriteSheet {
public:
typedef ExportSpriteSheetCommand::SpriteSheetType SpriteSheetType;
typedef ExportSpriteSheetCommand::ExportAction ExportAction;
ExportSpriteSheetWindow(Document* doc, Sprite* sprite)
ExportSpriteSheetWindow(Document* doc, Sprite* sprite,
DocumentPreferences& docPref)
: m_sprite(sprite)
, m_docPref(docPref)
{
doc::ExportDataPtr data = doc->exportData();
static_assert(
(int)app::gen::SpriteSheetType::NONE == 0 &&
(int)app::gen::SpriteSheetType::HORIZONTAL_STRIP == 1 &&
(int)app::gen::SpriteSheetType::VERTICAL_STRIP == 2 &&
(int)app::gen::SpriteSheetType::MATRIX == 3,
"ExportType enum changed");
sheetType()->addItem("Horizontal Strip");
sheetType()->addItem("Vertical Strip");
sheetType()->addItem("Matrix");
if (data)
sheetType()->setSelectedItemIndex((int)data->type()-1); // TODO harcoded -1
exportAction()->addItem("Save Copy As...");
exportAction()->addItem("Save As...");
exportAction()->addItem("Save");
exportAction()->addItem("Do Not Save");
if (m_docPref.spriteSheet.type() != app::gen::SpriteSheetType::NONE)
sheetType()->setSelectedItemIndex((int)m_docPref.spriteSheet.type()-1);
for (int i=2; i<=8192; i*=2) {
std::string value = base::convert_to<std::string>(i);
@ -141,44 +127,60 @@ public:
if (i >= m_sprite->height()) fitHeight()->addItem(value);
}
if (!data || data->bestFit()) {
if (m_docPref.spriteSheet.bestFit()) {
bestFit()->setSelected(true);
onBestFit();
}
else if (data) {
columns()->setTextf("%d", data->columns());
else {
columns()->setTextf("%d", m_docPref.spriteSheet.columns());
onColumnsChange();
if (data->width() > 0 || data->height() > 0) {
if (data->width() > 0) fitWidth()->getEntryWidget()->setTextf("%d", data->width());
if (data->height() > 0) fitHeight()->getEntryWidget()->setTextf("%d", data->height());
if (m_docPref.spriteSheet.width() > 0 || m_docPref.spriteSheet.height() > 0) {
if (m_docPref.spriteSheet.width() > 0)
fitWidth()->getEntryWidget()->setTextf("%d", m_docPref.spriteSheet.width());
if (m_docPref.spriteSheet.height() > 0)
fitHeight()->getEntryWidget()->setTextf("%d", m_docPref.spriteSheet.height());
onSizeChange();
}
}
else {
columns()->setText("4");
onColumnsChange();
m_filename = m_docPref.spriteSheet.textureFilename();
m_dataFilename = m_docPref.spriteSheet.dataFilename();
dataEnabled()->setSelected(!m_dataFilename.empty());
std::string base = doc->filename();
base = base::join_path(base::get_file_path(base), base::get_file_title(base));
if (m_filename.empty()) {
if (base::utf8_icmp(base::get_file_extension(doc->filename()), "png") == 0)
m_filename = base + "-sheet.png";
else
m_filename = base + ".png";
}
if (m_dataFilename.empty())
m_dataFilename = base + ".json";
sheetType()->Change.connect(&ExportSpriteSheetWindow::onSheetTypeChange, this);
columns()->EntryChange.connect(Bind<void>(&ExportSpriteSheetWindow::onColumnsChange, this));
fitWidth()->Change.connect(Bind<void>(&ExportSpriteSheetWindow::onSizeChange, this));
fitHeight()->Change.connect(Bind<void>(&ExportSpriteSheetWindow::onSizeChange, this));
bestFit()->Click.connect(Bind<void>(&ExportSpriteSheetWindow::onBestFit, this));
imageFilename()->Click.connect(Bind<void>(&ExportSpriteSheetWindow::onImageFilename, this));
dataEnabled()->Click.connect(Bind<void>(&ExportSpriteSheetWindow::onDataEnabledChange, this));
dataFilename()->Click.connect(Bind<void>(&ExportSpriteSheetWindow::onDataFilename, this));
onSheetTypeChange();
onFileNamesChange();
onDataEnabledChange();
}
bool ok() {
return getKiller() == exportButton();
}
SpriteSheetType spriteSheetTypeValue() {
return (SpriteSheetType)sheetType()->getSelectedItemIndex();
}
ExportAction exportActionValue() {
return (ExportAction)exportAction()->getSelectedItemIndex();
app::gen::SpriteSheetType spriteSheetTypeValue() {
return (app::gen::SpriteSheetType)(sheetType()->getSelectedItemIndex()+1);
}
int columnsValue() {
@ -197,12 +199,23 @@ public:
return bestFit()->isSelected();
}
std::string filenameValue() {
return m_filename;
}
std::string dataFilenameValue() {
if (dataEnabled()->isSelected())
return m_dataFilename;
else
return std::string();
}
protected:
void onSheetTypeChange() {
bool state = false;
switch (sheetType()->getSelectedItemIndex()) {
case ExportSpriteSheetCommand::Matrix:
switch (spriteSheetTypeValue()) {
case app::gen::SpriteSheetType::MATRIX:
state = true;
break;
}
@ -215,11 +228,13 @@ protected:
fitHeight()->setVisible(state);
bestFitFiller()->setVisible(state);
bestFit()->setVisible(state);
resize();
}
gfx::Size reqSize = getPreferredSize();
moveWindow(gfx::Rect(getOrigin(), reqSize));
invalidate();
void onFileNamesChange() {
imageFilename()->setText("Select File: " + base::get_file_name(m_filename));
dataFilename()->setText("Select File: " + base::get_file_name(m_dataFilename));
resize();
}
void onColumnsChange() {
@ -249,8 +264,69 @@ protected:
fitHeight()->getEntryWidget()->setTextf("%d", fit.height);
}
void onImageFilename() {
std::string exts = get_writable_extensions();
std::string newFilename = app::show_file_selector(
"Save Sprite Sheet", m_filename, exts, FileSelectorType::Save);
if (newFilename.empty())
return;
m_filename = newFilename;
onFileNamesChange();
}
void onDataFilename() {
// TODO hardcoded "json" extension
std::string newFilename = app::show_file_selector(
"Save JSON Data", m_dataFilename, "json", FileSelectorType::Save);
if (newFilename.empty())
return;
m_dataFilename = newFilename;
onFileNamesChange();
}
void onDataEnabledChange() {
dataFilename()->setVisible(dataEnabled()->isSelected());
resize();
}
private:
void resize() {
gfx::Size reqSize = getPreferredSize();
moveWindow(gfx::Rect(getOrigin(), reqSize));
invalidate();
}
Sprite* m_sprite;
DocumentPreferences& m_docPref;
std::string m_filename;
std::string m_dataFilename;
};
class ExportSpriteSheetCommand : public Command {
public:
ExportSpriteSheetCommand();
Command* clone() const override { return new ExportSpriteSheetCommand(*this); }
void setUseUI(bool useUI) { m_useUI = useUI; }
protected:
void onLoadParams(const Params& params) override;
bool onEnabled(Context* context) override;
void onExecute(Context* context) override;
private:
bool m_useUI;
app::gen::SpriteSheetType m_type;
int m_columns;
int m_width;
int m_height;
bool m_bestFit;
std::string m_filename;
std::string m_dataFilename;
};
ExportSpriteSheetCommand::ExportSpriteSheetCommand()
@ -261,6 +337,14 @@ ExportSpriteSheetCommand::ExportSpriteSheetCommand()
{
}
void ExportSpriteSheetCommand::onLoadParams(const Params& params)
{
if (params.has_param("ui"))
m_useUI = params.get_as<bool>("ui");
else
m_useUI = true;
}
bool ExportSpriteSheetCommand::onEnabled(Context* context)
{
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
@ -270,21 +354,32 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
{
Document* document(context->activeDocument());
Sprite* sprite = document->sprite();
DocumentPreferences& docPref(App::instance()->preferences().document(document));
if (m_useUI) {
ExportSpriteSheetWindow window(document, sprite);
if (m_useUI && context->isUiAvailable()) {
ExportSpriteSheetWindow window(document, sprite, docPref);
window.openWindowInForeground();
if (!window.ok())
return;
m_type = window.spriteSheetTypeValue();
m_action = window.exportActionValue();
m_columns = window.columnsValue();
m_width = window.fitWidthValue();
m_height= window.fitHeightValue();
m_bestFit = window.bestFitValue();
docPref.spriteSheet.type(window.spriteSheetTypeValue());
docPref.spriteSheet.columns(window.columnsValue());
docPref.spriteSheet.width(window.fitWidthValue());
docPref.spriteSheet.height(window.fitHeightValue());
docPref.spriteSheet.bestFit(window.bestFitValue());
docPref.spriteSheet.textureFilename(window.filenameValue());
docPref.spriteSheet.dataFilename(window.dataFilenameValue());
}
else if (m_bestFit) {
m_type = docPref.spriteSheet.type();
m_columns = docPref.spriteSheet.columns();
m_width = docPref.spriteSheet.width();
m_height = docPref.spriteSheet.height();
m_bestFit = docPref.spriteSheet.bestFit();
m_filename = docPref.spriteSheet.textureFilename();
m_dataFilename = docPref.spriteSheet.dataFilename();
if (m_bestFit) {
Fit fit = best_fit(sprite);
m_columns = fit.columns;
m_width = fit.width;
@ -297,13 +392,13 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
int sheet_h = 0;
switch (m_type) {
case HorizontalStrip:
case app::gen::SpriteSheetType::HORIZONTAL_STRIP:
columns = nframes;
break;
case VerticalStrip:
case app::gen::SpriteSheetType::VERTICAL_STRIP:
columns = 1;
break;
case Matrix:
case app::gen::SpriteSheetType::MATRIX:
columns = m_columns;
if (m_width > 0) sheet_w = m_width;
if (m_height > 0) sheet_h = m_height;
@ -315,194 +410,19 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
if (sheet_h == 0) sheet_h = sprite->height()*((nframes/columns)+((nframes%columns)>0?1:0));
columns = sheet_w / sprite->width();
ImageRef resultImage(Image::create(sprite->pixelFormat(), sheet_w, sheet_h));
doc::clear_image(resultImage, 0);
DocumentExporter exporter;
exporter.setTextureFilename(m_filename);
if (!m_dataFilename.empty())
exporter.setDataFilename(m_dataFilename);
exporter.setTextureWidth(sheet_w);
exporter.setTextureHeight(sheet_h);
exporter.setTexturePack(true);
exporter.addDocument(document);
exporter.exportSheet();
render::Render render;
int column = 0, row = 0;
for (frame_t frame = 0; frame<nframes; ++frame) {
render.renderSprite(resultImage, sprite, frame,
gfx::Clip(column*sprite->width(), row*sprite->height(),
sprite->bounds()));
if (++column >= columns) {
column = 0;
++row;
}
}
// Store the frame in the current editor so we can restore it
// after change and restore the setTotalFrames() number.
frame_t oldSelectedFrame = (current_editor ?
current_editor->frame():
frame_t(0));
{
// The following steps modify the sprite, so we wrap all
// operations in a undo-transaction.
ContextWriter writer(context);
Transaction transaction(writer.context(), "Export Sprite Sheet", ModifyDocument);
DocumentApi api = document->getApi(transaction);
// Add the layer in the sprite.
LayerImage* resultLayer = api.newLayer(sprite);
// Create the cel.
base::UniquePtr<Cel> resultCel(new Cel(frame_t(0), resultImage));
// 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->folder()->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 (just one, the sprite sheet). As
// we are using the observable API, all DocumentView will change
// its current frame to frame 1. We'll try to restore the
// selected frame for the current_editor later.
api.setTotalFrames(sprite, frame_t(1));
// Set the size of the sprite to the tile size.
api.setSpriteSize(sprite, sheet_w, sheet_h);
transaction.commit();
// Draw the document with the new dimensions in the screen.
update_screen_for_document(document);
}
// This flag indicates if we've to undo the last action (so we
// back to the original sprite dimensions).
bool undo = false;
Params params;
if (!m_filename.empty())
params.set("filename", m_filename.c_str());
SaveFileBaseCommand* command = NULL;
// Do the "Export Action"
switch (m_action) {
case SaveCopyAs:
command = static_cast<SaveFileBaseCommand*>(CommandsModule::instance()
->getCommandByName(CommandId::SaveFileCopyAs));
context->executeCommand(command, params);
// Always go back, as we are using "Save Copy As", so the user
// wants to continue editing the original sprite.
undo = true;
break;
case SaveAs:
command = static_cast<SaveFileBaseCommand*>(CommandsModule::instance()
->getCommandByName(CommandId::SaveFileAs));
context->executeCommand(command, params);
// If the command was cancelled, we go back to the original
// state, if the sprite sheet was saved then we don't undo
// because the user wants to edit the sprite sheet.
undo = (document->isModified());
break;
case Save:
command = static_cast<SaveFileBaseCommand*>(CommandsModule::instance()
->getCommandByName(CommandId::SaveFile));
context->executeCommand(command, params);
// Same case as "Save As"
undo = (document->isModified());
break;
case DoNotSave:
// Do not undo as the user wants to edit the sprite sheet
// before to save the file.
undo = false;
break;
}
// Set export data
if (command != NULL) {
doc::ExportData::Type type;
switch (m_type) {
case ExportSpriteSheetCommand::HorizontalStrip:
type = doc::ExportData::HorizontalStrip;
break;
case ExportSpriteSheetCommand::VerticalStrip:
type = doc::ExportData::VerticalStrip;
break;
case ExportSpriteSheetCommand::Matrix:
type = doc::ExportData::Matrix;
break;
}
doc::ExportDataPtr data(new doc::ExportData);
data->setType(type);
data->setColumns(columns);
data->setWidth(m_width);
data->setHeight(m_height);
data->setBestFit(m_bestFit);
data->setFilename(command->selectedFilename());
document->setExportData(data);
}
// Undo the sprite sheet conversion
if (undo) {
if (document->undoHistory()->canUndo()) {
document->undoHistory()->undo();
// We've to restore the previously selected frame. As we've
// called setTotalFrames(), all document observers
// (current_editor included) have changed its current frame to
// the first one (to a visible/editable frame). The "undo"
// action doesn't restore the previously selected frame in
// observers, so at least we can restore the current_editor's
// frame.
if (current_editor)
current_editor->setFrame(oldSelectedFrame);
}
document->generateMaskBoundaries();
document->destroyExtraCel(); // Regenerate extras
// Redraw the sprite.
update_screen_for_document(document);
}
}
void ExportSpriteSheetCommand::setExportData(doc::ExportDataPtr data)
{
ExportSpriteSheetCommand::SpriteSheetType type;
switch (data->type()) {
case doc::ExportData::None: return;
case doc::ExportData::HorizontalStrip:
type = ExportSpriteSheetCommand::HorizontalStrip;
break;
case doc::ExportData::VerticalStrip:
type = ExportSpriteSheetCommand::VerticalStrip;
break;
case doc::ExportData::Matrix:
type = ExportSpriteSheetCommand::Matrix;
break;
}
m_type = type;
m_action = ExportSpriteSheetCommand::SaveCopyAs;
m_columns = data->columns();
m_width = data->width();
m_height = data->height();
m_bestFit = data->bestFit();
m_filename = data->filename();
StatusBar* statusbar = StatusBar::instance();
if (statusbar)
statusbar->showTip(1000, "Sprite Sheet Generated");
}
Command* CommandFactory::createExportSpriteSheetCommand()

View File

@ -1,51 +0,0 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_COMMANDS_CMD_EXPORT_SPRITE_SHEET_H_INCLUDED
#define APP_COMMANDS_CMD_EXPORT_SPRITE_SHEET_H_INCLUDED
#pragma once
#include "app/commands/command.h"
#include "doc/export_data.h"
#include <string>
namespace app {
class ExportSpriteSheetCommand : public Command {
public:
enum SpriteSheetType { HorizontalStrip, VerticalStrip, Matrix };
enum ExportAction { SaveCopyAs, SaveAs, Save, DoNotSave };
ExportSpriteSheetCommand();
Command* clone() const override { return new ExportSpriteSheetCommand(*this); }
SpriteSheetType type() const { return m_type; }
ExportAction action() const { return m_action; }
void setUseUI(bool useUI) { m_useUI = useUI; }
void setExportData(doc::ExportDataPtr data);
void setAction(ExportAction action) { m_action = action; }
protected:
virtual bool onEnabled(Context* context) override;
virtual void onExecute(Context* context) override;
private:
bool m_useUI;
SpriteSheetType m_type;
ExportAction m_action;
int m_columns;
int m_width;
int m_height;
bool m_bestFit;
std::string m_filename;
};
} // namespace app
#endif

View File

@ -41,9 +41,7 @@ LoadPaletteCommand::LoadPaletteCommand()
void LoadPaletteCommand::onExecute(Context* context)
{
char exts[4096];
get_readable_palette_extensions(exts, sizeof(exts));
std::string exts = get_readable_palette_extensions();
std::string filename =
app::show_file_selector("Load Palette", "", exts,
FileSelectorType::Open);

View File

@ -109,8 +109,7 @@ void OpenFileCommand::onExecute(Context* context)
// interactive
if (context->isUiAvailable() && m_filename.empty()) {
char exts[4096];
get_readable_extensions(exts, sizeof(exts));
std::string exts = get_readable_extensions();
// Add backslash as show_file_selector() expected a filename as
// initial path (and the file part is removed from the path).

View File

@ -9,12 +9,13 @@
#include "config.h"
#endif
#include "app/commands/cmd_export_sprite_sheet.h"
#include "app/app.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/context.h"
#include "app/context_access.h"
#include "app/pref/preferences.h"
namespace app {
@ -42,25 +43,20 @@ bool RepeatLastExportCommand::onEnabled(Context* context)
void RepeatLastExportCommand::onExecute(Context* context)
{
base::UniquePtr<ExportSpriteSheetCommand> command(
static_cast<ExportSpriteSheetCommand*>(
CommandsModule::instance()->getCommandByName(CommandId::ExportSpriteSheet)->clone()));
Command* cmd = CommandsModule::instance()->getCommandByName(CommandId::ExportSpriteSheet);
Params params;
{
const ContextReader reader(context);
const Document* document(reader.document());
doc::ExportDataPtr data = document->exportData();
DocumentPreferences& docPref =
App::instance()->preferences().document(document);
if (data != NULL) {
if (data->type() == doc::ExportData::None)
return; // Do nothing case
command->setUseUI(false);
command->setExportData(data);
}
params.set("ui",
(docPref.spriteSheet.type() == app::gen::SpriteSheetType::NONE ? "1": "0"));
}
context->executeCommand(command);
context->executeCommand(cmd, params);
}
Command* CommandFactory::createRepeatLastExportCommand()

View File

@ -135,8 +135,7 @@ void SaveFileBaseCommand::saveAsDialog(const ContextReader& reader, const char*
else {
filename = document->filename();
char exts[4096];
get_writable_extensions(exts, sizeof(exts));
std::string exts = get_writable_extensions();
for (;;) {
std::string newfilename = app::show_file_selector(

View File

@ -40,9 +40,7 @@ SavePaletteCommand::SavePaletteCommand()
void SavePaletteCommand::onExecute(Context* context)
{
char exts[4096];
get_writable_palette_extensions(exts, sizeof(exts));
std::string exts = get_writable_palette_extensions();
std::string filename;
int ret;

View File

@ -28,6 +28,7 @@
#include "doc/context.h"
#include "doc/document_event.h"
#include "doc/document_observer.h"
#include "doc/frame_tag.h"
#include "doc/layer.h"
#include "doc/mask.h"
#include "doc/palette.h"
@ -344,9 +345,17 @@ void Document::resetTransformation()
void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, Layer* destLayer0) const
{
LayerFlags dstFlags = sourceLayer0->flags();
// Remove the "background" flag if the destDoc already has a background layer.
if (((int)dstFlags & (int)LayerFlags::Background) == (int)LayerFlags::Background &&
(destDoc->sprite()->backgroundLayer())) {
dstFlags = (LayerFlags)((int)dstFlags & ~(int)(LayerFlags::BackgroundLayerFlags));
}
// Copy the layer name
destLayer0->setName(sourceLayer0->name());
destLayer0->setFlags(sourceLayer0->flags());
destLayer0->setFlags(dstFlags);
if (sourceLayer0->isImage() && destLayer0->isImage()) {
const LayerImage* sourceLayer = static_cast<const LayerImage*>(sourceLayer0);
@ -438,6 +447,10 @@ Document* Document::duplicate(DuplicateType type) const
for (frame_t i(0); i < sourceSprite->totalFrames(); ++i)
spriteCopy->setFrameDuration(i, sourceSprite->frameDuration(i));
// Copy frame tags
for (const FrameTag* tag : sourceSprite->frameTags())
spriteCopy->frameTags().add(new FrameTag(*tag));
// Copy color palettes
{
PalettesList::const_iterator it = sourceSprite->getPalettes().begin();
@ -454,10 +467,8 @@ Document* Document::duplicate(DuplicateType type) const
// Copy the layer folder
copyLayerContent(sourceSprite->folder(), documentCopy, spriteCopy->folder());
if (sourceSprite->backgroundLayer() != NULL) {
ASSERT(spriteCopy->folder()->getFirstLayer());
static_cast<LayerImage*>(spriteCopy->folder()->getFirstLayer())->configureAsBackground();
}
ASSERT((spriteCopy->backgroundLayer() && sourceSprite->backgroundLayer()) ||
(!spriteCopy->backgroundLayer() && !sourceSprite->backgroundLayer()));
break;
case DuplicateWithFlattenLayers:

View File

@ -43,38 +43,34 @@ using namespace base;
static FileOp* fop_new(FileOpType type, Context* context);
static void fop_prepare_for_sequence(FileOp* fop);
void get_readable_extensions(char* buf, int size)
std::string get_readable_extensions()
{
FileFormatsList::iterator it = FileFormatsManager::instance()->begin();
FileFormatsList::iterator end = FileFormatsManager::instance()->end();
std::string buf;
// Clear the string
strncpy(buf, "", size);
// Insert file format
for (; it != end; ++it) {
if ((*it)->support(FILE_SUPPORT_LOAD)) {
if (*buf) strncat(buf, ",", size);
strncat(buf, (*it)->extensions(), size);
for (const FileFormat* format : *FileFormatsManager::instance()) {
if (format->support(FILE_SUPPORT_LOAD)) {
if (!buf.empty())
buf.push_back(',');
buf += format->extensions();
}
}
return buf;
}
void get_writable_extensions(char* buf, int size)
std::string get_writable_extensions()
{
FileFormatsList::iterator it = FileFormatsManager::instance()->begin();
FileFormatsList::iterator end = FileFormatsManager::instance()->end();
std::string buf;
// Clear the string
strncpy(buf, "", size);
// Insert file format
for (; it != end; ++it) {
if ((*it)->support(FILE_SUPPORT_SAVE)) {
if (*buf) strncat(buf, ",", size);
strncat(buf, (*it)->extensions(), size);
for (const FileFormat* format : *FileFormatsManager::instance()) {
if (format->support(FILE_SUPPORT_SAVE)) {
if (!buf.empty())
buf.push_back(',');
buf += format->extensions();
}
}
return buf;
}
Document* load_document(Context* context, const char* filename)

View File

@ -112,8 +112,8 @@ namespace app {
// Available extensions for each load/save operation.
void get_readable_extensions(char* buf, int size);
void get_writable_extensions(char* buf, int size);
std::string get_readable_extensions();
std::string get_writable_extensions();
// High-level routines to load/save documents.

View File

@ -30,16 +30,18 @@ namespace app {
using namespace doc;
void get_readable_palette_extensions(char* buf, int size)
std::string get_readable_palette_extensions()
{
get_readable_extensions(buf, size);
std::strcat(buf, ",col,gpl");
std::string buf = get_readable_extensions();
buf += ",col,gpl";
return buf;
}
void get_writable_palette_extensions(char* buf, int size)
std::string get_writable_palette_extensions()
{
get_writable_extensions(buf, size);
std::strcat(buf, ",col,gpl");
std::string buf = get_writable_extensions();
buf += ",col,gpl";
return buf;
}
Palette* load_palette(const char *filename)

View File

@ -15,8 +15,8 @@ namespace doc {
namespace app {
void get_readable_palette_extensions(char* buf, int size);
void get_writable_palette_extensions(char* buf, int size);
std::string get_readable_palette_extensions();
std::string get_writable_palette_extensions();
doc::Palette* load_palette(const char *filename);
bool save_palette(const char *filename, doc::Palette* pal);

View File

@ -69,7 +69,7 @@ ToolPreferences& Preferences::tool(tools::Tool* tool)
}
}
DocumentPreferences& Preferences::document(app::Document* document)
DocumentPreferences& Preferences::document(const app::Document* document)
{
auto it = m_docs.find(document);
if (it != m_docs.end()) {
@ -102,7 +102,7 @@ void Preferences::onRemoveDocument(doc::Document* doc)
}
}
std::string Preferences::docConfigFileName(app::Document* doc)
std::string Preferences::docConfigFileName(const app::Document* doc)
{
if (!doc)
return "";
@ -118,7 +118,7 @@ std::string Preferences::docConfigFileName(app::Document* doc)
return rf.getFirstOrCreateDefault();
}
void Preferences::serializeDocPref(app::Document* doc, app::DocumentPreferences* docPref, bool save)
void Preferences::serializeDocPref(const app::Document* doc, app::DocumentPreferences* docPref, bool save)
{
bool specific_file = false;

View File

@ -42,18 +42,18 @@ namespace app {
void save();
ToolPreferences& tool(tools::Tool* tool);
DocumentPreferences& document(app::Document* doc);
DocumentPreferences& document(const app::Document* doc);
protected:
void onRemoveDocument(doc::Document* doc) override;
private:
std::string docConfigFileName(app::Document* doc);
std::string docConfigFileName(const app::Document* doc);
void serializeDocPref(app::Document* doc, app::DocumentPreferences* docPref, bool save);
void serializeDocPref(const app::Document* doc, app::DocumentPreferences* docPref, bool save);
std::map<std::string, app::ToolPreferences*> m_tools;
std::map<app::Document*, app::DocumentPreferences*> m_docs;
std::map<const app::Document*, app::DocumentPreferences*> m_docs;
};
} // namespace app

View File

@ -672,8 +672,11 @@ void Tabs::startDrag()
void Tabs::stopDrag()
{
m_isDragging = false;
m_selected->oldX = m_selected->x;
m_selected->oldWidth = m_selected->width;
if (m_selected) {
m_selected->oldX = m_selected->x;
m_selected->oldWidth = m_selected->width;
}
resetOldPositions(double(m_ani_t) / double(m_ani_T));
updateTabs();

View File

@ -1079,7 +1079,8 @@ void Timeline::drawClipboardRange(ui::Graphics* g)
m_clipboard_timer.start();
CheckedDrawMode checked(g, m_offset_count);
g->drawRect(0, getRangeBounds(clipboard_range));
g->drawRect(gfx::rgba(0, 0, 0),
getRangeBounds(clipboard_range));
}
void Timeline::drawTop(ui::Graphics* g)
@ -1196,6 +1197,17 @@ void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx)
(hotlayer && m_hot.part == PART_LAYER_TEXT),
(clklayer && m_clk.part == PART_LAYER_TEXT));
if (layer->isBackground()) {
int s = ui::guiscale();
g->fillRect(
is_active ?
skinTheme()->colors.timelineClickedText():
skinTheme()->colors.timelineNormalText(),
gfx::Rect(bounds.x+4*s,
bounds.y+bounds.h-2*s,
getFont()->textLength(layer->name().c_str()), s));
}
// If this layer wasn't clicked but there are another layer clicked,
// we have to draw some indicators to show that the user can move
// layers.

View File

@ -208,7 +208,7 @@ void clipboard::copy_range(const ContextReader& reader, const DocumentRange& ran
clipboard_range.setRange(writer.document(), range);
// TODO Replace this with a signal, because here the timeline
// depends on the clipboard and the clipboard of the timeline.
// depends on the clipboard and the clipboard on the timeline.
App::instance()->getMainWindow()
->getTimeline()->activateClipboardRange();
}
@ -372,14 +372,20 @@ void clipboard::paste()
if (lastCel && maxFrame < lastCel->frame())
maxFrame = lastCel->frame();
}
if (dstSpr->totalFrames() < maxFrame+1)
api.setTotalFrames(dstSpr, maxFrame+1);
while (dstSpr->totalFrames() < maxFrame+1)
api.addEmptyFrame(dstSpr, dstSpr->totalFrames());
for (LayerIndex i = srcRange.layerBegin(); i <= srcRange.layerEnd(); ++i) {
Layer* afterThis;
if (srcLayers[i]->isBackground() &&
!dstDoc->sprite()->backgroundLayer()) {
afterThis = nullptr;
}
else
afterThis = dstSpr->folder()->getLastLayer();
LayerImage* newLayer = new LayerImage(dstSpr);
api.addLayer(
dstSpr->folder(), newLayer,
dstSpr->folder()->getLastLayer());
api.addLayer(dstSpr->folder(), newLayer, afterThis);
srcDoc->copyLayerContent(
srcLayers[i], dstDoc, newLayer);

View File

@ -1,5 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2001-2014 David Capello
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -12,7 +12,6 @@
#include "base/path.h"
#include "doc/context.h"
#include "doc/export_data.h"
#include "doc/sprite.h"
namespace doc {
@ -69,11 +68,6 @@ void Document::setFilename(const std::string& filename)
notifyObservers(&DocumentObserver::onFileNameChanged, this);
}
void Document::setExportData(const ExportDataPtr& data)
{
m_exportData = data;
}
void Document::close()
{
removeFromContext();

View File

@ -1,5 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2001-2014 David Capello
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -13,14 +13,12 @@
#include "base/observable.h"
#include "base/unique_ptr.h"
#include "doc/document_observer.h"
#include "doc/export_data.h"
#include "doc/object.h"
#include "doc/sprites.h"
namespace doc {
class Context;
class ExportData;
class Document : public Object
, public base::Observable<DocumentObserver> {
@ -43,10 +41,7 @@ namespace doc {
std::string name() const;
const std::string& filename() const { return m_filename; }
ExportDataPtr exportData() const { return m_exportData; }
void setFilename(const std::string& filename);
void setExportData(const ExportDataPtr& data);
void close();
@ -61,7 +56,6 @@ namespace doc {
std::string m_filename;
Sprites m_sprites;
Context* m_ctx;
ExportDataPtr m_exportData;
};
} // namespace doc

View File

@ -1,62 +0,0 @@
// Aseprite Document Library
// Copyright (c) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef DOC_EXPORT_DATA_H_INCLUDED
#define DOC_EXPORT_DATA_H_INCLUDED
#pragma once
#include "base/shared_ptr.h"
#include "gfx/rect.h"
#include <string>
namespace doc {
class ExportData {
public:
enum Type {
None,
HorizontalStrip,
VerticalStrip,
Matrix,
};
ExportData() : m_type(None) {
m_columns = 0;
m_width = 0;
m_height = 0;
m_bestFit = false;
}
Type type() const { return m_type; }
int columns() const { return m_columns; }
int width() const { return m_width; }
int height() const { return m_height; }
bool bestFit() const { return m_bestFit; }
const std::string& filename() const { return m_filename; }
void setType(Type type) { m_type = type; }
void setColumns(int columns) { m_columns = columns; }
void setWidth(int width) { m_width = width; }
void setHeight(int height) { m_height = height; }
void setBestFit(bool bestFit) { m_bestFit = bestFit; }
void setFilename(const std::string& filename) {
m_filename = filename;
}
private:
Type m_type;
int m_columns;
int m_width;
int m_height;
bool m_bestFit;
std::string m_filename;
};
typedef SharedPtr<ExportData> ExportDataPtr;
} // namespace doc
#endif

View File

@ -25,6 +25,17 @@ FrameTag::FrameTag(frame_t from, frame_t to)
{
}
FrameTag::FrameTag(const FrameTag& other)
: Object(ObjectType::FrameTag)
, m_owner(nullptr)
, m_from(other.m_from)
, m_to(other.m_to)
, m_color(other.m_color)
, m_name(other.m_name)
, m_aniDir(other.m_aniDir)
{
}
FrameTag::~FrameTag()
{
ASSERT(!m_owner);

View File

@ -22,6 +22,7 @@ namespace doc {
class FrameTag : public Object {
public:
FrameTag(frame_t from, frame_t to);
FrameTag(const FrameTag& other);
~FrameTag();
FrameTags* owner() const { return m_owner; }
@ -45,7 +46,8 @@ namespace doc {
std::string m_name;
AniDir m_aniDir;
DISABLE_COPYING(FrameTag);
// Disable operator=
FrameTag& operator=(FrameTag&);
};
} // namespace doc

View File

@ -1,5 +1,5 @@
// Aseprite Render Library
// Copyright (c) 2001-2014 David Capello
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -18,8 +18,7 @@ namespace render {
// Scaled composite
template<class DstTraits, class SrcTraits>
class BlenderHelper
{
class BlenderHelper {
BLEND_COLOR m_blend_color;
color_t m_mask_color;
public:
@ -41,8 +40,7 @@ public:
};
template<>
class BlenderHelper<RgbTraits, GrayscaleTraits>
{
class BlenderHelper<RgbTraits, GrayscaleTraits> {
BLEND_COLOR m_blend_color;
color_t m_mask_color;
public:
@ -66,8 +64,7 @@ public:
};
template<>
class BlenderHelper<RgbTraits, IndexedTraits>
{
class BlenderHelper<RgbTraits, IndexedTraits> {
const Palette* m_pal;
int m_blend_mode;
color_t m_mask_color;
@ -96,6 +93,33 @@ public:
}
};
template<>
class BlenderHelper<IndexedTraits, IndexedTraits> {
int m_blend_mode;
color_t m_mask_color;
public:
BlenderHelper(const Image* src, const Palette* pal, int blend_mode)
{
m_blend_mode = blend_mode;
m_mask_color = src->maskColor();
}
inline void operator()(IndexedTraits::pixel_t& scanline,
const IndexedTraits::pixel_t& dst,
const IndexedTraits::pixel_t& src,
int opacity)
{
if (m_blend_mode == BLEND_MODE_COPY) {
scanline = src;
}
else {
if (src != m_mask_color)
scanline = src;
else
scanline = dst;
}
}
};
template<class DstTraits, class SrcTraits>
static void compose_scaled_image_scale_up(
Image* dst, const Image* src, const Palette* pal,