Little Forms
Documentation
Not logged in
/* 
 * Little Forms -- user interface library
 * Copyright (C) 2011 Kostas Michalopoulos
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * Kostas Michalopoulos badsector@runtimelegend.com
 */

#define LFORMS_SOURCE_CODE
#include <stdlib.h>
#include <string.h>
#include <lforms.h>

typedef struct _state_t
{
    char* caption;
    int down;
    int checked;
    int update_prefsize;
} state_t;

static void update_prefsize(ff_window_t cb)
{
    state_t* state = ff_get(cb, "-state");
    unsigned int tw, th;
    ff_bitmap_t bmp = ff_bitmap(1, 1, NULL);
    ff_gc_t gc = ff_bitmap_gc(bmp);
    ff_text_size(gc, state->caption, &tw, &th);
    ff_bitmap_free(bmp);
    ff_prefsize(cb, tw + 19, th > 15 ? th : 15);
}

static int set_handler(ff_window_t cb, ff_event_t* ev, void* data)
{
    ff_namevalue_t* nv = ev->p;
    state_t* state = ff_get(cb, "-state");
    if (!strcmp(nv->name, "caption")) {
        free(state->caption);
        state->caption = ff_strdup(nv->value);
        update_prefsize(cb);
        ff_paint(cb);
        return 1;
    }
    if (!strcmp(nv->name, "checked")) {
        state->checked = nv->value ? 1 : 0;
        ff_paint(cb);
        return 1;
    }
    return 0;
}

static int get_handler(ff_window_t cb, ff_event_t* ev, void* data)
{   
    ff_namevalue_t* nv = ev->p;
    state_t* state = ff_get(cb, "-state");
    if (!strcmp(nv->name, "caption")) {
        nv->value = state->caption;
        return 1;
    }
    if (!strcmp(nv->name, "checked")) {
        nv->value = state->checked ? (void*)1 : 0;
        return 1;
    }
    return 0;
}

static int destroy_handler(ff_window_t cb, ff_event_t* ev, void* data)
{
    state_t* state = ff_get(cb, "-state");
    free(state->caption);
    free(state);
    return 0;
}

static int paint_handler(ff_window_t cb, ff_event_t* ev, void* data)
{
    ff_gc_t gc = ev->p;
    unsigned int w, h, tw, th, cy;
    state_t* state = ff_get(cb, "-state");
    ff_area(cb, NULL, NULL, &w, &h);
    cy = (h - 15)/2;
    ff_color_attr(gc, cb, "background");
    ff_fill(gc, 0, 0, w, h);
    if (state->down) {
        ff_color(gc, FF_ACTIVE_COLOR);
        ff_fill(gc, 1, cy + 1, 15, cy + 15);
        ff_color(gc, FF_3DDARK_COLOR);
        ff_line(gc, 0, cy, 14, cy);
        ff_line(gc, 0, cy, 0, cy + 14);
        ff_color(gc, FF_ACTEXT_COLOR);
        if (state->checked) {
            ff_line(gc, 4, cy + 11, 11, cy + 4);
            ff_line(gc, 4, cy + 5, 4, cy + 10);
            ff_line(gc, 3, cy + 11, 11, cy + 3);
            ff_line(gc, 3, cy + 5, 3, cy + 10);
            ff_line(gc, 3, cy + 10, 11, cy + 2);
        }
    } else {
        ff_color(gc, FF_3DLIGHT_COLOR);
        ff_line(gc, 0, cy, 14, cy);
        ff_line(gc, 0, cy, 0, cy + 14);
        ff_color(gc, FF_3DDARK_COLOR);
        ff_line(gc, 14, cy, 14, cy + 14);
        ff_line(gc, 0, cy + 14, 14, cy + 14);
        ff_color(gc, FF_3DSHADOW_COLOR);
        ff_line(gc, 13, cy + 1, 13, cy + 13);
        ff_line(gc, 1, cy + 13, 13, cy + 13);
        if (state->checked) {
            ff_line(gc, 4, cy + 11, 11, cy + 4);
            ff_color(gc, FF_3DDARK_COLOR);
            ff_line(gc, 4, cy + 5, 4, cy + 10);
            ff_line(gc, 3, cy + 11, 11, cy + 3);
            ff_color(gc, FF_3DLIGHT_COLOR);
            ff_line(gc, 3, cy + 5, 3, cy + 10);
            ff_line(gc, 3, cy + 10, 11, cy + 2);
        }
        ff_color(gc, FF_3DTEXT_COLOR);
    }
    ff_text_size(gc, state->caption, &tw, &th);
    ff_text(gc, 19, (h + th)/2, state->caption);
    return 1;
}

static int press_handler(ff_window_t cb, ff_event_t* ev, void* data)
{
    state_t* state = ff_get(cb, "-state");
    if (ev->z == 1) {
        state->down = 1;
        ff_paint(cb);
    }
    return 0;
}

static int release_handler(ff_window_t cb, ff_event_t* ev, void* data)
{
    state_t* state = ff_get(cb, "-state");
    if (ev->z == 1 && state->down) {
        int px, py;
        state->down = 0;
        ff_paint(cb);
        ff_pointer(&px, &py);
        if (ff_pick(NULL, px, py) == cb) {
            if (ff_geti(cb, "autocheck"))
                ff_seti(cb, "checked", !ff_geti(cb, "checked"));
            ff_send(cb, FF_ACTION, 0, 0, 0, NULL, FF_BUBBLE);
        }
    }
    return 0;
}

ff_window_t ff_checkbox(ff_window_t parent, const char* caption, int checked)
{
    ff_window_t cb = ff_window(parent, 0, 0, 100, 25, FF_NOFLAGS);
    state_t* state = calloc(1, sizeof(state_t));
    ff_set(cb, "-state", state);
    ff_link(cb, FF_SET, set_handler, NULL);
    ff_link(cb, FF_GET, get_handler, NULL);
    ff_set(cb, "caption", (void*)caption);
    ff_seti(cb, "checked", checked);
    ff_seti(cb, "autocheck", 1);
    ff_link(cb, FF_DESTROY, destroy_handler, NULL);
    ff_link(cb, FF_PAINT, paint_handler, NULL);
    ff_link(cb, FF_PRESS, press_handler, NULL);
    ff_link(cb, FF_RELEASE, release_handler, NULL);
    return cb;
}