diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libtk/panel.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libtk/panel.c')
| -rw-r--r-- | libtk/panel.c | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/libtk/panel.c b/libtk/panel.c new file mode 100644 index 00000000..f482a796 --- /dev/null +++ b/libtk/panel.c @@ -0,0 +1,408 @@ +#include "lib9.h" +#include "draw.h" +#include "tk.h" + +#define O(t, e) ((long)(&((t*)0)->e)) + +typedef struct TkPanel TkPanel; +struct TkPanel +{ + Image* image; + Image* matte; + Point view; /* vector from image origin to widget origin */ + Rectangle r; /* drawn rectangle (in image coords) */ + int anchor; + int hasalpha; /* does the image include an alpha channel? */ +}; + +static TkOption tkpanelopts[] = +{ + "anchor", OPTflag, O(TkPanel, anchor), tkanchor, + nil +}; + +static int +tkdrawnrect(Image *image, Image *matte, Rectangle *r) +{ + *r = image->clipr; + if (matte != nil) { + if (!rectclip(r, matte->clipr)) + return 0; + if (!matte->repl && !rectclip(r, matte->r)) + return 0; + } + if (!image->repl && !rectclip(r, image->r)) + return 0; + return 1; +} + +char* +tkpanel(TkTop *t, char *arg, char **ret) +{ + TkOptab tko[3]; + Tk *tk; + TkPanel *tkp; + TkName *names; + char *e; + + tk = tknewobj(t, TKpanel, sizeof(Tk)+sizeof(TkPanel)); + if(tk == nil) + return TkNomem; + + tkp = TKobj(TkPanel, tk); + tkp->anchor = Tkcenter; + + tko[0].ptr = tk; + tko[0].optab = tkgeneric; + tko[1].ptr = tkp; + tko[1].optab = tkpanelopts; + 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 = tkaddchild(t, tk, &names); + + tkfreename(names); + if (e != nil) { + tkfreeobj(tk); + return e; + } + + tk->name->link = nil; + return tkvalue(ret, "%s", tk->name->name); +} + +void +tkgetpanelimage(Tk *tk, Image **i, Image **m) +{ + TkPanel *tkp = TKobj(TkPanel, tk); + *i = tkp->image; + *m = tkp->matte; +} + +void +tksetpanelimage(Tk *tk, Image *image, Image *matte) +{ + TkPanel *tkp = TKobj(TkPanel, tk); + int ishuge; + TkGeom g; + + g = tk->req; + + tkp->image = image; + tkp->matte = matte; + + if (!tkdrawnrect(image, matte, &tkp->r)) { + tkp->r.min = image->r.min; + tkp->r.max = image->r.min; + } + + tkp->view = tkp->r.min; /* XXX do we actually want to keep the old one? */ + /* + * if both image and matte are replicated, then we've got no idea what + * the rectangle should be, so request zero size, and set origin to (0, 0). + */ + ishuge = (Dx(tkp->r) >= 10000000); + if((tk->flag & Tksetwidth) == 0){ + if(ishuge) + tk->req.width = 0; + else + tk->req.width = Dx(tkp->r); + } + if(ishuge) + tkp->view.x = 0; + + ishuge = (Dy(tkp->r) >= 10000000); + if((tk->flag & Tksetheight) == 0){ + if(ishuge) + tk->req.height = 0; + else + tk->req.height = Dy(tkp->r); + } + if(ishuge) + tkp->view.y = 0; + + tkp->hasalpha = tkchanhastype(image->chan, CAlpha); + tkgeomchg(tk, &g, tk->borderwidth); + tksettransparent(tk, tkp->hasalpha || tkhasalpha(tk->env, TkCbackgnd)); + tk->dirty = tkrect(tk, 0); +} + +static void +tkfreepanel(Tk *tk) +{ + TkPanel *tkp = TKobj(TkPanel, tk); + tkdelpanelimage(tk->env->top, tkp->image); + tkdelpanelimage(tk->env->top, tkp->matte); +} + +static Point +tkpanelview(Tk *tk) +{ + int dx, dy; + Point view; + TkPanel *tkp = TKobj(TkPanel, tk); + + dx = tk->act.width - Dx(tkp->r); + dy = tk->act.height - Dy(tkp->r); + + view = tkp->view; + + if (dx > 0) { + if((tkp->anchor & (Tkeast|Tkwest)) == 0) + view.x -= dx/2; + else + if(tkp->anchor & Tkeast) + view.x -= dx; + } + if (dy > 0) { + if((tkp->anchor & (Tknorth|Tksouth)) == 0) + view.y -= dy/2; + else + if(tkp->anchor & Tksouth) + view.y -= dy; + } + return view; +} + +static char* +tkdrawpanel(Tk *tk, Point orig) +{ + Rectangle r, pr; + TkPanel *tkp = TKobj(TkPanel, tk); + Image *i; + int any; + Point view, p; + + i = tkimageof(tk); + if (i == nil) + return nil; + + p.x = orig.x + tk->act.x + tk->borderwidth; + p.y = orig.y + tk->act.y + tk->borderwidth; + + view = tkpanelview(tk); + + /* + * if the image doesn't fully cover the dirty rectangle, then + * paint some background in there + */ + r = rectsubpt(tkp->r, view); /* convert to widget coords */ + pr = tkrect(tk, 0); + any = rectclip(&r, pr); /* clip to inside widget borders */ + + if (!any || tkp->hasalpha || !rectinrect(tk->dirty, r)) + draw(i, rectaddpt(tk->dirty, p), tkgc(tk->env, TkCbackgnd), nil, ZP); + + if (any && rectclip(&r, tk->dirty)) + draw(i, rectaddpt(r, p), tkp->image, tkp->matte, addpt(r.min, view)); + + if (!rectinrect(tk->dirty, pr)) { + p.x -= tk->borderwidth; + p.y -= tk->borderwidth; + tkdrawrelief(i, tk, p, TkCbackgnd, tk->relief); + } + return nil; +} + +static char* +tkpanelcget(Tk *tk, char *arg, char **val) +{ + TkOptab tko[3]; + TkPanel *tkp = TKobj(TkPanel, tk); + + tko[0].ptr = tk; + tko[0].optab = tkgeneric; + tko[1].ptr = tkp; + tko[1].optab = tkpanelopts; + tko[2].ptr = nil; + + return tkgencget(tko, arg, val, tk->env->top); +} + +static char* +tkpanelcvt(Tk *tk, char *arg, int rel, int *p) +{ + char buf[Tkmaxitem]; + + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + *p = atoi(buf) + rel; + return nil; +} + +/* + * screen to image + */ +static char* +tkpanelpanelx(Tk *tk, char *arg, char **val) +{ + Point p; + char *e; + + USED(val); + p = subpt(tkposn(tk), tkpanelview(tk)); + e = tkpanelcvt(tk, arg, -p.x, &p.x); + if (e != nil) + return e; + return tkvalue(val, "%d", p.x); +} + +static char* +tkpanelpanely(Tk *tk, char *arg, char **val) +{ + Point p; + char *e; + + USED(val); + p = subpt(tkposn(tk), tkpanelview(tk)); + e = tkpanelcvt(tk, arg, -p.y, &p.y); + if (e != nil) + return e; + return tkvalue(val, "%d", p.y); +} + +/* + * image to screen + */ +static char* +tkpanelscreenx(Tk *tk, char *arg, char **val) +{ + Point p; + char *e; + + USED(val); + p = subpt(tkposn(tk), tkpanelview(tk)); + e = tkpanelcvt(tk, arg, p.x, &p.x); + if (e != nil) + return e; + return tkvalue(val, "%d", p.x); +} + +static char* +tkpanelscreeny(Tk *tk, char *arg, char **val) +{ + Point p; + char *e; + + USED(val); + p = subpt(tkposn(tk), tkpanelview(tk)); + e = tkpanelcvt(tk, arg, p.y, &p.y); + if (e != nil) + return e; + return tkvalue(val, "%d", p.y); +} + +static char* +tkpanelconf(Tk *tk, char *arg, char **val) +{ + char *e; + TkGeom g; + int bd; + TkOptab tko[3]; + TkPanel *tkp = TKobj(TkPanel, tk); + + tko[0].ptr = tk; + tko[0].optab = tkgeneric; + tko[1].ptr = tkp; + tko[1].optab = tkpanelopts; + 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); + tkgeomchg(tk, &g, bd); + tksettransparent(tk, tkp->hasalpha || tkhasalpha(tk->env, TkCbackgnd)); + + tk->dirty = tkrect(tk, 1); + + return e; +} + +static char* +tkpaneldirty(Tk *tk, char *arg, char **val) +{ + char buf[Tkmaxitem]; + int n, coords[4]; + Rectangle r; + char *e, *p; + TkPanel *tkp = TKobj(TkPanel, tk); + + USED(val); + n = 0; + while (n < 4) { + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if (buf[0] == 0) + break; + p = buf; + e = tkfrac(&p, &coords[n++], nil); + if (e != nil) + return TkBadvl; + } + if (n == 0) + r = tkp->r; + else { + if (n != 4) + return TkBadvl; + r.min.x = TKF2I(coords[0]); + r.min.y = TKF2I(coords[1]); + r.max.x = TKF2I(coords[2]); + r.max.y = TKF2I(coords[3]); + } + if (rectclip(&r, tkp->r)) { + r = rectsubpt(r, tkpanelview(tk)); /* convert to widget coords */ + if (rectclip(&r, tkrect(tk, 0))) /* clip to visible area */ + combinerect(&tk->dirty, r); + } + return nil; +} + +static char* +tkpanelorigin(Tk *tk, char *arg, char **val) +{ + char *e; + Point view; + TkPanel *tkp = TKobj(TkPanel, tk); + + e = tkxyparse(tk, &arg, &view); + if (e != nil) { + if (e == TkOparg) + return tkvalue(val, "%d %d", tkp->view.x, tkp->view.y); + return e; + } + tkp->view = view; + tk->dirty = tkrect(tk, 0); + return nil; +} + +static +TkCmdtab tkpanelcmd[] = +{ + "cget", tkpanelcget, + "configure", tkpanelconf, + "dirty", tkpaneldirty, + "origin", tkpanelorigin, + "panelx", tkpanelpanelx, + "panely", tkpanelpanely, + "screenx", tkpanelscreenx, + "screeny", tkpanelscreeny, + nil +}; + +TkMethod panelmethod = { + "panel", + tkpanelcmd, + tkfreepanel, + tkdrawpanel +}; |
