#include #include #include #include #include #include #include #include #include #include #include #include /* See comment around MakeSpecialForms */ #include "defs.h" #include "externs.h" #include "game.h" #include "grades.h" #include "options.h" #include "search.h" #include "searchwidgets.h" #include "strokesearch.h" #include "learn.h" #include "utils.h" #include "multikanji.h" #include "init.h" #include "log.h" #include "timeout.h" Widget toplevel,mainform; XFontStruct *largekfont; XFontStruct *smallkfont; XFontStruct *englishfont; XFontStruct *defaultfont; Widget kanjiform,englishform,buttonform; Widget statusline; Widget currentkanjiForm; Widget currentkanjiGrade,currentkanjiFreq,currentkanjiNum; Widget kanjiMissed; Widget choicesWidgets[NUMBEROFCHOICES],questionWidget; Widget ONWidget; static char * jumpAccel = " Return: jump-to-kanji()"; /* setstatus: * sets label for main status bar widget. * ( the long one at the bottom) * and also the same message at the bottom of the search popup window */ void setstatus(char *s) { if((statusline==NULL) || (searchstatusline==NULL)){ /* Some kind of warning message, before program has fullyh * come up. Print to stdout instead */ printf("%s\n", s); return; } XtVaSetValues(statusline, XtNlabel,s, NULL); XtVaSetValues(searchstatusline, XtNlabel,s, NULL); } /* handle_button * exists for the sole purpose of getting Button2 events */ void handle_button(Widget w,XtPointer closure,XEvent *e,Boolean *cont) { XButtonEvent *event = (XButtonEvent *) e; int buttoncount=0; if(e->type == ClientMessage) puts("CLIENT MESSAGE FROM BUTTONH"); if((event->button != Button2) && (event->button != Button3)) return; #ifdef DEBUG puts("Got button2/3 click?"); #endif do { if(w == choicesWidgets[buttoncount]){ break; } buttoncount++; } while(buttoncount highestkanji){ setstatus("Using closest index available"); Beep(); return closestindex; } } if(abs(target - closestindex) > abs(target - counter)){ closestindex = counter; if(closestindex == target) break; } counter++; } if(target != closestindex){ setstatus("Using closest index available"); Beep(); } return closestindex; } /* given a frequency rating, * will find the closest usable kanji */ int getindexfromfreq(int freq){ int closestindex = lowestkanji; int closestfreq = translations[lowestkanji]->frequency; int counter = lowestkanji-1; while(counter <=highestkanji){ while(!UseThisKanji(counter)){ counter++; if(counter >highestkanji) return closestindex; } if(abs(closestfreq - freq) > abs((translations[counter]->frequency) - freq) ) { closestindex = counter; closestfreq = translations[counter]->frequency; if(closestfreq == freq) break; } counter++; } return closestindex; } /* DescribeCurrent() * Sets labels in MAIN window to display difficulty of * reading displayed on the top */ void DescribeCurrent(TRANSLATION kanji) { int kindex; if(kanji->kanji == NULL) { kindex = 0; } else { kindex = kanji->kanji[0].byte1; kindex = kindex <<8; kindex |= kanji->kanji[0].byte2; } if(kindex == NOKANJI) { kindex = 0; } SetWidgetNumberval(currentkanjiGrade,(int)kanji->grade_level); SetWidgetNumberval(currentkanjiFreq,(int)kanji->frequency); SetWidgetHexval(currentkanjiNum,kindex); } /* JumpToKanji * This is the MAIN WINDOW "jump to kanji" routine. * The search window has its own. * This handles jump for either direct index, Or Frequency. */ void JumpToKanji(Widget w,XEvent *event,String *params,Cardinal *num_parags) { int kindex; kindex = GetWidgetNumberval(w); /* kindex is actually EITHER index, or * frequency rating */ if(w == currentkanjiNum){ if((kindex highestkanji)){ SetWidgetHexval(w,kindex); return; } kindex = getclosestindex(kindex); } else { if(kindex <1){ setstatus("negative frequencies do not occur"); /* SetWidgetNumberval(w,values[truevalue]);*/ return; } kindex = getindexfromfreq(kindex); } lastpicked = values[truevalue]; values[truevalue] = translations[kindex]; DescribeCurrent(translations[kindex]); printallchoices(); printquestion(); return; } /* This is a special hack to attempt to force all the widgets to be the * same size. * It has the unfortunate side-effect of killing initial auto-size-width * for the top-level main window. * So if you use this, remember to do a good layout of the top-level window * as well. SIGH. * * The standard creation methods like MakeQuestionWidget are set up to * create the forms if they have not already been made here. */ void MakeSpecialForms(Widget parent){ /* We try to set resource so that we will be happy with EITHER * a Paned parent, or a Form parent. * * Note that if the parent is PanedWidget, these forms will * all be forcibly resized and stretched, ignoring * XawChainXXX */ kanjiform = XtVaCreateManagedWidget("kanjiform",formWidgetClass, mainform, XtNshowGrip, False, XtNright, XawChainRight, XtNleft, XawChainLeft, XtNtop,XawChainBottom, XtNbottom,XawChainBottom, NULL); englishform = XtVaCreateManagedWidget("englishform",formWidgetClass, mainform, XtNfromVert,kanjiform, XtNvertDistance,10, XtNshowGrip, False, XtNright, XawChainRight, XtNleft, XawChainLeft, XtNtop,XawChainBottom, XtNbottom,XawChainBottom, NULL); buttonform = XtVaCreateManagedWidget( "buttonform",formWidgetClass,mainform, XtNfromVert,englishform, XtNvertDistance,15, XtNshowGrip, False, XtNskipAdjust, True, XtNright, XawChainLeft, XtNleft, XawChainLeft, XtNtop,XawChainBottom, XtNbottom,XawChainBottom, NULL); } /* MakeCurrent; * Makes window that describes current widget. * Has current kanji grade, frequency, and index listed * (It is now also editable, to enable jumping to a kanji) */ Widget MakeCurrent(Widget parent,Widget fromvert){ Widget gradelabel,freqlabel,numlabel; XtAccelerators Accel; currentkanjiForm = XtVaCreateManagedWidget( "curkanjiForm",boxWidgetClass,parent, /*XtNright,XawChainRight,XtNleft,XawChainRight,*/ XtNtop,XawChainTop, XtNbottom,XawChainTop, XtNleft, XawChainLeft, XtNright,XawChainLeft, XtNfromVert,fromvert, XtNorientation,XtEhorizontal, NULL); gradelabel = XtVaCreateManagedWidget( "currgradelabel",labelWidgetClass,currentkanjiForm, XtNlabel,"G:", XtNtop,XawChainTop, XtNbottom,XawChainTop, XtNborderWidth,0, NULL); currentkanjiGrade = XtVaCreateManagedWidget( "curkanjiGrade",asciiTextWidgetClass,currentkanjiForm, XtNwidth,30, /* match search window */ XtNstring," ", XtNdisplayCaret,False, NULL); freqlabel = XtVaCreateManagedWidget( "currfreqlabel",labelWidgetClass,currentkanjiForm, XtNlabel,"F:", XtNborderWidth,0, NULL); currentkanjiFreq = XtVaCreateManagedWidget( "curkanjiFreq",asciiTextWidgetClass,currentkanjiForm, XtNeditType,XawtextEdit, XtNstring," ", XtNwidth,INPUTWIDTH, NULL); numlabel = XtVaCreateManagedWidget( "curNumlabel",labelWidgetClass,currentkanjiForm, XtNlabel,"#x:", XtNborderWidth,0, NULL); currentkanjiNum = XtVaCreateManagedWidget( "curkanjiNum",asciiTextWidgetClass,currentkanjiForm, XtNeditType,XawtextEdit, XtNstring," ", XtNwidth,INPUTWIDTH, NULL); /* NOTE ! ! we do NOT add a callback, because that is * taken care of by the accelerators. * callback is JumpToKanji */ Accel = XtParseAcceleratorTable(jumpAccel); XtOverrideTranslations(currentkanjiFreq,Accel); XtOverrideTranslations(currentkanjiNum,Accel); return currentkanjiForm; } static char *missedAccel = " \ BackSpace: Accelerator(x)\n \ Delete: Accelerator(x)\n \ "; /* MakeQuestionWidget() * set up widgets for top section of main window */ void MakeQuestionWidget(){ Widget tmplabel, qthrowaway; XtAccelerators Accel; if(kanjiform == NULL){ /* normally made in MakeSpecialForms() */ kanjiform = XtVaCreateManagedWidget( "kanjiform",formWidgetClass, mainform, XtNright, XawChainRight, XtNleft, XawChainLeft, XtNtop,XawChainBottom, XtNbottom,XawChainBottom, NULL); } questionWidget = XtVaCreateManagedWidget("questionlarge", commandWidgetClass, kanjiform, XtNshapeStyle,XawShapeRoundedRectangle, XtNcornerRoundPercent,50, XtNlabel,"", XtNwidth,FULLWIDTH, XtNencoding,XawTextEncodingChar2b, XtNfont,largekfont, XtNtop,XawChainTop, XtNbottom,XawChainTop, XtNleft, XawChainLeft, XtNright,XawChainRight, NULL); #ifdef USE_OKU ONWidget = XtVaCreateManagedWidget( "ONreading",labelWidgetClass,kanjiform, XtNlabel," ", XtNencoding,XawTextEncodingChar2b, XtNfont,smallkfont, XtNtop,XawChainTop, XtNbottom,XawChainTop, XtNjustify,XtJustifyLeft, XtNwidth,KANJIWIDTH * NUMBEROFCHOICES + (NUMBEROFCHOICES *5), XtNfromVert,questionWidget, NULL); #endif /* now describe current kanji */ MakeCurrent(kanjiform,questionWidget); tmplabel=XtVaCreateManagedWidget( "missedlabel",labelWidgetClass,kanjiform, XtNfromVert, questionWidget, XtNfromHoriz, currentkanjiForm, XtNtop,XawChainTop, XtNbottom,XawChainTop, XtNleft, XawChainLeft, XtNright,XawChainLeft, XtNlabel,"missed", XtNborderWidth,0, /* nasty hardcode.. */ XtNvertDistance, 10, NULL); kanjiMissed=XtVaCreateManagedWidget( "missedkanji",asciiTextWidgetClass,kanjiform, XtNfromVert, questionWidget, XtNfromHoriz, tmplabel, XtNtop,XawChainTop, XtNbottom,XawChainTop, XtNleft, XawChainLeft, XtNright,XawChainLeft, /*XtNlabel,"00/00/00",*/ /* hardcode numbers, becuase ascitxtwidget is wierd*/ XtNwidth, (int)(INPUTWIDTH *1.5) , XtNdisplayCaret,False, XtNvertDistance, 10, NULL); /* Xaw layout is a black art. This is solely for spacing */ /* qthrowaway=XtVaCreateManagedWidget( "qthrowaway",asciiTextWidgetClass,kanjiform, XtNfromVert, questionWidget, XtNfromHoriz, kanjiMissed, XtNtop,XawChainTop, XtNbottom,XawChainTop, XtNleft, XawChainLeft, XtNright,XawChainLeft, XtNlabel,"0", XtNdisplayCaret,False, NULL); */ Accel = XtParseAcceleratorTable(missedAccel); XtOverrideTranslations(kanjiMissed,Accel); } /* MakeEnglishButtons: * Just that. initialize the english buttons that display the possible * guesses. */ void MakeChoicesButtons(){ int i; if(englishform==NULL) { /* See also MakeSpecialWidgets() */ englishform = XtVaCreateManagedWidget( "englishform",formWidgetClass, mainform, XtNfromVert,kanjiform, XtNvertDistance,5, XtNright, XawChainRight, XtNleft, XawChainLeft, XtNtop,XawChainBottom, XtNbottom,XawChainBottom, NULL); } for(i=0;i1){ printf("Warning: Accelerator functions take one argument, and one only\n"); } switch(param[0]){ case 'b': BackCallback(NULL,NULL,NULL); break; case 'c': cheatcallback(NULL,NULL,NULL); break; case 'C': supercheat(); break; case 'e': ChangeMode(NULL,(XtPointer) GUESS_ENGLISH,NULL); break; case 'E': ChangeQuestion(NULL,(XtPointer) GUESS_ENGLISH,NULL); break; case 'k': ChangeMode(NULL,(XtPointer) GUESS_KANJI,NULL); break; case 'K': ChangeQuestion(NULL,(XtPointer) GUESS_KANJI,NULL); break; case 'l': LearnCallback(NULL,(XtPointer) NULL,NULL); break; case 'm': ChangeMode(NULL,(XtPointer) GUESS_KANA,NULL); break; case 'n': if(w==learn_popup){ LearnNewChar(w, (XtPointer)True,NULL); } break; case 'N': if(w==learn_popup){ LearnNewChar(w, False,NULL); } break; case 'M': ChangeQuestion(NULL,(XtPointer) GUESS_KANA,NULL); break; case 'o': ordercallback(orderbutton,NULL,NULL); break; case 'O': OptionsCallback(NULL,NULL,NULL); break; case 'u': UsefileCallback(usefilebutton,NULL,NULL); break; case 's': SearchCallback(NULL,NULL,NULL); break; /* handle two-digit accelerator code. * This is actually S[123456+] */ case 'S': param+=1; int_store = (*param)-'0'; GradeCallback(gradeButtons[int_store], (XtPointer) int_store,NULL); break; case 'T': TimerCallback(NULL,NULL,NULL); break; case 'x': if(w== kanjiMissed){ ClearMissed(); break; } break; default: printf("DEBUG: unrecognized Accelerator '%c'\n", param[0]); } } /* delete_calback * sole purpose is to handle window deletion. (like)WM_PROTOCOLS * still technically selected, via Actions.? bizzare, and irritating that we * have to use TWO METHODS to deal with this insanity. sigh. * * EXCEPT... This one seems to be to simply notify us. * If we don't register this, the client dies. But now that * we register this via XtAugmentTranslations... we dont actually * have to do anything. Mindbogglingly stupid, really. */ void delete_callback(Widget w, XEvent *event,String *params,Cardinal *num_params) { if(event->xclient.data.l[0] == delete_message){ /* handle_delete(w, NULL, event, NULL); */ return; } puts("Got NON-delete event, in delete_callback?"); } void quitaction(Widget w, XEvent * e, String *p, Cardinal *c) { quit(NULL, NULL, NULL); } /* deliberately a "nop". used primarily to make the RETURN key * do nothing, when we want to disable it. */ void do_nothing(Widget w, XEvent * e, String *p, Cardinal *c) { return; } /* Different widgets may have different "Accelerator" tables, * parsed by * but all of them have to hook through this shared Actions list */ static XtActionsRec kdrillActionList[] = { { "quit", quitaction}, { "update-frequency", UpdateFrequency}, { "update-timeout", UpdateTimeout}, { "do-find", DoFind}, { "stroke-search", DoStrokeSearch}, /* ignore warning*/ { "jump-to-kanji", JumpToKanji}, { "guess-meaning", Guessvalue}, { "Accelerator", Accelerator}, { "delete-window", delete_callback}, { "do-nothing", do_nothing}, }; XtAccelerators AllAccel; void handle_delete(Widget,XtPointer,XEvent *,Boolean *); /* MakeWidgets() * Highest level routine for making ALL the widgets. * This is THE starting point for making widgets * (even the popup stuff actually gets created through here) */ void MakeWidgets(){ #ifdef DEBUG puts("Starting MakeWidgets"); #endif /* I suppose I shouldn't hard-code window-width and height.. but it makes things easier for now. */ #ifdef USEFORMFORTOP /* not currently used */ mainform = XtVaCreateManagedWidget("kdrill",formWidgetClass, toplevel, XtNvSpace,16, XtNhSpace,10, NULL); #else /* Note: This automatically stretches out the widgets to be * the full width of the window */ mainform = XtVaCreateManagedWidget("kdrill",panedWidgetClass, toplevel, NULL); #endif initfonts(); XtAppAddActions(Context,kdrillActionList,XtNumber(kdrillActionList) ); AllAccel = XtParseAcceleratorTable(guessAccel); /*XtOverrideTranslations(mainform,AllAccel);*/ XtAugmentTranslations(mainform,AllAccel); MakeSpecialForms(mainform); MakeQuestionWidget(); MakeChoicesButtons(); MakeOptionsPopup(); MakeSearchPopup(); MakeLearnPopup(); MakeMulti(); MakeButtons(); #ifdef DEBUG puts("Ending MakeWidgets"); #endif }