Fix crashes saving sprites with '%' char in their filename

To fix this we changed the way StatusBar text is handled (we are using
fmt::format() in StatusBar instead of printf-like ... args now).
This commit is contained in:
David Capello 2020-05-08 17:39:55 -03:00
parent 6e4b96f548
commit 46f4002368
22 changed files with 165 additions and 139 deletions

View File

@ -101,7 +101,7 @@ void FlipCommand::onExecute(Context* ctx)
if (cels.empty()) { if (cels.empty()) {
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, Strings::statusbar_tips_all_layers_are_locked().c_str()); 1000, Strings::statusbar_tips_all_layers_are_locked());
return; return;
} }
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -18,6 +19,7 @@
#include "app/ui/timeline/timeline.h" #include "app/ui/timeline/timeline.h"
#include "doc/layer.h" #include "doc/layer.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "fmt/format.h"
namespace app { namespace app {
@ -73,9 +75,9 @@ protected:
void updateStatusBar(Site& site) { void updateStatusBar(Site& site) {
if (site.layer() != NULL) if (site.layer() != NULL)
StatusBar::instance()->setStatusText( StatusBar::instance()->setStatusText(
1000, "%s '%s' selected", 1000, fmt::format("{} '{}' selected",
(site.layer()->isGroup() ? "Group": "Layer"), (site.layer()->isGroup() ? "Group": "Layer"),
site.layer()->name().c_str()); site.layer()->name()));
} }
private: private:

View File

@ -175,7 +175,7 @@ void NewBrushCommand::createBrush(const Site& site, const Mask* mask)
std::string tooltip; std::string tooltip;
tooltip += "Shortcut: "; tooltip += "Shortcut: ";
tooltip += key->accels().front().toString(); tooltip += key->accels().front().toString();
StatusBar::instance()->showTip(2000, tooltip.c_str()); StatusBar::instance()->showTip(2000, tooltip);
} }
} }

View File

@ -172,10 +172,10 @@ void NewFrameCommand::onExecute(Context* context)
if (context->isUIAvailable()) { if (context->isUIAvailable()) {
update_screen_for_document(document); update_screen_for_document(document);
StatusBar::instance() StatusBar::instance()->showTip(
->showTip(1000, "New frame %d/%d", 1000, fmt::format("New frame {}/{}",
(int)context->activeSite().frame()+1, (int)context->activeSite().frame()+1,
(int)sprite->totalFrames()); (int)sprite->totalFrames()));
App::instance()->mainWindow()->popTimeline(); App::instance()->mainWindow()->popTimeline();
} }

View File

@ -421,9 +421,9 @@ void NewLayerCommand::onExecute(Context* context)
StatusBar::instance()->invalidate(); StatusBar::instance()->invalidate();
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, "%s '%s' created", 1000, fmt::format("{} '{}' created",
layerPrefix().c_str(), layerPrefix(),
name.c_str()); name));
App::instance()->mainWindow()->popTimeline(); App::instance()->mainWindow()->popTimeline();
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -11,6 +12,7 @@
#include "app/app.h" #include "app/app.h"
#include "app/commands/command.h" #include "app/commands/command.h"
#include "app/ui/status_bar.h" #include "app/ui/status_bar.h"
#include "fmt/format.h"
#include "ui/scale.h" #include "ui/scale.h"
#include "ui/system.h" #include "ui/system.h"
#include "ui/theme.h" #include "ui/theme.h"
@ -47,12 +49,12 @@ void RefreshCommand::onExecute(Context* context)
{ {
PROCESS_MEMORY_COUNTERS pmc; PROCESS_MEMORY_COUNTERS pmc;
if (::GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { if (::GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
StatusBar::instance() StatusBar::instance()->showTip(
->showTip(1000, 1000,
"Current memory: %.16g KB (%lu)\n" fmt::format("Current memory: {:.2f} MB ({})\n"
"Peak of memory: %.16g KB (%lu)", "Peak of memory: {:.2f} MB ({})",
pmc.WorkingSetSize / 1024.0, pmc.WorkingSetSize, pmc.WorkingSetSize / 1024.0 / 1024.0, pmc.WorkingSetSize,
pmc.PeakWorkingSetSize / 1024.0, pmc.PeakWorkingSetSize); pmc.PeakWorkingSetSize / 1024.0 / 1024.0, pmc.PeakWorkingSetSize));
} }
} }
#endif #endif

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -18,6 +19,7 @@
#include "app/ui/status_bar.h" #include "app/ui/status_bar.h"
#include "doc/layer.h" #include "doc/layer.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "fmt/format.h"
#include "ui/alert.h" #include "ui/alert.h"
#include "ui/widget.h" #include "ui/widget.h"
@ -95,7 +97,7 @@ void RemoveLayerCommand::onExecute(Context* context)
StatusBar::instance()->invalidate(); StatusBar::instance()->invalidate();
if (!layerName.empty()) if (!layerName.empty())
StatusBar::instance()->showTip(1000, "Layer '%s' removed", layerName.c_str()); StatusBar::instance()->showTip(1000, fmt::format("Layer '{}' removed", layerName));
else else
StatusBar::instance()->showTip(1000, "Layers removed"); StatusBar::instance()->showTip(1000, "Layers removed");
} }

View File

@ -21,6 +21,7 @@
#include "doc/selected_objects.h" #include "doc/selected_objects.h"
#include "doc/slice.h" #include "doc/slice.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "fmt/format.h"
#include "ui/alert.h" #include "ui/alert.h"
#include "ui/widget.h" #include "ui/widget.h"
@ -121,10 +122,10 @@ void RemoveSliceCommand::onExecute(Context* context)
StatusBar::instance()->invalidate(); StatusBar::instance()->invalidate();
if (!sliceName.empty()) if (!sliceName.empty())
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, "Slice '%s' removed", sliceName.c_str()); 1000, fmt::format("Slice '{}' removed", sliceName));
else else
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, "%d slice(s) removed", slicesToDelete.size()); 1000, fmt::format("{} slice(s) removed", slicesToDelete.size()));
} }
Command* CommandFactory::createRemoveSliceCommand() Command* CommandFactory::createRemoveSliceCommand()

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -223,7 +223,7 @@ void RotateCommand::onExecute(Context* context)
if (cels.empty()) { if (cels.empty()) {
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, Strings::statusbar_tips_all_layers_are_locked().c_str()); 1000, Strings::statusbar_tips_all_layers_are_locked());
return; return;
} }
} }

View File

@ -248,9 +248,9 @@ void SaveFileBaseCommand::saveDocumentInBackground(
document->incrementVersion(); document->incrementVersion();
} }
#ifdef ENABLE_UI #ifdef ENABLE_UI
StatusBar::instance() StatusBar::instance()->setStatusText(
->setStatusText(2000, "File <%s> saved.", 2000, fmt::format("File <{}> saved.",
base::get_file_name(filename).c_str()); base::get_file_name(filename)));
#endif #endif
} }
} }

View File

@ -116,9 +116,9 @@ void UndoCommand::onExecute(Context* context)
else else
msg = "Redid " + undo->nextRedoLabel(); msg = "Redid " + undo->nextRedoLabel();
if (Preferences::instance().undo.showTooltip()) if (Preferences::instance().undo.showTooltip())
statusbar->showTip(1000, msg.c_str()); statusbar->showTip(1000, msg);
else else
statusbar->setStatusText(0, msg.c_str()); statusbar->setStatusText(0, msg);
} }
#endif // ENABLE_UI #endif // ENABLE_UI

View File

@ -327,9 +327,9 @@ bool DocView::onCloseView(Workspace* workspace, bool quitting)
DocDestroyer destroyer( DocDestroyer destroyer(
static_cast<app::Context*>(m_document->context()), m_document, 500); static_cast<app::Context*>(m_document->context()), m_document, 500);
StatusBar::instance() StatusBar::instance()->setStatusText(
->setStatusText(0, "Sprite '%s' closed.", 0, fmt::format("Sprite '{}' closed.",
m_document->name().c_str()); m_document->name()));
// Just close the document (so we can reopen it with // Just close the document (so we can reopen it with
// ReopenClosedFile command). // ReopenClosedFile command).

View File

@ -28,6 +28,7 @@
#include "doc/layer.h" #include "doc/layer.h"
#include "doc/mask.h" #include "doc/mask.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "fmt/format.h"
#include "ui/message.h" #include "ui/message.h"
#include <algorithm> #include <algorithm>
@ -289,29 +290,31 @@ bool MovingCelState::onUpdateStatusBar(Editor* editor)
if (m_hasReference) { if (m_hasReference) {
if (m_scaled && m_cel) { if (m_scaled && m_cel) {
StatusBar::instance()->setStatusText StatusBar::instance()->setStatusText(
(0, 0,
":pos: %.2f %.2f :offset: %.2f %.2f :size: %.2f%% %.2f%%", fmt::format(
pos.x, pos.y, ":pos: {:.2f} {:.2f} :offset: {:.2f} {:.2f} :size: {:.2f}% {:.2f}%",
m_celOffset.x, m_celOffset.y, pos.x, pos.y,
100.0*m_celScale.w*m_celMainSize.w/m_cel->image()->width(), m_celOffset.x, m_celOffset.y,
100.0*m_celScale.h*m_celMainSize.h/m_cel->image()->height()); 100.0*m_celScale.w*m_celMainSize.w/m_cel->image()->width(),
100.0*m_celScale.h*m_celMainSize.h/m_cel->image()->height()));
} }
else { else {
StatusBar::instance()->setStatusText StatusBar::instance()->setStatusText(
(0, 0,
":pos: %.2f %.2f :offset: %.2f %.2f", fmt::format(
pos.x, pos.y, ":pos: {:.2f} {:.2f} :offset: {:.2f} {:.2f}",
m_celOffset.x, m_celOffset.y); pos.x, pos.y,
m_celOffset.x, m_celOffset.y));
} }
} }
else { else {
gfx::Point intOffset = intCelOffset(); gfx::Point intOffset = intCelOffset();
StatusBar::instance()->setStatusText StatusBar::instance()->setStatusText(
(0, 0,
":pos: %3d %3d :offset: %3d %3d", fmt::format(":pos: {:3d} {:3d} :offset: {:3d} {:3d}",
int(pos.x), int(pos.y), int(pos.x), int(pos.y),
intOffset.x, intOffset.y); intOffset.x, intOffset.y));
} }
return true; return true;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -41,6 +41,7 @@
#include "doc/algorithm/flip_image.h" #include "doc/algorithm/flip_image.h"
#include "doc/mask.h" #include "doc/mask.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "fmt/format.h"
#include "gfx/rect.h" #include "gfx/rect.h"
#include "ui/manager.h" #include "ui/manager.h"
#include "ui/message.h" #include "ui/message.h"
@ -491,19 +492,21 @@ bool MovingPixelsState::onUpdateStatusBar(Editor* editor)
int w = int(transform.bounds().w); int w = int(transform.bounds().w);
int h = int(transform.bounds().h); int h = int(transform.bounds().h);
int gcd = base::gcd(w, h); int gcd = base::gcd(w, h);
StatusBar::instance()->setStatusText StatusBar::instance()->setStatusText(
(100, ":pos: %d %d :size: %3d %3d :selsize: %d %d [%.02f%% %.02f%%] :angle: %.1f :aspect_ratio: %d:%d", 100,
int(transform.bounds().x), fmt::format(
int(transform.bounds().y), ":pos: {} {} :size: {:3d} {:3d} :selsize: {} {} [{:.02f}% {:.02f}%] :angle: {:.1f} :aspect_ratio: {}:{}",
imageSize.w, int(transform.bounds().x),
imageSize.h, int(transform.bounds().y),
w, imageSize.w,
h, imageSize.h,
(double)w*100.0/imageSize.w, w,
(double)h*100.0/imageSize.h, h,
180.0 * transform.angle() / PI, (double)w*100.0/imageSize.w,
w/gcd, (double)h*100.0/imageSize.h,
h/gcd); 180.0 * transform.angle() / PI,
w/gcd,
h/gcd));
return true; return true;
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2017-2018 David Capello // Copyright (C) 2017-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -20,6 +20,7 @@
#include "app/ui_context.h" #include "app/ui_context.h"
#include "app/ui_context.h" #include "app/ui_context.h"
#include "doc/mask.h" #include "doc/mask.h"
#include "fmt/format.h"
#include "ui/message.h" #include "ui/message.h"
namespace app { namespace app {
@ -132,11 +133,13 @@ bool MovingSelectionState::onUpdateStatusBar(Editor* editor)
{ {
const gfx::Rect bounds = editor->document()->mask()->bounds(); const gfx::Rect bounds = editor->document()->mask()->bounds();
StatusBar::instance()->setStatusText StatusBar::instance()->setStatusText(
(100, ":pos: %d %d :size: %3d %3d :offset: %d %d", 100,
bounds.x, bounds.y, fmt::format(
bounds.w, bounds.h, ":pos: {} {} :size: {:3d} {:3d} :offset: {} {}",
m_delta.x, m_delta.y); bounds.x, bounds.y,
bounds.w, bounds.h,
m_delta.x, m_delta.y));
return true; return true;
} }

View File

@ -14,6 +14,7 @@
#include "app/ui/editor/editor.h" #include "app/ui/editor/editor.h"
#include "app/ui/status_bar.h" #include "app/ui/status_bar.h"
#include "base/clamp.h" #include "base/clamp.h"
#include "fmt/format.h"
#include "ui/message.h" #include "ui/message.h"
#include <cmath> #include <cmath>
@ -70,13 +71,15 @@ bool MovingSymmetryState::onMouseMove(Editor* editor, MouseMessage* msg)
bool MovingSymmetryState::onUpdateStatusBar(Editor* editor) bool MovingSymmetryState::onUpdateStatusBar(Editor* editor)
{ {
if (m_symmetryMode == app::gen::SymmetryMode::HORIZONTAL) if (m_symmetryMode == app::gen::SymmetryMode::HORIZONTAL)
StatusBar::instance()->setStatusText StatusBar::instance()->setStatusText(
(0, "Left %3.1f Right %3.1f", m_symmetryAxis(), 0, fmt::format("Left {:3.1f} Right {:3.1f}",
double(editor->sprite()->width()) - m_symmetryAxis()); m_symmetryAxis(),
double(editor->sprite()->width()) - m_symmetryAxis()));
else else
StatusBar::instance()->setStatusText StatusBar::instance()->setStatusText(
(0, "Top %3.1f Bottom %3.1f", m_symmetryAxis(), 0, fmt::format("Top {:3.1f} Bottom {:3.1f}",
double(editor->sprite()->height()) - m_symmetryAxis()); m_symmetryAxis(),
double(editor->sprite()->height()) - m_symmetryAxis()));
return true; return true;
} }

View File

@ -56,6 +56,7 @@
#include "doc/slice.h" #include "doc/slice.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "fixmath/fixmath.h" #include "fixmath/fixmath.h"
#include "fmt/format.h"
#include "gfx/rect.h" #include "gfx/rect.h"
#include "os/surface.h" #include "os/surface.h"
#include "os/system.h" #include "os/system.h"
@ -190,12 +191,12 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
"The background layer cannot be moved"); "The background layer cannot be moved");
} }
else if (!layer->isVisibleHierarchy()) { else if (!layer->isVisibleHierarchy()) {
StatusBar::instance()->showTip(1000, StatusBar::instance()->showTip(
"Layer '%s' is hidden", layer->name().c_str()); 1000, fmt::format("Layer '{}' is hidden", layer->name()));
} }
else if (!layer->isMovable() || !layer->isEditableHierarchy()) { else if (!layer->isMovable() || !layer->isEditableHierarchy()) {
StatusBar::instance()->showTip(1000, StatusBar::instance()->showTip(
"Layer '%s' is locked", layer->name().c_str()); 1000, fmt::format("Layer '{}' is locked", layer->name()));
} }
else { else {
MovingCelCollect collect(editor, layer); MovingCelCollect collect(editor, layer);
@ -299,8 +300,8 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
Image* image = site.image(&x, &y, &opacity); Image* image = site.image(&x, &y, &opacity);
if (layer && image) { if (layer && image) {
if (!layer->isEditableHierarchy()) { if (!layer->isEditableHierarchy()) {
StatusBar::instance()->showTip(1000, StatusBar::instance()->showTip(
"Layer '%s' is locked", layer->name().c_str()); 1000, fmt::format("Layer '{}' is locked", layer->name()));
return true; return true;
} }
@ -320,8 +321,8 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
// Move selected pixels // Move selected pixels
if (layer && editor->canStartMovingSelectionPixels() && msg->left()) { if (layer && editor->canStartMovingSelectionPixels() && msg->left()) {
if (!layer->isEditableHierarchy()) { if (!layer->isEditableHierarchy()) {
StatusBar::instance()->showTip(1000, StatusBar::instance()->showTip(
"Layer '%s' is locked", layer->name().c_str()); 1000, fmt::format("Layer '{}' is locked", layer->name()));
return true; return true;
} }
@ -741,8 +742,8 @@ void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleT
Layer* layer = editor->layer(); Layer* layer = editor->layer();
if (layer && layer->isReference()) { if (layer && layer->isReference()) {
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, "Layer '%s' is reference, cannot be transformed", 1000, fmt::format("Layer '{}' is reference, cannot be transformed",
layer->name().c_str()); layer->name()));
return; return;
} }

View File

@ -717,19 +717,19 @@ tools::ToolLoop* create_tool_loop(
} }
else if (!layer->isVisibleHierarchy()) { else if (!layer->isVisibleHierarchy()) {
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, "Layer '%s' is hidden", layer->name().c_str()); 1000, fmt::format("Layer '{}' is hidden", layer->name()));
return nullptr; return nullptr;
} }
// If the active layer is read-only. // If the active layer is read-only.
else if (!layer->isEditableHierarchy()) { else if (!layer->isEditableHierarchy()) {
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, "Layer '%s' is locked", layer->name().c_str()); 1000, fmt::format("Layer '{}' is locked", layer->name()));
return nullptr; return nullptr;
} }
// If the active layer is reference. // If the active layer is reference.
else if (layer->isReference()) { else if (layer->isReference()) {
StatusBar::instance()->showTip( StatusBar::instance()->showTip(
1000, "Layer '%s' is reference, cannot be modified", layer->name().c_str()); 1000, fmt::format("Layer '{}' is reference, cannot be modified", layer->name()));
return nullptr; return nullptr;
} }
} }

View File

@ -29,6 +29,7 @@
#include "doc/image.h" #include "doc/image.h"
#include "doc/palette.h" #include "doc/palette.h"
#include "doc/remap.h" #include "doc/remap.h"
#include "fmt/format.h"
#include "gfx/color.h" #include "gfx/color.h"
#include "gfx/point.h" #include "gfx/point.h"
#include "os/font.h" #include "os/font.h"
@ -935,9 +936,11 @@ void PaletteView::setStatusBar()
std::max(palSize, destIndex + picks)); std::max(palSize, destIndex + picks));
statusBar->setStatusText( statusBar->setStatusText(
0, "%s to %d - New Palette Size %d", 0,
(m_copy ? "Copy": "Move"), fmt::format("{} to {} - New Palette Size {}",
destIndex, newPalSize); (m_copy ? "Copy": "Move"),
destIndex,
newPalSize));
} }
else { else {
statusBar->showDefaultText(); statusBar->showDefaultText();
@ -950,8 +953,8 @@ void PaletteView::setStatusBar()
m_hot.part == Hit::RESIZE_HANDLE) { m_hot.part == Hit::RESIZE_HANDLE) {
int newPalSize = std::max(1, m_hot.color); int newPalSize = std::max(1, m_hot.color);
statusBar->setStatusText( statusBar->setStatusText(
0, "New Palette Size %d", 0, fmt::format("New Palette Size {}",
newPalSize); newPalSize));
} }
else { else {
statusBar->showDefaultText(); statusBar->showDefaultText();

View File

@ -609,7 +609,7 @@ void StatusBar::onSelectedToolChange(tools::Tool* tool)
void StatusBar::clearText() void StatusBar::clearText()
{ {
setStatusText(1, ""); setStatusText(1, std::string());
} }
// TODO Workspace views should have a method to set the default status // TODO Workspace views should have a method to set the default status
@ -621,8 +621,8 @@ void StatusBar::showDefaultText()
showDefaultText(current_editor->document()); showDefaultText(current_editor->document());
} }
else if (App::instance()->mainWindow()->isHomeSelected()) { else if (App::instance()->mainWindow()->isHomeSelected()) {
setStatusText(0, "-- %s %s by David & Gaspar Capello -- Igara Studio --", setStatusText(0, fmt::format("-- {} {} by David & Gaspar Capello -- Igara Studio --",
get_app_name(), get_app_version()); get_app_name(), get_app_version()));
} }
else { else {
clearText(); clearText();
@ -647,7 +647,7 @@ void StatusBar::showDefaultText(Doc* doc)
buf += fmt::format(" ({})", path); buf += fmt::format(" ({})", path);
} }
setStatusText(1, buf.c_str()); setStatusText(1, buf);
} }
} }
@ -662,14 +662,9 @@ void StatusBar::showBackupIcon(BackupIcon icon)
m_indicators->showBackupIcon(icon); m_indicators->showBackupIcon(icon);
} }
bool StatusBar::setStatusText(int msecs, const char* format, ...) bool StatusBar::setStatusText(int msecs, const std::string& msg)
{ {
if ((base::current_tick() > m_timeout) || (msecs > 0)) { if ((base::current_tick() > m_timeout) || (msecs > 0)) {
std::va_list ap;
va_start(ap, format);
std::string msg = base::string_vprintf(format, ap);
va_end(ap);
IndicatorsGeneration(m_indicators).add(msg.c_str()); IndicatorsGeneration(m_indicators).add(msg.c_str());
m_timeout = base::current_tick() + msecs; m_timeout = base::current_tick() + msecs;
return true; return true;
@ -678,13 +673,8 @@ bool StatusBar::setStatusText(int msecs, const char* format, ...)
return false; return false;
} }
void StatusBar::showTip(int msecs, const char* format, ...) void StatusBar::showTip(int msecs, const std::string& msg)
{ {
std::va_list ap;
va_start(ap, format);
std::string msg = base::string_vprintf(format, ap);
va_end(ap);
if (m_tipwindow == NULL) { if (m_tipwindow == NULL) {
m_tipwindow = new CustomizedTipWindow(msg); m_tipwindow = new CustomizedTipWindow(msg);
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -57,8 +57,8 @@ namespace app {
void showDefaultText(); void showDefaultText();
void showDefaultText(Doc* document); void showDefaultText(Doc* document);
bool setStatusText(int msecs, const char* format, ...); bool setStatusText(int msecs, const std::string& text);
void showTip(int msecs, const char* format, ...); void showTip(int msecs, const std::string& msg);
void showColor(int msecs, const char* text, const Color& color); void showColor(int msecs, const char* text, const Color& color);
void showTool(int msecs, tools::Tool* tool); void showTool(int msecs, tools::Tool* tool);
void showSnapToGridWarning(bool state); void showSnapToGridWarning(bool state);

View File

@ -50,6 +50,7 @@
#include "base/memory.h" #include "base/memory.h"
#include "base/scoped_value.h" #include "base/scoped_value.h"
#include "doc/doc.h" #include "doc/doc.h"
#include "fmt/format.h"
#include "gfx/point.h" #include "gfx/point.h"
#include "gfx/rect.h" #include "gfx/rect.h"
#include "os/font.h" #include "os/font.h"
@ -3267,17 +3268,19 @@ void Timeline::updateStatusBar(ui::Message* msg)
switch (m_range.type()) { switch (m_range.type()) {
case Range::kCels: case Range::kCels:
sb->setStatusText(0, "%s cels", verb); sb->setStatusText(0, fmt::format("{} cels", verb));
break; return;
case Range::kFrames: case Range::kFrames:
if (validFrame(m_hot.frame)) { if (validFrame(m_hot.frame)) {
if (m_dropTarget.hhit == DropTarget::Before) { if (m_dropTarget.hhit == DropTarget::Before) {
sb->setStatusText(0, "%s before frame %d", verb, int(m_dropRange.firstFrame()+1)); sb->setStatusText(0, fmt::format("{} before frame {}",
verb, int(m_dropRange.firstFrame()+1)));
return; return;
} }
else if (m_dropTarget.hhit == DropTarget::After) { else if (m_dropTarget.hhit == DropTarget::After) {
sb->setStatusText(0, "%s after frame %d", verb, int(m_dropRange.lastFrame()+1)); sb->setStatusText(0, fmt::format("{} after frame {}",
verb, int(m_dropRange.lastFrame()+1)));
return; return;
} }
} }
@ -3291,7 +3294,7 @@ void Timeline::updateStatusBar(ui::Message* msg)
break; break;
if (m_dropTarget.vhit == DropTarget::VeryBottom) { if (m_dropTarget.vhit == DropTarget::VeryBottom) {
sb->setStatusText(0, "%s at the very bottom", verb); sb->setStatusText(0, fmt::format("{} at the very bottom", verb));
return; return;
} }
@ -3306,13 +3309,16 @@ void Timeline::updateStatusBar(ui::Message* msg)
if (layer) { if (layer) {
switch (m_dropTarget.vhit) { switch (m_dropTarget.vhit) {
case DropTarget::Bottom: case DropTarget::Bottom:
sb->setStatusText(0, "%s at bottom of layer %s", verb, layer->name().c_str()); sb->setStatusText(0, fmt::format("{} below layer '{}'",
verb, layer->name()));
return; return;
case DropTarget::Top: case DropTarget::Top:
sb->setStatusText(0, "%s at top of layer %s", verb, layer->name().c_str()); sb->setStatusText(0, fmt::format("{} above layer '{}'",
verb, layer->name()));
return; return;
case DropTarget::FirstChild: case DropTarget::FirstChild:
sb->setStatusText(0, "%s as first child of layer %s", verb, layer->name().c_str()); sb->setStatusText(0, fmt::format("{} as first child of group '{}'",
verb, layer->name()));
return; return;
} }
} }
@ -3328,37 +3334,41 @@ void Timeline::updateStatusBar(ui::Message* msg)
switch (m_hot.part) { switch (m_hot.part) {
case PART_HEADER_ONIONSKIN: { case PART_HEADER_ONIONSKIN: {
sb->setStatusText(0, "Onionskin is %s", sb->setStatusText(0, fmt::format("Onionskin is {}",
docPref().onionskin.active() ? "enabled": "disabled"); docPref().onionskin.active()
? "enabled": "disabled"));
return; return;
} }
case PART_ROW_TEXT: case PART_ROW_TEXT:
if (layer != NULL) { if (layer != NULL) {
sb->setStatusText( sb->setStatusText(
0, "%s '%s' [%s%s]", 0, fmt::format("{} '{}' [{}{}]",
layer->isReference() ? "Reference layer": "Layer", layer->isReference() ? "Reference layer": "Layer",
layer->name().c_str(), layer->name(),
layer->isVisible() ? "visible": "hidden", layer->isVisible() ? "visible": "hidden",
layer->isEditable() ? "": " locked"); layer->isEditable() ? "": " locked"));
return; return;
} }
break; break;
case PART_ROW_EYE_ICON: case PART_ROW_EYE_ICON:
if (layer != NULL) { if (layer != NULL) {
sb->setStatusText(0, "Layer '%s' is %s", sb->setStatusText(
layer->name().c_str(), 0, fmt::format("Layer '{}' is {}",
layer->isVisible() ? "visible": "hidden"); layer->name(),
layer->isVisible() ? "visible": "hidden"));
return; return;
} }
break; break;
case PART_ROW_PADLOCK_ICON: case PART_ROW_PADLOCK_ICON:
if (layer != NULL) { if (layer != NULL) {
sb->setStatusText(0, "Layer '%s' is %s", sb->setStatusText(
layer->name().c_str(), 0, fmt::format("Layer '{}' is {}",
layer->isEditable() ? "unlocked (editable)": "locked (read-only)"); layer->name(),
layer->isEditable() ? "unlocked (editable)":
"locked (read-only)"));
return; return;
} }
break; break;
@ -3366,12 +3376,16 @@ void Timeline::updateStatusBar(ui::Message* msg)
case PART_ROW_CONTINUOUS_ICON: case PART_ROW_CONTINUOUS_ICON:
if (layer) { if (layer) {
if (layer->isImage()) if (layer->isImage())
sb->setStatusText(0, "Layer '%s' is %s (%s)", sb->setStatusText(
layer->name().c_str(), 0, fmt::format("Layer '{}' is {} ({})",
layer->isContinuous() ? "continuous": "discontinuous", layer->name(),
layer->isContinuous() ? "prefer linked cels/frames": "prefer individual cels/frames"); layer->isContinuous() ? "continuous":
"discontinuous",
layer->isContinuous() ? "prefer linked cels/frames":
"prefer individual cels/frames"));
else if (layer->isGroup()) else if (layer->isGroup())
sb->setStatusText(0, "Group '%s'", layer->name().c_str()); sb->setStatusText(
0, fmt::format("Group '{}'", layer->name()));
return; return;
} }
break; break;
@ -3455,8 +3469,7 @@ void Timeline::updateStatusBarForFrame(const frame_t frame,
} }
} }
StatusBar::instance() StatusBar::instance()->setStatusText(0, buf);
->setStatusText(0, buf);
} }
void Timeline::showCel(layer_t layer, frame_t frame) void Timeline::showCel(layer_t layer, frame_t frame)