Integrate paste command with the new MovingPixelsState editor's state.

This commit is contained in:
David Capello 2012-01-05 23:21:51 -03:00
parent d4cb85f7a1
commit b1044003c8
12 changed files with 112 additions and 742 deletions

View File

@ -57,8 +57,7 @@ bool PasteCommand::onEnabled(Context* context)
void PasteCommand::onExecute(Context* context)
{
ActiveDocumentWriter document(context);
clipboard::paste(document);
clipboard::paste();
}
//////////////////////////////////////////////////////////////////////

View File

@ -30,6 +30,7 @@
#include "raster/cel.h"
#include "raster/image.h"
#include "raster/layer.h"
#include "raster/mask.h"
#include "raster/palette.h"
#include "raster/quantization.h"
#include "raster/rotate.h"
@ -58,55 +59,15 @@
#include "util/clipboard_win32.h"
#endif
#define SCALE_MODE 0
#define ROTATE_MODE 1
enum {
ACTION_SETMODE,
ACTION_MOVE,
ACTION_SCALE_TL,
ACTION_SCALE_T,
ACTION_SCALE_TR,
ACTION_SCALE_L,
ACTION_SCALE_R,
ACTION_SCALE_BL,
ACTION_SCALE_B,
ACTION_SCALE_BR,
ACTION_ROTATE_TL,
ACTION_ROTATE_T,
ACTION_ROTATE_TR,
ACTION_ROTATE_L,
ACTION_ROTATE_R,
ACTION_ROTATE_BL,
ACTION_ROTATE_B,
ACTION_ROTATE_BR,
};
static void set_clipboard(Image* image, Palette* palette, bool set_system_clipboard);
static bool copy_from_document(const Document* document);
static bool interactive_transform(Editor* widget, Image *dest_image, Image *image,
int x, int y, int xout[4], int yout[4]);
static void apply_rotation(int x1, int y1, int x2, int y2,
fixed angle, int cx, int cy,
int xout[4], int yout[4]);
static void draw_box(BITMAP *bmp,
int cx1, int cy1, int cx2, int cy2,
int x1, int y1, int x2, int y2, BITMAP *preview,
int mode, fixed angle, int cx, int cy);
static void draw_icon(BITMAP *bmp, int x, int y, int mode, fixed angle);
static void fill_in_vars(int *in_box,
int *in_left, int *in_center, int *in_right,
int *in_top, int *in_middle, int *in_bottom,
int x1, int y1, int x2, int y2, fixed angle,
int cx, int cy);
static void update_status_bar(Editor* editor, Image *image,
int x1, int y1, int x2, int y2, fixed angle);
static bool first_time = true;
static Palette* clipboard_palette = NULL;
static Image* clipboard_image = NULL;
static int clipboard_x = 0;
static int clipboard_y = 0;
static void on_exit_delete_clipboard()
{
@ -143,6 +104,9 @@ static bool copy_from_document(const Document* document)
if (!image)
return false;
clipboard_x = document->getMask()->x;
clipboard_y = document->getMask()->y;
const Palette* pal = document->getSprite()->getPalette(document->getSprite()->getCurrentFrame());
set_clipboard(image, pal ? new Palette(*pal): NULL, true);
return true;
@ -197,17 +161,12 @@ void clipboard::copy_image(Image* image, Palette* pal)
pal ? new Palette(*pal): NULL, true);
}
void clipboard::paste(DocumentWriter& document)
void clipboard::paste()
{
UndoTransaction undoTransaction(document, "Paste");
undo::UndoHistory* undo = document->getUndoHistory();
int xout[4], yout[4];
int dst_x, dst_y;
Image *src_image;
Image* dst_image;
bool paste;
Editor* editor = current_editor;
#ifdef ALLEGRO_WINDOWS
// Get the image from the clipboard.
{
Image* win32_image = NULL;
Palette* win32_palette = NULL;
@ -216,45 +175,14 @@ void clipboard::paste(DocumentWriter& document)
set_clipboard(win32_image, win32_palette, false);
}
#endif
Sprite* sprite = editor->getDocument()->getSprite();
if (clipboard_image == NULL)
return;
ASSERT(document != NULL);
ASSERT(document->getSprite() != NULL);
Sprite* sprite = document->getSprite();
// Destination image (where to put this image)
dst_image = sprite->getCurrentImage(&dst_x, &dst_y);
if (!dst_image) {
// We don't have an image to paste the clipboard content,
// here we create the cel/image to draw on it
LayerImage* layer = dynamic_cast<LayerImage*>(sprite->getCurrentLayer());
ASSERT(layer != NULL);
// Create the image for the cel (of a size equal to the entire sprite size)
dst_image = image_new(sprite->getImgType(), sprite->getWidth(), sprite->getHeight());
image_clear(dst_image, 0);
// Add the new image in the stock
int dst_image_index = sprite->getStock()->addImage(dst_image);
if (undo->isEnabled())
undo->pushUndoer(new undoers::AddImage(undo->getObjects(),
sprite->getStock(), dst_image_index));
// Create the new cel in the current frame with the recently
// created image
Cel* cel = new Cel(sprite->getCurrentFrame(), dst_image_index);
// Add the cel to the layer
undoTransaction.addCel(layer, cel);
// Default destination position
dst_x = dst_y = 0;
}
// Source image (clipboard or a converted copy to the destination 'imgtype')
Image* src_image;
if (clipboard_image->imgtype == sprite->getImgType())
src_image = clipboard_image;
else {
@ -264,630 +192,9 @@ void clipboard::paste(DocumentWriter& document)
false);
}
// Do the interactive-transform loop (where the user can move the floating image)
{
View* view = View::getView(current_editor);
gfx::Rect vp = view->getViewportBounds();
int x, y, x1, y1, x2, y2;
current_editor->screenToEditor(vp.x, vp.y, &x1, &y1);
current_editor->screenToEditor(vp.x+vp.w-1, vp.y+vp.h-1, &x2, &y2);
x = (x1+x2)/2-src_image->w/2;
y = (y1+y2)/2-src_image->h/2;
paste = interactive_transform(current_editor,
dst_image, src_image, x, y, xout, yout);
}
if (paste) {
int c, w, h, u1, v1, u2, v2;
/* align to the destination cel-position */
for (c=0; c<4; ++c) {
xout[c] -= dst_x;
yout[c] -= dst_y;
}
/* clip the box for the undo */
u1 = MAX(0, MIN(xout[0], MIN(xout[1], MIN(xout[2], xout[3]))));
v1 = MAX(0, MIN(yout[0], MIN(yout[1], MIN(yout[2], yout[3]))));
u2 = MIN(dst_image->w-1, MAX(xout[0], MAX(xout[1], MAX(xout[2], xout[3]))));
v2 = MIN(dst_image->h-1, MAX(yout[0], MAX(yout[1], MAX(yout[2], yout[3]))));
w = u2-u1+1;
h = v2-v1+1;
if (w >= 1 && h >= 1) {
// Add information to hold the modified region in the image.
if (undo->isEnabled())
undo->pushUndoer(new undoers::ImageArea(undo->getObjects(),
dst_image, u1, v1, w, h));
// Draw the transformed image.
image_parallelogram(dst_image, src_image,
xout[0], yout[0], xout[1], yout[1],
xout[2], yout[2], xout[3], yout[3]);
}
// Commit the "paste" operation
undoTransaction.commit();
}
// Change to MovingPixelsState
editor->pasteImage(src_image, clipboard_x, clipboard_y);
if (src_image != clipboard_image)
image_free(src_image);
update_screen_for_document(document);
}
/**********************************************************************/
/* interactive transform */
enum { DONE_NONE, DONE_CANCEL, DONE_PASTE };
static bool interactive_transform(Editor* editor,
Image *dest_image, Image *image,
int x, int y,
int xout[4], int yout[4])
{
#define UPDATE() \
jmouse_hide(); \
old_screen = ji_screen; \
ji_screen = bmp1; \
jmanager_dispatch_messages(ji_get_default_manager()); \
ji_screen = old_screen; \
REDRAW(); \
jmouse_show();
#define REDRAW() \
jmouse_hide(); \
blit(bmp1, bmp2, vp.x, vp.y, 0, 0, vp.w, vp.h); \
draw_box(bmp2, \
0, 0, vp.w-1, vp.h-1, \
x1-vp.x, y1-vp.y, x2-vp.x, y2-vp.y, \
preview, mode, angle, cx-vp.x, cy-vp.y); \
blit(bmp2, ji_screen, 0, 0, vp.x, vp.y, vp.w, vp.h); \
update_status_bar(editor, image, x1, y1, x2, y2, angle); \
jmouse_show();
int x1, y1, x2, y2;
int u1, v1, u2, v2;
int action = ACTION_SETMODE;
int mode = SCALE_MODE;
BITMAP *bmp1, *bmp2, *preview, *old_screen;
gfx::Rect vp = View::getView(editor)->getViewportBounds();
int done = DONE_NONE;
fixed angle = 0;
int cx, cy;
int mask_color;
editor->hideDrawingCursor();
editor->editorToScreen(x, y, &x1, &y1);
editor->editorToScreen(x+image->w, y+image->h, &x2, &y2);
cx = (x1+x2)/2;
cy = (y1+y2)/2;
/* generate a bitmap to save the viewport content and other to make
double-buffered */
bmp1 = create_bitmap(JI_SCREEN_W, JI_SCREEN_H);
bmp2 = create_bitmap(vp.w, vp.h);
jmouse_hide();
blit(ji_screen, bmp1, 0, 0, 0, 0, JI_SCREEN_W, JI_SCREEN_H);
jmouse_show();
/* generate the preview bitmap (for fast-blitting) */
preview = create_bitmap(image->w, image->h);
mask_color = bitmap_mask_color(preview);
image_to_allegro(image, preview, 0, 0, get_current_palette());
switch (image->imgtype) {
case IMAGE_RGB: {
int x, y;
for (y=0; y<image->h; y++)
for (x=0; x<image->w; x++)
if (_rgba_geta(image_getpixel_fast<RgbTraits>(image, x, y)) < 128)
putpixel(preview, x, y, mask_color);
break;
}
case IMAGE_GRAYSCALE: {
int x, y;
for (y=0; y<image->h; y++)
for (x=0; x<image->w; x++)
if (_graya_geta(image_getpixel_fast<GrayscaleTraits>(image, x, y)) < 128)
putpixel(preview, x, y, mask_color);
break;
}
case IMAGE_INDEXED: {
int x, y;
for (y=0; y<image->h; y++)
for (x=0; x<image->w; x++)
if (image_getpixel_fast<IndexedTraits>(image, x, y) == 0)
putpixel(preview, x, y, mask_color);
break;
}
}
/* update the bitmaps */
UPDATE();
while (done == DONE_NONE) {
poll_keyboard();
if (keypressed()) {
int c = readkey();
fixed old_angle = angle;
switch (c>>8) {
case KEY_ESC: done = DONE_CANCEL; break; /* cancel */
case KEY_ENTER: done = DONE_PASTE; break; /* paste */
case KEY_LEFT: angle = fixadd(angle, itofix(1)); break;
case KEY_RIGHT: angle = fixsub(angle, itofix(1)); break;
case KEY_UP: angle = fixadd(angle, itofix(32)); break;
case KEY_DOWN: angle = fixsub(angle, itofix(32)); break;
}
if (old_angle != angle) {
angle &= 255<<16;
REDRAW();
}
}
/* mouse moved */
if (jmouse_poll()) {
int in_left, in_center, in_right;
int in_top, in_middle, in_bottom;
int in_box;
fill_in_vars(&in_box,
&in_left, &in_center, &in_right,
&in_top, &in_middle, &in_bottom,
x1, y1, x2, y2, angle, cx, cy);
if (in_box) {
jmouse_set_cursor(JI_CURSOR_SCROLL);
action = ACTION_MOVE;
}
else {
/* top */
if (in_top && in_left) {
jmouse_set_cursor(JI_CURSOR_SIZE_TL);
action = mode == SCALE_MODE ? ACTION_SCALE_TL: ACTION_ROTATE_TL;
}
else if (in_top && in_center) {
jmouse_set_cursor(JI_CURSOR_SIZE_T);
action = mode == SCALE_MODE ? ACTION_SCALE_T: ACTION_ROTATE_T;
}
else if (in_top && in_right) {
jmouse_set_cursor(JI_CURSOR_SIZE_TR);
action = mode == SCALE_MODE ? ACTION_SCALE_TR: ACTION_ROTATE_TR;
}
/* middle */
else if (in_middle && in_left) {
jmouse_set_cursor(JI_CURSOR_SIZE_L);
action = mode == SCALE_MODE ? ACTION_SCALE_L: ACTION_ROTATE_L;
}
else if (in_middle && in_right) {
jmouse_set_cursor(JI_CURSOR_SIZE_R);
action = mode == SCALE_MODE ? ACTION_SCALE_R: ACTION_ROTATE_R;
}
/* bottom */
else if (in_bottom && in_left) {
jmouse_set_cursor(JI_CURSOR_SIZE_BL);
action = mode == SCALE_MODE ? ACTION_SCALE_BL: ACTION_ROTATE_BL;
}
else if (in_bottom && in_center) {
jmouse_set_cursor(JI_CURSOR_SIZE_B);
action = mode == SCALE_MODE ? ACTION_SCALE_B: ACTION_ROTATE_B;
}
else if (in_bottom && in_right) {
jmouse_set_cursor(JI_CURSOR_SIZE_BR);
action = mode == SCALE_MODE ? ACTION_SCALE_BR: ACTION_ROTATE_BR;
}
/* normal */
else {
jmouse_set_cursor(JI_CURSOR_NORMAL);
action = ACTION_SETMODE;
}
}
}
/* button pressed */
if (jmouse_b(0)) {
/* left button+shift || middle button = scroll movement */
if ((jmouse_b(0) == 1 && (key[KEY_LSHIFT] || key[KEY_RSHIFT])) ||
(jmouse_b(0) == 4)) {
View* view = View::getView(editor);
x = jmouse_x(0) - jmouse_x(1);
y = jmouse_y(0) - jmouse_y(1);
/* screenToEditor (widget, x1, y1, &x1, &y1); */
/* screenToEditor (widget, x2, y2, &x2, &y2); */
/* TODO */
gfx::Point scroll = view->getViewScroll();
editor->setEditorScroll(scroll.x-x, scroll.y-y, true);
/* editorToScreen(widget, x1, y1, &x1, &y1); */
/* editorToScreen(widget, x2, y2, &x2, &y2); */
jmouse_control_infinite_scroll(vp);
view->invalidate();
jwidget_flush_redraw(view);
UPDATE();
/* recenter the pivot (cx, cy) */
/* { */
/* MATRIX m; */
/* fixed fx, fy, fz; */
/* /\* new pivot position with transformation *\/ */
/* int ncx = (x1+x2)/2; */
/* int ncy = (y1+y2)/2; */
/* get_rotation_matrix (&m, 0, 0, angle); */
/* /\* new pivot position in the screen *\/ */
/* apply_matrix (&m, itofix(ncx-cx), itofix(ncy-cy), 0, &fx, &fy, &fz); */
/* cx = cx+fixtoi(fx); */
/* cy = cy+fixtoi(fy); */
/* /\* move all vertices to leave the pivot as the center *\/ */
/* x1 += cx - ncx; */
/* y1 += cy - ncy; */
/* x2 += cx - ncx; */
/* y2 += cy - ncy; */
/* jmouse_hide(); */
/* blit (bmp1, bmp2, 0, 0, 0, 0, vp->w, vp->h); */
/* draw_box (bmp2, */
/* 0, 0, vp->w-1, vp->h-1, */
/* x1-vp->x, y1-vp->y, x2-vp->x, y2-vp->y, */
/* preview, mode, angle, cx-vp->x, cy-vp->y); */
/* blit (bmp2, ji_screen, 0, 0, vp->x, vp->y, vp->w, vp->h); */
/* update_status_bar (widget, image, x1, y1, x2, y2, angle); */
/* jmouse_show(); */
/* } */
}
/* right button = paste */
else if (jmouse_b(0) == 2) {
done = DONE_PASTE; /* paste */
}
/* change mode */
else if (action == ACTION_SETMODE) {
mode = (mode == SCALE_MODE) ? ROTATE_MODE: SCALE_MODE;
REDRAW();
do {
poll_keyboard();
jmouse_poll();
gui_feedback();
} while (jmouse_b(0));
}
/* modify selection */
else {
int mx = jmouse_x(0);
int my = jmouse_y(0);
fixed angle1 = angle;
fixed angle2 = fixatan2(itofix(jmouse_y(0)-cy),
itofix(jmouse_x(0)-cx));
angle2 = fixsub(0, angle2);
u1 = x1;
v1 = y1;
u2 = x2;
v2 = y2;
do {
poll_keyboard();
if (jmouse_poll()) {
if (action == ACTION_MOVE) {
x = jmouse_x(0) - mx;
y = jmouse_y(0) - my;
}
else if (action >= ACTION_SCALE_TL &&
action <= ACTION_SCALE_BR) {
x = fixtoi(fixmul(itofix(jmouse_x(0) - mx), fixcos(angle)))
+ fixtoi(fixmul(itofix(jmouse_y(0) - my),-fixsin(angle)));
y = fixtoi(fixmul(itofix(jmouse_x(0) - mx), fixsin(angle)))
+ fixtoi(fixmul(itofix(jmouse_y(0) - my), fixcos(angle)));
}
else
x = y = 0;
x1 = u1;
y1 = v1;
x2 = u2;
y2 = v2;
switch (action) {
case ACTION_MOVE:
x1 += x;
y1 += y;
x2 += x;
y2 += y;
cx = (x1+x2)/2;
cy = (y1+y2)/2;
break;
case ACTION_SCALE_L:
x1 = MIN(x1+x, x2);
break;
case ACTION_SCALE_T:
y1 = MIN(y1+y, y2);
break;
case ACTION_SCALE_R:
x2 = MAX(x2+x, x1);
break;
case ACTION_SCALE_B:
y2 = MAX(y2+y, y1);
break;
case ACTION_SCALE_TL:
x1 = MIN(x1+x, x2);
y1 = MIN(y1+y, y2);
break;
case ACTION_SCALE_TR:
x2 = MAX(x2+x, x1);
y1 = MIN(y1+y, y2);
break;
case ACTION_SCALE_BL:
x1 = MIN(x1+x, x2);
y2 = MAX(y2+y, y1);
break;
case ACTION_SCALE_BR:
x2 = MAX(x2+x, x1);
y2 = MAX(y2+y, y1);
break;
case ACTION_ROTATE_TL:
case ACTION_ROTATE_T:
case ACTION_ROTATE_TR:
case ACTION_ROTATE_L:
case ACTION_ROTATE_R:
case ACTION_ROTATE_BL:
case ACTION_ROTATE_B:
case ACTION_ROTATE_BR:
angle = fixatan2(itofix(jmouse_y(0)-cy),
itofix(jmouse_x(0)-cx));
angle &= 255<<16;
angle = fixsub(0, angle);
angle = fixadd(angle1, fixsub (angle, angle2));
break;
}
editor->screenToEditor(x1, y1, &x1, &y1);
editor->screenToEditor(x2, y2, &x2, &y2);
// if (UIContext::instance()->getSettings()->get_snap_to_grid() && angle == 0) {
// int ox = x1;
// int oy = y1;
// apply_grid(&x1, &y1, false);
// x2 += x1 - ox;
// y2 += y1 - oy;
// }
editor->editorToScreen(x1, y1, &x1, &y1);
editor->editorToScreen(x2, y2, &x2, &y2);
/* redraw the screen */
REDRAW();
}
gui_feedback();
} while (jmouse_b(0));
/* recenter the pivot (cx, cy) */
{
MATRIX m;
fixed fx, fy, fz;
/* new pivot position with transformation */
int ncx = (x1+x2)/2;
int ncy = (y1+y2)/2;
get_rotation_matrix(&m, 0, 0, angle);
/* new pivot position in the screen */
apply_matrix(&m, itofix(ncx-cx), itofix(ncy-cy), 0, &fx, &fy, &fz);
cx = cx+fixtoi(fx);
cy = cy+fixtoi(fy);
/* move all vertices to leave the pivot as the center */
x1 += cx - ncx;
y1 += cy - ncy;
x2 += cx - ncx;
y2 += cy - ncy;
REDRAW();
}
}
}
gui_feedback();
}
if (done == DONE_PASTE) {
int c;
apply_rotation(x1, y1, x2, y2, angle, cx, cy, xout, yout);
for (c=0; c<4; c++)
editor->screenToEditor(xout[c], yout[c], xout+c, yout+c);
}
destroy_bitmap(bmp1);
destroy_bitmap(bmp2);
destroy_bitmap(preview);
clear_keybuf();
/* restore the cursor */
editor->showDrawingCursor();
return done == DONE_PASTE;
}
static void apply_rotation(int x1, int y1, int x2, int y2,
fixed angle, int cx, int cy,
int xout[4], int yout[4])
{
#define APPLYMATRIX(_x,_y,n) \
apply_matrix (&m, itofix (_x-cx), itofix (_y-cy), 0, &fx, &fy, &fz); \
xout[n] = cx+fixtoi(fx); \
yout[n] = cy+fixtoi(fy);
MATRIX m;
fixed fx, fy, fz;
get_rotation_matrix (&m, 0, 0, angle);
APPLYMATRIX(x1,y1,0);
APPLYMATRIX(x2,y1,1);
APPLYMATRIX(x2,y2,2);
APPLYMATRIX(x1,y2,3);
}
static void draw_box(BITMAP *bmp,
int cx1, int cy1, int cx2, int cy2,
int x1, int y1, int x2, int y2,
BITMAP *preview, int mode, fixed angle,
int cx, int cy)
{
fixed xs[4], ys[4];
int x[4], y[4];
int c;
set_clip_rect(bmp, cx1, cy1, cx2, cy2);
/* calculate corner positions */
apply_rotation(x1, y1, x2, y2, angle, cx, cy, x, y);
/* draw the preview */
for (c=0; c<4; c++) {
xs[c] = itofix(x[c]);
ys[c] = itofix(y[c]);
}
_parallelogram_map_standard(bmp, preview, xs, ys);
/* draw bounds */
#if 1
simple_dotted_mode(bmp, makecol(0, 0, 0), makecol(255, 255, 255));
line(bmp, x[0], y[0], x[1], y[1], 0xffffff);
line(bmp, x[0], y[0], x[3], y[3], 0xffffff);
line(bmp, x[2], y[2], x[1], y[1], 0xffffff);
line(bmp, x[2], y[2], x[3], y[3], 0xffffff);
solid_mode();
#endif
/* draw icons */
#define DRAWICON(n1,n2,_angle) \
draw_icon(bmp, (x[n1]+x[n2])/2, (y[n1]+y[n2])/2, mode, _angle)
DRAWICON(1, 2, angle);
DRAWICON(1, 1, fixadd(angle, itofix(32)));
DRAWICON(0, 1, fixadd(angle, itofix(64)));
DRAWICON(0, 0, fixadd(angle, itofix(96)));
DRAWICON(0, 3, fixadd(angle, itofix(128)));
DRAWICON(3, 3, fixadd(angle, itofix(160)));
DRAWICON(3, 2, fixadd(angle, itofix(192)));
DRAWICON(2, 2, fixadd(angle, itofix(224)));
set_clip_rect(bmp, 0, 0, bmp->w-1, bmp->h-1);
}
static void draw_icon(BITMAP *bmp, int x, int y, int mode, fixed angle)
{
SkinTheme* theme = static_cast<SkinTheme*>(CurrentTheme::get());
BITMAP* gfx;
angle &= (255<<16);
// 0 degree
if ((angle > ((256-16)<<16)) || (angle <= ((0+16)<<16))) {
gfx = theme->get_part(mode == SCALE_MODE ? PART_SCALE_ARROW_3: PART_ROTATE_ARROW_3);
draw_sprite_ex(bmp, gfx, x, y-gfx->h/2, DRAW_SPRITE_TRANS, DRAW_SPRITE_H_FLIP);
}
// 45 degree
else if ((angle >= ((32-16)<<16)) && (angle <= ((32+16)<<16))) {
gfx = theme->get_part(mode == SCALE_MODE ? PART_SCALE_ARROW_1: PART_ROTATE_ARROW_1);
draw_sprite_ex(bmp, gfx, x, y-gfx->h, DRAW_SPRITE_TRANS, DRAW_SPRITE_H_FLIP);
}
// 90 degree
else if ((angle >= ((64-16)<<16)) && (angle <= ((64+16)<<16))) {
gfx = theme->get_part(mode == SCALE_MODE ? PART_SCALE_ARROW_2: PART_ROTATE_ARROW_2);
draw_sprite_ex(bmp, gfx, x-gfx->w/2, y-gfx->h, DRAW_SPRITE_TRANS, DRAW_SPRITE_NO_FLIP);
}
// 135 degree
else if ((angle >= ((96-16)<<16)) && (angle <= ((96+16)<<16))) {
gfx = theme->get_part(mode == SCALE_MODE ? PART_SCALE_ARROW_1: PART_ROTATE_ARROW_1);
draw_sprite_ex(bmp, gfx, x-gfx->w, y-gfx->h, DRAW_SPRITE_TRANS, DRAW_SPRITE_NO_FLIP);
}
// 180 degree
else if ((angle >= ((128-16)<<16)) && (angle <= ((128+16)<<16))) {
gfx = theme->get_part(mode == SCALE_MODE ? PART_SCALE_ARROW_3: PART_ROTATE_ARROW_3);
draw_sprite_ex(bmp, gfx, x-gfx->w, y-gfx->h/2, DRAW_SPRITE_TRANS, DRAW_SPRITE_NO_FLIP);
}
// 225 degree
else if ((angle >= ((160-16)<<16)) && (angle <= ((160+16)<<16))) {
gfx = theme->get_part(mode == SCALE_MODE ? PART_SCALE_ARROW_1: PART_ROTATE_ARROW_1);
draw_sprite_ex(bmp, gfx, x-gfx->w, y, DRAW_SPRITE_TRANS, DRAW_SPRITE_V_FLIP);
}
// 270 degree
else if ((angle >= ((192-16)<<16)) && (angle <= ((192+16)<<16))) {
gfx = theme->get_part(mode == SCALE_MODE ? PART_SCALE_ARROW_2: PART_ROTATE_ARROW_2);
draw_sprite_ex(bmp, gfx, x-gfx->w/2, y, DRAW_SPRITE_TRANS, DRAW_SPRITE_V_FLIP);
}
// 315 degree
else if ((angle >= ((224-16)<<16)) && (angle <= ((224+16)<<16))) {
gfx = theme->get_part(mode == SCALE_MODE ? PART_SCALE_ARROW_1: PART_ROTATE_ARROW_1);
draw_sprite_ex(bmp, gfx, x, y, DRAW_SPRITE_TRANS, DRAW_SPRITE_VH_FLIP);
}
}
static void fill_in_vars(int *in_box,
int *in_left, int *in_center, int *in_right,
int *in_top, int *in_middle, int *in_bottom,
int x1, int y1, int x2, int y2, fixed angle,
int cx, int cy)
{
MATRIX m;
int mx = jmouse_x(0);
int my = jmouse_y(0);
fixed fx, fy, fz;
get_rotation_matrix (&m, 0, 0, fixsub (0, angle));
apply_matrix (&m, itofix (mx-cx), itofix (my-cy), 0, &fx, &fy, &fz);
mx = cx+fixtoi (fx);
my = cy+fixtoi (fy);
*in_box = (mx >= x1 && my >= y1 && mx <= x2 && my <= y2);
*in_left = (mx >= x1-12 && mx < x1);
*in_top = (my >= y1-12 && my < y1);
*in_right = (mx > x2 && mx <= x2+12);
*in_bottom = (my > y2 && my <= y2+12);
*in_center = (mx > (x1+x2)/2-6 && mx < (x1+x2)/2+6);
*in_middle = (my > (y1+y2)/2-6 && my < (y1+y2)/2+6);
}
static void update_status_bar(Editor* editor, Image *image,
int x1, int y1, int x2, int y2, fixed angle)
{
int u1, v1, u2, v2;
int iangle = 360*(fixtoi (angle & (255<<16)))/256;
editor->screenToEditor(x1, y1, &u1, &v1);
editor->screenToEditor(x2, y2, &u2, &v2);
app_get_statusbar()->setStatusText
(0,
"Pos: %3d %3d Size: %3d %3d Orig: %3d %3d (%.02f%% %.02f%%) Angle: %3d",
u1, v1, u2-u1, v2-v1,
image->w, image->h,
(double)(u2-u1)*100/image->w,
(double)(v2-v1)*100/image->h,
iangle);
jwidget_flush_redraw(app_get_statusbar());
jmanager_dispatch_messages(ji_get_default_manager());
}

View File

@ -32,7 +32,7 @@ namespace clipboard {
void cut(DocumentWriter& document);
void copy(const DocumentReader& document);
void copy_image(Image* image, Palette* palette);
void paste(DocumentWriter& document);
void paste();
} // namespace clipboard

View File

@ -45,6 +45,8 @@
#include "widgets/color_bar.h"
#include "widgets/editor/editor_customization_delegate.h"
#include "widgets/editor/editor_decorator.h"
#include "widgets/editor/moving_pixels_state.h"
#include "widgets/editor/pixels_movement.h"
#include "widgets/editor/standby_state.h"
#include "widgets/statebar.h"
@ -1152,3 +1154,17 @@ void Editor::setZoomAndCenterInMouse(int zoom, int mouse_x, int mouse_y)
}
showDrawingCursor();
}
void Editor::pasteImage(const Image* image, int x, int y)
{
Document* document = getDocument();
int opacity = 255;
Sprite* sprite = getSprite();
PixelsMovement* pixelsMovement = new PixelsMovement(document, sprite, image, x, y, opacity,
"Paste");
// Select the pasted image so the user can move it and transform it.
pixelsMovement->maskImage(image, x, y);
setState(EditorStatePtr(new MovingPixelsState(this, NULL, pixelsMovement, NoHandle)));
}

View File

@ -136,6 +136,8 @@ public:
bool processKeysToSetZoom(int scancode);
void pasteImage(const Image* image, int x, int y);
// in cursor.c
static int get_raw_cursor_color();

View File

@ -25,7 +25,7 @@ enum HandleType {
NoHandle,
// This is the handle to move the pixels region, generally, the
// whole region activates this handle.
//MoveHandle,
MoveHandle,
// One of the region's corders to scale.
ScaleNWHandle, ScaleNHandle, ScaleNEHandle,
ScaleWHandle, ScaleEHandle,

View File

@ -32,7 +32,6 @@
#include "raster/sprite.h"
#include "tools/ink.h"
#include "tools/tool.h"
#include "util/misc.h"
#include "widgets/editor/editor.h"
#include "widgets/editor/editor_customization_delegate.h"
#include "widgets/editor/pixels_movement.h"
@ -42,36 +41,24 @@
#include <allegro.h>
MovingPixelsState::MovingPixelsState(Editor* editor, Message* msg, Image* imge, int x, int y, int opacity, HandleType handle)
MovingPixelsState::MovingPixelsState(Editor* editor, Message* msg, PixelsMovement* pixelsMovement, HandleType handle)
{
EditorCustomizationDelegate* customization = editor->getCustomizationDelegate();
m_pixelsMovement = pixelsMovement;
// Copy the mask to the extra cel image
Document* document = editor->getDocument();
Sprite* sprite = editor->getSprite();
{
UniquePtr<Image> tmpImage(NewImageFromMask(document));
x = document->getMask()->x;
y = document->getMask()->y;
m_pixelsMovement = new PixelsMovement(document, sprite, tmpImage, x, y, opacity);
if (handle != NoHandle) {
int u, v;
editor->screenToEditor(msg->mouse.x, msg->mouse.y, &u, &v);
m_pixelsMovement->catchImage(u, v, handle);
editor->captureMouse();
}
// If the Ctrl key is pressed start dragging a copy of the selection
if (customization && customization->isCopySelectionKeyPressed())
m_pixelsMovement->copyMask();
else
m_pixelsMovement->cutMask();
editor->screenToEditor(msg->mouse.x, msg->mouse.y, &x, &y);
m_pixelsMovement->catchImage(x, y, handle);
// Setup mask color
setTransparentColor(app_get_statusbar()->getTransparentColor());
app_get_statusbar()->addListener(this);
app_get_statusbar()->showMovePixelsOptions();
editor->captureMouse();
}
MovingPixelsState::~MovingPixelsState()
@ -153,7 +140,7 @@ bool MovingPixelsState::onMouseDown(Editor* editor, Message* msg)
// Re-catch the image
int x, y;
editor->screenToEditor(msg->mouse.x, msg->mouse.y, &x, &y);
m_pixelsMovement->catchImageAgain(x, y, NoHandle);
m_pixelsMovement->catchImageAgain(x, y, MoveHandle);
editor->captureMouse();
return true;

View File

@ -31,8 +31,7 @@ class PixelsMovement;
class MovingPixelsState : public StandbyState, StatusBarListener
{
public:
MovingPixelsState(Editor* editor, Message* msg, Image* imge, int x, int y, int opacity,
HandleType handle);
MovingPixelsState(Editor* editor, Message* msg, PixelsMovement* pixelsMovement, HandleType handle);
virtual ~MovingPixelsState();
virtual bool onBeforeChangeState(Editor* editor) OVERRIDE;

View File

@ -36,10 +36,11 @@ static inline const la::Vector2d<double> point2Vector(const gfx::PointT<T>& pt)
return la::Vector2d<double>(pt.x, pt.y);
}
PixelsMovement::PixelsMovement(Document* document, Sprite* sprite, const Image* moveThis, int initialX, int initialY, int opacity)
PixelsMovement::PixelsMovement(Document* document, Sprite* sprite, const Image* moveThis, int initialX, int initialY, int opacity,
const char* operationName)
: m_documentReader(document)
, m_sprite(sprite)
, m_undoTransaction(document, "Pixels Movement")
, m_undoTransaction(document, operationName)
, m_firstDrop(true)
, m_isDragging(false)
, m_adjustPivot(false)
@ -91,6 +92,8 @@ void PixelsMovement::copyMask()
void PixelsMovement::catchImage(int x, int y, HandleType handle)
{
ASSERT(handle != NoHandle);
m_catchX = x;
m_catchY = y;
m_isDragging = true;
@ -119,6 +122,32 @@ void PixelsMovement::catchImageAgain(int x, int y, HandleType handle)
update_screen_for_document(m_documentReader);
}
void PixelsMovement::maskImage(const Image* image, int x, int y)
{
mask_replace(m_currentMask, x, y, image->w, image->h);
m_currentMask->freeze();
image_clear(m_currentMask->bitmap, 0);
for (int v=0; v<image->h; ++v) {
for (int u=0; u<image->w; ++u) {
int bit = (image->getpixel(u, v) != image->mask_color ? 1: 0);
m_currentMask->bitmap->putpixel(u, v, bit);
}
}
m_currentMask->unfreeze();
mask_copy(m_initialMask, m_currentMask);
DocumentWriter documentWriter(m_documentReader);
m_undoTransaction.copyToCurrentMask(m_currentMask);
documentWriter->setMask(m_currentMask);
documentWriter->generateMaskBoundaries(m_currentMask);
update_screen_for_document(m_documentReader);
}
gfx::Rect PixelsMovement::moveImage(int x, int y)
{
DocumentWriter documentWriter(m_documentReader);
@ -141,7 +170,7 @@ gfx::Rect PixelsMovement::moveImage(int x, int y)
switch (m_handle) {
case NoHandle:
case MoveHandle:
x1 += dx;
y1 += dy;
x2 += dx;

View File

@ -37,7 +37,8 @@ class PixelsMovement
public:
// The "moveThis" image specifies the chunk of pixels to be moved.
// The "x" and "y" parameters specify the initial position of the image.
PixelsMovement(Document* document, Sprite* sprite, const Image* moveThis, int x, int y, int opacity);
PixelsMovement(Document* document, Sprite* sprite, const Image* moveThis, int x, int y, int opacity,
const char* operationName);
~PixelsMovement();
void cutMask();
@ -45,6 +46,10 @@ public:
void catchImage(int x, int y, HandleType handle);
void catchImageAgain(int x, int y, HandleType handle);
// Creates a mask for the given image. Useful when the user paste a
// image from the clipboard.
void maskImage(const Image* image, int x, int y);
// Moves the image to the new position (relative to the start
// position given in the ctor). Returns the rectangle that should be
// redrawn.

View File

@ -36,6 +36,7 @@
#include "tools/ink.h"
#include "tools/tool.h"
#include "ui_context.h"
#include "util/misc.h"
#include "widgets/color_bar.h"
#include "widgets/editor/drawing_state.h"
#include "widgets/editor/editor.h"
@ -43,6 +44,7 @@
#include "widgets/editor/handle_type.h"
#include "widgets/editor/moving_cel_state.h"
#include "widgets/editor/moving_pixels_state.h"
#include "widgets/editor/pixels_movement.h"
#include "widgets/editor/scrolling_state.h"
#include "widgets/editor/tool_loop_impl.h"
#include "widgets/editor/transform_handles.h"
@ -176,7 +178,7 @@ bool StandbyState::onMouseDown(Editor* editor, Message* msg)
}
// Change to MovingPixelsState
editor->setState(EditorStatePtr(new MovingPixelsState(editor, msg, image, x, y, opacity, handle)));
transformSelection(editor, msg, handle);
}
return true;
}
@ -195,7 +197,7 @@ bool StandbyState::onMouseDown(Editor* editor, Message* msg)
}
// Change to MovingPixelsState
editor->setState(EditorStatePtr(new MovingPixelsState(editor, msg, image, x, y, opacity, NoHandle)));
transformSelection(editor, msg, MoveHandle);
}
return true;
}
@ -467,6 +469,27 @@ gfx::Transformation StandbyState::getTransformation(Editor* editor)
return editor->getDocument()->getTransformation();
}
void StandbyState::transformSelection(Editor* editor, Message* msg, HandleType handle)
{
EditorCustomizationDelegate* customization = editor->getCustomizationDelegate();
Document* document = editor->getDocument();
UniquePtr<Image> tmpImage(NewImageFromMask(document));
int x = document->getMask()->x;
int y = document->getMask()->y;
int opacity = 255;
Sprite* sprite = editor->getSprite();
PixelsMovement* pixelsMovement = new PixelsMovement(document, sprite, tmpImage, x, y, opacity,
"Transformation");
// If the Ctrl key is pressed start dragging a copy of the selection
if (customization && customization->isCopySelectionKeyPressed())
pixelsMovement->copyMask();
else
pixelsMovement->cutMask();
editor->setState(EditorStatePtr(new MovingPixelsState(editor, msg, pixelsMovement, handle)));
}
//////////////////////////////////////////////////////////////////////
// Decorator

View File

@ -23,6 +23,7 @@
#include "gfx/transformation.h"
#include "widgets/editor/editor_decorator.h"
#include "widgets/editor/editor_state.h"
#include "widgets/editor/handle_type.h"
class TransformHandles;
@ -68,6 +69,8 @@ protected:
};
private:
void transformSelection(Editor* editor, Message* msg, HandleType handle);
Decorator* m_decorator;
};