diff --git a/data/pref.xml b/data/pref.xml index e702e603e..1c7c7ed7b 100644 --- a/data/pref.xml +++ b/data/pref.xml @@ -177,6 +177,9 @@
+
+
diff --git a/data/widgets/sprite_properties.xml b/data/widgets/sprite_properties.xml index 29214bd28..3c4efc5d3 100644 --- a/data/widgets/sprite_properties.xml +++ b/data/widgets/sprite_properties.xml @@ -1,45 +1,47 @@ - + - + diff --git a/src/app/commands/cmd_sprite_properties.cpp b/src/app/commands/cmd_sprite_properties.cpp index 975d16f5d..16695d9eb 100644 --- a/src/app/commands/cmd_sprite_properties.cpp +++ b/src/app/commands/cmd_sprite_properties.cpp @@ -12,6 +12,7 @@ #include "app/cmd/assign_color_profile.h" #include "app/cmd/convert_color_profile.h" #include "app/cmd/set_pixel_ratio.h" +#include "app/cmd/set_user_data.h" #include "app/color.h" #include "app/commands/command.h" #include "app/context_access.h" @@ -21,11 +22,13 @@ #include "app/pref/preferences.h" #include "app/tx.h" #include "app/ui/color_button.h" +#include "app/ui/user_data_view.h" #include "app/util/pixel_ratio.h" #include "base/mem_utils.h" #include "doc/image.h" #include "doc/palette.h" #include "doc/sprite.h" +#include "doc/user_data.h" #include "fmt/format.h" #include "os/color_space.h" #include "os/system.h" @@ -37,6 +40,37 @@ namespace app { using namespace ui; +class SpritePropertiesWindow : public app::gen::SpriteProperties { +public: + SpritePropertiesWindow(Sprite* sprite) + : SpriteProperties() + , m_sprite(sprite) + , m_userDataView(new gen::UserData(), &Preferences::instance().sprite.userDataVisibility) + { + userData()->Click.connect([this]{ onToggleUserData(); }); + + ui::Grid* mainGrid = propertiesGrid(); + m_userDataView.configureAndSet(m_sprite->userData(), mainGrid); + + remapWindow(); + centerWindow(); + load_window_pos(this, "SpriteProperties"); + manager()->invalidate(); + } + + const UserData& getUserData() const { return m_userDataView.userData(); } + +private: + void onToggleUserData() { + m_userDataView.toggleVisibility(); + remapWindow(); + manager()->invalidate(); + } + + Sprite* m_sprite; + UserDataView m_userDataView; +}; + class SpritePropertiesCommand : public Command { public: SpritePropertiesCommand(); @@ -67,7 +101,8 @@ void SpritePropertiesCommand::onExecute(Context* context) os::instance()->listColorSpaces(colorSpaces); // Load the window widget - app::gen::SpriteProperties window; + SpritePropertiesWindow window(context->activeDocument()->sprite()); + int selectedColorProfile = -1; auto updateButtons = @@ -208,8 +243,11 @@ void SpritePropertiesCommand::onExecute(Context* context) PixelRatio pixelRatio = base::convert_to(window.pixelRatio()->getValue()); + const UserData newUserData = window.getUserData(); + if (index != sprite->transparentColor() || - pixelRatio != sprite->pixelRatio()) { + pixelRatio != sprite->pixelRatio() || + newUserData != sprite->userData()) { Tx tx(writer.context(), "Change Sprite Properties"); DocApi api = writer.document()->getApi(tx); @@ -219,6 +257,9 @@ void SpritePropertiesCommand::onExecute(Context* context) if (pixelRatio != sprite->pixelRatio()) tx(new cmd::SetPixelRatio(sprite, pixelRatio)); + if (newUserData != sprite->userData()) + tx(new cmd::SetUserData(sprite, newUserData, static_cast(sprite->document()))); + tx.commit(); update_screen_for_document(writer.document()); diff --git a/src/app/file/ase_format.cpp b/src/app/file/ase_format.cpp index 7b4f280ff..db18a3a75 100644 --- a/src/app/file/ase_format.cpp +++ b/src/app/file/ase_format.cpp @@ -378,6 +378,10 @@ bool AseFormat::onSave(FileOp* fop) // Write extra chunks in the first frame if (frame == fop->roi().fromFrame()) { + // Write sprite user data only if needed + if (!sprite->userData().isEmpty()) + ase_file_write_user_data_chunk(f, &frame_header, &sprite->userData()); + // Write tilesets ase_file_write_tileset_chunks(f, fop, &frame_header, ext_files, sprite->tilesets()); diff --git a/src/app/ui/browser_view.cpp b/src/app/ui/browser_view.cpp index 360dd12c0..616ae5e28 100644 --- a/src/app/ui/browser_view.cpp +++ b/src/app/ui/browser_view.cpp @@ -560,6 +560,11 @@ TabIcon BrowserView::getTabIcon() return TabIcon::NONE; } +gfx::Color BrowserView::getTabColor() +{ + return gfx::ColorNone; +} + WorkspaceView* BrowserView::cloneWorkspaceView() { return new BrowserView(); diff --git a/src/app/ui/browser_view.h b/src/app/ui/browser_view.h index 849492740..caad3a8e8 100644 --- a/src/app/ui/browser_view.h +++ b/src/app/ui/browser_view.h @@ -25,6 +25,7 @@ namespace app { // TabView implementation std::string getTabText() override; TabIcon getTabIcon() override; + gfx::Color getTabColor() override; // WorkspaceView implementation ui::Widget* getContentWidget() override { return this; } diff --git a/src/app/ui/data_recovery_view.cpp b/src/app/ui/data_recovery_view.cpp index ae66e22d8..72122a129 100644 --- a/src/app/ui/data_recovery_view.cpp +++ b/src/app/ui/data_recovery_view.cpp @@ -378,6 +378,11 @@ TabIcon DataRecoveryView::getTabIcon() return TabIcon::NONE; } +gfx::Color DataRecoveryView::getTabColor() +{ + return gfx::ColorNone; +} + void DataRecoveryView::onWorkspaceViewSelected() { // Do nothing diff --git a/src/app/ui/data_recovery_view.h b/src/app/ui/data_recovery_view.h index c28c2ceb8..e5773da92 100644 --- a/src/app/ui/data_recovery_view.h +++ b/src/app/ui/data_recovery_view.h @@ -37,6 +37,7 @@ namespace app { // TabView implementation std::string getTabText() override; TabIcon getTabIcon() override; + gfx::Color getTabColor() override; // WorkspaceView implementation ui::Widget* getContentWidget() override { return this; } diff --git a/src/app/ui/devconsole_view.cpp b/src/app/ui/devconsole_view.cpp index d5626947a..128e16fe3 100644 --- a/src/app/ui/devconsole_view.cpp +++ b/src/app/ui/devconsole_view.cpp @@ -113,6 +113,11 @@ TabIcon DevConsoleView::getTabIcon() return TabIcon::NONE; } +gfx::Color DevConsoleView::getTabColor() +{ + return gfx::ColorNone; +} + WorkspaceView* DevConsoleView::cloneWorkspaceView() { return new DevConsoleView(); diff --git a/src/app/ui/devconsole_view.h b/src/app/ui/devconsole_view.h index c26eaf751..a368e2fa4 100644 --- a/src/app/ui/devconsole_view.h +++ b/src/app/ui/devconsole_view.h @@ -32,6 +32,7 @@ namespace app { // TabView implementation std::string getTabText() override; TabIcon getTabIcon() override; + gfx::Color getTabColor() override; // WorkspaceView implementation ui::Widget* getContentWidget() override { return this; } diff --git a/src/app/ui/doc_view.cpp b/src/app/ui/doc_view.cpp index c06c647c2..e13eefb2f 100644 --- a/src/app/ui/doc_view.cpp +++ b/src/app/ui/doc_view.cpp @@ -38,6 +38,7 @@ #include "app/util/clipboard.h" #include "app/util/range_utils.h" #include "base/fs.h" +#include "doc/color.h" #include "doc/layer.h" #include "doc/sprite.h" #include "fmt/format.h" @@ -234,6 +235,12 @@ TabIcon DocView::getTabIcon() return TabIcon::NONE; } +gfx::Color DocView::getTabColor() +{ + color_t c = m_editor->sprite()->userData().color(); + return gfx::rgba(doc::rgba_getr(c), doc::rgba_getg(c), doc::rgba_getb(c), doc::rgba_geta(c)); +} + WorkspaceView* DocView::cloneWorkspaceView() { return new DocView(m_document, Normal, m_previewDelegate); diff --git a/src/app/ui/doc_view.h b/src/app/ui/doc_view.h index 5a8449d25..1dce2ff8a 100644 --- a/src/app/ui/doc_view.h +++ b/src/app/ui/doc_view.h @@ -58,6 +58,7 @@ namespace app { // TabView implementation std::string getTabText() override; TabIcon getTabIcon() override; + gfx::Color getTabColor() override; // WorkspaceView implementation ui::Widget* getContentWidget() override { return this; } diff --git a/src/app/ui/home_view.cpp b/src/app/ui/home_view.cpp index f8b8e82cc..3d6a1b012 100644 --- a/src/app/ui/home_view.cpp +++ b/src/app/ui/home_view.cpp @@ -111,6 +111,11 @@ TabIcon HomeView::getTabIcon() return TabIcon::HOME; } +gfx::Color HomeView::getTabColor() +{ + return gfx::ColorNone; +} + bool HomeView::onCloseView(Workspace* workspace, bool quitting) { workspace->removeView(this); diff --git a/src/app/ui/home_view.h b/src/app/ui/home_view.h index a6f071a86..53793e4cd 100644 --- a/src/app/ui/home_view.h +++ b/src/app/ui/home_view.h @@ -49,6 +49,7 @@ namespace app { // TabView implementation std::string getTabText() override; TabIcon getTabIcon() override; + gfx::Color getTabColor() override; // WorkspaceView implementation ui::Widget* getContentWidget() override { return this; } diff --git a/src/app/ui/tabs.cpp b/src/app/ui/tabs.cpp index 26e793b9d..d14eeed69 100644 --- a/src/app/ui/tabs.cpp +++ b/src/app/ui/tabs.cpp @@ -174,6 +174,7 @@ void Tabs::updateTabs() tab->text = tab->view->getTabText(); tab->icon = tab->view->getTabIcon(); + tab->color = tab->view->getTabColor(); tab->x = int(x); tab->width = int(x+tabWidth) - int(x); x += tabWidth; @@ -626,6 +627,10 @@ void Tabs::drawTab(Graphics* g, const gfx::Rect& _box, // Tab with text + clipping the close button if (box.w > 8*ui::guiscale()) { info.text = &tab->text; + if (tab->color != gfx::ColorNone) { + g->fillRect(tab->color, gfx::Rect(box.x+dx+2, box.y+dy+3, box.w-dx-2, box.h-3)); + g->fillRect(tab->color, gfx::Rect(box.x+dx+3, box.y+dy+2, box.w-dx-3, 1)); + } theme->paintWidgetPart( g, theme->styles.tabText(), gfx::Rect(box.x+dx, box.y+dy, box.w-dx, box.h), @@ -656,6 +661,11 @@ void Tabs::drawTab(Graphics* g, const gfx::Rect& _box, } } + if (tab->color != gfx::ColorNone) { + g->fillRect(tab->color, gfx::Rect(closeBox.x, closeBox.y+3, closeBox.w-3, closeBox.h-3)); + g->fillRect(tab->color, gfx::Rect(closeBox.x, closeBox.y+2, closeBox.w-4, 1)); + } + info.styleFlags = 0; if (selected) info.styleFlags |= ui::Style::Layer::kFocus; diff --git a/src/app/ui/tabs.h b/src/app/ui/tabs.h index 4ca1bec5c..c0bdb9c80 100644 --- a/src/app/ui/tabs.h +++ b/src/app/ui/tabs.h @@ -41,6 +41,9 @@ namespace app { // Returns the icon to be shown in the tab virtual TabIcon getTabIcon() = 0; + + // Returns the tab background color + virtual gfx::Color getTabColor() = 0; }; enum class DropTabResult { @@ -116,6 +119,7 @@ namespace app { TabView* view; std::string text; TabIcon icon; + gfx::Color color; int x, width; int oldX, oldWidth; bool modified; @@ -124,6 +128,7 @@ namespace app { ASSERT(view); text = view->getTabText(); icon = view->getTabIcon(); + color = view->getTabColor(); x = width = oldX = oldWidth = #if _DEBUG diff --git a/src/dio/aseprite_decoder.cpp b/src/dio/aseprite_decoder.cpp index 5337dc3fc..39099ab04 100644 --- a/src/dio/aseprite_decoder.cpp +++ b/src/dio/aseprite_decoder.cpp @@ -82,7 +82,7 @@ bool AsepriteDecoder::decode() // Prepare variables for layer chunks doc::Layer* last_layer = sprite->root(); - doc::WithUserData* last_object_with_user_data = nullptr; + doc::WithUserData* last_object_with_user_data = sprite.get(); doc::Cel* last_cel = nullptr; auto tag_it = sprite->tags().begin(); auto tag_end = sprite->tags().end(); diff --git a/src/doc/sprite.cpp b/src/doc/sprite.cpp index 30296ea17..20c46bb14 100644 --- a/src/doc/sprite.cpp +++ b/src/doc/sprite.cpp @@ -66,7 +66,7 @@ void Sprite::SetDefaultRgbMapAlgorithm(const RgbMapAlgorithm mapAlgo) Sprite::Sprite(const ImageSpec& spec, int ncolors) - : Object(ObjectType::Sprite) + : WithUserData(ObjectType::Sprite) , m_document(nullptr) , m_spec(spec) , m_pixelRatio(1, 1) diff --git a/src/doc/sprite.h b/src/doc/sprite.h index 90f1ca1c7..74c490f1e 100644 --- a/src/doc/sprite.h +++ b/src/doc/sprite.h @@ -24,6 +24,7 @@ #include "doc/rgbmap_algorithm.h" #include "doc/slices.h" #include "doc/tags.h" +#include "doc/with_user_data.h" #include "gfx/rect.h" #include @@ -52,7 +53,7 @@ namespace doc { typedef std::vector PalettesList; // The main structure used in the whole program to handle a sprite. - class Sprite : public Object { + class Sprite : public WithUserData { public: enum class RgbMapFor { OpaqueLayer,