Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <thread.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
#include <frame.h>
#include <plumb.h>
#include <html.h>
#include "dat.h"
#include "fns.h"

void
drawtable(Box *b, Page *p, Image *im)
{
        Rectangle r, cr;
        Tablecell *c;
        Table *t;

        t = ((Itable *)b->i)->table;
        r = rectsubpt(b->r, p->pos);
        draw(im, r, getcolor(t->background.color), nil, ZP);
        if(t->border)
                border(im, r, t->border, display->black, ZP);
        for(c=t->cells; c!=nil; c=c->next){
                cr = rectsubpt(c->lay->r, p->pos);
                if(c->background.color != t->background.color)
                        draw(im, cr, getcolor(c->background.color), nil, ZP);
                if(t->border)
                        border(im, cr, t->border, display->black, ZP);
                laydraw(p, im,  c->lay);
        }
}

enum
{
        Tablemax = 2000,
        Ttoplevel = 1<<0,

};

static
void
settable(Table *t)
{
        Tablecell *c;
        Lay *lay;

        for(c=t->cells; c!=nil; c=c->next){
                lay = layitems(c->content, Rect(0,0,0,0), FALSE);
                c->minw = Dx(lay->r);
                layfree(lay);
                if(dimenkind(c->wspec) == Dnone){
                        lay = layitems(c->content, Rect(0,0,Tablemax,0), FALSE);
                        c->maxw = Dx(lay->r);
                        layfree(lay);
                }
        }
}

void
settables(Page *p)
{
        Table *t;
        Item *i;

        if(p->doc==nil)
                return;
        for(i=p->items; i!=nil; i=i->next)
                if(i->tag == Itabletag)
                        ((Itable *)i)->table->flags |= Ttoplevel;

        for(t=p->doc->tables; t!=nil; t=t->next)
                settable(t);
}

static
int
cellwidth(Table *t, Tablecell *c, int sep)
{
        int w, i, n;

        n = c->colspan;
        if(n == 1)
                return t->cols[c->col].width;
        if(n == 0)
                n = t->ncol - c->col;

        w = t->cellspacing*(n-1) + n*sep;
        for(i=c->col; i<c->col+n; i++)
                w += t->cols[i].width;

        return w;
}

static
int
cellheight(Table *t, Tablecell *c, int sep)
{
        int h, i, n;

        n = c->rowspan;
        if(n == 1)
                return t->rows[c->row].height;
        if(n == 0)
                n = t->nrow - c->row;

        h = t->cellspacing*(n-1) + n*sep;
        for(i=c->row; i<c->row+n; i++)
                h += t->rows[i].height;

        return h;
}

static
int
getwidth(int *w, int n)
{
        int i, tot;

        tot = 0;
        for(i=0; i<n; i++)
                tot += w[i];

        return tot;
}

static
void
fixcols(Table *t, int *width, int sep, int domax)
{
        Tablecell *c;
        int w, aw, i, d, n, rem;


        for(c=t->cells; c!=nil; c=c->next){
                if(c->colspan == 1)
                        continue;

                n = c->colspan;
                if(n == 0)
                        n = t->ncol - c->col;

                w = domax ? c->maxw : c->minw;
                w -= t->cellspacing*(n-1) + n*sep;

                aw = 0;
                for(i=c->col; i<c->col+n; i++)
                        aw += width[i];

                rem = w-aw;
                if(rem <= 0)
                        continue;

                for(i=c->col; i<c->col+n; i++){
                        if(aw > 0){
                                d = width[i]*100/aw;
                                d = d*rem/100;
                        }else
                                d = rem/n;
                        width[i] += d;
                }
        }
}

static
int
tablewidth(Table *t, int tw, int sep)
{
        Tablecell *c;
        int i, w, tmin, tmax, d;
        int *maxw, *minw;
        int totw;

        maxw = emalloc(sizeof(int)*t->ncol);
        minw = emalloc(sizeof(int)*t->ncol);
        for(c=t->cells; c!=nil; c=c->next){
                if(dimenkind(c->wspec) != Dnone){
                        d = c->minw;
                        c->minw = c->maxw = max(dimwidth(c->wspec, tw), c->minw);
                        c->minw = d;
                }
                if(c->colspan != 1)
                        continue;
                maxw[c->col] = max(maxw[c->col], c->maxw);
                minw[c->col] = max(minw[c->col], c->minw);
        }
        totw = 0;
        fixcols(t, maxw, sep, TRUE);
        tmax = getwidth(maxw, t->ncol);
        if(tmax <= tw){
                d = 0;
                if(tw>tmax && dimenkind(t->width)!=Dnone && t->availw!=Tablemax)
                        d = (tw-tmax)/t->ncol;
                for(i=0; i<t->ncol; i++){
                        t->cols[i].width = maxw[i] + d;
                        totw += t->cols[i].width;
                }
        }else{
                fixcols(t, minw, sep, FALSE);
                tmin = getwidth(minw, t->ncol);
                w = tw - tmin;
                d = tmax - tmin;
                for(i=0; i<t->ncol; i++){
                        if(w<=0 || d<=0)
                                t->cols[i].width = minw[i];
                        else
                                t->cols[i].width = minw[i] + (maxw[i] - minw[i])*w/d;
                        totw += t->cols[i].width;
                }
        }
        free(minw);
        free(maxw);

        return totw;
}

static
void
fixrows(Table *t, int sep)
{
        Tablecell *c;
        Lay *lay;
        int h, ah, i, d, n, rem;

        for(c=t->cells; c!=nil; c=c->next){
                if(c->rowspan == 1)
                        continue;
                n = c->rowspan;
                if(n==0 || c->row+n>t->nrow)
                        n = t->nrow - c->row;

                lay = layitems(c->content, Rect(0,0,cellwidth(t, c, sep),0), FALSE);
                h = max(Dy(lay->r), c->hspec);
                layfree(lay);
                h -= t->cellspacing*(n-1) + n*sep;
                ah = 0;
                for(i=c->row; i<c->row+n; i++)
                        ah += t->rows[i].height;

                rem = h-ah;
                if(rem <= 0)
                        continue;

                for(i=c->row; i<c->row+n; i++){
                        if(ah > 0){
                                d = t->rows[i].height*100/ah;
                                d = d*rem/100;
                        }else
                                d = rem/n;

                        t->rows[i].height += d;
                }
        }
}

static
int
tableheight(Table *t, int sep)
{
        Tablecell *c;
        Lay *lay;
        int i, h, toth;

        for(i=0; i<t->nrow; i++){
                h = 0;
                for(c=t->rows[i].cells; c!=nil; c=c->nextinrow){
                        if(c->rowspan != 1)
                                continue;
                        lay = layitems(c->content, Rect(0, 0, cellwidth(t, c, sep), 0), FALSE);
                        h = max(h, max(Dy(lay->r), c->hspec));
                        layfree(lay);
                }
                t->rows[i].height = h;
        }
        fixrows(t, sep);
        toth = 0;
        for(i=0; i<t->nrow; i++)
                toth += t->rows[i].height;

        return toth;
}

void
tablesize(Table *t, int availw)
{
        int w, sep, hsep, vsep;

        t->availw = availw;
        sep = 2*(t->border+t->cellpadding);
        hsep = t->cellspacing*(t->ncol+1) + 2*t->border + t->ncol*sep;
        vsep = t->cellspacing*(t->nrow+1) + 2*t->border + t->nrow*sep;
        w = dimwidth(t->width, availw);
        w -= hsep;
        w = w>0 ? w : 0;
        t->totw = tablewidth(t, w, sep);
        t->totw += hsep;
        t->toth = tableheight(t, sep);
        t->toth += vsep;
}

void
laytable(Itable *it, Rectangle r)
{
        Rectangle cr;
        Tablecell *c;
        Table *t;
        int x, y, h, w;
        int sep, i;

        t = it->table;

        sep = (t->cellpadding+t->border) * 2;
        r = insetrect(r, t->cellspacing+t->border);
        for(c=t->cells; c!=nil; c=c->next){
                w = cellwidth(t, c, sep);
                h = cellheight(t, c, sep);
                x = r.min.x;
                if(c->col > 0)
                        for(i=0; i<c->col; i++)
                                x += t->cols[i].width + sep + t->cellspacing;
                y = r.min.y;
                if(c->row > 0)
                        for(i=0;i <c->row; i++)
                                y += t->rows[i].height + sep + t->cellspacing;
                cr = Rect(x, y, x+w+sep, y+h+sep);
                c->lay = layitems(c->content, insetrect(cr, sep/2), TRUE);
                c->lay->r = cr;
        }
}