/* General purpose interface routines. */ #include "common.h" #include "help.h" /* Since there is no legal way in Vibrant to retrieve the callback for the given object's handle (one needs something like GetAction(obj)) we call an internal Vibrant function. */ #define DoAction(obj) Nlm_DoAction(obj) extern Global(CharPtr PNTR) DialogTxt; /* defined in text.c */ enum { /* see setup.c, init[], /dialog */ OK_B, CANCEL_B, HELP_B, YES_B, NO_B, FIND_T, REPLACE_T, SELALL_B, DESELALL_B, REVSEL_B, SEPARATOR_I, EDIT_M, COPY_I, CUT_I, PASTE_I, CLEAR_I, READ_I, WRITE_I, SEARCH_M, FIND_I, FINDNEXT_I, REPLACE_I, HELP_M, HELPEDIT_I, LSTDIM /* (10,10) ! (ListLines,LineLen) */ } DialogTxtIndex; /* Get Button name */ Global(CharPtr) GetButtonTitle(CharPtr Title) { StrCpy(ParBuf,Title); /* Not implemented yet: extract and erase hot key equivalent */ /* ... */ if (*ParBuf=='"') { StrCpy(ParBuf,ParBuf+1); *StringChr(ParBuf,'"')='\0'; } return ParBuf; } /* Compute spacing between buttons */ #ifdef VAR_ARGS Global(Int2) Spacing(len, horiz, va_alist) Int2 len; Boolean horiz; va_dcl #else Global(Int2) Spacing(Int2 len, Boolean horiz, ...) #endif { Int2 n=1; CharPtr p; ButtoN b; WindoW w; RecT r; va_list ap; w=FixedWindow(0,0,100,100,"",NULL); #ifdef VAR_ARGS va_start(ap); #else va_start(ap,horiz); #endif do { p=va_arg(ap,CharPtr); if (!p) break; b=PushButton(w,GetButtonTitle(p),NULL); GetPosition(b,&r); len-=horiz ? r.right-r.left : r.bottom-r.top; Remove(b); n++; } while (1); va_end(ap); Remove(w); return len>0 ? len/n :(sysCharWidth2); } /*------------------------------*/ /* Ask the user to input a name */ /* Skip input if Len==0 */ Local(Boolean) AskWait; Local(Int2) AskChoice; #if _WIN #pragma argsused #endif Local(void) AskOkProc(ButtoN b) { AskWait=FALSE; AskChoice=0; } #if _WIN #pragma argsused #endif Local(void) AskCancelProc(ButtoN b) { AskWait=FALSE; AskChoice=1; } Local(CharPtr) Askprompt; Local(CharPtr) Askbuf; Local(Int2) Asklen=0; Global(Int2) Ask(CharPtr Prompt, CharPtr Buf, Int2 Len) { WindoW w; GrouP g; TexT t,t0; RecT r; Int2 space,len,l1,l2; #if ZAP2 WindoW cw; cw=CurrentWindow(); /* to restore later */ #endif if (Len<0) { /* couple with the next call */ Askprompt=Prompt; Askbuf=Buf; Asklen=-Len; return 0; } if (Len==0) return myMessage(MSG_OKC,Prompt)==ANS_OK ? 0 : 1; PushContext(GetHelpKey()/***NULL***/,NULL,NULL); /* supress KeyboardView proc */ /* Window */ w=FixedWindow(-50,-50,-sysCharWidth,-sysLineHeight,NULL,NULL); /* Prompt and Dialog */ g=HiddenGroup(w,2,0,NULL); l1=Asklen ? StringWidth(Askbuf) : 0; l2=StringWidth(Buf); len=MAX(l1,l2); len=(Int2)(1.3*len); if (len3*screenRect.right/4) len=3*screenRect.right/4; len/=sysCharWidth; if (Asklen) { StaticPrompt(g,Askprompt,0,dialogTextHeight,NULL,'l'); t0=DialogText(g,Askbuf,len,NULL); } StaticPrompt(g,Prompt,0,dialogTextHeight,NULL,'l'); t=DialogText(g,Buf,len,NULL); /* Define spacing in button group */ GetPosition(g,&r); space=r.right-r.left; g=HiddenGroup(w,2,0,NULL); /* Set spacing and margins and populate the group */ space=Spacing(space,TRUE,DialogTxt[OK_B],DialogTxt[CANCEL_B],NULL); SetGroupMargins(g,space,sysLineHeight4); SetGroupSpacing(g,space,sysLineHeight4); (Asklen ? PushButton : DefaultButton) (g,GetButtonTitle(DialogTxt[OK_B]),AskOkProc); PushButton(g,GetButtonTitle(DialogTxt[CANCEL_B]),AskCancelProc); Show(w); SelectText(Asklen ? t0 : t,0,0); AskWait=TRUE; do { while (AskWait) myProcessAnyEvent(); if (!AskChoice) { /* Get text and put it to the Buf */ if (Asklen) GetTitle(t0,Askbuf,Asklen); GetTitle(t,Buf,Len); #if ZAP3 if (Asklen) if (TextLength(t0)>=Asklen) Askbuf[Asklen-1]='\0'; if (TextLength(t)>=Len) Buf[Len-1]='\0'; #endif if (!Asklen) { StrTrim(Buf); if (*Buf=='\0') AskWait=TRUE; } } } while (AskWait); Remove(w); PopContext(); #if ZAP2 Select(cw); #endif Asklen=0; return AskChoice; } /*----------------*/ /* Message window */ /* Vibrant's Message() disables all the windows. For graphic windows that means cleaning. To avoid this we implement our own Message. */ #include "tsprintf.h" Local(Boolean) msggo; Local(MsgAnswer) msgans; Local(ButtoN) msgO,msgC,msgY,msgN; Local(void) msgProc(ButtoN bt) { msggo=FALSE; if (bt==msgO) { msgans=ANS_OK; return; } if (bt==msgC) { msgans=ANS_CANCEL; return; } if (bt==msgY) { msgans=ANS_YES; return; } if (bt==msgN) { msgans=ANS_NO; return; } } Local(void) (*myMessageUser)(GrouP g)=NULL; Global(void) myMessageSetUser(void (*user)(GrouP g)) { myMessageUser=user; } #ifdef VAR_ARGS Global(MsgAnswer) CDECL myMessage(sevkey, fmt, va_alist) Int2 sevkey; const CharPtr fmt; va_dcl #else Global(MsgAnswer) CDECL myMessage(Int2 sevkey, const CharPtr fmt, ...) #endif { va_list list; const Char PNTR p; Char PNTR q; WindoW win; GrouP g,gb; WindoW cw; Int2 width,space; RecT r; cw=CurrentWindow(); /* to restore later */ PushContext(GetHelpKey()/***NULL***/,NULL,NULL); #ifdef VAR_ARGS va_start(list); #else va_start(list,fmt); #endif p=TSPrintfArgs(fmt,list); va_end(list); msggo=TRUE; win=FixedWindow(-50,-50,-stdCharWidth,-stdLineHeight,NULL,NULL); g=HiddenGroup(win,0,100,NULL); do { q=StrChr(p,'\n'); if (q) *q='\0'; StaticPrompt(g,(CharPtr)p,0,0,NULL,'l'); if (q) p=q+1; else break; } while (TRUE); StaticPrompt(g," ",0,0,NULL,'l'); /* spacing */ if (myMessageUser) { myMessageUser(g); StaticPrompt(g," ",0,0,NULL,'l'); /* spacing */ } GetPosition(g,&r); width=r.right-r.left; gb=HiddenGroup(g,10,0,NULL); msgO=msgC=msgY=msgN=NULL; switch (sevkey) { case MSG_OKC: space=Spacing(width,TRUE,DialogTxt[OK_B],DialogTxt[CANCEL_B],NULL); break; case MSG_YN: space=Spacing(width,TRUE,DialogTxt[YES_B],DialogTxt[NO_B],NULL); break; case MSG_YNC: space=Spacing(width,TRUE,DialogTxt[YES_B],DialogTxt[NO_B],DialogTxt[CANCEL_B],NULL); break; case MSG_OK: default: sevkey=MSG_OK; space=Spacing(width,TRUE,DialogTxt[OK_B],NULL); } SetGroupMargins(gb,space,0); SetGroupSpacing(gb,space,0); if (sevkey==MSG_OK || sevkey==MSG_OKC) msgO=PushButton(gb,GetButtonTitle(DialogTxt[OK_B]),msgProc); if (sevkey==MSG_YN || sevkey==MSG_YNC) { msgY=PushButton(gb,GetButtonTitle(DialogTxt[YES_B]),msgProc); msgN=PushButton(gb,GetButtonTitle(DialogTxt[NO_B]),msgProc); } if (sevkey==MSG_OKC || sevkey==MSG_YNC) msgC=PushButton(gb,GetButtonTitle(DialogTxt[CANCEL_B]),msgProc); Show(win); while (msggo) myProcessAnyEvent(); PopContext(); Select(cw); Remove(win); return msgans; } /* Issues a warning message. The same as Warning (see utility.c) except it calls myMessage instead. Side effect: sets myWarningAnswer. */ Local(MsgAnswer) myWarningAnswer; #ifdef VAR_ARGS Global(Int2) myWarning(Key, va_alist) CharPtr Key; va_dcl #else Global(Int2) myWarning(CharPtr Key,...) #endif { CharPtr saveParBuf,format; va_list list; const Char PNTR p; myWarningAnswer=ANS_OK; saveParBuf=_StringSave(ParBuf); if (GetParamString(SFS_KERNELERRORS,Key)) { format=_StringSave(ParBuf); StrCpy(ParBuf,saveParBuf); #ifdef VAR_ARGS va_start(list); #else va_start(list,Key); #endif p=TSPrintfArgs(format,list); format=_MemMore(format,StrLen(p)+1); StrCpy(format,(CharPtr)p); #if DEB if (myMessage(MSG_OKC,format)==ANS_CANCEL) Abend(); #else /* 1st char may be a control char */ if (!StrNCmp(format,"?okc",4)) myWarningAnswer=myMessage(MSG_OKC,format+4); else if (!StrNCmp(format,"?ync",4)) myWarningAnswer=myMessage(MSG_YNC,format+4); else if (!StrNCmp(format,"?yn",3)) myWarningAnswer=myMessage(MSG_YN,format+3); else myMessage(MSG_OK,format); #endif va_end(list); _MemFree(format); } _MemFree(saveParBuf); return 1; } /*------------------------*/ /* Multi-line text editor */ Local(EditorNotifyPtr) Notify; /* saved notify parameter of CreateEditor */ Local(TexT) Text; /* ScrollText id */ #if _WIN #pragma argsused #endif Local(Boolean) Always_Status(Int2 index) { return TRUE; } /* Call the callback function associated with the text object. This may be needed to allow the calback to record the changes made (e.g. to make a copy of the text - see function.c). */ Local(void) CallCallback(TexT t) { DoAction(t); } /* Copy/Cut/Paste support */ Local(TexT) ActiveText; Global(void) EditTextSelect(TexT t) { ActiveText=t; } #if _WIN #pragma argsused #endif Local(void) CopyProc(Int2 index) { CopyText(ActiveText); } #define CopyProc_Status Always_Status #if _WIN #pragma argsused #endif Local(void) CutProc(Int2 index) { CutText(ActiveText); } #define CutProc_Status Always_Status #if _WIN #pragma argsused #endif Local(void) PasteProc(Int2 index) { PasteText(ActiveText); } #define PasteProc_Status Always_Status #if _WIN #pragma argsused #endif Local(void) ClearProc(Int2 index) { ClearText(ActiveText); } #define ClearProc_Status Always_Status Local(Boolean) IsTextLong(TexT t, Boolean msg) { size_t len; len=TextLength(t); if (len>INT2_MAX) { if (msg) myWarning("ED_TEXTLONG"); return TRUE; } else return FALSE; } #if _WIN #pragma argsused #endif Local(void) ReadProc(Int2 index) { Char FileName[FILENAME_MAX]="*"; FILE *stream; TexT tEdit; CharPtr f,t; long flen; size_t tlen; Int2 b,e; tEdit=ActiveText; /* Windows: GetInputFileName will change ActiveText */ if (IsTextLong(tEdit,TRUE)) return; if (myGetInputFileName(FileName,sizeof(FileName),"*")) { stream=fopen(FileName,"rb"); if (stream) { fseek(stream,0,SEEK_END); flen=ftell(stream); rewind(stream); tlen=TextLength(tEdit)+1; TextSelectionRange(tEdit,&b,&e); t=_MemNew(tlen); GetTitle(tEdit,t,tlen); f=_MemNew(b+(size_t)flen+StrLen(t+e)+1); if (f) { StrNCpy(f,t,b); fread(f+b,sizeof(Char),(size_t)flen,stream); #if _WIN if (f[b+flen-1]=='\x1a') /* DOS EOF */ f[b+flen-1]='\0'; #endif StrCat(f,t+e); e=b+(Int2)flen; SetTitle(tEdit,f); SelectText(tEdit,e,e); _MemFree(f); CallCallback(tEdit); } _MemFree(t); fclose(stream); } } } #define ReadProc_Status Always_Status #if _WIN #pragma argsused #endif Local(void) WriteProc(Int2 index) { Char FileName[FILENAME_MAX]="*"; FILE *stream; TexT tEdit; CharPtr t; size_t tlen; Int2 b,e; Boolean longtxt; tEdit=ActiveText; /* Windows: GetOutputFileName will change ActiveText */ longtxt=IsTextLong(tEdit,FALSE); if (longtxt) { myWarning("ED_WRTLONG"); /* explicitly sets myWarningAnswer */ if (myWarningAnswer==ANS_CANCEL) return; } else myWarningAnswer=ANS_YES; if (myGetOutputFileName(FileName,sizeof(FileName),"")) { stream=fopen(FileName,"wb"); if (stream) { tlen=TextLength(tEdit)+1; if (myWarningAnswer==ANS_YES) TextSelectionRange(tEdit,&b,&e); else {b=1; e=0;} t=_MemNew(tlen); GetTitle(tEdit,t,tlen); if (bTexts; pmd->Lock=0; for (dstack=0, go=(GraphiC)win; (go=Parent(go),go); dstack++); mstack[dstack]=(MenU)win; for (i=f=0; iNum; i++) { f&=~(SUB|END|SUBC|ENDC|STA); p=GetButtonTitle(texts[pmd->Menu[i].Title]); if (StrCmp(p,"-")==0) { /* separator */ SeparatorItem(mstack[dstack]); pmd->Menu[i].Kind=MENU_SEP; continue; } q=p+(StrLen(p)-1); if (*q=='{') { f|=SUB; *q='\0'; } if (*q=='}') { f|=END; *q='\0'; } if (*q=='[') { f|=SUBC; *q='\0'; } if (*q==']') { f|=ENDC; *q='\0'; } if (*q=='?') { f|=STA; *q='\0'; } if (f&SUB) { #if _MAC MenU m; m=AppleMenu(NULL); DeskAccGroup(m); #define PARENT NULL #else #define PARENT (WindoW)mstack[dstack] #endif mstack[dstack+1]=dstack ? SubMenu(mstack[dstack],p) : PulldownMenu(PARENT,p); pmd->Menu[i].ItemId=(IteM)mstack[dstack+1]; pmd->Menu[i].Kind=dstack ? MENU_SUB : MENU_PULLDOWN; dstack++; } else { if (f&SUBC) { mstack[dstack+1]=(MenU)ChoiceGroup(mstack[dstack],(ChsActnProc)umbrella); pmd->Menu[i].ItemId=(IteM)mstack[dstack+1]; pmd->Menu[i].Kind=MENU_CHOICEGRP; dstack++; f|=INC; } else { if (f&INC) { pmd->Menu[i].ItemId=*p ? ChoiceItem((ChoicE)mstack[dstack],p) : 0; pmd->Menu[i].Kind=MENU_CHOICE; } else { if (f&STA) { pmd->Menu[i].ItemId=*p ? StatusItem(mstack[dstack],p,umbrella) : 0; pmd->Menu[i].Kind=MENU_STATUS; } else { pmd->Menu[i].ItemId=*p ? CommandItem(mstack[dstack],p,umbrella) : 0; pmd->Menu[i].Kind=MENU_COMMAND; } } } } if (f&END) dstack--; if (f&ENDC) { dstack--; f&=~INC; } } SetStatusOfItems(pmd); #undef PARENT #undef SUB #undef END #undef SUBC #undef INC #undef ENDC #undef STA } Global(IteM) currentItem; /* for status functions (EnableDisable) */ /* Enable/Disable items depending on their status functions */ /* for status items: check/uncheck status */ Global(void) SetStatusOfItems(MenuDescPtr pmd) { Int2 i; WindoW cw=CurrentWindow(); if (pmd->Lock) return; /* don't refresh locked menu */ UseWindow(ParentWindow(pmd->Menu[0].ItemId)); for (i=0; iNum; i++) if (pmd->Menu[i].EnableDisable) { currentItem=pmd->Menu[i].ItemId; if (pmd->Menu[i].Kind==MENU_STATUS) SetStatus(currentItem,pmd->Menu[i].EnableDisable(i)); else (pmd->Menu[i].EnableDisable(i) ? Enable : Disable)(pmd->Menu[i].ItemId); } UseWindow(cw); } Global(time_t) StartDuration(void) { UpdateInfoInMainWindow(MWI_DURATION,""); return GetSecs(); } Global(void) ShowDuration(time_t begin) { time_t t; Char b[sizeof("hh:mm:ss")+1]; t=GetSecs()-begin; sprintf(b,"%02d:%02d:%02d",(int)(t/3600),(int)((t%3600)/60),(int)(t%60)); UpdateInfoInMainWindow(MWI_DURATION,b); } /* Do menu action */ Global(void) DoMenuAction(MenuDescPtr pmd, IteM it) { time_t t1; Int2 i; Boolean Ilocked; LibraryUnlockRequested(); UseWindow(ParentWindow(it)); /* for Motif */ for (i=0; iNum; i++) if (pmd->Menu[i].ItemId==it) { Ilocked=pmd->Lock==0; if (Ilocked) { /* don't lock twice - see IncompleteAction() */ LockAll(); UpdateInfoInMainWindow(MWI_DURATION,""); t1=GetSecs(); } pmd->Menu[i].Action(i); if (TermFlag) break; /* Main window has been Remove'd by ExitProc */ if (Ilocked) { ShowDuration(t1); UnlockAll(); } break; } } /*---------------------*/ /* Lock/Unlock support */ Local(void) DisableItems(MenuDescPtr pmd) { Int2 i; for (i=0; iNum; i++) if (pmd->Menu[i].Kind!=MENU_STATUS) if (pmd->Menu[i].EnableDisable) Disable(pmd->Menu[i].ItemId); } Global(Int2) Locked(MenuDescPtr pmd) { if (!pmd) return 0; if (pmd->Lock) Beep(); return pmd->Lock; } Global(void) Lock(MenuDescPtr pmd) { if (!pmd->Lock++) DisableItems(pmd); } Global(Int2) Unlock(MenuDescPtr pmd) { if (pmd->Lock) { if (!--pmd->Lock) SetStatusOfItems(pmd); } return pmd->Lock; } Global(void) PauseItems(MenuDescPtr pmd, Boolean enable) { Int2 i; WindoW cw=CurrentWindow(); UseWindow(ParentWindow(pmd->Menu[0].ItemId)); for (i=0; iNum; i++) if (pmd->Menu[i].Flags&MNFL_ACTIVEINPAUSE) { currentItem=pmd->Menu[i].ItemId; /* for EnableDisable() */ (enable && pmd->Menu[i].EnableDisable(i) ? Enable : Disable) (currentItem); } UseWindow(cw); } /*---------------*/ /* Misc routines */ /* GetTitle and Save it in allocated memory */ Global(void) GetTitleAndSave(TexT t, CharPtr PNTR indirptr) { size_t len; if (t) { _MemFree(*indirptr); len=TextLength(t)+1; *indirptr=_MemNew(len); GetTitle(t,*indirptr,len); } } /*-------------------------------------------------*/ /* Creates a list of names with multiple-selection */ Local(PairPtr PNTR) Selection; Local(LisT) List; Local(ButtoN) bSelAll,bDeselAll,bReverseSel; Local(Int1) Level; Local(Int2) offset; Local(void) savelistpos(void) { GetOffset(List,NULL,&offset); Disable(List); } Local(void) restorelistpos(void) { SetOffset(List,0,offset); Enable(List); } /* list buttons callbacks: select all, deselect all, reverse selection */ Local(void) ButtonProc(ButtoN b) { Int2 i,n; n=CountItems(List); savelistpos(); for (i=2; i<=n; i++) { if (b==bSelAll) SetItemStatus(List,i,TRUE); if (b==bDeselAll) SetItemStatus(List,i,FALSE); if (b==bReverseSel) SetItemStatus(List,i,!GetItemStatus(List,i)); } restorelistpos(); /* Simulate clicking the first item - go up */ SetItemStatus(List,1,TRUE); DoAction(List); } Local(void) savemarks(void) { PairPtr pp; Int2 i,k,cnt,n; n=CountItems(List); pp=NULL; _MemFree(Selection[ListCurrentItem-1]); for (k=0,i=1+1; i<=n; i++) { /* the 1st item is .. */ /* skip unselected */ for (; i<=n && !GetItemStatus(List,i); i++); /* count selected */ for (cnt=0; i<=n && GetItemStatus(List,i); cnt++,i++); /* add a pair */ if (cnt) { pp=k ? _MemMore(pp,ARRAYSIZE(Pair,k+1)) : _MemNew(sizeof(Pair)); pp[k].from=i-2-cnt; pp[k].num=cnt; k++; } } if (k) pp[k-1].num=-pp[k-1].num; /* the last pair */ Selection[ListCurrentItem-1]=pp; } Local(int) CountSelected(Int2 cl) { PairPtr pp; int n; pp=Selection[cl]; n=0; if (pp) do { n+=ABS(pp->num); } while ((pp++)->num>0); return n; } /* Multi-selection list's callback */ Local(void) ListProc(LisT List, Int2 Var) { PairPtr pp; Int2 i,n; if (Var==-1) { /* down, to a list of names belongs to particular class */ pp=Selection[ListCurrentItem-1]; if (pp) { savelistpos(); do { n=ABS(pp->num); for (i=0; ifrom+1+i,TRUE); /* the 1st item is .. */ } while ((pp++)->num>0); restorelistpos(); } Enable(bSelAll); Enable(bDeselAll); Enable(bReverseSel); Level++; } if (Var==-2) { /* Up, to list of classes */ savemarks(); Disable(bSelAll); Disable(bDeselAll); Disable(bReverseSel); Level--; } } Global(LisT) MultiNamesList(GrouP g, PairPtr PNTR selection) { GrouP gg; RecT r; int lines,linelen; Int2 space; if (selection) { /* Create list */ Selection=selection; sscanf(DialogTxt[LSTDIM],"(%i,%i)",&lines,&linelen); List=CreateNamesList(g,linelen,lines,ListProc,CountSelected); Level=0; gg=HiddenGroup(g,0,5,NULL); GetPosition(Parent(List),&r); space=r.bottom-r.top; space=Spacing(space,FALSE,DialogTxt[SELALL_B], DialogTxt[DESELALL_B], DialogTxt[REVSEL_B],NULL); SetGroupMargins(gg,0,space); SetGroupSpacing(gg,0,space); bSelAll=PushButton(gg,DialogTxt[SELALL_B],ButtonProc); bDeselAll=PushButton(gg,DialogTxt[DESELALL_B],ButtonProc); bReverseSel=PushButton(gg,DialogTxt[REVSEL_B],ButtonProc); Disable(bSelAll); Disable(bDeselAll); Disable(bReverseSel); } else { /* Store current selections */ if (Level) savemarks(); } return List; } /*====================================*/ /* Create a group of terminal buttons */ Global(GrouP) TermButtons(WindoW win, GrouP samewidth, BtnActnProc OkProc, BtnActnProc CancelProc, BtnActnProc HelpProc) { GrouP g; RecT r; Int2 space; /* Define spacing in button group */ GetPosition(samewidth,&r); space=r.right-r.left; g=HiddenGroup(win,3,0,NULL); if (CancelProc) space=Spacing(space,TRUE,DialogTxt[OK_B], DialogTxt[CANCEL_B], DialogTxt[HELP_B],NULL); else space=Spacing(space,TRUE,DialogTxt[OK_B], DialogTxt[HELP_B],NULL); /* Set spacing and margins and populate the group */ SetGroupMargins(g,space,sysCharWidth2); SetGroupSpacing(g,space,sysCharWidth2); PushButton(g,GetButtonTitle(DialogTxt[OK_B]),OkProc); if (CancelProc) PushButton(g,GetButtonTitle(DialogTxt[CANCEL_B]),CancelProc); PushButton(g,GetButtonTitle(DialogTxt[HELP_B]),HelpProc); return g; } #if MYSWITCH /*---------------*/ /* Custom Switch */ typedef struct { PaneL p; RecT drawrect; Int2 old,new,maxv; Int2 textwidth; PoinT larrow[3],rarrow[3]; ChngProc actn; } SwitchData, PNTR SwitchDataPtr; #if _UNIX /* Margins */ #define LT_M 2 /* Left-Text */ #define TA_M 2 /* Text-LeftArrow */ #define AA_M 2 /* LeftArrow-RightArrow */ #define AR_M 2 /* RightArrow-Right */ #define U_M 2 /* Upper */ #define L_M 1 /* Lower */ #define A_W ((3*sysCharWidth)>>2) /* width of arrows */ #define A_H (sysLineHeight-sysDescent) /* height of arrows */ #endif #if _WIN /* Margins */ #define LT_M 2 /* Left-Text */ #define TA_M 2 /* Text-LeftArrow */ #define AA_M 3 /* LeftArrow-RightArrow */ #define AR_M 3 /* RightArrow-Right */ #define U_M 2 /* Upper */ #define L_M 1 /* Lower */ #define A_W ((3*sysCharWidth)>>2) /* width of arrows */ #define A_H (sysLineHeight-sysDescent) /* height of arrows */ #endif #if _MAC /* Margins */ #define LT_M 2 /* Left-Text */ #define TA_M 2 /* Text-LeftArrow */ #define AA_M 2 /* LeftArrow-RightArrow */ #define AR_M 2 /* RightArrow-Right */ #define U_M 2 /* Upper */ #define L_M 1 /* Lower */ #define A_W ((3*sysCharWidth)>>2) /* width of arrows */ #define A_H (sysLineHeight-sysDescent) /* height of arrows */ #endif Local(void) SwitchLoadData(SwitchDataPtr dp, RectPtr r) { Int2 midh; midh=(r->bottom-L_M+r->top+U_M)/2; LoadRect(&dp->drawrect,r->left+LT_M,r->top+U_M,r->left+LT_M+dp->textwidth,r->top+U_M+stdLineHeight); LoadPt(&dp->larrow[0],r->left+LT_M+dp->textwidth+TA_M+A_W,r->top+U_M); LoadPt(&dp->larrow[1],r->left+LT_M+dp->textwidth+TA_M,midh); LoadPt(&dp->larrow[2],r->left+LT_M+dp->textwidth+TA_M+A_W,r->top+U_M+A_H); LoadPt(&dp->rarrow[0],r->left+LT_M+dp->textwidth+TA_M+A_W+AA_M,r->top+U_M); LoadPt(&dp->rarrow[1],r->left+LT_M+dp->textwidth+TA_M+A_W+AA_M+A_W,midh); LoadPt(&dp->rarrow[2],r->left+LT_M+dp->textwidth+TA_M+A_W+AA_M,r->top+U_M+A_H); } Local(void) SwitchDraw(PaneL sw) { SwitchDataPtr dp=(SwitchDataPtr)GetObjectExtra(sw); RecT r; Char buf[50]; if (!dp) return; /* _WIN: may be called before SetObjectExtra (SwitchCreate) */ Select(sw); SelectFont(SystemFont); GetPosition(sw,&r); SwitchLoadData(dp,&r); FrameRect(&r); sprintf(buf,"%i/%i",(int)dp->new,(int)dp->maxv); DrawString(&dp->drawrect,buf,'r',FALSE); if (dp->new==1) { InvertColors(); PaintPoly(3,dp->larrow); InvertColors(); FramePoly(3,dp->larrow); } else PaintPoly(3,dp->larrow); if (dp->new==dp->maxv) { InvertColors(); PaintPoly(3,dp->rarrow); InvertColors(); FramePoly(3,dp->rarrow); } else PaintPoly(3,dp->rarrow); } Local(void) SwitchUpdate(SwitchDataPtr dp) { RecT r; Select(dp->p); GetPosition(dp->p,&r); InvalRect(&r); Update(); } Local(void) SwitchRelease(PaneL sw, PoinT pt) { SwitchDataPtr dp=(SwitchDataPtr)GetObjectExtra(sw); RecT r,r1; GetPosition(sw,&r); LoadRect(&r1,r.left+LT_M+dp->textwidth+TA_M,r.top+U_M,0,r.bottom-L_M); r1.right=r1.left+A_W; if (PtInRect(pt,&r1)) { if (dp->new>1) { dp->old=dp->new; dp->new--; SwitchUpdate(dp); if (dp->actn) dp->actn((GraphiC)sw,dp->new,dp->old); return; } } LoadRect(&r1,r.left+LT_M+dp->textwidth+TA_M+A_W+AA_M,r.top+U_M,0,r.bottom-L_M); r1.right=r1.left+A_W; if (PtInRect(pt,&r1)) { if (dp->newmaxv) { dp->old=dp->new; dp->new++; SwitchUpdate(dp); if (dp->actn) dp->actn((GraphiC)sw,dp->new,dp->old); } } } #if _WIN #pragma argsused #endif Local(void) FreeData(GraphiC s, VoidPtr dp) { _MemFree(dp); } Global(Switch) SwitchCreate(GrouP prnt, Int2 maxval, ChngProc actn) { Switch sw; SwitchDataPtr dp; RecT r; Char buf[50]; SelectFont(SystemFont); dp=_MemNew(sizeof(SwitchData)); dp->old=dp->new=1; dp->maxv=maxval; dp->actn=actn; sprintf(buf,"%i/%i",(int)maxval,(int)maxval); dp->textwidth=StringWidth(buf); dp->p=sw=SimplePanel(prnt, LT_M+dp->textwidth+TA_M+A_W+AA_M+A_W+AR_M, U_M+MAX(A_H,sysLineHeight)+L_M,SwitchDraw); SetPanelClick(sw,NULL,NULL,NULL,SwitchRelease); GetPosition(sw,&r); SwitchLoadData(dp,&r); SetObjectExtra(sw,dp,FreeData); return sw; } Global(void) SwitchSetValue(Switch sw, Int2 val) { SwitchDataPtr dp=(SwitchDataPtr)GetObjectExtra(sw); dp->old=dp->new; dp->new=val; SwitchUpdate(dp); } Global(Int2) SwitchGetValue(Switch sw) { SwitchDataPtr dp=(SwitchDataPtr)GetObjectExtra(sw); return dp->new; } Global(void) SwitchSetMax(Switch sw, Int2 maxv) { SwitchDataPtr dp=(SwitchDataPtr)GetObjectExtra(sw); dp->maxv=maxv; SwitchUpdate(dp); } Global(void) SwitchSetParams(Switch sw, Int2 val, Int2 maxv) { SwitchDataPtr dp=(SwitchDataPtr)GetObjectExtra(sw); dp->old=dp->new; dp->new=val; dp->maxv=maxv; SwitchUpdate(dp); } Global(Int2) SwitchHeight(void) { SelectFont(SystemFont); return U_M+MAX(A_H,sysLineHeight)+L_M; } #undef LT_M #undef TA_M #undef AA_M #undef AR_M #undef U_M #undef L_M #undef A_W #undef A_H #endif /* MYSWITCH */ /* Read/Write window position */ #define FORMAT "%i/%i,%i/%i" Global(void) ReadWindowPos(CharPtr id, Int2Ptr left, Int2Ptr top) { int l,w,t,h; GetParam(SFS_CURRENTS,id); sscanf(ParBuf,FORMAT,&l,&w,&t,&h); if (w<=0) w=screenRect.right; if (h<=0) h=screenRect.bottom; *left=l<0 ? l : (Int2)((Int4)l*w/screenRect.right); *top=t<0 ? t :(Int2)((Int4)t*h/screenRect.bottom); } Global(void) WriteWindowPos(CharPtr id, WindoW win) { RecT r; GetPosition(win,&r); sprintf(ParBuf,FORMAT,r.left,screenRect.right,r.top,screenRect.bottom); SetParam(SFS_CURRENTS,id,ParBuf); } #undef FORMAT