summaryrefslogtreecommitdiff
path: root/libtk/packr.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libtk/packr.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libtk/packr.c')
-rw-r--r--libtk/packr.c689
1 files changed, 689 insertions, 0 deletions
diff --git a/libtk/packr.c b/libtk/packr.c
new file mode 100644
index 00000000..14572e79
--- /dev/null
+++ b/libtk/packr.c
@@ -0,0 +1,689 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+typedef struct Pack Pack;
+struct Pack
+{
+ Tk* t;
+ Pack* next;
+};
+static Pack *packorder;
+
+static int tkpacker(Tk *);
+
+typedef struct TkParam TkParam;
+struct TkParam
+{
+ Point pad;
+ Point ipad;
+ int side;
+ int anchor;
+ int fill;
+ Tk* in;
+ Tk* before;
+ Tk* after;
+ int expand;
+};
+
+TkParam defparam = {
+ {-1, -1}, /* p.pad */
+ {-1, -1}, /* p.ipad */
+ -1, /* side */
+ -1, /* anchor */
+ -1, /* fill */
+ nil, /* in */
+ nil, /* before */
+ nil, /* after */
+ BoolX /* expand */
+};
+
+static
+TkStab tkside[] =
+{
+ "top", Tktop,
+ "bottom", Tkbottom,
+ "left", Tkleft,
+ "right", Tkright,
+ nil
+};
+
+static
+TkStab tkfill[] =
+{
+ "none", 0,
+ "x", Tkfillx,
+ "y", Tkfilly,
+ "both", Tkfillx|Tkfilly,
+ nil
+};
+
+static
+TkOption opts[] =
+{
+ "padx", OPTnndist, O(TkParam, pad.x), nil,
+ "pady", OPTnndist, O(TkParam, pad.y), nil,
+ "ipadx", OPTnndist, O(TkParam, ipad.x), nil,
+ "ipady", OPTnndist, O(TkParam, ipad.y), nil,
+ "side", OPTstab, O(TkParam, side), tkside,
+ "anchor", OPTstab, O(TkParam, anchor), tkanchor,
+ "fill", OPTstab, O(TkParam, fill), tkfill,
+ "in", OPTwinp, O(TkParam, in), nil,
+ "before", OPTwinp, O(TkParam, before), nil,
+ "after", OPTwinp, O(TkParam, after), nil,
+ "expand", OPTstab, O(TkParam, expand), tkbool,
+ nil
+};
+
+void
+tkdelpack(Tk *t)
+{
+ Tk *f, **l;
+
+ if(t->master == nil)
+ return;
+
+ if(t->master->grid != nil)
+ tkgriddelslave(t);
+
+ l = &t->master->slave;
+ for(f = *l; f; f = f->next) {
+ if(f == t) {
+ *l = t->next;
+ break;
+ }
+ l = &f->next;
+ }
+ t->master = nil;
+}
+
+void
+tkappendpack(Tk *parent, Tk *tk, int where)
+{
+ Tk *f, **l;
+
+ tk->master = parent;
+ l = &parent->slave;
+ for(f = *l; f; f = f->next) {
+ if(where-- == 0)
+ break;
+ l = &f->next;
+ }
+ *l = tk;
+ tk->next = f;
+
+ for( ; parent != nil; parent = parent->master)
+ if(parent->parent != nil){
+ tk->flag |= Tksubsub;
+ break;
+ }
+}
+
+static void
+tkpackqrm(Tk *t)
+{
+ Pack *f, **l;
+
+ l = &packorder;
+ for(f = *l; f; f = f->next) {
+ if(f->t == t) {
+ *l = f->next;
+ free(f);
+ break;
+ }
+ l = &f->next;
+ }
+}
+
+/* XXX - Tad: leaky... should propagate */
+void
+tkpackqit(Tk *t)
+{
+ Pack *f;
+
+ if(t == nil || (t->flag & Tkdestroy))
+ return;
+
+ tkpackqrm(t);
+ f = malloc(sizeof(Pack));
+ if(f == nil) {
+ print("tkpackqit: malloc failed\n");
+ return;
+ }
+
+ f->t = t;
+ f->next = packorder;
+ packorder = f;
+}
+
+void
+tkrunpack(TkTop *t)
+{
+ Tk *tk;
+ int done;
+
+ while(packorder != nil) {
+ tk = packorder->t;
+ if (tk->grid != nil)
+ done = tkgridder(tk);
+ else
+ done = tkpacker(tk);
+ if (done)
+ tkpackqrm(tk);
+ }
+ tkenterleave(t);
+ tkdirtyfocusorder(t);
+}
+
+static void
+tksetopt(TkParam *p, Tk *tk)
+{
+ if(p->pad.x != -1)
+ tk->pad.x = p->pad.x*2;
+ if(p->pad.y != -1)
+ tk->pad.y = p->pad.y*2;
+ if(p->ipad.x != -1)
+ tk->ipad.x = p->ipad.x*2;
+ if(p->ipad.y != -1)
+ tk->ipad.y = p->ipad.y*2;
+ if(p->side != -1) {
+ tk->flag &= ~Tkside;
+ tk->flag |= p->side;
+ }
+ if(p->anchor != -1) {
+ tk->flag &= ~Tkanchor;
+ tk->flag |= p->anchor;
+ }
+ if(p->fill != -1) {
+ tk->flag &= ~Tkfill;
+ tk->flag |= p->fill;
+ }
+ if(p->expand != BoolX) {
+ if(p->expand == BoolT) {
+ tk->flag |= Tkexpand;
+ }
+ else
+ tk->flag &= ~Tkexpand;
+ }
+}
+
+static char*
+tkforget(TkTop *t, char *arg)
+{
+ Tk *tk;
+ char *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ for(;;) {
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ if(buf[0] == '\0')
+ break;
+ tk = tklook(t, buf, 0);
+ if(tk == nil) {
+ tkrunpack(t);
+ tkerr(t, buf);
+ free(buf);
+ return TkBadwp;
+ }
+ tkpackqit(tk->master);
+ tkdelpack(tk);
+ }
+ free(buf);
+ tkrunpack(t);
+ return nil;
+}
+
+char*
+tkpropagate(TkTop *t, char *arg)
+{
+ Tk *tk;
+ TkStab *s;
+ char *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ tk = tklook(t, buf, 0);
+ if(tk == nil) {
+ tkerr(t, buf);
+ free(buf);
+ return TkBadwp;
+ }
+
+ tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ for(s = tkbool; s->val; s++) {
+ if(strcmp(s->val, buf) == 0) {
+ if(s->con == BoolT) {
+ tk->flag &= ~Tknoprop;
+ tkpackqit(tk);
+ tkrunpack(t);
+ } else
+ tk->flag |= Tknoprop;
+ free(buf);
+ return nil;
+ }
+ }
+ free(buf);
+ return TkBadvl;
+}
+
+static char*
+tkslaves(TkTop *t, char *arg, char **val)
+{
+ Tk *tk;
+ char *fmt, *e, *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ tk = tklook(t, buf, 0);
+ if(tk == nil){
+ tkerr(t, buf);
+ free(buf);
+ return TkBadwp;
+ }
+ free(buf);
+
+ fmt = "%s";
+ for(tk = tk->slave; tk; tk = tk->next) {
+ if (tk->name != nil) {
+ e = tkvalue(val, fmt, tk->name->name);
+ if(e != nil)
+ return e;
+ fmt = " %s";
+ }
+ }
+
+ return nil;
+}
+
+int
+tkisslave(Tk *in, Tk *tk)
+{
+ if(in == nil)
+ return 0;
+ if(in == tk)
+ return 1;
+ for(tk = tk->slave; tk; tk = tk->next)
+ if(tkisslave(in, tk))
+ return 1;
+ return 0;
+}
+
+static char*
+tkcanpack(Tk *tk, Tk *parent)
+{
+ if(tkisslave(parent, tk))
+ return TkRecur;
+ if (parent->grid != nil) {
+ if (parent->slave != nil)
+ return TkIsgrid;
+ tkfreegrid(parent->grid);
+ parent->grid = nil;
+ }
+ return nil;
+}
+
+char*
+tkpack(TkTop *t, char *arg, char **val)
+{
+ TkParam param = defparam;
+ TkParam *p = &param;
+ TkOptab tko[2];
+ Tk *tk, **l, *tkp;
+ TkName *names, *n;
+ char *e, *w, *buf;
+
+ buf = mallocz(Tkminitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ w = tkword(t, arg, buf, buf+Tkminitem, nil);
+ if(strcmp(buf, "forget") == 0) {
+ e = tkforget(t, w);
+ free(buf);
+ return e;
+ }
+ if(strcmp(buf, "propagate") == 0) {
+ e = tkpropagate(t, w);
+ free(buf);
+ return e;
+ }
+ if(strcmp(buf, "slaves") == 0) {
+ e = tkslaves(t, w, val);
+ free(buf);
+ return e;
+ }
+ free(buf);
+
+ tko[0].ptr = p;
+ tko[0].optab = opts;
+ tko[1].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil)
+ return e;
+
+ if((p->before && p->before->master == nil) ||
+ (p->after && p->after->master == nil)) {
+ tkfreename(names);
+ return TkNotpk;
+ }
+
+ for(n = names; n; n = n->link) {
+ tkp = tklook(t, n->name, 0);
+ if(tkp == nil) {
+ tkerr(t, n->name);
+ tkfreename(names);
+ return TkBadwp;
+ }
+ if(tkp->flag & Tkwindow) {
+ tkfreename(names);
+ return TkIstop;
+ }
+ if(tkp->parent != nil) {
+ tkfreename(names);
+ return TkWpack;
+ }
+ n->obj = tkp;
+ }
+
+ e = nil;
+ for(n = names; n; n = n->link) {
+ tk = n->obj;
+ if(tk->master == nil) {
+ tk->pad = ZP;
+ tk->ipad = ZP;
+ tk->flag &= ~(Tkanchor|Tkside|Tkfill|Tkexpand);
+ tk->flag |= Tktop;
+ }
+ if(tk->master != nil) {
+ tkpackqit(tk->master);
+ tkdelpack(tk);
+ }
+ if(p->before == nil && p->after == nil && p->in == nil) {
+ tkp = tklook(t, n->name, 1);
+ if(tkp == nil) {
+ e = TkBadwp;
+ tkerr(t, n->name);
+ goto Error;
+ }
+ e = tkcanpack(tk, tkp);
+ if (e != nil)
+ goto Error;
+ tkappendpack(tkp, tk, -1);
+ }
+ else {
+ if(p->in != nil) {
+ e = tkcanpack(tk, p->in);
+ if(e != nil)
+ goto Error;
+ tkappendpack(p->in, tk, -1);
+ }
+ else
+ if(p->before != nil) {
+ e = tkcanpack(tk, p->before->master);
+ if (e != nil)
+ goto Error;
+ tk->master = p->before->master;
+ l = &tk->master->slave;
+ for(;;) {
+ if(*l == p->before) {
+ tk->next = *l;
+ *l = tk;
+ break;
+ }
+ l = &(*l)->next;
+ }
+ p->before = tk;
+ }
+ else {
+ e = tkcanpack(tk, p->after->master);
+ if (e != nil)
+ goto Error;
+ tk->master = p->after->master;
+ tk->next = p->after->next;
+ p->after->next = tk;
+ p->after = tk;
+ }
+ }
+ tksetopt(p, tk);
+ if (tk->master->flag&Tksubsub)
+ tksetbits(tk, Tksubsub);
+ tkpackqit(tk->master);
+ }
+
+Error:
+ tkfreename(names);
+ tkrunpack(t);
+
+ return e;
+}
+
+void
+tksetslavereq(Tk *slave, TkGeom frame)
+{
+ Point border;
+ TkGeom pos, old;
+ int slave2BW;
+ void (*geomfn)(Tk*);
+
+ border.x = slave->pad.x;
+ border.y = slave->pad.y;
+
+ slave2BW = slave->borderwidth * 2;
+
+ pos.width = slave->req.width + slave2BW + slave->ipad.x;
+ if((slave->flag&Tkfillx) || (pos.width > (frame.width - border.x)))
+ pos.width = frame.width - border.x;
+
+ pos.height = slave->req.height + slave2BW + slave->ipad.y;
+ if((slave->flag&Tkfilly) || (pos.height > (frame.height - border.y)))
+ pos.height = frame.height - border.y;
+
+ border.x /= 2;
+ border.y /= 2;
+
+ if(slave->flag & Tknorth)
+ pos.y = frame.y + border.y;
+ else
+ if(slave->flag & Tksouth)
+ pos.y = frame.y + frame.height - pos.height - border.y;
+ else
+ pos.y = frame.y + (frame.height - pos.height)/2;
+
+ if(slave->flag & Tkwest)
+ pos.x = frame.x + border.x;
+ else
+ if(slave->flag & Tkeast)
+ pos.x = frame.x + frame.width - pos.width - border.x;
+ else
+ pos.x = frame.x + (frame.width - pos.width)/2;
+
+ pos.width -= slave2BW;
+ pos.height -= slave2BW;
+
+ if(memcmp(&slave->act, &pos, sizeof(TkGeom)) != 0) {
+ old = slave->act;
+ slave->act = pos;
+ geomfn = tkmethod[slave->type]->geom;
+ if(geomfn != nil)
+ geomfn(slave);
+ if(slave->slave)
+ tkpackqit(slave);
+ tkdeliver(slave, TkConfigure, &old);
+
+ slave->dirty = tkrect(slave, 1);
+ slave->flag |= Tkrefresh;
+ }
+}
+static int
+tkexpandx(Tk* slave, int cavityWidth)
+{
+ int numExpand, minExpand, curExpand, childWidth;
+
+ minExpand = cavityWidth;
+ numExpand = 0;
+ for( ;slave != nil; slave = slave->next) {
+ childWidth = slave->req.width + slave->borderwidth*2 +
+ slave->pad.x + slave->ipad.x;
+ if(slave->flag & (Tktop|Tkbottom)) {
+ curExpand = (cavityWidth - childWidth)/numExpand;
+ if (curExpand < minExpand)
+ minExpand = curExpand;
+ }
+ else {
+ cavityWidth -= childWidth;
+ if(slave->flag & Tkexpand)
+ numExpand++;
+ }
+ }
+ curExpand = cavityWidth/numExpand;
+ if(curExpand < minExpand)
+ minExpand = curExpand;
+
+ return (minExpand < 0) ? 0 : minExpand;
+}
+
+static int
+tkexpandy(Tk *slave, int cavityHeight)
+{
+ int numExpand, minExpand, curExpand, childHeight;
+
+ minExpand = cavityHeight;
+ numExpand = 0;
+ for ( ;slave != nil; slave = slave->next) {
+ childHeight = slave->req.height + slave->borderwidth*2 +
+ + slave->pad.y + slave->ipad.y;
+ if(slave->flag & (Tkleft|Tkright)) {
+ curExpand = (cavityHeight - childHeight)/numExpand;
+ if(curExpand < minExpand)
+ minExpand = curExpand;
+ }
+ else {
+ cavityHeight -= childHeight;
+ if(slave->flag & Tkexpand)
+ numExpand++;
+ }
+ }
+ curExpand = cavityHeight/numExpand;
+ if(curExpand < minExpand)
+ minExpand = curExpand;
+
+ return (minExpand < 0) ? 0 : minExpand;
+}
+
+static int
+tkpacker(Tk *master)
+{
+ Tk *slave;
+ TkGeom frame, cavity, pos;
+ int maxwidth, maxheight, tmp, slave2BW;
+
+ pos.width = 0;
+ pos.height = 0;
+ maxwidth = 0;
+ maxheight = 0;
+
+ master->flag |= Tkrefresh;
+
+ for (slave = master->slave; slave != nil; slave = slave->next) {
+ slave2BW = slave->borderwidth*2;
+ if(slave->flag & (Tktop|Tkbottom)) {
+ tmp = slave->req.width + slave2BW +
+ slave->pad.x + slave->ipad.x + pos.width;
+ if(tmp > maxwidth)
+ maxwidth = tmp;
+ pos.height += slave->req.height + slave2BW +
+ slave->pad.y + slave->ipad.y;
+ }
+ else {
+ tmp = slave->req.height + slave2BW +
+ slave->pad.y + slave->ipad.y + pos.height;
+ if(tmp > maxheight)
+ maxheight = tmp;
+ pos.width += slave->req.width + slave2BW +
+ + slave->pad.x + slave->ipad.x;
+ }
+ }
+ if(pos.width > maxwidth)
+ maxwidth = pos.width;
+ if(pos.height > maxheight)
+ maxheight = pos.height;
+
+ if(maxwidth != master->req.width || maxheight != master->req.height)
+ if((master->flag & Tknoprop) == 0) {
+ if(master->geom != nil) {
+ master->geom(master, master->act.x, master->act.y,
+ maxwidth, maxheight);
+ } else {
+ master->req.width = maxwidth;
+ master->req.height = maxheight;
+ tkpackqit(master->master);
+ }
+ return 0;
+ }
+
+ cavity.x = 0;
+ cavity.y = 0;
+ pos.x = 0;
+ pos.y = 0;
+ cavity.width = master->act.width;
+ cavity.height = master->act.height;
+
+ for(slave = master->slave; slave != nil; slave = slave->next) {
+ slave2BW = slave->borderwidth*2;
+ if(slave->flag & (Tktop|Tkbottom)) {
+ frame.width = cavity.width;
+ frame.height = slave->req.height + slave2BW +
+ slave->pad.y + slave->ipad.y;
+ if(slave->flag & Tkexpand)
+ frame.height += tkexpandy(slave, cavity.height);
+ cavity.height -= frame.height;
+ if(cavity.height < 0) {
+ frame.height += cavity.height;
+ cavity.height = 0;
+ }
+ frame.x = cavity.x;
+ if(slave->flag & Tktop) {
+ frame.y = cavity.y;
+ cavity.y += frame.height;
+ }
+ else
+ frame.y = cavity.y + cavity.height;
+ }
+ else {
+ frame.height = cavity.height;
+ frame.width = slave->req.width + slave2BW +
+ slave->pad.x + slave->ipad.x;
+ if(slave->flag & Tkexpand)
+ frame.width += tkexpandx(slave, cavity.width);
+ cavity.width -= frame.width;
+ if(cavity.width < 0) {
+ frame.width += cavity.width;
+ cavity.width = 0;
+ }
+ frame.y = cavity.y;
+ if(slave->flag & Tkleft) {
+ frame.x = cavity.x;
+ cavity.x += frame.width;
+ }
+ else
+ frame.x = cavity.x + cavity.width;
+ }
+
+ tksetslavereq(slave, frame);
+ }
+
+ master->dirty = tkrect(master, 1);
+ tkdirty(master);
+ return 1;
+}
+