/* * Copyright (c) 2005-2023 Julien Nadeau Carriere * 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. */ /* * Graphical, feature-based tile element. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char *rgTileSnapModes[] = { N_("No snapping"), N_("Snap to grid"), NULL }; /* * Blend a pixmap with the tile; add the source alpha to the destination * alpha of each pixel. */ static void BlendOverlayAlpha(RG_Tile *_Nonnull t, AG_Surface *_Nonnull su, AG_Rect *_Nonnull rd) { Uint sx, sy, dx, dy; Uint8 *pSrc, *pDst; AG_Color Csrc, Cdst; int alpha; for (sy = 0, dy = rd->y; sy < su->h; sy++, dy++) { for (sx = 0, dx = rd->x; sx < su->w; sx++, dx++) { if (AG_SurfaceClipped(t->su, dx,dy)) continue; pSrc = (Uint8 *)su->pixels + sy*su->pitch + (sx << 2); if (*(Uint32 *)pSrc == su->colorkey) continue; pDst = (Uint8 *)t->su->pixels + dy*t->su->pitch + (dx << 2); if (*(Uint32 *)pDst != t->su->colorkey) { AG_GetColor32(&Cdst, *(Uint32 *)pDst, &t->su->format); AG_GetColor32(&Csrc, *(Uint32 *)pSrc, &su->format); alpha = (Cdst.a+Csrc.a) > AG_OPAQUE ? AG_OPAQUE : (Cdst.a+Csrc.a); *(Uint32 *)pDst = AG_MapPixel32_RGBA8( &t->su->format, (((Csrc.r - Cdst.r)*Csrc.a) >> 8) + Cdst.r, (((Csrc.g - Cdst.g)*Csrc.a) >> 8) + Cdst.g, (((Csrc.b - Cdst.b)*Csrc.a) >> 8) + Cdst.b, (Uint8)alpha); } else { *(Uint32 *)pDst = *(Uint32 *)pSrc; } } } } RG_Tile * RG_TileNew(RG_Tileset *ts, const char *pName, Uint16 w, Uint16 h, Uint flags) { char name[RG_TILE_NAME_MAX]; int no = 0; RG_Tile *t; tryname: Snprintf(name, sizeof(name), _("%s #%d"), (pName != NULL) ? pName : _("Tile"), no++); if (RG_TilesetFindTile(ts, name) != NULL) goto tryname; t = Malloc(sizeof(RG_Tile)); RG_TileInit(t, ts, name); t->flags = flags; RG_TileScale(ts, t, w, h); if ((ts->nTileTbl+1) >= RG_TILE_ID_MAX) { AG_FatalError("Out of tile mappings"); } ts->tileTbl = Realloc(ts->tileTbl, (ts->nTileTbl+1)*sizeof(RG_Tile *)); ts->tileTbl[ts->nTileTbl] = t; t->main_id = ts->nTileTbl++; TAILQ_INSERT_TAIL(&ts->tiles, t, tiles); return (t); } void RG_TileInit(RG_Tile *t, RG_Tileset *ts, const char *name) { Strlcpy(t->name, name, sizeof(t->name)); t->clname[0] = '\0'; t->main_id = 0; t->flags = 0; t->su = NULL; t->ts = ts; t->nRefs = 0; t->blend_fn = BlendOverlayAlpha; t->attrs = NULL; t->layers = NULL; t->nw = 0; t->nh = 0; TAILQ_INIT(&t->elements); SLIST_INIT(&t->vars); } void RG_TileScale(RG_Tileset *ts, RG_Tile *t, Uint16 w, Uint16 h) { Uint sFlags = 0; int wNew, hNew; int x, y; Uint *nAttrs; int *nLayers; /* Resize the attribute grids. */ wNew = w/RG_TILESZ + 1; hNew = h/RG_TILESZ + 1; nAttrs = Malloc(wNew*hNew*sizeof(Uint)); nLayers = Malloc(wNew*hNew*sizeof(int)); for (y = 0; y < hNew; y++) { for (x = 0; x < wNew; x++) { if (x >= t->nw || y >= t->nh) { nAttrs[y*wNew + x] = 0; nLayers[y*wNew + x] = 0; } else { nAttrs[y*wNew + x] = t->attrs[y*t->nw + x]; nLayers[y*wNew + x] = t->layers[y*t->nw + x]; } } } Free(t->attrs); Free(t->layers); t->attrs = nAttrs; t->layers = nLayers; t->nw = wNew; t->nh = hNew; if (t->flags & RG_TILE_SRCCOLORKEY) { sFlags |= AG_SURFACE_COLORKEY; } if ((t->su = RG_SurfaceStd(ts, w, h, sFlags)) == NULL) { AG_FatalError(NULL); } t->flags |= RG_TILE_DIRTY; } void RG_TileGenerate(RG_Tile *t) { RG_TileElement *tel; RG_Tileset *ts = t->ts; AG_Color c; t->su->alpha = ts->icon->alpha; /* TODO check for opaque fill features/pixmaps first */ AG_ColorNone(&c); AG_FillRect(t->su, NULL, &c); TAILQ_FOREACH(tel, &t->elements, elements) { if (!tel->visible) { continue; } switch (tel->type) { case RG_TILE_FEATURE: { RG_Feature *ft = tel->tel_feature.ft; if (ft->ops->apply != NULL) ft->ops->apply(ft, t, tel->tel_feature.x, tel->tel_feature.y); } break; case RG_TILE_PIXMAP: { RG_Pixmap *px = tel->tel_pixmap.px; AG_Rect rd; rd.x = tel->tel_pixmap.x; rd.y = tel->tel_pixmap.y; rd.w = px->su->w; rd.h = px->su->h; t->blend_fn(t, px->su, &rd); } break; #if 0 case RG_TILE_SKETCH: RG_SketchRender(t, tel); break; #endif } } if ((t->flags & RG_TILE_SRCALPHA) == 0 && (t->flags & RG_TILE_SRCCOLORKEY)) { AG_Surface *su = t->su; Uint i, size = su->w*su->h; Uint8 *p = su->pixels; for (i = 0; i < size; i++) { AG_GetColor32(&c, AG_SurfaceGet32_At(su,p), &su->format); AG_SurfacePut32_At(su, p, (c.a == 0) ? su->colorkey : AG_MapPixel32(&su->format, &c)); p += su->format.BytesPerPixel; } AG_SurfaceSetAlpha(t->su, 0, 0); AG_SurfaceSetColorKey(t->su, AG_SURFACE_COLORKEY, ts->icon->colorkey); } else if ((t->flags & (RG_TILE_SRCCOLORKEY|RG_TILE_SRCALPHA)) == 0) { AG_SurfaceSetAlpha(t->su, 0, 0); AG_SurfaceSetColorKey(t->su, 0, 0); } else { AG_SurfaceSetColorKey(t->su, AG_SURFACE_COLORKEY, ts->icon->colorkey); } } static __inline__ void GenerateElementName(RG_TileElement *_Nonnull tel, RG_Tile *_Nonnull t, const char *_Nonnull fname) { RG_TileElement *oel; Uint elno = 0; tryname: Snprintf(tel->name, sizeof(tel->name), "%s <#%u>", fname, elno); TAILQ_FOREACH(oel, &t->elements, elements) { if (strcmp(oel->name, tel->name) == 0) break; } if (oel != NULL) { elno++; goto tryname; } } RG_TileElement * RG_TileFindElement(RG_Tile *t, enum rg_tile_element_type type, const char *name) { RG_TileElement *tel; TAILQ_FOREACH(tel, &t->elements, elements) { if (tel->type == type && strcmp(tel->name, name) == 0) break; } return (tel); } RG_TileElement * RG_TileAddFeature(RG_Tile *t, const char *name, void *ft, int x, int y) { RG_TileElement *tel; tel = Malloc(sizeof(RG_TileElement)); if (name != NULL) { Strlcpy(tel->name, name, sizeof(tel->name)); } else { GenerateElementName(tel, t, RG_FEATURE(ft)->name); } tel->type = RG_TILE_FEATURE; tel->visible = 1; tel->tel_feature.ft = ft; tel->tel_feature.x = x; tel->tel_feature.y = y; TAILQ_INSERT_TAIL(&t->elements, tel, elements); t->flags |= RG_TILE_DIRTY; return (tel); } void RG_TileDelFeature(RG_Tile *t, void *ftp, int destroy) { RG_Feature *ft = ftp; RG_TileElement *tel; TAILQ_FOREACH(tel, &t->elements, elements) { if (tel->tel_feature.ft == ft) break; } if (tel != NULL) { TAILQ_REMOVE(&t->elements, tel, elements); Free(tel); if (--ft->nRefs == 0 && destroy) { AG_TextTmsg(AG_MSG_INFO, 2000, _("Destroying unreferenced feature: %s"), ft->name); TAILQ_REMOVE(&t->ts->features, ft, features); RG_FeatureDestroy(ft); Free(ft); } } } RG_TileElement * RG_TileAddPixmap(RG_Tile *t, const char *name, RG_Pixmap *px, int x, int y) { RG_TileElement *tel; tel = Malloc(sizeof(RG_TileElement)); if (name != NULL) { Strlcpy(tel->name, name, sizeof(tel->name)); } else { GenerateElementName(tel, t, px->name); } tel->type = RG_TILE_PIXMAP; tel->visible = 1; tel->tel_pixmap.px = px; tel->tel_pixmap.x = x; tel->tel_pixmap.y = y; tel->tel_pixmap.alpha = 255; TAILQ_INSERT_TAIL(&t->elements, tel, elements); px->nRefs++; t->flags |= RG_TILE_DIRTY; return (tel); } #if 0 RG_TileElement * RG_TileAddSketch(RG_Tile *t, const char *name, RG_Sketch *sk, int x, int y) { RG_TileElement *tel; tel = Malloc(sizeof(RG_TileElement)); if (name != NULL) { Strlcpy(tel->name, name, sizeof(tel->name)); } else { GenerateElementName(tel, t, sk->name); } tel->type = RG_TILE_SKETCH; tel->visible = 1; tel->tel_sketch.sk = sk; tel->tel_sketch.x = x; tel->tel_sketch.y = y; tel->tel_sketch.alpha = 255; tel->tel_sketch.scale = 1.0; TAILQ_INSERT_TAIL(&t->elements, tel, elements); sk->nRefs++; t->flags |= RG_TILE_DIRTY; return (tel); } #endif void RG_TileDelPixmap(RG_Tile *t, RG_Pixmap *px, int destroy) { RG_TileElement *tel; TAILQ_FOREACH(tel, &t->elements, elements) { if (tel->tel_pixmap.px == px) break; } if (tel != NULL) { TAILQ_REMOVE(&t->elements, tel, elements); Free(tel); if (--px->nRefs == 0 && destroy) { AG_TextTmsg(AG_MSG_INFO, 2000, _("Destroying unreferenced pixmap: %s"), px->name); TAILQ_REMOVE(&t->ts->pixmaps, px, pixmaps); RG_PixmapDestroy(px); Free(px); } } } #if 0 void RG_TileDelSketch(RG_Tile *t, RG_Sketch *sk, int destroy) { RG_TileElement *tel; TAILQ_FOREACH(tel, &t->elements, elements) { if (tel->tel_sketch.sk == sk) break; } if (tel != NULL) { TAILQ_REMOVE(&t->elements, tel, elements); Free(tel); if (--sk->nRefs == 0 && destroy) { AG_TextTmsg(AG_MSG_INFO, 2000, _("Destroying unreferenced sketch: %s"), sk->name); TAILQ_REMOVE(&t->ts->sketches, sk, sketches); RG_SketchDestroy(sk); Free(sk); } } } #endif void RG_TileSave(RG_Tile *t, AG_DataSource *buf) { Uint32 nelements = 0; off_t nelements_offs; RG_TileElement *tel; int x, y; AG_WriteString(buf, t->name); AG_WriteUint8(buf, t->flags & ~RG_TILE_DIRTY); AG_WriteSurface(buf, t->su); AG_WriteSint16(buf, (Sint16)t->xOrig); AG_WriteSint16(buf, (Sint16)t->yOrig); AG_WriteUint8(buf, (Uint8)t->snap_mode); AG_WriteUint32(buf, (Uint32)t->nw); AG_WriteUint32(buf, (Uint32)t->nh); for (y = 0; y < t->nh; y++) { for (x = 0; x < t->nw; x++) { AG_WriteUint32(buf, (Uint32)t->attrs[y*t->nw + x]); AG_WriteSint32(buf, (Sint32)t->layers[y*t->nw + x]); } } nelements_offs = AG_Tell(buf); AG_WriteUint32(buf, 0); TAILQ_FOREACH(tel, &t->elements, elements) { AG_WriteString(buf, tel->name); AG_WriteUint32(buf, (Uint32)tel->type); AG_WriteUint8(buf, (Uint8)tel->visible); switch (tel->type) { case RG_TILE_FEATURE: { RG_Feature *ft = tel->tel_feature.ft; AG_WriteString(buf, ft->name); AG_WriteSint32(buf, (Sint32)tel->tel_feature.x); AG_WriteSint32(buf, (Sint32)tel->tel_feature.y); } break; case RG_TILE_PIXMAP: { RG_Pixmap *px = tel->tel_pixmap.px; AG_WriteString(buf, px->name); AG_WriteSint32(buf, (Sint32)tel->tel_pixmap.x); AG_WriteSint32(buf, (Sint32)tel->tel_pixmap.y); AG_WriteUint8(buf, (Uint8)tel->tel_pixmap.alpha); } break; #if 0 case RG_TILE_SKETCH: { RG_Sketch *sk = tel->tel_sketch.sk; AG_WriteString(buf, sk->name); AG_WriteSint32(buf, (Sint32)tel->tel_sketch.x); AG_WriteSint32(buf, (Sint32)tel->tel_sketch.y); AG_WriteUint8(buf, (Uint8)tel->tel_sketch.alpha); } break; #endif } nelements++; } AG_WriteUint32At(buf, nelements, nelements_offs); } int RG_TileLoad(RG_Tile *t, AG_DataSource *buf) { RG_Tileset *ts = t->ts; Uint32 i, nelements; int x, y; t->flags = AG_ReadUint8(buf); if ((t->su = AG_ReadSurface(buf)) == NULL) return (-1); t->xOrig = (int)AG_ReadSint16(buf); t->yOrig = (int)AG_ReadSint16(buf); t->snap_mode = (int)AG_ReadUint8(buf); t->nw = (Uint)AG_ReadUint32(buf); t->nh = (Uint)AG_ReadUint32(buf); t->attrs = Realloc(t->attrs, t->nw*t->nh*sizeof(Uint)); t->layers = Realloc(t->layers, t->nw*t->nh*sizeof(int)); for (y = 0; y < t->nh; y++) { for (x = 0; x < t->nw; x++) { t->attrs[y*t->nw + x] = (Uint)AG_ReadUint32(buf); t->layers[y*t->nw + x] = (int)AG_ReadSint32(buf); } } nelements = AG_ReadUint32(buf); for (i = 0; i < nelements; i++) { char name[RG_TILE_ELEMENT_NAME_MAX]; enum rg_tile_element_type type; RG_TileElement *tel; int visible; AG_CopyString(name, buf, sizeof(name)); type = (enum rg_tile_element_type)AG_ReadUint32(buf); visible = (int)AG_ReadUint8(buf); switch (type) { case RG_TILE_FEATURE: { char feat_name[RG_FEATURE_NAME_MAX]; RG_Feature *ft; Sint32 x, y; AG_CopyString(feat_name, buf, sizeof(feat_name)); x = AG_ReadSint32(buf); y = AG_ReadSint32(buf); TAILQ_FOREACH(ft, &ts->features, features) { if (strcmp(ft->name, feat_name) == 0) break; } if (ft != NULL) { tel = RG_TileAddFeature(t, name, ft, x, y); tel->visible = visible; } else { AG_TextMsg(AG_MSG_ERROR, _("%s: no such feature: %s " "(ignored)"), t->name, feat_name); } } break; case RG_TILE_PIXMAP: { char pix_name[RG_PIXMAP_NAME_MAX]; RG_Pixmap *px; Sint32 x, y; int alpha; AG_CopyString(pix_name, buf, sizeof(pix_name)); x = AG_ReadSint32(buf); y = AG_ReadSint32(buf); alpha = (int)AG_ReadUint8(buf); TAILQ_FOREACH(px, &ts->pixmaps, pixmaps) { if (strcmp(px->name, pix_name) == 0) break; } if (px == NULL) { AG_SetError("bad pixmap: %s", pix_name); return (-1); } tel = RG_TileAddPixmap(t, name, px, x, y); tel->tel_pixmap.alpha = alpha; tel->visible = visible; } break; #if 0 case RG_TILE_SKETCH: { char sk_name[RG_SKETCH_NAME_MAX]; RG_Sketch *sk; Sint32 x, y; int alpha; AG_CopyString(sk_name, buf, sizeof(sk_name)); x = AG_ReadSint32(buf); y = AG_ReadSint32(buf); alpha = (int)AG_ReadUint8(buf); TAILQ_FOREACH(sk, &ts->sketches, sketches) { if (strcmp(sk->name, sk_name) == 0) break; } if (sk == NULL) { AG_SetError("bad sketch: %s", sk_name); return (-1); } tel = RG_TileAddSketch(t, name, sk, x, y); tel->tel_sketch.alpha = alpha; tel->visible = visible; } break; #endif default: break; } } t->flags &= ~RG_TILE_DIRTY; return (0); } void RG_TileDestroy(RG_Tile *t) { RG_TileElement *tel, *tel_next; RG_TileVariant *var, *var_next; Free(t->attrs); Free(t->layers); AG_SurfaceFree(t->su); for (tel = TAILQ_FIRST(&t->elements); tel != TAILQ_END(&t->elements); tel = tel_next) { tel_next = TAILQ_NEXT(tel, elements); Free(tel); } for (var = SLIST_FIRST(&t->vars); var != SLIST_END(&t->vars); var = var_next) { var_next = SLIST_NEXT(var, vars); Free(var); } } static void GeoCtrlButtonUp(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_SELF(); RG_TileviewCtrl *ctrl = AG_PTR(1); RG_Tileset *ts = tv->ts; RG_Tile *t = tv->tile; int w = RG_TileviewInt(ctrl, 2); int h = RG_TileviewInt(ctrl, 3); if (w != t->su->w || h != t->su->h) { RG_TileScale(ts, t, w, h); RG_TileviewSetZoom(tv, tv->zoom, 0); } } static void CloseElement(RG_Tileview *_Nonnull tv) { RG_TileviewCtrl *ctrl, *nctrl; RG_Tile *t = tv->tile; for (ctrl = TAILQ_FIRST(&tv->ctrls); ctrl != TAILQ_END(&tv->ctrls); ctrl = nctrl) { nctrl = TAILQ_NEXT(ctrl, ctrls); RG_TileviewDelCtrl(tv, ctrl); } switch (tv->state) { case RG_TILEVIEW_TILE_EDIT: tv->tile_ctrl.geo_ctrl = NULL; tv->tile_ctrl.orig_ctrl = NULL; break; case RG_TILEVIEW_FEATURE_EDIT: if (tv->feature.ft->ops->flags & RG_FEATURE_AUTOREDRAW) { RG_TileviewSetAutoRefresh(tv, 0, 0); } if (tv->feature.menu != NULL) { RG_FeatureCloseMenu(tv); } if (tv->feature.win != NULL) { AG_ObjectDetach(tv->feature.win); tv->feature.win = NULL; } break; case RG_TILEVIEW_PIXMAP_EDIT: if (tv->pixmap.win != NULL) { tv->pixmap.ctrl = NULL; AG_ObjectDetach(tv->pixmap.win); tv->pixmap.win = NULL; } break; #if 0 case RG_TILEVIEW_SKETCH_EDIT: if (tv->sketch.win != NULL) { tv->sketch.ctrl = NULL; AG_ObjectDetach(tv->sketch.win); tv->sketch.win = NULL; } break; #endif default: if (tv->menu != NULL) { RG_TileCloseMenu(tv); } break; } tv->state = RG_TILEVIEW_TILE_EDIT; tv->edit_mode = 0; tv->tile_ctrl.geo_ctrl = RG_TileviewAddCtrl(tv, RG_TILEVIEW_RDIMENSIONS, "%i,%i,%u,%u", 0, 0, (Uint)t->su->w, (Uint)t->su->h); tv->tile_ctrl.geo_ctrl->buttonup = AG_SetEvent(tv, NULL, GeoCtrlButtonUp,"%p",tv->tile_ctrl.geo_ctrl); tv->tile_ctrl.orig_ctrl = RG_TileviewAddCtrl(tv, RG_TILEVIEW_POINT, "%*i,%*i", &t->xOrig, &t->yOrig); /* XXX use new style system */ AG_ColorRGB_8(&tv->tile_ctrl.orig_ctrl->cIna, 0, 255,0); AG_ColorRGB_8(&tv->tile_ctrl.orig_ctrl->cHigh, 73, 186,51); AG_ColorRGB_8(&tv->tile_ctrl.orig_ctrl->cLow, 86, 161,71); AG_ColorRGB_8(&tv->tile_ctrl.orig_ctrl->cOver, 191,170,47); tv->tile_ctrl.orig_ctrl->aEna = 70; tv->tile_ctrl.orig_ctrl->aIna = 30; tv->tile_ctrl.orig_ctrl->aOver= 100; if (tv->tel_tbar != NULL) { AG_ObjectDetach(tv->tel_tbar); AG_WidgetUpdate(tv->tel_tbar); AG_ObjectDestroy(tv->tel_tbar); tv->tel_tbar = NULL; } } static void ElementClosedEv(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); if (tv->edit_mode) CloseElement(tv); } static void PixmapCtrlButtonUp(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_SELF(); RG_TileviewCtrl *ctrl = AG_PTR(1); RG_Pixmap *px = AG_PTR(2); RG_Tile *t = tv->tile; int w = RG_TileviewInt(ctrl, 2); int h = RG_TileviewInt(ctrl, 3); if (w != px->su->w || h != px->su->h) { RG_PixmapScale(px, w, h); } t->flags |= RG_TILE_DIRTY; } #if 0 static void SketchCtrlButtonUp(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_SELF(); RG_TileviewCtrl *ctrl = AG_PTR(1); RG_TileElement *tel = AG_PTR(2); RG_Sketch *sk = tel->tel_sketch.sk; RG_Tile *t = tv->tile; int w = RG_TileviewInt(ctrl, 2); int h = RG_TileviewInt(ctrl, 3); if (w != sk->vg->su->w || h != sk->vg->su->h) { RG_SketchScale(sk, w, h, tel->tel_sketch.scale, ctrl->xoffs, ctrl->yoffs); } t->flags |= RG_TILE_DIRTY; } #endif static void OpenElement(RG_Tileview *_Nonnull tv, RG_TileElement *_Nonnull tel) { AG_Window *pWin; if ((pWin = AG_ParentWindow(tv)) == NULL) return; CloseElement(tv); if (tv->state == RG_TILEVIEW_TILE_EDIT) { RG_TileviewDelCtrl(tv, tv->tile_ctrl.geo_ctrl); RG_TileviewDelCtrl(tv, tv->tile_ctrl.orig_ctrl); tv->tile_ctrl.geo_ctrl = NULL; tv->tile_ctrl.orig_ctrl = NULL; } switch (tel->type) { case RG_TILE_FEATURE: { AG_Window *win; RG_Feature *ft = tel->tel_feature.ft; tv->state = RG_TILEVIEW_FEATURE_EDIT; tv->feature.ft = ft; tv->feature.menu = NULL; if (ft->ops->flags & RG_FEATURE_AUTOREDRAW) RG_TileviewSetAutoRefresh(tv, 1, 125); if (ft->ops->edit != NULL) { win = ft->ops->edit(ft, tv); AG_WindowSetPosition(win, AG_WINDOW_MIDDLE_LEFT, 0); AG_WindowAttach(pWin, win); AG_WindowShow(win); tv->feature.win = win; AG_SetEvent(win, "window-close", ElementClosedEv, "%p", tv); AG_WindowFocus(pWin); AG_WidgetFocus(tv); } else { tv->feature.win = NULL; } if (ft->ops->toolbar != NULL) { tv->tel_tbar = ft->ops->toolbar(ft, tv); AG_WidgetUpdate(tv); } } break; case RG_TILE_PIXMAP: { AG_Window *win; tv->state = RG_TILEVIEW_PIXMAP_EDIT; tv->pixmap.px = tel->tel_pixmap.px; tv->pixmap.tel = tel; tv->pixmap.ctrl = RG_TileviewAddCtrl(tv, RG_TILEVIEW_RECTANGLE, "%*i,%*i,%u,%u", &tel->tel_pixmap.x, &tel->tel_pixmap.y, (Uint)tel->tel_pixmap.px->su->w, (Uint)tel->tel_pixmap.px->su->h); tv->pixmap.ctrl->buttonup = AG_SetEvent(tv, NULL, PixmapCtrlButtonUp, "%p,%p", tv->pixmap.ctrl, tel->tel_pixmap.px); tv->pixmap.state = RG_TVPIXMAP_IDLE; tv->pixmap.win = win = RG_PixmapEdit(tv, tel); tv->pixmap.menu = NULL; AG_WindowAttach(pWin, win); AG_WindowShow(win); AG_SetEvent(win, "window-close", ElementClosedEv, "%p",tv); AG_WindowFocus(pWin); AG_WidgetFocus(tv); tv->tel_tbar = RG_PixmapToolbar(tv, tel); AG_WidgetUpdate(tv); } break; #if 0 case RG_TILE_SKETCH: { AG_Window *win; tv->state = RG_TILEVIEW_SKETCH_EDIT; tv->sketch.sk = tel->tel_sketch.sk; tv->sketch.tel = tel; tv->sketch.ctrl = RG_TileviewAddCtrl(tv, RG_TILEVIEW_RECTANGLE, "%*i,%*i,%u,%u", &tel->tel_sketch.x, &tel->tel_sketch.y, tel->tel_sketch.sk->vg->su->w, tel->tel_sketch.sk->vg->su->h); tv->sketch.ctrl->buttonup = AG_SetEvent(tv, NULL, SketchCtrlButtonUp, "%p,%p", tv->sketch.ctrl, tel); tv->sketch.win = win = RG_SketchEdit(tv, tel); tv->sketch.menu = NULL; AG_WindowAttach(pWin, win); AG_WindowShow(win); AG_SetEvent(win, "window-close", ElementClosedEv, "%p",tv); AG_WindowFocus(pWin); AG_WidgetFocus(tv); tv->tel_tbar = RG_SketchToolbar(tv, tel); AG_WidgetUpdate(tv); } break; #endif } tv->edit_mode = 1; } static void CreatePixmap(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tlFeatures = AG_TLIST_PTR(2); AG_TlistItem *eit; RG_Pixmap *px; RG_TileElement *tel; Uint pixno = 0; RG_Pixmap *opx; px = Malloc(sizeof(RG_Pixmap)); RG_PixmapInit(px, tv->ts, 0); tryname: Snprintf(px->name, sizeof(px->name), "pixmap #%u", pixno); TAILQ_FOREACH(opx, &tv->ts->pixmaps, pixmaps) { if (strcmp(opx->name, px->name) == 0) break; } if (opx != NULL) { pixno++; goto tryname; } RG_PixmapScale(px, tv->tile->su->w, tv->tile->su->h); TAILQ_INSERT_TAIL(&tv->ts->pixmaps, px, pixmaps); tel = RG_TileAddPixmap(tv->tile, NULL, px, 0, 0); OpenElement(tv, tel); /* Select the newly inserted feature. */ AG_PostEvent(tlFeatures, "tlist-poll", NULL); AG_TlistDeselectAll(tlFeatures); TAILQ_FOREACH(eit, &tlFeatures->items, items) { RG_TileElement *tel; if (strcmp(eit->cat, "pixmap") != 0) { continue; } tel = eit->p1; if (tel->tel_pixmap.px == px) { AG_TlistSelect(tlFeatures, eit); break; } } } #if 0 static void CreateSketch(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tlFeatures = AG_TLIST_PTR(2); AG_TlistItem *eit; RG_Sketch *sk, *osk; RG_TileElement *tel; Uint skno = 0; sk = Malloc(sizeof(RG_Sketch)); RG_SketchInit(sk, tv->ts, 0); tryname: Snprintf(sk->name, sizeof(sk->name), "sketch #%u", skno); TAILQ_FOREACH(osk, &tv->ts->sketches, sketches) { if (strcmp(osk->name, sk->name) == 0) break; } if (osk != NULL) { skno++; goto tryname; } RG_SketchScale(sk, tv->tile->su->w, tv->tile->su->h, 1.0, 0, 0); TAILQ_INSERT_TAIL(&tv->ts->sketches, sk, sketches); tel = RG_TileAddSketch(tv->tile, NULL, sk, 0, 0); tv->tile->flags |= RG_TILE_DIRTY; OpenElement(tv, tel); /* Select the newly inserted feature. */ AG_PostEvent(tlFeatures, "tlist-poll", NULL); AG_TlistDeselectAll(tlFeatures); TAILQ_FOREACH(eit, &tlFeatures->items, items) { RG_TileElement *tel; if (strcmp(eit->cat, "sketch") != 0) { continue; } tel = eit->p1; if (tel->tel_sketch.sk == sk) { AG_TlistSelect(tlFeatures, eit); break; } } } #endif static void AttachPixmap(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Window *dlgWin = AG_WINDOW_PTR(2); AG_Tlist *tlFeatures = AG_TLIST_PTR(3); AG_Tlist *tl_pixmaps = AG_TLIST_PTR(4); AG_TlistItem *it; RG_TileElement *tel; RG_Pixmap *px; if ((it = AG_TlistSelectedItem(tl_pixmaps)) == NULL) { return; } px = it->p1; tel = RG_TileAddPixmap(tv->tile, NULL, px, 0, 0); OpenElement(tv, tel); /* Select the newly inserted feature. */ AG_PostEvent(tlFeatures, "tlist-poll", NULL); AG_TlistDeselectAll(tlFeatures); TAILQ_FOREACH(it, &tlFeatures->items, items) { RG_TileElement *tel; if (strcmp(it->cat, "pixmap") != 0) { continue; } tel = it->p1; if (tel->tel_pixmap.px == px) { AG_TlistSelect(tlFeatures, it); break; } } AG_ObjectDetach(dlgWin); } static void AttachPixmapDlg(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tlFeatures = AG_TLIST_PTR(2); AG_Tlist *tl; RG_Pixmap *px; AG_Window *win; AG_Box *bo; if ((win = AG_WindowNew(AG_WINDOW_MODAL|AG_WINDOW_NOMINIMIZE)) == NULL) { return; } AG_WindowSetCaption(win, _("Attach existing pixmap")); tl = AG_TlistNew(win, AG_TLIST_EXPAND); AG_TlistSetItemHeight(tl, RG_TILESZ); AG_TlistSizeHint(tl, "XXXXXXXXXXXXXXXXXXX", 5); AG_WidgetFocus(tl); TAILQ_FOREACH(px, &tv->ts->pixmaps, pixmaps) { AG_TlistItem *it; it = AG_TlistAdd(tl, NULL, "%s (%ux%u)", px->name, px->su->w, px->su->h); it->p1 = px; AG_TlistSetIcon(tl, it, px->su); } bo = AG_BoxNew(win, AG_BOX_HORIZ, AG_BOX_HOMOGENOUS|AG_BOX_HFILL); { AG_ButtonNewFn(bo, 0, _("OK"), AttachPixmap, "%p,%p,%p,%p", tv, win, tlFeatures, tl); AG_ButtonNewFn(bo, 0, _("Cancel"), AGWINDETACH(win)); } AG_WindowAttach(AG_ParentWindow(tv), win); AG_WindowShow(win); } #if 0 static void AttachSketch(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Window *dlgWin = AG_WINDOW_PTR(2); AG_Tlist *tlFeatures = AG_TLIST_PTR(3); AG_Tlist *tl_sketches = AG_TLIST_PTR(4); AG_TlistItem *it; RG_TileElement *tel; RG_Sketch *sk; if ((it = AG_TlistSelectedItem(tl_sketches)) == NULL) { return; } sk = it->p1; tel = RG_TileAddSketch(tv->tile, NULL, sk, 0, 0); OpenElement(tv, tel); /* Select the newly inserted feature. */ AG_PostEvent(tlFeatures, "tlist-poll", NULL); AG_TlistDeselectAll(tlFeatures); TAILQ_FOREACH(it, &tlFeatures->items, items) { RG_TileElement *tel; if (strcmp(it->cat, "sketch") != 0) { continue; } tel = it->p1; if (tel->tel_sketch.sk == sk) { AG_TlistSelect(tlFeatures, it); break; } } AG_ObjectDetach(dlgWin); } static void AttachSketchDlg(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tlFeatures = AG_TLIST_PTR(2); AG_Tlist *tl; RG_Sketch *sk; AG_Window *win; AG_Box *bo; if ((win = AG_WindowNew(AG_WINDOW_MODAL|AG_WINDOW_NOMINIMIZE)) == NULL) { return; } AG_WindowSetCaption(win, _("Attach existing sketch")); tl = AG_TlistNew(win, AG_TLIST_EXPAND); AG_TlistSetItemHeight(tl, RG_TILESZ); AG_TlistSizeHint(tl, "XXXXXXXXXXXXXXXXXXXXXXXXX", 5); AG_WidgetFocus(tl); TAILQ_FOREACH(sk, &tv->ts->sketches, sketches) { AG_TlistItem *it; it = AG_TlistAdd(tl, NULL, "%s (%ux%u, %.0f%%)", sk->name, sk->vg->su->w, sk->vg->su->h, sk->vg->scale*100.0); it->p1 = sk; AG_TlistSetIcon(tl, it, sk->vg->su); } bo = AG_BoxNew(win, AG_BOX_HORIZ, AG_BOX_HOMOGENOUS|AG_BOX_HFILL); { AG_ButtonNewFn(bo, 0, _("OK"), AttachSketch, "%p,%p,%p,%p", tv, win, tlFeatures, tl); AG_ButtonNewFn(bo, 0, _("Cancel"), AGWINDETACH(win)); } AG_WindowAttach(AG_ParentWindow(tv), win); AG_WindowShow(win); } #endif static void SelectFeature(AG_Tlist *_Nonnull tlFeatures, void *_Nonnull fp) { RG_Feature *feat = fp; AG_TlistItem *eit; /* Select the newly inserted feature. */ AG_PostEvent(tlFeatures, "tlist-poll", NULL); AG_TlistDeselectAll(tlFeatures); TAILQ_FOREACH(eit, &tlFeatures->items, items) { RG_TileElement *tel; if (strcmp(eit->cat, "feature") != 0) { continue; } tel = eit->p1; if (tel->tel_feature.ft == feat) { AG_TlistSelect(tlFeatures, eit); break; } } } static void AddFillFeature(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tlFeatures = AG_TLIST_PTR(2); struct rg_fill_feature *fill; RG_TileElement *tel; fill = Malloc(sizeof(struct rg_fill_feature)); RG_FillInit(fill, tv->ts, 0); TAILQ_INSERT_TAIL(&tv->ts->features, RG_FEATURE(fill), features); tel = RG_TileAddFeature(tv->tile, NULL, fill, 0, 0); OpenElement(tv, tel); SelectFeature(tlFeatures, fill); } #if 0 static void AddSketchProjFeature(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tlFeatures = AG_TLIST_PTR(2); struct rg_sketchproj *sproj; RG_TileElement *tel; sproj = Malloc(sizeof(struct rg_sketchproj)); RG_SketchProjInit(sproj, tv->ts, 0); TAILQ_INSERT_TAIL(&tv->ts->features, RG_FEATURE(sproj), features); tel = RG_TileAddFeature(tv->tile, NULL, sproj, 0, 0); OpenElement(tv, tel); SelectFeature(tlFeatures, sproj); } #endif static void PollFeatures(AG_Event *_Nonnull event) { AG_Tlist *tl = AG_TLIST_SELF(); #ifdef AG_THREADS RG_Tileset *ts = RG_TILESET_PTR(1); #endif RG_Tile *t = AG_PTR(2); RG_Tileview *tv = RG_TILEVIEW_PTR(4); RG_TileElement *tel; AG_TlistItem *it; static char attr_names[6]; /* XXX tlist hack */ AG_TlistClear(tl); AG_MutexLock(&ts->lock); it = AG_TlistAdd(tl, NULL, _("Grid Attributes")); it->cat = "attributes"; it->depth = 0; it->flags |= AG_TLIST_HAS_CHILDREN; it->p1 = &attr_names[0]; if (AG_TlistVisibleChildren(tl, it)) { it = AG_TlistAdd(tl, rgIconLayerEditor.s, _("%sLayers"), (tv->state==RG_TILEVIEW_LAYERS_EDIT) ? "* " : ""); it->cat = "layers"; it->depth = 1; it->p1 = &attr_names[1]; it = AG_TlistAdd(tl, rgIconWalkable.s, _("%sWalkable"), (tv->state==RG_TILEVIEW_ATTRIB_EDIT && tv->edit_attr == RG_TILE_BLOCK) ? "* " : ""); it->cat = "walkable-attrs"; it->depth = 1; it->p1 = &attr_names[2]; it = AG_TlistAdd(tl, rgIconClimbable.s, _("%sClimbable"), (tv->state==RG_TILEVIEW_ATTRIB_EDIT && tv->edit_attr == RG_TILE_CLIMBABLE) ? "* " : ""); it->cat = "climbable-attrs"; it->depth = 1; it->p1 = &attr_names[3]; it = AG_TlistAdd(tl, rgIconJumpable.s, _("%sJumpable"), (tv->state==RG_TILEVIEW_ATTRIB_EDIT && tv->edit_attr == RG_TILE_JUMPABLE) ? "* " : ""); it->cat = "jumpable-attrs"; it->depth = 1; it->p1 = &attr_names[4]; it = AG_TlistAdd(tl, rgIconSlippery.s, _("%sSlippery"), (tv->state==RG_TILEVIEW_ATTRIB_EDIT && tv->edit_attr == RG_TILE_SLIPPERY) ? "* " : ""); it->cat = "slippery-attrs"; it->depth = 1; it->p1 = &attr_names[5]; } TAILQ_FOREACH(tel, &t->elements, elements) { if (tel->type == RG_TILE_FEATURE) { RG_Feature *ft = tel->tel_feature.ft; /* RG_FeatureSketch *fsk; */ RG_FeaturePixmap *fpx; it = AG_TlistAdd(tl, rgIconObject.s, "%s%s%s", (tv->state==RG_TILEVIEW_FEATURE_EDIT && tv->feature.ft == ft) ? "* " : "", tel->name, tel->visible ? "" : _(" (invisible)")); it->cat = "feature"; it->p1 = tel; it->depth = 0; /* if (!TAILQ_EMPTY(&ft->sketches) || */ if (!TAILQ_EMPTY(&ft->pixmaps)) { it->flags |= AG_TLIST_HAS_CHILDREN; } if (!AG_TlistVisibleChildren(tl, it)) continue; #if 0 TAILQ_FOREACH(fsk, &ft->sketches, sketches) { it = AG_TlistAdd(tl, rgIconDrawing.s, "%s%s%s", (tv->state==RG_TILEVIEW_SKETCH_EDIT && tv->sketch.sk == fsk->sk) ? "* ": "", tel->name, fsk->visible ? "" : _(" (invisible)")); it->cat = "feature-sketch"; it->p1 = fsk; } #endif TAILQ_FOREACH(fpx, &ft->pixmaps, pixmaps) { it = AG_TlistAdd(tl, rgIconPixmap.s, "%s%s (%d,%d)%s", (tv->state==RG_TILEVIEW_PIXMAP_EDIT && tv->pixmap.px == fpx->px) ? "* ": "", tel->name, fpx->x, fpx->y, fpx->visible ? "" : _(" (invisible)")); it->cat = "feature-pixmap"; it->p1 = fpx; } } else if (tel->type == RG_TILE_PIXMAP) { RG_Pixmap *px = tel->tel_pixmap.px; it = AG_TlistAdd(tl, NULL, "%s%s%s", (tv->state==RG_TILEVIEW_PIXMAP_EDIT && tv->pixmap.px == px) ? "* ": "", tel->name, tel->visible ? "" : _(" (invisible)")); it->cat = "pixmap"; it->p1 = tel; it->depth = 0; AG_TlistSetIcon(tl, it, px->su); #if 0 } else if (tel->type == RG_TILE_SKETCH) { RG_Sketch *sk = tel->tel_sketch.sk; VG *vg = sk->vg; VG_Element *vge; it = AG_TlistAdd(tl, NULL, "%s%s%s", (tv->state==RG_TILEVIEW_SKETCH_EDIT && tv->sketch.sk == sk) ? "* ": "", tel->name, tel->visible ? "" : _(" (invisible)")); it->cat = "sketch"; it->p1 = tel; it->depth = 0; /* AG_TlistSetIcon(tl, it, sk->vg->su); */ if (!TAILQ_EMPTY(&vg->vges)) { it->flags |= AG_TLIST_HAS_CHILDREN; } if (!AG_TlistVisibleChildren(tl, it)) continue; TAILQ_FOREACH(vge, &vg->vges, vges) { it = AG_TlistAdd(tl, vgElementTypes[vge->type]->icon->s, "%s%s", (vge == vg->cur_vge) ? "* " : "", vgElementTypes[vge->type]->name); it->cat = "sketch-element"; it->p1 = vge; it->depth = 1; } #endif } } AG_MutexUnlock(&ts->lock); AG_TlistRestore(tl); } static void EditElement(AG_Event *_Nonnull event) { AG_Widget *sndr = AG_WIDGET_SELF(); RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tl = AG_TLIST_PTR(2); AG_TlistItem *it; if (AG_BUTTON_ISA(sndr) && !tv->edit_mode) { CloseElement(tv); return; } CloseElement(tv); if ((it = AG_TlistSelectedItem(tl)) == NULL) return; if (strcmp(it->cat, "feature") == 0 || strcmp(it->cat, "pixmap") == 0 || strcmp(it->cat, "sketch") == 0) { if (it->p1 != NULL) { OpenElement(tv, (RG_TileElement *)it->p1); } } else if (strcmp(it->cat, "walkable-attrs") == 0) { tv->state = RG_TILEVIEW_ATTRIB_EDIT; tv->edit_mode = 1; tv->edit_attr = RG_TILE_BLOCK; } else if (strcmp(it->cat, "climbable-attrs") == 0) { tv->state = RG_TILEVIEW_ATTRIB_EDIT; tv->edit_mode = 1; tv->edit_attr = RG_TILE_CLIMBABLE; } else if (strcmp(it->cat, "jumpable-attrs") == 0) { tv->state = RG_TILEVIEW_ATTRIB_EDIT; tv->edit_mode = 1; tv->edit_attr = RG_TILE_JUMPABLE; } else if (strcmp(it->cat, "slippery-attrs") == 0) { tv->state = RG_TILEVIEW_ATTRIB_EDIT; tv->edit_mode = 1; tv->edit_attr = RG_TILE_SLIPPERY; } else if (strcmp(it->cat, "layers") == 0) { tv->state = RG_TILEVIEW_LAYERS_EDIT; tv->edit_mode = 1; } } static void DeleteElement(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); RG_Tile *t = tv->tile; AG_Tlist *tlFeatures = AG_TLIST_PTR(2); const int detach_only = AG_INT(3); AG_TlistItem *it; RG_TileElement *tel; if ((it = AG_TlistSelectedItem(tlFeatures)) == NULL) return; #if 0 if (tv->state == RG_TILEVIEW_SKETCH_EDIT && strcmp(it->cat, "sketch-element") == 0) { VG *vg = tv->sketch.sk->vg; VG_Element *vge = it->p1; RG_SketchUnselect(tv, tv->sketch.tel, vge); VG_DestroyElement(vg, vge); return; } #endif tel = it->p1; /* XXX check that it's the element being deleted */ if (tv->edit_mode) CloseElement(tv); if (strcmp(it->cat, "feature") == 0) { RG_TileDelFeature(t, tel->tel_feature.ft, !detach_only); } else if (strcmp(it->cat, "pixmap") == 0) { RG_TileDelPixmap(t, tel->tel_pixmap.px, !detach_only); #if 0 } else if (strcmp(it->cat, "sketch") == 0) { RG_TileDelSketch(t, tel->tel_sketch.sk, !detach_only); #endif } t->flags |= RG_TILE_DIRTY; } static void UpdateTileSettings(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Window *win = AG_WINDOW_PTR(2); AG_MSpinbutton *msbSize = AGMSPINBUTTON (AG_GetPointer(win,"msbSize")); AG_Checkbox *cbColorkey = AGCHECKBOX (AG_GetPointer(win,"cbColorkey")); AG_Checkbox *cbAlpha = AGCHECKBOX (AG_GetPointer(win,"cbAlpha")); AG_Numerical *numAlpha = AGNUMERICAL (AG_GetPointer(win,"numAlpha")); RG_Tileset *ts = tv->ts; RG_Tile *t = tv->tile; const int w = AG_GetInt(msbSize, "xvalue"); const int h = AG_GetInt(msbSize, "yvalue"); if (AG_GetBool(cbColorkey,"state")) { t->flags |= RG_TILE_SRCCOLORKEY; } else { t->flags &= ~(RG_TILE_SRCCOLORKEY); } if (AG_GetBool(cbAlpha,"state")) { t->flags |= RG_TILE_SRCALPHA; } else { t->flags &= ~(RG_TILE_SRCALPHA); } RG_TileScale(ts, t, w,h); t->su->alpha = AG_GetInt(numAlpha, "value"); RG_TileviewSetZoom(tv, 100, 0); AG_ObjectDetach(win); if (tv->state == RG_TILEVIEW_TILE_EDIT) { RG_TileviewSetInt(tv->tile_ctrl.geo_ctrl, 2, w); RG_TileviewSetInt(tv->tile_ctrl.geo_ctrl, 3, h); } } static void TileSettingsDlg(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); RG_Tile *t = tv->tile; AG_Window *win; AG_MSpinbutton *msbSize; AG_Box *box; AG_Checkbox *cbColorkey, *cbAlpha; AG_Numerical *numAlpha; AG_Textbox *tb; if ((win = AG_WindowNewNamed(AG_WINDOW_MODAL, "rg-tileinfo-%s", t->name)) == NULL) { return; } AG_WindowSetCaption(win, _("Tile information: %s"), t->name); tb = AG_TextboxNew(win, AG_TEXTBOX_HFILL, _("Name: ")); AG_TextboxBindUTF8(tb, t->name, sizeof(t->name)); AG_WidgetFocus(tb); tb = AG_TextboxNew(win, AG_TEXTBOX_HFILL, _("Class: ")); AG_TextboxBindUTF8(tb, t->clname, sizeof(t->clname)); msbSize = AG_MSpinbuttonNew(win, 0, "x", _("Size: ")); AG_MSpinbuttonSetRange(msbSize, RG_TILE_SIZE_MIN, RG_TILE_SIZE_MAX); AG_SetInt(msbSize, "xvalue", t->su->w); AG_SetInt(msbSize, "yvalue", t->su->h); AG_SetPointer(win, "msbSize", msbSize); numAlpha = AG_NumericalNewS(win, 0, NULL, _("Overall alpha: ")); AG_SetInt(numAlpha, "value", t->su->alpha); AG_SetPointer(win, "numAlpha", numAlpha); AG_SeparatorNew(win, AG_SEPARATOR_HORIZ); cbColorkey = AG_CheckboxNew(win, 0, _("Colorkey")); AG_SetInt(cbColorkey, "state", t->flags & RG_TILE_SRCCOLORKEY); AG_SetPointer(win, "cbColorkey", cbColorkey); cbAlpha = AG_CheckboxNew(win, 0, _("Source alpha")); AG_SetInt(cbAlpha, "state", t->flags & RG_TILE_SRCALPHA); AG_SetPointer(win, "cbAlpha", cbAlpha); AG_SeparatorNew(win, AG_SEPARATOR_HORIZ); AG_LabelNewS(win, 0, _("Snapping mode: ")); AG_RadioNewUint(win, 0, rgTileSnapModes, &t->snap_mode); AG_SeparatorNew(win, AG_SEPARATOR_HORIZ); box = AG_BoxNew(win, AG_BOX_HORIZ, AG_BOX_HFILL | AG_BOX_HOMOGENOUS); { AG_ButtonNewFn(box, 0, _("OK"), UpdateTileSettings, "%p,%p", tv,win); AG_ButtonNewFn(box, 0, _("Cancel"), AGWINDETACH(win)); } AG_WindowAttach(AG_ParentWindow(tv), win); AG_WindowShow(win); } static void MoveElementUp(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tl = AG_TLIST_PTR(2); RG_Tile *t = tv->tile; AG_TlistItem *it; RG_TileElement *tel, *ptel; if ((it = AG_TlistSelectedItem(tl)) == NULL || (strcmp(it->cat, "feature") != 0 && strcmp(it->cat, "pixmap") != 0 && strcmp(it->cat, "sketch") != 0)) { return; } tel = it->p1; if (tel != TAILQ_FIRST(&t->elements)) { ptel = TAILQ_PREV(tel, rg_tile_elementq, elements); TAILQ_REMOVE(&t->elements, tel, elements); TAILQ_INSERT_BEFORE(ptel, tel, elements); } t->flags |= RG_TILE_DIRTY; } static void MoveElementDown(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tl = AG_TLIST_PTR(2); RG_Tile *t = tv->tile; AG_TlistItem *it; RG_TileElement *tel, *ntel; if ((it = AG_TlistSelectedItem(tl)) == NULL || (strcmp(it->cat, "feature") != 0 && strcmp(it->cat, "pixmap") != 0 && strcmp(it->cat, "sketch") != 0)) { return; } tel = it->p1; if ((ntel = TAILQ_NEXT(tel, elements)) != NULL) { TAILQ_REMOVE(&t->elements, tel, elements); TAILQ_INSERT_AFTER(&t->elements, ntel, tel, elements); } t->flags |= RG_TILE_DIRTY; } static void ToggleElementVisibility(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); AG_Tlist *tl = AG_TLIST_PTR(2); RG_Tile *t = tv->tile; AG_TlistItem *it; RG_TileElement *tel; if ((it = AG_TlistSelectedItem(tl)) == NULL || (strcmp(it->cat, "pixmap") != 0 && strcmp(it->cat, "sketch") != 0 && strcmp(it->cat, "feature") != 0)) { return; } tel = it->p1; tel->visible = !tel->visible; t->flags |= RG_TILE_DIRTY; } static void Undo(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); switch (tv->state) { case RG_TILEVIEW_PIXMAP_EDIT: RG_PixmapUndo(tv, tv->pixmap.tel); break; default: break; } } static void Redo(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); switch (tv->state) { case RG_TILEVIEW_PIXMAP_EDIT: RG_PixmapRedo(tv, tv->pixmap.tel); break; default: break; } } static void ImportImage(AG_Event *_Nonnull event) { RG_Tile *t = AG_PTR(1); RG_Tileview *tv = RG_TILEVIEW_PTR(2); char *path = AG_STRING(3); AG_Surface *su; RG_Pixmap *px; if ((su = AG_SurfaceFromFile(path)) == NULL) { AG_TextMsgFromError(); return; } px = RG_PixmapNew(t->ts, AG_ShortFilename(path), 0); px->su = AG_SurfaceConvert(su, t->ts->fmt); OpenElement(tv, RG_TileAddPixmap(t, NULL, px, 0, 0)); RG_TileGenerate(t); AG_SurfaceFree(su); } static void ImportImageDlg(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); RG_Tile *t = tv->tile; AG_FileDlg *dlg; AG_Window *win; if ((win = AG_WindowNew(0)) == NULL) { return; } AG_WindowSetCaption(win, _("Import %s image from..."), t->name); dlg = AG_FileDlgNewMRU(win, "rg-imgimport", AG_FILEDLG_LOAD | AG_FILEDLG_CLOSEWIN | AG_FILEDLG_EXPAND); AG_FileDlgAddType(dlg, _("PNG Image"), "*.png", ImportImage, "%p,%p", t, tv); AG_FileDlgAddType(dlg, _("JPEG Image"), "*.jpg,*.jpeg", ImportImage, "%p,%p", t, tv); AG_FileDlgAddType(dlg, _("PC bitmap"), "*.bmp", ImportImage, "%p,%p", t, tv); AG_WindowAttach(AG_ParentWindow(tv), win); AG_WindowShow(win); } static void ExportBMP(AG_Event *_Nonnull event) { RG_Tile *t = AG_PTR(1); char *path = AG_STRING(2); if (AG_SurfaceExportBMP(t->su, path, 0) == -1) { AG_TextMsgFromError(); return; } AG_TextTmsg(AG_MSG_INFO, 1000, _("Tile exported successfully to %s"), path); } static void ExportImageDlg(AG_Event *_Nonnull event) { RG_Tileview *tv = RG_TILEVIEW_PTR(1); RG_Tile *t = tv->tile; AG_FileDlg *dlg; AG_Window *win; if ((win = AG_WindowNew(0)) == NULL) { return; } AG_WindowSetCaption(win, _("Export %s image to..."), t->name); dlg = AG_FileDlgNewMRU(win, "rg-imgexport", AG_FILEDLG_SAVE | AG_FILEDLG_CLOSEWIN | AG_FILEDLG_EXPAND); AG_FileDlgSetFilename(dlg, "%s.bmp", t->name); AG_FileDlgAddType(dlg, _("PC bitmap"), "*.bmp", ExportBMP, "%p", t); AG_WindowAttach(AG_ParentWindow(tv), win); AG_WindowShow(win); } static void InitTileFeatureMenu(RG_Tileview *_Nonnull tv, AG_Tlist *_Nonnull tl) { AG_MenuItem *mi; mi = AG_TlistSetPopup(tl, "feature"); { AG_MenuAction(mi, _("Toggle visibility"), NULL, ToggleElementVisibility, "%p,%p", tv, tl); #if 0 AG_MenuAction(mi, _("Edit feature"), NULL, EditElement, "%p,%p", tv, tl); #endif AG_MenuSeparator(mi); AG_MenuAction(mi, _("Detach feature"), agIconTrash.s, DeleteElement, "%p,%p,%i", tv, tl, 1); AG_MenuAction(mi, _("Destroy feature"), agIconTrash.s, DeleteElement, "%p,%p,%i", tv, tl, 0); AG_MenuSeparator(mi); AG_MenuActionKb(mi, _("Move up"), agIconUp.s, AG_KEY_U, AG_KEYMOD_SHIFT, MoveElementUp, "%p,%p", tv, tl); AG_MenuActionKb(mi, _("Move down"), agIconDown.s, AG_KEY_D, AG_KEYMOD_SHIFT, MoveElementDown, "%p,%p", tv, tl); } mi = AG_TlistSetPopup(tl, "pixmap"); { AG_MenuAction(mi, _("Toggle visibility"), NULL, ToggleElementVisibility, "%p,%p", tv, tl); AG_MenuSeparator(mi); #if 0 AG_MenuAction(mi, _("Edit pixmap"), NULL, EditElement, "%p,%p", tv, tl); #endif AG_MenuAction(mi, _("Detach pixmap"), agIconTrash.s, DeleteElement, "%p,%p,%i", tv, tl, 1); AG_MenuAction(mi, _("Destroy pixmap"), agIconTrash.s, DeleteElement, "%p,%p,%i", tv, tl, 0); AG_MenuSeparator(mi); AG_MenuActionKb(mi, _("Move up"), agIconUp.s, AG_KEY_U, AG_KEYMOD_SHIFT, MoveElementUp, "%p,%p", tv, tl); AG_MenuActionKb(mi, _("Move down"), agIconDown.s, AG_KEY_D, AG_KEYMOD_SHIFT, MoveElementDown, "%p,%p", tv, tl); } #if 0 mi = AG_TlistSetPopup(tl, "sketch"); { AG_MenuAction(mi, _("Toggle visibility"), NULL, ToggleElementVisibility, "%p,%p", tv, tl); AG_MenuSeparator(mi); AG_MenuAction(mi, _("Edit sketch"), rgIconSketch.s, EditElement, "%p,%p", tv, tl); AG_MenuAction(mi, _("Detach sketch"), agIconTrash.s, DeleteElement, "%p,%p,%i", tv, tl, 1); AG_MenuAction(mi, _("Destroy sketch"), agIconTrash.s, DeleteElement, "%p,%p,%i", tv, tl, 0); AG_MenuSeparator(mi); AG_MenuActionKb(mi, _("Move up"), agIconUp.s, AG_KEY_U, AG_KEYMOD_SHIFT, MoveElementUp, "%p,%p", tv, tl); AG_MenuActionKb(mi, _("Move down"), agIconDown.s, AG_KEY_D, AG_KEYMOD_SHIFT, MoveElementDown, "%p,%p", tv, tl); } mi = AG_TlistSetPopup(tl, "sketch-element"); { AG_MenuAction(mi, _("Edit sketch element"), rgIconSketch.s, EditElement, "%p,%p", tv, tl); AG_MenuAction(mi, _("Delete sketch element"), agIconTrash.s, DeleteElement, "%p,%p,%i", tv, tl, 1); } #endif } static void CreateView(AG_Event *_Nonnull event) { RG_Tileset *ts = RG_TILESET_PTR(1); RG_Tile *t = AG_PTR(2); AG_Window *pWin = AG_WINDOW_PTR(3); AG_Window *win; RG_Tileview *tv; if ((win = AG_WindowNew(0)) == NULL) { return; } AG_WindowSetCaption(win, "%s <%s>", t->name, OBJECT(ts)->name); AG_WindowSetPosition(win, AG_WINDOW_UPPER_CENTER, 0); tv = RG_TileviewNew(win, ts, RG_TILEVIEW_READONLY); RG_TileviewSetTile(tv, t); AG_WindowAttach(pWin, win); AG_WindowShow(win); } AG_Window * RG_TileEdit(RG_Tileset *ts, RG_Tile *t) { AG_Window *win; AG_Menu *me; AG_MenuItem *mi; RG_Tileview *tv; AG_Tlist *tlFeatures; AG_Toolbar *tbar; AG_Button *btn; AG_Pane *pane; if ((win = AG_WindowNewNamed(0, "tile-%s:%s", OBJECT(ts)->name, t->name)) == NULL) { return (NULL); } AG_WindowSetCaption(win, "%s <%s>", t->name, OBJECT(ts)->name); AG_WindowSetPosition(win, AG_WINDOW_CENTER, 1); AG_WindowSetCloseAction(win, AG_WINDOW_DETACH); AG_SetSpacing(win, "0"); AG_SetStyleF(win, "padding", "0 %d %d %d", WIDGET(win)->paddingRight, WIDGET(win)->paddingBottom, WIDGET(win)->paddingLeft); tv = RG_TileviewNew(NULL, ts, 0); RG_TileviewSetTile(tv, t); RG_TileScale(ts, t, t->su->w, t->su->h); #if 0 { extern RG_TileviewSketchToolOps sketch_line_ops; extern RG_TileviewSketchToolOps sketch_polygon_ops; extern RG_TileviewSketchToolOps sketch_circle_ops; RG_TileviewRegTool(tv, &sketch_line_ops); RG_TileviewRegTool(tv, &sketch_polygon_ops); RG_TileviewRegTool(tv, &sketch_circle_ops); } #endif tlFeatures = AG_TlistNew(NULL, AG_TLIST_POLL | AG_TLIST_VFILL); AG_TlistSizeHint(tlFeatures, _("FEATURE #00 <#00>"), 5); AG_SetEvent(tlFeatures, "tlist-poll", PollFeatures, "%p,%p,%p,%p", ts, t, win, tv); InitTileFeatureMenu(tv, tlFeatures); me = AG_MenuNew(win, AG_MENU_HFILL); tbar = AG_ToolbarNew(NULL, AG_TOOLBAR_HORIZ, 1, 0); mi = AG_MenuNode(me->root, ("File"), NULL); { AG_MenuAction(mi, _("Import image file..."), agIconLoad.s, ImportImageDlg, "%p", tv); AG_MenuAction(mi, _("Export image file..."), agIconSave.s, ExportImageDlg, "%p", tv); AG_MenuSeparator(mi); AG_MenuActionKb(mi, _("Close tileset"), agIconClose.s, AG_KEY_W, AG_KEYMOD_CTRL, AGWINCLOSE(win)); } mi = AG_MenuNode(me->root, _("Edit"), NULL); { AG_MenuActionKb(mi, _("Undo"), NULL, AG_KEY_Z, AG_KEYMOD_CTRL, Undo, "%p", tv); AG_MenuActionKb(mi, _("Redo"), NULL, AG_KEY_R, AG_KEYMOD_CTRL, Redo, "%p", tv); AG_MenuSeparator(mi); AG_MenuAction(mi, _("Tile settings..."), rgIconPixmapResize.s, TileSettingsDlg, "%p", tv); } mi = AG_MenuNode(me->root, _("Features"), NULL); { AG_MenuTool(mi, tbar, _("Fill"), rgIconFill.s, AG_KEY_F, AG_KEYMOD_CTRL|AG_KEYMOD_SHIFT, AddFillFeature, "%p,%p", tv, tlFeatures); #if 0 AG_MenuActionKb(mi, _("Sketch projection"), rgIconSketchProj.s, AG_KEY_S, AG_KEYMOD_CTRL|AG_KEYMOD_SHIFT, AddSketchProjFeature, "%p,%p", tv, tlFeatures); #endif } mi = AG_MenuNode(me->root, _("View"), NULL); { AG_MenuAction(mi, _("Create view..."), rgIconMagnifier.s, CreateView, "%p,%p,%p", tv->ts, tv->tile, win); } mi = AG_MenuNode(me->root, _("Pixmaps"), NULL); { AG_MenuTool(mi, tbar, _("Create pixmap"), rgIconPixmap.s, 0, 0, CreatePixmap, "%p,%p", tv, tlFeatures); AG_MenuAction(mi, _("Attach existing pixmap..."), rgIconPixmapAttach.s, AttachPixmapDlg, "%p,%p", tv, tlFeatures); } #if 0 mi = AG_MenuNode(me->root, _("Sketches"), NULL); { AG_MenuTool(mi, tbar, _("Create sketch..."), rgIconSketch.s, 0, 0, CreateSketch, "%p,%p", tv, tlFeatures); AG_MenuAction(mi, _("Attach sketch..."), rgIconSketchAttach.s, AttachSketchDlg, "%p,%p", tv, tlFeatures); } #endif pane = AG_PaneNewHoriz(win, AG_PANE_EXPAND); { AG_ObjectAttach(pane->div[0], tlFeatures); WIDGET(tlFeatures)->flags |= AG_WIDGET_HFILL; btn = AG_ButtonNewS(pane->div[0], AG_BUTTON_STICKY|AG_BUTTON_HFILL, _("Edit")); WIDGET(btn)->flags |= AG_WIDGET_HFILL; AG_BindInt(btn, "state", &tv->edit_mode); AG_SetEvent(btn, "button-pushed", EditElement, "%p,%p", tv, tlFeatures); AG_SetEvent(tlFeatures, "tlist-dblclick", EditElement, "%p,%p", tv, tlFeatures); AG_ObjectAttach(pane->div[1], tbar); tv->tel_box = AG_BoxNew(pane->div[1], AG_BOX_HORIZ, AG_BOX_EXPAND); AG_ObjectAttach(tv->tel_box, tv); AG_WidgetFocus(tv); } /* Set the tile edition mode. */ CloseElement(tv); AG_WindowSetGeometryAlignedPct(win, AG_WINDOW_MC, 70, 50); /* Center the tile. */ tv->xoffs = (WIDGET(tv)->w - t->su->w)/2; tv->yoffs = (WIDGET(tv)->h - t->su->h)/2; return (win); } void RG_TileOpenMenu(RG_Tileview *tv, int x, int y) { if (tv->menu != NULL) { goto out; } tv->menu = AG_PopupNew(tv); RG_TileviewGenericMenu(tv, tv->menu->root); out: AG_PopupShowAt(tv->menu, x,y); } void RG_TileCloseMenu(RG_Tileview *tv) { if (tv->menu != NULL) { AG_PopupDestroy(tv->menu); tv->menu = NULL; } }