/*
* Copyright (c) 2002-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 "checkbox.h"
#include "window.h"
#include "primitive.h"
#include "text.h"
#include
#include
AG_Checkbox *
AG_CheckboxNew(void *parent, Uint flags, const char *fmt, ...)
{
AG_Checkbox *cb;
va_list args;
cb = Malloc(sizeof(AG_Checkbox));
AG_ObjectInit(cb, &agCheckboxClass);
cb->flags |= flags;
if (fmt != NULL) {
char text[AG_LABEL_MAX];
va_start(args, fmt);
Vsnprintf(text, sizeof(text), fmt, args);
va_end(args);
cb->lbl = AG_LabelNewString(cb, 0, text);
AG_LabelValign(cb->lbl, AG_TEXT_MIDDLE);
}
if (flags & AG_CHECKBOX_SET) {
cb->state = 1;
}
AG_ObjectAttach(parent, cb);
return (cb);
}
AG_Checkbox *
AG_CheckboxNewFn(void *parent, Uint flags, const char *label, AG_EventFn fn,
const char *fmt, ...)
{
AG_Checkbox *cb;
AG_Event *ev;
cb = AG_CheckboxNew(parent, flags, label);
ev = AG_SetEvent(cb, "checkbox-changed", fn, NULL);
AG_EVENT_GET_ARGS(ev, fmt);
return (cb);
}
AG_Checkbox *
AG_CheckboxNewInt(void *parent, Uint flags, const char *label, int *pVal)
{
AG_Checkbox *cb;
cb = AG_CheckboxNew(parent, flags, label);
AG_BindInt(cb, "state", pVal);
return (cb);
}
AG_Checkbox *
AG_CheckboxNewFlag(void *parent, Uint flags, const char *label, Uint *pFlags,
Uint bitmask)
{
AG_Checkbox *cb;
cb = AG_CheckboxNew(parent, flags, label);
AG_BindFlag(cb, "state", pFlags, bitmask);
return (cb);
}
AG_Checkbox *
AG_CheckboxNewFlag32(void *parent, Uint flags, const char *label,
Uint32 *pFlags, Uint32 bitmask)
{
AG_Checkbox *cb;
cb = AG_CheckboxNew(parent, flags, label);
AG_BindFlag32(cb, "state", pFlags, bitmask);
return (cb);
}
/* Create a set of checkboxes for the given set of flags. */
void
AG_CheckboxSetFromFlags(void *parent, Uint flags, Uint *pFlags,
const AG_FlagDescr *fdSet)
{
const AG_FlagDescr *fd;
AG_Checkbox *cb;
int i;
for (i = 0; fdSet[i].bitmask != 0; i++) {
fd = &fdSet[i];
cb = AG_CheckboxNewFlag(parent, flags, fd->descr,
pFlags, fd->bitmask);
if (!fd->writeable)
AG_WidgetDisable(cb);
}
}
/* Create a set of checkboxes for the given set of flags. */
void
AG_CheckboxSetFromFlags32(void *parent, Uint flags, Uint32 *pFlags,
const AG_FlagDescr *fdSet)
{
const AG_FlagDescr *fd;
AG_Checkbox *cb;
int i;
for (i = 0; fdSet[i].bitmask != 0; i++) {
fd = &fdSet[i];
cb = AG_CheckboxNewFlag32(parent, flags, fd->descr,
pFlags, (Uint32)fd->bitmask);
if (!fd->writeable)
AG_WidgetDisable(cb);
}
}
static void
MouseButtonDown(AG_Event *event)
{
AG_Checkbox *cb = AG_SELF();
int button = AG_INT(1);
if (!AG_WidgetEnabled(cb))
return;
if (button == SDL_BUTTON(1)) {
AG_WidgetFocus(cb);
AG_CheckboxToggle(cb);
}
}
static void
KeyDown(AG_Event *event)
{
AG_Checkbox *cb = AG_SELF();
if (!AG_WidgetEnabled(cb))
return;
switch (AG_SDLKEY(1)) {
case SDLK_RETURN:
case SDLK_SPACE:
AG_CheckboxToggle(cb);
break;
default:
break;
}
}
static void
Init(void *obj)
{
AG_Checkbox *cb = obj;
WIDGET(cb)->flags |= AG_WIDGET_FOCUSABLE;
AG_BindInt(cb, "state", &cb->state);
cb->flags = 0;
cb->state = 0;
cb->lbl = NULL;
cb->spacing = 6;
cb->btnSize = agTextFontHeight;
AG_SetEvent(cb, "window-mousebuttondown", MouseButtonDown, NULL);
AG_SetEvent(cb, "window-keydown", KeyDown, NULL);
}
static void
Draw(void *obj)
{
AG_Checkbox *cb = obj;
AG_Variable *stateb;
void *p;
int state;
stateb = AG_GetVariable(cb, "state", &p);
switch (AG_VARIABLE_TYPE(stateb)) {
case AG_VARIABLE_INT:
case AG_VARIABLE_UINT:
state = *(int *)p;
break;
case AG_VARIABLE_P_FLAG:
state = *(int *)p & (int)stateb->info.bitmask;
break;
case AG_VARIABLE_P_FLAG8:
state = *(Uint8 *)p & (Uint8)stateb->info.bitmask;
break;
case AG_VARIABLE_P_FLAG16:
state = *(Uint16 *)p & (Uint16)stateb->info.bitmask;
break;
case AG_VARIABLE_P_FLAG32:
state = *(Uint32 *)p & (Uint32)stateb->info.bitmask;
break;
case AG_VARIABLE_UINT8:
case AG_VARIABLE_SINT8:
state = *(Uint8 *)p;
break;
case AG_VARIABLE_UINT16:
case AG_VARIABLE_SINT16:
state = *(Uint16 *)p;
break;
case AG_VARIABLE_UINT32:
case AG_VARIABLE_SINT32:
state = *(Uint32 *)p;
break;
default:
state = 0;
break;
}
STYLE(cb)->CheckboxButton(cb, state, cb->btnSize);
if (cb->lbl != NULL) {
AG_WidgetDraw(cb->lbl);
}
AG_UnlockVariable(stateb);
}
static void
SizeRequest(void *obj, AG_SizeReq *r)
{
AG_Checkbox *cb = obj;
AG_SizeReq rLbl;
r->h = cb->btnSize;
r->w = cb->btnSize;
if (cb->lbl != NULL) {
AG_WidgetSizeReq(cb->lbl, &rLbl);
r->w += cb->spacing + rLbl.w;
r->h = agTextFontHeight;
}
}
static int
SizeAllocate(void *obj, const AG_SizeAlloc *a)
{
AG_Checkbox *cb = obj;
AG_SizeAlloc aLbl;
if (a->w < cb->btnSize || a->h < cb->btnSize) {
return (-1);
}
if (cb->lbl != NULL) {
aLbl.x = cb->btnSize + cb->spacing;
aLbl.y = 0;
aLbl.w = a->w - aLbl.x;
aLbl.h = a->h;
AG_WidgetSizeAlloc(cb->lbl, &aLbl);
}
return (0);
}
/* Toggle the checkbox state. */
void
AG_CheckboxToggle(AG_Checkbox *cb)
{
AG_Variable *stateb;
void *p;
AG_ObjectLock(cb);
stateb = AG_GetVariable(cb, "state", &p);
switch (AG_VARIABLE_TYPE(stateb)) {
case AG_VARIABLE_INT:
case AG_VARIABLE_UINT:
{
int *state = (int *)p;
*state = !(*state);
AG_PostEvent(NULL, cb, "checkbox-changed", "%i",
*state);
}
break;
case AG_VARIABLE_P_FLAG:
{
int *state = (int *)p;
AG_INVFLAGS(*state, (int)stateb->info.bitmask);
AG_PostEvent(NULL, cb, "checkbox-changed", "%i",
(int)*state);
}
break;
case AG_VARIABLE_P_FLAG8:
{
Uint8 *state = (Uint8 *)p;
AG_INVFLAGS(*state, (Uint8)stateb->info.bitmask);
AG_PostEvent(NULL, cb, "checkbox-changed", "%i",
(Uint8)*state);
}
break;
case AG_VARIABLE_P_FLAG16:
{
Uint16 *state = (Uint16 *)p;
AG_INVFLAGS(*state, (Uint16)stateb->info.bitmask);
AG_PostEvent(NULL, cb, "checkbox-changed", "%i",
(Uint16)*state);
}
break;
case AG_VARIABLE_P_FLAG32:
{
Uint32 *state = (Uint32 *)p;
AG_INVFLAGS(*state, (Uint32)stateb->info.bitmask);
AG_PostEvent(NULL, cb, "checkbox-changed", "%i",
(Uint32)*state);
}
break;
case AG_VARIABLE_UINT8:
case AG_VARIABLE_SINT8:
{
Uint8 *state = (Uint8 *)p;
*state = !(*state);
AG_PostEvent(NULL, cb, "checkbox-changed", "%i",
(int)*state);
}
break;
case AG_VARIABLE_UINT16:
case AG_VARIABLE_SINT16:
{
Uint16 *state = (Uint16 *)p;
*state = !(*state);
AG_PostEvent(NULL, cb, "checkbox-changed", "%i",
(int)*state);
}
break;
case AG_VARIABLE_UINT32:
case AG_VARIABLE_SINT32:
{
Uint32 *state = (Uint32 *)p;
*state = !(*state);
AG_PostEvent(NULL, cb, "checkbox-changed", "%i",
(int)*state);
}
break;
default:
break;
}
AG_UnlockVariable(stateb);
AG_ObjectUnlock(cb);
}
AG_WidgetClass agCheckboxClass = {
{
"Agar(Widget:Checkbox)",
sizeof(AG_Checkbox),
{ 0,0 },
Init,
NULL, /* free */
NULL, /* destroy */
NULL, /* load */
NULL, /* save */
NULL /* edit */
},
Draw,
SizeRequest,
SizeAllocate
};