/* * Copyright (c) 2008 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. */ /* * Schematic block entity. Blocks represent groups of entities which remain * rigid across transformations and are specific to a component. Components * may create one or more blocks on attach. */ #include "core.h" #include #include static void Init(void *p) { ES_SchemBlock *sb = p; sb->name[0] = '\0'; sb->com = NULL; } static int Load(void *p, AG_DataSource *ds, const AG_Version *ver) { ES_SchemBlock *sb = p; (void)AG_ReadUint32(ds); /* flags */ AG_CopyString(sb->name, ds, sizeof(sb->name)); return (0); } static void Save(void *p, AG_DataSource *ds) { ES_SchemBlock *sb = p; AG_WriteUint32(ds, 0); /* flags */ AG_WriteString(ds, sb->name); } static void GetNodeExtent(VG_Node *vn, VG_View *vv, VG_Vector *aBlk, VG_Vector *bBlk) { VG_Vector a, b; VG_Node *vnChld; if (vn->ops->extent != NULL) { vn->ops->extent(vn, vv, &a, &b); } if (a.x < aBlk->x) { aBlk->x = a.x; } if (a.y < aBlk->y) { aBlk->y = a.y; } if (b.x > bBlk->x) { bBlk->x = b.x; } if (b.y > bBlk->y) { bBlk->y = b.y; } VG_FOREACH_CHLD(vnChld, vn, vg_node) GetNodeExtent(vnChld, vv, aBlk, bBlk); } static void Extent(void *p, VG_View *vv, VG_Vector *a, VG_Vector *b) { ES_SchemBlock *sb = p; VG_Vector vPos = VG_Pos(sb); VG_Node *vnChld; a->x = vPos.x; a->y = vPos.y; b->x = vPos.x; b->y = vPos.y; VG_FOREACH_CHLD(vnChld, sb, vg_node) GetNodeExtent(vnChld, vv, a, b); } static void Draw(void *p, VG_View *vv) { ES_SchemBlock *sb = p; AG_Rect rDraw; VG_Vector a, b; AG_Color c; if (sb->com->flags & (ES_COMPONENT_SELECTED | ES_COMPONENT_HIGHLIGHTED)) { const float wPixel4 = vv->wPixel*4.0f; Extent(sb, vv, &a, &b); a.x -= wPixel4; a.y -= wPixel4; b.x += wPixel4; b.y += wPixel4; VG_GetViewCoords(vv, a, &rDraw.x, &rDraw.y); rDraw.w = (b.x - a.x)*vv->scale; rDraw.h = (b.y - a.y)*vv->scale; if (sb->com->flags & ES_COMPONENT_SELECTED) { AG_ColorRGBA_8(&c, 0,255,0, 64); AG_DrawRectBlended(vv, &rDraw, &c, AG_ALPHA_SRC, AG_ALPHA_ONE_MINUS_SRC); } if (sb->com->flags & ES_COMPONENT_HIGHLIGHTED) { AG_Color c; c = VG_MapColorRGB(VGNODE(sb)->color); AG_DrawRectOutline(vv, &rDraw, &c); } } } static float PointProximity(void *p, VG_View *vv, VG_Vector *vPt) { ES_SchemBlock *sb = p; float x = vPt->x; float y = vPt->y; VG_Vector a, b, c, d; float len; Extent(sb, vv, &a, &c); a.x -= vv->wPixel*4; a.y -= vv->wPixel*4; c.x += vv->wPixel*4; c.y += vv->wPixel*4; b.x = c.x; b.y = a.y; d.x = a.x; d.y = c.y; if (x >= a.x && x <= c.x && y >= a.y && y <= c.y) return (0.0f); if (y < a.y) { if (x < a.x) { len = VG_Distance(a, *vPt); *vPt = a; return (len); } else if (x > c.x) { len = VG_Distance(b, *vPt); *vPt = b; return (len); } else { return VG_PointLineDistance(a,b, vPt); } } else if (y > c.y) { if (x > c.x) { len = VG_Distance(c, *vPt); *vPt = c; return (len); } else if (x < a.x) { len = VG_Distance(d, *vPt); *vPt = d; return (len); } else { return VG_PointLineDistance(d,c, vPt); } } else { if (x < a.x) { return VG_PointLineDistance(a,d, vPt); } else if (x > c.x) { return VG_PointLineDistance(b,c, vPt); } } return (HUGE_VAL); } static void Move(void *p, VG_Vector vPos, VG_Vector vRel) { ES_SchemBlock *sb = p; VG_Matrix T; T = VGNODE(sb)->T; VG_LoadIdentity(sb); VG_Translate(sb, vRel); VG_MultMatrix(&VGNODE(sb)->T, &T); } /* Load the contents of the specified VG file into a SchemBlock. */ int ES_SchemBlockLoad(ES_SchemBlock *sb, const char *path) { ES_Schem *scm; scm = ES_SchemNew(NULL); if (AG_ObjectLoadFromFile(scm, path) == -1) { return (-1); } VG_Merge(sb, scm->vg); AG_ObjectDestroy(scm); return (0); } VG_NodeOps esSchemBlockOps = { N_("SchemBlock"), &esIconComponent, sizeof(ES_SchemBlock), Init, NULL, /* destroy */ Load, Save, Draw, Extent, PointProximity, NULL, /* lineProximity */ NULL, /* delete */ Move, NULL /* edit */ };