/* This file implements kanji 'radical' search widgets. * At one point, I intended to make my own radical list, with * my own definition of radicals * But I have wimped out and decided to go with the "standard" ones. * * This stuff takes advantage of the 'radkfile' file, included with * Jim Breen's xjdic program, and copied here with permission. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "defs.h" #include "externs.h" #include "game.h" /* for GUESS_XXX defines */ #include "search.h" #include "multikanji.h" #include "searchwidgets.h" #include "utils.h" #include "init.h" /* for setup_deletewindow() */ Cursor pointercursor, busycursor; Widget radical_popup; Widget radicalinputform; Widget radsearch_help; /* like a status bar */ int num_radicals=0; /* number of radicals read from file */ /*MAXRADICALS is defined in defs.h now */ XChar2b radicals[MAXRADICALS]; /* char for each radical */ XChar2b radical_array[MAXRADICALS][MAXKRADPOST]; /* kanji containing each rad*/ Widget radbuttons[MAXRADICALS]; CARD8 radtoggle[MAXRADICALS]; /* array to show if radical is selected*/ int numradsactive; /* number of radicals indicated by current select */ XChar2b activelist[MAXKRADPOST]; /* activelist[] is the intersection of the kanji list from each * highlighted radical (eg: if its entry in radtoggle[] is set) */ static void setradstatus(char *s) { XtVaSetValues(radsearch_help,XtNlabel,s,NULL); } /* Callback for 'clear' button * Note that we have to duplicate PART of functionality in here, * in subtractRadical() */ void ClearRadicals(Widget w, XtPointer data, XtPointer call_data) { int rcount; for(rcount=0; rcount=num_radicals){ puts("ERROR: mergeRadical passed invalid radnum"); return 0; } kradptr=radical_array[radnum]; /* kradptr now points to list of all kanji that use this radical*/ while(kradptr->byte1!=0){ if(kstrchr(activelist,*kradptr) != NULL){ newactivelist[newcount++]=*kradptr; } kradptr++; } if(newcount>0){ if(do_merge==0){ /* we were just checking to see if it was POSSIBLE*/ return 1; } newactivelist[newcount].byte1=0; newactivelist[newcount].byte2=0; #ifdef DEBUG { XChar2b *tmpptr=activelist; int kcount=0; printf("kanji in old active list:\n "); while(tmpptr->byte1!=0){ printf("0x%2x%2x ", tmpptr->byte1,tmpptr->byte2); tmpptr++; kcount++; } printf(" (kcount=%d)\n",kcount); tmpptr=&radical_array[radnum][0]; kcount=0; printf("kanji in radical%d list:\n ",radnum); while(tmpptr->byte1!=0){ printf("0x%2x%2x ", tmpptr->byte1,tmpptr->byte2); tmpptr++; kcount++; } printf(" (kcount=%d)\n",kcount); } #endif printf("DEBUG: copying %d bytes from %p to %p\n", (newcount+1)*sizeof(XChar2b),newactivelist,activelist); bcopy(newactivelist,activelist,(newcount+1)*sizeof(XChar2b)); #ifdef DEBUG { XChar2b *tmpptr=activelist; int kcount=0; printf("kanji in MERGED active list:\n "); while(tmpptr->byte1!=0){ printf("0x%2x%2x ", tmpptr->byte1,tmpptr->byte2); tmpptr++; kcount++; } printf(" (kcount=%d)\n",kcount); } #endif return 1; } else { return 0; } } /* Given a SINGLE kanji, look up all radicals that we know of, that * are used in it. * Length of radlist array should be MAXRADICALS+1, * although in reality, there probably wont be more than 5 radicals involved. */ void FindRadicals(XChar2b kanji, XChar2b *radlist){ int rcount; XChar2b *radscan; for(rcount=0; rcountbyte1 !=0){ if((radscan->byte1==kanji.byte1) && (radscan->byte2==kanji.byte2)) { radlist->byte1=radicals[rcount].byte1; radlist->byte2=radicals[rcount].byte2; radlist++; } radscan++; } } } /* given a radical indexnumber, * take all kanji referenced by that radical and add to 'active' list. * return 1 if okay, 0 if we tried to merge, and failed. */ static int addRadical(int radnum) { int radcount; XChar2b *radptr; if((radnum>num_radicals)||(radnum<0)){ puts("ERROR: addRadical passed invalid number"); return 0; } if(numradsactive==0){ bcopy(radical_array[radnum], activelist, MAXKRADPOST*sizeof(XChar2b)); } else { if(!mergeRadical(radnum, 1)){ setradstatus("no combination possible"); return 0; } } /* mask out buttons that no longer can be used */ /* skip one that was just pressed, and any that are highlighted*/ for(radcount=0; radcount byte1!=0){ radcount++; radptr++; } { char countbuf[50]; sprintf(countbuf,"%d kanji possible",radcount); setradstatus(countbuf); numradsactive=radcount; } return 1; } /* Need to just recalculate intersection of all currently active * radicals, except the one passed in. * Make sure to update numradsactive * Logic in here must match ClearRadicals() */ static void subtractRadical(int radnum) { int rcount,totalactive; radtoggle[radnum]=0; numradsactive=0; activelist[0].byte1=0; /* Kinda brute-force, but cant think of "elegant" way to do this */ for(rcount=0,totalactive=0; rcount=getMultiMax()){ return; } /* Now fill out the "multikanji" popup window, with an entry * for each "active" kanji that is potentially a match with * the radicals the user has selected so far. */ ClearAllMulti(); for(rcount=0;rcountMAXKANJIALLOWED)){ printf("SelectRadical: ERROR: kanji 0x%x in activelist out of range\n", kindex); continue; } kanjiptr=translations[kindex]; if(kanjiptr==NULL){ printf("SelectRadical: ERROR: no entry for kanji 0x%x (position %d)\n", kindex, rcount); } else { AddMultiTranslation(kanjiptr); } } SetMultiMode(GUESS_KANJI); ShowMulti(); } XChar2b fakelabel[2]={{0x24, 0x22}, {0x0, 0x0}}; /* * Internal routine, to create the buttons for the * kanji radical search popup. * Should have: * - Buttons for all 250 radicals * - a 'clear' button * - a 'search' button * - a status label. * */ void makeradicalinput(Widget parent) { Widget radform,bottomform; Widget clearbutton; int radcount; XChar2b buttonlabel[2]; buttonlabel[1].byte1=0; buttonlabel[1].byte2=0; radform=XtVaCreateManagedWidget("radinputform", boxWidgetClass,parent, XtNwidth,600, XtNleft,XawChainLeft, XtNright,XawChainRight, XtNtop, XawChainTop, XtNbottom, XawChainBottom, NULL); for(radcount=0;radcount0) return 1; return 0; } /* exported routine */ /* Call HaveRadicals() if you want to know if it * succeeded or not */ void InitRadicals() { #define RADBUFLEN 8192 /* I'm not particularly proud of the internals of this thing. * Unfortunately, the file format doesnt easily lend itself * to a better approach, that I can think of. * Oh well, memory is a lot cheaper these days. Sigh. */ char radfile[MAXLINELEN]; /* path to "radkfile" */ CARD8 linebuf[RADBUFLEN]; int cur_radnum=-1; int kradpos=0; FILE *radfp; GetXtrmString("radkfile","Radkfile",radfile); numradsactive=0; bzero(radical_array,MAXRADICALS*MAXKRADPOST*sizeof(XChar2b)); bzero(radtoggle,MAXRADICALS); radfp=fopen(radfile,"r"); if(radfp==NULL){ num_radicals=0; return; } printf("Opened radfile %s\n",radfile); while(cur_radnum= RADBUFLEN){ fprintf(stderr,"ERROR: radkfile %s corrupted!\n", radfile); printf("linepos=%d,kradpos=%d\n",linepos,kradpos); exit(1); } } if(cur_radnum==MAXRADICALS){ fprintf(stderr,"ERROR:InitRadicals exceeded MAXRADICALS\n"); /* Need to increase the #define */ num_radicals=0; return; } num_radicals=cur_radnum; printf("%d radicals read from radkfile\n",num_radicals); } /* exported routine */ void MakeRadicalinputPopup() { if(num_radicals==0) { return; } pointercursor=XCreateFontCursor(display, XC_X_cursor); busycursor=XCreateFontCursor(display, XC_clock); radical_popup = XtVaCreatePopupShell("kdrill_radicalsearch ", topLevelShellWidgetClass, search_popup, NULL); radicalinputform = XtVaCreateManagedWidget("radicalinputform", formWidgetClass, radical_popup, XtNleft,XawChainLeft, XtNright,XawChainRight, XtNtop, XawChainTop, XtNbottom, XawChainBottom, NULL); /* make all the substuff */ makeradicalinput(radicalinputform); } /* * Exported routine: * * It pops up the kanji radical search window */ void ShowRadicalinput(Widget w,XtPointer client_data, XtPointer call_data) { static int radicals_up = -1; static Position rel_x,rel_y; Position x,y; if(num_radicals==0){ setstatus("ERROR: Radical file radkfile not present"); return; } if(radicals_up==-1){ /* first time init.. */ /*rel_x = GetXtNumber("radical_popupx","Search_popupx");*/ /*rel_y = GetXtNumber("radical_popupy","Search_popupy");*/ rel_x = 10; rel_y = 10; radicals_up=0; } if(isMapped(radical_popup)==False){ XtTranslateCoords(search_popup,rel_x,rel_y,&x,&y); XtVaSetValues(radical_popup, XtNx,x, XtNy,y, NULL); XtPopup(radical_popup,XtGrabNone); if(radicals_up==0){ setup_deletewindow(radical_popup); radicals_up=1; } setstatus("Bringing up radical input window..."); } else { XtPopdown(radical_popup); } }