Added "Grab Alpha" option to eye dropper (issue 134)

This commit is contained in:
David Capello 2014-01-28 23:56:44 -03:00
parent beda78e168
commit c8c099864c
12 changed files with 260 additions and 40 deletions

View File

@ -8,6 +8,7 @@ add_library(app-library
backup.cpp
check_update.cpp
color.cpp
color_picker.cpp
color_swatches.cpp
color_utils.cpp
commands/cmd_about.cpp

68
src/app/color_picker.cpp Normal file
View File

@ -0,0 +1,68 @@
/* Aseprite
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/color_picker.h"
#include "app/document_location.h"
#include "raster/image.h"
#include "raster/primitives.h"
#include "raster/sprite.h"
namespace app {
ColorPicker::ColorPicker()
: m_alpha(0)
{
}
void ColorPicker::pickColor(DocumentLocation& location, int x, int y, Mode mode)
{
m_alpha = 255;
m_color = app::Color::fromMask();
// Get the color from the image
if (mode == FromComposition) { // Pick from the composed image
m_color = app::Color::fromImage(
location.sprite()->getPixelFormat(),
location.sprite()->getPixel(x, y, location.frame()));
}
else { // Pick from the current layer
int u, v;
raster::Image* image = location.image(&u, &v, NULL);
if (image) {
raster::color_t imageColor = get_pixel(image, x-u, y-v);
switch (image->getPixelFormat()) {
case IMAGE_RGB:
m_alpha = raster::rgba_geta(imageColor);
break;
case IMAGE_GRAYSCALE:
m_alpha = raster::graya_geta(imageColor);
break;
}
m_color = app::Color::fromImage(image->getPixelFormat(), imageColor);
}
}
}
} // namespace app

45
src/app/color_picker.h Normal file
View File

@ -0,0 +1,45 @@
/* Aseprite
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_COLOR_PICKER_H_INCLUDED
#define APP_COLOR_PICKER_H_INCLUDED
#include "app/color.h"
namespace app {
class DocumentLocation;
class ColorPicker {
public:
enum Mode { FromComposition, FromActiveLayer };
ColorPicker();
void pickColor(DocumentLocation& location, int x, int y, Mode mode);
app::Color color() const { return m_color; }
int alpha() const { return m_alpha; }
private:
app::Color m_color;
int m_alpha;
};
} // namespace app
#endif

View File

@ -20,18 +20,23 @@
#include "config.h"
#endif
#include <allegro/unicode.h>
#include "ui/ui.h"
#include "app/app.h"
#include "app/color.h"
#include "app/color_picker.h"
#include "app/commands/command.h"
#include "app/commands/params.h"
#include "app/document_location.h"
#include "app/modules/editors.h"
#include "app/settings/settings.h"
#include "app/tools/tool.h"
#include "app/tools/tool_box.h"
#include "app/ui/color_bar.h"
#include "app/ui/editor/editor.h"
#include "app/ui_context.h"
#include "raster/image.h"
#include "raster/sprite.h"
#include "ui/manager.h"
#include "ui/system.h"
namespace app {
@ -84,17 +89,27 @@ void EyedropperCommand::onExecute(Context* context)
int x, y;
editor->screenToEditor(jmouse_x(0), jmouse_y(0), &x, &y);
// get the color from the image
app::Color color = app::Color::fromImage(sprite->getPixelFormat(),
sprite->getPixel(x, y, frame));
// Check if we've to grab alpha channel or the merged color.
ISettings* settings = UIContext::instance()->settings();
bool grabAlpha = settings->getGrabAlpha();
// TODO replace the color in the "context", not directly from the color-bar
ColorPicker picker;
picker.pickColor(editor->getDocumentLocation(), x, y,
grabAlpha ?
ColorPicker::FromActiveLayer:
ColorPicker::FromComposition);
if (grabAlpha) {
tools::ToolBox* toolBox = App::instance()->getToolBox();
for (tools::ToolIterator it=toolBox->begin(), end=toolBox->end(); it!=end; ++it) {
settings->getToolSettings(*it)->setOpacity(picker.alpha());
}
}
// set the color of the color-bar
if (m_background)
ColorBar::instance()->setBgColor(color);
settings->setBgColor(picker.color());
else
ColorBar::instance()->setFgColor(color);
settings->setFgColor(picker.color());
}
Command* CommandFactory::createEyedropperCommand()

View File

@ -52,12 +52,14 @@ namespace app {
// General settings
virtual bool getShowSpriteEditorScrollbars() = 0;
virtual bool getGrabAlpha() = 0;
virtual app::Color getFgColor() = 0;
virtual app::Color getBgColor() = 0;
virtual tools::Tool* getCurrentTool() = 0;
virtual app::ColorSwatches* getColorSwatches() = 0;
virtual void setShowSpriteEditorScrollbars(bool state) = 0;
virtual void setGrabAlpha(bool state) = 0;
virtual void setFgColor(const app::Color& color) = 0;
virtual void setBgColor(const app::Color& color) = 0;
virtual void setCurrentTool(tools::Tool* tool) = 0;

View File

@ -70,6 +70,7 @@ namespace app {
virtual ~GlobalSettingsObserver() {}
virtual void onSetShowSpriteEditorScrollbars(bool state) {}
virtual void onSetGrabAlpha(bool state) {}
virtual void onSetFgColor(app::Color newColor) {}
virtual void onSetBgColor(app::Color newColor) {}
virtual void onSetCurrentTool(tools::Tool* newTool) {}

View File

@ -27,6 +27,7 @@
#include "app/ini_file.h"
#include "app/settings/document_settings.h"
#include "app/tools/controller.h"
#include "app/tools/ink.h"
#include "app/tools/point_shape.h"
#include "app/tools/tool.h"
#include "app/tools/tool_box.h"
@ -178,6 +179,7 @@ UISettingsImpl::UISettingsImpl()
, m_colorSwatches(NULL)
, m_selectionSettings(new UISelectionSettingsImpl)
, m_showSpriteEditorScrollbars(get_config_bool("Options", "ShowScrollbars", true))
, m_grabAlpha(get_config_bool("Options", "GrabAlpha", false))
{
m_colorSwatches = new app::ColorSwatches("Default");
for (size_t i=0; i<16; ++i)
@ -188,6 +190,9 @@ UISettingsImpl::UISettingsImpl()
UISettingsImpl::~UISettingsImpl()
{
set_config_bool("Options", "ShowScrollbars", m_showSpriteEditorScrollbars);
set_config_bool("Options", "GrabAlpha", m_grabAlpha);
delete m_globalDocumentSettings;
// Delete all tool settings.
@ -212,6 +217,11 @@ bool UISettingsImpl::getShowSpriteEditorScrollbars()
return m_showSpriteEditorScrollbars;
}
bool UISettingsImpl::getGrabAlpha()
{
return m_grabAlpha;
}
app::Color UISettingsImpl::getFgColor()
{
return ColorBar::instance()->getFgColor();
@ -242,6 +252,13 @@ void UISettingsImpl::setShowSpriteEditorScrollbars(bool state)
notifyObservers<bool>(&GlobalSettingsObserver::onSetShowSpriteEditorScrollbars, state);
}
void UISettingsImpl::setGrabAlpha(bool state)
{
m_grabAlpha = state;
notifyObservers<bool>(&GlobalSettingsObserver::onSetGrabAlpha, state);
}
void UISettingsImpl::setFgColor(const app::Color& color)
{
ColorBar::instance()->setFgColor(color);
@ -604,6 +621,7 @@ public:
set_config_int(cfg_section.c_str(), "PenAngle", m_pen.getAngle());
set_config_int(cfg_section.c_str(), "PenAngle", m_pen.getAngle());
set_config_int(cfg_section.c_str(), "InkType", m_inkType);
set_config_bool(cfg_section.c_str(), "PreviewFilled", m_previewFilled);
if (m_tool->getPointShape(0)->isSpray() ||
m_tool->getPointShape(1)->isSpray()) {
@ -615,8 +633,6 @@ public:
m_tool->getController(1)->isFreehand()) {
set_config_int(cfg_section.c_str(), "FreehandAlgorithm", m_freehandAlgorithm);
}
set_config_bool(cfg_section.c_str(), "PreviewFilled", m_previewFilled);
}
IPenSettings* getPen() { return &m_pen; }

View File

@ -40,12 +40,14 @@ namespace app {
// ISettings implementation
bool getShowSpriteEditorScrollbars() OVERRIDE;
bool getGrabAlpha() OVERRIDE;
app::Color getFgColor() OVERRIDE;
app::Color getBgColor() OVERRIDE;
tools::Tool* getCurrentTool() OVERRIDE;
app::ColorSwatches* getColorSwatches() OVERRIDE;
void setShowSpriteEditorScrollbars(bool state) OVERRIDE;
void setGrabAlpha(bool state) OVERRIDE;
void setFgColor(const app::Color& color) OVERRIDE;
void setBgColor(const app::Color& color) OVERRIDE;
void setCurrentTool(tools::Tool* tool) OVERRIDE;
@ -73,6 +75,7 @@ namespace app {
std::vector<app::ColorSwatches*> m_colorSwatchesStore;
ISelectionSettings* m_selectionSettings;
bool m_showSpriteEditorScrollbars;
bool m_grabAlpha;
};
} // namespace app

View File

@ -435,8 +435,24 @@ protected:
}
};
class ContextBar::GrabAlphaField : public CheckBox
{
public:
GrabAlphaField() : CheckBox("Grab Alpha") {
setup_mini_font(this);
}
protected:
void onClick(Event& ev) OVERRIDE {
CheckBox::onClick(ev);
UIContext::instance()->settings()->setGrabAlpha(isSelected());
}
};
ContextBar::ContextBar()
: Box(JI_HORIZONTAL)
, m_toolSettings(NULL)
{
border_width.b = 2*jguiscale();
@ -459,6 +475,9 @@ ContextBar::ContextBar()
addChild(m_opacityLabel = new Label("Opacity:"));
addChild(m_inkOpacity = new InkOpacityField());
addChild(m_grabAlpha = new GrabAlphaField());
// addChild(new InkChannelTargetField());
// addChild(new InkShadeField());
// addChild(new InkSelectionField());
@ -486,6 +505,11 @@ ContextBar::ContextBar()
tooltipManager->addTooltipFor(m_transparentColor, "Transparent Color", JI_BOTTOM);
tooltipManager->addTooltipFor(m_rotAlgo, "Rotation Algorithm", JI_BOTTOM);
tooltipManager->addTooltipFor(m_freehandAlgo, "Freehand trace algorithm", JI_BOTTOM);
tooltipManager->addTooltipFor(m_grabAlpha,
"When checked the tool picks the color from the active layer, and its alpha\n"
"component is used to setup the opacity level of all drawing tools.\n\n"
"When unchecked -the default behavior- the color is picked\n"
"from the composition of all sprite layers.", JI_LEFT | JI_TOP);
m_selectionMode->setupTooltips(tooltipManager);
App::instance()->PenSizeAfterChange.connect(&ContextBar::onPenSizeChange, this);
@ -497,6 +521,8 @@ ContextBar::ContextBar()
ContextBar::~ContextBar()
{
if (m_toolSettings)
m_toolSettings->removeObserver(this);
}
bool ContextBar::onProcessMessage(Message* msg)
@ -504,6 +530,11 @@ bool ContextBar::onProcessMessage(Message* msg)
return Box::onProcessMessage(msg);
}
void ContextBar::onSetOpacity(int newOpacity)
{
m_inkOpacity->setTextf("%d", newOpacity);
}
void ContextBar::onPenSizeChange()
{
ISettings* settings = UIContext::instance()->getSettings();
@ -529,10 +560,20 @@ void ContextBar::onPenAngleChange()
void ContextBar::onCurrentToolChange()
{
ISettings* settings = UIContext::instance()->getSettings();
Tool* currentTool = settings->getCurrentTool();
IToolSettings* toolSettings = settings->getToolSettings(currentTool);
updateFromTool(settings->getCurrentTool());
}
void ContextBar::updateFromTool(tools::Tool* tool)
{
ISettings* settings = UIContext::instance()->getSettings();
IToolSettings* toolSettings = settings->getToolSettings(tool);
IPenSettings* penSettings = toolSettings->getPen();
if (m_toolSettings)
m_toolSettings->removeObserver(this);
m_toolSettings = toolSettings;
m_toolSettings->addObserver(this);
m_brushType->setPenSettings(penSettings);
m_brushSize->setTextf("%d", penSettings->getSize());
m_brushAngle->setTextf("%d", penSettings->getAngle());
@ -542,35 +583,41 @@ void ContextBar::onCurrentToolChange()
m_inkType->setInkType(toolSettings->getInkType());
m_inkOpacity->setTextf("%d", toolSettings->getOpacity());
m_grabAlpha->setSelected(settings->getGrabAlpha());
m_freehandAlgo->setSelected(toolSettings->getFreehandAlgorithm() == kPixelPerfectFreehandAlgorithm);
m_sprayWidth->setValue(toolSettings->getSprayWidth());
m_spraySpeed->setValue(toolSettings->getSpraySpeed());
// True if the current tool needs opacity options
bool hasOpacity = (currentTool->getInk(0)->isPaint() ||
currentTool->getInk(0)->isEffect() ||
currentTool->getInk(1)->isPaint() ||
currentTool->getInk(1)->isEffect());
bool hasOpacity = (tool->getInk(0)->isPaint() ||
tool->getInk(0)->isEffect() ||
tool->getInk(1)->isPaint() ||
tool->getInk(1)->isEffect());
// True if the current tool is eyedropper.
bool isEyedropper =
(tool->getInk(0)->isEyedropper() ||
tool->getInk(1)->isEyedropper());
// True if it makes sense to change the ink property for the current
// tool.
bool hasInk = hasOpacity;
// True if the current tool needs tolerance options
bool hasTolerance = (currentTool->getPointShape(0)->isFloodFill() ||
currentTool->getPointShape(1)->isFloodFill());
bool hasTolerance = (tool->getPointShape(0)->isFloodFill() ||
tool->getPointShape(1)->isFloodFill());
// True if the current tool needs spray options
bool hasSprayOptions = (currentTool->getPointShape(0)->isSpray() ||
currentTool->getPointShape(1)->isSpray());
bool hasSprayOptions = (tool->getPointShape(0)->isSpray() ||
tool->getPointShape(1)->isSpray());
bool hasSelectOptions = (currentTool->getInk(0)->isSelection() ||
currentTool->getInk(1)->isSelection());
bool hasSelectOptions = (tool->getInk(0)->isSelection() ||
tool->getInk(1)->isSelection());
bool isFreehand =
(currentTool->getController(0)->isFreehand() ||
currentTool->getController(1)->isFreehand());
(tool->getController(0)->isFreehand() ||
tool->getController(1)->isFreehand());
// Show/Hide fields
m_brushType->setVisible(hasOpacity);
@ -579,7 +626,8 @@ void ContextBar::onCurrentToolChange()
m_opacityLabel->setVisible(hasOpacity);
m_inkType->setVisible(hasInk);
m_inkOpacity->setVisible(hasOpacity);
m_freehandBox->setVisible(isFreehand);
m_grabAlpha->setVisible(isEyedropper);
m_freehandBox->setVisible(isFreehand && hasOpacity);
m_toleranceLabel->setVisible(hasTolerance);
m_tolerance->setVisible(hasTolerance);
m_sprayBox->setVisible(hasSprayOptions);

View File

@ -19,6 +19,7 @@
#ifndef APP_UI_CONTEXT_BAR_H_INCLUDED
#define APP_UI_CONTEXT_BAR_H_INCLUDED
#include "app/settings/settings_observers.h"
#include "base/compiler_specific.h"
#include "ui/box.h"
@ -27,16 +28,28 @@ namespace ui {
class Label;
}
namespace tools {
class Tool;
}
namespace app {
class ContextBar : public ui::Box {
class IToolSettings;
class ContextBar : public ui::Box,
public ToolSettingsObserver {
public:
ContextBar();
~ContextBar();
void updateFromTool(tools::Tool* tool);
protected:
bool onProcessMessage(ui::Message* msg) OVERRIDE;
// ToolSettingsObserver impl
void onSetOpacity(int newOpacity) OVERRIDE;
private:
void onPenSizeChange();
void onPenAngleChange();
@ -54,7 +67,9 @@ namespace app {
class TransparentColorField;
class RotAlgorithmField;
class FreehandAlgorithmField;
class GrabAlphaField;
IToolSettings* m_toolSettings;
BrushTypeField* m_brushType;
BrushAngleField* m_brushAngle;
BrushSizeField* m_brushSize;
@ -63,6 +78,7 @@ namespace app {
InkTypeField* m_inkType;
ui::Label* m_opacityLabel;
InkOpacityField* m_inkOpacity;
GrabAlphaField* m_grabAlpha;
ui::Box* m_freehandBox;
FreehandAlgorithmField* m_freehandAlgo;
ui::Box* m_sprayBox;

View File

@ -40,11 +40,13 @@
#include "app/tools/tool.h"
#include "app/tools/tool_box.h"
#include "app/ui/color_bar.h"
#include "app/ui/context_bar.h"
#include "app/ui/editor/editor_customization_delegate.h"
#include "app/ui/editor/editor_decorator.h"
#include "app/ui/editor/moving_pixels_state.h"
#include "app/ui/editor/pixels_movement.h"
#include "app/ui/editor/standby_state.h"
#include "app/ui/main_window.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/status_bar.h"
#include "app/ui/toolbar.h"
@ -860,8 +862,12 @@ void Editor::editor_update_quicktool()
// If the tool has changed, we must to update the status bar because
// the new tool can display something different in the status bar (e.g. Eyedropper)
if (old_quicktool != m_quicktool)
if (old_quicktool != m_quicktool) {
updateStatusBar();
App::instance()->getMainWindow()->getContextBar()
->updateFromTool(getCurrentEditorTool());
}
}
}

View File

@ -23,10 +23,12 @@
#include "app/ui/editor/standby_state.h"
#include "app/app.h"
#include "app/color_picker.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/document_location.h"
#include "app/ini_file.h"
#include "app/settings/settings.h"
#include "app/tools/ink.h"
#include "app/tools/tool.h"
#include "app/ui/color_bar.h"
@ -452,20 +454,17 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
}
// For eye-dropper
else if (current_tool->getInk(0)->isEyedropper()) {
PixelFormat format = sprite->getPixelFormat();
uint32_t pixel = sprite->getPixel(x, y, editor->getFrame());
app::Color color = app::Color::fromImage(format, pixel);
int alpha = 255;
switch (format) {
case IMAGE_RGB: alpha = rgba_geta(pixel); break;
case IMAGE_GRAYSCALE: alpha = graya_geta(pixel); break;
}
bool grabAlpha = UIContext::instance()->settings()->getGrabAlpha();
ColorPicker picker;
picker.pickColor(editor->getDocumentLocation(), x, y,
grabAlpha ?
ColorPicker::FromActiveLayer:
ColorPicker::FromComposition);
char buf[256];
usprintf(buf, "- Pos %d %d", x, y);
StatusBar::instance()->showColor(0, buf, color, alpha);
StatusBar::instance()->showColor(0, buf, picker.color(), picker.alpha());
}
else {
Mask* mask =