/* File: ksetdisp.c * Author: Jean Thierry-Mieg (mieg@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1991 * ------------------------------------------------------------------- * Acedb is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: Manipulate Key Sets. keyset windows have their own menus and KEYSET. When they are destroyed they (VERY IMPORTANT) destroy the keyset. * Exported functions: * HISTORY: * Last edited: May 6 10:21 2003 (edgrif) * - fn() to void(void) to please WIN32 compiler * * Jun 10 16:53 1996 (il) * * Oct 15 15:15 1992 (mieg): Mailer * * Nov 5 18:27 1991 (mieg): I introduced keySetAlpha * * Oct 23 18:53 1991 (mieg): changed name dump to a keySetDump * * May 1996 (il) : added scroll bar to keyset's and rearranged the menus. * * : ability to select/highlight members of the keyset and * * : perform the usual operation's on them. * Created: Wed Oct 23 18:52:00 1991 (mieg) * CVS info: $Id: ksetdisp.c,v 1.140 2003/05/06 13:13:09 edgrif Exp $ *------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* our own public header */ #include #include #include #include /* keySetShow () displays a KEYSET (a sorted array of KEY's) in multicolumn format, allowing the user to pick and move around with arrow keys. Objects are displayed with default displaytype. To initialise the system, call with handle==0. It returns the new handle. To reuse the graph call first with (0,handle) to kill the alphabetic keyset. The aim of this is to allow the user to change the displayed KEYSET. keySetGetShowAs() let's you find out which "Show As"-displayType has been selected in a given keyset-window. It returns NULL by default. This return value can be used as the third argument for display(), where NULL also causes the default display type to be determined. Although we can save to permanent objects (by the menu Save option) and recover from them (via display() and keySetDispCreate()), a keyset display window is NEVER attached to an object - it always deals in copies of the permanent keyset. This allows much greater flexibility in changing the contents of a window, avoids tangles with the cache, and is absolutely necessary. */ #define COLWIDTH 16 #define MAXOBS 1000 #define SCROLLBARGAP 4 #define SCROLLBARPOS 1.0 #define MINSCROLLBARLENGTH 0.7 #define BOTGAP 1 #define DEFAULT 0 /* check that these numbers are ok in menuOptions */ #define OR 21 #define AND 22 #define XOR 23 #define MINUS 24 #define UP TRUE #define DOWN FALSE #define MAX_CLASSES 200 /* rounding - nearest int */ #define nint(x) (((x) > 0) ? ((int)(x + .5)) : -((int)(.5 - x)) ) /************************************************************/ /* complete the opaque datastructure from keysetdisp.h */ struct KeySetDispStruct { magic_t *magic; /* == &KeySetDisp_MAGIC */ KEYSET kSet , keySetAlpha ,selected; BOOL fullAlpha ; /* complete call to keySetAlphaHeap done */ KEY curr ; KEY showtype; Graph graph, owner ; BOOL isBlocking ; int base, top ; /* top is 1 + index of last displayed key */ Array box2key ; BOOL showClass ; int showQuery; /* 0: no, 1:yes-nofocus, 2:yes-focus */ float scrolllen; char txtBuffer[60], queryBuffer[256] ; int numperpage, colWidth[50]; int txtbox,numselpage,queryBox; int scrollBarBox,upBox,downBox,firstBox,lastBox; int itemBoxStart,itemBoxEnd; int nitem, nselected ; char touched ; char *message ; KEY keySetKey ; /* the key if displaying a KEYSET class object */ } ; static magic_t KeySetDisp_MAGIC = "KeySetDisp"; static magic_t GRAPH2KeySetDisp_ASSOC = "KeySetDisp"; static BOOL isOtherTools = FALSE ; /* extended set of buttons for specialists */ static float TOPGAP ; static int N3rdLINE, NQueryLine ; static int startbox,lastbox,numboxes,oldcol, oldy ; static KeySetDisp selectedKeySet = 0 ; static FREEOPT menuOptions[] = { {19,"Key Set ?"}, {99,"Quit"}, {98,"Help"}, {97, "Print"}, {0,""}, {7,"New empty keyset"}, {10,"Import keyset"}, {2,"Copy whole keyset"}, {1,"Save as"}, {0,""}, {6,"Add-Remove"}, {OR,"OR"}, /* reserved 20-26 for these */ {AND,"AND"}, {MINUS,"MINUS"}, {XOR,"XOR"}, {0,""}, /* 47,"Show/Hide Classes", */ {41,"Mail"}, {51,"Keyset Summary"}, {45,"Show as Multimap"}, {8,"Show as Text"}, } ; static void localDestroy (void) ; static void localPick (int box,double x,double y, int modifier_unused) ; static void localKbd (int k, int modifier_unused) ; static void ksetlocalMenu (KEY k, int unused) ; static void pageUp(void), pageDown(void) ; static KeySetDisp keySetShow2 (KEYSET kSet, KeySetDisp look) ; static void ksetAddKey (KEY key) ; static void ksetDeleteKey (KEY key) ; static void ksetUnBlock (void) ; static void controlLeftDown (double x, double y); static void controlLeftUp (double x, double y); static void controlLeftDrag (double x, double y); static void selectedToNewKeySet(void); static BOOL columnWidth(int startpos,int direction,int *width,int *endpos,int numrows); static void drawMenus(void); static void drawScrollBar(int max); static void keySetMix(KeySetDisp qry, int combinetype); static void keySetSummary(void); static void changeShowtype(KEY key); static void nextShowtype(void); static void scrollMiddleUp (double x, double y); static void keySetSelect (void); static BOOL importKeySet(KEYSET kSet, ACEIN keyset_in); /* Dumping routines. */ static void dumpAsDnaFasta(void) ; static void dumpAsCDSDnaFasta(void) ; static void dumpDnaFasta(BOOL cds_only) ; static void dumpAsProtFasta(void) ; static void dumpAsCDSProtFasta(void) ; static void dumpProtFasta(BOOL cds_only) ; /************************************************************/ static KeySetDisp currentKeySetDisp (char *caller) { KeySetDisp ksdisp; if (!graphAssFind (&GRAPH2KeySetDisp_ASSOC,&ksdisp)) messcrash("%s() could not find KeySetDisp on graph", caller); if (!ksdisp) messcrash("%s() received NULL KeySetDisp pointer", caller); if (ksdisp->magic != &KeySetDisp_MAGIC) messcrash("%s() received non-magic KeySetDisp pointer", caller); return ksdisp; } /* currentKeySetDisp */ static int scrollTriangle(BOOL direction, float x, float y, int colour) { int i = 3, box,col; float incr; Array temp ; if(direction) incr = -1.0; else incr = 1.0; box = graphBoxStart(); col = graphColor(colour); temp = arrayCreate(2*i, float) ; array(temp, 0, float) = x; array(temp, 1, float) = y; array(temp, 2, float) = x+2.0; array(temp, 3, float) = y; array(temp, 4, float) = x+1.0; array(temp, 5, float) = y+incr; graphPolygon(temp); col = graphColor(col); graphLine(x, y, x+2.0, y); graphLine(x+2.0, y, x+1.0, y+incr); graphLine(x+1.0, y+incr, x, y); arrayDestroy(temp); graphBoxEnd(); return box; } /******************************/ static int nItem (KeySetDisp look) { int i, nitem = 0 ; if (!(look->touched & 2)) return look->nitem ; if (look->fullAlpha && keySetExists(look->keySetAlpha)) return keySetMax(look->keySetAlpha) ; if (keySetExists(look->kSet)) { KEY *kp = arrp (look->kSet, 0, KEY) - 1 ; i = keySetMax(look->kSet) ; while (kp++, i--) if (lexIsKeyVisible(*kp)) nitem++ ; } look->nitem = nitem ; look->touched &= 0x1 ; /* not 2 */ return nitem ; } /* mhmp 04.09.98 forcement necessaire comme nItem */ static int nSelected (KeySetDisp look) { int i, nselected = 0 ; if (!(look->touched & 1)) return look->nselected ; if (keySetExists(look->selected)) { KEY *kp = arrp (look->selected, 0, KEY) - 1 ; i = keySetMax(look->selected) ; while (kp++, i--) if (*kp && lexIsKeyVisible(*kp)) nselected++ ; } look->nselected = nselected ; look->touched &= 0x2 ; /* not 1 */ return nselected ; } static void shownItem (KeySetDisp look) { if (look->touched) { nItem (look) ; nSelected (look) ; } if(look->numselpage == look->nselected) sprintf(look->txtBuffer,"%d items %d selected", look->nitem, look->nselected); else sprintf(look->txtBuffer,"%d items %d selected (%d off screen)", look->nitem, look->nselected,look->nselected-look->numselpage) ; } /******************************/ /** fake biblio functions **/ /** for model free kernel **/ /******************************/ static BOOL setPage(float *z) { int w,h ; float temp,top,bottom; int max; KeySetDisp look = currentKeySetDisp ("setPage") ; if (look != selectedKeySet) keySetSelect () ; look->curr = 0; max = nItem (look) ; graphFitBounds(&w,&h); top = (float)TOPGAP; bottom = (float)(h - BOTGAP); if(*z<=top) look->base = 0; else if(*z+look->scrolllen >= bottom){ look->base = max; if (!look->fullAlpha && keySetMax(look->keySetAlpha) < keySetMax(look->kSet) && /* load extra items needed */ keySetMax(look->keySetAlpha) < look->base + 200) { keySetDestroy(look->keySetAlpha) ; look->keySetAlpha = keySetAlphaHeap(look->kSet, keySetMax(look->kSet)) ; look->fullAlpha = TRUE ; } } else{ if(look->scrolllen==MINSCROLLBARLENGTH) temp = (*z-top)/(bottom-top-look->scrolllen); else temp = (*z-top)/(bottom-top); look->base = (int)(temp * max); if(look->base > max){ look->base=max; } } return TRUE; } static void keyBandDrag(float *x, float *y, BOOL isUP) { float top,bottom; int nx,ny; KeySetDisp look = currentKeySetDisp ("keyBandDrag") ; *x = 0.5; /* x is set to the middle */ top = (float)TOPGAP; graphFitBounds (&nx, &ny) ; bottom = (float)(ny - BOTGAP); if(*y > bottom - look->scrolllen) *y = bottom - look->scrolllen; if(*y < top ) *y = top; if(isUP) /* after scrolling has finished */ { if(setPage(y)){ if(look->base == keySetMax(look->keySetAlpha)){ --look->base; pageUp(); return; } if (look != selectedKeySet) keySetSelect () ; keySetShow2 (look->kSet, look) ; } } } static void pageUp(void) { int nx,ny,colX,startpos,endpos,numrows,cWidth; BOOL room= TRUE; KeySetDisp look = currentKeySetDisp ("pageUp") ; if (look->base) { graphFitBounds (&nx, &ny) ; colX = SCROLLBARGAP; startpos = look->base+1; /* il +1 to keep last item still on page */ numrows = ny-(TOPGAP+BOTGAP); while(room) { startpos--; room = columnWidth(startpos,FALSE,&cWidth,&endpos,numrows); /* mhmp comme dans keySetShow2 */ if((cWidth && (colX + cWidth) < nx) || colX == SCROLLBARGAP) { /* if it fits or is the first */ startpos= endpos; look->base = endpos; } else room = FALSE; colX += cWidth +2; } if(look->base < 0) /* returns -1 if before start of first page */ look->base = 0; look->curr = 0; keySetShow2 (look->kSet, look) ; } } /* pageUp */ static void pageDown(void) { KeySetDisp look = currentKeySetDisp ("pageDown") ; if (look->top+1 < keySetMax(look->keySetAlpha)) { look->base = look->top ; /* removed +1 to keep last item on next page */ look->curr = 0; keySetShow2 (look->kSet, look) ; } } /* pageDown */ static void localResize (void) { KeySetDisp look = currentKeySetDisp("localResize") ; look->curr = 0; keySetShow2 (look->kSet, look) ; } static void none(void) { } static void keySetDispDump (KeySetDisp look, BOOL isAceDump, BOOL isTimeStamps) { /* .ace dump */ static char directory[DIR_BUFFER_SIZE] = ""; static char filename[FIL_BUFFER_SIZE] = ""; ACEOUT dump_out; register int i; char *prompt; if (!look->keySetAlpha) return ; prompt = messprintf ("Where do you wish to export the %s ?", isAceDump ? ".ace-file data" : "keyset list"); dump_out = aceOutCreateToChooser (prompt, directory, filename, "ace", "w", 0); if (!dump_out) return; if (!look->fullAlpha && keySetMax(look->kSet) > keySetMax(look->keySetAlpha)) { keySetDestroy(look->keySetAlpha) ; look->keySetAlpha = keySetAlphaHeap(look->kSet, keySetMax(look->kSet)) ; look->fullAlpha = TRUE ; } if (isAceDump) /* write out a full acedump of every object */ { dumpTimeStamps = isTimeStamps ; aceOutPrint (dump_out, "// data dumped from keyset display\n\n") ; for (i = 0 ; i < keySetMax(look->keySetAlpha) ; ++i) if (!dumpKey (dump_out, keySet(look->keySetAlpha,i))) if (!messQuery("Do you want to proceed ?")) break ; dumpTimeStamps = FALSE; } else /* write out the acedump of the keyset itself */ { aceOutPrint (dump_out, "KeySet : \"%s\"\n",filename) ; keySetDump(dump_out, look->keySetAlpha) ; } aceOutDestroy (dump_out); return; } /* keySetDispDump */ /************************************************************/ static void dumpAsAce (void) /* menu/button func */ { KeySetDisp look = currentKeySetDisp("dumpAsAce"); keySetDispDump (look, TRUE, FALSE); return; } /* dumpAsAce */ /************************************************************/ static void dumpAsAceWithTimeStamps (void) /* menu/button func */ { KeySetDisp look = currentKeySetDisp("dumpAsAceWithTimeStamps"); keySetDispDump (look, TRUE, TRUE); return; } /* dumpAsAceWithTimeStamps */ /************************************************************/ static void dumpAsNames (void) /* menu/button func */ { KeySetDisp look = currentKeySetDisp("dumpAsNames"); keySetDispDump (look, FALSE, FALSE); return; } /* dumpAsNames */ /************************************************************/ /* FastA format sequence dump, either all of the dna or just the CDS part. */ /* */ /* menu/button func */ static void dumpAsDnaFasta (void) { dumpDnaFasta(FALSE) ; return ; } /* menu/button func */ static void dumpAsCDSDnaFasta (void) { dumpDnaFasta(TRUE) ; return ; } static void dumpDnaFasta(BOOL cds_only) { ACEOUT dna_out; KeySetDisp look = currentKeySetDisp("dumpDnaFasta"); if (!look->keySetAlpha) return ; if (!(dna_out = dnaFileOpen(0))) return ; if (!look->fullAlpha && keySetMax(look->kSet) > keySetMax(look->keySetAlpha)) { keySetDestroy(look->keySetAlpha) ; look->keySetAlpha = keySetAlphaHeap(look->kSet, keySetMax(look->kSet)) ; look->fullAlpha = TRUE ; } if (cds_only) dnaDumpCDSFastAKeySet(dna_out, look->keySetAlpha) ; else dnaDumpFastAKeySet(dna_out, look->keySetAlpha) ; aceOutDestroy(dna_out) ; return ; } /* dumpAsDnaFasta */ /* FastA format protein dump, either all of the dna or just the CDS part. */ /* */ /* menu/button func */ static void dumpAsProtFasta(void) { dumpProtFasta(FALSE) ; return ; } /* dumpAsDnaFasta */ /* menu/button func */ static void dumpAsCDSProtFasta(void) { dumpProtFasta(TRUE) ; return ; } /* dumpAsDnaFasta */ static void dumpProtFasta(BOOL cds_only) { KeySetDisp look = currentKeySetDisp("dumpAsProtFasta"); ACEOUT pep_out; if (!look->keySetAlpha) return ; if (!(pep_out = pepFileOpen(0))) return ; if (!look->fullAlpha && keySetMax(look->kSet) > keySetMax(look->keySetAlpha)) { keySetDestroy(look->keySetAlpha) ; look->keySetAlpha = keySetAlphaHeap(look->kSet, keySetMax(look->kSet)) ; look->fullAlpha = TRUE ; } if (cds_only) pepDumpCDSFastAKeySet(pep_out, look->keySetAlpha) ; else pepDumpFastAKeySet(pep_out, look->keySetAlpha) ; aceOutDestroy (pep_out); return ; } /* dumpAsProtFasta */ /************************************************************/ static void dumpAsProtAlign (void) /* menu/button func */ { /* Alignment dump */ KeySetDisp look = currentKeySetDisp("dumpAsProtAlign"); ACEOUT pep_out; if (!(pep_out = pepFileOpen(0))) return ; alignDumpKeySet (pep_out, look->kSet) ; aceOutDestroy (pep_out); return ; } /* dumpAsProtAlign */ /************************************************************/ static void selectAllKeySet(void) { KeySetDisp look = currentKeySetDisp("SelectAllKeySet"); keySetDestroy(look->selected); look->touched |= 1 ; look->selected = keySetCopy(look->kSet); keySetShow2(look->kSet,look) ; } static void reverseSelectedKeySet(void) { KEYSET temp; KeySetDisp look = currentKeySetDisp("SelectAllKeySet"); look->curr = 0 ; look->touched |= 1 ; temp = keySetCopy(look->selected); look->selected = keySetXOR(temp,look->kSet); keySetDestroy(temp); keySetShow2(look->kSet,look) ; } static void removeSelectedKeySet(void) { KEYSET tmp; KeySetDisp look = currentKeySetDisp("removeSelectedKeySet"); tmp =keySetCopy(look->kSet); look->kSet = keySetXOR(tmp,look->selected); look->curr = 0; look->touched |= 3 ; keySetDestroy(look->keySetAlpha) ; keySetReCreate(look->selected); keySetDestroy(tmp); keySetShow2(look->kSet,look) ; } static void clearSelected(void) { KeySetDisp look = currentKeySetDisp("clearSelected"); look->curr = 0 ; look->touched |= 1 ; keySetReCreate(look->selected); look->numselpage = 0; look->nselected = 0; keySetShow2(look->kSet,look) ; } static void editSelected(void) { int i, max, max1; KEY *kp; char *cp ; KEYSET ksNew = 0 ; static char* buffer ; Stack localStack = 0 ; KeySetDisp look = currentKeySetDisp("editSelected"); ACEIN command_in; if (!look->selected || !(max = keySetMax(look->selected))) { messout("first select the objects you want to edit") ; return ; } i = max ; kp = arrp (look->selected, 0, KEY) - 1 ; max1 = 0 ; while (kp++, i--) if (pickType(*kp) == 'B') /* don t edit array this way */ max1++ ; if (max != max1) { messout("You have selected %d non-text objects, \n" "they cannot be edited in this way", max - max1) ; return ; } if(!checkWriteAccess()) return; cp = messprintf("%s%d%s", "Type a .ace command, it will be applied to the ", max, " currently selected objects") ; if (!(command_in = messPrompt(cp, buffer ? buffer : "", "t", 0))) return ; cp = aceInWord (command_in) ; if (!cp) { aceInDestroy (command_in); return ; } messfree(buffer) ; buffer= strnew(cp, 0) ; aceInDestroy (command_in); i = max ; localStack = stackCreate (40*i) ; kp = arrp (look->selected, 0, KEY) - 1 ; while (kp++, i--) if (pickType(*kp) == 'B') /* don t edit array this way */ { catText (localStack, className (*kp)) ; catText (localStack, " ") ; catText (localStack, freeprotect(name (*kp))) ; catText (localStack, "\n") ; catText (localStack, buffer) ; catText (localStack, "\n\n") ; } ksNew = keySetCreate () ; parseBuffer (stackText (localStack,0), ksNew,FALSE) ; stackDestroy (localStack) ; /* it can be quite big */ i = keySetMax(ksNew) ; messout (messprintf ("// I updated %d objects with command\n %s\n", i, buffer)) ; /* parseKeepGoing = FALSE ; */ keySetDestroy (ksNew) ; } static void killSelected(void) { int max; register int i; KEY key; KeySetDisp look = currentKeySetDisp("killSelected"); if (!look->selected || !(max = keySetMax(look->selected))) { messout("first select the objects you want to kill") ; return ; } if(!checkWriteAccess()) return; if (!messQuery (messprintf ("Do you really want to destroy %d items", max))) return ; look->touched |= 3 ; i= 0; while(iselected,i) ; switch ( pickType(key)) { case 'A': arrayKill (key) ; break ; case 'B': { OBJ obj ; if ((obj = bsUpdate (key))) bsKill (obj) ; } break ; } { KEY *kp = arrp(look->kSet, 0, KEY) ; int max = keySetMax (look->kSet) ; while (max-- && *kp != key) kp++ ; while (kp++, max--) *(kp - 1) = *kp ; } keySetMax (look->kSet)-- ; i++; } keySetDestroy(look->keySetAlpha) ; keySetReCreate(look->selected); look->curr = 0; /* else crashes if remove last item */ keySetShow2(look->kSet,look) ; } static void editAll (void) { selectAllKeySet () ; editSelected () ; } static void killAll (void) { selectAllKeySet () ; killSelected () ; } static void beforecombine (int type) { KeySetDisp look = currentKeySetDisp("before Combine"); if (selectedKeySet && selectedKeySet->magic == &KeySetDisp_MAGIC) { displayPreserve() ; look->owner = -1 ; clearSelected() ; look->touched |= 3 ; look->curr = 0 ; look->fullAlpha = FALSE ; keySetMix(look, type) ; } else messout ("First select a key Set window by picking " "its background with the left mouse button") ; return; } /* beforecombine */ static void combineXOR (void) { beforecombine(XOR); } static void combineAND(void) { beforecombine(AND); } static void combineOR(void) { beforecombine(OR); } static void combineMINUS(void) { beforecombine(MINUS); } static void follow(void) { int i; KEY key = 0; KeySetDisp look = currentKeySetDisp("follow"); if (!look->keySetAlpha) return ; i = look->curr-2+look->base ; if (i < 0 || i > keySetMax(look->keySetAlpha)) i = 0 ; if (!keySetMax(look->keySetAlpha)) return ; key = keySet(look->keySetAlpha,i) ; if (pickType(key) != 'B') return ; { int type, tcl ; KEY tag ; Stack sta = stackCreate (50) ; if (treeChooseTagFromModel (&type, &tcl, class(key), &tag, sta, FALSE)) { KEYSET tmp = query(look->kSet, messprintf(">%s",stackText (sta, 0))) ; keySetDestroy(look->kSet) ; keySetDestroy(look->keySetAlpha) ; look->kSet = tmp ; look->touched |= 3 ; look->curr = 0 ; keySetShow2(look->kSet,look) ; } stackDestroy (sta) ; } } static void grepset (void) { char *cp ; int i ; KEYSET ks = 0 ; Stack s = 0 ; KeySetDisp look = currentKeySetDisp("grepset"); ACEIN word_in; word_in = messPrompt ("Type a few words (at least 3 letters long), " "upper/lower case do not matter","", "t", 0); if (!word_in) return ; s = stackCreate(50) ; catText (s, "*") ; while ((cp = aceInWord (word_in))) { catText (s, cp) ; catText (s, "*") ; } aceInDestroy (word_in); cp = stackText (s, 0) ; i = 0 ; while (*cp) { if (*cp != ' ' && *cp != '*') i++ ; cp++ ;} if (i >= 3) { ks = queryGrep (look->kSet, stackText (s, 0)) ; keySetNewDisplay (ks, stackText(s,0)) ; /* will destroy ks */ keySetSelect () ; } else messout ("word too short") ; stackDestroy (s) ; } static void relatedBiblio(void) { KeySetDisp look = currentKeySetDisp("relatedBiblio"); biblioKeySet ("Biblio for keyset", look->kSet) ; } KeySetDisp keySetNewDisplay (KEYSET ks, char *title) { KeySetDisp look = 0 ; if (keySetExists(ks)) { Graph g = graphActive () ; displayCreate("DtKeySet") ; graphRetitle(title) ; look = keySetShow (ks,0) ; keySetSelect () ; graphActivate (g) ; } return look ; } static void keySetDoQuery(char *txt) { KEYSET ks = 0 ; char *cp ; KeySetDisp look = currentKeySetDisp("keySetDoQuery"); cp = look->queryBuffer ; while (*cp == ' ') cp++ ; if (!*cp) return ; ks = query (look->kSet, cp) ; keySetNewDisplay (ks, look->queryBuffer) ; /* will destroy ks */ keySetSelect () ; } static void openQueryBox(void) { KeySetDisp look = currentKeySetDisp("openQueryBox"); if(look->curr) look->curr -= (look->showQuery ? 1 : -1 ) * NQueryLine ; look->showQuery = look->showQuery ? 0 : 2 ; /* toggle */ keySetShow2 (look->kSet, look) ; } static void findneigh(void) { KEYSET tmp ; KeySetDisp look = currentKeySetDisp("findneigh"); if (!look->keySetAlpha) return ; tmp = look->kSet ; look->kSet = keySetNeighbours(tmp) ; /* will destroy tmp */ look->touched |= 3 ; look->curr = 0 ; keySetDestroy(look->keySetAlpha) ; keySetShow2(look->kSet,look) ; } static void queByExam(void) { int i; KeySetDisp look = currentKeySetDisp("queByExam"); if (!look->keySetAlpha) return ; i = look->curr-2+look->base ; if (i < 0 || i >= keySetMax (look->keySetAlpha)) i = 0 ; qbeCreateFromKeySet (look->keySetAlpha,i - 1) ; } static void showClasses(void) { KeySetDisp look = currentKeySetDisp("showClasses"); look->curr = 0; look->showClass = !look->showClass; keySetShow2(look->kSet,look) ; } static KeySetDisp keySetShow2 (KEYSET kSet, KeySetDisp look) { int i, iy, y, colX, col, nx, ny, numcol; int max = ( kSet ? keySetMax(kSet) : 0 ) ; char *cp ; KEY key ; int box=0; BOOL FIRST = TRUE, room = TRUE ; int startpos=0, cWidth=0, endpos=0, numrows=0 ; if (!look->isBlocking) /* so as not to hide message */ graphPop() ; if (look->base >= max) look->base = 0 ; if (!keySetActive (0, 0)) selectedKeySet = look ; graphFitBounds (&nx, &ny) ; if (look->kSet != kSet) { look->showQuery = 0 ; if (keySetExists(look->keySetAlpha)) keySetDestroy(look->keySetAlpha) ; /* don't destroy look->kSet here, calling routine should */ } look->kSet = kSet ; look->touched |= 3 ; look->curr = 0 ; drawMenus(); /* here, hence after evaluation of biblio possible */ if (max) { col = 1 + nx/2 ; /* max number possible columns */ if (!look->keySetAlpha) { look->keySetAlpha = keySetAlphaHeap(kSet, look->base + 4*col*ny) ; look->fullAlpha = FALSE ; } else if (!look->fullAlpha && keySetMax(look->keySetAlpha) < keySetMax(look->kSet) && keySetMax(look->keySetAlpha) < look->base + col*ny) { keySetDestroy(look->keySetAlpha) ; look->keySetAlpha = keySetAlphaHeap(look->kSet, keySetMax(look->kSet)) ; look->fullAlpha = TRUE ; } } look->box2key = arrayReCreate(look->box2key, 100, KEY) ; TOPGAP += 1.7; /* we leave a gap for the text 'n items selected..' */ look->numselpage = 0; if (max) { colX = SCROLLBARGAP; endpos = look->base -1; numrows = (ny-TOPGAP)-BOTGAP; if (numrows < 0) { graphRedraw(); return look; /* window too small to start with */ } i = numcol = 0; while (room) { startpos = endpos+1; room = columnWidth(startpos,TRUE,&cWidth,&endpos,numrows); look->colWidth[i++] = cWidth; if (cWidth && ((colX + cWidth) < nx || colX == SCROLLBARGAP)) { /* if it fits or is the first */ look->top = endpos; y = nint(TOPGAP); numcol++; while (startpos <= endpos) { key = arr(look->keySetAlpha,startpos++,KEY) ; cp = 0 ; if (!nextName (key, &cp) || *cp == '\177') continue ; box = graphBoxStart() ; array (look->box2key, box, KEY) = key ; if (iskey(key) == 2) graphTextFormat (BOLD) ; /* pickable object */ else graphTextFormat (PLAIN_FORMAT) ; if (look->showClass) graphText (messprintf ("%s:%s", className(key), cp), colX, y++) ; else graphText (cp, colX, y++) ; graphBoxEnd () ; if (FIRST) { look->firstBox = box; FIRST = FALSE; } if (keySetFind (look->selected, key, 0)) { graphBoxDraw(box,BLACK,LIGHTGRAY); look->numselpage++; } } colX += (cWidth+2); } else if (cWidth != 0) /* Do not stop on blank keys. For some reason some databases have multiple ""'s */ room = FALSE; } look->lastBox = box; /* look->numperpage = numcol*numrows; mhmp */ look->numperpage = look->lastBox - look->firstBox + 1 ; array(look->box2key, arrayMax(look->box2key), KEY) = 0 ; /* terminate */ graphTextFormat (PLAIN_FORMAT) ; if(look->curr) { if(look->curr >= look->firstBox && look->curr <= look->lastBox) /* current may not be on the page now */ graphBoxDraw(look->curr,WHITE,BLACK); /* due to other tools being expanded */ else look->curr = 0; } iy = look->base ? 2 : 0 ; shownItem (look) ; /* mhmp 11.09.98 */ if (numrows >= 1) drawScrollBar(look->nitem); } else shownItem (look) ; look->txtbox = graphBoxStart(); graphTextPtr(look->txtBuffer, (nx/2)-15, TOPGAP-1.5, 60) ; graphBoxEnd(); graphRedraw(); messfree (look->message) ; return look ; } KeySetDisp keySetShow (KEYSET kSet, KeySetDisp handle) { return keySetMessageShow (kSet, handle, 0) ; } KeySetDisp keySetMessageShow (KEYSET kSet, KeySetDisp old_ksdisp, char *message) { Graph old = graphActive() ; KeySetDisp ksdisp; if (!old_ksdisp) { ksdisp = (KeySetDisp) messalloc (sizeof (struct KeySetDispStruct)) ; ksdisp->magic = &KeySetDisp_MAGIC ; ksdisp->graph = graphActive() ; ksdisp->owner = old ; ksdisp->showtype = DEFAULT; ksdisp->selected = keySetCreate(); ksdisp->showClass = FALSE; ksdisp->showQuery = 0 ; ksdisp->curr = 0; ksdisp->numselpage = 0; graphRegister (DESTROY, localDestroy) ; graphRegister (MESSAGE_DESTROY, ksetUnBlock) ; graphRegister (PICK, localPick) ; graphRegister (KEYBOARD, localKbd) ; graphRegister (RESIZE, localResize) ; graphRegister (MIDDLE_UP, scrollMiddleUp) ; graphFreeMenu (ksetlocalMenu, menuOptions) ; graphAssociate (&GRAPH2KeySetDisp_ASSOC, ksdisp) ; if (!selectedKeySet) selectedKeySet = ksdisp ; } else { ksdisp = old_ksdisp; if (ksdisp->magic != &KeySetDisp_MAGIC) messcrash("keySetShow called with corrupted KeySetDisp pointer") ; if (!graphActivate (ksdisp->graph)) messcrash ("keySetMessageShow() - keyset window lost its graph"); ksdisp->curr = 0 ; ksdisp->base = 0 ; messfree (ksdisp->message) ; keySetDestroy(ksdisp->keySetAlpha) ; keySetReCreate(ksdisp->selected); } if (message) ksdisp->message = strnew (message, 0) ; ksdisp->touched |= 3 ; ksdisp->curr = 0 ; return keySetShow2(kSet, ksdisp) ; } /*****************************/ static BOOL importKeySet (KEYSET kSet, ACEIN keyset_in) { int table, nbad = 0 ; char *word ; KEY key = 0; keySetMax(kSet) = 0 ; while (aceInCard (keyset_in)) if ((word = aceInWord(keyset_in))) { if (!(table = pickWord2Class (word))) { ++nbad ; continue ; } if (table == _VKeySet && !keySetMax(kSet)) continue ; aceInStep (keyset_in, ':') ; if (!(word = aceInWord(keyset_in))) { messout ("No object name, line %d", aceInStreamLine (keyset_in)) ; continue ; } if (lexword2key (word, &key, table)) keySet(kSet, keySetMax(kSet)) = key ; else ++nbad ; } if (nbad) messout ("%d objects not recognized", nbad) ; keySetSort(kSet) ; keySetCompress(kSet) ; return TRUE; } /***********************************/ BOOL keySetDisplay (KEY key, KEY from, BOOL isOldGraph, void *unused) { KEYSET kset ; KeySetDisp look ; KEY keySetKey; if (class(key) == _VKeySet) { if (!(kset = arrayGet (key,KEY,"k"))) return FALSE ; keySetKey = key; } else { /* key is not a KeySet object, so we make a keyset and put the key in it as the only element and then display that */ kset = keySetCreate(); keySet(kset, 0) = key; keySetKey = 0; } if (isOldGraph) localDestroy () ; else displayCreate("DtKeySet") ; graphRetitle (name(key)) ; look = keySetShow (kset, 0) ; look->keySetKey = keySetKey ; return look ? TRUE : FALSE ; } /* keySetDisplay */ /***********************************/ char *keySetGetShowAs (KeySetDisp ksdisp, KEY key) { /* which "Show As"-displayType has been selected in a given keyset-window */ if (ksdisp->magic != &KeySetDisp_MAGIC) messcrash ("keySetGetShowAs() - received non-magic KeySetDisp pointer") ; if (ksdisp->showtype) return name(ksdisp->showtype) ; return (char*)0; } /* keySetGetShowAs */ /*************************************/ static void localDestroy (void) { KeySetDisp look = currentKeySetDisp("keySetDestroy") ; look->magic = 0 ; if (selectedKeySet == look) selectedKeySet = 0 ; keySetDestroy (look->kSet) ; keySetDestroy (look->keySetAlpha) ; messfree (look) ; graphAssRemove (&GRAPH2KeySetDisp_ASSOC) ; } /*************************************/ static void keySetSelect (void) { KeySetDisp look = currentKeySetDisp ("keySetSelect") ; if ( selectedKeySet && selectedKeySet != look && selectedKeySet->magic == &KeySetDisp_MAGIC && graphExists(selectedKeySet->graph)) { Graph hold = graphActive () ; graphActivate (selectedKeySet->graph) ; graphBoxDraw (1,BLACK,WHITE) ; graphActivate (hold) ; } graphBoxDraw (1,BLACK,PALERED) ; selectedKeySet = look ; } /***************/ BOOL keySetActive(KEYSET *setp, KeySetDisp* lookp) { if (selectedKeySet && selectedKeySet->magic == &KeySetDisp_MAGIC && graphExists(selectedKeySet->graph) && arrayExists(selectedKeySet->kSet)) { if (setp) *setp = selectedKeySet->kSet ; if (lookp) *lookp = selectedKeySet ; return TRUE ; } selectedKeySet = 0 ; if (setp) *setp = 0 ; if (lookp) *lookp = 0 ; return FALSE ; } /***************/ static void localPick (int box,double x,double y, int modifier_unused) { KeySetDisp look = currentKeySetDisp("keySetPick"); if (look != selectedKeySet) keySetSelect () ; if (look->showQuery) { if (box == look->queryBox) { graphTextScrollEntry (look->queryBuffer,0,0,0,0,0) ; look->showQuery = 2 ; /* keep focus */ return ; } else { graphEntryDisable() ; graphRegister (KEYBOARD, localKbd) ; look->showQuery = 1 ;/* release focus */ } } if (!box) return ; if(box == look->upBox) pageUp(); else if(box == look->downBox) pageDown(); else if(box == look->scrollBarBox) graphBoxDrag(box, keyBandDrag); else { if (box == look->curr) /* double click */ { KEY key = array(look->box2key, look->curr, KEY) ; if (key) { if (look->isBlocking) ksetDeleteKey (key) ; else { graphPostBuffer (name(key)) ; if(look->showtype != 0) display(key,0,name(look->showtype)); else display(key,0,0); } } } else { if(look->curr > 1) graphBoxDraw(look->curr,BLACK,LIGHTGRAY); look->curr=box; if(look->curr >1) { startbox = box; controlLeftDown (x,y); if (look->curr < arrayMax(look->box2key)) graphPostBuffer (name(array(look->box2key, look->curr, KEY))) ; } } } } /* localPick */ /***********************************/ static void keySetMix(KeySetDisp qry, int combinetype) { KEYSET s=0; KeySetDisp q = selectedKeySet ; if(combinetype == AND) s = keySetAND(q->kSet,qry->kSet) ; else if(combinetype == OR) s = keySetOR(q->kSet,qry->kSet) ; else if(combinetype == MINUS) s = keySetMINUS(qry->kSet,q->kSet) ; else if(combinetype == XOR) s = keySetXOR(q->kSet,qry->kSet) ; else messcrash("keySetMix received wrong operator %d",combinetype) ; arrayDestroy(qry->kSet) ; qry->kSet = s ; qry->touched |= 3 ; qry->curr = 0 ; keySetDestroy(qry->keySetAlpha) ; keySetShow2(qry->kSet,qry ) ; } /***********************************/ static void localKbd (int k, int modifier_unused) { float x0,y0,x1,y1,x2,y2,x3,y3,x4,y4 ; int max, before ; KEY key; KeySetDisp look = currentKeySetDisp("keySetPick") ; if (look->curr < 2) return ; max = keySetMax (look->kSet) ; key = arr(look->box2key,look->curr, KEY); graphBoxDraw(look->curr, BLACK, LIGHTGRAY); switch (k) { case UP_KEY : if (arr(look->box2key, look->curr-1, KEY)) --look->curr ; else if (look->base) { pageUp () ; for (look->curr = arrayMax(look->box2key)-1 ; look->curr && !arr(look->box2key, look->curr, KEY) ; --look->curr) ; } break ; case DOWN_KEY : if(arr(look->box2key,look->curr,KEY) != arrayMax(look->kSet)){ /* do not want to go down if this is the last key */ if (arr(look->box2key, look->curr+1, KEY)) ++look->curr ; else if (look->top < max-1) { pageDown () ; for (look->curr = 1 ; look->curr < arrayMax (look->box2key) && !arr(look->box2key, look->curr, KEY) ; ++look->curr) ; } } break ; case RIGHT_KEY : graphBoxDim (look->curr,&x0,&y0,&x2,&y2) ; graphBoxDim (look->lastBox,&x3,&y3,&x4,&y4); if(x0 != x3 || look->lastBox == look->curr){ y1 = y0 ; x1 = x0 ; while (arr(look->box2key,look->curr+1,KEY) && (y1 < y0-0.5 || x1 == x0)) graphBoxDim (++look->curr,&x1,&y1,&x2,&y2) ; if ((y1 < y0 - 0.5 || x1 == x0) && look->top < max-1) { pageDown() ; for (look->curr = 1 ; look->curr < arrayMax (look->box2key) && !arr(look->box2key, look->curr, KEY) ; ++look->curr) ; } } break ; case LEFT_KEY : graphBoxDim (look->curr,&x0,&y0,&x2,&y2) ; graphBoxDim (look->firstBox,&x3,&y3,&x4,&y4); if(x3 != x0 || look->curr == look->firstBox){ /* i.e. the first column */ y1 = y0 ; x1 = x0 ; before = look->curr; while (look->curr > 2 && (y1 > y0+0.5 || x1 == x0) &&look->curr > look->firstBox) graphBoxDim (--look->curr,&x1,&y1,&x2,&y2) ; if ( ((y1 > y0+0.5 || x1 == x0) && look->base) || ( (before == look->firstBox) && (arr(look->box2key,before,KEY)!= arr(look->keySetAlpha,0,KEY)) ) ) { pageUp () ; for (look->curr = arrayMax(look->box2key)-1 ; look->curr && !arr(look->box2key, look->curr, KEY) ; --look->curr) ; } if(look->curr < look->firstBox) look->curr = look->firstBox; } break ; case HOME_KEY : if (look->base) { look->base =0; keySetShow2 (look->kSet, look) ; } for (look->curr = 1 ; look->curr < arrayMax (look->box2key) && !arr(look->box2key, look->curr, KEY) ; ++look->curr) ; break ; default: graphBoxDraw(look->curr, WHITE, BLACK) ; return ; } key = arr(look->box2key,look->curr, KEY); if ( key && !keySetFind (look->selected, key, 0)) { keySetInsert (look->selected, key) ; look->numselpage ++ ; look->touched |= 1 ; } graphBoxDraw (look->curr, WHITE, BLACK) ; shownItem (look) ; if (look->txtbox) graphBoxDraw(look->txtbox,BLACK,WHITE); graphPostBuffer(name(key)); { KEY key = array(look->box2key, look->curr, KEY) ; Graph g = graphActive () ; if(look->showtype != 0) display(key,0,name(look->showtype)); else display(key,0,0); /* display() calls graphPop on the window it creates, which can change the keyboard focus in click-to-type window managers (and MS-windows) We move the focus back to the keyset window here so that repeated arrow-key presses work. */ graphActivate(g); graphPop(); } } /***************************/ static void ksetAddKey (KEY key) { KeySetDisp look = currentKeySetDisp("ksetAddKey") ; if (key) keySetInsert(look->kSet,key) ; look->touched |= 3 ; keySetDestroy(look->keySetAlpha) ; keySetShow2(look->kSet,look) ; displayRepeatBlock () ; } /***************************/ static void ksetDeleteKey (KEY key) { KeySetDisp look = currentKeySetDisp("ksetDeleteKey") ; keySetRemove(look->kSet,key) ; look->touched |= 3 ; keySetRemove(look->selected,key) ; /* mhmp add-remove */ keySetDestroy(look->keySetAlpha) ; look->curr = 0; /* otherwise if it is the last box it crashes */ keySetShow2(look->kSet,look) ; displayRepeatBlock () ; } /*****************************/ static void ksetUnBlock (void) { KeySetDisp look = currentKeySetDisp("ksetUnBlock") ; if (look->isBlocking) { look->isBlocking = FALSE ; displayUnBlock() ; } } /*************************************/ static void selectedToNewKeySet(void) { Graph g ; KeySetDisp look = currentKeySetDisp("selectedToNewKeySet") ; g = graphActive () ; displayCreate("DtKeySet") ; graphRetitle ("Copied selected keyset") ; keySetShow (keySetCopy (look->selected),0) ; displayPreserve() ; graphActivate (g) ; } /* dummy is used in the prototype so that the ksetlocalMenu matches the */ /* FreeMenuFunction type. */ static void ksetlocalMenu (KEY k, int unused) { extern void Bdump (KEY key) ; Graph g ; KEY key = 0 ; char *word = 0 ; KeySetDisp look = currentKeySetDisp("ksetlocalMenu") ; ACEIN name_in; switch (k) { case 99: graphDestroy () ; break ; case 98: helpOn("KeySet") ; break ; case 97: graphPrint() ; break ; case 51: keySetSummary(); break; case 1: /* save */ if (!look->keySetAlpha) break ; if(!checkWriteAccess()) return ; word = look->keySetKey ? name(look->keySetKey) : "" ; while (!key && (name_in = messPrompt ("Give a name", word, "t", 0))) { if (!(word = aceInWord(name_in)) || !*word || (!lexaddkey (word,&key,_VKeySet) && !messQuery ("Overwrite existing keyset ?"))) { aceInDestroy (name_in); return ; } aceInDestroy (name_in); } if (!key) break ; if (!lexlock(key)) { messout ("Sorry, key is locked by someone else") ; break ; } arrayStore (key,look->kSet,"k") ; lexunlock (key) ; look->keySetKey = key ; break ; case 2: /* copy */ g = graphActive () ; displayCreate("DtKeySet"); graphRetitle ("Copied keyset") ; keySetShow (keySetCopy (look->kSet),0) ; displayPreserve() ; graphActivate (g) ; break ; case 8: if (look->curr > 1 && look->curr < arrayMax(look->box2key)) { key = array(look->box2key, look->curr, KEY) ; if (key) display(key, 0, "TREE"); } break; case 10: /* Read from file */ { ACEIN keyset_in; static char directory[DIR_BUFFER_SIZE] = ""; static char filename[FIL_BUFFER_SIZE] = ""; keyset_in = aceInCreateFromChooser ("File of object names ?", directory, filename, "ace", "r", 0); if (keyset_in) { importKeySet(look->kSet, keyset_in); aceInDestroy (keyset_in); keySetDestroy(look->keySetAlpha) ; keySetShow2(look->kSet,look) ; } } break ; case 6: /* Add key */ look->isBlocking = TRUE ; displayPreserve() ; look->owner = -1 ; displayBlock (ksetAddKey, "Double-clicking in a different KeySet window will add entries,\n" "inside the current window will delete them from this KeySet.\n" "This will continue until you remove this message\n") ; break ; case 7: /* "New empty KeySet" */ keySetNewDisplay (keySetCreate(), "New KeySet") ; break ; case 41 : /* Mailer */ if (!look->keySetAlpha) break ; acedbMailer(0, look->kSet, 0) ; break ; case 42: /* JTM Hexadecimal dump of disk blocks */ if (!look->keySetAlpha) break ; if (look->curr < 2) break ; #ifdef ACEDB4 Bdump(keySet(look->keySetAlpha,look->curr-2+look->base)) ; #endif break ; case 45: if (!look->keySetAlpha) break ; multiMapDisplayKeySet (0, look->kSet, 0, 0, 0, 2) ; break ; case 46: if (!look->keySetAlpha) break ; forestDisplayKeySet (0, keySetCopy(look->kSet), FALSE) ; break ; case 47: look->curr = 0; look->showClass = !look->showClass; keySetShow2(look->kSet,look) ; break ; case 48: findneigh() ; break ; case OR: beforecombine(OR); break ; case AND: beforecombine(AND); break ; case MINUS: beforecombine(MINUS); break ; case XOR: beforecombine(XOR); break ; default: break ; } } /* ksetlocalMenu */ /*************************************************/ /************* left button for thumb **********/ static void controlLeftDrag (double x, double y) { int i,nx,ny,ix,numrows,incr,iy,col,colour,addbit,index; BOOL inlimits=TRUE; float right,ncol; KEY key; KeySetDisp look = currentKeySetDisp("controlLeftDrag"); if(oldcol >= 0){ graphFitBounds (&nx, &ny) ; iy = (int)y; numrows = ny-(TOPGAP+BOTGAP); col = 0; if(x < SCROLLBARGAP) x= (float)SCROLLBARGAP+1.0; right = (float)SCROLLBARGAP; ncol = ((float)look->numperpage/(float)numrows); i=0; while(i <= ncol){ right+=(float)look->colWidth[i++]+2.0; } if(x > right) x= right; ix = SCROLLBARGAP; while(ix < x){ ix +=look->colWidth[col++] + 2; } if(iy > ny-BOTGAP-1) iy = ny-BOTGAP-1; if(iy < TOPGAP-1) iy = TOPGAP-1; incr = iy-oldy; oldy=iy; incr += (col-oldcol)*numrows; oldcol = col; numboxes += incr; if(incr > 0) addbit = -1; else addbit =-2; if(incr != 0){ while(lastbox != startbox+(numboxes+addbit) && inlimits){ if((incr>0 && lastbox > startbox) || (incr<0 && lastbox < startbox) || lastbox == startbox) colour = LIGHTGRAY; else{ key = arr(look->box2key,lastbox,KEY); if(!keySetFind(look->selected,key,&index)) colour = WHITE; else colour = LIGHTGRAY; } if(lastbox >= look->firstBox && lastbox <= look->lastBox) graphBoxDraw(lastbox,BLACK,colour); else inlimits = FALSE; if(incr > 0) lastbox++; else lastbox--; } } } else{ col = 0; ix = SCROLLBARGAP; while(ix < x){ ix +=look->colWidth[col++] + 2; } oldy = (int)y-1; oldcol = col; } } static void controlLeftUp (double x, double y) { KEY key; int endbox=0,index ; KeySetDisp look = currentKeySetDisp("controlLeftUp"); look->curr = 0; if(numboxes > 1){ numboxes--; endbox = startbox+numboxes-1; } if(numboxes < 1){ numboxes--; endbox = startbox; startbox = startbox + numboxes; } else if(numboxes == 1){ endbox = startbox; look->curr = startbox; } while(startbox <= endbox){ key = arr(look->box2key,startbox, KEY); if(key && !keySetFind(look->selected,key,&index)) { keySetInsert(look->selected,key); look->touched |= 1 ; look->numselpage++; } startbox++; } graphRegister (LEFT_DRAG, none) ; graphRegister (LEFT_UP, none) ; shownItem (look) ; graphBoxDraw(look->txtbox,BLACK,WHITE); if(numboxes==1 && look->curr > 0){ graphBoxDraw(look->curr,WHITE,BLACK); graphPostBuffer(name(arr(look->box2key,look->curr, KEY))); } } static void controlLeftDown (double x, double y) { numboxes = 1; oldcol = -1; lastbox = startbox; graphBoxDraw(lastbox,BLACK,LIGHTGRAY); graphRegister (LEFT_DRAG, controlLeftDrag) ; graphRegister (LEFT_UP, controlLeftUp) ; } static void nextShowtype(void) { FREEOPT *menu; int i ; KeySetDisp look = currentKeySetDisp("changeShowtype"); menu = displayGetShowTypesMenu(); for(i=1;i<=menu[0].key;i++) if(look->showtype == menu[i].key) { i++ ; if (i > menu[0].key) i = 1 ; look->showtype = menu[i].key ; keySetShow2(look->kSet,look) ; break ; } } static void changeShowtype(KEY key) { KeySetDisp look = currentKeySetDisp("changeShowtype"); look->showtype = key; keySetShow2(look->kSet,look) ; } #define MAXLEN 45 static void keySetSummary(void) { int i, *summary ; KEY *kp ; char *buf ; KeySetDisp look = currentKeySetDisp("keySetSummary") ; summary = (int *) messalloc ((sizeof(int) * MAX_CLASSES)) ; if (look->kSet) for (i = keySetMax(look->kSet), kp = arrp (look->kSet, 0, KEY) - 1 ; i-- ; kp++) if (lexIsKeyVisible(*kp)) summary[class(*kp)]++; buf = (char *) messalloc ((MAX_CLASSES+1)*MAXLEN) ; sprintf (buf,"KeySet Class Information\n"); for (i = 0 ; i < MAX_CLASSES ; i++) if (summary[i] != 0) strcat (buf, messprintf ("%s %d items\n", pickClass2Word(i), summary[i])) ; graphMessage (buf) ; messfree (buf) ; messfree (summary) ; } static BOOL columnWidth (int startpos, int direction, int *cWidth, int *endpos, int numrows) { int k=0,i,max,j; char *cp,*cp2,*cp3; KEY key; KEYSET kSet; KeySetDisp look = currentKeySetDisp("columnWidth"); if (numrows < 1) return FALSE; kSet = look->kSet; i= startpos; *cWidth = 0; max = keySetMax(look->keySetAlpha); while(k= max){ /* check end if moving forward */ return FALSE; } if(i < 0) /* check for start if going back a page */ return FALSE; cp = cp2 =0; key = arr(look->keySetAlpha,i,KEY) ; if (!nextName (key, &cp) || *cp == '\177'){ if(direction) *endpos = i++; else *endpos = i--; continue ; } if(look->showClass){ cp2 = className (key); cp3 = strnew(messprintf("%s:%s",cp2,cp),0); /*sprintf(cp3,"%s:%s\n",cp2,cp);*/ if ((j = strlen(cp3)) > *cWidth){ *cWidth = j ; } messfree(cp3); } else{ if ((j = strlen(cp)) > *cWidth){ *cWidth = j ; } } if(direction) *endpos = i++; else *endpos = i--; k++; } return TRUE; } static void drawScrollBar(int max) { int colX,nx,ny,k; float xpt,top,bottom,boxstart,boxend,len; KeySetDisp look = currentKeySetDisp("drawScrollBar"); graphFitBounds (&nx, &ny) ; if(max > look->numperpage && max != 0) { colX = SCROLLBARGAP ; top = (float)TOPGAP; bottom = (float)(ny - BOTGAP); xpt = SCROLLBARPOS; k = graphLinewidth(0.4); graphLine(xpt,top,xpt,bottom); k= graphLinewidth(k); if(look->base !=0) look->upBox = scrollTriangle(UP,xpt-1.0,top,GREEN); else look->upBox = scrollTriangle(UP,xpt-1.0,top,WHITE); if(look->top != max-1) look->downBox = scrollTriangle(DOWN,xpt-1.0,bottom,GREEN) ; else look->downBox = scrollTriangle(DOWN,xpt-1.0,bottom,WHITE) ; len = (((float)look->numperpage)/(float)max)*(bottom-top); if(len < MINSCROLLBARLENGTH) len = MINSCROLLBARLENGTH; look->scrolllen = len; if(look->base == 0) boxstart = top; else { if(look->scrolllen == MINSCROLLBARLENGTH) boxstart = (((float)look->base/(float)max)*(bottom-top-look->scrolllen)) + top; else boxstart = (((float)look->base/(float)max)*(bottom-top)) + top; } boxend = boxstart + len; if(boxend > bottom) { boxend = bottom; boxstart = bottom-len; } look->scrollBarBox = graphBoxStart(); graphRectangle(xpt-0.5,boxstart,xpt+0.5,boxend); graphBoxEnd(); graphBoxDraw(look->scrollBarBox,BLACK,GREEN); } else look->scrollBarBox = look->upBox = look->downBox = 0; } /* drawScrollBar */ static void beforeForest (void) { KeySetDisp look = currentKeySetDisp ("beforeForest") ; if (!look->keySetAlpha || !look->kSet || !keySetMax(look->kSet)) return ; forestDisplayKeySet (0, keySetCopy(look->kSet), FALSE) ; } static void otherTools (void) { KeySetDisp look = currentKeySetDisp("otherTools") ; /* changing the number of buttons changes the current selected */ if(look->curr) look->curr -= (isOtherTools ? 1 : -1 ) * N3rdLINE ; isOtherTools = !isOtherTools ; keySetShow2(look->kSet,look) ; } static void beforeAddRemove(void) { ksetlocalMenu (6, 0) ; } static void beforeSaveAs(void) { checkWriteAccess() ; if (!isWriteAccess()) return ; ksetlocalMenu (1, 0) ; } static void beforeEmpty(void) { ksetlocalMenu (7, 0) ; } static void beforeCopy(void) { ksetlocalMenu (2, 0) ; } static void drawMenus(void) { int i,nx,ny,menuregion, box; float line ; static int wp = 0 ; FREEOPT *menu; KEYSET kSet; static MENUOPT dumpAs[] = { {menuSpacer,"Mail/Write data as:.."}, {dumpAsAce, " ace file"}, {dumpAsAceWithTimeStamps, " ace file with timestamps"}, {dumpAsNames, " list of names"}, {dumpAsDnaFasta, " DNA in FASTA format"}, {dumpAsCDSDnaFasta, " CDS DNA in FASTA format"}, {dumpAsProtFasta, " Protein in FASTA format"}, {dumpAsCDSProtFasta, " CDS Protein in FASTA format"}, {dumpAsProtAlign, " Protein alignment"}, {0,0} }; static MENUOPT combine[] = { {combineOR,"OR"}, {combineAND,"AND"}, {combineMINUS,"MINUS"}, {combineXOR,"XOR"}, {0,0} }; static MENUOPT query[] = { {openQueryBox, "Query"}, {follow,"Follow"}, {findneigh,"Find Neighbours"}, /* redundant on morer info -> background ? */ {queByExam,"Query by Example"}, {grepset,"Text search"}, {0,0} }; /* static MENUOPT selectMenu[] = { {clearSelected,"Clear Selection"}, {selectAllKeySet,"Select All"}, {reverseSelectedKeySet,"Reverse"}, {removeSelectedKeySet,"Remove Selected"}, {selectedToNewKeySet,"Selected To New Keyset"}, {0,0} }; */ static MENUOPT modifSelectMenu[] = { {beforeAddRemove, "Add/remove items one by one"}, {menuSpacer,""}, {beforeEmpty,"New empty keyset"}, {beforeCopy,"Copy whole keyset"}, {beforeSaveAs,"Save current keyset as"}, {menuSpacer,""}, {selectAllKeySet,"Select All"}, {clearSelected,"Clear Selection"}, {reverseSelectedKeySet,"Reverse selection"}, {removeSelectedKeySet,"Remove selected items"}, {selectedToNewKeySet,"Copy selected items"}, {0,0} }; static MENUOPT editMenu[] = { {editAll,"Select and Edit all these objects"}, {killAll,"Kill all these objects"}, {editSelected,"Edit only the selected objects"}, {killSelected,"Kill only the selected objects"}, {0,0} } ; KeySetDisp look = currentKeySetDisp("drawMenus"); kSet = look->kSet; if (!wp) wp = writeAccessPossible() ? 1 : 2 ; graphRegister(LEFT_DOWN, controlLeftDown); graphClear () ; graphFitBounds (&nx, &ny) ; /* draw a line at the bottom of the window to extend box0 * to the dimensions of the window */ graphLine(0.0, (float)ny+1, (float)nx+1.0, (float)ny+1); /**********************************************/ menuregion = graphBoxStart(); /**** first line of buttons ****/ graphLine(0.0, 0.0, (float)nx+1.0, 0.0); line = .5 ; box = graphButton("Show As..:", nextShowtype, 1.0 ,line); menu = displayGetShowTypesMenu(); graphBoxFreeMenu(box, (FreeMenuFunction)changeShowtype,menu); for(i=1;i<=menu[0].key;i++) if(look->showtype == menu[i].key) { graphText(menu[i].text, 13, line + .2) ; break; } if (biblioPossible(kSet)) { box = graphButton("Biblio",relatedBiblio,23.5,line); graphBoxMenu(box, 0); } box = graphButton("More Info",beforeForest,31.1,line) ; graphBoxMenu(box, 0); box = graphButton("Quit",graphDestroy,42.0,line); graphBoxMenu(box, 0); line += 1.7; /* end of first line */ /**** second line of buttons ****/ box = graphButton("Query..",openQueryBox,1.0,line); graphBoxMenu(box, query); box = graphButton("Select/Modif..",clearSelected,9.9,line) ; /* was 0.5); */ graphBoxMenu(box, modifSelectMenu) ; box = graphButton("Export..",none,25.5,line) ; graphBoxMenu(box, dumpAs); box = graphButton("Other",otherTools,35.1,line) ; /* was 0.5); */ graphBoxMenu(box, 0); box = graphButton("Help",help,42.0,line); graphBoxMenu(box, 0); line += 1.7 ; /* end of second line */ /**** optional third line of buttons ****/ N3rdLINE = wp ? 3 : 2 ; /* number of boxes of third line */ if (isOtherTools) { /* ATTENTION, adjust N3rdLINE if you edit this piece of code * ++ it for each additional box */ box = graphButton("Combine..",none,1.0,line); graphBoxMenu(box, combine); graphButton(look->showClass ? "Hide Class" : "Class Names" ,showClasses,12.0,line) ; if (wp) box = graphButton("Edit/Kill..",editSelected,25.5,line); graphBoxMenu(box, editMenu); line += 1.7 ; } NQueryLine = 2 ; /* number of boxes of query line */ if (look->showQuery) { graphText ("Query: ", 3, line) ; look->queryBox = graphTextScrollEntry (look->queryBuffer,254, nx-10, 9, line, keySetDoQuery) ; line += 1.7; } if (look->showQuery != 2) /* 2 means focus desired */ { graphEntryDisable() ; graphRegister (KEYBOARD, localKbd) ; } graphLine(0.0, line, (float)nx+1.0, line); graphBoxEnd(); /* end of menuregion box */ if (look->message) { int len = strlen(look->message); char *start = look->message; char *cp = start; while (cp <= look->message + len) { if (*cp == '\0' || *cp == '\n') { *cp = '\0'; graphText (start, 2, line+0.3) ; start = cp+1; line += 1.0; } cp++; } line += 0.7 ; } TOPGAP = line; /************/ if (look == selectedKeySet) graphBoxDraw (menuregion,BLACK,PALERED) ; else graphBoxDraw (menuregion,BLACK,WHITE) ; return; } /* drawMenus */ static void scrollMiddleUp(double x, double y) /* re-center scrollbar */ { float newy; KeySetDisp look = currentKeySetDisp("scrollMiddleUp"); if(look->keySetAlpha && look->scrollBarBox) { newy = (float)y-(look->scrolllen/2.0); setPage(&newy); if(look->base == keySetMax(look->keySetAlpha)) { --look->base; pageUp(); return; } if (look != selectedKeySet) keySetSelect () ; keySetShow2 (look->kSet, look) ; } } /************************** eof *****************************/