/*
* 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.
*/
#include
#include "mspinbutton.h"
#include "window.h"
#include
#include
AG_MSpinbutton *
AG_MSpinbuttonNew(void *parent, Uint flags, const char *sep, const char *label)
{
AG_MSpinbutton *sbu;
sbu = Malloc(sizeof(AG_MSpinbutton));
AG_ObjectInit(sbu, &agMSpinbuttonClass);
sbu->sep = sep;
if (!(flags & AG_MSPINBUTTON_NOHFILL)) { AG_ExpandHoriz(sbu); }
if ( flags & AG_MSPINBUTTON_VFILL) { AG_ExpandVert(sbu); }
if (label != NULL) {
AG_TextboxSetLabel(sbu->input, "%s", label);
}
AG_ObjectAttach(parent, sbu);
return (sbu);
}
static void
Bound(AG_Event *event)
{
AG_MSpinbutton *sbu = AG_SELF();
AG_Variable *binding = AG_PTR(1);
if (strcmp(binding->name, "xvalue") == 0 ||
strcmp(binding->name, "yvalue") == 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_MSpinbutton *sbu = AG_SELF();
int keysym = AG_INT(1);
switch (keysym) {
case SDLK_LEFT:
AG_MSpinbuttonAddValue(sbu, "xvalue", -sbu->inc);
break;
case SDLK_RIGHT:
AG_MSpinbuttonAddValue(sbu, "xvalue", sbu->inc);
break;
case SDLK_UP:
AG_MSpinbuttonAddValue(sbu, "yvalue", -sbu->inc);
break;
case SDLK_DOWN:
AG_MSpinbuttonAddValue(sbu, "yvalue", sbu->inc);
break;
}
}
static void
TextReturn(AG_Event *event)
{
char text[AG_TEXTBOX_STRING_MAX];
AG_MSpinbutton *sbu = AG_PTR(1);
AG_Variable *stringb;
char *tp = &text[0], *s;
AG_ObjectLock(sbu);
stringb = AG_GetVariable(sbu->input->ed, "string", &s);
Strlcpy(text, s, sizeof(text));
if ((s = AG_Strsep(&tp, sbu->sep)) != NULL) {
AG_MSpinbuttonSetValue(sbu, "xvalue", atoi(s));
}
if ((s = AG_Strsep(&tp, sbu->sep)) != NULL) {
AG_MSpinbuttonSetValue(sbu, "yvalue", atoi(s));
}
AG_UnlockVariable(stringb);
AG_PostEvent(NULL, sbu, "mspinbutton-return", NULL);
AG_WidgetUnfocus(sbu->input);
AG_ObjectUnlock(sbu);
}
static void
TextChanged(AG_Event *event)
{
char text[AG_TEXTBOX_STRING_MAX];
AG_MSpinbutton *sbu = AG_PTR(1);
AG_Variable *stringb;
char *tp = &text[0], *s;
AG_ObjectLock(sbu);
stringb = AG_GetVariable(sbu->input->ed, "string", &s);
Strlcpy(text, s, sizeof(text));
if ((s = AG_Strsep(&tp, sbu->sep)) != NULL) {
AG_MSpinbuttonSetValue(sbu, "xvalue", atoi(s));
}
if ((s = AG_Strsep(&tp, sbu->sep)) != NULL) {
AG_MSpinbuttonSetValue(sbu, "yvalue", atoi(s));
}
AG_UnlockVariable(stringb);
AG_PostEvent(NULL, sbu, "mspinbutton-changed", NULL);
AG_ObjectUnlock(sbu);
}
static void
DecrementY(AG_Event *event)
{
AG_MSpinbutton *sbu = AG_PTR(1);
AG_ObjectLock(sbu);
AG_MSpinbuttonAddValue(sbu, "yvalue", -sbu->inc);
AG_ObjectUnlock(sbu);
}
static void
IncrementY(AG_Event *event)
{
AG_MSpinbutton *sbu = AG_PTR(1);
AG_ObjectLock(sbu);
AG_MSpinbuttonAddValue(sbu, "yvalue", sbu->inc);
AG_ObjectUnlock(sbu);
}
static void
DecrementX(AG_Event *event)
{
AG_MSpinbutton *sbu = AG_PTR(1);
AG_ObjectLock(sbu);
AG_MSpinbuttonAddValue(sbu, "xvalue", -sbu->inc);
AG_ObjectUnlock(sbu);
}
static void
IncrementX(AG_Event *event)
{
AG_MSpinbutton *sbu = AG_PTR(1);
AG_ObjectLock(sbu);
AG_MSpinbuttonAddValue(sbu, "xvalue", sbu->inc);
AG_ObjectUnlock(sbu);
}
static void
Init(void *obj)
{
AG_MSpinbutton *sbu = obj;
AG_BindInt(sbu, "xvalue", &sbu->xvalue);
AG_BindInt(sbu, "yvalue", &sbu->yvalue);
AG_BindInt(sbu, "min", &sbu->min);
AG_BindInt(sbu, "max", &sbu->max);
sbu->xvalue = 0;
sbu->yvalue = 0;
sbu->min = 0;
sbu->max = 0;
sbu->inc = 1;
sbu->writeable = 0;
sbu->sep = ",";
sbu->input = AG_TextboxNew(sbu, 0, NULL);
AG_SetEvent(sbu->input, "textbox-return", TextReturn, "%p", sbu);
AG_SetEvent(sbu->input, "textbox-postchg", TextChanged, "%p", sbu);
AG_TextboxSizeHint(sbu->input, "88888");
sbu->xdecbu = AG_ButtonNew(sbu, AG_BUTTON_REPEAT, _("-"));
AG_SetEvent(sbu->xdecbu, "button-pushed", DecrementX, "%p", sbu);
sbu->xincbu = AG_ButtonNew(sbu, AG_BUTTON_REPEAT, _("+"));
AG_SetEvent(sbu->xincbu, "button-pushed", IncrementX, "%p", sbu);
sbu->ydecbu = AG_ButtonNew(sbu, AG_BUTTON_REPEAT, _("-"));
AG_SetEvent(sbu->ydecbu, "button-pushed", DecrementY, "%p", sbu);
sbu->yincbu = AG_ButtonNew(sbu, AG_BUTTON_REPEAT, _("+"));
AG_SetEvent(sbu->yincbu, "button-pushed", IncrementY, "%p", sbu);
AG_ButtonSetPadding(sbu->xdecbu, 1,1,1,1);
AG_ButtonSetPadding(sbu->xincbu, 1,1,1,1);
AG_ButtonSetPadding(sbu->ydecbu, 1,1,1,1);
AG_ButtonSetPadding(sbu->yincbu, 1,1,1,1);
AG_ButtonSetRepeatMode(sbu->xincbu, 1);
AG_ButtonSetRepeatMode(sbu->xdecbu, 1);
AG_ButtonSetRepeatMode(sbu->yincbu, 1);
AG_ButtonSetRepeatMode(sbu->ydecbu, 1);
AG_WidgetSetFocusable(sbu->xincbu, 0);
AG_WidgetSetFocusable(sbu->xdecbu, 0);
AG_WidgetSetFocusable(sbu->yincbu, 0);
AG_WidgetSetFocusable(sbu->ydecbu, 0);
AG_SetEvent(sbu, "bound", Bound, NULL);
AG_SetEvent(sbu, "window-keydown", KeyDown, NULL);
}
static void
SizeRequest(void *obj, AG_SizeReq *r)
{
AG_MSpinbutton *fsu = obj;
AG_SizeReq rChld, rYinc, rYdec;
AG_WidgetSizeReq(fsu->input, &rChld);
r->w = rChld.w;
r->h = rChld.h;
AG_WidgetSizeReq(fsu->xdecbu, &rChld);
r->w += rChld.w;
AG_WidgetSizeReq(fsu->xincbu, &rChld);
r->w += rChld.w;
AG_WidgetSizeReq(fsu->yincbu, &rYinc);
AG_WidgetSizeReq(fsu->ydecbu, &rYdec);
r->w += MAX(rYinc.w,rYdec.w);
}
static int
SizeAllocate(void *obj, const AG_SizeAlloc *a)
{
AG_MSpinbutton *fsu = obj;
int szBtn = a->h/2;
int x = 0, y = 0;
AG_SizeAlloc aChld;
if (a->w < szBtn*3 + 4)
return (-1);
/* Input textbox */
aChld.x = x;
aChld.y = y;
aChld.w = a->w - 4 - szBtn*3;
aChld.h = a->h;
AG_WidgetSizeAlloc(fsu->input, &aChld);
x += aChld.w + 2;
/* Buttons */
aChld.w = szBtn;
aChld.h = szBtn;
aChld.x = x;
aChld.y = y + szBtn/2;
AG_WidgetSizeAlloc(fsu->xdecbu, &aChld);
aChld.x = x + szBtn*2;
aChld.y = y + szBtn/2;
AG_WidgetSizeAlloc(fsu->xincbu, &aChld);
aChld.x = x + szBtn;
aChld.y = y;
AG_WidgetSizeAlloc(fsu->ydecbu, &aChld);
aChld.x = x + szBtn;
aChld.y = y + szBtn;
AG_WidgetSizeAlloc(fsu->yincbu, &aChld);
return (0);
}
static void
Draw(void *obj)
{
AG_MSpinbutton *sbu = obj;
AG_Variable *xvalueb, *yvalueb;
void *xvalue, *yvalue;
AG_WidgetDraw(sbu->input);
AG_WidgetDraw(sbu->xdecbu);
AG_WidgetDraw(sbu->ydecbu);
AG_WidgetDraw(sbu->xincbu);
AG_WidgetDraw(sbu->yincbu);
if (AG_WidgetFocused(sbu->input))
return;
xvalueb = AG_GetVariable(sbu, "xvalue", &xvalue);
yvalueb = AG_GetVariable(sbu, "yvalue", &yvalue);
switch (AG_VARIABLE_TYPE(xvalueb)) {
case AG_VARIABLE_INT:
AG_TextboxPrintf(sbu->input, "%d%s%d",
*(int *)xvalue, sbu->sep, *(int *)yvalue);
break;
case AG_VARIABLE_UINT:
AG_TextboxPrintf(sbu->input, "%u%s%u",
*(Uint *)xvalue, sbu->sep, *(Uint *)yvalue);
break;
case AG_VARIABLE_UINT8:
AG_TextboxPrintf(sbu->input, "%u%s%u",
*(Uint8 *)xvalue, sbu->sep, *(Uint8 *)yvalue);
break;
case AG_VARIABLE_SINT8:
AG_TextboxPrintf(sbu->input, "%d%s%d",
*(Sint8 *)xvalue, sbu->sep, *(Sint8 *)yvalue);
break;
case AG_VARIABLE_UINT16:
AG_TextboxPrintf(sbu->input, "%u%s%u",
*(Uint16 *)xvalue, sbu->sep, *(Uint16 *)yvalue);
break;
case AG_VARIABLE_SINT16:
AG_TextboxPrintf(sbu->input, "%d%s%d",
*(Sint16 *)xvalue, sbu->sep, *(Sint16 *)yvalue);
break;
case AG_VARIABLE_UINT32:
AG_TextboxPrintf(sbu->input, "%u%s%u",
*(Uint32 *)xvalue, sbu->sep, *(Uint32 *)yvalue);
break;
case AG_VARIABLE_SINT32:
AG_TextboxPrintf(sbu->input, "%d%s%d",
*(Sint32 *)xvalue, sbu->sep, *(Sint32 *)yvalue);
break;
default:
break;
}
AG_UnlockVariable(xvalueb);
AG_UnlockVariable(yvalueb);
}
void
AG_MSpinbuttonAddValue(AG_MSpinbutton *sbu, const char *which, int inc)
{
AG_Variable *valueb, *minb, *maxb;
void *value;
int *min, *max;
AG_ObjectLock(sbu);
valueb = AG_GetVariable(sbu, which, &value);
minb = AG_GetVariable(sbu, "min", &min);
maxb = AG_GetVariable(sbu, "max", &max);
switch (AG_VARIABLE_TYPE(valueb)) {
case AG_VARIABLE_INT:
if (*(int *)value+inc >= *min &&
*(int *)value+inc <= *max)
*(int *)value += inc;
break;
case AG_VARIABLE_UINT:
if (*(Uint *)value+inc >= *min &&
*(Uint *)value+inc <= *max)
*(Uint *)value += inc;
break;
case AG_VARIABLE_UINT8:
if (*(Uint8 *)value+inc >= *min &&
*(Uint8 *)value+inc <= *max)
*(Uint8 *)value += inc;
break;
case AG_VARIABLE_SINT8:
if (*(Sint8 *)value+inc >= *min &&
*(Sint8 *)value+inc <= *max)
*(Sint8 *)value += inc;
break;
case AG_VARIABLE_UINT16:
if (*(Uint16 *)value+inc >= *min &&
*(Uint16 *)value+inc <= *max)
*(Uint16 *)value += inc;
break;
case AG_VARIABLE_SINT16:
if (*(Sint16 *)value+inc >= *min &&
*(Sint16 *)value+inc <= *max)
*(Sint16 *)value += inc;
break;
case AG_VARIABLE_UINT32:
if (*(Uint32 *)value+inc >= *min &&
*(Uint32 *)value+inc <= *max)
*(Uint32 *)value += inc;
break;
case AG_VARIABLE_SINT32:
if (*(Sint32 *)value+inc >= *min &&
*(Sint32 *)value+inc <= *max)
*(Sint32 *)value += inc;
break;
default:
break;
}
AG_PostEvent(NULL, sbu, "mspinbutton-changed", "%s", which);
AG_UnlockVariable(maxb);
AG_UnlockVariable(minb);
AG_UnlockVariable(valueb);
AG_ObjectUnlock(sbu);
}
void
AG_MSpinbuttonSetValue(AG_MSpinbutton *sbu, const char *which, ...)
{
AG_Variable *valueb, *minb, *maxb;
void *value;
int *min, *max;
va_list ap;
AG_ObjectLock(sbu);
valueb = AG_GetVariable(sbu, which, &value);
minb = AG_GetVariable(sbu, "min", &min);
maxb = AG_GetVariable(sbu, "max", &max);
va_start(ap, which);
switch (AG_VARIABLE_TYPE(valueb)) {
case AG_VARIABLE_INT:
{
int i = va_arg(ap, int);
if (i < *min) {
*(int *)value = *min;
} else if (i > *max) {
*(int *)value = *max;
} else {
*(int *)value = i;
}
}
break;
case AG_VARIABLE_UINT:
{
Uint i = va_arg(ap, unsigned int);
if (i < (Uint)*min) {
*(Uint *)value = *min;
} else if (i > (Uint)*max) {
*(Uint *)value = *max;
} else {
*(Uint *)value = i;
}
}
break;
case AG_VARIABLE_UINT8:
{
Uint8 i = (Uint8)va_arg(ap, int);
if (i < (Uint8)*min) {
*(Uint8 *)value = *min;
} else if (i > (Uint8)*max) {
*(Uint8 *)value = *max;
} else {
*(Uint8 *)value = i;
}
}
break;
case AG_VARIABLE_SINT8:
{
Sint8 i = (Sint8)va_arg(ap, int);
if (i < (Sint8)*min) {
*(Sint8 *)value = *min;
} else if (i > (Sint8)*max) {
*(Sint8 *)value = *max;
} else {
*(Sint8 *)value = i;
}
}
break;
case AG_VARIABLE_UINT16:
{
Uint16 i = (Uint16)va_arg(ap, int);
if (i < (Uint16)*min) {
*(Uint16 *)value = *min;
} else if (i > (Uint16)*max) {
*(Uint16 *)value = *max;
} else {
*(Uint16 *)value = i;
}
}
break;
case AG_VARIABLE_SINT16:
{
Sint16 i = (Sint16)va_arg(ap, int);
if (i < (Sint16)*min) {
*(Sint16 *)value = *min;
} else if (i > (Sint16)*max) {
*(Sint16 *)value = *max;
} else {
*(Sint16 *)value = i;
}
}
break;
case AG_VARIABLE_UINT32:
{
Uint32 i = (Uint32)va_arg(ap, int);
if (i < (Uint32)*min) {
*(Uint32 *)value = *min;
} else if (i > (Uint32)*max) {
*(Uint32 *)value = *max;
} else {
*(Uint32 *)value = i;
}
}
break;
case AG_VARIABLE_SINT32:
{
Sint32 i = (Sint32)va_arg(ap, int);
if (i < (Sint32)*min) {
*(Sint32 *)value = *min;
} else if (i > (Sint32)*max) {
*(Sint32 *)value = *max;
} else {
*(Sint32 *)value = i;
}
}
break;
default:
break;
}
va_end(ap);
AG_PostEvent(NULL, sbu, "mspinbutton-changed", "%s", which);
AG_UnlockVariable(valueb);
AG_UnlockVariable(minb);
AG_UnlockVariable(maxb);
AG_ObjectUnlock(sbu);
}
void
AG_MSpinbuttonSetMin(AG_MSpinbutton *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_MSpinbuttonSetMax(AG_MSpinbutton *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_MSpinbuttonSetRange(AG_MSpinbutton *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_MSpinbuttonSetIncrement(AG_MSpinbutton *sbu, int inc)
{
AG_ObjectLock(sbu);
sbu->inc = inc;
AG_ObjectUnlock(sbu);
}
void
AG_MSpinbuttonSetWriteable(AG_MSpinbutton *sbu, int writeable)
{
AG_ObjectLock(sbu);
sbu->writeable = writeable;
if (writeable) {
AG_WidgetEnable(sbu->xincbu);
AG_WidgetEnable(sbu->xdecbu);
AG_WidgetEnable(sbu->yincbu);
AG_WidgetEnable(sbu->ydecbu);
AG_WidgetEnable(sbu->input);
} else {
AG_WidgetDisable(sbu->xincbu);
AG_WidgetDisable(sbu->xdecbu);
AG_WidgetDisable(sbu->yincbu);
AG_WidgetDisable(sbu->ydecbu);
AG_WidgetDisable(sbu->input);
}
AG_ObjectUnlock(sbu);
}
AG_WidgetClass agMSpinbuttonClass = {
{
"Agar(Widget:MSpinbutton)",
sizeof(AG_MSpinbutton),
{ 0,0 },
Init,
NULL, /* free */
NULL, /* destroy */
NULL, /* load */
NULL, /* save */
NULL /* edit */
},
Draw,
SizeRequest,
SizeAllocate
};