mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-06 12:39:57 +00:00
Move code into a MaskByColorWindow class
Refactor code to separate responsibilities, now the UI related code is in its own class and the command class looks cleaner
This commit is contained in:
parent
5464c4a3c2
commit
4dc7ba6dc0
@ -48,22 +48,87 @@ using namespace ui;
|
||||
|
||||
static const char* ConfigSection = "MaskColor";
|
||||
|
||||
class MaskByColorCommand : public Command {
|
||||
class MaskByColorWindow : public ui::Window {
|
||||
public:
|
||||
MaskByColorCommand();
|
||||
MaskByColorWindow(const ContextReader& reader)
|
||||
: Window(Window::WithTitleBar, Strings::mask_by_color_title())
|
||||
, m_reader(&reader)
|
||||
// Save original mask visibility to process it correctly in
|
||||
// ADD/SUBTRACT/INTERSECT Selection Mode
|
||||
, m_isOrigMaskVisible(reader.document()->isMaskVisible()) {
|
||||
TooltipManager* tooltipManager = new TooltipManager();
|
||||
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(Strings::mask_by_color_label_color());
|
||||
m_buttonColor = new ColorButton(
|
||||
ColorBar::instance()->getFgColor(),
|
||||
reader.sprite()->pixelFormat(),
|
||||
ColorButtonOptions());
|
||||
auto label_tolerance = new Label(Strings::mask_by_color_tolerance());
|
||||
m_sliderTolerance = new Slider(0, 255, get_config_int(ConfigSection, "Tolerance", 0));
|
||||
|
||||
protected:
|
||||
bool onEnabled(Context* context) override;
|
||||
void onExecute(Context* context) override;
|
||||
m_selMode = new SelModeField;
|
||||
m_selMode->setupTooltips(tooltipManager);
|
||||
|
||||
m_checkPreview = new CheckBox(Strings::mask_by_color_preview());
|
||||
m_buttonOk = new Button(Strings::mask_by_color_ok());
|
||||
auto button_cancel = new Button(Strings::mask_by_color_cancel());
|
||||
|
||||
m_checkPreview->processMnemonicFromText();
|
||||
m_buttonOk->processMnemonicFromText();
|
||||
button_cancel->processMnemonicFromText();
|
||||
|
||||
if (get_config_bool(ConfigSection, "Preview", true))
|
||||
m_checkPreview->setSelected(true);
|
||||
|
||||
m_buttonOk->Click.connect([this]{ closeWindow(m_buttonOk); });
|
||||
button_cancel->Click.connect([this, button_cancel]{ closeWindow(button_cancel); });
|
||||
|
||||
m_buttonColor->Change.connect([&]{ maskPreview(); });
|
||||
m_sliderTolerance->Change.connect([&]{ maskPreview(); });
|
||||
m_checkPreview->Click.connect([&]{ maskPreview(); });
|
||||
m_selMode->ModeChange.connect([&]{ maskPreview(); });
|
||||
|
||||
m_buttonOk->setFocusMagnet(true);
|
||||
m_buttonColor->setExpansive(true);
|
||||
m_sliderTolerance->setExpansive(true);
|
||||
box2->setExpansive(true);
|
||||
|
||||
addChild(box1);
|
||||
box1->addChild(m_selMode);
|
||||
box1->addChild(box2);
|
||||
box1->addChild(box3);
|
||||
box1->addChild(m_checkPreview);
|
||||
box1->addChild(box4);
|
||||
box2->addChild(label_color);
|
||||
box2->addChild(m_buttonColor);
|
||||
box3->addChild(label_tolerance);
|
||||
box3->addChild(m_sliderTolerance);
|
||||
box4->addChild(m_buttonOk);
|
||||
box4->addChild(button_cancel);
|
||||
|
||||
// Default position
|
||||
remapWindow();
|
||||
centerWindow();
|
||||
|
||||
// Mask first preview
|
||||
maskPreview();
|
||||
}
|
||||
|
||||
bool accepted() const { return closer() == m_buttonOk; }
|
||||
|
||||
app::Color getColor() const { return m_buttonColor->getColor(); }
|
||||
|
||||
int getTolerance() const { return m_sliderTolerance->getValue(); }
|
||||
|
||||
gen::SelectionMode getSelectionMode() const { return m_selMode->selectionMode(); }
|
||||
|
||||
bool isPreviewChecked() const { return m_checkPreview->isSelected(); }
|
||||
|
||||
private:
|
||||
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;
|
||||
@ -73,157 +138,31 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
Window* m_window = nullptr;
|
||||
void maskPreview();
|
||||
|
||||
const ContextReader* m_reader = nullptr;
|
||||
bool m_isOrigMaskVisible;
|
||||
Button* m_buttonOk = nullptr;
|
||||
ColorButton* m_buttonColor = nullptr;
|
||||
CheckBox* m_checkPreview = nullptr;
|
||||
Slider* m_sliderTolerance = nullptr;
|
||||
SelModeField* m_selMode = nullptr;
|
||||
bool m_isOrigMaskVisible;
|
||||
|
||||
};
|
||||
|
||||
MaskByColorCommand::MaskByColorCommand()
|
||||
: Command(CommandId::MaskByColor(), CmdUIOnlyFlag)
|
||||
static Mask* generateMask(const Mask& origMask,
|
||||
bool isOrigMaskVisible,
|
||||
const Image* image,
|
||||
int xpos, int ypos,
|
||||
gen::SelectionMode mode,
|
||||
int color,
|
||||
int tolerance)
|
||||
{
|
||||
}
|
||||
|
||||
bool MaskByColorCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||
ContextFlags::HasActiveSprite |
|
||||
ContextFlags::HasActiveImage);
|
||||
}
|
||||
|
||||
void MaskByColorCommand::onExecute(Context* context)
|
||||
{
|
||||
ASSERT(!m_window);
|
||||
|
||||
const ContextReader reader(context);
|
||||
const Sprite* sprite = reader.sprite();
|
||||
|
||||
if (!App::instance()->isGui() || !sprite)
|
||||
return;
|
||||
|
||||
int xpos, ypos;
|
||||
const Image* image = reader.image(&xpos, &ypos);
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
std::unique_ptr<Window> win(
|
||||
new Window(Window::WithTitleBar, Strings::mask_by_color_title()));
|
||||
base::ScopedValue<Window*> setWindow(m_window, win.get(), nullptr);
|
||||
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(Strings::mask_by_color_label_color());
|
||||
m_buttonColor = new ColorButton(
|
||||
ColorBar::instance()->getFgColor(),
|
||||
sprite->pixelFormat(),
|
||||
ColorButtonOptions());
|
||||
auto label_tolerance = new Label(Strings::mask_by_color_tolerance());
|
||||
m_sliderTolerance = new Slider(0, 255, get_config_int(ConfigSection, "Tolerance", 0));
|
||||
|
||||
m_selMode = new SelModeField;
|
||||
m_selMode->setupTooltips(tooltipManager);
|
||||
|
||||
m_checkPreview = new CheckBox(Strings::mask_by_color_preview());
|
||||
auto button_ok = new Button(Strings::mask_by_color_ok());
|
||||
auto button_cancel = new Button(Strings::mask_by_color_cancel());
|
||||
|
||||
m_checkPreview->processMnemonicFromText();
|
||||
button_ok->processMnemonicFromText();
|
||||
button_cancel->processMnemonicFromText();
|
||||
|
||||
if (get_config_bool(ConfigSection, "Preview", true))
|
||||
m_checkPreview->setSelected(true);
|
||||
|
||||
button_ok->Click.connect([this, button_ok]{ m_window->closeWindow(button_ok); });
|
||||
button_cancel->Click.connect([this, button_cancel]{ m_window->closeWindow(button_cancel); });
|
||||
|
||||
m_buttonColor->Change.connect([&]{ maskPreview(reader); });
|
||||
m_sliderTolerance->Change.connect([&]{ maskPreview(reader); });
|
||||
m_checkPreview->Click.connect([&]{ maskPreview(reader); });
|
||||
m_selMode->ModeChange.connect([&]{ maskPreview(reader); });
|
||||
|
||||
button_ok->setFocusMagnet(true);
|
||||
m_buttonColor->setExpansive(true);
|
||||
m_sliderTolerance->setExpansive(true);
|
||||
box2->setExpansive(true);
|
||||
|
||||
m_window->addChild(box1);
|
||||
box1->addChild(m_selMode);
|
||||
box1->addChild(box2);
|
||||
box1->addChild(box3);
|
||||
box1->addChild(m_checkPreview);
|
||||
box1->addChild(box4);
|
||||
box2->addChild(label_color);
|
||||
box2->addChild(m_buttonColor);
|
||||
box3->addChild(label_tolerance);
|
||||
box3->addChild(m_sliderTolerance);
|
||||
box4->addChild(button_ok);
|
||||
box4->addChild(button_cancel);
|
||||
|
||||
// Default position
|
||||
m_window->remapWindow();
|
||||
m_window->centerWindow();
|
||||
|
||||
// Save original mask visibility to process it correctly in
|
||||
// ADD/SUBTRACT/INTERSECT Selection Mode
|
||||
m_isOrigMaskVisible = reader.document()->isMaskVisible();
|
||||
|
||||
// Mask first preview
|
||||
maskPreview(reader);
|
||||
|
||||
// Load window configuration
|
||||
load_window_pos(m_window, ConfigSection);
|
||||
|
||||
// Open the window
|
||||
m_window->openWindowInForeground();
|
||||
|
||||
bool apply = (m_window->closer() == button_ok);
|
||||
|
||||
ContextWriter writer(reader);
|
||||
Doc* document(writer.document());
|
||||
|
||||
if (apply) {
|
||||
Tx tx(writer, "Mask by Color", DoesntModifyDocument);
|
||||
std::unique_ptr<Mask> mask(generateMask(*document->mask(),
|
||||
sprite, image, xpos, ypos,
|
||||
m_selMode->selectionMode()));
|
||||
tx(new cmd::SetMask(document, mask.get()));
|
||||
tx.commit();
|
||||
|
||||
set_config_int(ConfigSection, "Tolerance", m_sliderTolerance->getValue());
|
||||
set_config_bool(ConfigSection, "Preview", m_checkPreview->isSelected());
|
||||
}
|
||||
else {
|
||||
document->generateMaskBoundaries();
|
||||
}
|
||||
|
||||
// Update boundaries and editors.
|
||||
update_screen_for_document(document);
|
||||
|
||||
// Save window configuration.
|
||||
save_window_pos(m_window, ConfigSection);
|
||||
}
|
||||
|
||||
Mask* MaskByColorCommand::generateMask(const Mask& origMask,
|
||||
const Sprite* sprite,
|
||||
const Image* image,
|
||||
int xpos, int ypos,
|
||||
gen::SelectionMode mode)
|
||||
{
|
||||
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() && m_isOrigMaskVisible) {
|
||||
if (!origMask.isEmpty() && isOrigMaskVisible) {
|
||||
switch (mode) {
|
||||
case gen::SelectionMode::DEFAULT:
|
||||
break;
|
||||
@ -251,18 +190,99 @@ Mask* MaskByColorCommand::generateMask(const Mask& origMask,
|
||||
return mask.release();
|
||||
}
|
||||
|
||||
void MaskByColorCommand::maskPreview(const ContextReader& reader)
|
||||
{
|
||||
ASSERT(m_window);
|
||||
if (m_window && m_checkPreview->isSelected()) {
|
||||
int xpos, ypos;
|
||||
const Image* image = reader.image(&xpos, &ypos);
|
||||
std::unique_ptr<Mask> mask(generateMask(*reader.document()->mask(),
|
||||
reader.sprite(), image,
|
||||
xpos, ypos,
|
||||
m_selMode->selectionMode()));
|
||||
class MaskByColorCommand : public CommandWithNewParams<MaskByColorParams> {
|
||||
public:
|
||||
MaskByColorCommand();
|
||||
|
||||
ContextWriter writer(reader);
|
||||
protected:
|
||||
bool onEnabled(Context* context) override;
|
||||
void onExecute(Context* context) override;
|
||||
|
||||
};
|
||||
|
||||
MaskByColorCommand::MaskByColorCommand()
|
||||
: CommandWithNewParams(CommandId::MaskByColor(), CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
||||
bool MaskByColorCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||
ContextFlags::HasActiveSprite |
|
||||
ContextFlags::HasActiveImage);
|
||||
}
|
||||
|
||||
void MaskByColorCommand::onExecute(Context* context)
|
||||
{
|
||||
const ContextReader reader(context);
|
||||
const Sprite* sprite = reader.sprite();
|
||||
|
||||
if (!App::instance()->isGui() || !sprite)
|
||||
return;
|
||||
|
||||
int xpos, ypos;
|
||||
const Image* image = reader.image(&xpos, &ypos);
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
MaskByColorWindow window(reader);
|
||||
// Save original mask visibility to process it correctly in
|
||||
// ADD/SUBTRACT/INTERSECT Selection Mode
|
||||
bool isOrigMaskVisible = reader.document()->isMaskVisible();
|
||||
|
||||
// Load window configuration
|
||||
load_window_pos(&window, ConfigSection);
|
||||
|
||||
// Open the window
|
||||
window.openWindowInForeground();
|
||||
|
||||
bool apply = window.accepted();
|
||||
|
||||
ContextWriter writer(reader);
|
||||
Doc* document(writer.document());
|
||||
|
||||
if (apply) {
|
||||
int color = color_utils::color_for_image(window.getColor(),
|
||||
sprite->pixelFormat());
|
||||
int tolerance = window.getTolerance();
|
||||
Tx tx(writer, "Mask by Color", DoesntModifyDocument);
|
||||
std::unique_ptr<Mask> mask(generateMask(*document->mask(),
|
||||
isOrigMaskVisible,
|
||||
image, xpos, ypos,
|
||||
window.getSelectionMode(),
|
||||
color, tolerance));
|
||||
tx(new cmd::SetMask(document, mask.get()));
|
||||
tx.commit();
|
||||
|
||||
set_config_int(ConfigSection, "Tolerance", tolerance);
|
||||
set_config_bool(ConfigSection, "Preview", window.isPreviewChecked());
|
||||
}
|
||||
else {
|
||||
document->generateMaskBoundaries();
|
||||
}
|
||||
|
||||
// Update boundaries and editors.
|
||||
update_screen_for_document(document);
|
||||
|
||||
// Save window configuration.
|
||||
save_window_pos(&window, ConfigSection);
|
||||
}
|
||||
|
||||
void MaskByColorWindow::maskPreview()
|
||||
{
|
||||
if (isPreviewChecked()) {
|
||||
int xpos, ypos;
|
||||
const Image* image = m_reader->image(&xpos, &ypos);
|
||||
int color = color_utils::color_for_image(m_buttonColor->getColor(),
|
||||
m_reader->sprite()->pixelFormat());
|
||||
int tolerance = m_sliderTolerance->getValue();
|
||||
std::unique_ptr<Mask> mask(generateMask(*m_reader->document()->mask(),
|
||||
m_isOrigMaskVisible,
|
||||
image, xpos, ypos,
|
||||
m_selMode->selectionMode(),
|
||||
color, tolerance));
|
||||
|
||||
ContextWriter writer(*m_reader);
|
||||
|
||||
#ifdef SHOW_BOUNDARIES_GEN_PERFORMANCE
|
||||
base::Chrono chrono;
|
||||
|
Loading…
x
Reference in New Issue
Block a user