/* This file is a whole module unto itself.
* It's like an "object", that will store up to MAXMULTI different kanji
* translations.
* (or at least pointers thereof)
*
* User can pick whether these translations will be displayed in terms
* of kanji, kana, or english.
* Clicking on one will set the search window to display that entry.
*
* Basic functions from the outside:
* void MakeMulti(); [create X Widget]
* void ShowMulti(); [ make window visible ]
* void AddMultiTranslation(TRANSLATION); [ add to current list]
* void ClearAllMulti();
* int getMultiMax(); [ return value of MAXMULTI define]
* int getMultiCount(); [ return number of translations in current list]
*
* And one PRIVATE function that is public because of callbacks:
* multicallback(int)
*
* Note: it is expected behaviour that routines outside this file,
* will call AddMultiTranslation() a buncha times, but then
* call ShowMulti() when they are all done adding. This allows
* us to put cleanup routines in ShowMulti()
*/
#include <Xos.h>
#include <Intrinsic.h>
#include <StringDefs.h>
#include <Xlib.h>
#include <Xutil.h>
#include <Xfuncs.h>
#include <Shell.h>
#include <Xaw/Command.h>
#include <Xaw/Label.h>
#include <Xaw/Form.h>
#include <Xaw/Box.h>
#include <Xaw/Viewport.h>
#include <stdio.h> /* shouldnt be neccessary, but it is. sigh. */
#include "defs.h"
#include "externs.h"
#include "game.h"
#include "init.h"
#include "utils.h"
#include "log.h"
#include "readfile.h"
#include "learn.h"
#include "searchwidgets.h"
/* MAXMULTI == max translation lines we will hold in multi-window */
/* If external routine wants to know this value, call getMultiMax() */
#define MAXMULTI 200
static Widget transwin[MAXMULTI]; /* user clicks to select translation*/
static TRANSLATION transptrs[MAXMULTI]; /* info in each transwin */
static Widget usefiletoggles[MAXMULTI]; /* is each one in usefile? */
static int transcount=0;
static int overflow=0; /* number of added translations over MAXMULTI */
Widget multikanab, multikanjib, multienglishb;
Widget multiclose;
static int displaymode=GUESS_ENGLISH;
static Widget multi_popup;
static Widget multi_form;
static Widget multi_viewport;
static Widget multi_status;
void RefreshMultiLabels();
void AddMultiTranslation(TRANSLATION nt);
/************************************************************/
void ShowMulti(){
static int doneinit=0;
XtPopup(multi_popup, XtGrabNone);
if(doneinit==0){
setup_deletewindow(multi_popup);
doneinit=1;
}
XawFormDoLayout(multi_form,True);
}
void HideMulti(){
XtPopdown(multi_popup);
}
/* resizing isn't behaving. so I'll force it to never go too small.
* Hopefully.
* Always have string more than 30 chars long. space-pad the end.
*/
static void setmultistatus(char *string){
#define FORCEWIDE
#ifdef FORCEWIDE
char statusbuff[50];
int stringlen=strlen(string);
if(stringlen>49)
stringlen=49;
if(multi_status==NULL)
return;
strcpy(statusbuff,
" ");
bcopy(string, statusbuff, stringlen);
XtVaSetValues(multi_status, XtNlabel,statusbuff, NULL);
#else /* STUPID */
XtVaSetValues(multi_status, XtNlabel,string, NULL);
#endif /* STUPID */
}
void ClearAllMulti(){
int tc;
overflow=0;
/* for(tc=transcount -1; tc>=0; tc--){*/
for(tc=MAXMULTI -1; tc>=0; tc--){
XUnmapWindow(XtDisplay(transwin[tc]),
XtWindow(transwin[tc]));
XtVaSetValues(usefiletoggles[tc], XtNfromVert, NULL, NULL);
/*XXX XUnmapWindow(XtDisplay(usefiletoggles[tc]),
XtWindow(usefiletoggles[tc]));
XtVaSetValues(transwin[tc], XtNfromVert, NULL, NULL);
*/
}
bzero(transptrs, sizeof(transptrs));
transcount=0;
/* Scroll up to top. Otherwise, it gets stuck at prev pos. */
XawViewportSetCoordinates(multi_viewport, 0, 0);
setmultistatus("No matches");
}
/* This callback handles both "Change what mode you display", and
* 'Hey, show me this one in detail'
*/
void multicallback(Widget button, XtPointer data, XtPointer call_data){
int newmode=-1;
int buttoncount;
if(button==multiclose){
HideMulti();
return;
}
if(button==multikanab){
newmode=GUESS_KANA;
}
if(button==multikanjib){
newmode=GUESS_KANJI;
}
if(button==multienglishb){
newmode=GUESS_ENGLISH;
}
if(newmode!=-1){
/*
* disable this optimization, becuase we want
* romaji/kana to switch more easily
if(newmode==displaymode)
return;
*/
displaymode = newmode;
RefreshMultiLabels();
return;
}
for(buttoncount=0;buttoncount<transcount; buttoncount++){
if(button== transwin[buttoncount]){
printsearch(transptrs[buttoncount]);
return;
}
}
puts("Error: multicallback got click on unrecognized button?");
}
/* This handles a click on a usefile toggle button,
* in the multikanji popup.
* Parallel function to ToggleUsefile()
*/
void multiUcallback(Widget button, XtPointer data, XtPointer call_data){
TRANSLATION trans=transptrs[(int)data];
int kindex=trans_to_index(trans);
SetUseKanji(kindex,!InUsefile(kindex));
if(InUsefile(kindex)){
HighlightButton(button);
} else {
UnhighlightButton(button);
}
/* Just in case this is for the currently displayed search line*/
UpdateSearchlabels();
DisplayLearnChar();
CountKanji();
}
/* just create the line-item buttons, not "everything" */
/* We pre-create all the buttons, and hide them when not in use.*/
void createallmulti(){
Widget newbutton,newu;
Widget prevbutton=NULL;
int formwidth=GetWidgetWidth(multi_popup);
char buttname[10],uname[10];
int transcount;
if(formwidth>50){
formwidth-=50;
}
for(transcount=0;transcount<MAXMULTI;transcount++){
sprintf(buttname, "multi%x\n", (unsigned int)transcount);
sprintf(uname, "multiU%x\n", (unsigned int)transcount);
if(transcount>0){
/* we use this for XtNfromVert offset */
prevbutton=transwin[transcount-1];
}
newbutton=XtVaCreateManagedWidget(buttname, commandWidgetClass,
multi_form,
XtNfromVert,prevbutton,
XtNwidth, formwidth,
XtNshapeStyle,XawShapeRoundedRectangle,
XtNcornerRoundPercent,20,
/* this is to get the height always right*/
XtNencoding,XawTextEncodingChar2b,
XtNfont,largekfont,
XtNleft,XawChainLeft,
XtNright,XawChainRight,
XtNlabel,"\0\0\0\0",
NULL);
XtAddCallback(newbutton, XtNcallback, multicallback, NULL);
transwin[transcount]=newbutton;
newu=XtVaCreateManagedWidget(buttname, commandWidgetClass,
multi_form,
XtNfromVert,prevbutton,
XtNfromHoriz,newbutton,
XtNleft,XawChainRight,
XtNright,XawChainRight,
XtNencoding,XawTextEncoding8bit,
XtNfont,englishfont,
XtNlabel,"u",
NULL);
XtAddCallback(newu, XtNcallback, multiUcallback, (XtPointer)transcount);
usefiletoggles[transcount]=newu;
}
XawFormDoLayout(multi_form, True);
/* Want to do this here.
* But need to do this at end of MakeMulti (our calling function)
* instead
*/
/* ClearAllMulti(); */
}
#define VWIDTH 400
#define VHEIGHT 300
/* called ONCE at start of program*/
void MakeMulti(){
Widget multitop, buttonform;
multi_popup=XtVaCreatePopupShell("multi_popup",
topLevelShellWidgetClass,
search_popup,
XtNwidth, 350,
XtNheight, 500,
NULL);
multitop=XtVaCreateManagedWidget("multitopform",
formWidgetClass,
multi_popup,
NULL);
multi_viewport=XtVaCreateManagedWidget("multiport",
viewportWidgetClass,
multitop,
XtNforceBars, True,
XtNallowHoriz,False,
XtNallowVert,True,
XtNwidth, VWIDTH,
XtNheight, VHEIGHT,
XtNbottom,XawChainBottom,
XtNright,XawChainRight,
XtNleft,XawChainLeft,
NULL);
/* This is what holds the multiple buttons, that show
* all the different matches to a search
* YES, we DO need to seed this with an initial height, otherwize
* we get irritating behavior the first time we are used.
*/
multi_form=XtVaCreateManagedWidget("multikanjiform",
formWidgetClass,
/*boxWidgetClass,*/
multi_viewport,
NULL);
/* make all the little things inside multi_form */
createallmulti();
multi_status=XtVaCreateManagedWidget("multistatus",
labelWidgetClass,
multitop,
XtNfromVert, multi_viewport,
XtNtop, XawChainBottom,
XtNbottom,XawChainBottom,
XtNleft,XawChainLeft,
XtNright,XawChainRight,
XtNlabel, "Status ",
XtNwidth, VWIDTH,
NULL);
buttonform=XtVaCreateManagedWidget("multibform",
formWidgetClass, multitop,
XtNfromVert, multi_status,
XtNtop, XawChainBottom,
XtNbottom,XawChainBottom,
XtNleft,XawChainLeft,
XtNright,XawChainLeft,
XtNresizable, False,
XtNborderWidth,0,
NULL);
multikanjib=XtVaCreateManagedWidget("multikanjib",
commandWidgetClass,
buttonform,
XtNshapeStyle,XawShapeEllipse,
XtNlabel,"Kanji",
XtNresize, False,
NULL);
multienglishb=XtVaCreateManagedWidget("multienglishb",
commandWidgetClass,
buttonform,
XtNshapeStyle,XawShapeEllipse,
XtNfromHoriz, multikanjib,
XtNlabel,"English",
XtNresize, False,
NULL);
multikanab=XtVaCreateManagedWidget("multikanab",
commandWidgetClass,
buttonform,
XtNshapeStyle,XawShapeEllipse,
XtNfromHoriz, multienglishb,
XtNlabel,"Kana meaning",
XtNresize, False,
NULL);
multiclose=XtVaCreateManagedWidget("multiclose",
commandWidgetClass,
buttonform,
/*XtNfromVert, multi_status,*/
XtNfromHoriz, multikanab,
XtNlabel,"Close",
XtNhorizDistance, 60,
XtNshapeStyle,XawShapeRoundedRectangle,
XtNcornerRoundPercent,10,
XtNborderWidth, 2,
NULL);
XtAddCallback(multiclose, XtNcallback, multicallback, NULL);
XtAddCallback(multikanab, XtNcallback, multicallback, NULL);
XtAddCallback(multikanjib, XtNcallback, multicallback, NULL);
XtAddCallback(multienglishb, XtNcallback, multicallback, NULL);
/* HAVE TO DO THIS NOW, otherwise layout doesn't happen the first
* time
*/
XtRealizeWidget(multi_popup);
/* must do this AFTER widgets have been created */
ClearAllMulti();
}
/* Sometimes, it is good to allow external functions to override
* current display setting.
* Like if we are doing radical search, for example.
* Caller should call this AFTER having done the normal AddTranslations loop,
* because this will take care of refreshing display if neccessary.
*/
void SetMultiMode(int mode){
switch(mode){
case GUESS_ENGLISH:
case GUESS_KANJI:
case GUESS_KANA:
if(displaymode!=mode){
displaymode=mode;
RefreshMultiLabels();
}
break;
default:
puts("ERROR: SetMultiMode passed in invalid mode?!");
}
}
/* run through all the widgets we have, and set labels appropriately.
* kinda like printallchoices()
* I just LOOOOVE code reuse :-)
* Call this when usefile status, or kana/romaji status changes.
*/
void RefreshMultiLabels(){
int lc;
for(lc=0;lc<transcount;lc++){
switch(displaymode){
case GUESS_ENGLISH:
setenglabel(transwin[lc], transptrs[lc]);
break;
case GUESS_KANA:
setkanalabel(transwin[lc], transptrs[lc]);
break;
case GUESS_KANJI:
setkanjilabel(transwin[lc], transptrs[lc]);
break;
}
if(InUsefile(trans_to_index(transptrs[lc]))){
HighlightButton(usefiletoggles[lc]);
} else {
UnhighlightButton(usefiletoggles[lc]);
}
}
}
/* We ignore attempts to add more than our MAXMULTI value */
void AddMultiTranslation(TRANSLATION trans){
int kindex;
char statusprompt[20];
/*int formwidth=GetWidgetWidth(multi_popup);*/
if(transcount>=MAXMULTI){
char msgbuff[100];
overflow++;
sprintf(msgbuff, "(only showing %d of %d)",
MAXMULTI, MAXMULTI+overflow);
setmultistatus(msgbuff);
return;
}
transptrs[transcount]=trans;
kindex=trans_to_index(trans);
if(transcount>0){
XtVaSetValues(transwin[transcount],
XtNfromVert,transwin[transcount-1],
NULL);
XtVaSetValues(usefiletoggles[transcount],
XtNfromVert,transwin[transcount-1],
NULL);
}
if(InUsefile(kindex)){
HighlightButton(usefiletoggles[transcount]);
} else {
UnhighlightButton(usefiletoggles[transcount]);
}
switch(displaymode){
case GUESS_ENGLISH:
setenglabel(transwin[transcount], transptrs[transcount]);
break;
case GUESS_KANA:
setkanalabel(transwin[transcount], transptrs[transcount]);
break;
case GUESS_KANJI:
setkanjilabel(transwin[transcount], transptrs[transcount]);
break;
}
XMapWindow(XtDisplay(transwin[transcount]),
XtWindow(transwin[transcount]));
XMapWindow(XtDisplay(usefiletoggles[transcount]),
XtWindow(usefiletoggles[transcount]));
transcount++;
sprintf(statusprompt,"%d matches",transcount);
setmultistatus(statusprompt);
}
int getMultiMax(){
return MAXMULTI;
}
int getMultiCount(){
return transcount;
}
syntax highlighted by Code2HTML, v. 0.9.1