Add ability to cut colors in the ColorBar

This commit is contained in:
David Capello 2015-05-10 21:36:46 -03:00
parent cd1f764d85
commit 9fc7b993d4
7 changed files with 125 additions and 108 deletions

View File

@ -33,6 +33,7 @@
#include "app/ui/status_bar.h" #include "app/ui/status_bar.h"
#include "app/ui_context.h" #include "app/ui_context.h"
#include "app/ui_context.h" #include "app/ui_context.h"
#include "app/util/clipboard.h"
#include "base/bind.h" #include "base/bind.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/palette.h" #include "doc/palette.h"
@ -421,7 +422,7 @@ void ColorBar::onPaletteViewChangeSize(int boxsize)
} }
void ColorBar::onPaletteViewPasteColors( void ColorBar::onPaletteViewPasteColors(
Editor* editor, const doc::PalettePicks& from, const doc::PalettePicks& _to) const Palette* fromPal, const doc::PalettePicks& from, const doc::PalettePicks& _to)
{ {
if (!from.picks() || !_to.picks()) // Nothing to do if (!from.picks() || !_to.picks()) // Nothing to do
return; return;
@ -440,7 +441,6 @@ void ColorBar::onPaletteViewPasteColors(
} }
} }
Palette* copyFromPalette = editor->sprite()->palette(editor->frame());
Palette newPalette(*get_current_palette()); Palette newPalette(*get_current_palette());
int i = 0; int i = 0;
@ -449,7 +449,7 @@ void ColorBar::onPaletteViewPasteColors(
for (auto state : from) { for (auto state : from) {
if (state) { if (state) {
if (j < newPalette.size()) { if (j < newPalette.size()) {
newPalette.setEntry(j, copyFromPalette->getEntry(i)); newPalette.setEntry(j, fromPal->getEntry(i));
for (++j; j<to.size(); ++j) for (++j; j<to.size(); ++j)
if (to[j]) if (to[j])
break; break;
@ -608,7 +608,7 @@ void ColorBar::onNewInputPriority(InputChainElement* element)
bool ColorBar::onCanCut(Context* ctx) bool ColorBar::onCanCut(Context* ctx)
{ {
return false; // TODO return (m_paletteView.getSelectedEntriesCount() > 0);
} }
bool ColorBar::onCanCopy(Context* ctx) bool ColorBar::onCanCopy(Context* ctx)
@ -618,7 +618,7 @@ bool ColorBar::onCanCopy(Context* ctx)
bool ColorBar::onCanPaste(Context* ctx) bool ColorBar::onCanPaste(Context* ctx)
{ {
return m_paletteView.areColorsInClipboard(); return (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries);
} }
bool ColorBar::onCanClear(Context* ctx) bool ColorBar::onCanClear(Context* ctx)
@ -628,7 +628,8 @@ bool ColorBar::onCanClear(Context* ctx)
bool ColorBar::onCut(Context* ctx) bool ColorBar::onCut(Context* ctx)
{ {
return false; // TODO m_paletteView.cutToClipboard();
return true;
} }
bool ColorBar::onCopy(Context* ctx) bool ColorBar::onCopy(Context* ctx)

View File

@ -93,7 +93,7 @@ namespace app {
void onPaletteViewIndexChange(int index, ui::MouseButtons buttons) override; void onPaletteViewIndexChange(int index, ui::MouseButtons buttons) override;
void onPaletteViewRemapColors(const doc::Remap& remap, const doc::Palette* newPalette) override; void onPaletteViewRemapColors(const doc::Remap& remap, const doc::Palette* newPalette) override;
void onPaletteViewChangeSize(int boxsize) override; void onPaletteViewChangeSize(int boxsize) override;
void onPaletteViewPasteColors(Editor* editor, const doc::PalettePicks& from, const doc::PalettePicks& to) override; void onPaletteViewPasteColors(const Palette* fromPal, const doc::PalettePicks& from, const doc::PalettePicks& to) override;
private: private:
void destroyRemap(); void destroyRemap();

View File

@ -21,6 +21,7 @@
#include "app/ui/skin/skin_theme.h" #include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h" #include "app/ui/skin/style.h"
#include "app/ui/status_bar.h" #include "app/ui/status_bar.h"
#include "app/util/clipboard.h"
#include "doc/blend.h" #include "doc/blend.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/palette.h" #include "doc/palette.h"
@ -64,11 +65,9 @@ PaletteView::PaletteView(bool editable, PaletteViewDelegate* delegate, int boxsi
, m_currentEntry(-1) , m_currentEntry(-1)
, m_rangeAnchor(-1) , m_rangeAnchor(-1)
, m_selectedEntries(Palette::MaxColors) , m_selectedEntries(Palette::MaxColors)
, m_clipboardEntries(Palette::MaxColors)
, m_isUpdatingColumns(false) , m_isUpdatingColumns(false)
, m_hot(Hit::NONE) , m_hot(Hit::NONE)
, m_copy(false) , m_copy(false)
, m_clipboardEditor(nullptr)
{ {
setFocusStop(true); setFocusStop(true);
setDoubleBuffered(true); setDoubleBuffered(true);
@ -80,11 +79,6 @@ PaletteView::PaletteView(bool editable, PaletteViewDelegate* delegate, int boxsi
m_conn = App::instance()->PaletteChange.connect(&PaletteView::onAppPaletteChange, this); m_conn = App::instance()->PaletteChange.connect(&PaletteView::onAppPaletteChange, this);
} }
PaletteView::~PaletteView()
{
setClipboardEditor(nullptr);
}
void PaletteView::setColumns(int columns) void PaletteView::setColumns(int columns)
{ {
int old_columns = m_columns; int old_columns = m_columns;
@ -211,23 +205,57 @@ void PaletteView::setBoxSize(int boxsize)
view->layout(); view->layout();
} }
void PaletteView::cutToClipboard()
{
if (!m_selectedEntries.picks())
return;
clipboard::copy_palette(get_current_palette(), m_selectedEntries);
// Convert selected colors to black and send them to the back of the
// palette.
Palette palette(*get_current_palette());
Palette newPalette(palette);
Remap remap = create_remap_to_move_picks(m_selectedEntries, palette.size());
for (int i=0; i<palette.size(); ++i) {
if (m_selectedEntries[i])
newPalette.setEntry(remap[i], rgba(0, 0, 0, 255));
else
newPalette.setEntry(remap[i], palette.getEntry(i));
}
m_currentEntry = m_selectedEntries.firstPick();
m_selectedEntries.clear();
stopMarchingAnts();
if (m_delegate) {
m_delegate->onPaletteViewRemapColors(remap, &newPalette);
m_delegate->onPaletteViewIndexChange(m_currentEntry, ui::kButtonLeft);
}
set_current_palette(&newPalette, false);
getManager()->invalidate();
}
void PaletteView::copyToClipboard() void PaletteView::copyToClipboard()
{ {
if (current_editor) { if (!m_selectedEntries.picks())
setClipboardEditor(current_editor); return;
m_clipboardEntries = m_selectedEntries;
clipboard::copy_palette(get_current_palette(), m_selectedEntries);
startMarchingAnts(); startMarchingAnts();
invalidate(); invalidate();
}
} }
void PaletteView::pasteFromClipboard() void PaletteView::pasteFromClipboard()
{ {
if (m_clipboardEditor && m_clipboardEntries.picks()) { if (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries) {
if (m_delegate) if (m_delegate)
m_delegate->onPaletteViewPasteColors( m_delegate->onPaletteViewPasteColors(
m_clipboardEditor, m_clipboardEntries, m_selectedEntries); clipboard::get_palette(),
clipboard::get_palette_picks(),
m_selectedEntries);
// We just hide the marching ants, the user can paste multiple // We just hide the marching ants, the user can paste multiple
// times. // times.
@ -238,30 +266,10 @@ void PaletteView::pasteFromClipboard()
void PaletteView::discardClipboardSelection() void PaletteView::discardClipboardSelection()
{ {
bool redraw = false;
if (m_clipboardEditor) {
setClipboardEditor(nullptr);
redraw = true;
}
if (m_clipboardEntries.picks() > 0) {
m_clipboardEntries.clear();
redraw = true;
}
if (isMarchingAntsRunning()) { if (isMarchingAntsRunning()) {
stopMarchingAnts(); stopMarchingAnts();
redraw = true;
}
if (redraw)
invalidate(); invalidate();
} }
bool PaletteView::areColorsInClipboard() const
{
return (m_clipboardEditor && m_clipboardEntries.picks());
} }
bool PaletteView::onProcessMessage(Message* msg) bool PaletteView::onProcessMessage(Message* msg)
@ -425,15 +433,19 @@ void PaletteView::onPaint(ui::PaintEvent& ev)
} }
// Draw marching ants // Draw marching ants
if (isMarchingAntsRunning() && if ((isMarchingAntsRunning()) &&
m_clipboardEditor && (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries)) {
m_clipboardEditor == current_editor) { Palette* clipboardPalette = clipboard::get_palette();
for (int i=0; i<palette->size(); ++i) { const PalettePicks& clipboardPicks = clipboard::get_palette_picks();
if (!m_clipboardEntries[i])
if (clipboardPalette &&
clipboardPalette->countDiff(palette, nullptr, nullptr) == 0) {
for (int i=0; i<clipboardPicks.size(); ++i) {
if (!clipboardPicks[i])
continue; continue;
gfx::Rect box, clipR; gfx::Rect box, clipR;
getEntryBoundsAndClip(i, m_clipboardEntries, box, clipR, outlineWidth); getEntryBoundsAndClip(i, clipboardPicks, box, clipR, outlineWidth);
IntersectClip clip(g, clipR); IntersectClip clip(g, clipR);
if (clip) { if (clip) {
@ -442,6 +454,7 @@ void PaletteView::onPaint(ui::PaintEvent& ev)
} }
} }
} }
}
// Draw drop target // Draw drop target
if (m_state == State::DRAGGING_OUTLINE) { if (m_state == State::DRAGGING_OUTLINE) {
@ -490,12 +503,6 @@ void PaletteView::onDrawMarchingAnts()
invalidate(); invalidate();
} }
void PaletteView::onDestroyEditor(Editor* editor)
{
if (m_clipboardEditor == editor)
discardClipboardSelection();
}
void PaletteView::request_size(int* w, int* h) void PaletteView::request_size(int* w, int* h)
{ {
div_t d = div(Palette::MaxColors, m_columns); div_t d = div(Palette::MaxColors, m_columns);
@ -708,17 +715,6 @@ bool PaletteView::pickedXY(const doc::PalettePicks& entries, int i, int dx, int
return false; return false;
} }
void PaletteView::setClipboardEditor(Editor* editor)
{
if (m_clipboardEditor)
m_clipboardEditor->removeObserver(this);
m_clipboardEditor = editor;
if (m_clipboardEditor)
m_clipboardEditor->addObserver(this);
}
void PaletteView::updateCopyFlag(ui::Message* msg) void PaletteView::updateCopyFlag(ui::Message* msg)
{ {
bool oldCopy = m_copy; bool oldCopy = m_copy;

View File

@ -10,7 +10,6 @@
#pragma once #pragma once
#include "app/color.h" #include "app/color.h"
#include "app/ui/editor/editor_observer.h"
#include "app/ui/marching_ants.h" #include "app/ui/marching_ants.h"
#include "base/connection.h" #include "base/connection.h"
#include "doc/palette_picks.h" #include "doc/palette_picks.h"
@ -27,8 +26,6 @@ namespace doc {
namespace app { namespace app {
class Editor;
class PaletteViewDelegate { class PaletteViewDelegate {
public: public:
virtual ~PaletteViewDelegate() { } virtual ~PaletteViewDelegate() { }
@ -36,15 +33,13 @@ namespace app {
virtual void onPaletteViewRemapColors(const doc::Remap& remap, const doc::Palette* newPalette) { } virtual void onPaletteViewRemapColors(const doc::Remap& remap, const doc::Palette* newPalette) { }
virtual void onPaletteViewChangeSize(int boxsize) { } virtual void onPaletteViewChangeSize(int boxsize) { }
virtual void onPaletteViewPasteColors( virtual void onPaletteViewPasteColors(
Editor* editor, const doc::PalettePicks& from, const doc::PalettePicks& to) { } const doc::Palette* fromPal, const doc::PalettePicks& from, const doc::PalettePicks& to) { }
}; };
class PaletteView : public ui::Widget class PaletteView : public ui::Widget
, public MarchingAnts , public MarchingAnts {
, public EditorObserver {
public: public:
PaletteView(bool editable, PaletteViewDelegate* delegate, int boxsize); PaletteView(bool editable, PaletteViewDelegate* delegate, int boxsize);
~PaletteView();
bool isEditable() const { return m_editable; } bool isEditable() const { return m_editable; }
@ -65,10 +60,10 @@ namespace app {
int getBoxSize() const; int getBoxSize() const;
void setBoxSize(int boxsize); void setBoxSize(int boxsize);
void cutToClipboard();
void copyToClipboard(); void copyToClipboard();
void pasteFromClipboard(); void pasteFromClipboard();
void discardClipboardSelection(); void discardClipboardSelection();
bool areColorsInClipboard() const;
Signal0<void> FocusEnter; Signal0<void> FocusEnter;
@ -79,9 +74,6 @@ namespace app {
void onPreferredSize(ui::PreferredSizeEvent& ev) override; void onPreferredSize(ui::PreferredSizeEvent& ev) override;
void onDrawMarchingAnts() override; void onDrawMarchingAnts() override;
// EditorObserver impl
void onDestroyEditor(Editor* editor) override;
private: private:
enum class State { enum class State {
@ -124,7 +116,6 @@ namespace app {
gfx::Rect& box, gfx::Rect& clip, gfx::Rect& box, gfx::Rect& clip,
int outlineWidth) const; int outlineWidth) const;
bool pickedXY(const doc::PalettePicks& entries, int i, int dx, int dy) const; bool pickedXY(const doc::PalettePicks& entries, int i, int dx, int dy) const;
void setClipboardEditor(Editor* editor);
void updateCopyFlag(ui::Message* msg); void updateCopyFlag(ui::Message* msg);
void setCursor(); void setCursor();
@ -136,12 +127,10 @@ namespace app {
int m_currentEntry; int m_currentEntry;
int m_rangeAnchor; int m_rangeAnchor;
doc::PalettePicks m_selectedEntries; doc::PalettePicks m_selectedEntries;
doc::PalettePicks m_clipboardEntries;
bool m_isUpdatingColumns; bool m_isUpdatingColumns;
ScopedConnection m_conn; ScopedConnection m_conn;
Hit m_hot; Hit m_hot;
bool m_copy; bool m_copy;
Editor* m_clipboardEditor;
}; };
ui::WidgetType palette_view_type(); ui::WidgetType palette_view_type();

View File

@ -10,8 +10,8 @@
#endif #endif
#include "app/app.h" #include "app/app.h"
#include "app/cmd/deselect_mask.h"
#include "app/cmd/clear_mask.h" #include "app/cmd/clear_mask.h"
#include "app/cmd/deselect_mask.h"
#include "app/console.h" #include "app/console.h"
#include "app/context_access.h" #include "app/context_access.h"
#include "app/document.h" #include "app/document.h"
@ -32,6 +32,7 @@
#include "app/ui_context.h" #include "app/ui_context.h"
#include "app/util/clipboard.h" #include "app/util/clipboard.h"
#include "app/util/new_image_from_mask.h" #include "app/util/new_image_from_mask.h"
#include "base/shared_ptr.h"
#include "doc/doc.h" #include "doc/doc.h"
#include "render/quantization.h" #include "render/quantization.h"
@ -86,15 +87,16 @@ static bool copy_from_document(const Site& site);
static bool first_time = true; static bool first_time = true;
static Palette* clipboard_palette = NULL; static base::SharedPtr<Palette> clipboard_palette;
static Image* clipboard_image = NULL; static PalettePicks clipboard_picks(Palette::MaxColors);
static ImageRef clipboard_image;
static ClipboardRange clipboard_range; static ClipboardRange clipboard_range;
static gfx::Point clipboard_pos(0, 0); static gfx::Point clipboard_pos(0, 0);
static void on_exit_delete_clipboard() static void on_exit_delete_clipboard()
{ {
delete clipboard_palette; clipboard_palette.reset();
delete clipboard_image; clipboard_image.reset();
} }
static void set_clipboard_image(Image* image, Palette* palette, bool set_system_clipboard) static void set_clipboard_image(Image* image, Palette* palette, bool set_system_clipboard)
@ -104,11 +106,9 @@ static void set_clipboard_image(Image* image, Palette* palette, bool set_system_
App::instance()->Exit.connect(&on_exit_delete_clipboard); App::instance()->Exit.connect(&on_exit_delete_clipboard);
} }
delete clipboard_palette; clipboard_palette.reset(palette);
delete clipboard_image; clipboard_picks.clear();
clipboard_image.reset(image);
clipboard_palette = palette;
clipboard_image = image;
// copy to the Windows clipboard // copy to the Windows clipboard
#ifdef USE_NATIVE_WIN32_CLIPBOARD #ifdef USE_NATIVE_WIN32_CLIPBOARD
@ -144,10 +144,12 @@ clipboard::ClipboardFormat clipboard::get_current_format()
return ClipboardImage; return ClipboardImage;
#endif #endif
if (clipboard_image != NULL) if (clipboard_image)
return ClipboardImage; return ClipboardImage;
else if (clipboard_range.valid()) else if (clipboard_range.valid())
return ClipboardDocumentRange; return ClipboardDocumentRange;
else if (clipboard_palette && clipboard_picks.picks())
return ClipboardPaletteEntries;
else else
return ClipboardNone; return ClipboardNone;
} }
@ -224,6 +226,15 @@ void clipboard::copy_image(Image* image, Palette* pal, const gfx::Point& point)
clipboard_pos = point; clipboard_pos = point;
} }
void clipboard::copy_palette(const Palette* palette, const doc::PalettePicks& picks)
{
if (!picks.picks())
return; // Do nothing case
set_clipboard_image(nullptr, new Palette(*palette), true);
clipboard_picks = picks;
}
void clipboard::paste() void clipboard::paste()
{ {
Editor* editor = current_editor; Editor* editor = current_editor;
@ -247,13 +258,13 @@ void clipboard::paste()
} }
#endif #endif
if (clipboard_image == NULL) if (!clipboard_image)
return; return;
Palette* dst_palette = dstSpr->palette(editor->frame()); Palette* dst_palette = dstSpr->palette(editor->frame());
// Source image (clipboard or a converted copy to the destination 'imgtype') // Source image (clipboard or a converted copy to the destination 'imgtype')
Image* src_image; ImageRef src_image;
if (clipboard_image->pixelFormat() == dstSpr->pixelFormat() && if (clipboard_image->pixelFormat() == dstSpr->pixelFormat() &&
// Indexed images can be copied directly only if both images // Indexed images can be copied directly only if both images
// have the same palette. // have the same palette.
@ -264,17 +275,15 @@ void clipboard::paste()
else { else {
RgbMap* dst_rgbmap = dstSpr->rgbMap(editor->frame()); RgbMap* dst_rgbmap = dstSpr->rgbMap(editor->frame());
src_image = render::convert_pixel_format( src_image.reset(
clipboard_image, NULL, dstSpr->pixelFormat(), render::convert_pixel_format(
DitheringMethod::NONE, dst_rgbmap, clipboard_palette, clipboard_image.get(), NULL, dstSpr->pixelFormat(),
false); DitheringMethod::NONE, dst_rgbmap, clipboard_palette.get(),
false));
} }
// Change to MovingPixelsState // Change to MovingPixelsState
editor->pasteImage(src_image, clipboard_pos); editor->pasteImage(src_image.get(), clipboard_pos);
if (src_image != clipboard_image)
delete src_image;
break; break;
} }
@ -422,4 +431,19 @@ bool clipboard::get_image_size(gfx::Size& size)
#endif #endif
} }
Palette* clipboard::get_palette()
{
if (clipboard::get_current_format() == ClipboardPaletteEntries) {
ASSERT(clipboard_palette);
return clipboard_palette.get();
}
else
return nullptr;
}
const PalettePicks& clipboard::get_palette_picks()
{
return clipboard_picks;
}
} // namespace app } // namespace app

View File

@ -16,6 +16,7 @@
namespace doc { namespace doc {
class Image; class Image;
class Palette; class Palette;
class PalettePicks;
} }
namespace app { namespace app {
@ -30,9 +31,10 @@ namespace app {
ClipboardNone, ClipboardNone,
ClipboardImage, ClipboardImage,
ClipboardDocumentRange, ClipboardDocumentRange,
ClipboardPaletteEntries,
}; };
// TODO Horrible API: refactor it. // TODO Horrible API: refactor it (maybe a merge with she::clipboard).
ClipboardFormat get_current_format(); ClipboardFormat get_current_format();
void get_document_range_info(Document** document, DocumentRange* range); void get_document_range_info(Document** document, DocumentRange* range);
@ -42,6 +44,7 @@ namespace app {
void copy(const ContextReader& context); void copy(const ContextReader& context);
void copy_range(const ContextReader& context, const DocumentRange& range); void copy_range(const ContextReader& context, const DocumentRange& range);
void copy_image(Image* image, Palette* palette, const gfx::Point& point); void copy_image(Image* image, Palette* palette, const gfx::Point& point);
void copy_palette(const Palette* palette, const PalettePicks& picks);
void paste(); void paste();
// Returns true and fills the specified "size"" with the image's // Returns true and fills the specified "size"" with the image's
@ -49,6 +52,9 @@ namespace app {
// doesn't contain an image at all. // doesn't contain an image at all.
bool get_image_size(gfx::Size& size); bool get_image_size(gfx::Size& size);
Palette* get_palette();
const PalettePicks& get_palette_picks();
} // namespace clipboard } // namespace clipboard
} // namespace app } // namespace app

View File

@ -19,6 +19,7 @@
#include "doc/frame_tags.h" #include "doc/frame_tags.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/image_bits.h" #include "doc/image_bits.h"
#include "doc/image_ref.h"
#include "doc/layer.h" #include "doc/layer.h"
#include "doc/mask.h" #include "doc/mask.h"
#include "doc/object.h" #include "doc/object.h"