mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-05 00:39:50 +00:00
Several changes were included: - Fixes in TextBox widget to show it with proper size hint when it's outside a viewport - Added the IncompatFileWindow with a message + link to know how to update Aseprite and solve the situation - Moved CannotModifyWhenReadOnlyException from app/doc.h to app/transaction.h
This commit is contained in:
parent
77cdbf4739
commit
c32b9b07a8
@ -528,6 +528,10 @@
|
||||
<background color="textbox_face" />
|
||||
<text color="textbox_text" align="left" />
|
||||
</style>
|
||||
<style id="textbox_label" extends="textbox_text">
|
||||
<background color="window_face" />
|
||||
<text color="text" align="left" />
|
||||
</style>
|
||||
<style id="label" padding="1">
|
||||
<text color="text" align="left" />
|
||||
<text color="disabled" align="left" state="disabled" />
|
||||
|
@ -521,6 +521,10 @@
|
||||
<background color="textbox_face" />
|
||||
<text color="textbox_text" align="left" />
|
||||
</style>
|
||||
<style id="textbox_label" extends="textbox_text">
|
||||
<background color="window_face" />
|
||||
<text color="text" align="left" />
|
||||
</style>
|
||||
<style id="label" padding="1">
|
||||
<text color="text" align="left" />
|
||||
<text color="disabled" align="left" state="disabled" />
|
||||
|
@ -41,7 +41,10 @@ non_transformable_reference_layer = Layer '{}' is reference, cannot be transform
|
||||
sprite_locked_somewhere = The sprite is locked in other editor
|
||||
not_enough_transform_memory = Not enough memory to transform the selection
|
||||
not_enough_rotsprite_memory = Not enough memory for RotSprite
|
||||
unmodifiable_sprite = Read-only sprite cannot be modified
|
||||
cannot_modify_readonly_sprite = <<<END
|
||||
Cannot modify a read-only sprite.
|
||||
Use File > Save menu for more information.
|
||||
END
|
||||
|
||||
[alerts]
|
||||
applying_filter = FX<<Applying effect...||&Cancel
|
||||
@ -218,17 +221,6 @@ Information
|
||||
<<Activating Aseprite will give you access to automatic updates.
|
||||
||&OK
|
||||
END
|
||||
load_file_with_incompatibilities = <<<END
|
||||
Incompatibility error found:
|
||||
|
||||
|
||||
{0}.
|
||||
|
||||
|
||||
This file will be opened as read-only. Please upgrade Aseprite to the latest version to be able to save changes without losing data.
|
||||
END
|
||||
cannot_overwrite_readonly = Cannot save/overwrite a read-only sprite. Use File > Save As option.
|
||||
cannot_modify_readonly = Cannot modify a read-only sprite.
|
||||
|
||||
[brightness_contrast]
|
||||
title = Brightness/Contrast
|
||||
@ -1020,6 +1012,20 @@ layer_name = Sprite Sheet
|
||||
import = &Import
|
||||
cancel = &Cancel
|
||||
|
||||
[incompat_file]
|
||||
title = Incompatible File
|
||||
message = <<<END
|
||||
This file was originally created with a newer version of Aseprite which contains information we cannot fully read.
|
||||
|
||||
It's marked as read-only to avoid losing that information when you try to save/overwrite it.
|
||||
|
||||
To solve this situation you can:
|
||||
- Update Aseprite to the latest version and try to load the file again (recommended), or
|
||||
- Use the "File > Save As" option to save the file with other name (you will lose information stored in the original file anyway)
|
||||
END
|
||||
incompatibilities = Incompatibilities:
|
||||
update_link = Update Aseprite
|
||||
|
||||
[inks]
|
||||
simple_ink = Simple Ink
|
||||
alpha_compositing = Alpha Compositing
|
||||
|
23
data/widgets/incompat_file.xml
Normal file
23
data/widgets/incompat_file.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (c) 2023 Igara Studio S.A. -->
|
||||
<gui>
|
||||
<window id="incompat_file" text="@.title">
|
||||
<vbox>
|
||||
<textbox text="@.message" wordwrap="true" style="textbox_label" />
|
||||
<vbox id="errors_placeholder" expansive="true">
|
||||
<label text="@.incompatibilities" />
|
||||
<view id="errors_view" expansive="true">
|
||||
<textbox id="errors" text="" />
|
||||
</view>
|
||||
</vbox>
|
||||
<hbox>
|
||||
<boxfiller />
|
||||
<vbox>
|
||||
<link text="@.update_link" url="https://www.aseprite.org/faq/#update" />
|
||||
<button text="@general.close" closewindow="true" id="ok" magnet="true" minwidth="60" />
|
||||
</vbox>
|
||||
<boxfiller />
|
||||
</hbox>
|
||||
</vbox>
|
||||
</window>
|
||||
</gui>
|
@ -386,6 +386,7 @@ if(ENABLE_UI)
|
||||
ui/hex_color_entry.cpp
|
||||
ui/home_view.cpp
|
||||
ui/icon_button.cpp
|
||||
ui/incompat_file_window.cpp
|
||||
ui/input_chain.cpp
|
||||
ui/keyboard_shortcuts.cpp
|
||||
ui/main_menu_bar.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -30,6 +30,7 @@
|
||||
#include "app/recent_files.h"
|
||||
#include "app/restore_visible_layers.h"
|
||||
#include "app/ui/export_file_window.h"
|
||||
#include "app/ui/incompat_file_window.h"
|
||||
#include "app/ui/layer_frame_comboboxes.h"
|
||||
#include "app/ui/optional_alert.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
@ -112,7 +113,7 @@ void SaveFileBaseCommand::onLoadParams(const Params& params)
|
||||
// [main thread]
|
||||
bool SaveFileBaseCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsReadable);
|
||||
}
|
||||
|
||||
std::string SaveFileBaseCommand::saveAsDialog(
|
||||
@ -200,6 +201,17 @@ void SaveFileBaseCommand::saveDocumentInBackground(
|
||||
const ResizeOnTheFly resizeOnTheFly,
|
||||
const gfx::PointF& scale)
|
||||
{
|
||||
#ifdef ENABLE_UI
|
||||
// If the document is read only, we cannot save it directly (we have
|
||||
// to use File > Save As)
|
||||
if (document->isReadOnly() &&
|
||||
context->isUIAvailable()) {
|
||||
IncompatFileWindow window;
|
||||
window.show();
|
||||
return;
|
||||
}
|
||||
#endif // ENABLE_UI
|
||||
|
||||
if (params().aniDir.isSet()) {
|
||||
switch (params().aniDir()) {
|
||||
case AniDir::REVERSE:
|
||||
@ -323,7 +335,6 @@ public:
|
||||
|
||||
protected:
|
||||
void onExecute(Context* context) override;
|
||||
bool onEnabled(Context* context) override;
|
||||
};
|
||||
|
||||
SaveFileAsCommand::SaveFileAsCommand()
|
||||
@ -340,11 +351,6 @@ void SaveFileAsCommand::onExecute(Context* context)
|
||||
MarkAsSaved::On);
|
||||
}
|
||||
|
||||
bool SaveFileAsCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsReadable);
|
||||
}
|
||||
|
||||
class SaveFileCopyAsCommand : public SaveFileBaseCommand {
|
||||
public:
|
||||
SaveFileCopyAsCommand();
|
||||
|
@ -12,10 +12,8 @@
|
||||
#include "app/doc_observer.h"
|
||||
#include "app/extra_cel.h"
|
||||
#include "app/file/format_options.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/transformation.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "base/exception.h"
|
||||
#include "base/rw_lock.h"
|
||||
#include "doc/blend_mode.h"
|
||||
#include "doc/color.h"
|
||||
@ -149,6 +147,13 @@ namespace app {
|
||||
void markAsBackedUp();
|
||||
bool isFullyBackedUp() const;
|
||||
|
||||
// TODO This read-only flag might be confusing because it
|
||||
// indicates that the file was loaded from an incompatible
|
||||
// version (future unknown feature) and it's preferable to
|
||||
// mark the sprite as read-only to avoid overwriting unknown
|
||||
// data. If in the future we want to add the possibility to
|
||||
// mark a regular file as read-only, this flag'll need a new
|
||||
// name.
|
||||
void markAsReadOnly();
|
||||
bool isReadOnly() const;
|
||||
void removeReadOnlyMark();
|
||||
@ -275,14 +280,6 @@ namespace app {
|
||||
DISABLE_COPYING(Doc);
|
||||
};
|
||||
|
||||
// Exception thrown when we want to modify a sprite (add new
|
||||
// app::Cmd objects) marked as read-only.
|
||||
class CannotModifyWhenReadOnlyException : public base::Exception {
|
||||
public:
|
||||
CannotModifyWhenReadOnlyException() throw()
|
||||
: base::Exception(Strings::alerts_cannot_modify_readonly()) { }
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
||||
|
@ -293,7 +293,7 @@ bool AseFormat::onLoad(FileOp* fop)
|
||||
return false;
|
||||
|
||||
Sprite* sprite = delegate.sprite();
|
||||
fop->createDocument(sprite, fop->hasIncompatibilityError());
|
||||
fop->createDocument(sprite);
|
||||
|
||||
if (sprite->colorSpace() != nullptr &&
|
||||
sprite->colorSpace()->type() != gfx::ColorSpace::None) {
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/tx.h"
|
||||
#include "app/ui/incompat_file_window.h"
|
||||
#include "app/ui/optional_alert.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "base/fs.h"
|
||||
@ -920,12 +921,6 @@ void FileOp::operate(IFileOpProgress* progress)
|
||||
setError("Error loading data file: %s\n", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
if (hasIncompatibilityError()) {
|
||||
setError(
|
||||
fmt::format(Strings::alerts_load_file_with_incompatibilities(),
|
||||
m_incompatibilityError).c_str());
|
||||
}
|
||||
}
|
||||
// Save //////////////////////////////////////////////////////////////////////
|
||||
else if (m_type == FileOpSave &&
|
||||
@ -942,10 +937,9 @@ void FileOp::operate(IFileOpProgress* progress)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_document && m_document->isReadOnly()) {
|
||||
setError(Strings::alerts_cannot_overwrite_readonly().c_str());
|
||||
return;
|
||||
}
|
||||
// TODO Should we check m_document->isReadOnly() here? the flag
|
||||
// is already checked in SaveFileBaseCommand::saveDocumentInBackground
|
||||
// and only in UI mode (so the CLI still works)
|
||||
|
||||
// Save a sequence
|
||||
if (isSequence()) {
|
||||
@ -1092,14 +1086,12 @@ FileOp::~FileOp()
|
||||
delete m_seq.palette;
|
||||
}
|
||||
|
||||
void FileOp::createDocument(Sprite* spr, bool readOnly)
|
||||
void FileOp::createDocument(Sprite* spr)
|
||||
{
|
||||
// spr can be NULL if the sprite is set in onPostLoad() then
|
||||
|
||||
ASSERT(m_document == NULL);
|
||||
m_document = new Doc(spr);
|
||||
if (readOnly)
|
||||
m_document->markAsReadOnly();
|
||||
}
|
||||
|
||||
void FileOp::postLoad()
|
||||
@ -1228,7 +1220,35 @@ void FileOp::postLoad()
|
||||
}
|
||||
}
|
||||
|
||||
// Mark this document as associated to a file in the disk (so File >
|
||||
// Save doesn't ask for a new name)
|
||||
m_document->markAsSaved();
|
||||
|
||||
// In case that the document was loaded without all the information
|
||||
// from the file, i.e. we loaded an .aseprite file created with a
|
||||
// newer Aseprite version and cannot interpret all its information,
|
||||
// saving this file should show a warning that some original data
|
||||
// will be lost if we save/overwrite it.
|
||||
if (hasIncompatibilityError()) {
|
||||
// Mark the active undo state as impossible to reach the original
|
||||
// disk state.
|
||||
m_document->impossibleToBackToSavedState();
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
if (m_context && m_context->isUIAvailable()) {
|
||||
IncompatFileWindow window;
|
||||
window.show(m_incompatibilityError);
|
||||
}
|
||||
else
|
||||
#endif // ENABLE_UI
|
||||
{
|
||||
setError(m_incompatibilityError.c_str());
|
||||
}
|
||||
|
||||
// Mark as read-only so we cannot save the file directly (without
|
||||
// an incompatibility warning/error).
|
||||
m_document->markAsReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
void FileOp::setLoadedFormatOptions(const FormatOptionsPtr& opts)
|
||||
|
@ -168,7 +168,8 @@ namespace app {
|
||||
|
||||
const FileOpROI& roi() const { return m_roi; }
|
||||
|
||||
void createDocument(Sprite* spr, bool readOnly = false);
|
||||
// Creates a new document with the given sprite.
|
||||
void createDocument(Sprite* spr);
|
||||
void operate(IFileOpProgress* progress = nullptr);
|
||||
|
||||
void done();
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "app/context_access.h"
|
||||
#include "app/doc.h"
|
||||
#include "app/doc_undo.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "ui/manager.h"
|
||||
@ -26,6 +27,11 @@ namespace app {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
CannotModifyWhenReadOnlyException::CannotModifyWhenReadOnlyException() throw()
|
||||
: base::Exception(Strings::statusbar_tips_cannot_modify_readonly_sprite())
|
||||
{
|
||||
}
|
||||
|
||||
Transaction::Transaction(
|
||||
Context* ctx,
|
||||
Doc* doc,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include "app/cmd_transaction.h"
|
||||
#include "app/doc_observer.h"
|
||||
#include "base/exception.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -26,6 +27,13 @@ namespace app {
|
||||
DoesntModifyDocument // This item doesn't modify the document.
|
||||
};
|
||||
|
||||
// Exception thrown when we want to modify a sprite (add new
|
||||
// app::Cmd objects) marked as read-only.
|
||||
class CannotModifyWhenReadOnlyException : public base::Exception {
|
||||
public:
|
||||
CannotModifyWhenReadOnlyException() throw();
|
||||
};
|
||||
|
||||
// High-level class to group a set of commands to modify the
|
||||
// document atomically, with enough information to rollback the
|
||||
// whole operation if something fails (e.g. an exceptions is thrown)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -786,7 +786,7 @@ tools::ToolLoop* create_tool_loop(
|
||||
// If the document is read-only.
|
||||
if (site.document()->isReadOnly()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, Strings::statusbar_tips_unmodifiable_sprite());
|
||||
3000, Strings::statusbar_tips_cannot_modify_readonly_sprite());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
36
src/app/ui/incompat_file_window.cpp
Normal file
36
src/app/ui/incompat_file_window.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2023 Igara Studio S.A.
|
||||
//
|
||||
// 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/ui/incompat_file_window.h"
|
||||
|
||||
#include "base/trim_string.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
void IncompatFileWindow::show(std::string incompatibilities)
|
||||
{
|
||||
base::trim_string(incompatibilities,
|
||||
incompatibilities);
|
||||
if (!incompatibilities.empty()) {
|
||||
errors()->setText(incompatibilities);
|
||||
errorsView()->setSizeHint(
|
||||
errorsView()->border().size()
|
||||
+ gfx::Size(0, std::min(textHeight()*16, // 16 lines as max height
|
||||
errors()->sizeHint().h)));
|
||||
}
|
||||
else {
|
||||
errorsPlaceholder()->setVisible(false);
|
||||
}
|
||||
|
||||
// Run modal
|
||||
openWindowInForeground();
|
||||
}
|
||||
|
||||
} // namespace app
|
29
src/app/ui/incompat_file_window.h
Normal file
29
src/app/ui/incompat_file_window.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_INCOMPAT_FILE_WINDOW_H_INCLUDED
|
||||
#define APP_UI_INCOMPAT_FILE_WINDOW_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/size.h"
|
||||
|
||||
#include "incompat_file.xml.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
|
||||
// Shows the window to offer a solution for forward compatibility
|
||||
// (don't save/overwrite files that were saved with future Aseprite
|
||||
// versions/unknown data in the original .aseprite file).
|
||||
class IncompatFileWindow : public app::gen::IncompatFile {
|
||||
public:
|
||||
void show(std::string incompatibilities = std::string());
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -12,6 +12,7 @@
|
||||
#include "ui/textbox.h"
|
||||
|
||||
#include "gfx/size.h"
|
||||
#include "ui/display.h"
|
||||
#include "ui/intern.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
@ -26,6 +27,7 @@ namespace ui {
|
||||
TextBox::TextBox(const std::string& text, int align)
|
||||
: Widget(kTextBoxWidget)
|
||||
{
|
||||
setBgColor(gfx::ColorNone);
|
||||
setFocusStop(true);
|
||||
setAlign(align);
|
||||
setText(text);
|
||||
@ -156,8 +158,9 @@ void TextBox::onPaint(PaintEvent& ev)
|
||||
|
||||
void TextBox::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
gfx::Size borderSize = border().size();
|
||||
int w = borderSize.w;
|
||||
int h = borderSize.h;
|
||||
|
||||
Theme::drawTextBox(nullptr, this, &w, &h, gfx::ColorNone, gfx::ColorNone);
|
||||
|
||||
@ -165,17 +168,17 @@ void TextBox::onSizeHint(SizeHintEvent& ev)
|
||||
View* view = View::getView(this);
|
||||
int width, min = w;
|
||||
|
||||
if (view) {
|
||||
if (view)
|
||||
width = view->viewportBounds().w;
|
||||
}
|
||||
else {
|
||||
else if (bounds().w > 0)
|
||||
width = bounds().w;
|
||||
}
|
||||
else if (auto display = this->display())
|
||||
width = display->size().w / guiscale();
|
||||
else
|
||||
width = 0;
|
||||
|
||||
w = std::max(min, width);
|
||||
Theme::drawTextBox(nullptr, this, &w, &h, gfx::ColorNone, gfx::ColorNone);
|
||||
|
||||
w = min;
|
||||
}
|
||||
|
||||
ev.setSizeHint(gfx::Size(w, h));
|
||||
|
Loading…
x
Reference in New Issue
Block a user