2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
Fix transparent color is possible on opaque sprites (fix #4370)
To reproduce the error before this fix on RGBA/Grayscale Color Mode:
- New 100x100 RGBA/Grayscale opaque sprite (white background).
- Draw something with some gray color in the palette.
- Keep the selected gray color as primary color.
- Configure as secondary color the mask color (#000000 alpha=0).
- Pick 'eraser' tool and erase over the gray color with right click.
- Result: The sprite doesn't look more opaque, which is wrong. Also,
if we export this sprite, the transparent parts will turn black.
A similar problem occurs in Indexed Color Mode, but getting a
transparent color in a Background sprite is inevitable if the color of
a palette entry is transparent or semi-transparent, since the index
must be set as is. This could be fixed in the future at the
render stage, however, this could lead to other perceived
inconsistencies. For now it'll be left as is.
Original issue description:
Downloaded PNG in RGB mode fails to support transparency: erase
uses secondary color and export PNG replaces transparent color
with black
Added tests for 'eraser' in 'Replace Color Mode'
To make the eraser work in 'Replace Color Mode' within the tests,
was implemented the possibility of using the right button in
the creation of the point vector.
During testing with UI available it was observed that the 'bg' color
was copied from the 'fg'. Changed this to be compatible with the way
the default value of 'fg' is assigned when it is not specified.
This last modification resulted in errors during 'tilemap.lua' due to
incompatibility of the type of 'bg' color. This was corrected
considering the color type of 'fg' color.
Furthermore, it was found that the command 'app.range.tiles = { 1 }'
did not finish assigning the tile picks to the activeSite,
then 'assert(1, #app.range.tiles)' was failing. This was fixed too.
2024-08-22 22:07:54 +08:00
|
|
|
// Copyright (C) 2019-2024 Igara Studio S.A.
|
2018-05-07 11:11:50 +08:00
|
|
|
// Copyright (C) 2001-2018 David Capello
|
2015-02-12 23:16:25 +08:00
|
|
|
//
|
2016-08-27 04:02:58 +08:00
|
|
|
// This program is distributed under the terms of
|
|
|
|
// the End-User License Agreement for Aseprite.
|
2009-06-01 10:59:15 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2009-06-01 10:59:15 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
|
|
|
|
2019-06-08 00:17:21 +08:00
|
|
|
#include "app/ui_context.h"
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/app.h"
|
2018-07-07 22:54:44 +08:00
|
|
|
#include "app/doc.h"
|
2018-07-07 13:47:42 +08:00
|
|
|
#include "app/site.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/color_bar.h"
|
2018-07-15 10:24:49 +08:00
|
|
|
#include "app/ui/doc_view.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/editor/editor.h"
|
2015-05-10 06:55:33 +08:00
|
|
|
#include "app/ui/input_chain.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/main_window.h"
|
2015-02-10 20:38:07 +08:00
|
|
|
#include "app/ui/preview_editor.h"
|
2015-04-07 13:29:33 +08:00
|
|
|
#include "app/ui/status_bar.h"
|
2017-03-27 00:33:12 +08:00
|
|
|
#include "app/ui/timeline/timeline.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/workspace.h"
|
2015-04-03 02:43:50 +08:00
|
|
|
#include "app/ui/workspace_tabs.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/sprite.h"
|
2025-09-16 11:21:35 +08:00
|
|
|
#include "ui/manager.h"
|
2019-07-29 23:13:53 +08:00
|
|
|
#include "ui/system.h"
|
2009-06-01 10:59:15 +08:00
|
|
|
|
2019-05-28 00:51:41 +08:00
|
|
|
#include <algorithm>
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
namespace app {
|
2009-06-01 10:59:15 +08:00
|
|
|
|
2015-04-21 03:27:09 +08:00
|
|
|
UIContext* UIContext::m_instance = nullptr;
|
2013-01-21 05:40:37 +08:00
|
|
|
|
2023-03-22 04:18:05 +08:00
|
|
|
UIContext::UIContext() : m_closedDocs(preferences())
|
2009-06-01 10:59:15 +08:00
|
|
|
{
|
2019-12-11 23:27:56 +08:00
|
|
|
ASSERT(m_instance == nullptr);
|
2009-10-09 09:34:06 +08:00
|
|
|
m_instance = this;
|
2009-06-01 10:59:15 +08:00
|
|
|
}
|
|
|
|
|
2009-10-09 09:34:06 +08:00
|
|
|
UIContext::~UIContext()
|
2009-06-01 10:59:15 +08:00
|
|
|
{
|
2010-08-04 10:33:44 +08:00
|
|
|
ASSERT(m_instance == this);
|
2019-12-11 23:27:56 +08:00
|
|
|
m_instance = nullptr;
|
2014-07-29 11:53:24 +08:00
|
|
|
|
|
|
|
// The context must be empty at this point. (It's to check if the UI
|
|
|
|
// is working correctly, i.e. closing all files when the user can
|
|
|
|
// take any action about it.)
|
2020-02-05 23:23:11 +08:00
|
|
|
//
|
|
|
|
// Note: This assert is commented because it's really common to hit
|
|
|
|
// it when the program crashes by any other reason, and we would
|
|
|
|
// like to see that other reason instead of this assert.
|
|
|
|
|
|
|
|
// ASSERT(documents().empty());
|
2009-06-01 10:59:15 +08:00
|
|
|
}
|
|
|
|
|
2015-05-19 04:04:31 +08:00
|
|
|
bool UIContext::isUIAvailable() const
|
2014-11-07 05:40:29 +08:00
|
|
|
{
|
|
|
|
return App::instance()->isGui();
|
|
|
|
}
|
|
|
|
|
2018-07-15 10:24:49 +08:00
|
|
|
DocView* UIContext::activeView() const
|
2013-01-21 05:40:37 +08:00
|
|
|
{
|
2015-05-19 04:04:31 +08:00
|
|
|
if (!isUIAvailable())
|
2015-10-27 04:51:32 +08:00
|
|
|
return nullptr;
|
|
|
|
|
2023-03-22 04:18:05 +08:00
|
|
|
// Bypass the active workspace view.
|
|
|
|
if (m_targetView)
|
|
|
|
return m_targetView;
|
|
|
|
|
2016-04-23 00:19:06 +08:00
|
|
|
Workspace* workspace = App::instance()->workspace();
|
2015-10-27 04:51:32 +08:00
|
|
|
if (!workspace)
|
|
|
|
return nullptr;
|
2014-11-07 05:40:29 +08:00
|
|
|
|
2014-07-29 11:53:24 +08:00
|
|
|
WorkspaceView* view = workspace->activeView();
|
2018-07-15 10:24:49 +08:00
|
|
|
if (DocView* docView = dynamic_cast<DocView*>(view))
|
2013-03-28 08:19:35 +08:00
|
|
|
return docView;
|
|
|
|
else
|
2015-10-27 04:51:32 +08:00
|
|
|
return nullptr;
|
2013-01-21 05:40:37 +08:00
|
|
|
}
|
|
|
|
|
2018-07-15 10:24:49 +08:00
|
|
|
void UIContext::setActiveView(DocView* docView)
|
2013-01-21 05:40:37 +08:00
|
|
|
{
|
2016-04-23 00:19:06 +08:00
|
|
|
MainWindow* mainWin = App::instance()->mainWindow();
|
2015-05-10 06:55:33 +08:00
|
|
|
|
2018-08-14 08:33:59 +08:00
|
|
|
// This can happen when the main window is being destroyed when we
|
|
|
|
// close the app, and the active view is changing because we are
|
|
|
|
// closing down every single tab.
|
|
|
|
if (!mainWin)
|
|
|
|
return;
|
|
|
|
|
2015-05-10 06:55:33 +08:00
|
|
|
// Prioritize workspace for user input.
|
2018-06-06 00:11:29 +08:00
|
|
|
App::instance()->inputChain().prioritize(mainWin->getWorkspace(), nullptr);
|
2015-05-10 06:55:33 +08:00
|
|
|
|
2015-04-07 03:12:28 +08:00
|
|
|
// Do nothing cases: 1) the view is already selected, or 2) the view
|
|
|
|
// is the a preview.
|
|
|
|
if (m_lastSelectedView == docView || (docView && docView->isPreview()))
|
2014-08-25 19:27:42 +08:00
|
|
|
return;
|
|
|
|
|
2022-10-20 23:31:22 +08:00
|
|
|
Editor* editor = nullptr;
|
2015-02-10 20:38:07 +08:00
|
|
|
if (docView) {
|
2022-10-20 23:31:22 +08:00
|
|
|
editor = docView->editor();
|
2015-02-10 20:38:07 +08:00
|
|
|
mainWin->getTabsBar()->selectTab(docView);
|
2013-01-21 05:40:37 +08:00
|
|
|
|
2015-02-10 20:38:07 +08:00
|
|
|
if (mainWin->getWorkspace()->activeView() != docView)
|
|
|
|
mainWin->getWorkspace()->setActiveView(docView);
|
2013-01-21 05:40:37 +08:00
|
|
|
|
2022-10-20 23:31:22 +08:00
|
|
|
if (editor)
|
|
|
|
editor->requestFocus();
|
2021-01-16 01:46:45 +08:00
|
|
|
}
|
2013-01-21 05:40:37 +08:00
|
|
|
|
2022-10-20 23:31:22 +08:00
|
|
|
// This is the only place where we change the Editor::m_activeEditor
|
|
|
|
// value.
|
|
|
|
//
|
|
|
|
// TODO probably Editor should have an observer to update its active
|
|
|
|
// editor value.
|
|
|
|
Editor::_setActiveEditor(editor);
|
|
|
|
|
|
|
|
mainWin->getTimeline()->updateUsingEditor(editor);
|
|
|
|
mainWin->getPreviewEditor()->updateUsingEditor(editor);
|
2013-02-21 06:54:00 +08:00
|
|
|
|
2025-09-16 11:21:35 +08:00
|
|
|
// Update mouse widgets immediately after changing views rather
|
|
|
|
// than waiting for mouse movement.
|
|
|
|
mainWin->manager()->_updateMouseWidgets();
|
|
|
|
|
2013-03-12 07:29:45 +08:00
|
|
|
// Change the image-type of color bar.
|
|
|
|
ColorBar::instance()->setPixelFormat(app_get_current_pixel_format());
|
|
|
|
|
2013-02-21 06:54:00 +08:00
|
|
|
// Restore the palette of the selected document.
|
2013-03-12 07:29:45 +08:00
|
|
|
app_refresh_screen();
|
|
|
|
|
|
|
|
// Change the main frame title.
|
2014-09-03 11:39:15 +08:00
|
|
|
App::instance()->updateDisplayTitleBar();
|
2014-08-25 19:27:42 +08:00
|
|
|
|
|
|
|
m_lastSelectedView = docView;
|
2015-05-05 23:58:50 +08:00
|
|
|
|
|
|
|
// TODO all the calls to functions like updateUsingEditor(),
|
2019-10-01 20:24:03 +08:00
|
|
|
// setPixelFormat(), app_refresh_screen(), updateDisplayTitleBar(),
|
|
|
|
// etc. could be replaced with the Transaction class, which is a
|
|
|
|
// DocObserver and handles updates on the screen processing the
|
|
|
|
// observed changes.
|
2015-05-05 23:58:50 +08:00
|
|
|
notifyActiveSiteChanged();
|
2013-01-21 05:40:37 +08:00
|
|
|
}
|
|
|
|
|
2021-10-08 05:56:39 +08:00
|
|
|
void UIContext::onSetActiveDocument(Doc* document, bool notify)
|
2015-04-21 03:27:09 +08:00
|
|
|
{
|
2021-10-08 05:56:39 +08:00
|
|
|
notify = (notify && lastSelectedDoc() != document);
|
2024-11-12 22:35:23 +08:00
|
|
|
|
|
|
|
if (notify)
|
|
|
|
notifyBeforeActiveSiteChanged();
|
|
|
|
|
2021-10-08 05:56:39 +08:00
|
|
|
app::Context::onSetActiveDocument(document, false);
|
2015-04-21 03:27:09 +08:00
|
|
|
|
2018-07-15 10:24:49 +08:00
|
|
|
DocView* docView = getFirstDocView(document);
|
2015-05-05 23:58:50 +08:00
|
|
|
if (docView) { // The view can be null if we are in --batch mode
|
2015-04-21 03:27:09 +08:00
|
|
|
setActiveView(docView);
|
2015-05-05 23:58:50 +08:00
|
|
|
notify = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (notify)
|
|
|
|
notifyActiveSiteChanged();
|
2015-04-21 03:27:09 +08:00
|
|
|
}
|
|
|
|
|
2019-04-14 03:25:21 +08:00
|
|
|
void UIContext::onSetActiveLayer(doc::Layer* layer)
|
|
|
|
{
|
|
|
|
if (DocView* docView = activeView()) {
|
|
|
|
if (Editor* editor = docView->editor())
|
|
|
|
editor->setLayer(layer);
|
|
|
|
}
|
|
|
|
else if (!isUIAvailable())
|
|
|
|
Context::onSetActiveLayer(layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIContext::onSetActiveFrame(const doc::frame_t frame)
|
|
|
|
{
|
|
|
|
if (DocView* docView = activeView()) {
|
|
|
|
if (Editor* editor = docView->editor())
|
|
|
|
editor->setFrame(frame);
|
|
|
|
}
|
|
|
|
else if (!isUIAvailable())
|
|
|
|
Context::onSetActiveFrame(frame);
|
|
|
|
}
|
|
|
|
|
2023-06-09 06:00:49 +08:00
|
|
|
void UIContext::onSetRange(const view::RealRange& range)
|
2020-04-17 06:19:18 +08:00
|
|
|
{
|
|
|
|
Timeline* timeline =
|
|
|
|
(App::instance()->mainWindow() ? App::instance()->mainWindow()->getTimeline() : nullptr);
|
|
|
|
if (timeline) {
|
2023-06-09 06:00:49 +08:00
|
|
|
timeline->setRealRange(range);
|
2020-04-17 06:19:18 +08:00
|
|
|
}
|
|
|
|
else if (!isUIAvailable()) {
|
|
|
|
Context::onSetRange(range);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-11 01:37:18 +08:00
|
|
|
void UIContext::onSetSelectedColors(const doc::PalettePicks& picks)
|
|
|
|
{
|
2019-09-06 04:56:41 +08:00
|
|
|
if (activeView()) {
|
2019-08-11 01:37:18 +08:00
|
|
|
if (ColorBar* colorBar = ColorBar::instance())
|
|
|
|
colorBar->getPaletteView()->setSelectedEntries(picks);
|
|
|
|
}
|
|
|
|
else if (!isUIAvailable())
|
|
|
|
Context::onSetSelectedColors(picks);
|
|
|
|
}
|
|
|
|
|
2020-07-17 05:51:12 +08:00
|
|
|
void UIContext::onSetSelectedTiles(const doc::PalettePicks& picks)
|
|
|
|
{
|
|
|
|
if (activeView()) {
|
|
|
|
if (ColorBar* colorBar = ColorBar::instance())
|
|
|
|
colorBar->getTilesView()->setSelectedEntries(picks);
|
|
|
|
}
|
|
|
|
else if (!isUIAvailable())
|
|
|
|
Context::onSetSelectedTiles(picks);
|
|
|
|
}
|
|
|
|
|
2018-07-15 10:24:49 +08:00
|
|
|
DocView* UIContext::getFirstDocView(Doc* document) const
|
2014-12-01 08:06:29 +08:00
|
|
|
{
|
2016-04-23 00:19:06 +08:00
|
|
|
Workspace* workspace = App::instance()->workspace();
|
|
|
|
if (!workspace) // Workspace (main window) can be null if we are in --batch mode
|
2015-05-01 04:02:57 +08:00
|
|
|
return nullptr;
|
|
|
|
|
2015-02-23 08:18:53 +08:00
|
|
|
for (WorkspaceView* view : *workspace) {
|
2018-07-15 10:24:49 +08:00
|
|
|
if (DocView* docView = dynamic_cast<DocView*>(view)) {
|
2016-02-13 12:33:43 +08:00
|
|
|
if (docView->document() == document) {
|
2014-12-01 08:06:29 +08:00
|
|
|
return docView;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-01 04:02:57 +08:00
|
|
|
return nullptr;
|
2014-12-01 08:06:29 +08:00
|
|
|
}
|
|
|
|
|
2018-07-15 10:24:49 +08:00
|
|
|
DocViews UIContext::getAllDocViews(Doc* document) const
|
2015-08-15 00:06:26 +08:00
|
|
|
{
|
2018-07-15 10:24:49 +08:00
|
|
|
DocViews docViews;
|
2019-03-19 09:31:31 +08:00
|
|
|
// The workspace can be nullptr when we are running in batch mode.
|
|
|
|
if (Workspace* workspace = App::instance()->workspace()) {
|
|
|
|
for (WorkspaceView* view : *workspace) {
|
|
|
|
if (DocView* docView = dynamic_cast<DocView*>(view)) {
|
|
|
|
if (docView->document() == document) {
|
|
|
|
docViews.push_back(docView);
|
|
|
|
}
|
2015-08-15 00:06:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return docViews;
|
|
|
|
}
|
|
|
|
|
2018-07-24 10:43:31 +08:00
|
|
|
Editors UIContext::getAllEditorsIncludingPreview(Doc* document) const
|
|
|
|
{
|
|
|
|
std::vector<Editor*> editors;
|
|
|
|
for (DocView* docView : getAllDocViews(document)) {
|
|
|
|
if (docView->editor())
|
|
|
|
editors.push_back(docView->editor());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MainWindow* mainWin = App::instance()->mainWindow()) {
|
|
|
|
PreviewEditorWindow* previewWin = mainWin->getPreviewEditor();
|
|
|
|
if (previewWin) {
|
|
|
|
Editor* miniEditor = previewWin->previewEditor();
|
|
|
|
if (miniEditor && miniEditor->document() == document)
|
|
|
|
editors.push_back(miniEditor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return editors;
|
|
|
|
}
|
|
|
|
|
2014-07-29 11:53:24 +08:00
|
|
|
Editor* UIContext::activeEditor()
|
2013-01-21 05:40:37 +08:00
|
|
|
{
|
2018-07-15 10:24:49 +08:00
|
|
|
DocView* view = activeView();
|
2014-07-29 11:53:24 +08:00
|
|
|
if (view)
|
2016-02-13 12:33:43 +08:00
|
|
|
return view->editor();
|
2013-01-21 05:40:37 +08:00
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-10-16 04:00:00 +08:00
|
|
|
Editor* UIContext::getEditorFor(Doc* document)
|
|
|
|
{
|
|
|
|
if (auto view = getFirstDocView(document))
|
|
|
|
return view->editor();
|
|
|
|
else
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-06-08 00:17:21 +08:00
|
|
|
bool UIContext::hasClosedDocs()
|
|
|
|
{
|
|
|
|
return m_closedDocs.hasClosedDocs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIContext::reopenLastClosedDoc()
|
2019-05-28 00:51:41 +08:00
|
|
|
{
|
2019-06-08 00:17:21 +08:00
|
|
|
if (Doc* doc = m_closedDocs.reopenLastClosedDoc()) {
|
|
|
|
// Put the document in the context again.
|
|
|
|
doc->setContext(this);
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 00:51:41 +08:00
|
|
|
|
2019-06-08 00:17:21 +08:00
|
|
|
std::vector<Doc*> UIContext::getAndRemoveAllClosedDocs()
|
|
|
|
{
|
|
|
|
return m_closedDocs.getAndRemoveAllClosedDocs();
|
2019-05-28 00:51:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void UIContext::onAddDocument(Doc* doc)
|
2009-06-01 10:59:15 +08:00
|
|
|
{
|
2018-05-07 11:11:50 +08:00
|
|
|
app::Context::onAddDocument(doc);
|
2009-06-01 10:59:15 +08:00
|
|
|
|
2013-12-09 07:19:32 +08:00
|
|
|
// We don't create views in batch mode.
|
|
|
|
if (!App::instance()->isGui())
|
|
|
|
return;
|
|
|
|
|
2013-01-21 05:40:37 +08:00
|
|
|
// Add a new view for this document
|
2018-07-15 10:24:49 +08:00
|
|
|
DocView* view = new DocView(lastSelectedDoc(),
|
|
|
|
DocView::Normal,
|
2016-04-23 00:19:06 +08:00
|
|
|
App::instance()->mainWindow()->getPreviewEditor());
|
2013-01-21 05:40:37 +08:00
|
|
|
|
|
|
|
// Add a tab with the new view for the document
|
2016-04-23 00:19:06 +08:00
|
|
|
App::instance()->workspace()->addView(view);
|
2013-01-21 05:40:37 +08:00
|
|
|
|
2016-02-13 12:33:43 +08:00
|
|
|
view->editor()->setDefaultScroll();
|
2009-06-01 10:59:15 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void UIContext::onRemoveDocument(Doc* doc)
|
2009-06-01 10:59:15 +08:00
|
|
|
{
|
2018-05-07 11:11:50 +08:00
|
|
|
app::Context::onRemoveDocument(doc);
|
2015-04-21 03:27:09 +08:00
|
|
|
|
2014-11-07 08:04:32 +08:00
|
|
|
// We don't destroy views in batch mode.
|
2015-05-19 04:04:31 +08:00
|
|
|
if (isUIAvailable()) {
|
2016-04-23 00:19:06 +08:00
|
|
|
Workspace* workspace = App::instance()->workspace();
|
2009-06-01 10:59:15 +08:00
|
|
|
|
2018-07-15 10:24:49 +08:00
|
|
|
for (DocView* docView : getAllDocViews(doc)) {
|
2015-04-07 12:21:31 +08:00
|
|
|
workspace->removeView(docView);
|
|
|
|
delete docView;
|
|
|
|
}
|
2013-03-28 08:19:35 +08:00
|
|
|
}
|
2009-06-01 10:59:15 +08:00
|
|
|
}
|
|
|
|
|
2015-04-21 03:27:09 +08:00
|
|
|
void UIContext::onGetActiveSite(Site* site) const
|
2009-06-01 10:59:15 +08:00
|
|
|
{
|
2019-07-29 23:13:53 +08:00
|
|
|
// We can use the activeView only from the UI thread.
|
|
|
|
#ifdef _DEBUG
|
|
|
|
if (isUIAvailable())
|
|
|
|
ui::assert_ui_thread();
|
|
|
|
#endif
|
|
|
|
|
2018-07-15 10:24:49 +08:00
|
|
|
DocView* view = activeView();
|
2014-11-07 08:04:32 +08:00
|
|
|
if (view) {
|
2015-04-21 03:27:09 +08:00
|
|
|
view->getSite(site);
|
2016-06-14 01:50:43 +08:00
|
|
|
|
|
|
|
if (site->sprite()) {
|
2021-04-08 02:20:36 +08:00
|
|
|
// Selected range in the timeline. We use it only if the
|
|
|
|
// timeline is visible. A common scenario might be
|
|
|
|
// undoing/redoing actions where the range is re-selected, that
|
|
|
|
// could enable the range even if the timeline is hidden. In
|
|
|
|
// this way we avoid using the timeline selection unexpectedly.
|
2016-06-14 01:50:43 +08:00
|
|
|
Timeline* timeline = App::instance()->timeline();
|
2023-06-09 06:00:49 +08:00
|
|
|
if (timeline && timeline->isVisible() && timeline->isRangeEnabled()) {
|
|
|
|
site->range(timeline->realRange());
|
2016-06-14 01:50:43 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ColorBar* colorBar = ColorBar::instance();
|
|
|
|
if (colorBar && colorBar->getPaletteView()->getSelectedEntriesCount() > 0) {
|
2016-06-14 21:15:47 +08:00
|
|
|
site->focus(Site::InColorBar);
|
2019-08-11 01:37:18 +08:00
|
|
|
|
|
|
|
doc::PalettePicks picks;
|
|
|
|
colorBar->getPaletteView()->getSelectedEntries(picks);
|
|
|
|
site->selectedColors(picks);
|
2016-06-14 01:50:43 +08:00
|
|
|
}
|
Fix transparent color is possible on opaque sprites (fix #4370)
To reproduce the error before this fix on RGBA/Grayscale Color Mode:
- New 100x100 RGBA/Grayscale opaque sprite (white background).
- Draw something with some gray color in the palette.
- Keep the selected gray color as primary color.
- Configure as secondary color the mask color (#000000 alpha=0).
- Pick 'eraser' tool and erase over the gray color with right click.
- Result: The sprite doesn't look more opaque, which is wrong. Also,
if we export this sprite, the transparent parts will turn black.
A similar problem occurs in Indexed Color Mode, but getting a
transparent color in a Background sprite is inevitable if the color of
a palette entry is transparent or semi-transparent, since the index
must be set as is. This could be fixed in the future at the
render stage, however, this could lead to other perceived
inconsistencies. For now it'll be left as is.
Original issue description:
Downloaded PNG in RGB mode fails to support transparency: erase
uses secondary color and export PNG replaces transparent color
with black
Added tests for 'eraser' in 'Replace Color Mode'
To make the eraser work in 'Replace Color Mode' within the tests,
was implemented the possibility of using the right button in
the creation of the point vector.
During testing with UI available it was observed that the 'bg' color
was copied from the 'fg'. Changed this to be compatible with the way
the default value of 'fg' is assigned when it is not specified.
This last modification resulted in errors during 'tilemap.lua' due to
incompatibility of the type of 'bg' color. This was corrected
considering the color type of 'fg' color.
Furthermore, it was found that the command 'app.range.tiles = { 1 }'
did not finish assigning the tile picks to the activeSite,
then 'assert(1, #app.range.tiles)' was failing. This was fixed too.
2024-08-22 22:07:54 +08:00
|
|
|
else if (colorBar && colorBar->getTilesView()->getSelectedEntriesCount() > 0) {
|
|
|
|
site->focus(Site::InColorBar);
|
|
|
|
|
|
|
|
doc::PalettePicks picks;
|
|
|
|
colorBar->getTilesView()->getSelectedEntries(picks);
|
|
|
|
site->selectedTiles(picks);
|
|
|
|
}
|
2016-06-14 01:50:43 +08:00
|
|
|
else {
|
2016-06-14 21:15:47 +08:00
|
|
|
site->focus(Site::InEditor);
|
2016-06-14 01:50:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-07 08:04:32 +08:00
|
|
|
}
|
2015-05-19 04:04:31 +08:00
|
|
|
else if (!isUIAvailable()) {
|
2018-05-07 11:11:50 +08:00
|
|
|
return app::Context::onGetActiveSite(site);
|
2014-11-07 08:04:32 +08:00
|
|
|
}
|
2009-06-01 10:59:15 +08:00
|
|
|
}
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2019-05-28 00:51:41 +08:00
|
|
|
void UIContext::onCloseDocument(Doc* doc)
|
|
|
|
{
|
|
|
|
ASSERT(doc != nullptr);
|
|
|
|
ASSERT(doc->context() == nullptr);
|
2019-06-08 00:17:21 +08:00
|
|
|
|
|
|
|
m_closedDocs.addClosedDoc(doc);
|
2019-05-28 00:51:41 +08:00
|
|
|
}
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
} // namespace app
|