Add command to fill selection with foreground color (F key, related to #1387)

This commit is contained in:
David Capello 2018-05-30 16:53:20 -03:00
parent 6ab467e5f9
commit 291e9c7dde
9 changed files with 207 additions and 29 deletions

View File

@ -18,7 +18,7 @@
<key command="ImportSpriteSheet" shortcut="Ctrl+I" mac="Cmd+I" /> <key command="ImportSpriteSheet" shortcut="Ctrl+I" mac="Cmd+I" />
<key command="ExportSpriteSheet" shortcut="Ctrl+E" mac="Cmd+E" /> <key command="ExportSpriteSheet" shortcut="Ctrl+E" mac="Cmd+E" />
<key command="RepeatLastExport" shortcut="Ctrl+Shift+X" mac="Cmd+Shift+X" /> <key command="RepeatLastExport" shortcut="Ctrl+Shift+X" mac="Cmd+Shift+X" />
<key command="AdvancedMode" shortcut="F" /> <key command="AdvancedMode" shortcut="Ctrl+F" />
<key command="DeveloperConsole" shortcut="F12" /> <key command="DeveloperConsole" shortcut="F12" />
<key command="Exit" win="Ctrl+Q" linux="Ctrl+Q" mac="Cmd+Q" /> <key command="Exit" win="Ctrl+Q" linux="Ctrl+Q" mac="Cmd+Q" />
<key command="Exit" win="Alt+F4" /> <key command="Exit" win="Alt+F4" />
@ -39,6 +39,7 @@
<key command="Paste" shortcut="Shift+Ins" /> <key command="Paste" shortcut="Shift+Ins" />
<key command="Clear" shortcut="Del" /> <key command="Clear" shortcut="Del" />
<key command="Clear" shortcut="Backspace" /> <key command="Clear" shortcut="Backspace" />
<key command="Fill" shortcut="F" />
<key command="Flip" shortcut="Shift+H"> <key command="Flip" shortcut="Shift+H">
<param name="target" value="mask" /> <param name="target" value="mask" />
<param name="orientation" value="horizontal" /> <param name="orientation" value="horizontal" />
@ -591,6 +592,8 @@
<item command="Paste" text="@.edit_paste" /> <item command="Paste" text="@.edit_paste" />
<item command="Clear" text="@.edit_clear" /> <item command="Clear" text="@.edit_clear" />
<separator /> <separator />
<item command="Fill" text="@.edit_fill" />
<separator />
<menu text="@.edit_rotate"> <menu text="@.edit_rotate">
<item command="Rotate" text="@.edit_rotate_180"> <item command="Rotate" text="@.edit_rotate_180">
<param name="target" value="mask" /> <param name="target" value="mask" />

View File

@ -228,6 +228,7 @@ DuplicateView = Duplicate View
Exit = Exit Exit = Exit
ExportSpriteSheet = Export Sprite Sheet ExportSpriteSheet = Export Sprite Sheet
Eyedropper = Eyedropper Eyedropper = Eyedropper
Fill = Fill Selection with Foreground Color
FitScreen = Fit on Screen FitScreen = Fit on Screen
FlattenLayers = Flatten Layers FlattenLayers = Flatten Layers
Flip = Flip {0} {1} Flip = Flip {0} {1}
@ -636,6 +637,7 @@ edit_copy = &Copy
edit_copy_merged = Copy Mer&ged edit_copy_merged = Copy Mer&ged
edit_paste = &Paste edit_paste = &Paste
edit_clear = &Delete edit_clear = &Delete
edit_fill = &Fill
edit_rotate = R&otate edit_rotate = R&otate
edit_rotate_180 = &180 edit_rotate_180 = &180
edit_rotate_90cw = &90 CW edit_rotate_90cw = &90 CW
@ -661,7 +663,7 @@ edit_fx_convolution_matrix = Convolution &Matrix...
edit_fx_despeckle = &Despeckle (Median Filter)... edit_fx_despeckle = &Despeckle (Median Filter)...
edit_insert_text = Insert Text edit_insert_text = Insert Text
edit_keyboard_shortcuts = &Keyboard Shortcuts... edit_keyboard_shortcuts = &Keyboard Shortcuts...
edit_preferences = Pre&ferences... edit_preferences = Preferences&...
sprite = &Sprite sprite = &Sprite
sprite_properties = &Properties... sprite_properties = &Properties...
sprite_color_mode = Color &Mode sprite_color_mode = Color &Mode

View File

@ -196,6 +196,7 @@ if(ENABLE_UI)
commands/cmd_exit.cpp commands/cmd_exit.cpp
commands/cmd_export_sprite_sheet.cpp commands/cmd_export_sprite_sheet.cpp
commands/cmd_eyedropper.cpp commands/cmd_eyedropper.cpp
commands/cmd_fill.cpp
commands/cmd_fit_screen.cpp commands/cmd_fit_screen.cpp
commands/cmd_flatten_layers.cpp commands/cmd_flatten_layers.cpp
commands/cmd_flip.cpp commands/cmd_flip.cpp
@ -390,6 +391,7 @@ if(ENABLE_UI)
ui_context.cpp ui_context.cpp
util/clipboard.cpp util/clipboard.cpp
util/clipboard_native.cpp util/clipboard_native.cpp
util/fill_selection.cpp
widget_loader.cpp) widget_loader.cpp)
endif() endif()

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -12,6 +12,7 @@
#include "app/cmd/clear_cel.h" #include "app/cmd/clear_cel.h"
#include "app/document.h" #include "app/document.h"
#include "app/util/fill_selection.h"
#include "doc/cel.h" #include "doc/cel.h"
#include "doc/image_impl.h" #include "doc/image_impl.h"
#include "doc/layer.h" #include "doc/layer.h"
@ -35,18 +36,18 @@ ClearMask::ClearMask(Cel* cel)
return; return;
} }
Image* image = (cel ? cel->image(): NULL); Image* image = cel->image();
assert(image);
if (!image) if (!image)
return; return;
Mask* mask = doc->mask(); Mask* mask = doc->mask();
m_offsetX = mask->bounds().x - cel->x(); m_offset = mask->bounds().origin() - cel->position();
m_offsetY = mask->bounds().y - cel->y();
gfx::Rect bounds = gfx::Rect bounds =
image->bounds().createIntersection( image->bounds().createIntersection(
gfx::Rect( gfx::Rect(
m_offsetX, m_offsetY, m_offset.x, m_offset.y,
mask->bounds().w, mask->bounds().h)); mask->bounds().w, mask->bounds().h));
if (bounds.isEmpty()) if (bounds.isEmpty())
return; return;
@ -88,27 +89,7 @@ void ClearMask::clear()
app::Document* doc = static_cast<app::Document*>(cel->document()); app::Document* doc = static_cast<app::Document*>(cel->document());
Mask* mask = doc->mask(); Mask* mask = doc->mask();
ASSERT(mask->bitmap()); fill_selection(image, m_offset, mask, m_bgcolor);
if (!mask->bitmap())
return;
const LockImageBits<BitmapTraits> maskBits(mask->bitmap());
LockImageBits<BitmapTraits>::const_iterator it = maskBits.begin();
// Clear the masked zones
int u, v;
for (v=0; v<mask->bounds().h; ++v) {
for (u=0; u<mask->bounds().w; ++u, ++it) {
ASSERT(it != maskBits.end());
if (*it) {
put_pixel(image,
u + m_offsetX,
v + m_offsetY, m_bgcolor);
}
}
}
ASSERT(it == maskBits.end());
} }
void ClearMask::restore() void ClearMask::restore()

View File

@ -40,7 +40,7 @@ namespace cmd {
CmdSequence m_seq; CmdSequence m_seq;
base::UniquePtr<WithImage> m_dstImage; base::UniquePtr<WithImage> m_dstImage;
ImageRef m_copy; ImageRef m_copy;
int m_offsetX, m_offsetY; gfx::Point m_offset;
int m_boundsX, m_boundsY; int m_boundsX, m_boundsY;
color_t m_bgcolor; color_t m_bgcolor;
}; };

View File

@ -0,0 +1,113 @@
// Aseprite
// Copyright (C) 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/app.h"
#include "app/cmd/clear_mask.h"
#include "app/cmd/trim_cel.h"
#include "app/color_utils.h"
#include "app/commands/command.h"
#include "app/context_access.h"
#include "app/modules/editors.h"
#include "app/pref/preferences.h"
#include "app/transaction.h"
#include "app/ui/editor/editor.h"
#include "app/util/expand_cel_canvas.h"
#include "app/util/fill_selection.h"
#include "doc/mask.h"
namespace app {
class FillCommand : public Command {
public:
FillCommand();
Command* clone() const override { return new FillCommand(*this); }
protected:
bool onEnabled(Context* ctx) override;
void onExecute(Context* ctx) override;
};
FillCommand::FillCommand()
: Command(CommandId::Fill(), CmdUIOnlyFlag)
{
}
bool FillCommand::onEnabled(Context* ctx)
{
if (ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable |
ContextFlags::ActiveLayerIsVisible |
ContextFlags::ActiveLayerIsEditable |
ContextFlags::ActiveLayerIsImage)) {
return true;
}
else if (current_editor &&
current_editor->isMovingPixels()) {
return true;
}
else
return false;
}
void FillCommand::onExecute(Context* ctx)
{
ContextWriter writer(ctx);
Site site = *writer.site();
Document* doc = (app::Document*)site.document();
Sprite* sprite = site.sprite();
Cel* cel = site.cel();
Mask* mask = doc->mask();
if (!doc || !sprite || !cel || !mask ||
!doc->isMaskVisible())
return;
Preferences& pref = Preferences::instance();
app::Color color = pref.colorBar.fgColor();
{
Transaction transaction(writer.context(), "Fill Selection with Foreground Color");
{
ExpandCelCanvas expand(
site, cel->layer(),
TiledMode::NONE, transaction,
ExpandCelCanvas::None);
gfx::Region rgn(sprite->bounds() |
mask->bounds());
expand.validateDestCanvas(rgn);
const gfx::Point offset = (mask->bounds().origin()
- expand.getCel()->position());
fill_selection(expand.getDestCanvas(),
offset,
mask,
color_utils::color_for_layer(color,
cel->layer()));
expand.commit();
}
// If the cel wasn't deleted by cmd::ClearMask, we trim it.
cel = ctx->activeSite().cel();
if (cel && cel->layer()->isTransparent())
transaction.execute(new cmd::TrimCel(cel));
transaction.commit();
}
doc->notifyGeneralUpdate();
}
Command* CommandFactory::createFillCommand()
{
return new FillCommand;
}
} // namespace app

View File

@ -48,6 +48,7 @@ FOR_EACH_COMMAND(DuplicateView)
FOR_EACH_COMMAND(Exit) FOR_EACH_COMMAND(Exit)
FOR_EACH_COMMAND(ExportSpriteSheet) FOR_EACH_COMMAND(ExportSpriteSheet)
FOR_EACH_COMMAND(Eyedropper) FOR_EACH_COMMAND(Eyedropper)
FOR_EACH_COMMAND(Fill)
FOR_EACH_COMMAND(FitScreen) FOR_EACH_COMMAND(FitScreen)
FOR_EACH_COMMAND(FlattenLayers) FOR_EACH_COMMAND(FlattenLayers)
FOR_EACH_COMMAND(Flip) FOR_EACH_COMMAND(Flip)

View File

@ -0,0 +1,48 @@
// Aseprite
// Copyright (C) 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/util/fill_selection.h"
#include "doc/image_impl.h"
#include "doc/mask.h"
#include "doc/primitives.h"
namespace app {
using namespace doc;
void fill_selection(Image* image,
const gfx::Point& offset,
const Mask* mask,
const color_t color)
{
ASSERT(mask->bitmap());
if (!mask->bitmap())
return;
const LockImageBits<BitmapTraits> maskBits(mask->bitmap());
LockImageBits<BitmapTraits>::const_iterator it = maskBits.begin();
const gfx::Rect maskBounds = mask->bounds();
for (int v=0; v<maskBounds.h; ++v) {
for (int u=0; u<maskBounds.w; ++u, ++it) {
ASSERT(it != maskBits.end());
if (*it) {
put_pixel(image,
u + offset.x,
v + offset.y, color);
}
}
}
ASSERT(it == maskBits.end());
}
} // namespace app

View File

@ -0,0 +1,28 @@
// Aseprite
// Copyright (C) 2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_UTIL_FILL_SELECTION_H_INCLUDED
#define APP_UTIL_FILL_SELECTION_H_INCLUDED
#pragma once
#include "doc/color.h"
#include "gfx/point.h"
namespace doc {
class Image;
class Mask;
}
namespace app {
void fill_selection(doc::Image* image,
const gfx::Point& offset,
const doc::Mask* mask,
const doc::color_t color);
} // namespace app
#endif