2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
|
|
|
// Copyright (C) 2001-2015 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
|
|
|
|
// published by the Free Software Foundation.
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2012-01-06 06:45:03 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/editor/tool_loop_impl.h"
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/app.h"
|
2015-01-19 09:05:33 +08:00
|
|
|
#include "app/cmd/set_mask.h"
|
2012-01-06 06:45:03 +08:00
|
|
|
#include "app/color.h"
|
|
|
|
#include "app/color_utils.h"
|
2015-04-10 07:05:02 +08:00
|
|
|
#include "app/console.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/context.h"
|
|
|
|
#include "app/context_access.h"
|
2014-08-25 06:22:43 +08:00
|
|
|
#include "app/document_undo.h"
|
2014-12-09 01:57:56 +08:00
|
|
|
#include "app/modules/gui.h"
|
2015-02-15 20:48:38 +08:00
|
|
|
#include "app/pref/preferences.h"
|
2014-12-09 01:57:56 +08:00
|
|
|
#include "app/tools/controller.h"
|
2015-05-22 03:14:26 +08:00
|
|
|
#include "app/tools/freehand_algorithm.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/tools/ink.h"
|
2015-04-27 02:59:28 +08:00
|
|
|
#include "app/tools/point_shape.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/tools/shade_table.h"
|
|
|
|
#include "app/tools/shading_options.h"
|
|
|
|
#include "app/tools/tool.h"
|
|
|
|
#include "app/tools/tool_box.h"
|
|
|
|
#include "app/tools/tool_loop.h"
|
2015-01-19 09:05:33 +08:00
|
|
|
#include "app/transaction.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/color_bar.h"
|
2015-04-29 05:21:33 +08:00
|
|
|
#include "app/ui/context_bar.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/editor/editor.h"
|
2015-04-29 05:21:33 +08:00
|
|
|
#include "app/ui/main_window.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/status_bar.h"
|
|
|
|
#include "app/util/expand_cel_canvas.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/brush.h"
|
|
|
|
#include "doc/cel.h"
|
2015-04-27 02:59:28 +08:00
|
|
|
#include "doc/image.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/layer.h"
|
|
|
|
#include "doc/mask.h"
|
|
|
|
#include "doc/sprite.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "ui/ui.h"
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
namespace app {
|
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
using namespace ui;
|
|
|
|
|
2015-04-27 02:59:28 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2015-05-22 03:00:27 +08:00
|
|
|
// Common properties between drawing/preview ToolLoop impl
|
2015-04-27 02:59:28 +08:00
|
|
|
|
2015-05-22 03:00:27 +08:00
|
|
|
class ToolLoopBase : public tools::ToolLoop,
|
2013-08-06 08:20:19 +08:00
|
|
|
public tools::ShadingOptions {
|
2015-05-22 03:00:27 +08:00
|
|
|
|
|
|
|
protected:
|
2012-01-06 06:45:03 +08:00
|
|
|
Editor* m_editor;
|
|
|
|
tools::Tool* m_tool;
|
2015-04-29 05:21:33 +08:00
|
|
|
BrushRef m_brush;
|
2012-01-06 06:45:03 +08:00
|
|
|
Document* m_document;
|
|
|
|
Sprite* m_sprite;
|
|
|
|
Layer* m_layer;
|
2014-12-29 07:39:11 +08:00
|
|
|
frame_t m_frame;
|
2015-02-15 20:48:38 +08:00
|
|
|
DocumentPreferences& m_docPref;
|
2015-05-19 03:53:25 +08:00
|
|
|
ToolPreferences& m_toolPref;
|
2012-01-06 06:45:03 +08:00
|
|
|
int m_opacity;
|
|
|
|
int m_tolerance;
|
2014-08-07 11:07:24 +08:00
|
|
|
bool m_contiguous;
|
2012-01-06 06:45:03 +08:00
|
|
|
gfx::Point m_offset;
|
|
|
|
gfx::Point m_speed;
|
|
|
|
tools::ToolLoop::Button m_button;
|
2013-04-02 07:44:59 +08:00
|
|
|
tools::Ink* m_ink;
|
2015-05-22 03:14:26 +08:00
|
|
|
tools::Controller* m_controller;
|
|
|
|
tools::PointShape* m_pointShape;
|
|
|
|
tools::Intertwine* m_intertwine;
|
|
|
|
tools::TracePolicy m_tracePolicy;
|
2015-05-19 03:53:25 +08:00
|
|
|
doc::color_t m_fgColor;
|
|
|
|
doc::color_t m_bgColor;
|
|
|
|
doc::color_t m_primaryColor;
|
|
|
|
doc::color_t m_secondaryColor;
|
2013-01-21 05:40:37 +08:00
|
|
|
gfx::Region m_dirtyArea;
|
2012-01-06 06:45:03 +08:00
|
|
|
|
|
|
|
public:
|
2015-05-22 03:00:27 +08:00
|
|
|
ToolLoopBase(Editor* editor,
|
2012-01-06 06:45:03 +08:00
|
|
|
tools::Tool* tool,
|
2014-08-19 19:17:57 +08:00
|
|
|
tools::Ink* ink,
|
2012-01-06 06:45:03 +08:00
|
|
|
Document* document,
|
|
|
|
tools::ToolLoop::Button button,
|
2015-05-19 03:53:25 +08:00
|
|
|
const app::Color& fgColor,
|
|
|
|
const app::Color& bgColor)
|
2012-01-06 06:45:03 +08:00
|
|
|
: m_editor(editor)
|
|
|
|
, m_tool(tool)
|
2015-05-22 03:14:26 +08:00
|
|
|
, m_brush(App::instance()->getMainWindow()->getContextBar()->activeBrush())
|
2012-01-06 06:45:03 +08:00
|
|
|
, m_document(document)
|
2014-07-30 12:28:15 +08:00
|
|
|
, m_sprite(editor->sprite())
|
|
|
|
, m_layer(editor->layer())
|
|
|
|
, m_frame(editor->frame())
|
2015-05-19 03:53:25 +08:00
|
|
|
, m_docPref(Preferences::instance().document(m_document))
|
|
|
|
, m_toolPref(Preferences::instance().tool(m_tool))
|
2015-05-22 03:14:26 +08:00
|
|
|
, m_opacity(m_toolPref.opacity())
|
|
|
|
, m_tolerance(m_toolPref.tolerance())
|
|
|
|
, m_contiguous(m_toolPref.contiguous())
|
2012-01-06 06:45:03 +08:00
|
|
|
, m_button(button)
|
2014-08-19 19:17:57 +08:00
|
|
|
, m_ink(ink)
|
2015-05-22 03:14:26 +08:00
|
|
|
, m_controller(m_tool->getController(m_button))
|
|
|
|
, m_pointShape(m_tool->getPointShape(m_button))
|
|
|
|
, m_intertwine(m_tool->getIntertwine(m_button))
|
|
|
|
, m_tracePolicy(m_tool->getTracePolicy(m_button))
|
2015-07-27 21:53:02 +08:00
|
|
|
, m_fgColor(color_utils::color_for_target_mask(fgColor, ColorTarget(m_layer)))
|
|
|
|
, m_bgColor(color_utils::color_for_target_mask(bgColor, ColorTarget(m_layer)))
|
2015-05-19 03:53:25 +08:00
|
|
|
, m_primaryColor(button == tools::ToolLoop::Left ? m_fgColor: m_bgColor)
|
|
|
|
, m_secondaryColor(button == tools::ToolLoop::Left ? m_bgColor: m_fgColor)
|
2015-05-22 03:00:27 +08:00
|
|
|
{
|
2015-05-22 03:14:26 +08:00
|
|
|
tools::FreehandAlgorithm algorithm = m_toolPref.freehandAlgorithm();
|
|
|
|
|
|
|
|
if (m_tracePolicy == tools::TracePolicy::Accumulate ||
|
|
|
|
m_tracePolicy == tools::TracePolicy::AccumulateUpdateLast) {
|
|
|
|
tools::ToolBox* toolbox = App::instance()->getToolBox();
|
|
|
|
|
|
|
|
switch (algorithm) {
|
|
|
|
case tools::FreehandAlgorithm::DEFAULT:
|
|
|
|
m_intertwine = toolbox->getIntertwinerById(tools::WellKnownIntertwiners::AsLines);
|
|
|
|
m_tracePolicy = tools::TracePolicy::Accumulate;
|
|
|
|
break;
|
|
|
|
case tools::FreehandAlgorithm::PIXEL_PERFECT:
|
|
|
|
m_intertwine = toolbox->getIntertwinerById(tools::WellKnownIntertwiners::AsPixelPerfect);
|
|
|
|
m_tracePolicy = tools::TracePolicy::AccumulateUpdateLast;
|
|
|
|
break;
|
|
|
|
case tools::FreehandAlgorithm::DOTS:
|
|
|
|
m_intertwine = toolbox->getIntertwinerById(tools::WellKnownIntertwiners::None);
|
|
|
|
m_tracePolicy = tools::TracePolicy::Accumulate;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-05-22 03:00:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// IToolLoop interface
|
|
|
|
tools::Tool* getTool() override { return m_tool; }
|
|
|
|
Brush* getBrush() override { return m_brush.get(); }
|
|
|
|
Document* getDocument() override { return m_document; }
|
|
|
|
Sprite* sprite() override { return m_sprite; }
|
|
|
|
Layer* getLayer() override { return m_layer; }
|
|
|
|
frame_t getFrame() override { return m_frame; }
|
|
|
|
RgbMap* getRgbMap() override { return m_sprite->rgbMap(m_frame); }
|
|
|
|
const render::Zoom& zoom() override { return m_editor->zoom(); }
|
|
|
|
ToolLoop::Button getMouseButton() override { return m_button; }
|
|
|
|
doc::color_t getFgColor() override { return m_fgColor; }
|
|
|
|
doc::color_t getBgColor() override { return m_bgColor; }
|
|
|
|
doc::color_t getPrimaryColor() override { return m_primaryColor; }
|
|
|
|
void setPrimaryColor(doc::color_t color) override { m_primaryColor = color; }
|
|
|
|
doc::color_t getSecondaryColor() override { return m_secondaryColor; }
|
|
|
|
void setSecondaryColor(doc::color_t color) override { m_secondaryColor = color; }
|
|
|
|
int getOpacity() override { return m_opacity; }
|
|
|
|
int getTolerance() override { return m_tolerance; }
|
|
|
|
bool getContiguous() override { return m_contiguous; }
|
|
|
|
tools::SelectionMode getSelectionMode() override { return m_editor->getSelectionMode(); }
|
|
|
|
filters::TiledMode getTiledMode() override { return m_docPref.tiled.mode(); }
|
|
|
|
bool getGridVisible() override { return m_docPref.grid.visible(); }
|
|
|
|
bool getSnapToGrid() override { return m_docPref.grid.snap(); }
|
2015-06-18 00:22:46 +08:00
|
|
|
bool getStopAtGrid() override {
|
|
|
|
switch (m_toolPref.floodfill.stopAtGrid()) {
|
|
|
|
case app::gen::StopAtGrid::NEVER:
|
|
|
|
return false;
|
|
|
|
case app::gen::StopAtGrid::IF_VISIBLE:
|
|
|
|
return m_docPref.grid.visible();
|
|
|
|
case app::gen::StopAtGrid::ALWAYS:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2015-05-22 03:00:27 +08:00
|
|
|
gfx::Rect getGridBounds() override { return m_docPref.grid.bounds(); }
|
|
|
|
gfx::Point getOffset() override { return m_offset; }
|
|
|
|
void setSpeed(const gfx::Point& speed) override { m_speed = speed; }
|
|
|
|
gfx::Point getSpeed() override { return m_speed; }
|
|
|
|
tools::Ink* getInk() override { return m_ink; }
|
2015-05-22 03:14:26 +08:00
|
|
|
tools::Controller* getController() override { return m_controller; }
|
|
|
|
tools::PointShape* getPointShape() override { return m_pointShape; }
|
|
|
|
tools::Intertwine* getIntertwine() override { return m_intertwine; }
|
|
|
|
tools::TracePolicy getTracePolicy() override { return m_tracePolicy; }
|
2015-05-22 03:00:27 +08:00
|
|
|
tools::ShadingOptions* getShadingOptions() override { return this; }
|
|
|
|
|
|
|
|
gfx::Point screenToSprite(const gfx::Point& screenPoint) override {
|
|
|
|
return m_editor->screenToEditor(screenPoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx::Region& getDirtyArea() override {
|
|
|
|
return m_dirtyArea;
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateDirtyArea() override {
|
2015-07-06 22:05:49 +08:00
|
|
|
// TODO find a way to avoid calling hide/show brush preview here
|
|
|
|
HideBrushPreview hide(m_editor->brushPreview());
|
2015-05-22 03:00:27 +08:00
|
|
|
m_document->notifySpritePixelsModified(m_sprite, m_dirtyArea);
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateStatusBar(const char* text) override {
|
|
|
|
StatusBar::instance()->setStatusText(0, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ShadingOptions implementation
|
|
|
|
tools::ShadeTable8* getShadeTable() override {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// For drawing
|
|
|
|
|
|
|
|
class ToolLoopImpl : public ToolLoopBase {
|
|
|
|
Context* m_context;
|
|
|
|
bool m_filled;
|
|
|
|
bool m_previewFilled;
|
|
|
|
int m_sprayWidth;
|
|
|
|
int m_spraySpeed;
|
|
|
|
bool m_useMask;
|
|
|
|
Mask* m_mask;
|
|
|
|
gfx::Point m_maskOrigin;
|
|
|
|
bool m_canceled;
|
|
|
|
Transaction m_transaction;
|
|
|
|
ExpandCelCanvas m_expandCelCanvas;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ToolLoopImpl(Editor* editor,
|
|
|
|
Context* context,
|
|
|
|
tools::Tool* tool,
|
|
|
|
tools::Ink* ink,
|
|
|
|
Document* document,
|
|
|
|
tools::ToolLoop::Button button,
|
|
|
|
const app::Color& fgColor,
|
|
|
|
const app::Color& bgColor)
|
|
|
|
: ToolLoopBase(editor, tool, ink, document,
|
2015-06-29 22:00:46 +08:00
|
|
|
button, fgColor, bgColor)
|
2015-05-22 03:00:27 +08:00
|
|
|
, m_context(context)
|
|
|
|
, m_canceled(false)
|
2015-01-19 09:05:33 +08:00
|
|
|
, m_transaction(m_context,
|
|
|
|
m_tool->getText().c_str(),
|
|
|
|
((getInk()->isSelection() ||
|
|
|
|
getInk()->isEyedropper() ||
|
|
|
|
getInk()->isScrollMovement() ||
|
|
|
|
getInk()->isSlice() ||
|
|
|
|
getInk()->isZoom()) ? DoesntModifyDocument:
|
|
|
|
ModifyDocument))
|
2015-04-21 03:27:09 +08:00
|
|
|
, m_expandCelCanvas(editor->getSite(),
|
2015-02-15 20:48:38 +08:00
|
|
|
m_docPref.tiled.mode(),
|
2015-01-19 09:05:33 +08:00
|
|
|
m_transaction,
|
2014-12-09 01:57:56 +08:00
|
|
|
ExpandCelCanvas::Flags(
|
|
|
|
ExpandCelCanvas::NeedsSource |
|
|
|
|
// If the tool is freehand-like, we can use the modified
|
|
|
|
// region directly as undo information to save the modified
|
|
|
|
// pixels (it's faster than creating a Dirty object).
|
|
|
|
// See ExpandCelCanvas::commit() for details about this flag.
|
|
|
|
(getController()->isFreehand() ?
|
|
|
|
ExpandCelCanvas::UseModifiedRegionAsUndoInfo:
|
|
|
|
ExpandCelCanvas::None)))
|
2012-01-06 06:45:03 +08:00
|
|
|
{
|
2012-11-18 21:21:06 +08:00
|
|
|
// Settings
|
2012-01-06 06:45:03 +08:00
|
|
|
switch (tool->getFill(m_button)) {
|
|
|
|
case tools::FillNone:
|
|
|
|
m_filled = false;
|
|
|
|
break;
|
|
|
|
case tools::FillAlways:
|
|
|
|
m_filled = true;
|
|
|
|
break;
|
|
|
|
case tools::FillOptional:
|
2015-05-19 03:53:25 +08:00
|
|
|
m_filled = m_toolPref.filled();
|
2012-01-06 06:45:03 +08:00
|
|
|
break;
|
|
|
|
}
|
2014-01-26 04:58:29 +08:00
|
|
|
|
2015-05-19 03:53:25 +08:00
|
|
|
m_previewFilled = m_toolPref.filledPreview();
|
|
|
|
m_sprayWidth = m_toolPref.spray.width();
|
|
|
|
m_spraySpeed = m_toolPref.spray.speed();
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2014-08-27 20:43:42 +08:00
|
|
|
if (m_ink->isSelection())
|
|
|
|
m_useMask = false;
|
|
|
|
else
|
|
|
|
m_useMask = m_document->isMaskVisible();
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2015-01-19 09:05:33 +08:00
|
|
|
// Start with an empty mask if the user is selecting with "default selection mode"
|
2014-01-26 04:58:29 +08:00
|
|
|
if (getInk()->isSelection() &&
|
|
|
|
(!m_document->isMaskVisible() ||
|
2015-05-19 03:53:25 +08:00
|
|
|
getSelectionMode() == tools::SelectionMode::DEFAULT)) {
|
2012-01-06 06:45:03 +08:00
|
|
|
Mask emptyMask;
|
2015-01-19 09:05:33 +08:00
|
|
|
m_transaction.execute(new cmd::SetMask(m_document, &emptyMask));
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
|
2014-07-30 12:28:15 +08:00
|
|
|
int x1 = m_expandCelCanvas.getCel()->x();
|
|
|
|
int y1 = m_expandCelCanvas.getCel()->y();
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2014-07-30 12:28:15 +08:00
|
|
|
m_mask = m_document->mask();
|
|
|
|
m_maskOrigin = (!m_mask->isEmpty() ? gfx::Point(m_mask->bounds().x-x1,
|
|
|
|
m_mask->bounds().y-y1):
|
2012-01-09 09:34:36 +08:00
|
|
|
gfx::Point(0, 0));
|
2012-01-06 06:45:03 +08:00
|
|
|
|
|
|
|
m_offset.x = -x1;
|
|
|
|
m_offset.y = -y1;
|
|
|
|
}
|
|
|
|
|
2015-04-10 22:12:19 +08:00
|
|
|
// IToolLoop interface
|
|
|
|
void dispose() override
|
2012-01-06 06:45:03 +08:00
|
|
|
{
|
2014-12-09 01:57:56 +08:00
|
|
|
bool redraw = false;
|
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
if (!m_canceled) {
|
|
|
|
// Paint ink
|
|
|
|
if (getInk()->isPaint()) {
|
2015-04-10 22:10:42 +08:00
|
|
|
try {
|
|
|
|
ContextReader reader(m_context, 500);
|
|
|
|
ContextWriter writer(reader, 500);
|
|
|
|
m_expandCelCanvas.commit();
|
|
|
|
}
|
|
|
|
catch (const LockedDocumentException& ex) {
|
|
|
|
Console::showException(ex);
|
2015-04-08 04:50:57 +08:00
|
|
|
}
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
// Selection ink
|
|
|
|
else if (getInk()->isSelection()) {
|
|
|
|
m_document->generateMaskBoundaries();
|
2014-12-09 01:57:56 +08:00
|
|
|
redraw = true;
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
2012-07-08 12:25:26 +08:00
|
|
|
|
2015-01-19 09:05:33 +08:00
|
|
|
m_transaction.commit();
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
2014-12-09 01:57:56 +08:00
|
|
|
else
|
|
|
|
redraw = true;
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2014-12-09 01:57:56 +08:00
|
|
|
// If the trace was canceled or it is not a 'paint' ink...
|
2012-01-06 06:45:03 +08:00
|
|
|
if (m_canceled || !getInk()->isPaint()) {
|
2015-04-10 22:10:42 +08:00
|
|
|
try {
|
|
|
|
ContextReader reader(m_context, 500);
|
|
|
|
ContextWriter writer(reader, 500);
|
|
|
|
m_expandCelCanvas.rollback();
|
|
|
|
}
|
|
|
|
catch (const LockedDocumentException& ex) {
|
|
|
|
Console::showException(ex);
|
2015-04-08 04:50:57 +08:00
|
|
|
}
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
|
2014-12-09 01:57:56 +08:00
|
|
|
if (redraw)
|
|
|
|
update_screen_for_document(m_document);
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
|
2014-12-09 01:57:56 +08:00
|
|
|
const Image* getSrcImage() override { return m_expandCelCanvas.getSourceCanvas(); }
|
2014-08-15 10:07:47 +08:00
|
|
|
Image* getDstImage() override { return m_expandCelCanvas.getDestCanvas(); }
|
2014-12-09 01:57:56 +08:00
|
|
|
void validateSrcImage(const gfx::Region& rgn) override {
|
|
|
|
return m_expandCelCanvas.validateSourceCanvas(rgn);
|
|
|
|
}
|
|
|
|
void validateDstImage(const gfx::Region& rgn) override {
|
|
|
|
return m_expandCelCanvas.validateDestCanvas(rgn);
|
|
|
|
}
|
|
|
|
void invalidateDstImage() override {
|
|
|
|
return m_expandCelCanvas.invalidateDestCanvas();
|
|
|
|
}
|
|
|
|
void invalidateDstImage(const gfx::Region& rgn) override {
|
|
|
|
return m_expandCelCanvas.invalidateDestCanvas(rgn);
|
|
|
|
}
|
|
|
|
void copyValidDstToSrcImage(const gfx::Region& rgn) override {
|
|
|
|
return m_expandCelCanvas.copyValidDestToSourceCanvas(rgn);
|
|
|
|
}
|
|
|
|
|
2014-08-15 10:07:47 +08:00
|
|
|
bool useMask() override { return m_useMask; }
|
|
|
|
Mask* getMask() override { return m_mask; }
|
2015-01-19 09:05:33 +08:00
|
|
|
void setMask(Mask* newMask) override {
|
|
|
|
m_transaction.execute(new cmd::SetMask(m_document, newMask));
|
|
|
|
}
|
2014-08-15 10:07:47 +08:00
|
|
|
gfx::Point getMaskOrigin() override { return m_maskOrigin; }
|
|
|
|
bool getFilled() override { return m_filled; }
|
|
|
|
bool getPreviewFilled() override { return m_previewFilled; }
|
|
|
|
int getSprayWidth() override { return m_sprayWidth; }
|
|
|
|
int getSpraySpeed() override { return m_spraySpeed; }
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2014-08-15 10:07:47 +08:00
|
|
|
void cancel() override { m_canceled = true; }
|
|
|
|
bool isCanceled() override { return m_canceled; }
|
2012-01-06 06:45:03 +08:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2014-08-19 19:17:57 +08:00
|
|
|
tools::ToolLoop* create_tool_loop(Editor* editor, Context* context)
|
2012-01-06 06:45:03 +08:00
|
|
|
{
|
2014-08-19 19:17:57 +08:00
|
|
|
tools::Tool* current_tool = editor->getCurrentEditorTool();
|
|
|
|
tools::Ink* current_ink = editor->getCurrentEditorInk();
|
|
|
|
if (!current_tool || !current_ink)
|
2012-01-06 06:45:03 +08:00
|
|
|
return NULL;
|
|
|
|
|
2014-07-30 12:28:15 +08:00
|
|
|
Layer* layer = editor->layer();
|
2012-01-06 06:45:03 +08:00
|
|
|
if (!layer) {
|
2014-11-24 22:50:02 +08:00
|
|
|
StatusBar::instance()->showTip(1000,
|
|
|
|
"There is no active layer");
|
2012-01-06 06:45:03 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the active layer is not visible.
|
2014-11-17 10:03:30 +08:00
|
|
|
if (!layer->isVisible()) {
|
2014-11-24 22:50:02 +08:00
|
|
|
StatusBar::instance()->showTip(1000,
|
|
|
|
"Layer '%s' is hidden", layer->name().c_str());
|
2012-01-06 06:45:03 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// If the active layer is read-only.
|
2014-11-17 10:03:30 +08:00
|
|
|
else if (!layer->isEditable()) {
|
2014-11-24 22:50:02 +08:00
|
|
|
StatusBar::instance()->showTip(1000,
|
|
|
|
"Layer '%s' is locked", layer->name().c_str());
|
2012-01-06 06:45:03 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get fg/bg colors
|
2012-07-10 00:20:58 +08:00
|
|
|
ColorBar* colorbar = ColorBar::instance();
|
2013-01-07 01:45:43 +08:00
|
|
|
app::Color fg = colorbar->getFgColor();
|
|
|
|
app::Color bg = colorbar->getBgColor();
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2015-06-29 22:00:46 +08:00
|
|
|
ASSERT(fg.isValid());
|
|
|
|
ASSERT(bg.isValid());
|
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
if (!fg.isValid() || !bg.isValid()) {
|
|
|
|
Alert::show(PACKAGE
|
|
|
|
"<<The current selected foreground and/or background color"
|
2015-06-29 22:00:46 +08:00
|
|
|
"<<is out of range. Select a valid color in the color-bar."
|
2012-01-06 06:45:03 +08:00
|
|
|
"||&Close");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the new tool loop
|
2014-08-19 19:17:57 +08:00
|
|
|
try {
|
2015-05-19 03:53:25 +08:00
|
|
|
return new ToolLoopImpl(
|
|
|
|
editor, context,
|
2014-08-19 19:17:57 +08:00
|
|
|
current_tool,
|
|
|
|
current_ink,
|
|
|
|
editor->document(),
|
|
|
|
!editor->isSecondaryButton() ? tools::ToolLoop::Left: tools::ToolLoop::Right,
|
2015-05-19 03:53:25 +08:00
|
|
|
fg, bg);
|
2013-11-11 03:20:20 +08:00
|
|
|
}
|
2014-08-19 19:17:57 +08:00
|
|
|
catch (const std::exception& ex) {
|
2013-11-11 03:20:20 +08:00
|
|
|
Alert::show(PACKAGE
|
|
|
|
"<<Error drawing ink:"
|
|
|
|
"<<%s"
|
|
|
|
"||&Close",
|
|
|
|
ex.what());
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2015-04-27 02:59:28 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// For preview
|
|
|
|
|
2015-05-22 03:00:27 +08:00
|
|
|
class PreviewToolLoopImpl : public ToolLoopBase {
|
2015-04-27 02:59:28 +08:00
|
|
|
Image* m_image;
|
|
|
|
|
|
|
|
public:
|
|
|
|
PreviewToolLoopImpl(
|
|
|
|
Editor* editor,
|
|
|
|
Context* context,
|
|
|
|
tools::Tool* tool,
|
|
|
|
tools::Ink* ink,
|
|
|
|
Document* document,
|
2015-05-19 03:53:25 +08:00
|
|
|
const app::Color& fgColor,
|
|
|
|
const app::Color& bgColor,
|
2015-04-27 02:59:28 +08:00
|
|
|
Image* image,
|
|
|
|
const gfx::Point& offset)
|
2015-05-22 03:00:27 +08:00
|
|
|
: ToolLoopBase(editor, tool, ink, document,
|
|
|
|
tools::ToolLoop::Left, fgColor, bgColor)
|
2015-04-27 02:59:28 +08:00
|
|
|
, m_image(image)
|
|
|
|
{
|
2015-05-22 03:00:27 +08:00
|
|
|
m_offset = offset;
|
2015-04-27 02:59:28 +08:00
|
|
|
|
|
|
|
// Avoid preview for spray and flood fill like tools
|
|
|
|
if (m_pointShape->isSpray()) {
|
|
|
|
m_pointShape = App::instance()->getToolBox()->getPointShapeById(
|
|
|
|
tools::WellKnownPointShapes::Brush);
|
|
|
|
}
|
|
|
|
else if (m_pointShape->isFloodFill()) {
|
|
|
|
m_pointShape = App::instance()->getToolBox()->getPointShapeById(
|
|
|
|
tools::WellKnownPointShapes::Pixel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// IToolLoop interface
|
|
|
|
void dispose() override { }
|
|
|
|
const Image* getSrcImage() override { return m_image; }
|
|
|
|
Image* getDstImage() override { return m_image; }
|
|
|
|
void validateSrcImage(const gfx::Region& rgn) override { }
|
|
|
|
void validateDstImage(const gfx::Region& rgn) override { }
|
|
|
|
void invalidateDstImage() override { }
|
|
|
|
void invalidateDstImage(const gfx::Region& rgn) override { }
|
|
|
|
void copyValidDstToSrcImage(const gfx::Region& rgn) override { }
|
|
|
|
|
2015-05-22 03:00:27 +08:00
|
|
|
bool useMask() override { return false; }
|
|
|
|
Mask* getMask() override { return nullptr; }
|
2015-04-27 02:59:28 +08:00
|
|
|
void setMask(Mask* newMask) override { }
|
2015-05-22 03:00:27 +08:00
|
|
|
gfx::Point getMaskOrigin() override { return gfx::Point(0, 0); }
|
2015-04-27 02:59:28 +08:00
|
|
|
bool getFilled() override { return false; }
|
|
|
|
bool getPreviewFilled() override { return false; }
|
|
|
|
int getSprayWidth() override { return 0; }
|
|
|
|
int getSpraySpeed() override { return 0; }
|
|
|
|
|
|
|
|
void cancel() override { }
|
|
|
|
bool isCanceled() override { return true; }
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
tools::ToolLoop* create_tool_loop_preview(
|
|
|
|
Editor* editor, Context* context, Image* image,
|
|
|
|
const gfx::Point& offset)
|
|
|
|
{
|
|
|
|
tools::Tool* current_tool = editor->getCurrentEditorTool();
|
|
|
|
tools::Ink* current_ink = editor->getCurrentEditorInk();
|
|
|
|
if (!current_tool || !current_ink)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
Layer* layer = editor->layer();
|
|
|
|
if (!layer ||
|
|
|
|
!layer->isVisible() ||
|
|
|
|
!layer->isEditable()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get fg/bg colors
|
|
|
|
ColorBar* colorbar = ColorBar::instance();
|
|
|
|
app::Color fg = colorbar->getFgColor();
|
|
|
|
app::Color bg = colorbar->getBgColor();
|
|
|
|
if (!fg.isValid() || !bg.isValid())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
// Create the new tool loop
|
|
|
|
try {
|
|
|
|
return new PreviewToolLoopImpl(
|
|
|
|
editor, context,
|
|
|
|
current_tool,
|
|
|
|
current_ink,
|
|
|
|
editor->document(),
|
|
|
|
fg, bg, image, offset);
|
|
|
|
}
|
|
|
|
catch (const std::exception&) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
} // namespace app
|