/** * Updates palette and redraw the screen. */ void app_refresh_screen(const Document* document) { ASSERT(screen != NULL); if (document && document->getSprite()) set_current_palette(document->getSprite()->getCurrentPalette(), false); else set_current_palette(NULL, false); // Invalidate the whole screen. gui::Manager::getDefault()->invalidate(); }
void PaletteSizeCommand::onExecute(Context* context) { ContextReader reader(context); frame_t frame = reader.frame(); Palette palette(*reader.sprite()->palette(frame)); app::gen::PaletteSize window; window.colors()->setTextf("%d", palette.size()); window.openWindowInForeground(); if (window.closer() == window.ok()) { int ncolors = window.colors()->textInt(); if (ncolors == palette.size()) return; palette.resize(MID(1, ncolors, std::numeric_limits<int>::max())); ContextWriter writer(reader); Transaction transaction(context, "Palette Size", ModifyDocument); transaction.execute(new cmd::SetPalette(writer.sprite(), frame, &palette)); transaction.commit(); set_current_palette(&palette, false); ui::Manager::getDefault()->invalidate(); } }
void PaletteSizeCommand::onExecute(Context* context) { ContextWriter writer(context); Sprite* sprite = writer.sprite(); frame_t frame = writer.frame(); Palette palette(*sprite->palette(frame)); app::gen::PaletteSize window; window.colors()->setTextf("%d", palette.size()); window.openWindowInForeground(); if (window.getKiller() == window.ok()) { int ncolors = window.colors()->getTextInt(); if (ncolors == palette.size()) return; palette.resize(MID(1, ncolors, INT_MAX)); Transaction transaction(context, "Palette Size", ModifyDocument); transaction.execute(new cmd::SetPalette(sprite, frame, &palette)); transaction.commit(); set_current_palette(&palette, false); ui::Manager::getDefault()->invalidate(); } }
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); }
// Initializes the application loading the modules, setting the // graphics mode, loading the configuration and resources, etc. App::App(int argc, char* argv[]) : m_configModule(NULL) , m_checkArgs(NULL) , m_loggerModule(NULL) , m_modules(NULL) , m_legacy(NULL) , m_isGui(false) { ASSERT(m_instance == NULL); m_instance = this; for (int i = 0; i < argc; ++i) m_args.push_back(argv[i]); m_configModule = new ConfigModule(); m_checkArgs = new CheckArgs(m_args); m_loggerModule = new LoggerModule(m_checkArgs->isVerbose()); m_modules = new Modules(); m_isGui = !(m_checkArgs->isConsoleOnly()); m_legacy = new LegacyModules(isGui() ? REQUIRE_INTERFACE: 0); // Initialize editors. init_module_editors(); // Register well-known image file types. FileFormatsManager::instance().registerAllFormats(); // init editor cursor Editor::editor_cursor_init(); // Load RenderEngine configuration RenderEngine::loadConfig(); /* custom default palette? */ if (palette_filename) { PRINTF("Loading custom palette file: %s\n", palette_filename); UniquePtr<Palette> pal(Palette::load(palette_filename)); if (pal.get() == NULL) throw base::Exception("Error loading default palette from: %s", static_cast<const char*>(palette_filename)); set_default_palette(pal.get()); } /* set system palette to the default one */ set_current_palette(NULL, true); }
void update_screen_for_document(Document* document) { // Without document. if (!document) { // Well, change to the default palette. if (set_current_palette(NULL, false)) { // If the palette changes, refresh the whole screen. Manager::getDefault()->invalidate(); } } // With a document. else { document->notifyGeneralUpdate(); // Update the tabs (maybe the modified status has been changed). app_rebuild_documents_tabs(); } }
void onChangeAction() { Item* item = static_cast<Item*>( actions()->getSelectedChild()); if (m_document && m_document->undoHistory()->currentState() != item->state()) { try { DocumentWriter writer(m_document, 100); m_document->undoHistory()->moveToState(item->state()); m_document->generateMaskBoundaries(); // TODO this should be an observer of the current document palette set_current_palette(m_document->sprite()->palette(m_frame), false); m_document->notifyGeneralUpdate(); } catch (const std::exception& ex) { selectState(m_document->undoHistory()->currentState()); Console::showException(ex); } } }
void ColorQuantizationCommand::onExecute(Context* context) { try { ContextWriter writer(UIContext::instance(), 500); Sprite* sprite = writer.sprite(); frame_t frame = writer.frame(); if (sprite) { PalettePicks entries; ColorBar::instance()->getPaletteView()->getSelectedEntries(entries); entries.pickAllIfNeeded(); int n = entries.picks(); Palette palette(frame, n); render::create_palette_from_rgb(sprite, frame, &palette); Palette newPalette(*get_current_palette()); int i = 0, j = 0; for (bool state : entries) { if (state) newPalette.setEntry(i, palette.getEntry(j++)); ++i; } Transaction transaction(writer.context(), "Color Quantization", ModifyDocument); transaction.execute(new cmd::SetPalette(sprite, frame, &newPalette)); transaction.commit(); set_current_palette(&newPalette, false); ui::Manager::getDefault()->invalidate(); } } catch (base::Exception& e) { Console::showException(e); } }
void ColorQuantizationCommand::onExecute(Context* context) { try { app::gen::PaletteFromSprite window; PalettePicks entries; Sprite* sprite; frame_t frame; Palette* curPalette; { ContextReader reader(context); Site site = context->activeSite(); sprite = site.sprite(); frame = site.frame(); curPalette = sprite->palette(frame); window.newPalette()->setSelected(true); window.alphaChannel()->setSelected( App::instance()->preferences().quantization.withAlpha()); window.ncolors()->setText("256"); ColorBar::instance()->getPaletteView()->getSelectedEntries(entries); if (entries.picks() > 1) { window.currentRange()->setTextf( "%s, %d color(s)", window.currentRange()->text().c_str(), entries.picks()); } else window.currentRange()->setEnabled(false); window.currentPalette()->setTextf( "%s, %d color(s)", window.currentPalette()->text().c_str(), curPalette->size()); } window.openWindowInForeground(); if (window.closer() != window.ok()) return; bool withAlpha = window.alphaChannel()->isSelected(); App::instance()->preferences().quantization.withAlpha(withAlpha); bool createPal = false; if (window.newPalette()->isSelected()) { int n = window.ncolors()->textInt(); n = MAX(1, n); entries = PalettePicks(n); entries.all(); createPal = true; } else if (window.currentPalette()->isSelected()) { entries.all(); } if (entries.picks() == 0) return; Palette tmpPalette(frame, entries.picks()); ColorQuantizationJob job(sprite, withAlpha, &tmpPalette); job.startJob(); job.waitJob(); if (job.isCanceled()) return; base::UniquePtr<Palette> newPalette( new Palette(createPal ? tmpPalette: *get_current_palette())); if (createPal) { entries = PalettePicks(newPalette->size()); entries.all(); } int i = 0, j = 0; for (bool state : entries) { if (state) newPalette->setEntry(i, tmpPalette.getEntry(j++)); ++i; } if (*curPalette != *newPalette) { ContextWriter writer(UIContext::instance(), 500); Transaction transaction(writer.context(), "Color Quantization", ModifyDocument); transaction.execute(new cmd::SetPalette(sprite, frame, newPalette.get())); transaction.commit(); set_current_palette(newPalette.get(), false); ui::Manager::getDefault()->invalidate(); } } catch (base::Exception& e) { Console::showException(e); } }
void set_black_palette() { Palette* p = new Palette(FrameNumber(0), 256); set_current_palette(p, true); delete p; }
void AddColorCommand::onExecute(Context* ctx) { app::Color appColor; switch (m_source) { case Source::Fg: appColor = ColorBar::instance()->getFgColor(); break; case Source::Bg: appColor = ColorBar::instance()->getBgColor(); break; case Source::Color: appColor = m_color; break; } try { Palette* newPalette = get_current_palette(); // System current pal color_t color = doc::rgba( appColor.getRed(), appColor.getGreen(), appColor.getBlue(), appColor.getAlpha()); int index = newPalette->findExactMatch( appColor.getRed(), appColor.getGreen(), appColor.getBlue(), appColor.getAlpha(), -1); // It should be -1, because the user has pressed the warning // button that is available only when the color isn't in the // palette. ASSERT(index < 0); if (index >= 0) return; ContextWriter writer(ctx, 500); Doc* document(writer.document()); Sprite* sprite = writer.sprite(); if (!document || !sprite) { ASSERT(false); return; } newPalette->addEntry(color); index = newPalette->size()-1; if (document) { frame_t frame = writer.frame(); Tx tx(writer.context(), friendlyName(), ModifyDocument); tx(new cmd::SetPalette(sprite, frame, newPalette)); tx.commit(); } set_current_palette(newPalette, true); ui::Manager::getDefault()->invalidate(); } catch (base::Exception& e) { Console::showException(e); } }
void load_default_palette(const std::string& userDefined) { base::UniquePtr<Palette> pal; // Load specific palette file defined by the user in the command line. std::string palFile = userDefined; if (!palFile.empty()) pal.reset(load_palette(palFile.c_str())); // Load default palette file else { std::string defaultPalName = get_preset_palette_filename( get_default_palette_preset_name(), ".ase"); // If there is no palette in command line, we use the default one. palFile = defaultPalName; if (base::is_file(palFile)) { pal.reset(load_palette(palFile.c_str())); } else { // Migrate old default.gpl to default.ase format palFile = get_preset_palette_filename( get_default_palette_preset_name(), ".gpl"); if (base::is_file(palFile)) { pal.reset(load_palette(palFile.c_str())); // Remove duplicate black entries at the end (as old palettes // contains 256 colors) if (pal && pal->size() == 256) { doc::color_t black = rgba(0, 0, 0, 255); // Get the last non-black entry int i = 0; for (i=pal->size()-1; i>0; --i) { if (pal->getEntry(i) != black) break; } if (i < pal->size()-1) { // Check if there is a black entry in the first entries. bool hasBlack = false; for (int j=0; j<i; ++j) { if (pal->getEntry(j) == black) { hasBlack = true; break; } } if (!hasBlack) ++i; // Leave one black entry // Resize the palette if (i < pal->size()-1) pal->resize(i+1); } } // We could remove the old .gpl file (palFile), but as the // user could be using multiple versions of Aseprite, it's a // good idea to keep both formats (.gpl for Aseprite <= // v1.1-beta5, and .ase for future versions). } // If the default palette file doesn't exist, we copy db32.gpl // as the default one (default.ase). else { ResourceFinder rf; rf.includeDataDir("palettes/db32.gpl"); if (rf.findFirst()) { pal.reset(load_palette(rf.filename().c_str())); } } // Save default.ase file if (pal) { palFile = defaultPalName; save_palette(palFile.c_str(), pal.get(), 0); } } } if (pal) set_default_palette(pal.get()); set_current_palette(nullptr, true); }
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 ColorQuantizationCommand::onExecute(Context* context) { try { app::gen::PaletteFromSprite window; PalettePicks entries; Sprite* sprite; frame_t frame; Palette* curPalette; { ContextReader reader(context); Site site = context->activeSite(); sprite = site.sprite(); frame = site.frame(); curPalette = sprite->palette(frame); window.newPalette()->setSelected(true); window.alphaChannel()->setSelected( App::instance()->preferences().quantization.withAlpha()); window.ncolors()->setText("256"); ColorBar::instance()->getPaletteView()->getSelectedEntries(entries); if (entries.picks() > 1) { window.currentRange()->setTextf( "%s, %d color(s)", window.currentRange()->text().c_str(), entries.picks()); } else window.currentRange()->setEnabled(false); window.currentPalette()->setTextf( "%s, %d color(s)", window.currentPalette()->text().c_str(), curPalette->size()); } window.openWindowInForeground(); if (window.closer() != window.ok()) return; bool withAlpha = window.alphaChannel()->isSelected(); App::instance()->preferences().quantization.withAlpha(withAlpha); bool createPal = false; if (window.newPalette()->isSelected()) { int n = window.ncolors()->textInt(); n = MAX(1, n); entries = PalettePicks(n); entries.all(); createPal = true; } else if (window.currentPalette()->isSelected()) { entries.all(); } if (entries.picks() == 0) return; Palette tmpPalette(frame, entries.picks()); ContextReader reader(context); SpriteJob job(reader, "Color Quantization"); const bool newBlend = Preferences::instance().experimental.newBlend(); job.startJobWithCallback( [sprite, withAlpha, &tmpPalette, &job, newBlend]{ render::create_palette_from_sprite( sprite, 0, sprite->lastFrame(), withAlpha, &tmpPalette, &job, newBlend); // SpriteJob is a render::TaskDelegate }); job.waitJob(); if (job.isCanceled()) return; std::unique_ptr<Palette> newPalette( new Palette(createPal ? tmpPalette: *get_current_palette())); if (createPal) { entries = PalettePicks(newPalette->size()); entries.all(); } int i = 0, j = 0; for (bool state : entries) { if (state) newPalette->setEntry(i, tmpPalette.getEntry(j++)); ++i; } if (*curPalette != *newPalette) job.tx()(new cmd::SetPalette(sprite, frame, newPalette.get())); set_current_palette(newPalette.get(), false); ui::Manager::getDefault()->invalidate(); } catch (const base::Exception& e) { Console::showException(e); } }
/** * Shows the "New Sprite" dialog. */ void NewFileCommand::onExecute(Context* context) { Preferences& pref = Preferences::instance(); int ncolors = get_default_palette()->size(); char buf[1024]; app::Color bg_table[] = { app::Color::fromMask(), app::Color::fromRgb(255, 255, 255), app::Color::fromRgb(0, 0, 0), }; // Load the window widget app::gen::NewSprite window; // Default values: Indexed, 320x240, Background color PixelFormat format = pref.newFile.colorMode(); // Invalid format in config file. if (format != IMAGE_RGB && format != IMAGE_INDEXED && format != IMAGE_GRAYSCALE) { format = IMAGE_INDEXED; } int w = pref.newFile.width(); int h = pref.newFile.height(); int bg = pref.newFile.backgroundColor(); bg = MID(0, bg, 2); // If the clipboard contains an image, we can show the size of the // clipboard as default image size. gfx::Size clipboardSize; if (clipboard::get_image_size(clipboardSize)) { w = clipboardSize.w; h = clipboardSize.h; } window.width()->setTextf("%d", MAX(1, w)); window.height()->setTextf("%d", MAX(1, h)); // Select image-type window.colorMode()->setSelectedItem(format); // Select background color window.bgColor()->setSelectedItem(bg); // Advance options bool advanced = pref.newFile.advanced(); window.advancedCheck()->setSelected(advanced); window.advancedCheck()->Click.connect( base::Bind<void>( [&]{ gfx::Rect bounds = window.bounds(); window.advanced()->setVisible(window.advancedCheck()->isSelected()); window.setBounds(gfx::Rect(window.bounds().origin(), window.sizeHint())); window.layout(); window.manager()->invalidateRect(bounds); })); window.advanced()->setVisible(advanced); if (advanced) window.pixelRatio()->setValue(pref.newFile.pixelRatio()); else window.pixelRatio()->setValue("1:1"); // Open the window window.openWindowInForeground(); if (window.closer() == window.okButton()) { bool ok = false; // Get the options format = (doc::PixelFormat)window.colorMode()->selectedItem(); w = window.width()->textInt(); h = window.height()->textInt(); bg = window.bgColor()->selectedItem(); static_assert(IMAGE_RGB == 0, "RGB pixel format should be 0"); static_assert(IMAGE_INDEXED == 2, "Indexed pixel format should be 2"); format = MID(IMAGE_RGB, format, IMAGE_INDEXED); w = MID(1, w, DOC_SPRITE_MAX_WIDTH); h = MID(1, h, DOC_SPRITE_MAX_HEIGHT); bg = MID(0, bg, 2); // Select the color app::Color color = app::Color::fromMask(); if (bg >= 0 && bg <= 3) { color = bg_table[bg]; ok = true; } if (ok) { // Save the configuration pref.newFile.width(w); pref.newFile.height(h); pref.newFile.colorMode(format); pref.newFile.backgroundColor(bg); pref.newFile.advanced(window.advancedCheck()->isSelected()); pref.newFile.pixelRatio(window.pixelRatio()->getValue()); // Create the new sprite ASSERT(format == IMAGE_RGB || format == IMAGE_GRAYSCALE || format == IMAGE_INDEXED); ASSERT(w > 0 && h > 0); std::unique_ptr<Sprite> sprite(Sprite::createBasicSprite(format, w, h, ncolors)); if (window.advancedCheck()->isSelected()) { sprite->setPixelRatio( base::convert_to<PixelRatio>(window.pixelRatio()->getValue())); } if (sprite->pixelFormat() != IMAGE_GRAYSCALE) get_default_palette()->copyColorsTo(sprite->palette(frame_t(0))); // If the background color isn't transparent, we have to // convert the `Layer 1' in a `Background' if (color.getType() != app::Color::MaskType) { Layer* layer = sprite->root()->firstLayer(); if (layer && layer->isImage()) { LayerImage* layerImage = static_cast<LayerImage*>(layer); layerImage->configureAsBackground(); Image* image = layerImage->cel(frame_t(0))->image(); // TODO Replace this adding a new parameter to color utils Palette oldPal = *get_current_palette(); set_current_palette(get_default_palette(), false); doc::clear_image(image, color_utils::color_for_target(color, ColorTarget( ColorTarget::BackgroundLayer, sprite->pixelFormat(), sprite->transparentColor()))); set_current_palette(&oldPal, false); } } // Show the sprite to the user std::unique_ptr<Doc> doc(new Doc(sprite.get())); sprite.release(); sprintf(buf, "Sprite-%04d", ++_sprite_counter); doc->setFilename(buf); doc->setContext(context); doc.release(); } } }
void UndoCommand::onExecute(Context* context) { ContextWriter writer(context); Doc* document(writer.document()); DocUndo* undo = document->undoHistory(); #ifdef ENABLE_UI Sprite* sprite = document->sprite(); SpritePosition spritePosition; const bool gotoModified = (Preferences::instance().undo.gotoModified() && context->isUIAvailable() && current_editor); if (gotoModified) { SpritePosition currentPosition(writer.site()->layer(), writer.site()->frame()); if (m_type == Undo) spritePosition = undo->nextUndoSpritePosition(); else spritePosition = undo->nextRedoSpritePosition(); if (spritePosition != currentPosition) { Layer* selectLayer = spritePosition.layer(); if (selectLayer) current_editor->setLayer(selectLayer); 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); } } // Get the stream to deserialize the document range after executing // the undo/redo action. We cannot yet deserialize the document // range because there could be inexistent layers. std::istream* docRangeStream; if (m_type == Undo) docRangeStream = undo->nextUndoDocRange(); else docRangeStream = undo->nextRedoDocRange(); StatusBar* statusbar = StatusBar::instance(); if (statusbar) { std::string msg; if (m_type == Undo) msg = "Undid " + undo->nextUndoLabel(); else msg = "Redid " + undo->nextRedoLabel(); if (Preferences::instance().undo.showTooltip()) statusbar->showTip(1000, msg.c_str()); else statusbar->setStatusText(0, msg.c_str()); } #endif // ENABLE_UI // Effectively undo/redo. if (m_type == Undo) undo->undo(); else undo->redo(); #ifdef ENABLE_UI // 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) { Site newSite = context->activeSite(); SpritePosition currentPosition( newSite.layer(), newSite.frame()); if (spritePosition != currentPosition) { Layer* selectLayer = spritePosition.layer(); if (selectLayer) current_editor->setLayer(selectLayer); current_editor->setFrame(spritePosition.frame()); } } // Update timeline range. We've to deserialize the DocRange at // this point when objects (possible layers) are re-created after // the undo and we can deserialize them. if (docRangeStream) { Timeline* timeline = App::instance()->timeline(); if (timeline) { DocRange docRange; if (docRange.read(*docRangeStream)) timeline->setRange(docRange); } } #endif // ENABLE_UI document->generateMaskBoundaries(); document->setExtraCel(ExtraCelRef(nullptr)); #ifdef ENABLE_UI update_screen_for_document(document); #endif set_current_palette(writer.palette(), false); }