/* * Copyright (c) 2003-2007 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include /* Begin a rectangular selection of nodes. */ void MAP_NodeselBegin(MAP_View *mv) { mv->esel.set = 0; mv->msel.set = 1; mv->msel.x = mv->cx; mv->msel.y = mv->cy; mv->msel.xoffs = 1; mv->msel.yoffs = 1; } /* Apply the temporary rectangular selection. */ void MAP_NodeselEnd(MAP_View *mv) { int excess; mv->esel.x = mv->msel.x; mv->esel.y = mv->msel.y; mv->esel.w = mv->msel.xoffs; mv->esel.h = mv->msel.yoffs; if (mv->msel.xoffs < 0) { mv->esel.x += mv->msel.xoffs; mv->esel.w = -mv->msel.xoffs; } if (mv->msel.yoffs < 0) { mv->esel.y += mv->msel.yoffs; mv->esel.h = -mv->msel.yoffs; } if ((excess = (mv->esel.x + mv->esel.w) - mv->map->mapw) > 0) { if (excess < mv->esel.w) mv->esel.w -= excess; } if ((excess = (mv->esel.y + mv->esel.h) - mv->map->maph) > 0) { if (excess < mv->esel.h) mv->esel.h -= excess; } if (mv->esel.x < 0) { mv->esel.w += mv->esel.x; mv->esel.x = 0; } if (mv->esel.y < 0) { mv->esel.h += mv->esel.y; mv->esel.y = 0; } mv->esel.set = 1; MAP_ViewStatus(mv, _("Selected area %d,%d (%dx%d)"), mv->esel.x, mv->esel.y, mv->esel.w, mv->esel.h); } /* Begin displacement of the node selection. */ void MAP_NodeselBeginMove(MAP_View *mv) { MAP *mSrc = mv->map; MAP *mTmp = &mv->esel.map; int sx, sy, x, y; AG_ObjectInitStatic(mTmp, &mapClass); if (MAP_AllocNodes(mTmp, mv->esel.w, mv->esel.h) == -1) { goto fail; } if (MAP_PushLayer(mSrc, _("(Floating selection)")) == -1) { goto fail; } MAP_ModBegin(mSrc); for (y = 0, sy = mv->esel.y; y < mv->esel.h; y++, sy++) { for (x = 0, sx = mv->esel.x; x < mv->esel.w; x++, sx++) { MAP_Node *nSrc = &mSrc->map[sy][sx]; MAP_Node *nTmp = &mTmp->map[y][x]; MAP_ModNodeChg(mSrc, sx, sy); MAP_NodeCopy(mSrc, nSrc, mSrc->cur_layer, mTmp, nTmp, 0); MAP_NodeSwapLayers(mSrc, nSrc, mSrc->cur_layer, mSrc->nlayers-1); } } mv->esel.moving = 1; return; fail: AG_ObjectDestroy(mTmp); } void MAP_NodeselUpdateMove(MAP_View *mv, int xRel, int yRel) { MAP *mDst = mv->map; MAP *mTmp = &mv->esel.map; int x, y, dx, dy; if (mv->esel.x+xRel < 0 || mv->esel.x+mv->esel.w+xRel > (int)mDst->mapw) xRel = 0; if (mv->esel.y+yRel < 0 || mv->esel.y+mv->esel.h+yRel > (int)mDst->maph) yRel = 0; for (y = 0, dy = mv->esel.y; y < mv->esel.h; y++, dy++) { for (x = 0, dx = mv->esel.x; x < mv->esel.w; x++) { MAP_NodeRemoveAll(mDst, &mDst->map[dy][dx], mDst->nlayers-1); } } for (y = 0, dy = mv->esel.y+yRel; y < mv->esel.h; y++, dy++) { for (x = 0, dx = mv->esel.x+xRel; x < mv->esel.w; x++, dx++) { MAP_Node *nTmp = &mTmp->map[y][x]; MAP_Node *nDst = &mDst->map[dy][dx]; MAP_ModNodeChg(mDst, dx, dy); MAP_NodeCopy(mTmp, nTmp, 0, mDst, nDst, mDst->nlayers-1); } } mv->esel.x += xRel; mv->esel.y += yRel; } void MAP_NodeselEndMove(MAP_View *mv) { MAP *mDst = mv->map; MAP *mTmp = &mv->esel.map; int dx, dy, x, y; for (y = 0, dy = mv->esel.y; y < mv->esel.h; y++, dy++) { for (x = 0, dx = mv->esel.x; x < mv->esel.w; x++, dx++) { MAP_Node *node = &mDst->map[dy][dx]; MAP_Item *nref; TAILQ_FOREACH(nref, &node->nrefs, nrefs) { if (nref->layer == mDst->nlayers-1) nref->layer = mDst->cur_layer; } } } MAP_PopLayer(mDst); MAP_ModEnd(mDst); AG_ObjectReset(mTmp); AG_ObjectDestroy(mTmp); mv->esel.moving = 0; } /* Copy the selection to the copy buffer. */ int MAP_NodeselCopy(MAP_Tool *t, AG_KeySym key, int state, void *arg) { MAP_View *mv = t->mv; MAP *copybuf = &mapEditor.copybuf; MAP *m = mv->map; int sx, sy, dx, dy; if (!mv->esel.set) { AG_TextMsg(AG_MSG_ERROR, _("There is no selection to copy.")); return (0); } if (copybuf->map != NULL) { MAP_FreeNodes(copybuf); } if (MAP_AllocNodes(copybuf, mv->esel.w, mv->esel.h) == -1) { AG_TextMsgFromError(); return (0); } for (sy = mv->esel.y, dy = 0; sy < mv->esel.y + mv->esel.h; sy++, dy++) { for (sx = mv->esel.x, dx = 0; sx < mv->esel.x + mv->esel.w; sx++, dx++) { MAP_NodeCopy(m, &m->map[sy][sx], m->cur_layer, copybuf, ©buf->map[dy][dx], 0); } } return (1); } int MAP_NodeselPaste(MAP_Tool *t, AG_KeySym key, int state, void *arg) { MAP_View *mv = t->mv; MAP *copybuf = &mapEditor.copybuf; MAP *m = mv->map; int sx, sy, dx, dy; if (copybuf->map == NULL) { AG_TextMsg(AG_MSG_ERROR, _("The copy buffer is empty!")); return (0); } if (mv->esel.set) { dx = mv->esel.x; dy = mv->esel.y; } else { if (mv->cx != -1 && mv->cy != -1) { dx = mv->cx; dy = mv->cy; } else { dx = 0; dy = 0; } } Debug(m, "Pasting [%dx%d] map at [%d,%d]\n", copybuf->mapw, copybuf->maph, dx, dy); for (sy = 0, dy = mv->esel.y; sy < (int)copybuf->maph && dy < (int)m->maph; sy++, dy++) { for (sx = 0, dx = mv->esel.x; sx < (int)copybuf->mapw && dx < (int)m->mapw; sx++, dx++) { MAP_NodeCopy(copybuf, ©buf->map[sy][sx], 0, m, &m->map[dy][dx], m->cur_layer); } } return (1); } int MAP_NodeselKill(MAP_Tool *t, AG_KeySym key, int state, void *arg) { MAP_View *mv = t->mv; MAP *m = mv->map; int x, y; if (!mv->esel.set) return (0); Debug(m, "Deleting region [%d,%d]+[%d,%d]\n", mv->esel.x, mv->esel.y, mv->esel.w, mv->esel.h); for (y = mv->esel.y; y < mv->esel.y + mv->esel.h; y++) { for (x = mv->esel.x; x < mv->esel.x + mv->esel.w; x++) { MAP_NodeRemoveAll(m, &m->map[y][x], m->cur_layer); } } return (1); } int MAP_NodeselCut(MAP_Tool *t, AG_KeySym key, int state, void *arg) { MAP_View *mv = t->mv; if (!mv->esel.set) { AG_TextMsg(AG_MSG_ERROR, _("There is no selection to cut.")); return (0); } MAP_NodeselCopy(t, 0, 1, NULL); MAP_NodeselKill(t, 0, 1, NULL); return (1); } static void Init(void *p) { MAP_ToolBindKey(p, AG_KEYMOD_CTRL, AG_KEY_C, MAP_NodeselCopy, NULL); MAP_ToolBindKey(p, AG_KEYMOD_CTRL, AG_KEY_V, MAP_NodeselPaste, NULL); MAP_ToolBindKey(p, AG_KEYMOD_CTRL, AG_KEY_X, MAP_NodeselCut, NULL); MAP_ToolBindKey(p, AG_KEYMOD_CTRL, AG_KEY_K, MAP_NodeselKill, NULL); MAP_ToolBindKey(p, 0, AG_KEY_DELETE, MAP_NodeselKill, NULL); MAP_ToolPushStatus(p, _("Select a rectangle of nodes with $(L). Drag to displace node " "elements.")); } const MAP_ToolOps mapNodeselOps = { "Nodesel", N_("Select node(s)"), &mapIconSelectNode, sizeof(MAP_Tool), 0, Init, NULL, /* destroy */ NULL, /* pane */ NULL, /* edit */ NULL, /* cursor */ NULL, /* effect */ NULL, /* mousemotion */ NULL, /* mousebuttondown */ NULL, /* mousebuttonup */ NULL, /* keydown */ NULL /* keyup */ };