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

View File

@ -93,7 +93,7 @@ namespace app {
void onPaletteViewIndexChange(int index, ui::MouseButtons buttons) override;
void onPaletteViewRemapColors(const doc::Remap& remap, const doc::Palette* newPalette) 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:
void destroyRemap();

View File

@ -21,6 +21,7 @@
#include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h"
#include "app/ui/status_bar.h"
#include "app/util/clipboard.h"
#include "doc/blend.h"
#include "doc/image.h"
#include "doc/palette.h"
@ -64,11 +65,9 @@ PaletteView::PaletteView(bool editable, PaletteViewDelegate* delegate, int boxsi
, m_currentEntry(-1)
, m_rangeAnchor(-1)
, m_selectedEntries(Palette::MaxColors)
, m_clipboardEntries(Palette::MaxColors)
, m_isUpdatingColumns(false)
, m_hot(Hit::NONE)
, m_copy(false)
, m_clipboardEditor(nullptr)
{
setFocusStop(true);
setDoubleBuffered(true);
@ -80,11 +79,6 @@ PaletteView::PaletteView(bool editable, PaletteViewDelegate* delegate, int boxsi
m_conn = App::instance()->PaletteChange.connect(&PaletteView::onAppPaletteChange, this);
}
PaletteView::~PaletteView()
{
setClipboardEditor(nullptr);
}
void PaletteView::setColumns(int columns)
{
int old_columns = m_columns;
@ -211,23 +205,57 @@ void PaletteView::setBoxSize(int boxsize)
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()
{
if (current_editor) {
setClipboardEditor(current_editor);
m_clipboardEntries = m_selectedEntries;
if (!m_selectedEntries.picks())
return;
startMarchingAnts();
invalidate();
}
clipboard::copy_palette(get_current_palette(), m_selectedEntries);
startMarchingAnts();
invalidate();
}
void PaletteView::pasteFromClipboard()
{
if (m_clipboardEditor && m_clipboardEntries.picks()) {
if (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries) {
if (m_delegate)
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
// times.
@ -238,30 +266,10 @@ void PaletteView::pasteFromClipboard()
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()) {
stopMarchingAnts();
redraw = true;
}
if (redraw)
invalidate();
}
bool PaletteView::areColorsInClipboard() const
{
return (m_clipboardEditor && m_clipboardEntries.picks());
}
}
bool PaletteView::onProcessMessage(Message* msg)
@ -425,20 +433,25 @@ void PaletteView::onPaint(ui::PaintEvent& ev)
}
// Draw marching ants
if (isMarchingAntsRunning() &&
m_clipboardEditor &&
m_clipboardEditor == current_editor) {
for (int i=0; i<palette->size(); ++i) {
if (!m_clipboardEntries[i])
continue;
if ((isMarchingAntsRunning()) &&
(clipboard::get_current_format() == clipboard::ClipboardPaletteEntries)) {
Palette* clipboardPalette = clipboard::get_palette();
const PalettePicks& clipboardPicks = clipboard::get_palette_picks();
gfx::Rect box, clipR;
getEntryBoundsAndClip(i, m_clipboardEntries, box, clipR, outlineWidth);
if (clipboardPalette &&
clipboardPalette->countDiff(palette, nullptr, nullptr) == 0) {
for (int i=0; i<clipboardPicks.size(); ++i) {
if (!clipboardPicks[i])
continue;
IntersectClip clip(g, clipR);
if (clip) {
CheckedDrawMode checked(g, getMarchingAntsOffset());
g->drawRect(gfx::rgba(0, 0, 0), box);
gfx::Rect box, clipR;
getEntryBoundsAndClip(i, clipboardPicks, box, clipR, outlineWidth);
IntersectClip clip(g, clipR);
if (clip) {
CheckedDrawMode checked(g, getMarchingAntsOffset());
g->drawRect(gfx::rgba(0, 0, 0), box);
}
}
}
}
@ -490,12 +503,6 @@ void PaletteView::onDrawMarchingAnts()
invalidate();
}
void PaletteView::onDestroyEditor(Editor* editor)
{
if (m_clipboardEditor == editor)
discardClipboardSelection();
}
void PaletteView::request_size(int* w, int* h)
{
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;
}
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)
{
bool oldCopy = m_copy;

View File

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

View File

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

View File

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

View File

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