aseprite/src/app/commands/cmd_select_tile.cpp
David Capello 32a099dcb6 Fix crashes with ill-formed fmt format strings (fix #2274)
There is a third-party translation (and can happen with our own
translations) that a fmt format string is ill-formed in the .ini file
of the translation (this could happen even if the en.ini file was
manually modified/broken by hand).

This patch includes a refactor of the Strings class so we can:

1) Static check at compile-time about the number of required arguments
   to format a string (no need to call fmt::format() directly with
   arbitrary number of args)
2) If a string is not valid for the fmt library, the runtime exception
   is caught and the default (English) string is returned.
2024-06-20 20:49:10 -03:00

138 lines
3.2 KiB
C++

// Aseprite
// Copyright (C) 2018-2024 Igara Studio S.A.
// Copyright (C) 2015-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/cmd/set_mask.h"
#include "app/commands/command.h"
#include "app/context_access.h"
#include "app/doc.h"
#include "app/i18n/strings.h"
#include "app/modules/gui.h"
#include "app/snap_to_grid.h"
#include "app/tx.h"
#include "app/ui/editor/editor.h"
#include "doc/mask.h"
#include "ui/system.h"
namespace app {
using namespace doc;
class SelectTileCommand : public Command {
public:
SelectTileCommand();
protected:
void onLoadParams(const Params& params) override;
bool onEnabled(Context* ctx) override;
void onExecute(Context* ctx) override;
std::string onGetFriendlyName() const override;
private:
gen::SelectionMode m_mode;
};
SelectTileCommand::SelectTileCommand()
: Command(CommandId::SelectTile(), CmdRecordableFlag)
, m_mode(gen::SelectionMode::DEFAULT)
{
}
void SelectTileCommand::onLoadParams(const Params& params)
{
std::string mode = params.get("mode");
if (mode == "add")
m_mode = gen::SelectionMode::ADD;
else if (mode == "subtract")
m_mode = gen::SelectionMode::SUBTRACT;
else if (mode == "intersect")
m_mode = gen::SelectionMode::INTERSECT;
else
m_mode = gen::SelectionMode::DEFAULT;
}
bool SelectTileCommand::onEnabled(Context* ctx)
{
return ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable);
}
void SelectTileCommand::onExecute(Context* ctx)
{
auto editor = Editor::activeEditor();
if (!editor ||
!editor->hasMouse())
return;
// Lock sprite
ContextWriter writer(ctx);
Doc* doc(writer.document());
std::unique_ptr<Mask> mask(new Mask());
if (m_mode != gen::SelectionMode::DEFAULT)
mask->copyFrom(doc->mask());
{
gfx::Rect gridBounds = writer.site()->gridBounds();
gfx::Point pos = editor->screenToEditor(editor->mousePosInDisplay());
pos = snap_to_grid(gridBounds, pos, PreferSnapTo::BoxOrigin);
gridBounds.setOrigin(pos);
switch (m_mode) {
case gen::SelectionMode::DEFAULT:
case gen::SelectionMode::ADD:
mask->add(gridBounds);
break;
case gen::SelectionMode::SUBTRACT:
mask->subtract(gridBounds);
break;
case gen::SelectionMode::INTERSECT:
mask->intersect(gridBounds);
break;
}
}
// Set the new mask
Tx tx(writer,
friendlyName(),
DoesntModifyDocument);
tx(new cmd::SetMask(doc, mask.get()));
tx.commit();
update_screen_for_document(doc);
}
std::string SelectTileCommand::onGetFriendlyName() const
{
std::string text;
switch (m_mode) {
case gen::SelectionMode::ADD:
text = Strings::commands_SelectTile_Add();
break;
case gen::SelectionMode::SUBTRACT:
text = Strings::commands_SelectTile_Subtract();
break;
case gen::SelectionMode::INTERSECT:
text = Strings::commands_SelectTile_Intersect();
break;
default:
text = Strings::commands_SelectTile();
break;
}
return text;
}
Command* CommandFactory::createSelectTileCommand()
{
return new SelectTileCommand;
}
} // namespace app