123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- #include "lib9.h"
- #include "draw.h"
- #include "tk.h"
- #define O(t, e) ((long)(&((t*)0)->e))
- /* Layout constants */
- enum {
- Triangle = 10, /* Height of scroll bar triangle */
- Elembw = 1, /* border around elements (triangles etc.) */
- Scrollbw = 1, /* bevel border on scrollbar */
- Tribw= 1, /* shadow border on triangle */
- };
- typedef struct TkScroll TkScroll;
- struct TkScroll
- {
- int activer;
- int orient; /* Horitontal or Vertical */
- int dragpix; /* Scroll delta in button drag */
- int dragtop;
- int dragbot;
- int jump; /* Jump scroll enable */
- int flag; /* Display flags */
- int top; /* Top fraction */
- int bot; /* Bottom fraction */
- int a1; /* Pixel top/left arrow1 */
- int t1; /* Pixel top/left trough */
- int t2; /* Pixel top/left lower trough */
- int a2; /* Pixel top/left arrow2 */
- char* cmd;
- };
- enum {
- ActiveA1 = (1<<0), /* Scrollbar control */
- ActiveA2 = (1<<1),
- ActiveB1 = (1<<2),
- ButtonA1 = (1<<3),
- ButtonA2 = (1<<4),
- ButtonB1 = (1<<5),
- Autorepeat = (1<<6)
- };
- static
- TkOption opts[] =
- {
- "activerelief", OPTstab, O(TkScroll, activer), tkrelief,
- "command", OPTtext, O(TkScroll, cmd), nil,
- "jump", OPTstab, O(TkScroll, jump), tkbool,
- "orient", OPTstab, O(TkScroll, orient), tkorient,
- nil
- };
- static
- TkEbind b[] =
- {
- {TkLeave, "%W activate {}"},
- {TkEnter, "%W activate [%W identify %x %y]"},
- {TkMotion, "%W activate [%W identify %x %y]"},
- {TkButton1P|TkMotion, "%W tkScrollDrag %x %y"},
- {TkButton1P, "%W tkScrolBut1P %x %y"},
- {TkButton1P|TkDouble, "%W tkScrolBut1P %x %y"},
- {TkButton1R, "%W tkScrolBut1R; %W activate [%W identify %x %y]"},
- {TkButton2P, "%W tkScrolBut2P [%W fraction %x %y]"},
- };
- static char*
- tkinitscroll(Tk *tk)
- {
- int gap;
- TkScroll *tks;
- tks = TKobj(TkScroll, tk);
-
- gap = 2*tk->borderwidth;
- if(tks->orient == Tkvertical) {
- if(tk->req.width == 0)
- tk->req.width = Triangle + gap;
- if(tk->req.height == 0)
- tk->req.height = 2*Triangle + gap + 6*Elembw;
- }
- else {
- if(tk->req.width == 0)
- tk->req.width = 2*Triangle + gap + 6*Elembw;
- if(tk->req.height == 0)
- tk->req.height = Triangle + gap;
- }
- return tkbindings(tk->env->top, tk, b, nelem(b));
- }
- char*
- tkscrollbar(TkTop *t, char *arg, char **ret)
- {
- Tk *tk;
- char *e;
- TkName *names;
- TkScroll *tks;
- TkOptab tko[3];
- tk = tknewobj(t, TKscrollbar, sizeof(Tk)+sizeof(TkScroll));
- if(tk == nil)
- return TkNomem;
- tks = TKobj(TkScroll, tk);
- tk->relief = TKflat;
- tk->borderwidth = 1;
- tks->activer = TKraised;
- tks->orient = Tkvertical;
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tks;
- tko[1].optab = opts;
- tko[2].ptr = nil;
- names = nil;
- e = tkparse(t, arg, tko, &names);
- if(e != nil) {
- tkfreeobj(tk);
- return e;
- }
- tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
- e = tkinitscroll(tk);
- if(e != nil) {
- tkfreeobj(tk);
- return e;
- }
- e = tkaddchild(t, tk, &names);
- tkfreename(names);
- if(e != nil) {
- tkfreeobj(tk);
- return e;
- }
- tk->name->link = nil;
- return tkvalue(ret, "%s", tk->name->name);
- }
- static char*
- tkscrollcget(Tk *tk, char *arg, char **val)
- {
- TkOptab tko[3];
- TkScroll *tks = TKobj(TkScroll, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tks;
- tko[1].optab = opts;
- tko[2].ptr = nil;
- return tkgencget(tko, arg, val, tk->env->top);
- }
- void
- tkfreescrlb(Tk *tk)
- {
- TkScroll *tks = TKobj(TkScroll, tk);
- if(tks->cmd != nil)
- free(tks->cmd);
- }
- static void
- drawarrow(TkScroll *tks, Image *i, Point p[3], TkEnv *e, int activef, int buttonf)
- {
- Image *l, *d, *t;
- int bgnd;
- bgnd = TkCbackgnd;
- if(tks->flag & (activef|buttonf)) {
- bgnd = TkCactivebgnd;
- fillpoly(i, p, 3, ~0, tkgc(e, bgnd), p[0]);
- }
- l = tkgc(e, bgnd+TkLightshade);
- d = tkgc(e, bgnd+TkDarkshade);
- if(tks->flag & buttonf) {
- t = d;
- d = l;
- l = t;
- }
- line(i, p[1], p[2], 0, 0, Tribw-1, d, p[1]);
- line(i, p[2], p[0], 0, 0, Tribw-1, d, p[2]);
- line(i, p[0], p[1], 0, 0, Tribw-1, l, p[0]);
- }
- static void
- drawslider(TkScroll *tks, Image *i, Point o, int w, int h, TkEnv *e)
- {
- Image *l, *d;
- Rectangle r;
- int bgnd;
- bgnd = TkCbackgnd;
- if(tks->flag & (ActiveB1|ButtonB1)) {
- r.min = o;
- r.max.x = o.x + w + Elembw*2;
- r.max.y = o.y + h + Elembw*2;
- bgnd = TkCactivebgnd;
- draw(i, r, tkgc(e, bgnd), nil, ZP);
- }
- l = tkgc(e, bgnd+TkLightshade);
- d = tkgc(e, bgnd+TkDarkshade);
- if(tks->flag & ButtonB1)
- tkbevel(i, o, w, h, Scrollbw, d, l);
- else
- tkbevel(i, o, w, h, Scrollbw, l, d);
- }
- static void
- tkvscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
- {
- TkEnv *e;
- Point p[3], o;
- int bo, w, h, triangle;
- e = tk->env;
- triangle = tk->act.width - Elembw;
- bo = tk->borderwidth + Elembw;
- p[0].x = size.x/2;
- p[0].y = bo;
- p[1].x = p[0].x - triangle/2;
- p[1].y = p[0].y + triangle;
- p[2].x = p[0].x + triangle/2;
- p[2].y = p[0].y + triangle;
- drawarrow(tks, i, p, e, ActiveA1, ButtonA1);
- tks->a1 = p[2].y;
- h = p[2].y + Elembw;
- p[0].y = size.y - bo - 1;
- p[1].y = p[0].y - triangle;
- p[2].y = p[0].y - triangle;
- drawarrow(tks, i, p, e, ActiveA2, ButtonA2);
- tks->a2 = p[2].y;
- o.x = tk->borderwidth ;
- o.y = bo + triangle + 2*Elembw;
- w = size.x - 2*bo;
- h = p[2].y - 2*Elembw - h - 2*tk->borderwidth;
- o.y += TKF2I(tks->top*h);
- h *= tks->bot - tks->top;
- h = TKF2I(h);
- tks->t1 = o.y - Elembw;
- tks->t2 = o.y + h + Elembw;
- drawslider(tks, i, o, w, h, e);
- }
- static void
- tkhscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
- {
- TkEnv *e;
- Point p[3], o;
- int bo, w, h, triangle;
- e = tk->env;
- triangle = tk->act.height - Elembw;
- bo = tk->borderwidth + Elembw;
- p[0].x = bo;
- p[0].y = size.y/2;
- p[1].x = p[0].x + triangle;
- p[1].y = p[0].y - triangle/2 + 1;
- p[2].x = p[0].x + triangle;
- p[2].y = p[0].y + triangle/2 - 2;
- drawarrow(tks, i, p, e, ActiveA1, ButtonA1);
- tks->a1 = p[2].x;
- w = p[2].x + Elembw;
- p[0].x = size.x - bo - 1;
- p[1].x = p[0].x - triangle;
- p[2].x = p[0].x - triangle;
- drawarrow(tks, i, p, e, ActiveA2, ButtonA2);
- tks->a2 = p[2].x;
- o.x = bo + triangle + 2*Elembw;
- o.y = tk->borderwidth;
- w = p[2].x - 2*Elembw - w - 2*tk->borderwidth;
- h = size.y - 2*bo;
- o.x += TKF2I(tks->top*w);
- w *= tks->bot - tks->top;
- w = TKF2I(w);
- tks->t1 = o.x - Elembw;
- tks->t2 = o.x + w + Elembw;
- drawslider(tks, i, o, w, h, e);
- }
- char*
- tkdrawscrlb(Tk *tk, Point orig)
- {
- Point p;
- TkEnv *e;
- Rectangle r;
- Image *i, *dst;
- TkScroll *tks = TKobj(TkScroll, tk);
- e = tk->env;
- dst = tkimageof(tk);
- if(dst == nil)
- return nil;
- r.min = ZP;
- r.max.x = tk->act.width + 2*tk->borderwidth;
- r.max.y = tk->act.height + 2*tk->borderwidth;
- i = tkitmp(e, r.max, TkCbackgnd);
- if(i == nil)
- return nil;
- if(tks->orient == Tkvertical)
- tkvscroll(tk, tks, i, r.max);
- else
- tkhscroll(tk, tks, i, r.max);
- tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
- p.x = tk->act.x + orig.x;
- p.y = tk->act.y + orig.y;
- r = rectaddpt(r, p);
- draw(dst, r, i, nil, ZP);
- return nil;
- }
- /* Widget Commands (+ means implemented)
- +activate
- +cget
- +configure
- +delta
- +fraction
- +get
- +identify
- +set
- */
- static char*
- tkscrollconf(Tk *tk, char *arg, char **val)
- {
- char *e;
- TkGeom g;
- int bd;
- TkOptab tko[3];
- TkScroll *tks = TKobj(TkScroll, tk);
- tko[0].ptr = tk;
- tko[0].optab = tkgeneric;
- tko[1].ptr = tks;
- tko[1].optab = opts;
- tko[2].ptr = nil;
- if(*arg == '\0')
- return tkconflist(tko, val);
- g = tk->req;
- bd = tk->borderwidth;
- e = tkparse(tk->env->top, arg, tko, nil);
- tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
- tkgeomchg(tk, &g, bd);
- tk->dirty = tkrect(tk, 1);
- return e;
- }
- static char*
- tkscrollactivate(Tk *tk, char *arg, char **val)
- {
- int s, gotarg;
- char buf[Tkmaxitem];
- TkScroll *tks = TKobj(TkScroll, tk);
- USED(val);
- tkword(tk->env->top, arg, buf, buf+sizeof(buf), &gotarg);
- s = tks->flag;
- if (!gotarg) {
- char *a;
- if (s & ActiveA1)
- a = "arrow1";
- else if (s & ActiveA2)
- a = "arrow2";
- else if (s & ActiveB1)
- a = "slider";
- else
- a = "";
- return tkvalue(val, a);
- }
- tks->flag &= ~(ActiveA1 | ActiveA2 | ActiveB1);
- if(strcmp(buf, "arrow1") == 0)
- tks->flag |= ActiveA1;
- else
- if(strcmp(buf, "arrow2") == 0)
- tks->flag |= ActiveA2;
- else
- if(strcmp(buf, "slider") == 0)
- tks->flag |= ActiveB1;
- if(s ^ tks->flag)
- tk->dirty = tkrect(tk, 1);
- return nil;
- }
- static char*
- tkscrollset(Tk *tk, char *arg, char **val)
- {
- TkTop *t;
- char *e;
- TkScroll *tks = TKobj(TkScroll, tk);
- USED(val);
- t = tk->env->top;
- e = tkfracword(t, &arg, &tks->top, nil);
- if (e != nil)
- return e;
- e = tkfracword(t, &arg, &tks->bot, nil);
- if (e != nil)
- return e;
- if(tks->top < 0)
- tks->top = 0;
- if(tks->top > TKI2F(1))
- tks->top = TKI2F(1);
- if(tks->bot < 0)
- tks->bot = 0;
- if(tks->bot > TKI2F(1))
- tks->bot = TKI2F(1);
- tk->dirty = tkrect(tk, 1);
- return nil;
- }
- static char*
- tkscrolldelta(Tk *tk, char *arg, char **val)
- {
- int l, delta;
- char buf[Tkmaxitem];
- TkScroll *tks = TKobj(TkScroll, tk);
- arg = tkitem(buf, arg);
- if(tks->orient == Tkvertical)
- tkitem(buf, arg);
- if(*arg == '\0' || *buf == '\0')
- return TkBadvl;
- l = tks->a2-tks->a1-4*Elembw;
- delta = TKI2F(1);
- if(l != 0)
- delta = TKI2F(atoi(buf)) / l;
- tkfprint(buf, delta);
- return tkvalue(val, "%s", buf);
- }
- static char*
- tkscrollget(Tk *tk, char *arg, char **val)
- {
- char *v, buf[Tkmaxitem];
- TkScroll *tks = TKobj(TkScroll, tk);
- USED(arg);
- v = tkfprint(buf, tks->top);
- *v++ = ' ';
- tkfprint(v, tks->bot);
- return tkvalue(val, "%s", buf);
- }
- static char*
- tkscrollidentify(Tk *tk, char *arg, char **val)
- {
- int gotarg;
- TkTop *t;
- char *v, buf[Tkmaxitem];
- Point p;
- TkScroll *tks = TKobj(TkScroll, tk);
- t = tk->env->top;
- arg = tkword(t, arg, buf, buf+sizeof(buf), &gotarg);
- if (!gotarg)
- return TkBadvl;
- p.x = atoi(buf);
- tkword(t, arg, buf, buf+sizeof(buf), &gotarg);
- if (!gotarg)
- return TkBadvl;
- p.y = atoi(buf);
- if (!ptinrect(p, tkrect(tk, 0)))
- return nil;
- if (tks->orient == Tkvertical)
- p.x = p.y;
- p.x += tk->borderwidth;
- v = "";
- if(p.x <= tks->a1)
- v = "arrow1";
- if(p.x > tks->a1 && p.x <= tks->t1)
- v = "trough1";
- if(p.x > tks->t1 && p.x < tks->t2)
- v = "slider";
- if(p.x >= tks->t2 && p.x < tks->a2)
- v = "trough2";
- if(p.x >= tks->a2)
- v = "arrow2";
- return tkvalue(val, "%s", v);
- }
- static char*
- tkscrollfraction(Tk *tk, char *arg, char **val)
- {
- int len, frac, pos;
- char buf[Tkmaxitem];
- TkScroll *tks = TKobj(TkScroll, tk);
- arg = tkitem(buf, arg);
- if(tks->orient == Tkvertical)
- tkitem(buf, arg);
- if(*arg == '\0' || *buf == '\0')
- return TkBadvl;
- pos = atoi(buf);
- if(pos < tks->a1)
- pos = tks->a1;
- if(pos > tks->a2)
- pos = tks->a2;
- len = tks->a2 - tks->a1 - 4*Elembw;
- frac = TKI2F(1);
- if(len != 0)
- frac = TKI2F(pos-tks->a1)/len;
- tkfprint(buf, frac);
- return tkvalue(val, "%s", buf);
- }
- static char*
- tkScrolBut1R(Tk *tk, char *arg, char **val)
- {
- TkScroll *tks = TKobj(TkScroll, tk);
- USED(val);
- USED(arg);
- tkcancelrepeat(tk);
- tks->flag &= ~(ActiveA1|ActiveA2|ActiveB1|ButtonA1|ButtonA2|ButtonB1|Autorepeat);
- tk->dirty = tkrect(tk, 1);
- return nil;
- }
- /* tkScrolBut2P fraction */
- static char*
- tkScrolBut2P(Tk *tk, char *arg, char **val)
- {
- TkTop *t;
- char *e, buf[Tkmaxitem], fracbuf[Tkmaxitem];
- TkScroll *tks = TKobj(TkScroll, tk);
-
- USED(val);
- t = tk->env->top;
- if(arg[0] == '\0')
- return TkBadvl;
- tkword(t, arg, fracbuf, fracbuf+sizeof(fracbuf), nil);
- e = nil;
- if(tks->cmd != nil) {
- snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, fracbuf);
- e = tkexec(t, buf, nil);
- }
- return e;
- }
- static void
- sbrepeat(Tk *tk, void *v, int cancelled)
- {
- char *e, buf[Tkmaxitem];
- TkScroll *tks = TKobj(TkScroll, tk);
- char *fmt = (char *)v;
- if (cancelled) {
- tks->flag &= ~Autorepeat;
- return;
- }
-
- if(tks->cmd != nil && fmt != nil) {
- snprint(buf, sizeof(buf), fmt, tks->cmd);
- e = tkexec(tk->env->top, buf, nil);
- if (e != nil) {
- tks->flag &= ~Autorepeat;
- tkcancelrepeat(tk);
- } else
- tkupdate(tk->env->top);
- }
- }
- /* tkScrolBut1P %x %y */
- static char*
- tkScrolBut1P(Tk *tk, char *arg, char **val)
- {
- int pix;
- TkTop *t;
- char *e, *fmt, buf[Tkmaxitem];
- TkScroll *tks = TKobj(TkScroll, tk);
- USED(val);
- t = tk->env->top;
- if (tks->flag & Autorepeat)
- return nil;
- arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
- if(tks->orient == Tkvertical)
- tkword(t, arg, buf, buf+sizeof(buf), nil);
- if(buf[0] == '\0')
- return TkBadvl;
- pix = atoi(buf);
-
- tks->dragpix = pix;
- tks->dragtop = tks->top;
- tks->dragbot = tks->bot;
- pix += tk->borderwidth;
- fmt = nil;
- e = nil;
- if(pix <= tks->a1) {
- fmt = "%s scroll -1 unit";
- tks->flag |= ButtonA1;
- }
- if(pix > tks->a1 && pix <= tks->t1)
- fmt = "%s scroll -1 page";
- if(pix > tks->t1 && pix < tks->t2)
- tks->flag |= ButtonB1;
- if(pix >= tks->t2 && pix < tks->a2)
- fmt = "%s scroll 1 page";
- if(pix >= tks->a2) {
- fmt = "%s scroll 1 unit";
- tks->flag |= ButtonA2;
- }
- if(tks->cmd != nil && fmt != nil) {
- snprint(buf, sizeof(buf), fmt, tks->cmd);
- e = tkexec(t, buf, nil);
- tks->flag |= Autorepeat;
- tkrepeat(tk, sbrepeat, fmt, TkRptpause, TkRptinterval);
- }
- tk->dirty = tkrect(tk, 1);
- return e;
- }
- /* tkScrolDrag %x %y */
- static char*
- tkScrollDrag(Tk *tk, char *arg, char **val)
- {
- TkTop *t;
- int pix, delta;
- char frac[32], buf[Tkmaxitem];
- TkScroll *tks = TKobj(TkScroll, tk);
- USED(val);
- t = tk->env->top;
- if (tks->flag & Autorepeat)
- return nil;
- if((tks->flag & ButtonB1) == 0)
- return nil;
- arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
- if(tks->orient == Tkvertical)
- tkword(t, arg, buf, buf+sizeof(buf), nil);
- if(buf[0] == '\0')
- return TkBadvl;
- pix = atoi(buf);
- delta = TKI2F(pix-tks->dragpix);
- if ( tks->a2 == tks->a1 )
- return TkBadvl;
- delta = delta/(tks->a2-tks->a1-4*Elembw);
- if(tks->jump == BoolT) {
- if(tks->dragtop+delta >= 0 &&
- tks->dragbot+delta <= TKI2F(1)) {
- tks->top = tks->dragtop+delta;
- tks->bot = tks->dragbot+delta;
- }
- return nil;
- }
- if(tks->cmd != nil) {
- delta += tks->dragtop;
- if(delta < 0)
- delta = 0;
- if(delta > TKI2F(1))
- delta = TKI2F(1);
- tkfprint(frac, delta);
- snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, frac);
- return tkexec(t, buf, nil);
- }
- return nil;
- }
- TkCmdtab tkscrlbcmd[] =
- {
- "activate", tkscrollactivate,
- "cget", tkscrollcget,
- "configure", tkscrollconf,
- "delta", tkscrolldelta,
- "fraction", tkscrollfraction,
- "get", tkscrollget,
- "identify", tkscrollidentify,
- "set", tkscrollset,
- "tkScrollDrag", tkScrollDrag,
- "tkScrolBut1P", tkScrolBut1P,
- "tkScrolBut1R", tkScrolBut1R,
- "tkScrolBut2P", tkScrolBut2P,
- nil
- };
- TkMethod scrollbarmethod = {
- "scrollbar",
- tkscrlbcmd,
- tkfreescrlb,
- tkdrawscrlb
- };
|