mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-31 07:20:30 +00:00
Add selection modes to "Select > Color Range" command (fix #765)
This commit is contained in:
parent
3a77321597
commit
2a5fa78f56
@ -384,6 +384,7 @@ if(ENABLE_UI)
|
||||
ui/resources_listbox.cpp
|
||||
ui/search_entry.cpp
|
||||
ui/select_accelerator.cpp
|
||||
ui/selection_mode_field.cpp
|
||||
ui/skin/font_data.cpp
|
||||
ui/skin/skin_part.cpp
|
||||
ui/skin/skin_property.cpp
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -22,6 +23,7 @@
|
||||
#include "app/tx.h"
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/selection_mode_field.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/chrono.h"
|
||||
#include "base/convert_to.h"
|
||||
@ -32,6 +34,7 @@
|
||||
#include "ui/button.h"
|
||||
#include "ui/label.h"
|
||||
#include "ui/slider.h"
|
||||
#include "ui/tooltips.h"
|
||||
#include "ui/widget.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
@ -52,13 +55,27 @@ protected:
|
||||
void onExecute(Context* context) override;
|
||||
|
||||
private:
|
||||
Mask* generateMask(const Sprite* sprite, const Image* image, int xpos, int ypos);
|
||||
Mask* generateMask(const Mask& origMask,
|
||||
const Sprite* sprite,
|
||||
const Image* image,
|
||||
int xpos, int ypos,
|
||||
gen::SelectionMode mode);
|
||||
void maskPreview(const ContextReader& reader);
|
||||
|
||||
class SelModeField : public SelectionModeField {
|
||||
public:
|
||||
obs::signal<void()> ModeChange;
|
||||
protected:
|
||||
void onSelectionModeChange(gen::SelectionMode mode) override {
|
||||
ModeChange();
|
||||
}
|
||||
};
|
||||
|
||||
Window* m_window; // TODO we cannot use a std::unique_ptr because clone() needs a copy ctor
|
||||
ColorButton* m_buttonColor;
|
||||
CheckBox* m_checkPreview;
|
||||
Slider* m_sliderTolerance;
|
||||
SelModeField* m_selMode;
|
||||
};
|
||||
|
||||
MaskByColorCommand::MaskByColorCommand()
|
||||
@ -77,11 +94,6 @@ void MaskByColorCommand::onExecute(Context* context)
|
||||
{
|
||||
const ContextReader reader(context);
|
||||
const Sprite* sprite = reader.sprite();
|
||||
Box* box1, *box2, *box3, *box4;
|
||||
Widget* label_color;
|
||||
Widget* label_tolerance;
|
||||
Button* button_ok;
|
||||
Button* button_cancel;
|
||||
|
||||
if (!App::instance()->isGui() || !sprite)
|
||||
return;
|
||||
@ -92,21 +104,27 @@ void MaskByColorCommand::onExecute(Context* context)
|
||||
return;
|
||||
|
||||
m_window = new Window(Window::WithTitleBar, "Mask by Color");
|
||||
box1 = new Box(VERTICAL);
|
||||
box2 = new Box(HORIZONTAL);
|
||||
box3 = new Box(HORIZONTAL);
|
||||
box4 = new Box(HORIZONTAL | HOMOGENEOUS);
|
||||
label_color = new Label("Color:");
|
||||
TooltipManager* tooltipManager = new TooltipManager();
|
||||
m_window->addChild(tooltipManager);
|
||||
auto box1 = new Box(VERTICAL);
|
||||
auto box2 = new Box(HORIZONTAL);
|
||||
auto box3 = new Box(HORIZONTAL);
|
||||
auto box4 = new Box(HORIZONTAL | HOMOGENEOUS);
|
||||
auto label_color = new Label("Color:");
|
||||
m_buttonColor = new ColorButton
|
||||
(get_config_color("MaskColor", "Color",
|
||||
ColorBar::instance()->getFgColor()),
|
||||
sprite->pixelFormat(),
|
||||
ColorButtonOptions());
|
||||
label_tolerance = new Label("Tolerance:");
|
||||
auto label_tolerance = new Label("Tolerance:");
|
||||
m_sliderTolerance = new Slider(0, 255, get_config_int("MaskColor", "Tolerance", 0));
|
||||
|
||||
m_selMode = new SelModeField;
|
||||
m_selMode->setupTooltips(tooltipManager);
|
||||
|
||||
m_checkPreview = new CheckBox("&Preview");
|
||||
button_ok = new Button("&OK");
|
||||
button_cancel = new Button("&Cancel");
|
||||
auto button_ok = new Button("&OK");
|
||||
auto button_cancel = new Button("&Cancel");
|
||||
|
||||
m_checkPreview->processMnemonicFromText();
|
||||
button_ok->processMnemonicFromText();
|
||||
@ -122,6 +140,7 @@ void MaskByColorCommand::onExecute(Context* context)
|
||||
m_buttonColor->Change.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
|
||||
m_sliderTolerance->Change.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
|
||||
m_checkPreview->Click.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
|
||||
m_selMode->ModeChange.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
|
||||
|
||||
button_ok->setFocusMagnet(true);
|
||||
m_buttonColor->setExpansive(true);
|
||||
@ -129,6 +148,7 @@ void MaskByColorCommand::onExecute(Context* context)
|
||||
box2->setExpansive(true);
|
||||
|
||||
m_window->addChild(box1);
|
||||
box1->addChild(m_selMode);
|
||||
box1->addChild(box2);
|
||||
box1->addChild(box3);
|
||||
box1->addChild(m_checkPreview);
|
||||
@ -160,7 +180,9 @@ void MaskByColorCommand::onExecute(Context* context)
|
||||
|
||||
if (apply) {
|
||||
Tx tx(writer.context(), "Mask by Color", DoesntModifyDocument);
|
||||
std::unique_ptr<Mask> mask(generateMask(sprite, image, xpos, ypos));
|
||||
std::unique_ptr<Mask> mask(generateMask(*document->mask(),
|
||||
sprite, image, xpos, ypos,
|
||||
m_selMode->selectionMode()));
|
||||
tx(new cmd::SetMask(document, mask.get()));
|
||||
tx.commit();
|
||||
|
||||
@ -178,17 +200,44 @@ void MaskByColorCommand::onExecute(Context* context)
|
||||
delete m_window;
|
||||
}
|
||||
|
||||
Mask* MaskByColorCommand::generateMask(const Sprite* sprite, const Image* image, int xpos, int ypos)
|
||||
Mask* MaskByColorCommand::generateMask(const Mask& origMask,
|
||||
const Sprite* sprite,
|
||||
const Image* image,
|
||||
int xpos, int ypos,
|
||||
gen::SelectionMode mode)
|
||||
{
|
||||
int color, tolerance;
|
||||
|
||||
color = color_utils::color_for_image(m_buttonColor->getColor(), sprite->pixelFormat());
|
||||
tolerance = m_sliderTolerance->getValue();
|
||||
int color = color_utils::color_for_image(m_buttonColor->getColor(), sprite->pixelFormat());
|
||||
int tolerance = m_sliderTolerance->getValue();
|
||||
|
||||
std::unique_ptr<Mask> mask(new Mask());
|
||||
mask->byColor(image, color, tolerance);
|
||||
mask->offsetOrigin(xpos, ypos);
|
||||
|
||||
if (!origMask.isEmpty()) {
|
||||
switch (mode) {
|
||||
case gen::SelectionMode::DEFAULT:
|
||||
break;
|
||||
case gen::SelectionMode::ADD:
|
||||
mask->add(origMask);
|
||||
break;
|
||||
case gen::SelectionMode::SUBTRACT: {
|
||||
if (!mask->isEmpty()) {
|
||||
Mask mask2(origMask);
|
||||
mask2.subtract(*mask);
|
||||
mask->replace(mask2);
|
||||
}
|
||||
else {
|
||||
mask->replace(origMask);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gen::SelectionMode::INTERSECT: {
|
||||
mask->intersect(origMask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mask.release();
|
||||
}
|
||||
|
||||
@ -197,7 +246,10 @@ void MaskByColorCommand::maskPreview(const ContextReader& reader)
|
||||
if (m_checkPreview->isSelected()) {
|
||||
int xpos, ypos;
|
||||
const Image* image = reader.image(&xpos, &ypos);
|
||||
std::unique_ptr<Mask> mask(generateMask(reader.sprite(), image, xpos, ypos));
|
||||
std::unique_ptr<Mask> mask(generateMask(*reader.document()->mask(),
|
||||
reader.sprite(), image,
|
||||
xpos, ypos,
|
||||
m_selMode->selectionMode()));
|
||||
{
|
||||
ContextWriter writer(reader);
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "app/ui/dithering_selector.h"
|
||||
#include "app/ui/icon_button.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/selection_mode_field.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
@ -46,9 +47,9 @@
|
||||
#include "doc/palette.h"
|
||||
#include "doc/remap.h"
|
||||
#include "obs/connection.h"
|
||||
#include "render/dithering.h"
|
||||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
#include "render/dithering.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/combobox.h"
|
||||
#include "ui/int_entry.h"
|
||||
@ -925,44 +926,12 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class ContextBar::SelectionModeField : public ButtonSet {
|
||||
class ContextBar::SelectionModeField : public app::SelectionModeField {
|
||||
public:
|
||||
SelectionModeField() : ButtonSet(4) {
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
|
||||
addItem(theme->parts.selectionReplace());
|
||||
addItem(theme->parts.selectionAdd());
|
||||
addItem(theme->parts.selectionSubtract());
|
||||
addItem(theme->parts.selectionIntersect());
|
||||
|
||||
setSelectedItem((int)Preferences::instance().selection.mode());
|
||||
}
|
||||
|
||||
void setupTooltips(TooltipManager* tooltipManager) {
|
||||
tooltipManager->addTooltipFor(
|
||||
at(0), "Replace selection", BOTTOM);
|
||||
|
||||
tooltipManager->addTooltipFor(
|
||||
at(1), key_tooltip("Add to selection", KeyAction::AddSelection), BOTTOM);
|
||||
|
||||
tooltipManager->addTooltipFor(
|
||||
at(2), key_tooltip("Subtract from selection", KeyAction::SubtractSelection), BOTTOM);
|
||||
|
||||
tooltipManager->addTooltipFor(
|
||||
at(3), key_tooltip("Intersect selection", KeyAction::IntersectSelection), BOTTOM);
|
||||
}
|
||||
|
||||
void setSelectionMode(gen::SelectionMode mode) {
|
||||
setSelectedItem((int)mode, false);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
SelectionModeField() { }
|
||||
protected:
|
||||
void onItemChange(Item* item) override {
|
||||
ButtonSet::onItemChange(item);
|
||||
|
||||
Preferences::instance().selection.mode(
|
||||
(gen::SelectionMode)selectedItem());
|
||||
void onSelectionModeChange(gen::SelectionMode mode) override {
|
||||
Preferences::instance().selection.mode(mode);
|
||||
}
|
||||
};
|
||||
|
||||
|
66
src/app/ui/selection_mode_field.cpp
Normal file
66
src/app/ui/selection_mode_field.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
//
|
||||
// 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/ui/selection_mode_field.h"
|
||||
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace app::skin;
|
||||
using namespace ui;
|
||||
|
||||
SelectionModeField::SelectionModeField()
|
||||
: ButtonSet(4)
|
||||
{
|
||||
auto theme = static_cast<SkinTheme*>(this->theme());
|
||||
|
||||
addItem(theme->parts.selectionReplace());
|
||||
addItem(theme->parts.selectionAdd());
|
||||
addItem(theme->parts.selectionSubtract());
|
||||
addItem(theme->parts.selectionIntersect());
|
||||
|
||||
setSelectedItem((int)Preferences::instance().selection.mode());
|
||||
}
|
||||
|
||||
void SelectionModeField::setupTooltips(TooltipManager* tooltipManager)
|
||||
{
|
||||
tooltipManager->addTooltipFor(
|
||||
at(0), "Replace selection", BOTTOM);
|
||||
|
||||
tooltipManager->addTooltipFor(
|
||||
at(1), key_tooltip("Add to selection", KeyAction::AddSelection), BOTTOM);
|
||||
|
||||
tooltipManager->addTooltipFor(
|
||||
at(2), key_tooltip("Subtract from selection", KeyAction::SubtractSelection), BOTTOM);
|
||||
|
||||
tooltipManager->addTooltipFor(
|
||||
at(3), key_tooltip("Intersect selection", KeyAction::IntersectSelection), BOTTOM);
|
||||
}
|
||||
|
||||
gen::SelectionMode SelectionModeField::selectionMode()
|
||||
{
|
||||
return (gen::SelectionMode)selectedItem();
|
||||
}
|
||||
|
||||
void SelectionModeField::setSelectionMode(gen::SelectionMode mode)
|
||||
{
|
||||
setSelectedItem((int)mode, false);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SelectionModeField::onItemChange(Item* item)
|
||||
{
|
||||
ButtonSet::onItemChange(item);
|
||||
onSelectionModeChange(selectionMode());
|
||||
}
|
||||
|
||||
} // namespace app
|
39
src/app/ui/selection_mode_field.h
Normal file
39
src/app/ui/selection_mode_field.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_SELECTION_MODE_FIELD_H_INCLUDED
|
||||
#define APP_UI_SELECTION_MODE_FIELD_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/ui/button_set.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ui {
|
||||
class TooltipManager;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
class SelectionModeField : public ButtonSet {
|
||||
public:
|
||||
SelectionModeField();
|
||||
|
||||
void setupTooltips(ui::TooltipManager* tooltipManager);
|
||||
|
||||
gen::SelectionMode selectionMode();
|
||||
void setSelectionMode(gen::SelectionMode mode);
|
||||
|
||||
protected:
|
||||
void onItemChange(Item* item) override;
|
||||
|
||||
virtual void onSelectionModeChange(gen::SelectionMode mode) { }
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user