Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <control.h>
#include "group.h"

typedef struct Tab Tab;

struct Tab {
        Control;
        int             border;
        int             selected;
        int             separation;
        char            *format;
        CImage  *bordercolor;
        CImage  *image;
        Control *tabrow;
        Control *tabstack;
        Control *tabcolumn;
        int             ntabs;
        int             nbuttons;
        Control **buttons;
};

enum{
        EAdd,
        EBorder,
        EBordercolor,
        EButton,
        EFocus,
        EFormat,
        EHide,
        EImage,
        ERect,
        EReveal,
        ESeparation,
        ESeparatorcolor,
        EShow,
        ESize,
        EValue,
};

static char *cmds[] = {
        [EAdd] =                        "add",
        [EBorder] =             "border",
        [EBordercolor] =        "bordercolor",
        [EButton] =             "button",
        [EFocus] =              "focus",
        [EFormat] =             "format",
        [EHide] =                       "hide",
        [EImage] =              "image",
        [ERect] =                       "rect",
        [EReveal] =             "reveal",
        [ESeparation] =         "separation",
        [ESeparatorcolor] =     "separatorcolor",
        [EShow] =                       "show",
        [ESize] =                       "size",
        [EValue] =                      "value",
};

static void
tabshow(Tab *t)
{
        int i;
        Rectangle r;
        Group *g;

        if (t->hidden)
                return;
        for(i=0; i<t->nbuttons; i++){
                _ctlprint(t->buttons[i], "value %d", (t->selected==i));
        }
        _ctlprint(t->tabstack, "reveal %d", t->selected);
        _ctlprint(t->tabcolumn, "show");
        if (t->selected < 0)
                return;
        g = (Group*)t->tabcolumn;
        if (g->nseparators == 0){
                return;
        }
        r = g->separators[0];
        r.min.x = t->buttons[t->selected]->rect.min.x;
        r.max.x = t->buttons[t->selected]->rect.max.x;
        draw(t->screen, r, t->image->image, nil, t->image->image->r.min);
        flushimage(display, 1);
}

static void
tabsize(Control *c)
{
        Tab *t = (Tab*)c;
        if (t->tabcolumn && t->tabcolumn->setsize)
                t->tabcolumn->setsize((Control*)t->tabcolumn);
}

static void
tabctl(Control *c, CParse *cp)
{
        int cmd, i;
        Control *cbut, *cwin;
        Tab *t;
        Rectangle r;

        t = (Tab*)c;
        cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
        switch(cmd){
        case EAdd:
                if ((cp->nargs & 1) == 0)
                        ctlerror("%q: arg count: %s", t->name, cp->args[1]);
                for (i = 1; i < cp->nargs; i += 2){
                        cbut = controlcalled(cp->args[i]);
                        if (cbut == nil)
                                ctlerror("%q: no such control: %s", t->name, cp->args[i]);
                        cwin = controlcalled(cp->args[i+1]);
                        if (cwin == nil)
                                ctlerror("%q: no such control: %s", t->name, cp->args[i+1]);
                        _ctladdgroup(t->tabrow, cbut);
                        _ctlprint(t->tabstack, "add %q", cp->args[i+1]);
                        _ctlprint(cbut, "format '%%s: %q button %%d'", t->name);
                        controlwire(cbut, "event", t->controlset->ctl);
                        t->buttons = ctlrealloc(t->buttons, (t->nbuttons+1)*sizeof(Control*));
                        t->buttons[t->nbuttons] = cbut;
                        t->nbuttons++;
                        t->selected = -1;
                }
                _ctlprint(t->tabcolumn, "size");
                t->size = t->tabcolumn->size;
                break;
        case EBorder:
                _ctlargcount(t, cp, 2);
                if(cp->iargs[1] < 0)
                        ctlerror("%q: bad border: %c", t->name, cp->str);
                t->border = cp->iargs[1];
                break;
        case EBordercolor:
                _ctlargcount(t, cp, 2);
                _setctlimage(t, &t->bordercolor, cp->args[1]);
                break;
        case EButton:
                _ctlargcount(t, cp, 2);
                if (cp->sender == nil)
                        ctlerror("%q: senderless buttonevent: %q", t->name, cp->str);
                cbut = controlcalled(cp->sender);
                for(i=0; i<t->nbuttons; i++)
                        if (cbut == t->buttons[i])
                                break;
                if (i == t->nbuttons)
                        ctlerror("%q: not my event: %q", t->name, cp->str);
                if(cp->iargs[1] == 0){
                        /* button was turned off; turn it back on */
                        _ctlprint(cbut, "value 1");
                }else{
                        t->selected = i;
                        if (t->format)
                                chanprint(t->event, t->format, t->name, i);
                        tabshow(t);
                }
                break;
        case EFocus:
                /* ignore focus change */
                break;
        case EFormat:
                _ctlargcount(t, cp, 2);
                t->format = ctlstrdup(cp->args[1]);
                break;
        case EImage:
                _ctlargcount(t, cp, 2);
                _setctlimage(t, &t->image, cp->args[1]);
                break;
        case ESeparation:
                t->tabrow->ctl(t->tabrow, cp);
                t->tabcolumn->ctl(t->tabcolumn, cp);
                break;
        case ERect:
                _ctlargcount(t, cp, 5);
                r.min.x = cp->iargs[1];
                r.min.y = cp->iargs[2];
                r.max.x = cp->iargs[3];
                r.max.y = cp->iargs[4];
                if(Dx(r)<=0 || Dy(r)<=0)
                        ctlerror("%q: bad rectangle: %s", t->name, cp->str);
                t->rect = r;
                r = insetrect(r, t->border);
                _ctlprint(t->tabcolumn, "rect %R", r);
                break;
        case EReveal:
                _ctlargcount(t, cp, 1);
        case EHide:
        case ESize:
                t->tabcolumn->ctl(t->tabcolumn, cp);
                break;
        case EShow:
                tabshow(t);
                break;
        case EValue:
                _ctlargcount(t, cp, 2);
                if (cp->iargs[1] < 0 || cp->iargs[1] >= t->nbuttons)
                        ctlerror("%q: illegal value '%s'", t->name, cp->str);
                t->selected = cp->iargs[1];
                tabshow(t);
                break;
        default:
                ctlerror("%q: unrecognized message '%s'", t->name, cp->str);
                break;
        }
}

static void
tabfree(Control*c)
{
        Tab *t = (Tab*)c;
        t->nbuttons = 0;
        free(t->buttons);
        t->buttons = 0;
}

static void
activatetab(Control *c, int act)
{
        Tab *t;

        t = (Tab*)c;
        if (act)
                activate(t->tabcolumn);
        else
                deactivate(t->tabcolumn);
}
        
Control *
createtab(Controlset *cs, char *name)
{
        char s[128];

        Tab *t;
        t = (Tab*)_createctl(cs, "tab", sizeof(Tab), name);
        t->selected = -1;
        t->nbuttons = 0;
        t->ctl = tabctl;
        t->mouse = nil;
        t->exit = tabfree;
        snprint(s, sizeof s, "_%s-row", name);
        t->tabrow = createrow(cs, s);
        snprint(s, sizeof s, "_%s-stack", name);
        t->tabstack = createstack(cs, s);
        snprint(s, sizeof s, "_%s-column", name);
        t->tabcolumn = createcolumn(cs, s);
        ctlprint(t->tabcolumn, "add %q %q", t->tabrow->name, t->tabstack->name);
        t->bordercolor = _getctlimage("black");
        t->image = _getctlimage("white");
        t->setsize = tabsize;
        t->activate = activatetab;
        return (Control*)t;
}