/* Routines to create various types of gadgets, menus, etc Could do with a few comments and some documentation ... This code is placed in the public domain. David Gay, 1989. */ #include #include #include #include #include #include #include #include #include #include "user/gadgets.h" #include #define XDOUBLEMARGIN 4 /* Margin for "double" border reque sters */ #define YDOUBLEMARGIN 4 #define GADGTEXTX 4 /* How far away (X) text is from Op tion/Radio gadgets */ #define GADGTEXTY 4 /* idem, but when text above gadget */ #define TEXTBORDERX 2 /* How far out text gadget rectangl e is */ #define TEXTBORDERY 4 #define MENUMARGIN 20 /* Spacing between menus */ #define TEXTMARGIN 10 /* Space around text items */ #define TEXTGAP 2 /* Space above & below text items * / #define RULEHEIGHT 2 /* Height of rules */ #define RULEGAP 6 /* Space above & below rules */ #define RULEMARGIN 10 /* idem, but left & right */ #define MINITEMWIDTH (RULEMARGIN + 10) /* Min. menu item width */ #define SUBX 30 /* Sub item position */ boolean CheckFont(struct Memory *); struct Memory { struct MinList Fonts; struct MinList Lists; struct Remember *Mem; }; struct FontNode { struct MinNode fn_Node; struct TextFont *font; }; struct ITextNode { struct MinNode it_node; struct IntuiText it; }; typedef struct Gadget GArray[1]; struct ListInfo { struct MinNode li_node; char *buf; long len; struct List *list; struct MinList ilist; struct IntuiText *blank; long nb, current, pos; struct Gadget *arrow1, *arrow2, *strg, *sld; GArray *glist; long visible, exists, dispchars; ULONG clicksecs, clickmics; long clickpos; }; static struct TextAttr topaz8 = { "topaz.font", 8 }; static BYTE fore = 1, back = 0, mode = JAM1, depth = 2; static struct TextAttr *ta = &topaz8; static boolean fontopen; static struct TextFont *font; static UWORD chip down_data[] = { 0xF83E,0xF83E,0xF83E,0xC006,0xE00E,0xF01E,0xF83E,0xFC7E, 0xFEFE,0xFFFE,0x07C0,0x07C0,0x07C0,0x3FF8,0x1FF0,0x0FE0, 0x07C0,0x0380,0x0100,0x0000 }; static struct Image down_img = { 0, 1, 15, 10, 2, down_data, 0x0003, 0x0000, NULL }; static UWORD chip up_data[] = { 0xFEFE,0xFC7E,0xF83E,0xF01E,0xE00E,0xC006,0xF83E,0xF83E, 0xF83E,0xFFFE,0x0100,0x0380,0x07C0,0x0FE0,0x1FF0,0x3FF8, 0x07C0,0x07C0,0x07C0,0x0000 }; static struct Image up_img = { 0, 1, 15, 10, 2, up_data, 0x0003, 0x0000, NULL }; /* Returns number of nodes, or -1 for failure */ static long build_ilist(struct ListInfo *li) { int cnt = 0; struct Node *scan; NewList((struct List *)&li->ilist); for (scan = li->list->lh_Head; scan->ln_Succ; scan = scan->ln_Succ, cnt++) { struct ITextNode *in = AllocMem(sizeof(struct ITextNode) + li->dispchar s + 1, MEMF_CLEAR); char *str; struct IntuiText *it; int j; if (!in) return -1; it = (struct IntuiText *)&in->it; str = (char *)(in + 1); str[li->dispchars] = '\0'; strncpy(str, scan->ln_Name, li->dispchars); for (j = strlen(str); j < li->dispchars; j++) str[j] = ' '; it->FrontPen = fore; it->BackPen = back; it->DrawMode = JAM2; it->ITextFont = ta; it->IText = str; AddTail((struct List *)&li->ilist, (struct Node *)in); } li->exists = li->visible > cnt ? cnt : li->visible; return cnt; } static void free_ilist(struct ListInfo *li) { struct MinNode *scan, *next; for (scan = li->ilist.mlh_Head; next = scan->mln_Succ; scan = next) FreeMem(scan, sizeof(struct ITextNode) + li->dispchars + 1); } static void recalc_glist(struct ListInfo *li) { int i; struct ITextNode *scan; for (i = 0, scan = (struct ITextNode *)li->ilist.mlh_Head; i < li->pos; i++ , scan = (struct ITextNode *)scan->it_node.mln_Succ) ; for (i = 0; i < li->exists; i++, scan = (struct ITextNode *)scan->it_node.m ln_Succ) (*li->glist)[i].GadgetText = &scan->it; for (; i < li->visible; i++) (*li->glist)[i].GadgetText = li->blank; if (li->current >= li->pos && li->current < li->pos + li->exists) (*li->glist)[li->current - li->pos].Flags |= SELECTED; } struct Memory *NewMemory() { struct Memory *mem; struct Remember *key = NULL; mem = (struct Memory *)AllocRemember(&key, sizeof(struct Memory), MEMF_CLEA R); if (mem) { mem->Mem = key; NewList((struct List *)&mem->Fonts); NewList((struct List *)&mem->Lists); } return(mem); } void Free(mem) struct Memory *mem; { struct MinNode *mn; if (mem) { for (mn = mem->Fonts.mlh_Head; mn->mln_Succ; mn = mn->mln_Succ) CloseFont(((struct FontNode *)mn)->font); for (mn = mem->Lists.mlh_Head; mn->mln_Succ; mn = mn->mln_Succ) free_ilist((struct ListInfo *)mn); FreeRemember(&mem->Mem, TRUE); } } void ModSys(f, b, m, font) long f, b, m; struct TextAttr *font; { if (f != -1) fore = f; if (b != -1) back = b; if (m != -1) mode = m; if (font) { ta = font; fontopen = FALSE; } } void SetDepth(d) long d; { depth = d; } struct Requester *InitReq(left, top, width, height, mem) long left, top, width, height; struct Memory *mem; { struct Requester *req; req = (struct Requester *)AllocRemember(&mem->Mem, sizeof(struct Requester) , MEMF_CLEAR); if (req) { req->LeftEdge = left; req->TopEdge = top; req->Width = width; req->Height = height; req->BackFill = back; } return(req); } boolean SetReqBorder(req, type, mem) struct Requester *req; LONG type; struct Memory *mem; { struct Border *b = NULL; switch (type) { case 1: if (!AddRectBorder(&b, XDOUBLEMARGIN / 2, YDOUBLEMARGIN / 2, req->W idth - XDOUBLEMARGIN, req->Height - YDOUBLEMARGIN, mem)) break; case 0: if (!AddRectBorder(&b, 0, 0, req->Width, req->Height, mem)) b = NULL; break; default: b = (struct Border *)type; break; } return((req->ReqBorder = b) != NULL); } void SetReqGadgets(req, gl) struct Requester *req; struct Gadget *gl; { struct Gadget *g; for (g = gl; g; g = g->NextGadget) g->GadgetType |= REQGADGET; req->ReqGadget = gl; } void SetReqText(req, it) struct Requester *req; struct IntuiText *it; { req->ReqText = it; } struct Gadget *AddBox(gl, id, text, flags, act, x, y, w, h, thick, mem) struct Gadget **gl; char *text; long id, flags, act, x, y, w, h, thick; struct Memory *mem; { BYTE *data; struct Gadget *gadg = NULL; int i, tl, tx, ty, len = strlen(text); struct RastPort rp, rp2; struct BitMap bm, bm2; struct Image *im, *im2; if (CheckFont(mem) && (gadg = (struct Gadget *)AllocRemember(&mem->Mem, sizeof(struct Gadget) + 2 * sizeof(struct Image), MEMF_CLEAR)) && (data = (BYTE *)AllocRemember(&mem->Mem, 2 * depth * RASSIZE(w, h), MEM F_CLEAR | MEMF_CHIP))) { im2 = (im = (struct Image *)(gadg + 1)) + 1; InitBitMap(&bm, depth, w, h); InitBitMap(&bm2, depth, w, h); for (i = 0; i < depth; i++) { bm.Planes[i] = data; bm2.Planes[i] = data + RASSIZE(w, h) * depth; data += RASSIZE(w, h); } InitRastPort(&rp); rp.BitMap = &bm; InitRastPort(&rp2); rp2.BitMap = &bm2; SetAPen(&rp, fore); SetAPen(&rp2, fore); im->Width = im2->Width = w; im->Height = im2->Height = h; im->Depth = im2->Depth = depth; im->ImageData = (USHORT *)bm.Planes[0]; im2->ImageData = (USHORT *)bm2.Planes[0]; im->PlanePick = im2->PlanePick = 0xff; SetRast(&rp, back); SetRast(&rp2, back); DrawRoundedRect(&rp, 0, 0, w, h); FillRoundedRect(&rp2, 0, 0, w, h); if (thick) { DrawRoundedRect(&rp, 1, 1, w - 2, h - 2); DrawRoundedRect(&rp, 1, 0, w - 2, h); } SetFont(&rp, font); SetFont(&rp2, font); tl = TextLength(&rp, text, len); tx = (w - tl) / 2; ty = (h - font->tf_YSize + 1) / 2 + font->tf_Baseline; SetDrMd(&rp, JAM1); Move(&rp, tx, ty); Text(&rp, text, len); SetAPen(&rp2, back); SetDrMd(&rp2, JAM1); Move(&rp2, tx, ty); Text(&rp2, text, len); gadg->LeftEdge = x; gadg->TopEdge = y; gadg->Width = w; gadg->Height = h; gadg->GadgetType = BOOLGADGET; gadg->GadgetRender = (APTR)im; gadg->SelectRender = (APTR)im2; gadg->GadgetID = id; gadg->Flags = GADGHIMAGE | GADGIMAGE | flags; gadg->Activation = act; AppendGadget(gl, gadg); } return(gadg); } struct Gadget *AddRadio(gl, id, text, side, flags, act, mutex, x, y, w, h, mem) struct Gadget **gl; char *text; long id, side, flags, act, x, y, w, h, mutex; struct Memory *mem; { BYTE *data; struct Gadget *gadg = NULL; struct IntuiText *it = NULL; struct RastPort rp, rp2; struct BitMap bm, bm2; struct Image *im, *im2; int tl, bx, i; struct AreaInfo areainf; struct TmpRas tmpras; BYTE areabuf[4 * 5]; PLANEPTR plane; if (AddIntuiText(&it, text, side ? w + GADGTEXTX : 0, 0, mem) && (gadg = (struct Gadget *)AllocRemember(&mem->Mem, sizeof(struct Gadget) + 2 * sizeof(struct Image), MEMF_CLEAR)) && (data = (BYTE *)AllocRemember(&mem->Mem, 2 * depth * RASSIZE(w, h), MEM F_CLEAR | MEMF_CHIP))) { tl = IntuiTextLength(it); it->TopEdge = (h - font->tf_YSize) / 2; gadg->LeftEdge = side ? x : x - tl - GADGTEXTX; gadg->TopEdge = y; gadg->Width = tl + GADGTEXTX + w; gadg->Height = h; gadg->GadgetType = BOOLGADGET; gadg->MutualExclude = mutex; bx = side ? 0 : tl + GADGTEXTX; im2 = (im = (struct Image *)(gadg + 1)) + 1; InitBitMap(&bm, depth, w, h); InitBitMap(&bm2, depth, w, h); for (i = 0; i < depth; i++) { bm.Planes[i] = data; bm2.Planes[i] = data + RASSIZE(w, h) * depth; data += RASSIZE(w, h); } InitRastPort(&rp); rp.BitMap = &bm; InitRastPort(&rp2); rp2.BitMap = &bm2; if (plane = (PLANEPTR)AllocRaster(w, h)) { InitTmpRas(&tmpras, plane, RASSIZE(w, h)); rp2.TmpRas = &tmpras; memset(areabuf, 0, sizeof(areabuf)); InitArea(&areainf, (short *)areabuf, 4); rp2.AreaInfo = &areainf; SetAPen(&rp, fore); SetAPen(&rp2, fore); im->Width = im2->Width = w; im->Height = im2->Height = h; im->LeftEdge = im2->LeftEdge = bx; im->Depth = im2->Depth = depth; im->ImageData = (USHORT *)bm.Planes[0]; im2->ImageData = (USHORT *)bm2.Planes[0]; im->PlanePick = im2->PlanePick = 0xff; SetRast(&rp, back); SetRast(&rp2, back); DrawEllipse(&rp, w/2, h/2, w/2 - 1, h/2 - 1); DrawEllipse(&rp2, w/2, h/2, w/2 - 1, h/2 - 1); AreaEllipse(&rp2, w/2, h/2, w/4, h/4); AreaEnd(&rp2); FreeRaster(plane, w, h); rp2.TmpRas = NULL; rp2.AreaInfo = NULL; gadg->GadgetRender = (APTR)im; gadg->SelectRender = (APTR)im2; gadg->GadgetText = it; gadg->GadgetID = id; gadg->Flags = GADGHIMAGE | GADGIMAGE | flags; gadg->Activation = act; AppendGadget(gl, gadg); } else gadg = NULL; } return(gadg); } struct Gadget *AddOption(gl, id, text, side, flags, act, x, y, w, h, mem) struct Gadget **gl; char *text; long id, side, flags, act, x, y, w, h; struct Memory *mem; { struct Gadget *gadg = NULL; struct IntuiText *it = NULL; struct Border *b = NULL, *b2 = NULL; int tl, bx, f = fore, ba = back; if (AddIntuiText(&it, text, side ? w + GADGTEXTX : 0, 0, mem) && (gadg = (struct Gadget *)AllocRemember(&mem->Mem, sizeof(struct Gadget) , MEMF_CLEAR))) { gadg->Height = h; tl = IntuiTextLength(it); it->TopEdge = (h - font->tf_YSize) / 2; gadg->LeftEdge = side ? x : x - tl - GADGTEXTX; gadg->TopEdge = y; gadg->Width = tl + 4 + w; gadg->GadgetType = BOOLGADGET; bx = side ? 0 : tl + GADGTEXTX; if (AddLineBorder(&b, bx, 0, bx + w - 1, h - 1, mem) && AddLineBorder(&b, bx + w - 1, 0, bx, h - 1, mem) && AddRectBorder(&b, bx, 0, w, h, mem) && (fore = ba, back = f, AddLineBorder(&b2, bx, 0, bx + w - 1, h - 1, mem)) && AddLineBorder(&b2, bx + w - 1, 0, bx, h - 1, mem) && (fore = f, back = ba, AddRectBorder(&b2, bx, 0, w, h, mem))) { gadg->GadgetRender = (APTR)b2; gadg->SelectRender = (APTR)b; gadg->GadgetText = it; gadg->GadgetID = id; gadg->Flags = GADGHIMAGE | flags; gadg->Activation = TOGGLESELECT | act; AppendGadget(gl, gadg); } else gadg = NULL; } fore = f; back = ba; return(gadg); } struct Gadget *AddText(struct Gadget **gl, long id, char *text, long above, cha r *buf, long maxlen, long undo, long flags, long act, long x, long y, long w, lo ng h, long noborder, struct Memory *mem) { BYTE *data; struct StringInfo *si; struct Gadget *gadg = NULL; struct IntuiText *it = NULL; int tl; struct Border *b = NULL; char *undobuf; data = (BYTE *)AllocRemember(&mem->Mem, sizeof(struct Gadget) + sizeof(stru ct StringInfo) + (undo ? maxlen + 1: 0), MEMF_CLEAR); if (data) { gadg = (struct Gadget *)data; si = (struct StringInfo *)(gadg + 1); undobuf = undo ? data + sizeof(struct Gadget) + sizeof(struct StringInf o) : NULL; if (AddIntuiText(&it, text, 0, 0, mem)) { tl = IntuiTextLength(it); if (above) { it->TopEdge = -font->tf_YSize - GADGTEXTY; it->LeftEdge = 0; } else { it->TopEdge = h - font->tf_YSize - 2; it->LeftEdge = -tl - GADGTEXTX; } gadg->LeftEdge = x; gadg->TopEdge = y; gadg->Width = w; gadg->Height = h; gadg->GadgetType = STRGADGET; if (noborder || AddRectBorder(&b, -TEXTBORDERX + 1, -TEXTBORDERY + 1, w + TEXTBORDERX, h + TEXTBORDERY, mem)) { gadg->GadgetRender = (APTR)b; gadg->GadgetText = it; gadg->GadgetID = id; gadg->Flags = GADGHCOMP | flags; gadg->Activation = act; gadg->SpecialInfo = (APTR)si; si->Buffer = buf; si->UndoBuffer = undobuf; si->MaxChars = maxlen; AppendGadget(gl, gadg); } else gadg = NULL; } else gadg = NULL; } return(gadg); } struct Gadget *AddSlider(struct Gadget **gl, long id, long act, long x, long y, long w, long h, long vert, long knobsize, struct Memory *mem) { BYTE *data; struct Gadget *gg = NULL; struct PropInfo *info; struct Image *im; data = (BYTE *)AllocRemember(&mem->Mem, sizeof(struct Gadget) + sizeof(stru ct PropInfo) + sizeof(struct Image), MEMF_CLEAR); if (data) { gg = (struct Gadget *)data; info = (struct PropInfo *)(data + sizeof(struct Gadget)); im = (struct Image *)(data + sizeof(struct Gadget) + sizeof(struct Prop Info)); gg->LeftEdge = x; gg->TopEdge = y; gg->Width = w; gg->Height = h; gg->Flags = GADGHCOMP | GADGIMAGE | (y < 0 ? GRELBOTTOM : 0) | (x < 0 ? GRELRIGHT : 0) | (w < 0 ? GRELWIDTH : 0) | (h < 0 ? GRELHEIGHT : 0); gg->Activation = act; gg->GadgetType = PROPGADGET; gg->GadgetRender = (APTR)im; /* dummy image, why ? */ gg->SpecialInfo = (APTR)info; gg->GadgetID = id; info->Flags = AUTOKNOB | (vert ? FREEVERT : FREEHORIZ); if (vert) info->VertBody = knobsize; else info->HorizBody = knobsize; AppendGadget(gl, gg); } return(gg); } /* BUG: Arrows don't use selected colours */ struct ListInfo *AddList(struct Gadget **gl, long id, char *text, struct List * list, char *buf, long len, long flags, long act, long x, long y, long w, long h, long noborder, struct Memory *mem) { long ok = FALSE; struct ListInfo *li; int i; long nb; int a = font->tf_YSize; int dispchars = (w - 15 - 3) / font->tf_XSize; int nblines = (h - 2) / a; if (CheckFont(mem) && (li = (struct ListInfo *)AllocRemember(&mem->Mem, sizeof(struct ListInf o) + dispchars + 1, MEMF_CLEAR))) { char *spaces = (char *)(li + 1); memset(spaces, ' ', dispchars); spaces[dispchars] = '\0'; AddHead((struct List *)&mem->Lists, (struct Node *)li); if (nblines >= 5 && a * (nblines - 2) - 26 > 20 && w > 15 + 3 + 32) { w = font->tf_XSize * dispchars + 15 + 3; h = a * nblines + 2; li->buf = buf; li->len = len; li->list = list; li->pos = 0; li->current = -1; li->visible = nblines - 2; li->dispchars = dispchars; li->clickpos = -1; if ((li->nb = nb = build_ilist(li)) != -1 && AddIntuiText(&li->blank, spaces, 0, 0, mem)) { struct Gadget *arrow1, *arrow2, *sld; struct Border *b = NULL; long knobsize; if (nb == 0) knobsize = 0xffff; else { knobsize = 0xffff * li->exists; knobsize /= nb; } if ((sld = AddSlider(gl, id, RELVERIFY, x + w - 16, y + 13, 15, h - 2 * a - 26, TRUE, knobsize, mem)) && (arrow1 = (struct Gadget *)AllocRemember(&mem->Mem, 3 * siz eof(struct Gadget), MEMF_CLEAR)) && AddRectBorder(&b, 0, 0, w, h - 2 * a, mem) && AddRectBorder(&b, w - 17, 12, 17, h - 2 * a - 24, mem) && AddLineBorder(&b, w - 17, 0, w - 17, h - 2 * a - 1, mem)) { struct Gadget *strg, *cadre; int tx; sld->UserData = (APTR)li; li->sld = sld; arrow2 = arrow1 + 1; arrow1->TopEdge = y + 1; arrow1->LeftEdge = x + w - 16; arrow1->Width = 15; arrow1->Height = 11; arrow1->Flags = GADGHCOMP | GADGIMAGE; arrow1->Activation = GADGIMMEDIATE | RELVERIFY; arrow1->GadgetType = BOOLGADGET; arrow1->GadgetRender = (APTR)&up_img; arrow1->UserData = (APTR)li; arrow1->GadgetID = id; AppendGadget(gl, arrow1); li->arrow1 = arrow1; arrow2->LeftEdge = x + w - 16; arrow2->TopEdge = y + h - 2 * a - 1 - 11; arrow2->Width = 15; arrow2->Height = 11; arrow2->Flags = GADGHCOMP | GADGIMAGE; arrow2->Activation = GADGIMMEDIATE | RELVERIFY; arrow2->GadgetType = BOOLGADGET; arrow2->GadgetRender = (APTR)&down_img; arrow2->UserData = (APTR)li; arrow2->GadgetID = id; AppendGadget(gl, arrow2); li->arrow2 = arrow2; cadre = arrow2 + 1; cadre->LeftEdge = x; cadre->TopEdge = y; cadre->Width = 1; cadre->Height = 1; cadre->Flags = GADGHNONE; cadre->GadgetType = BOOLGADGET; cadre->GadgetRender = (APTR)b; cadre->UserData = (APTR)li; cadre->GadgetID = id; AppendGadget(gl, cadre); tx = font->tf_XSize * strlen(text); if (tx > w - 32) tx = w - 32; if (strg = AddText(gl, id, text, FALSE, buf, len, TRUE, fla gs, act | GADGIMMEDIATE, x + tx + GADGTEXTX, y + h - a - 2, w - tx - GADGTEXTX, a + 2, noborder, mem)) { GArray *bl; strg->UserData = (APTR)li; li->strg = strg; if (bl = (GArray *)AllocRemember(&mem->Mem, li->visible * sizeof(struct Gadget), MEMF_CLEAR)) { li->glist = bl; for (i = 0; i < li->visible; i++) { struct Gadget *gg = &(*bl)[i]; gg->LeftEdge = x + 1; gg->TopEdge = y + i * a + 1; gg->Width = w - 18; gg->Height = a; gg->Flags = GADGHCOMP; gg->Activation = GADGIMMEDIATE; gg->GadgetType = BOOLGADGET; gg->UserData = (APTR)li; gg->GadgetID = id; AppendGadget(gl, gg); } recalc_glist(li); ok = TRUE; } } } } } } return ok ? li : NULL; } long ModifyList(struct Gadget *gg, struct Requester *req, struct Window *win, l ong up) { struct ListInfo *li = (struct ListInfo *)gg->UserData; int change = FALSE, ret = 0; switch (gg->GadgetType & ~GADGETTYPE) { case STRGADGET: if (!up && li->current != -1) { change = TRUE; (*li->glist)[li->current - li->pos].Flags &= ~SELECTED; li->current = li->clickpos = -1; } else if (up) ret = 1; break; case PROPGADGET: { struct PropInfo *pi = (struct PropInfo *)gg->SpecialInfo; if (li->current != -1) (*li->glist)[li->current - li->pos].Flag s &= ~SELECTED; li->pos = (pi->VertPot + 1) * (li->nb - li->exists) >> 16; recalc_glist(li); change = TRUE; } break; case BOOLGADGET: if (gg == li->arrow1 || gg == li->arrow2) { if (up) { long newpos; if (li->current != -1) (*li->glist)[li->current - li->pos]. Flags &= ~SELECTED; newpos = li->pos + (gg == li->arrow1 ? -1 : 1); if (newpos >= 0 && newpos <= li->nb - li->exists) { struct PropInfo *pi = (struct PropInfo *)li->sld->Speci alInfo; long newpot; li->pos = newpos; newpot = 0xffff * li->pos; newpot /= li->nb - li->exists; NewModifyProp(li->sld, win, req, pi->Flags, 0, newpot, 0, pi->VertBody, 1); recalc_glist(li); change = TRUE; } } } else { int i, pos = -1; for (i = 0; i < li->exists; i++) if (gg == &(*li->glist)[i]) { pos = i; break; } if (pos != -1) { ULONG secs, micros; struct Node *scan; CurrentTime(&secs, µs); if (li->current != -1) (*li->glist)[li->current - li->pos]. Flags &= ~SELECTED; li->current = li->pos + pos; (*li->glist)[pos].Flags |= SELECTED; change = TRUE; li->buf[li->len - 1] = '\0'; for (i = 0, scan = li->list->lh_Head; i < li->current; i++, scan = scan->ln_Succ) ; strncpy(li->buf, scan->ln_Name, li->len - 1); RefreshGList(li->strg, win, req, 1); ret = li->clickpos == li->current && DoubleClick(li->clicks ecs, li->clickmics, secs, micros) ? 2 : 1; li->clickpos = li->current; li->clicksecs = secs; li->clickmics = micros; } } } if (change) RefreshGList(&(*li->glist)[0], win, req, li->exists); return ret; } long ChangeList(struct ListInfo *li, struct List *list, struct Requester *req, struct Window *win) { struct PropInfo *pi = (struct PropInfo *)li->sld->SpecialInfo; long knobsize; free_ilist(li); li->list = list; if ((li->nb = build_ilist(li)) != -1) { if (li->current != -1) (*li->glist)[li->current - li->pos].Flags &= ~SE LECTED; li->pos = 0; li->current = -1; li->clickpos = -1; if (li->nb == 0) knobsize = 0xffff; else { knobsize = 0xffff * li->exists; knobsize /= li->nb; } NewModifyProp(li->sld, win, req, pi->Flags, 0, 0, 0, knobsize, 1); recalc_glist(li); RefreshGList(&(*li->glist)[0], win, req, li->visible); return TRUE; } return FALSE; } struct Gadget *ListStr(struct ListInfo *li) { return li->strg; } struct IntuiText *AddIntuiText(it, str, x, y, mem) struct IntuiText **it; char *str; long x, y; struct Memory *mem; { struct IntuiText *intui = NULL; if (CheckFont(mem)) { intui = (struct IntuiText *)AllocRemember(&mem->Mem, sizeof(struct Intu iText), MEMF_CLEAR); if (intui) { intui->FrontPen = fore; intui->BackPen = back; intui->DrawMode = mode; intui->LeftEdge = x; intui->TopEdge = y; intui->ITextFont = ta; intui->IText = str; AppendText(it, intui); } } return(intui); } struct Border *AddLineBorder(struct Border **border, long x0, long y0, long x1, long y1, struct Memory *mem) { BYTE *data; struct Border *bb = NULL; WORD *vert; data = (BYTE *)AllocRemember(&mem->Mem, sizeof(struct Border) + 2 * 2 * siz eof(WORD), MEMF_CLEAR); if (data) { bb = (struct Border *)data; vert = (WORD *)(data + sizeof(struct Border)); bb->FrontPen = fore; bb->BackPen = back; bb->DrawMode = mode; bb->LeftEdge = 0; bb->TopEdge = 0; bb->Count = 2; bb->XY = vert; vert[0] = x0; vert[1] = y0; vert[2] = x1; vert[3] = y1; AppendBorder(border, bb); } return(bb); } struct Border *AddRectBorder(border, x, y, w, h, mem) struct Border **border; long x, y, w, h; struct Memory *mem; { BYTE *data; struct Border *bb = NULL; WORD *vert; data = (BYTE *)AllocRemember(&mem->Mem, sizeof(struct Border) + 5 * 2 * siz eof(WORD), MEMF_CLEAR); if (data) { bb = (struct Border *)data; vert = (WORD *)(data + sizeof(struct Border)); bb->FrontPen = fore; bb->BackPen = back; bb->DrawMode = mode; bb->LeftEdge = x; bb->TopEdge = y; bb->Count = 5; bb->XY = vert; vert[1 * 2 + 0] = w - 1; vert[2 * 2 + 0] = w - 1; vert[2 * 2 + 1] = h - 1; vert[3 * 2 + 1] = h - 1; AppendBorder(border, bb); } return(bb); } struct Menu *AddMenu(struct Menu **ml, struct Screen *scr, char *text, long fla gs, struct Memory *mem) { struct Screen look; struct TextFont *scrfont; struct Menu *menu = NULL, *prev; if (GetScreenData((char *)&look, sizeof(struct Screen), scr == NULL ? WBENC HSCREEN : CUSTOMSCREEN, scr)) if (scrfont = OpenDiskFont(look.Font)) { if (menu = (struct Menu *)AllocRemember(&mem->Mem, sizeof(struct Me nu), MEMF_CLEAR)) { menu->MenuName = text; menu->Flags = flags; menu->Height = scrfont->tf_YSize + 1; menu->Width = scrfont->tf_XSize * strlen(text) + MENUMARGIN / 2 ; if (*ml == NULL) { menu->LeftEdge = 0; *ml = menu; } else { for (prev = *ml; prev->NextMenu; prev = prev->NextMenu) ; prev->NextMenu = menu; menu->LeftEdge = prev->LeftEdge + prev->Width + MENUMARGIN; } } CloseFont(scrfont); } return menu; } /* Assumes HIRES screen (for COMMWIDTH) */ struct MenuItem *AddItem(struct Menu *menu, char *text, long flags, long mutex, long cmd, long sub, struct Memory *mem) { struct MenuItem *item = NULL, *prev; struct IntuiText *it = NULL; WORD width; if (AddIntuiText(&it, text, TEXTMARGIN / 2, TEXTGAP / 2, mem)) { if (item = (struct MenuItem *)AllocRemember(&mem->Mem, sizeof(struct Me nuItem), MEMF_CLEAR)) { item->LeftEdge = 0; width = IntuiTextLength(it) + TEXTMARGIN; item->Flags = flags | ITEMTEXT; item->Height = font->tf_YSize + TEXTGAP; item->MutualExclude = mutex; item->ItemFill = (APTR)it; if (cmd) { item->Flags |= COMMSEQ; width += COMMWIDTH + font->tf_XSize; item->Command = cmd; } if (sub) width += 2 * font->tf_XSize + TEXTMARGIN / 2; if (width < MINITEMWIDTH) width = MINITEMWIDTH; if (menu->FirstItem) { for (prev = menu->FirstItem; prev->NextItem; prev = prev->NextI tem) ; item->TopEdge = prev->TopEdge + prev->Height; prev->NextItem = item; if (prev->Width > width) item->Width = prev->Width; else for (prev = menu->FirstItem; prev; prev = prev->NextItem) { struct IntuiText *msg; if ((prev->Flags & ITEMTEXT) == 0) /* A rule */ ((struct Image *)(prev->ItemFill))->Width = width - RULEMARGIN; else if ((msg = ((struct IntuiText *)(prev->ItemFill))- >NextText) != NULL) /* A SubItem header */ msg->LeftEdge += width - prev->Width; prev->Width = width; } } else { menu->FirstItem = item; item->TopEdge = 0; item->Width = width; } if (sub && !AddIntuiText(&it, ".", item->Width - TEXTMARGIN / 2 - f ont->tf_XSize, TEXTGAP / 2, mem)) item = NULL; } } return item; } /* Assumes HIRES screen (for COMMWIDTH) */ struct MenuItem *AddSub(struct MenuItem *item, char *text, long flags, long mut ex, long cmd, struct Memory *mem) { struct MenuItem *subitem = NULL, *prev; struct IntuiText *it = NULL; WORD width; if (AddIntuiText(&it, text, TEXTMARGIN / 2, TEXTGAP / 2, mem)) { if (subitem = (struct MenuItem *)AllocRemember(&mem->Mem, sizeof(struct MenuItem), MEMF_CLEAR)) { subitem->LeftEdge = SUBX; width = IntuiTextLength(it) + TEXTMARGIN; subitem->Flags = flags | ITEMTEXT; subitem->Height = font->tf_YSize + TEXTGAP; subitem->MutualExclude = mutex; subitem->ItemFill = (APTR)it; if (cmd) { subitem->Flags |= COMMSEQ; width += COMMWIDTH + font->tf_XSize; subitem->Command = cmd; } if (width < MINITEMWIDTH) width = MINITEMWIDTH; if (item->SubItem) { for (prev = item->SubItem; prev->NextItem; prev = prev->NextIte m) ; subitem->TopEdge = prev->TopEdge + prev->Height; prev->NextItem = subitem; if (prev->Width > width) subitem->Width = prev->Width; else for (prev = item->SubItem; prev; prev = prev->NextItem) prev->Width = width; } else { item->SubItem = subitem; subitem->TopEdge = font->tf_YSize / 2 + 1; subitem->Width = width; } } } return subitem; } /* Inspired by Stuart Ferguson's code */ struct MenuItem *AddRule(struct Menu *menu, struct Memory *mem) { struct MenuItem *item = NULL, *prev; struct Image *img; if ((img = (struct Image *)AllocRemember(&mem->Mem, sizeof(struct Image), M EMF_CLEAR)) && (item = (struct MenuItem *)AllocRemember(&mem->Mem, sizeof(struct MenuI tem), MEMF_CLEAR))) { item->LeftEdge = 0; item->Flags = ITEMENABLED | HIGHNONE; item->Height = RULEGAP + RULEHEIGHT; item->MutualExclude = 0; item->ItemFill = (APTR)img; if (menu->FirstItem) { for (prev = menu->FirstItem; prev->NextItem; prev = prev->NextItem) ; item->TopEdge = prev->TopEdge + prev->Height; prev->NextItem = item; item->Width = prev->Width; } else { menu->FirstItem = item; item->TopEdge = 0; item->Width = MINITEMWIDTH; } img->LeftEdge = RULEMARGIN / 2; img->TopEdge = RULEGAP / 2; img->Width = item->Width - RULEMARGIN; img->Height = RULEHEIGHT; img->Depth = depth; img->ImageData = NULL; img->PlanePick = 0; img->PlaneOnOff = fore; } return item; } boolean CheckFont(mem) struct Memory *mem; { struct FontNode *fn; if (ta == NULL) fontopen = TRUE; if (!fontopen) { font = (struct TextFont *)OpenDiskFont(ta); if (font) { fn = (struct FontNode *)AllocRemember(&mem->Mem, sizeof(struct Font Node), MEMF_CLEAR); if (fn) { fn->font = font; AddHead((struct List *)&mem->Fonts, (struct Node *)fn); fontopen = TRUE; } else CloseFont(font); } } return(fontopen); } void AppendGadget(gl, gg) struct Gadget **gl, *gg; { struct Gadget *gadg; if (*gl == NULL) *gl = gg; else { gadg = *gl; while (gadg->NextGadget) gadg = gadg->NextGadget; gadg->NextGadget = gg; } } void AppendBorder(bl, bb) struct Border **bl, *bb; { struct Border *bord; if (*bl == NULL) *bl = bb; else { bord = *bl; while (bord->NextBorder) bord = bord->NextBorder; bord->NextBorder = bb; } } void AppendText(itl, txt) struct IntuiText **itl, *txt; { struct IntuiText *intui; if (*itl == NULL) *itl = txt; else { intui = *itl; while (intui->NextText) intui = intui->NextText; intui->NextText = txt; } } #define Line(rp, x1, y1, x2, y2) { Move((rp), (x1), (y1)); Draw((rp), (x2), (y2 )); } void DrawRect(rp, x, y, w, h) struct RastPort *rp; long x, y, w, h; { Move(rp, x, y); Draw(rp, x + w - 1, y); Draw(rp, x + w - 1, y + h - 1); Draw(rp, x, y + h - 1); Draw(rp, x, y); } void DrawRoundedRect(rp, x, y, w, h) struct RastPort *rp; long x, y, w, h; { int x2 = x + w - 1, y2 = y + h - 1; Line(rp, x + 5, y, x2 - 5, y); Line(rp, x + 5, y2, x2 - 5, y2); Line(rp, x, y + 5, x, y2 - 4); Line(rp, x2, y + 5, x2, y2 - 4); WritePixel(rp, x + 4, y + 1); WritePixel(rp, x + 3, y + 1); WritePixel(rp, x + 2, y + 2); WritePixel(rp, x + 1, y + 3); WritePixel(rp, x + 1, y + 4); WritePixel(rp, x + 4, y2 - 1); WritePixel(rp, x + 3, y2 - 1); WritePixel(rp , x + 2, y2 - 2); WritePixel(rp, x + 1, y2 - 3); WritePixel(rp, x + 1, y2 - 4); WritePixel(rp, x2 - 4, y + 1); WritePixel(rp, x2 - 3, y + 1); WritePixel(rp , x2 - 2, y + 2); WritePixel(rp, x2 - 1, y + 3); WritePixel(rp, x2 - 1, y + 4); WritePixel(rp, x2 - 4, y2 - 1); WritePixel(rp, x2 - 3, y2 - 1); WritePixel( rp, x2 - 2, y2 - 2); WritePixel(rp, x2 - 1, y2 - 3); WritePixel(rp, x2 - 1, y2 - 4); } void FillRoundedRect(rp, x, y, w, h) struct RastPort *rp; long x, y, w, h; { int x2 = x + w - 1, y2 = y + h - 1; RectFill(rp, x, y + 5, x2, y2 - 5); Line(rp, x + 1, y + 4, x2 - 1, y + 4); Line(rp, x + 1, y + 3, x2 - 1, y + 3 ); Line(rp, x + 2, y + 2, x2 - 2, y + 2); Line(rp, x + 4, y + 1, x2 - 4, y + 1); Line(rp, x + 1, y2 - 4, x2 - 1, y2 - 4); Line(rp, x + 1, y2 - 3, x2 - 1, y2 - 3); Line(rp, x + 2, y2 - 2, x2 - 2, y2 - 2); Line(rp, x + 4, y2 - 1, x2 - 4, y2 - 1); }