/*
* Copyright (c) 2002-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
#include
static void
insert_init(void *_Nonnull p)
{
struct map_insert_tool *ins = p;
ins->snap_mode = RG_SNAP_NONE;
ins->replace_mode = 0;
ins->angle = 0;
AG_ObjectInitStatic(&ins->mTmp, &mapClass);
ins->mvTmp = NULL;
MAP_ToolPushStatus(ins,
_("Select position on map ($(L)=Insert, $(M)=Rotate)"));
}
static void
insert_destroy(void *_Nonnull p)
{
struct map_insert_tool *ins = p;
AG_ObjectDestroy(&ins->mTmp);
}
#if 0
static void
SnapTile(struct map_insert_tool *_Nonnull ins, MAP_Item *_Nonnull r,
RG_Tile *_Nonnull tile)
{
MAP_View *mv = TOOL(ins)->mv;
switch (ins->snap_mode) {
case RG_SNAP_NONE:
r->r_gfx.xcenter += mv->cxoffs*MAPTILESZ/AGMTILESZ(mv);
r->r_gfx.ycenter += mv->cyoffs*MAPTILESZ/AGMTILESZ(mv);
break;
default:
break;
}
}
#endif
static void
GenerateTileMap(struct map_insert_tool *_Nonnull ins, RG_Tile *_Nonnull tile)
{
int sy, sx, dx, dy;
int sw = tile->su->w/MAPTILESZ;
int sh = tile->su->h/MAPTILESZ;
if (tile->su->w%MAPTILESZ > 0) sw++;
if (tile->su->h%MAPTILESZ > 0) sh++;
MAP_AllocNodes(&ins->mTmp, sw, sh);
ins->mTmp.origin.x = tile->xOrig/MAPTILESZ;
ins->mTmp.origin.y = tile->yOrig/MAPTILESZ;
for (sy = 0, dy = 0;
sy < tile->su->h;
sy += MAPTILESZ, dy++) {
for (sx = 0, dx = 0;
sx < tile->su->w;
sx += MAPTILESZ, dx++) {
MAP_Node *dn;
MAP_Item *r;
int dw, dh, nlayer;
if (dx >= (int)ins->mTmp.mapw ||
dy >= (int)ins->mTmp.maph)
continue;
dn = &ins->mTmp.map[dy][dx];
dw = tile->su->w - sx;
dh = tile->su->h - sy;
r = Malloc(sizeof(MAP_Item));
MAP_ItemInit(r, MAP_ITEM_TILE);
MAP_ItemSetTile(r, &ins->mTmp, tile->ts, tile->main_id);
r->r_gfx.rs.x = dx*MAPTILESZ;
r->r_gfx.rs.y = dy*MAPTILESZ;
r->r_gfx.rs.w = (dw >= MAPTILESZ) ? MAPTILESZ : dw;
r->r_gfx.rs.h = (dh >= MAPTILESZ) ? MAPTILESZ : dh;
r->flags |= RG_TILE_ATTR2(tile,dx,dy);
nlayer = RG_TILE_LAYER2(tile,dx,dy);
if (nlayer < 0) {
nlayer = 0;
} else {
if (nlayer >= (int)ins->mTmp.nlayers)
MAP_PushLayer(&ins->mTmp, "");
}
r->layer = nlayer;
/* XXX also need to rotate the whole map */
// RG_TransformRotate(r, ins->angle);
TAILQ_INSERT_TAIL(&dn->nrefs, r, nrefs);
}
}
}
static void
insert_pane(void *_Nonnull p, void *_Nonnull con)
{
struct map_insert_tool *ins = p;
AG_TlistItem *it;
MAP_View *mvMain = TOOL(ins)->mv;
MAP_View *mv;
RG_Tile *tile;
AG_Notebook *nb;
AG_NotebookTab *ntab;
if ((it = AG_TlistSelectedItem(mvMain->lib_tl)) == NULL ||
strcmp(it->cat, "tile") != 0) {
return;
}
tile = it->p1;
nb = AG_NotebookNew(con, AG_NOTEBOOK_VFILL|AG_NOTEBOOK_HFILL);
ntab = AG_NotebookAdd(nb, _("Tiles"), AG_BOX_VERT);
mv = ins->mvTmp = MAP_ViewNew(ntab, &ins->mTmp,
MAP_VIEW_EDIT|MAP_VIEW_GRID, NULL, NULL);
MAP_ViewSizeHint(mv, 7, 7);
MAP_ViewSelectTool(mv,
MAP_ViewRegTool(mv, &mapNodeselOps, &ins->mTmp),
&ins->mTmp);
GenerateTileMap(ins, tile);
ntab = AG_NotebookAdd(nb, _("Settings"), AG_BOX_VERT);
{
AG_Numerical *num;
AG_LabelNewS(ntab, 0, _("Snap to: "));
AG_RadioNewUint(ntab, AG_RADIO_HFILL,
rgTileSnapModes, &ins->snap_mode);
AG_CheckboxNewInt(ntab, 0, _("Replace mode"),
&ins->replace_mode);
num = AG_NumericalNewIntR(ntab, 0, "deg", _("Rotation: "),
&ins->angle, 0, 360);
AG_SetInt(num, "inc", 90);
}
}
static int
insert_effect(void *_Nonnull p, MAP_Node *_Nonnull node)
{
struct map_insert_tool *ins = p;
MAP_View *mv = TOOL(ins)->mv;
MAP *mSrc = &ins->mTmp;
MAP *mDst = mv->map;
int sx, sy, sx0, sy0, sx1, sy1;
int dx, dy, dx0, dy0;
AG_TlistItem *it;
if (mv->lib_tl == NULL ||
(it = AG_TlistSelectedItem(mv->lib_tl)) == 0 ||
strcmp(it->cat, "tile") != 0) {
return (1);
}
/* tile = it->p1; */
if (ins->mvTmp->esel.set) {
sx0 = ins->mvTmp->esel.x;
sy0 = ins->mvTmp->esel.y;
sx1 = sx0 + ins->mvTmp->esel.w - 1;
sy1 = sy0 + ins->mvTmp->esel.h - 1;
dx0 = mv->cx;
dy0 = mv->cy;
} else {
sx0 = 0;
sy0 = 0;
sx1 = mSrc->mapw-1;
sy1 = mSrc->maph-1;
dx0 = mv->cx - mSrc->origin.x;
dy0 = mv->cy - mSrc->origin.y;
}
MAP_ModBegin(mDst);
for (sy = sy0, dy = dy0;
sy <= sy1 && dy < (int)mDst->maph;
sy++, dy++) {
for (sx = sx0, dx = dx0;
sx <= sx1 && dx < (int)mDst->mapw;
sx++, dx++) {
MAP_Node *sn, *dn;
MAP_Item *r1, *r2;
if (dx < 0 || dx >= (int)mDst->mapw ||
dy < 0 || dy >= (int)mDst->maph) {
continue;
}
sn = &mSrc->map[sy][sx];
dn = &mDst->map[dy][dx];
MAP_ModNodeChg(mDst, dx, dy);
if (ins->replace_mode) {
MAP_NodeRemoveAll(mDst, dn, mDst->cur_layer);
}
TAILQ_FOREACH(r1, &sn->nrefs, nrefs) {
r2 = MAP_NodeCopyItem(r1, mDst, dn, -1);
r2->layer += mDst->cur_layer;
while (r2->layer >= mDst->nlayers) {
if (MAP_PushLayer(mDst, "") == 0)
MAP_ModLayerAdd(mDst,
mDst->nlayers - 1);
}
if (ins->snap_mode == RG_SNAP_NONE) {
r2->r_gfx.xcenter +=
mv->cxoffs*MAPTILESZ/AGMTILESZ(mv);
r2->r_gfx.ycenter +=
mv->cyoffs*MAPTILESZ/AGMTILESZ(mv);
}
}
}
}
MAP_ModEnd(mDst);
return (1);
}
static int
insert_cursor(void *_Nonnull p, AG_Rect *_Nonnull rd)
{
struct map_insert_tool *ins = p;
MAP_View *mv = TOOL(ins)->mv;
MAP *mSrc = &ins->mTmp;
AG_TlistItem *it;
RG_Tile *tile;
AG_Rect r;
AG_Color c;
int sx0, sy0, sx1, sy1;
int dx0, dy0;
int dx, dy, sx, sy;
if (mv->lib_tl == NULL ||
(it = AG_TlistSelectedItem(mv->lib_tl)) == NULL ||
strcmp(it->cat, "tile") != 0 ||
(tile = it->p1) == NULL || tile->su == NULL) {
return (-1);
}
if (ins->snap_mode == RG_SNAP_NONE) {
r.x = rd->x + 1;
r.y = rd->y + 1;
r.w = AGMTILESZ(mv) - 1;
r.h = AGMTILESZ(mv) - 1;
AG_ColorRGB_8(&c, 200,200,200);
AG_DrawRectOutline(mv, &r, &c);
}
if (ins->mvTmp->esel.set) {
sx0 = ins->mvTmp->esel.x;
sy0 = ins->mvTmp->esel.y;
sx1 = sx0 + ins->mvTmp->esel.w - 1;
sy1 = sy0 + ins->mvTmp->esel.h - 1;
dx0 = WIDGET(mv)->rView.x1 + rd->x;
dy0 = WIDGET(mv)->rView.y1 + rd->y;
} else {
sx0 = 0;
sy0 = 0;
sx1 = mSrc->mapw-1;
sy1 = mSrc->maph-1;
dx0 = WIDGET(mv)->rView.x1+rd->x - mSrc->origin.x*AGMTILESZ(mv);
dy0 = WIDGET(mv)->rView.y1+rd->y - mSrc->origin.y*AGMTILESZ(mv);
}
if (ins->snap_mode == RG_SNAP_NONE) {
dx0 += mv->cxoffs*MAPTILESZ/AGMTILESZ(mv);
dy0 += mv->cyoffs*MAPTILESZ/AGMTILESZ(mv);
}
for (sy = sy0, dy = dy0; sy <= sy1; sy++, dy += AGMTILESZ(mv)) {
for (sx = sx0, dx = dx0; sx <= sx1; sx++, dx += AGMTILESZ(mv)) {
MAP_Node *sn = &mSrc->map[sy][sx];
MAP_Item *r;
TAILQ_FOREACH(r, &sn->nrefs, nrefs)
MAP_ItemDraw(mv->map, r, dx, dy, mv->cam);
}
}
return (0);
}
static int
insert_mousebuttondown(void *_Nonnull p, int x, int y, int btn)
{
struct map_insert_tool *ins = p;
if (btn == AG_MOUSE_MIDDLE) {
ins->angle = (ins->angle + 90) % 360;
return (1);
}
return (0);
}
static int
insert_mousemotion(void *_Nonnull p, int x, int y, int xrel, int yrel, int btn)
{
struct map_insert_tool *ins = p;
MAP_View *mv = TOOL(ins)->mv;
int nx = x/AGMTILESZ(mv);
int ny = y/AGMTILESZ(mv);
AG_TlistItem *it;
if (nx == mv->mouse.x && ny == mv->mouse.y)
return (0);
if ((it = AG_TlistSelectedItem(mv->lib_tl)) == NULL ||
mv->cx == -1 || mv->cy == -1) {
return (1);
}
if (strcmp(it->cat, "tile") == 0) {
MAP_ToolSetStatus(ins,
_("Insert %s tile at [%d,%d] ($(L)=Confirm, $(M)=Rotate)."),
it->text, mv->cx, mv->cy);
}
return (0);
}
const MAP_ToolOps mapInsertOps = {
"Insert", N_("Insert node element"),
&mapIconStamp,
sizeof(struct map_insert_tool),
TOOL_HIDDEN,
insert_init,
insert_destroy,
insert_pane,
NULL, /* edit */
insert_cursor,
insert_effect,
insert_mousemotion,
insert_mousebuttondown,
NULL, /* mousebuttonup */
NULL, /* keydown */
NULL /* keyup */
};