/* * Copyright (c) 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 "socket.h" #include "icon.h" #include "window.h" #include "primitive.h" #include "label.h" #include "pixmap.h" #include static void SetState(AG_Variable *, void *, int); static void MouseMotion(AG_Event *); static void MouseButtonUp(AG_Event *); static void MouseButtonDown(AG_Event *); AG_Socket * AG_SocketNew(void *parent, Uint flags) { AG_Socket *sock; sock = Malloc(sizeof(AG_Socket)); AG_ObjectInit(sock, &agSocketClass); sock->flags |= flags; if (flags & AG_SOCKET_HFILL) { AG_ExpandHoriz(sock); } if (flags & AG_SOCKET_VFILL) { AG_ExpandVert(sock); } AG_ObjectAttach(parent, sock); return (sock); } AG_Socket * AG_SocketFromSurface(void *parent, Uint flags, AG_Surface *su) { AG_Socket *sock; sock = AG_SocketNew(parent, flags); AG_SocketBgPixmap(sock, su); return (sock); } AG_Socket * AG_SocketFromBMP(void *parent, Uint flags, const char *bmpfile) { AG_Socket *sock; AG_Surface *bmp; if ((bmp = AG_SurfaceFromBMP(bmpfile)) == NULL) { return (NULL); } sock = AG_SocketNew(parent, flags); AG_SocketBgPixmapNODUP(sock, bmp); return (sock); } static void Init(void *obj) { AG_Socket *sock = obj; WIDGET(sock)->flags |= AG_WIDGET_FOCUSABLE| AG_WIDGET_UNFOCUSED_MOTION| AG_WIDGET_UNFOCUSED_BUTTONUP; AG_BindInt(sock, "state", &sock->state); AG_BindInt(sock, "count", &sock->count); sock->flags = 0; sock->state = 0; sock->count = 0; sock->bgType = AG_SOCKET_RECT; sock->bgData.rect.w = 32; sock->bgData.rect.h = 32; sock->lblJustify = AG_TEXT_LEFT; sock->lPad = 2; sock->rPad = 2; sock->tPad = 2; sock->bPad = 2; sock->icon = NULL; sock->insertFn = NULL; sock->removeFn = NULL; sock->overlayFn = NULL; AG_SetEvent(sock, "window-mousebuttonup", MouseButtonUp, NULL); AG_SetEvent(sock, "window-mousebuttondown", MouseButtonDown, NULL); AG_SetEvent(sock, "window-mousemotion", MouseMotion, NULL); } void AG_SocketInsertFn(AG_Socket *sock, int (*fn)(AG_Socket *, AG_Icon *)) { AG_ObjectLock(sock); sock->insertFn = fn; AG_ObjectUnlock(sock); } void AG_SocketRemoveFn(AG_Socket *sock, void (*fn)(AG_Socket *, AG_Icon *)) { AG_ObjectLock(sock); sock->removeFn = fn; AG_ObjectUnlock(sock); } void AG_SocketOverlayFn(AG_Socket *sock, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(sock); if (sock->overlayFn != NULL) { AG_UnsetEvent(sock->overlayFn, sock->overlayFn->name); } sock->overlayFn = AG_SetEvent(sock, NULL, fn, NULL); AG_EVENT_GET_ARGS(sock->overlayFn, fmt); AG_ObjectUnlock(sock); } static void SizeRequest(void *obj, AG_SizeReq *r) { AG_Socket *sock = obj; switch (sock->bgType) { case AG_SOCKET_PIXMAP: r->w = WSURFACE(sock,sock->bgData.pixmap.s)->w; r->h = WSURFACE(sock,sock->bgData.pixmap.s)->h; break; case AG_SOCKET_RECT: r->w = sock->bgData.rect.w; r->h = sock->bgData.rect.h; break; case AG_SOCKET_CIRCLE: r->w = sock->bgData.circle.r*2; r->h = sock->bgData.circle.r*2; break; } r->w += sock->lPad + sock->rPad; r->h += sock->tPad + sock->bPad; } static int SizeAllocate(void *obj, const AG_SizeAlloc *a) { AG_Socket *sock = obj; if (a->w < (sock->lPad + sock->rPad) || a->h < (sock->tPad + sock->bPad)) { return (-1); } return (0); } static __inline__ int GetState(AG_Variable *binding, void *p) { switch (AG_VARIABLE_TYPE(binding)) { case AG_VARIABLE_INT: return *(int *)p; case AG_VARIABLE_UINT8: return (int)(*(Uint8 *)p); case AG_VARIABLE_UINT16: return (int)(*(Uint16 *)p); case AG_VARIABLE_UINT32: return (int)(*(Uint32 *)p); case AG_VARIABLE_P_FLAG: return (*(int *)p & (int)binding->info.bitmask); case AG_VARIABLE_P_FLAG8: return (int)(*(Uint8 *)p & (Uint8)binding->info.bitmask); case AG_VARIABLE_P_FLAG16: return (int)(*(Uint16 *)p & (Uint16)binding->info.bitmask); case AG_VARIABLE_P_FLAG32: return (int)(*(Uint32 *)p & (Uint32)binding->info.bitmask); default: return (-1); } return (-1); } static __inline__ int GetCount(AG_Variable *binding, void *p) { switch (AG_VARIABLE_TYPE(binding)) { case AG_VARIABLE_UINT: return (Uint)(*(int *)p); case AG_VARIABLE_INT: return *(int *)p; case AG_VARIABLE_UINT8: return (int)(*(Uint8 *)p); case AG_VARIABLE_SINT8: return (int)(*(Sint8 *)p); case AG_VARIABLE_UINT16: return (int)(*(Uint16 *)p); case AG_VARIABLE_SINT16: return (int)(*(Sint16 *)p); case AG_VARIABLE_UINT32: return (int)(*(Uint32 *)p); case AG_VARIABLE_SINT32: return (int)(*(Sint32 *)p); default: return (-1); } return (-1); } static void Draw(void *obj) { AG_Socket *sock = obj; AG_Variable *binding; void *pBinding; int state, count; binding = AG_GetVariable(sock, "state", &pBinding); state = GetState(binding, pBinding); AG_UnlockVariable(binding); binding = AG_GetVariable(sock, "count", &pBinding); count = GetCount(binding, pBinding); AG_UnlockVariable(binding); STYLE(sock)->SocketBackground(sock); if (sock->icon != NULL) { AGWIDGET_OPS(sock->icon)->draw(sock->icon); } if (sock->overlayFn != NULL) { AG_PostEvent(NULL, sock->overlayFn, sock->overlayFn->name, NULL); } else { STYLE(sock)->SocketOverlay(sock, state); } } static void SetState(AG_Variable *binding, void *p, int v) { switch (AG_VARIABLE_TYPE(binding)) { case AG_VARIABLE_INT: *(int *)p = v; break; case AG_VARIABLE_UINT8: *(Uint8 *)p = v; break; case AG_VARIABLE_UINT16: *(Uint16 *)p = v; break; case AG_VARIABLE_UINT32: *(Uint32 *)p = v; break; case AG_VARIABLE_P_FLAG: AG_SETFLAGS(*(int *)p, (int)binding->info.bitmask, v); break; case AG_VARIABLE_P_FLAG8: AG_SETFLAGS(*(Uint8 *)p, (Uint8)binding->info.bitmask, v); break; case AG_VARIABLE_P_FLAG16: AG_SETFLAGS(*(Uint16 *)p, (Uint16)binding->info.bitmask, v); break; case AG_VARIABLE_P_FLAG32: AG_SETFLAGS(*(Uint32 *)p, (Uint32)binding->info.bitmask, v); break; default: break; } } #if 0 static void SetCount(AG_Variable *binding, void *p, int v) { switch (AG_VARIABLE_TYPE(binding)) { case AG_VARIABLE_UINT: *(Uint *)p = v; break; case AG_VARIABLE_INT: *(int *)p = v; break; case AG_VARIABLE_UINT8: *(Uint8 *)p = v; break; case AG_VARIABLE_SINT8: *(Sint8 *)p = v; break; case AG_VARIABLE_UINT16: *(Uint16 *)p = v; break; case AG_VARIABLE_SINT16: *(Sint16 *)p = v; break; case AG_VARIABLE_UINT32: *(Uint32 *)p = v; break; case AG_VARIABLE_SINT32: *(Sint32 *)p = v; break; } } #endif static void MouseMotion(AG_Event *event) { AG_Socket *sock = AG_SELF(); AG_Variable *binding; int x = AG_INT(1); int y = AG_INT(2); void *pState; if (AG_WidgetDisabled(sock)) return; binding = AG_GetVariable(sock, "state", &pState); if (!AG_WidgetRelativeArea(sock, x, y)) { if ((sock->flags & AG_SOCKET_STICKY_STATE) == 0 && GetState(binding, pState) == 1) { SetState(binding, pState, 0); } if (sock->flags & AG_SOCKET_MOUSEOVER) { sock->flags &= ~(AG_SOCKET_MOUSEOVER); AG_PostEvent(NULL, sock, "socket-mouseoverlap", "%i", 0); } } else { sock->flags |= AG_SOCKET_MOUSEOVER; AG_PostEvent(NULL, sock, "socket-mouseoverlap", "%i", 1); } AG_UnlockVariable(binding); } static void IconMotion(AG_Event *event) { AG_Icon *icon = AG_PTR(1); int xRel = AG_INT(4); int yRel = AG_INT(5); AG_Window *wDND = icon->wDND; AG_WindowSetGeometryRect(wDND, AG_RECT(WIDGET(wDND)->x + xRel, WIDGET(wDND)->y + yRel, WIDTH(wDND), HEIGHT(wDND)), 1); } static void IconButtonUp(AG_Event *event) { AG_Icon *icon = AG_PTR(1); AG_Window *wDND = icon->wDND; int x = WIDGET(wDND)->rView.x1; int y = WIDGET(wDND)->rView.y1; AG_Socket *sock; int detach = 1; sock = AG_WidgetFindRect("AG_Widget:AG_Socket:*", x, y, WIDGET(wDND)->w, WIDGET(wDND)->h); if (sock != NULL) { AG_ObjectLock(sock); if (sock->insertFn != NULL) { detach = sock->insertFn(sock, icon); } else { if (icon->sock != NULL) { AG_SocketRemoveIcon(icon->sock); } AG_SocketInsertIcon(sock, icon); } AG_ObjectUnlock(sock); } if (detach) AG_ViewDetach(wDND); } static void MouseButtonDown(AG_Event *event) { AG_Socket *sock = AG_SELF(); int button = AG_INT(1); AG_Variable *binding; void *pState; int newState; AG_Icon *icon; if (AG_WidgetDisabled(sock) || button != SDL_BUTTON_LEFT) { return; } AG_WidgetFocus(sock); binding = AG_GetVariable(sock, "state", &pState); if (!(sock->flags & AG_SOCKET_STICKY_STATE)) { SetState(binding, pState, 1); } else { newState = !GetState(binding, pState); SetState(binding, pState, newState); AG_PostEvent(NULL, sock, "socket-click", "%i", newState); } AG_UnlockVariable(binding); if ((icon = sock->icon) != NULL) { AG_Pixmap *px; icon->wDND = AG_WindowNew(AG_WINDOW_PLAIN| AG_WINDOW_NOBACKGROUND| AG_WINDOW_NOUPDATERECT); px = AG_PixmapFromSurfaceCopy(icon->wDND, 0, WSURFACE(icon,icon->surface)); AG_ObjectLock(px); WIDGET(px)->flags |= AG_WIDGET_UNFOCUSED_MOTION| AG_WIDGET_UNFOCUSED_BUTTONUP; AG_SetEvent(px, "window-mousemotion", IconMotion,"%p",icon); AG_SetEvent(px, "window-mousebuttonup", IconButtonUp,"%p",icon); AG_ObjectUnlock(px); AG_WindowSetGeometry(icon->wDND, WIDGET(icon)->rView.x1, WIDGET(icon)->rView.y1, WIDTH(icon), HEIGHT(icon)); AG_WindowShow(icon->wDND); } } static void MouseButtonUp(AG_Event *event) { AG_Socket *sock = AG_SELF(); int button = AG_INT(1); AG_Variable *binding; void *pState; int x = AG_INT(2); int y = AG_INT(3); if (AG_WidgetDisabled(sock) || x < 0 || y < 0 || x > WIDGET(sock)->w || y > WIDGET(sock)->h) { return; } binding = AG_GetVariable(sock, "state", &pState); if (GetState(binding, pState) && button == SDL_BUTTON_LEFT && !(sock->flags & AG_SOCKET_STICKY_STATE)) { SetState(binding, pState, 0); AG_PostEvent(NULL, sock, "socket-click", "%i", 0); } AG_UnlockVariable(binding); } void AG_SocketSetPadding(AG_Socket *sock, int lPad, int rPad, int tPad, int bPad) { AG_ObjectLock(sock); if (lPad != -1) { sock->lPad = lPad; } if (rPad != -1) { sock->rPad = rPad; } if (tPad != -1) { sock->tPad = tPad; } if (bPad != -1) { sock->bPad = bPad; } AG_ObjectUnlock(sock); } void AG_SocketBgRect(AG_Socket *sock, Uint w, Uint h) { AG_ObjectLock(sock); sock->bgType = AG_SOCKET_RECT; sock->bgData.rect.w = w; sock->bgData.rect.h = h; AG_ObjectUnlock(sock); } void AG_SocketBgCircle(AG_Socket *sock, Uint r) { AG_ObjectLock(sock); sock->bgType = AG_SOCKET_RECT; sock->bgData.circle.r = r; AG_ObjectUnlock(sock); } void AG_SocketBgPixmap(AG_Socket *sock, AG_Surface *su) { AG_Surface *suDup = (su != NULL) ? AG_DupSurface(su) : NULL; AG_ObjectLock(sock); sock->bgType = AG_SOCKET_PIXMAP; sock->bgData.pixmap.s = AG_WidgetMapSurface(sock, suDup); AG_ObjectUnlock(sock); } void AG_SocketBgPixmapNODUP(AG_Socket *sock, AG_Surface *su) { AG_ObjectLock(sock); sock->bgType = AG_SOCKET_PIXMAP; sock->bgData.pixmap.s = AG_WidgetMapSurface(sock, su); AG_ObjectUnlock(sock); } void AG_SocketInsertIcon(AG_Socket *sock, AG_Icon *icon) { AG_SizeAlloc a; AG_ObjectLock(sock); AG_ObjectLock(icon); sock->icon = icon; icon->sock = sock; a.w = WIDGET(sock)->w; a.h = WIDGET(sock)->h; a.x = WIDGET(sock)->rView.x1; a.y = WIDGET(sock)->rView.y1; AG_WidgetSizeAlloc(icon, &a); AG_WidgetUpdateCoords(icon, a.x, a.y); AG_ObjectUnlock(icon); AG_ObjectUnlock(sock); } void AG_SocketRemoveIcon(AG_Socket *sock) { AG_ObjectLock(sock); if (sock->icon != NULL) { AG_ObjectLock(sock->icon); if (sock->removeFn != NULL) { sock->removeFn(sock, sock->icon); AG_ObjectUnlock(sock->icon); goto out; } sock->icon->sock = NULL; AG_ObjectUnlock(sock->icon); } sock->icon = NULL; out: AG_ObjectUnlock(sock); } AG_WidgetClass agSocketClass = { { "Agar(Widget:Socket)", sizeof(AG_Socket), { 0,0 }, Init, NULL, /* free */ NULL, /* destroy */ NULL, /* load */ NULL, /* save */ NULL /* edit */ }, Draw, SizeRequest, SizeAllocate };