/*
* 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
const AG_Version merge_ver = {
"agar merge tool",
6, 0
};
/* XXX */
static TAILQ_HEAD_(ag_object) brushes = TAILQ_HEAD_INITIALIZER(brushes);
static AG_Tlist *brushes_tl;
enum {
NODE, FILL,
EDNW, EDNO, EDNE,
EDWE, EDEA,
EDSW, EDSO, EDSE
};
#if 0
static const int
MergeTable[9][9] = {
/* nw n ne w fill e sw s se */
{ EDNW, EDNO, EDNO, EDWE, NODE, FILL, FILL, FILL, FILL }, /* nw */
{ EDNO, EDNO, EDNO, FILL, NODE, FILL, FILL, FILL, FILL }, /* n */
{ EDNO, EDNO, NODE, 0 , NODE, EDEA, FILL, FILL, EDEA }, /* ne */
{ EDWE, FILL, FILL, EDWE, NODE, FILL, EDWE, FILL, FILL }, /* w */
{ FILL, FILL, FILL, FILL, NODE, FILL, FILL, FILL, FILL }, /* fill */
{ FILL, FILL, EDEA, FILL, NODE, EDEA, FILL, FILL, EDEA }, /* e */
{ EDWE, 0, EDEA, EDWE, NODE, 0, EDSW, EDSO, EDSO }, /* sw */
{ FILL, FILL, FILL, FILL, NODE, FILL, EDSO, EDSO, EDSO }, /* s */
{ EDWE, 0, EDEA, EDNO, NODE, EDNO, EDSO, EDSO, EDSE } /* se */
};
#endif
static void
FreeBrushes(void)
{
AG_Object *ob, *nob;
for (ob = TAILQ_FIRST(&brushes);
ob != TAILQ_END(&brushes);
ob = nob) {
nob = TAILQ_NEXT(ob, cobjs);
AG_ObjectDestroy(ob);
}
TAILQ_INIT(&brushes);
}
static void
Destroy(MAP_Tool *t)
{
FreeBrushes();
}
static void
CreateBrush(AG_Event *_Nonnull event)
{
char brush_name[AG_OBJECT_NAME_MAX];
char m_name[AG_OBJECT_NAME_MAX];
AG_Textbox *name_tbox = AG_PTR(1);
MAP *m;
AG_TextboxCopyString(name_tbox, brush_name,
sizeof(brush_name) - sizeof("brush()"));
if (brush_name[0] == '\0') {
AG_TextMsg(AG_MSG_ERROR, _("No brush name was given."));
return;
}
Snprintf(m_name, sizeof(m_name), "brush(%s)", brush_name);
if (AG_TlistFindText(brushes_tl, m_name) != NULL) {
AG_TextMsg(AG_MSG_ERROR, _("A `%s' brush exists."), m_name);
return;
}
m = MAP_New(NULL, m_name);
if (AG_ObjectLoad(m) == -1) {
extern int mapDefaultBrushWidth, mapDefaultBrushHeight;
if (MAP_AllocNodes(m, mapDefaultBrushWidth,
mapDefaultBrushHeight) == -1) {
AG_TextMsg(AG_MSG_ERROR, "MAP_AllocNodes: %s",
AG_GetError());
goto fail;
}
}
TAILQ_INSERT_HEAD(&brushes, OBJECT(m), cobjs);
AG_TlistDeselectAll(brushes_tl);
AG_TlistSelect(brushes_tl, AG_TlistAddPtrHead(brushes_tl, NULL,
m_name, m));
AG_TextboxPrintf(name_tbox, NULL);
return;
fail:
AG_ObjectDestroy(m);
}
static void
EditBrush(AG_Event *event)
{
AG_TlistItem *it;
AG_Window *pwin = AG_PTR(1);
TAILQ_FOREACH(it, &brushes_tl->items, items) {
MAP *brush = it->p1;
AG_Window *win;
AG_Toolbar *tbar;
if (!it->selected)
continue;
if ((win = AG_WindowNewNamed(0, "mapedit-tool-merge-%s",
OBJECT(brush)->name)) == NULL)
continue;
tbar = AG_ToolbarNew(win, AG_TOOLBAR_HORIZ, 1, 0);
MAP_ViewNew(win, brush, MAP_VIEW_EDIT|MAP_VIEW_GRID|
MAPVIEW_PROPS, tbar, NULL);
AG_WindowAttach(pwin, win);
AG_WindowShow(win);
}
}
static void
RemoveBrush(AG_Event *event)
{
AG_TlistItem *it, *nit;
for (it = TAILQ_FIRST(&brushes_tl->items);
it != TAILQ_END(&brushes_tl->items);
it = nit) {
nit = TAILQ_NEXT(it, items);
if (it->selected) {
char wname[AG_OBJECT_NAME_MAX];
AG_Object *brush = it->p1;
AG_Window *win;
Snprintf(wname, sizeof(wname),
"win-mapedit-tool-merge-%s",
OBJECT(brush)->name);
if ((win = AG_FindWindow(wname)) != NULL) {
AG_WindowHide(win);
AG_ObjectDetach(win);
}
TAILQ_REMOVE(&brushes, brush, cobjs);
AG_TlistDel(brushes_tl, it);
AG_ObjectDestroy(brush);
}
}
}
static void
Interpolate(MAP *_Nonnull sm, MAP_Node *_Nonnull sn, MAP_Item *_Nonnull sr,
MAP *_Nonnull dm, MAP_Node *_Nonnull dn, MAP_Item *_Nonnull dr)
{
/* TODO */
}
static int
Effect(MAP_Tool *_Nonnull t, MAP_Node *_Nonnull n)
{
MAP_View *mv = t->mv;
MAP *m = mv->map;
AG_TlistItem *it;
/* Avoid circular references. XXX ugly */
if (strncmp(OBJECT(m)->name, "brush(", 6) == 0)
return (1);
TAILQ_FOREACH(it, &brushes_tl->items, items) {
MAP *sm;
int sx, sy, dx, dy;
if (!it->selected)
continue;
sm = it->p1;
for (sy = 0, dy = mv->cy;
sy < sm->maph && dy < m->maph;
sy++, dy++) {
for (sx = 0, dx = mv->cx;
sx < sm->mapw && dx < m->mapw;
sx++, dx++) {
MAP_Node *sn = &sm->map[sy][sx];
MAP_Node *dn = &m->map[dy][dx];
MAP_Item *sr, *dr;
TAILQ_FOREACH(sr, &sn->nrefs, nrefs) {
TAILQ_FOREACH(dr, &dn->nrefs, nrefs) {
Interpolate(sm,sn,sr, m,dn,dr);
}
}
}
}
}
return (1);
}
#if 0
static int
Load(MAP_Tool *_Nonnull t, AG_DataSource *_Nonnull buf)
{
Uint32 i, nbrushes;
if (AG_ReadVersion(buf, &merge_ver, NULL) != 0)
return (-1);
FreeBrushes();
AG_TlistClear(brushes_tl);
nbrushes = AG_ReadUint32(buf);
for (i = 0; i < nbrushes; i++) {
char m_name[AG_OBJECT_NAME_MAX];
MAP *nbrush;
AG_CopyString(m_name, buf, sizeof(m_name));
nbrush = Malloc(sizeof(MAP));
MAP_Init(nbrush, m_name);
map_load(nbrush, buf);
TAILQ_INSERT_HEAD(&brushes, OBJECT(nbrush), cobjs);
AG_TlistAddPtrHead(brushes_tl, NULL, m_name, nbrush);
}
return (0);
}
static int
Save(MAP_Tool *_Nonnull t, AG_DataSource *_Nonnull buf)
{
AG_Object *ob;
Uint32 nbrushes = 0;
off_t count_offs;
AG_WriteVersion(buf, &merge_ver);
count_offs = AG_Tell(buf); /* Skip count */
AG_WriteUint32(buf, 0);
TAILQ_FOREACH(ob, &brushes, cobjs) {
struct brush *brush = (struct brush *)ob;
AG_WriteString(buf, ob->name);
map_save(brush, buf);
nbrushes++;
}
AG_WriteUint32At(buf, nbrushes, count_offs); /* Write count */
return (0);
}
#endif
static int
Cursor(MAP_Tool *_Nonnull t, AG_Rect *_Nonnull rd)
{
MAP_View *mv = t->mv;
MAP_Item *r;
MAP *sm;
int sx, sy, dx, dy;
AG_TlistItem *it;
int rv = -1;
/* XXX ugly work around circular ref */
if (strncmp(OBJECT(mv->map)->name, "brush(", 6) == 0)
return (-1);
TAILQ_FOREACH(it, &brushes_tl->items, items) {
if (!it->selected) {
continue;
}
sm = it->p1;
for (sy = 0, dy = rd->y;
sy < sm->maph;
sy++, dy += AGMTILESZ(mv)) {
for (sx = 0, dx = rd->x;
sx < sm->mapw;
sx++, dx += AGMTILESZ(mv)) {
MAP_Node *sn = &sm->map[sy][sx];
TAILQ_FOREACH(r, &sn->nrefs, nrefs) {
MAP_ItemDraw(mv->map, r,
WIDGET(mv)->rView.x1 + dx,
WIDGET(mv)->rView.y1 + dy,
mv->cam);
rv = 0;
}
if (mv->flags & MAPVIEW_PROPS) {
MAP_ViewDraw_props(mv, sn, dx, dy,
-1, -1);
}
}
}
}
return (rv);
}
static void
Init(MAP_Tool *_Nonnull t)
{
AG_Window *win;
AG_HBox *hb;
AG_Button *bu;
AG_Textbox *tb;
if ((win = MAP_ToolWindow(t, "mapedit-tool-merge")) == NULL)
return;
hb = AG_HBoxNew(win, AG_HBOX_HFILL);
{
tb = AG_TextboxNewS(hb, AG_TEXTBOX_FOCUS, _("Name: "));
AG_SetEvent(tb, "textbox-return", CreateBrush, "%p", tb);
bu = AG_ButtonNew(hb, 0, _("Create"));
AG_ButtonSetPadding(bu, 6); /* Align */
AG_ButtonSetFocusable(bu, 0);
AG_SetEvent(bu, "button-pushed", CreateBrush, "%p", tb);
}
hb = AG_HBoxNew(win, AG_HBOX_HOMOGENOUS|AG_HBOX_HFILL);
{
#if 0
bu = AG_ButtonNew(hb, 0, _("Load set"));
AG_SetEvent(bu, "button-pushed", merge_load_brush_set, NULL);
bu = AG_ButtonNew(hb, 0, _("Save set"));
AG_SetEvent(bu, "button-pushed", merge_save_brush_set, NULL);
#endif
bu = AG_ButtonNew(hb, 0, _("Edit"));
AG_SetEvent(bu, "button-pushed", EditBrush, "%p", win);
bu = AG_ButtonNew(hb, 0, _("Remove"));
AG_SetEvent(bu, "button-pushed", RemoveBrush, NULL);
}
/* XXX */
brushes_tl = AG_TlistNew(win, AG_TLIST_MULTI|AG_TLIST_EXPAND);
}
const MAP_Tool mapMergeOps = {
"Merge",
N_("Merge Pattern"),
&mapIconMerge,
sizeof(MAP_Tool),
0,
Init,
Destroy,
NULL, /* pane */
NULL, /* edit */
Cursor,
Effect,
NULL, /* mousemotion */
NULL, /* mousebuttondown */
NULL, /* mousebuttonup */
NULL, /* keydown */
NULL, /* keyup */
NULL /* pane */
};