/* * Copyright (c) 2003-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. */ /* * LEGACY: Use AG_Numerical(3) instead of this widget. */ #include #include "spinbutton.h" #include "window.h" #include "primitive.h" #include #include AG_Spinbutton * AG_SpinbuttonNew(void *parent, Uint flags, const char *label) { AG_Spinbutton *sbu; sbu = Malloc(sizeof(AG_Spinbutton)); AG_ObjectInit(sbu, &agSpinbuttonClass); if (label != NULL) { AG_TextboxSetLabel(sbu->input, "%s", label); } if (!(flags & AG_SPINBUTTON_NOHFILL)) { AG_ExpandHoriz(sbu); } if ( flags & AG_SPINBUTTON_VFILL) { AG_ExpandVert(sbu); } AG_ObjectAttach(parent, sbu); return (sbu); } static void Bound(AG_Event *event) { AG_Spinbutton *sbu = AG_SELF(); AG_Variable *binding = AG_PTR(1); if (strcmp(binding->name, "value") == 0) { switch (AG_VARIABLE_TYPE(binding)) { case AG_VARIABLE_INT: sbu->min = AG_INT_MIN+1; sbu->max = AG_INT_MAX-1; break; case AG_VARIABLE_UINT: sbu->min = 0; sbu->max = AG_UINT_MAX-1; break; case AG_VARIABLE_UINT8: sbu->min = 0; sbu->max = 0xffU; break; case AG_VARIABLE_SINT8: sbu->min = -0x7f+1; sbu->max = 0x7f-1; break; case AG_VARIABLE_UINT16: sbu->min = 0; sbu->max = 0xffffU; break; case AG_VARIABLE_SINT16: sbu->min = -0x7fff+1; sbu->max = 0x7fff-1; break; case AG_VARIABLE_UINT32: sbu->min = 0; sbu->max = 0xffffffffU; break; case AG_VARIABLE_SINT32: sbu->min = -0x7fffffff+1; sbu->max = 0x7fffffff-1; break; default: break; } } } static void KeyDown(AG_Event *event) { AG_Spinbutton *sbu = AG_SELF(); int keysym = AG_INT(1); switch (keysym) { case SDLK_UP: AG_SpinbuttonAddValue(sbu, sbu->incr); break; case SDLK_DOWN: AG_SpinbuttonAddValue(sbu, -sbu->incr); break; } } static void PostChange(AG_Event *event) { AG_Spinbutton *sbu = AG_PTR(1); AG_Variable *string; char *s; AG_ObjectLock(sbu); string = AG_GetVariable(sbu->input->ed, "string", &s); AG_SpinbuttonSetValue(sbu, atoi(s)); AG_UnlockVariable(string); AG_PostEvent(NULL, sbu, "spinbutton-changed", NULL); AG_ObjectUnlock(sbu); } static void Return(AG_Event *event) { AG_Spinbutton *sbu = AG_PTR(1); AG_ObjectLock(sbu); AG_PostEvent(NULL, sbu, "spinbutton-return", NULL); AG_WidgetUnfocus(sbu->input); AG_ObjectUnlock(sbu); } static void Increment(AG_Event *event) { AG_Spinbutton *sbu = AG_PTR(1); AG_ObjectLock(sbu); AG_SpinbuttonAddValue(sbu, sbu->incr); AG_PostEvent(NULL, sbu, "spinbutton-changed", NULL); AG_ObjectUnlock(sbu); } static void Decrement(AG_Event *event) { AG_Spinbutton *sbu = AG_PTR(1); AG_ObjectLock(sbu); AG_SpinbuttonAddValue(sbu, -sbu->incr); AG_PostEvent(NULL, sbu, "spinbutton-changed", NULL); AG_ObjectUnlock(sbu); } static void Init(void *obj) { AG_Spinbutton *sbu = obj; AG_BindInt(sbu, "value", &sbu->value); AG_BindInt(sbu, "min", &sbu->min); AG_BindInt(sbu, "max", &sbu->max); sbu->value = 0; sbu->incr = 1; sbu->writeable = 0; sbu->min = 0; sbu->max = 0; sbu->input = AG_TextboxNew(sbu, 0, NULL); AG_TextboxSizeHint(sbu->input, "8888"); AG_SetEvent(sbu, "bound", Bound, NULL); AG_SetEvent(sbu, "window-keydown", KeyDown, NULL); sbu->incbu = AG_ButtonNew(sbu, AG_BUTTON_REPEAT, _("+")); AG_ButtonSetPadding(sbu->incbu, 1, 1, 1, 1); sbu->decbu = AG_ButtonNew(sbu, AG_BUTTON_REPEAT, _("-")); AG_ButtonSetPadding(sbu->decbu, 1, 1, 1, 1); AG_WidgetSetFocusable(sbu->incbu, 0); AG_WidgetSetFocusable(sbu->decbu, 0); AG_SetEvent(sbu->input, "textbox-return", Return, "%p", sbu); AG_SetEvent(sbu->input, "textbox-postchg", PostChange, "%p", sbu); AG_SetEvent(sbu->incbu, "button-pushed", Increment, "%p", sbu); AG_SetEvent(sbu->decbu, "button-pushed", Decrement, "%p", sbu); } static void Draw(void *obj) { AG_Spinbutton *sbu = obj; AG_Variable *value; void *p; AG_WidgetDraw(sbu->input); AG_WidgetDraw(sbu->incbu); AG_WidgetDraw(sbu->decbu); if (AG_WidgetFocused(sbu->input)) { /* The value is being edited. */ return; } value = AG_GetVariable(sbu, "value", &p); switch (AG_VARIABLE_TYPE(value)) { case AG_VARIABLE_INT: AG_TextboxPrintf(sbu->input, "%d", *(int *)p); break; case AG_VARIABLE_UINT: AG_TextboxPrintf(sbu->input, "%u", *(Uint *)p); break; case AG_VARIABLE_UINT8: AG_TextboxPrintf(sbu->input, "%u", *(Uint8 *)p); break; case AG_VARIABLE_SINT8: AG_TextboxPrintf(sbu->input, "%d", *(Sint8 *)p); break; case AG_VARIABLE_UINT16: AG_TextboxPrintf(sbu->input, "%u", *(Uint16 *)p); break; case AG_VARIABLE_SINT16: AG_TextboxPrintf(sbu->input, "%d", *(Sint16 *)p); break; case AG_VARIABLE_UINT32: AG_TextboxPrintf(sbu->input, "%u", *(Uint32 *)p); break; case AG_VARIABLE_SINT32: AG_TextboxPrintf(sbu->input, "%d", *(Sint32 *)p); break; default: break; } AG_UnlockVariable(value); } static void SizeRequest(void *obj, AG_SizeReq *r) { AG_Spinbutton *num = obj; AG_SizeReq rChld, rInc, rDec; AG_WidgetSizeReq(num->input, &rChld); r->w = rChld.w; r->h = rChld.h; AG_WidgetSizeReq(num->incbu, &rInc); AG_WidgetSizeReq(num->decbu, &rDec); r->w += MAX(rInc.w, rDec.w); } static int SizeAllocate(void *obj, const AG_SizeAlloc *a) { AG_Spinbutton *num = obj; AG_SizeAlloc aChld; AG_SizeReq rUnits; int szBtn = a->h/2; if (a->h < 4 || a->w < szBtn+4) return (-1); rUnits.w = 0; rUnits.h = 0; /* Size input textbox */ aChld.x = 0; aChld.y = 0; aChld.w = a->w - rUnits.w - szBtn - 4; aChld.h = a->h; AG_WidgetSizeAlloc(num->input, &aChld); aChld.x += aChld.w + 2; /* Size increment buttons */ aChld.w = szBtn; aChld.h = szBtn; AG_WidgetSizeAlloc(num->incbu, &aChld); aChld.y += aChld.h; if (aChld.h*2 < a->h) { aChld.h++; } AG_WidgetSizeAlloc(num->decbu, &aChld); return (0); } void AG_SpinbuttonAddValue(AG_Spinbutton *sbu, int inc) { AG_Variable *valueb, *minb, *maxb; void *value; int *min, *max; AG_ObjectLock(sbu); valueb = AG_GetVariable(sbu, "value", &value); minb = AG_GetVariable(sbu, "min", &min); maxb = AG_GetVariable(sbu, "max", &max); switch (AG_VARIABLE_TYPE(valueb)) { case AG_VARIABLE_INT: *(int *)value = *(int *)value+inc < *min ? *min : *(int *)value+inc > *max ? *max : *(int *)value+inc; break; case AG_VARIABLE_UINT: *(unsigned *)value = *(unsigned *)value+inc < *min ? *min : *(unsigned *)value+inc > *max ? *max : *(unsigned *)value+inc; break; case AG_VARIABLE_UINT8: *(Uint8 *)value = *(Uint8 *)value+inc < *min ? *min : *(Uint8 *)value+inc > *max ? *max : *(Uint8 *)value+inc; break; case AG_VARIABLE_SINT8: *(Sint8 *)value = *(Sint8 *)value+inc < *min ? *min : *(Sint8 *)value+inc > *max ? *max : *(Sint8 *)value+inc; break; case AG_VARIABLE_UINT16: *(Uint16 *)value = *(Uint16 *)value+inc < *min ? *min : *(Uint16 *)value+inc > *max ? *max : *(Uint16 *)value+inc; break; case AG_VARIABLE_SINT16: *(Sint16 *)value = *(Sint16 *)value+inc < *min ? *min : *(Sint16 *)value+inc > *max ? *max : *(Sint16 *)value+inc; break; case AG_VARIABLE_UINT32: *(Uint32 *)value = *(Uint32 *)value+inc < *min ? *min : *(Uint32 *)value+inc > *max ? *max : *(Uint32 *)value+inc; break; case AG_VARIABLE_SINT32: *(Sint32 *)value = *(Sint32 *)value+inc < *min ? *min : *(Sint32 *)value+inc > *max ? *max : *(Sint32 *)value+inc; break; default: break; } AG_PostEvent(NULL, sbu, "spinbutton-changed", NULL); AG_UnlockVariable(maxb); AG_UnlockVariable(minb); AG_UnlockVariable(valueb); AG_ObjectUnlock(sbu); } void AG_SpinbuttonSetValue(AG_Spinbutton *sbu, ...) { AG_Variable *valueb, *minb, *maxb; void *value; int *min, *max; va_list ap; AG_ObjectLock(sbu); valueb = AG_GetVariable(sbu, "value", &value); minb = AG_GetVariable(sbu, "min", &min); maxb = AG_GetVariable(sbu, "max", &max); va_start(ap, sbu); switch (AG_VARIABLE_TYPE(valueb)) { case AG_VARIABLE_INT: { int i = va_arg(ap, int); *(int *)value = i < *min ? *min : i > *max ? *max : i; } break; case AG_VARIABLE_UINT: { unsigned i = va_arg(ap, unsigned int); *(unsigned *)value = i<(unsigned)*min ? (unsigned)*min : i>(unsigned)*max ? (unsigned)*max : i; } break; case AG_VARIABLE_UINT8: { Uint8 i = (Uint8)va_arg(ap, int); *(Uint8 *)value = i < (Uint8)*min ? (Uint8)*min : i > (Uint8)*max ? (Uint8)*max : i; } break; case AG_VARIABLE_SINT8: { Sint8 i = (Sint8)va_arg(ap, int); *(Sint8 *)value = i < (Sint8)*min ? (Sint8)*min : i > (Sint8)*max ? (Sint8)*max : i; } break; case AG_VARIABLE_UINT16: { Uint16 i = (Uint16)va_arg(ap, int); *(Uint16 *)value = i < (Uint16)*min ? (Uint16)*min : i > (Uint16)*max ? (Uint16)*max : i; } break; case AG_VARIABLE_SINT16: { Sint16 i = (Sint16)va_arg(ap, int); *(Sint16 *)value = i < (Sint16)*min ? (Sint16)*min : i > (Sint16)*max ? (Sint16)*max : i; } break; case AG_VARIABLE_UINT32: { Uint32 i = (Uint32)va_arg(ap, int); *(Uint32 *)value = i < (Uint32)*min ? (Uint32)*min : i > (Uint32)*max ? (Uint32)*max : i; } break; case AG_VARIABLE_SINT32: { Sint32 i = (Sint32)va_arg(ap, int); *(Sint32 *)value = i < (Sint32)*min ? (Sint32)*min : i > (Sint32)*max ? (Sint32)*max : i; } break; default: break; } va_end(ap); AG_PostEvent(NULL, sbu, "spinbutton-changed", NULL); AG_UnlockVariable(valueb); AG_UnlockVariable(minb); AG_UnlockVariable(maxb); AG_ObjectUnlock(sbu); } void AG_SpinbuttonSetMin(AG_Spinbutton *sbu, int nmin) { AG_Variable *minb; int *min; AG_ObjectLock(sbu); minb = AG_GetVariable(sbu, "min", &min); *min = nmin; AG_UnlockVariable(minb); AG_ObjectUnlock(sbu); } void AG_SpinbuttonSetMax(AG_Spinbutton *sbu, int nmax) { AG_Variable *maxb; int *max; AG_ObjectLock(sbu); maxb = AG_GetVariable(sbu, "max", &max); *max = nmax; AG_UnlockVariable(maxb); AG_ObjectUnlock(sbu); } void AG_SpinbuttonSetRange(AG_Spinbutton *sbu, int nmin, int nmax) { AG_Variable *minb, *maxb; int *min, *max; AG_ObjectLock(sbu); minb = AG_GetVariable(sbu, "min", &min); maxb = AG_GetVariable(sbu, "max", &max); *min = nmin; *max = nmax; AG_UnlockVariable(minb); AG_UnlockVariable(maxb); AG_ObjectUnlock(sbu); } void AG_SpinbuttonSetIncrement(AG_Spinbutton *sbu, int incr) { AG_ObjectLock(sbu); sbu->incr = incr; AG_ObjectUnlock(sbu); } void AG_SpinbuttonSetWriteable(AG_Spinbutton *sbu, int writeable) { AG_ObjectLock(sbu); sbu->writeable = writeable; if (writeable) { AG_WidgetEnable(sbu->incbu); AG_WidgetEnable(sbu->decbu); AG_WidgetEnable(sbu->input); } else { AG_WidgetDisable(sbu->incbu); AG_WidgetDisable(sbu->decbu); AG_WidgetDisable(sbu->input); } AG_ObjectUnlock(sbu); } AG_WidgetClass agSpinbuttonClass = { { "Agar(Widget:Spinbutton)", sizeof(AG_Spinbutton), { 0,0 }, Init, NULL, /* free */ NULL, /* destroy */ NULL, /* load */ NULL, /* save */ NULL /* edit */ }, Draw, SizeRequest, SizeAllocate };