mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-29 09:23:32 +00:00
Fix selection UX to show white/black negative for the stroke
With this patch now we can use the selection tool in locked or hidden layers, because the selection doesn't modify the layers (only the selection). Also we can use the selection tool on any layer and we'll always see the feedback stroke/shape/rectangle while we're creating the new selection.
This commit is contained in:
parent
d838cbf91b
commit
640025e84b
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -14,6 +14,7 @@
|
||||
#include "app/commands/filters/filter_manager_impl.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/message.h"
|
||||
@ -68,7 +69,8 @@ bool FilterPreview::onProcessMessage(Message* msg)
|
||||
current_editor->renderEngine().setPreviewImage(
|
||||
m_filterMgr->layer(),
|
||||
m_filterMgr->frame(),
|
||||
m_filterMgr->destinationImage());
|
||||
m_filterMgr->destinationImage(),
|
||||
static_cast<doc::LayerImage*>(m_filterMgr->layer())->blendMode());
|
||||
break;
|
||||
|
||||
case kCloseMessage:
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "app/ui/editor/glue.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "doc/layer.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/system.h"
|
||||
|
||||
@ -61,7 +62,11 @@ void DrawingState::initToolLoop(Editor* editor, MouseMessage* msg)
|
||||
editor->renderEngine().setPreviewImage(
|
||||
m_toolLoop->getLayer(),
|
||||
m_toolLoop->getFrame(),
|
||||
m_toolLoop->getDstImage());
|
||||
m_toolLoop->getDstImage(),
|
||||
(m_toolLoop->getLayer() &&
|
||||
m_toolLoop->getLayer()->isImage() ?
|
||||
static_cast<LayerImage*>(m_toolLoop->getLayer())->blendMode():
|
||||
BlendMode::NEG_BW));
|
||||
|
||||
m_lastPoint = editor->lastDrawingPosition();
|
||||
|
||||
|
@ -479,7 +479,8 @@ void PixelsMovement::stampImage()
|
||||
{
|
||||
// Expand the canvas to paste the image in the fully visible
|
||||
// portion of sprite.
|
||||
ExpandCelCanvas expand(m_site,
|
||||
ExpandCelCanvas expand(
|
||||
m_site, m_site.layer(),
|
||||
TiledMode::NONE, m_transaction,
|
||||
ExpandCelCanvas::None);
|
||||
|
||||
|
@ -378,9 +378,10 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
editor->showMouseCursor(kArrowPlusCursor);
|
||||
else
|
||||
editor->showMouseCursor(kMoveCursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
editor->showBrushPreview(mouseScreenPos);
|
||||
return true;
|
||||
}
|
||||
else if (ink->isEyedropper()) {
|
||||
editor->showMouseCursor(kEyedropperCursor);
|
||||
|
@ -81,6 +81,7 @@ protected:
|
||||
tools::TracePolicy m_tracePolicy;
|
||||
base::UniquePtr<tools::Symmetry> m_symmetry;
|
||||
base::UniquePtr<doc::Remap> m_shadingRemap;
|
||||
app::ColorTarget m_colorTarget;
|
||||
doc::color_t m_fgColor;
|
||||
doc::color_t m_bgColor;
|
||||
doc::color_t m_primaryColor;
|
||||
@ -89,6 +90,7 @@ protected:
|
||||
|
||||
public:
|
||||
ToolLoopBase(Editor* editor,
|
||||
Layer* layer,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
Document* document,
|
||||
@ -100,7 +102,7 @@ public:
|
||||
, m_brush(App::instance()->contextBar()->activeBrush(m_tool))
|
||||
, m_document(document)
|
||||
, m_sprite(editor->sprite())
|
||||
, m_layer(editor->layer())
|
||||
, m_layer(layer)
|
||||
, m_frame(editor->frame())
|
||||
, m_rgbMap(nullptr)
|
||||
, m_docPref(Preferences::instance().document(m_document))
|
||||
@ -115,8 +117,12 @@ public:
|
||||
, m_intertwine(m_tool->getIntertwine(m_button))
|
||||
, m_tracePolicy(m_tool->getTracePolicy(m_button))
|
||||
, m_symmetry(nullptr)
|
||||
, m_fgColor(color_utils::color_for_target_mask(fgColor, ColorTarget(m_layer)))
|
||||
, m_bgColor(color_utils::color_for_target_mask(bgColor, ColorTarget(m_layer)))
|
||||
, m_colorTarget(m_layer ? ColorTarget(m_layer):
|
||||
ColorTarget(ColorTarget::BackgroundLayer,
|
||||
m_sprite->pixelFormat(),
|
||||
m_sprite->transparentColor()))
|
||||
, m_fgColor(color_utils::color_for_target_mask(fgColor, m_colorTarget))
|
||||
, m_bgColor(color_utils::color_for_target_mask(bgColor, m_colorTarget))
|
||||
, m_primaryColor(button == tools::ToolLoop::Left ? m_fgColor: m_bgColor)
|
||||
, m_secondaryColor(button == tools::ToolLoop::Left ? m_bgColor: m_fgColor)
|
||||
{
|
||||
@ -184,7 +190,8 @@ public:
|
||||
RgbMap* getRgbMap() override {
|
||||
if (!m_rgbMap) {
|
||||
Sprite::RgbMapFor forLayer =
|
||||
((m_layer->isBackground() ||
|
||||
((!m_layer ||
|
||||
m_layer->isBackground() ||
|
||||
m_sprite->pixelFormat() == IMAGE_RGB) ?
|
||||
Sprite::RgbMapFor::OpaqueLayer:
|
||||
Sprite::RgbMapFor::TransparentLayer);
|
||||
@ -265,6 +272,7 @@ class ToolLoopImpl : public ToolLoopBase {
|
||||
|
||||
public:
|
||||
ToolLoopImpl(Editor* editor,
|
||||
Layer* layer,
|
||||
Context* context,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
@ -272,7 +280,7 @@ public:
|
||||
tools::ToolLoop::Button button,
|
||||
const app::Color& fgColor,
|
||||
const app::Color& bgColor)
|
||||
: ToolLoopBase(editor, tool, ink, document,
|
||||
: ToolLoopBase(editor, layer, tool, ink, document,
|
||||
button, fgColor, bgColor)
|
||||
, m_context(context)
|
||||
, m_canceled(false)
|
||||
@ -284,7 +292,9 @@ public:
|
||||
getInk()->isSlice() ||
|
||||
getInk()->isZoom()) ? DoesntModifyDocument:
|
||||
ModifyDocument))
|
||||
, m_expandCelCanvas(editor->getSite(),
|
||||
, m_expandCelCanvas(
|
||||
editor->getSite(),
|
||||
layer,
|
||||
m_docPref.tiled.mode(),
|
||||
m_transaction,
|
||||
ExpandCelCanvas::Flags(
|
||||
@ -424,24 +434,39 @@ tools::ToolLoop* create_tool_loop(Editor* editor, Context* context)
|
||||
if (!current_tool || !current_ink)
|
||||
return NULL;
|
||||
|
||||
Layer* layer = editor->layer();
|
||||
if (!layer) {
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"There is no active layer");
|
||||
return NULL;
|
||||
}
|
||||
Layer* layer;
|
||||
|
||||
// If the active layer is not visible.
|
||||
if (!layer->isVisible()) {
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"Layer '%s' is hidden", layer->name().c_str());
|
||||
return NULL;
|
||||
// For selection tools, we can use any layer (even without layers at
|
||||
// all), so we specify a nullptr here as the active layer. This is
|
||||
// used as a special case by the render::Render class to show the
|
||||
// preview image/selection stroke as a xor'd overlay in the render
|
||||
// result.
|
||||
//
|
||||
// Anyway this cannot be used in 'magic wand' tool (isSelection +
|
||||
// isFloodFill) because we need the original layer source
|
||||
// image/pixels to stop the flood-fill algorithm.
|
||||
if (current_ink->isSelection() &&
|
||||
!current_tool->getPointShape(editor->isSecondaryButton() ? 1: 0)->isFloodFill()) {
|
||||
layer = nullptr;
|
||||
}
|
||||
// If the active layer is read-only.
|
||||
else if (!layer->isEditable()) {
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"Layer '%s' is locked", layer->name().c_str());
|
||||
return NULL;
|
||||
else {
|
||||
layer = editor->layer();
|
||||
if (!layer) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, "There is no active layer");
|
||||
return nullptr;
|
||||
}
|
||||
else if (!layer->isVisible()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, "Layer '%s' is hidden", layer->name().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
// If the active layer is read-only.
|
||||
else if (!layer->isEditable()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, "Layer '%s' is locked", layer->name().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Get fg/bg colors
|
||||
@ -463,7 +488,7 @@ tools::ToolLoop* create_tool_loop(Editor* editor, Context* context)
|
||||
// Create the new tool loop
|
||||
try {
|
||||
return new ToolLoopImpl(
|
||||
editor, context,
|
||||
editor, layer, context,
|
||||
current_tool,
|
||||
current_ink,
|
||||
editor->document(),
|
||||
@ -496,7 +521,7 @@ public:
|
||||
const app::Color& bgColor,
|
||||
Image* image,
|
||||
const gfx::Point& celOrigin)
|
||||
: ToolLoopBase(editor, tool, ink, document,
|
||||
: ToolLoopBase(editor, editor->layer(), tool, ink, document,
|
||||
tools::ToolLoop::Left, fgColor, bgColor)
|
||||
, m_image(image)
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -27,6 +27,7 @@
|
||||
#include "doc/primitives.h"
|
||||
#include "doc/site.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "render/render.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -57,11 +58,13 @@ static void create_buffers()
|
||||
|
||||
namespace app {
|
||||
|
||||
ExpandCelCanvas::ExpandCelCanvas(Site site,
|
||||
ExpandCelCanvas::ExpandCelCanvas(
|
||||
Site site, Layer* layer,
|
||||
TiledMode tiledMode, Transaction& transaction, Flags flags)
|
||||
: m_document(static_cast<app::Document*>(site.document()))
|
||||
, m_sprite(site.sprite())
|
||||
, m_layer(site.layer())
|
||||
, m_layer(layer)
|
||||
, m_frame(site.frame())
|
||||
, m_cel(NULL)
|
||||
, m_celImage(NULL)
|
||||
, m_celCreated(false)
|
||||
@ -77,14 +80,14 @@ ExpandCelCanvas::ExpandCelCanvas(Site site,
|
||||
|
||||
create_buffers();
|
||||
|
||||
if (m_layer->isImage()) {
|
||||
if (m_layer && m_layer->isImage()) {
|
||||
m_cel = m_layer->cel(site.frame());
|
||||
if (m_cel)
|
||||
m_celImage = m_cel->imageRef();
|
||||
}
|
||||
|
||||
// Create a new cel
|
||||
if (m_cel == NULL) {
|
||||
if (!m_cel) {
|
||||
m_celCreated = true;
|
||||
m_cel = new Cel(site.frame(), ImageRef(NULL));
|
||||
}
|
||||
@ -117,7 +120,9 @@ ExpandCelCanvas::ExpandCelCanvas(Site site,
|
||||
if (m_celCreated) {
|
||||
getDestCanvas();
|
||||
m_cel->data()->setImage(m_dstImage);
|
||||
static_cast<LayerImage*>(m_layer)->addCel(m_cel);
|
||||
|
||||
if (m_layer && m_layer->isImage())
|
||||
static_cast<LayerImage*>(m_layer)->addCel(m_cel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,6 +145,11 @@ void ExpandCelCanvas::commit()
|
||||
ASSERT(!m_closed);
|
||||
ASSERT(!m_committed);
|
||||
|
||||
if (!m_layer) {
|
||||
m_committed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Was the cel created in the start of the tool-loop?
|
||||
if (m_celCreated) {
|
||||
ASSERT(m_cel);
|
||||
@ -150,6 +160,7 @@ void ExpandCelCanvas::commit()
|
||||
validateDestCanvas(gfx::Region(m_bounds));
|
||||
|
||||
// We can temporary remove the cel.
|
||||
ASSERT(m_layer->isImage());
|
||||
static_cast<LayerImage*>(m_layer)->removeCel(m_cel);
|
||||
|
||||
// Add a copy of m_dstImage in the sprite's image stock
|
||||
@ -213,7 +224,9 @@ void ExpandCelCanvas::rollback()
|
||||
m_cel->setPosition(m_origCelPos);
|
||||
|
||||
if (m_celCreated) {
|
||||
static_cast<LayerImage*>(m_layer)->removeCel(m_cel);
|
||||
if (m_layer && m_layer->isImage())
|
||||
static_cast<LayerImage*>(m_layer)->removeCel(m_cel);
|
||||
|
||||
delete m_cel;
|
||||
m_celImage.reset(NULL);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -9,6 +9,7 @@
|
||||
#define APP_UTIL_EXPAND_CEL_CANVAS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/frame.h"
|
||||
#include "doc/image_ref.h"
|
||||
#include "filters/tiled_mode.h"
|
||||
#include "gfx/point.h"
|
||||
@ -45,7 +46,7 @@ namespace app {
|
||||
UseModifiedRegionAsUndoInfo = 2,
|
||||
};
|
||||
|
||||
ExpandCelCanvas(Site site,
|
||||
ExpandCelCanvas(Site site, Layer* layer,
|
||||
TiledMode tiledMode, Transaction& undo, Flags flags);
|
||||
~ExpandCelCanvas();
|
||||
|
||||
@ -73,6 +74,7 @@ namespace app {
|
||||
Document* m_document;
|
||||
Sprite* m_sprite;
|
||||
Layer* m_layer;
|
||||
frame_t m_frame;
|
||||
Cel* m_cel;
|
||||
ImageRef m_celImage;
|
||||
bool m_celCreated;
|
||||
|
@ -348,6 +348,7 @@ Render::Render()
|
||||
, m_selectedLayer(nullptr)
|
||||
, m_selectedFrame(-1)
|
||||
, m_previewImage(nullptr)
|
||||
, m_previewBlendMode(BlendMode::NORMAL)
|
||||
, m_onionskin(OnionskinType::NONE)
|
||||
{
|
||||
}
|
||||
@ -377,11 +378,13 @@ void Render::setBgCheckedSize(const gfx::Size& size)
|
||||
m_bgCheckedSize = size;
|
||||
}
|
||||
|
||||
void Render::setPreviewImage(const Layer* layer, frame_t frame, Image* image)
|
||||
void Render::setPreviewImage(const Layer* layer, frame_t frame,
|
||||
Image* image, BlendMode blendMode)
|
||||
{
|
||||
m_selectedLayer = layer;
|
||||
m_selectedFrame = frame;
|
||||
m_previewImage = image;
|
||||
m_previewBlendMode = blendMode;
|
||||
}
|
||||
|
||||
void Render::setExtraImage(
|
||||
@ -400,7 +403,7 @@ void Render::setExtraImage(
|
||||
|
||||
void Render::removePreviewImage()
|
||||
{
|
||||
m_previewImage = NULL;
|
||||
m_previewImage = nullptr;
|
||||
}
|
||||
|
||||
void Render::removeExtraImage()
|
||||
@ -548,6 +551,22 @@ void Render::renderSprite(
|
||||
// Draw onion skin in front of the sprite.
|
||||
if (m_onionskin.position() == OnionskinPosition::INFRONT)
|
||||
renderOnionskin(dstImage, area, frame, zoom, scaled_func);
|
||||
|
||||
// Overlay preview image
|
||||
if (m_previewImage &&
|
||||
m_selectedLayer == nullptr &&
|
||||
m_selectedFrame == frame) {
|
||||
renderImage(
|
||||
dstImage,
|
||||
m_previewImage,
|
||||
m_sprite->palette(frame),
|
||||
0, 0,
|
||||
area,
|
||||
scaled_func,
|
||||
255,
|
||||
m_previewBlendMode,
|
||||
zoom);
|
||||
}
|
||||
}
|
||||
|
||||
void Render::renderOnionskin(
|
||||
@ -827,13 +846,36 @@ void Render::renderCel(
|
||||
RenderScaledImage scaled_func,
|
||||
int opacity, BlendMode blend_mode, Zoom zoom)
|
||||
{
|
||||
int cel_x = zoom.apply(cel->x());
|
||||
int cel_y = zoom.apply(cel->y());
|
||||
renderImage(dst_image,
|
||||
cel_image,
|
||||
pal,
|
||||
cel->x(),
|
||||
cel->y(),
|
||||
area,
|
||||
scaled_func,
|
||||
opacity,
|
||||
blend_mode,
|
||||
zoom);
|
||||
}
|
||||
|
||||
void Render::renderImage(
|
||||
Image* dst_image,
|
||||
const Image* cel_image,
|
||||
const Palette* pal,
|
||||
const int x,
|
||||
const int y,
|
||||
const gfx::Clip& area,
|
||||
RenderScaledImage scaled_func,
|
||||
int opacity, BlendMode blend_mode, Zoom zoom)
|
||||
{
|
||||
int cel_x = zoom.apply(x);
|
||||
int cel_y = zoom.apply(y);
|
||||
|
||||
gfx::Rect src_bounds =
|
||||
area.srcBounds().createIntersection(
|
||||
gfx::Rect(
|
||||
cel_x, cel_y,
|
||||
cel_x,
|
||||
cel_y,
|
||||
zoom.apply(cel_image->width()),
|
||||
zoom.apply(cel_image->height())));
|
||||
if (src_bounds.isEmpty())
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Render Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -102,7 +102,8 @@ namespace render {
|
||||
|
||||
// Sets the preview image. This preview image is an alternative
|
||||
// image to be used for the given layer/frame.
|
||||
void setPreviewImage(const Layer* layer, frame_t frame, Image* drawable);
|
||||
void setPreviewImage(const Layer* layer, frame_t frame,
|
||||
Image* image, BlendMode blendMode);
|
||||
void removePreviewImage();
|
||||
|
||||
// Sets an extra cel/image to be drawn after the current
|
||||
@ -190,6 +191,16 @@ namespace render {
|
||||
RenderScaledImage scaled_func,
|
||||
int opacity, BlendMode blend_mode, Zoom zoom);
|
||||
|
||||
void renderImage(
|
||||
Image* dst_image,
|
||||
const Image* cel_image,
|
||||
const Palette* pal,
|
||||
const int x,
|
||||
const int y,
|
||||
const gfx::Clip& area,
|
||||
RenderScaledImage scaled_func,
|
||||
int opacity, BlendMode blend_mode, Zoom zoom);
|
||||
|
||||
static RenderScaledImage getRenderScaledImageFunc(
|
||||
PixelFormat dstFormat,
|
||||
PixelFormat srcFormat);
|
||||
@ -211,6 +222,7 @@ namespace render {
|
||||
const Layer* m_selectedLayer;
|
||||
frame_t m_selectedFrame;
|
||||
Image* m_previewImage;
|
||||
BlendMode m_previewBlendMode;
|
||||
OnionskinOptions m_onionskin;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user