aseprite/src/app/tools/active_tool.cpp

259 lines
6.8 KiB
C++

// Aseprite
// Copyright (C) 2018-2023 Igara Studio S.A.
// Copyright (C) 2016 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/tools/active_tool.h"
#include "app/app.h"
#include "app/color.h"
#include "app/pref/preferences.h"
#include "app/tools/active_tool_observer.h"
#include "app/tools/ink.h"
#include "app/tools/pointer.h"
#include "app/tools/tool_box.h"
#include "app/ui/color_bar.h"
#include "app/ui/context_bar.h"
namespace app {
namespace tools {
class ActiveToolChangeTrigger {
public:
ActiveToolChangeTrigger(ActiveToolManager* manager)
: m_manager(manager)
, m_oldTool(manager->activeTool()) {
}
~ActiveToolChangeTrigger() {
Tool* newTool = m_manager->activeTool();
if (m_oldTool != newTool) {
m_manager->notify_observers(
&ActiveToolObserver::onActiveToolChange, newTool);
}
}
private:
ActiveToolManager* m_manager;
Tool* m_oldTool;
};
ActiveToolManager::ActiveToolManager(ToolBox* toolbox)
: m_toolbox(toolbox)
, m_quickTool(nullptr)
, m_rightClick(false)
, m_rightClickTool(nullptr)
, m_rightClickInk(nullptr)
, m_proximityTool(nullptr)
, m_selectedTool(m_toolbox->getToolById(WellKnownTools::Pencil)) // "pencil" is the active tool by default
{
}
Tool* ActiveToolManager::activeTool() const
{
if (m_quickTool)
return m_quickTool;
if (m_rightClickTool)
return m_rightClickTool;
if (m_proximityTool)
return m_proximityTool;
// Active tool should never returns null
ASSERT(m_selectedTool);
return m_selectedTool;
}
Ink* ActiveToolManager::activeInk() const
{
if (!m_quickTool && m_rightClickInk)
return m_rightClickInk;
Tool* tool = activeTool();
Ink* ink = tool->getInk(m_rightClick ? 1: 0);
if (ink->isPaint() && !ink->isEffect()) {
const tools::InkType inkType = Preferences::instance().tool(tool).ink();
app::Color color;
if (ColorBar* colorbar = ColorBar::instance()) {
color = (m_rightClick ? colorbar->getBgColor():
colorbar->getFgColor());
}
ink = adjustToolInkDependingOnSelectedInkType(ink, inkType, color);
}
return ink;
}
Ink* ActiveToolManager::adjustToolInkDependingOnSelectedInkType(
Ink* ink,
const InkType inkType,
const app::Color& color) const
{
if (ink->isPaint() && !ink->isEffect()) {
const char* id = nullptr;
switch (inkType) {
case tools::InkType::SIMPLE:
id = tools::WellKnownInks::Paint;
if (color.getAlpha() == 0)
id = tools::WellKnownInks::PaintCopy;
break;
case tools::InkType::ALPHA_COMPOSITING:
id = tools::WellKnownInks::PaintAlphaCompositing;
break;
case tools::InkType::COPY_COLOR:
id = tools::WellKnownInks::PaintCopy;
break;
case tools::InkType::LOCK_ALPHA:
id = tools::WellKnownInks::PaintLockAlpha;
break;
case tools::InkType::SHADING:
id = tools::WellKnownInks::Shading;
break;
}
if (id)
ink = m_toolbox->getInkById(id);
}
return ink;
}
Tool* ActiveToolManager::quickTool() const
{
return m_quickTool;
}
Tool* ActiveToolManager::selectedTool() const
{
return m_selectedTool;
}
void ActiveToolManager::newToolSelectedInToolBar(Tool* tool)
{
ActiveToolChangeTrigger trigger(this);
m_selectedTool = tool;
}
void ActiveToolManager::newQuickToolSelectedFromEditor(Tool* tool)
{
ActiveToolChangeTrigger trigger(this);
m_quickTool = tool;
}
void ActiveToolManager::brushChanged()
{
ActiveToolChangeTrigger trigger(this);
m_quickTool = nullptr;
}
void ActiveToolManager::regularTipProximity()
{
if (m_proximityTool != nullptr) {
ActiveToolChangeTrigger trigger(this);
m_proximityTool = nullptr;
}
}
void ActiveToolManager::eraserTipProximity()
{
Tool* eraser = m_toolbox->getToolById(WellKnownTools::Eraser);
if (m_proximityTool != eraser) {
ActiveToolChangeTrigger trigger(this);
m_proximityTool = eraser;
}
}
void ActiveToolManager::pressButton(const Pointer& pointer)
{
ActiveToolChangeTrigger trigger(this);
Tool* tool = nullptr;
Ink* ink = nullptr;
if (pointer.button() == Pointer::Right) {
m_rightClick = true;
if (isToolAffectedByRightClickMode(activeTool())) {
switch (Preferences::instance().editor.rightClickMode()) {
case app::gen::RightClickMode::PAINT_BGCOLOR:
// Do nothing, use the active tool
break;
case app::gen::RightClickMode::PICK_FGCOLOR:
tool = m_toolbox->getToolById(WellKnownTools::Eyedropper);
ink = m_toolbox->getInkById(tools::WellKnownInks::PickFg);
break;
case app::gen::RightClickMode::ERASE:
tool = m_toolbox->getToolById(WellKnownTools::Eraser);
ink = m_toolbox->getInkById(tools::WellKnownInks::Eraser);
break;
case app::gen::RightClickMode::SCROLL:
tool = m_toolbox->getToolById(WellKnownTools::Hand);
ink = m_toolbox->getInkById(tools::WellKnownInks::Scroll);
break;
case app::gen::RightClickMode::RECTANGULAR_MARQUEE:
tool = m_toolbox->getToolById(WellKnownTools::RectangularMarquee);
ink = m_toolbox->getInkById(tools::WellKnownInks::Selection);
break;
case app::gen::RightClickMode::LASSO:
tool = m_toolbox->getToolById(WellKnownTools::Lasso);
ink = m_toolbox->getInkById(tools::WellKnownInks::Selection);
break;
case app::gen::RightClickMode::SELECT_LAYER_AND_MOVE:
tool = m_toolbox->getToolById(WellKnownTools::Move);
ink = m_toolbox->getInkById(tools::WellKnownInks::SelectLayerAndMove);
break;
}
}
}
else {
m_rightClick = false;
}
m_rightClickTool = tool;
m_rightClickInk = ink;
}
void ActiveToolManager::releaseButtons()
{
ActiveToolChangeTrigger trigger(this);
m_rightClick = false;
m_rightClickTool = nullptr;
m_rightClickInk = nullptr;
}
void ActiveToolManager::setSelectedTool(Tool* tool)
{
ActiveToolChangeTrigger trigger(this);
m_selectedTool = tool;
notify_observers(&ActiveToolObserver::onSelectedToolChange, tool);
}
// static
bool ActiveToolManager::isToolAffectedByRightClickMode(Tool* tool)
{
bool shadingMode = (Preferences::instance().tool(tool).ink() == InkType::SHADING);
if (shadingMode) {
if (auto* contextBar = App::instance()->contextBar()) {
// Shading ink is only enabled if we have a shade of two or more
// colors selected, in other case we disable it so a right-click
// can be used for its configured action.
shadingMode = (contextBar->getShade().size() >= 2);
}
}
return
((tool->getInk(0)->isPaint() && !shadingMode) ||
(tool->getInk(0)->isEffect())) &&
(!tool->getInk(0)->isEraser()) &&
(!tool->getInk(0)->isSelection());
}
} // namespace tools
} // namespace app