/*
* Copyright (c) 2005-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
#if 0
#include "load_xcf.h"
#endif
#include "pixmap.h"
#include "primitive.h"
AG_Pixmap *
AG_PixmapNew(void *parent, Uint flags, Uint w, Uint h)
{
AG_Pixmap *px;
px = Malloc(sizeof(AG_Pixmap));
AG_ObjectInit(px, &agPixmapClass);
px->flags |= flags;
px->flags |= AG_PIXMAP_FORCE_SIZE;
px->pre_w = w;
px->pre_h = h;
if (flags & AG_PIXMAP_HFILL) { AG_ExpandHoriz(px); }
if (flags & AG_PIXMAP_VFILL) { AG_ExpandVert(px); }
AG_WidgetMapSurface(px, AG_SurfaceEmpty());
AG_ObjectAttach(parent, px);
return (px);
}
AG_Pixmap *
AG_PixmapFromSurface(void *parent, Uint flags, AG_Surface *su)
{
AG_Pixmap *px;
px = Malloc(sizeof(AG_Pixmap));
AG_ObjectInit(px, &agPixmapClass);
px->flags |= flags;
if (flags & AG_PIXMAP_HFILL) { AG_ExpandHoriz(px); }
if (flags & AG_PIXMAP_VFILL) { AG_ExpandVert(px); }
AG_ObjectAttach(parent, px);
AG_WidgetMapSurface(px, su);
return (px);
}
AG_Pixmap *
AG_PixmapFromSurfaceCopy(void *parent, Uint flags, AG_Surface *su)
{
AG_Pixmap *px;
px = Malloc(sizeof(AG_Pixmap));
AG_ObjectInit(px, &agPixmapClass);
px->flags |= flags;
if (flags & AG_PIXMAP_HFILL) { AG_ExpandHoriz(px); }
if (flags & AG_PIXMAP_VFILL) { AG_ExpandVert(px); }
AG_ObjectAttach(parent, px);
AG_WidgetMapSurface(px, AG_DupSurface(su)); /* XXX leak */
return (px);
}
AG_Pixmap *
AG_PixmapFromSurfaceScaled(void *parent, Uint flags, AG_Surface *su,
Uint w, Uint h)
{
AG_Pixmap *px;
AG_Surface *su2 = NULL;
px = Malloc(sizeof(AG_Pixmap));
AG_ObjectInit(px, &agPixmapClass);
px->flags |= flags;
if (flags & AG_PIXMAP_HFILL) { AG_ExpandHoriz(px); }
if (flags & AG_PIXMAP_VFILL) { AG_ExpandVert(px); }
AG_ObjectAttach(parent, px);
if (AG_ScaleSurface(su, w, h, &su2) == -1) {
AG_FatalError(NULL);
}
AG_WidgetMapSurface(px, su2);
return (px);
}
AG_Pixmap *
AG_PixmapFromBMP(void *parent, Uint flags, const char *bmpfile)
{
AG_Pixmap *px;
AG_Surface *bmp;
if ((bmp = AG_SurfaceFromBMP(bmpfile)) == NULL) {
return (NULL);
}
px = Malloc(sizeof(AG_Pixmap));
AG_ObjectInit(px, &agPixmapClass);
px->flags |= flags;
if (flags & AG_PIXMAP_HFILL) { AG_ExpandHoriz(px); }
if (flags & AG_PIXMAP_VFILL) { AG_ExpandVert(px); }
AG_ObjectAttach(parent, px);
AG_WidgetMapSurface(px, bmp);
return (px);
}
/*
* Map an existing surface. Returned surface ID is valid as long as pixmap
* is locked.
*/
int
AG_PixmapAddSurface(AG_Pixmap *px, AG_Surface *su)
{
int name;
AG_ObjectLock(px);
name = AG_WidgetMapSurfaceNODUP(px, su);
px->flags |= AG_PIXMAP_UPDATE;
AG_ObjectUnlock(px);
return (name);
}
/*
* Map an existing surface from a BMP file. Returned surface ID is valid as
* long as pixmap is locked.
*/
int
AG_PixmapAddSurfaceFromBMP(AG_Pixmap *px, const char *path)
{
AG_Surface *bmp;
int name;
if ((bmp = AG_SurfaceFromBMP(path)) == NULL) {
return (-1);
}
AG_ObjectLock(px);
name = AG_WidgetMapSurface(px, bmp);
px->flags |= AG_PIXMAP_UPDATE;
AG_ObjectUnlock(px);
return (name);
}
/*
* Create a copy of a surface and map it. Returned surface ID is valid as
* long as pixmap is locked.
*/
int
AG_PixmapAddSurfaceCopy(AG_Pixmap *px, AG_Surface *su)
{
AG_Surface *dup;
int name;
dup = AG_DupSurface(su);
AG_ObjectLock(px);
name = AG_WidgetMapSurface(px, dup);
px->flags |= AG_PIXMAP_UPDATE;
AG_ObjectUnlock(px);
return (name);
}
/*
* Create a scaled version of a surface and map it. Returned surface ID
* is valid as long as pixmap is locked.
*/
int
AG_PixmapAddSurfaceScaled(AG_Pixmap *px, AG_Surface *su, Uint w, Uint h)
{
AG_Surface *scaled = NULL;
int name;
if (AG_ScaleSurface(su, w, h, &scaled) == -1) {
AG_FatalError(NULL);
}
AG_ObjectLock(px);
name = AG_WidgetMapSurface(px, scaled);
px->flags |= AG_PIXMAP_UPDATE;
AG_ObjectUnlock(px);
return (name);
}
/* Replace the specified surface with a scaled version of another surface. */
void
AG_PixmapReplaceSurfaceScaled(AG_Pixmap *px, int surface_name, AG_Surface *su,
Uint w, Uint h)
{
AG_Surface *scaled = NULL;
if (AG_ScaleSurface(su, w, h, &scaled) == -1) {
AG_FatalError(NULL);
}
AG_ObjectLock(px);
AG_WidgetReplaceSurface(px, surface_name, scaled);
if (surface_name == px->n) { px->flags |= AG_PIXMAP_UPDATE; }
AG_ObjectUnlock(px);
}
static void
Init(void *obj)
{
AG_Pixmap *px = obj;
px->flags = AG_PIXMAP_UPDATE;
px->n = 0;
px->s = 0;
px->t = 0;
px->pre_w = 64;
px->pre_h = 64;
px->rClip = AG_RECT(0,0,0,0);
px->sScaled = -1;
}
static void
SizeRequest(void *obj, AG_SizeReq *r)
{
AG_Pixmap *px = obj;
if ((px->flags & AG_PIXMAP_FORCE_SIZE) == 0) {
r->w = WSURFACE(px,px->n)->w;
r->h = WSURFACE(px,px->n)->h;
} else {
r->w = px->pre_w;
r->h = px->pre_h;
}
}
static int
SizeAllocate(void *obj, const AG_SizeAlloc *a)
{
AG_Pixmap *px = obj;
if (a->w < 1 || a->h < 1) {
return (-1);
}
px->rClip.w = a->w;
px->rClip.h = a->h;
px->flags |= AG_PIXMAP_UPDATE;
return (0);
}
static void
UpdateScaled(AG_Pixmap *px)
{
AG_Surface *scaled = NULL;
if (px->n < 0 || WIDTH(px) == 0 || HEIGHT(px) == 0) {
goto fail;
}
if (AG_ScaleSurface(WSURFACE(px,px->n), WIDTH(px), HEIGHT(px), &scaled)
== -1) {
goto fail;
}
if (px->sScaled == -1) {
px->sScaled = AG_WidgetMapSurface(px, scaled);
} else {
AG_WidgetReplaceSurface(px, px->sScaled, scaled);
}
return;
fail:
if (px->sScaled != -1) {
AG_WidgetUnmapSurface(px, px->sScaled);
px->sScaled = -1;
}
}
static void
Draw(void *obj)
{
AG_Pixmap *px = obj;
if (px->n < 0)
return;
if (px->flags & AG_PIXMAP_RESCALE) {
if (px->flags & AG_PIXMAP_UPDATE) {
UpdateScaled(px);
px->flags &= ~(AG_PIXMAP_UPDATE);
}
AG_WidgetBlitSurface(px, px->sScaled, px->s, px->t);
} else {
AG_PushClipRect(px, px->rClip);
AG_WidgetBlitSurface(px, px->n, px->s, px->t);
AG_PopClipRect();
}
}
AG_WidgetClass agPixmapClass = {
{
"Agar(Widget:Pixmap)",
sizeof(AG_Pixmap),
{ 0,0 },
Init,
NULL, /* free */
NULL, /* destroy */
NULL, /* load */
NULL, /* save */
NULL /* edit */
},
Draw,
SizeRequest,
SizeAllocate
};