X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=xaw%2Fxoptions.c;h=1c0a897b54df6d153a74fcc5e9cc454fc4f5e74f;hb=HEAD;hp=a475c588edeb020459f1106e64c22d691228392c;hpb=e6f4f8fdada1a701e4be2e4807920dbcad697fb1;p=xboard.git diff --git a/xaw/xoptions.c b/xaw/xoptions.c index a475c58..1c0a897 100644 --- a/xaw/xoptions.c +++ b/xaw/xoptions.c @@ -1,7 +1,7 @@ /* * xoptions.c -- Move list window, part of X front end for XBoard * - * Copyright 2000, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + * Copyright 2000, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc. * ------------------------------------------------------------------------ * * GNU XBoard is free software: you can redistribute it and/or modify @@ -143,6 +143,11 @@ static Arg formArgs[] = { }; void +CursorAtEnd (Option *opt) +{ +} + +void GetWidgetText (Option *opt, char **buf) { Arg arg; @@ -176,6 +181,11 @@ SetWidgetState (Option *opt, int state) } void +WidgetEcho (Option *opt, int state) +{ +} + +void SetWidgetLabel (Option *opt, char *buf) { Arg arg; @@ -184,6 +194,12 @@ SetWidgetLabel (Option *opt, char *buf) } void +SetComboChoice (Option *opt, int n) +{ + SetWidgetText(opt, opt->choice[n], MasterDlg); +} + +void SetDialogTitle (DialogClass dlg, char *title) { Arg args[16]; @@ -192,11 +208,12 @@ SetDialogTitle (DialogClass dlg, char *title) } void -LoadListBox (Option *opt, char *emptyText) +LoadListBox (Option *opt, char *emptyText, int n1, int n2) { static char *dummyList[2]; dummyList[0] = emptyText; // empty listboxes tend to crash X, so display user-supplied warning string instead - XawListChange(opt->handle, *(char*)opt->target ? opt->target : dummyList, 0, 0, True); + XawListChange(opt->handle, *(char**)opt->target ? opt->target : dummyList, 0, 0, True); +//printf("listbox data = %x\n", opt->target); } int @@ -260,6 +277,53 @@ SelectedListBoxItem (Option *opt) } void +SetTextColor (char **cnames, int fg, int bg, int attr) +{ // this is not possible in Xaw +} + +void +AppendColorized (Option *opt, char *message, int count) +{ + if(!opt->handle) return; + AppendText(opt, message); +} + +void +ApplyFont (Option *opt, char *font) +{ // dummy +} + +void +Show (Option *opt, int hide) +{ + static Dimension h; + Arg args[16]; + Dimension v; + int j=0; +return; // FIXME: it would be nice if the Chat window did have an ICS pane we could hide behind +//printf("Show(%d) %x\n", hide, opt->handle); + if(!opt->handle) return; + if(hide) { // make sure original size is saved + XtSetArg(args[j], XtNheight, &v); j++; + XtGetValues(opt->handle, args, j); + if(v != 1) h = v; + } +printf("h = %d\n",h); + j = 0; + XtSetArg(args[j], XtNheight, hide ? 1 : h); j++; + XtSetValues(opt->handle, args, j); +} + +void +HighlightText (Option *opt, int start, int end, Boolean on) +{ + if(on) + XawTextSetSelection( opt->handle, start, end ); // for lack of a better method, use selection for highighting + else + XawTextSetSelection( opt->handle, 0, 0 ); +} + +void FocusOnWidget (Option *opt, DialogClass dlg) { UnCaret(); @@ -277,13 +341,21 @@ SetIconName (DialogClass dlg, char *name) } static void +LabelCallback (Widget ww, XtPointer client_data, XEvent *event, Boolean *b) +{ // called on ButtonPress in label widgets with attached user handler (clocks!) + int s, data = (intptr_t) client_data; + Option *opt = dialogOptions[data >> 8] + (s = data & 255); + + if(((XButtonEvent*)event)->button != Button1) s = -s; + ((ButtonCallback*) opt->target) (s); +} + +static void CheckCallback (Widget ww, XtPointer client_data, XEvent *event, Boolean *b) { int s, data = (intptr_t) client_data; Option *opt = dialogOptions[data >> 8] + (data & 255); - if(opt->type == Label) { ((ButtonCallback*) opt->target)(data&255); return; } - GetWidgetState(opt, &s); SetWidgetState(opt, !s); } @@ -318,7 +390,7 @@ SpinCallback (Widget w, XtPointer client_data, XtPointer call_data) if(--j < opt->min) return; } else return; snprintf(buf, MSG_SIZ, "%d", j); - SetWidgetText(opt, buf, TransientDlg); + SetWidgetText(opt, buf, shellUp[TransientDlg] ? TransientDlg : MasterDlg); } static void @@ -359,6 +431,100 @@ CreateMenuItem (Widget menu, char *msg, XtCallbackProc CB, int n) return entry; } +char * +format_accel (char *input) +{ + char *output; + char *key,*test; + + output = strdup(""); + + if( strstr(input, "") ) + { + output = realloc(output, strlen(output) + strlen(_("Ctrl"))+2); + strncat(output, _("Ctrl"), strlen(_("Ctrl")) +1); + strncat(output, "+", 1); + }; + if( strstr(input, "") ) + { + output = realloc(output, strlen(output) + strlen(_("Alt"))+2); + strncat(output, _("Alt"), strlen(_("Alt")) +1); + strncat(output, "+", 1); + }; + if( strstr(input, "") ) + { + output = realloc(output, strlen(output) + strlen(_("Shift"))+2); + strncat(output, _("Shift"), strlen(_("Shift")) +1); + strncat(output, "+", 1); + }; + + test = strrchr(input, '>'); + if ( test==NULL ) + key = strdup(input); + else + key = strdup(++test); // remove ">" + if(strlen(key) == 1) key[0] = ToUpper(key[0]); + + output = realloc(output, strlen(output) + strlen(_(key))+2); + strncat(output, _(key), strlen(_(key)) +1); + + free(key); + return output; +} + +int +pixlen (char *s) +{ +#if 0 + int dummy; + XCharStruct overall; + XTextExtents(messageFontStruct, s, strlen(s), &dummy, &dummy, &dummy, &overall); + return overall.width; +#else + float tot = 0; + while(*s) switch(*s++) { + case '.': tot += 0.45; break; + case ' ': tot += 0.55; break; + case 'i': tot += 0.45; break; + case 'l': tot += 0.45; break; + case 'j': tot += 0.45; break; + case 'f': tot += 0.45; break; + case 'I': tot += 0.45; break; + case 't': tot += 0.45; break; + case 'k': tot += 0.83; break; + case 's': tot += 0.83; break; + case 'x': tot += 0.83; break; + case 'z': tot += 0.83; break; + case 'r': tot += 0.55; break; + case 'w': tot += 1.3; break; + case 'm': tot += 1.3; break; + case 'A': tot += 1.3; break; + case 'C': tot += 1.3; break; + case 'D': tot += 1.3; break; + case 'G': tot += 1.3; break; + case 'H': tot += 1.3; break; + case 'N': tot += 1.3; break; + case 'V': tot += 1.3; break; + case 'X': tot += 1.3; break; + case 'Y': tot += 1.3; break; + case 'Z': tot += 1.3; break; + case 'M': tot += 1.6; break; + case 'W': tot += 1.6; break; + case 'B': tot += 1.1; break; + case 'E': tot += 1.1; break; + case 'F': tot += 1.1; break; + case 'K': tot += 1.1; break; + case 'P': tot += 1.1; break; + case 'R': tot += 1.1; break; + case 'S': tot += 1.1; break; + case 'O': tot += 1.4; break; + case 'Q': tot += 1.4; break; + default: tot++; + } + return tot; +#endif +} + static Widget CreateComboPopup (Widget parent, Option *opt, int n, int fromList, int def) { // fromList determines if the item texts are taken from a list of strings, or from a menu table @@ -367,20 +533,51 @@ CreateComboPopup (Widget parent, Option *opt, int n, int fromList, int def) Arg arg; MenuItem *mb = (MenuItem *) opt->choice; char **list = (char **) opt->choice; + int maxlength=0, menuLen[1000]; + if(list[0] == NULL) return NULL; // avoid empty menus, as they cause crash menu = XtCreatePopupShell(opt->name, simpleMenuWidgetClass, parent, NULL, 0); - for (i=0; 1; i++) + if(!fromList) + for (i=0; mb[i].string; i++) if(mb[i].accel) { + int len = pixlen(_(mb[i].string)); + menuLen[i] = len; + if (maxlength < len ) + maxlength = len; + } + + for (i=0; 1; i++) { char *msg = fromList ? list[i] : mb[i].string; + char *label=NULL; + if(!msg) break; - entry = CreateMenuItem(menu, opt->min & NO_GETTEXT ? msg : _(msg), (XtCallbackProc) ComboSelect, (n<<16)+i); + + if(!fromList && mb[i].accel) + { + char *menuname = opt->min & NO_GETTEXT ? msg : _(msg); + char *accel = format_accel(mb[i].accel); + size_t len; +// int fill = maxlength - strlen(menuname) +2+strlen(accel); + int fill = (maxlength - menuLen[i] + 3)*1.8; + + len = strlen(menuname)+fill+strlen(accel)+1; + label = malloc(len); + + snprintf(label,len,"%s%*s%s",menuname,fill," ",accel); + free(accel); + } + else + label = strdup(opt->min & NO_GETTEXT ? msg : _(msg)); + + entry = CreateMenuItem(menu, label, (XtCallbackProc) ComboSelect, (n<<16)+i); if(!fromList) mb[i].handle = (void*) entry; // save item ID, for enabling / checkmarking if(i==def) { XtSetArg(arg, XtNpopupOnEntry, entry); XtSetValues(menu, &arg, 1); } + free(label); } return menu; } @@ -399,7 +596,7 @@ char *translationTable[] = { // beware: order is essential! }; void -AddHandler (Option *opt, int nr) +AddHandler (Option *opt, DialogClass dlg, int nr) { XtOverrideTranslations(opt->handle, XtParseTranslationTable(translationTable[nr])); } @@ -443,7 +640,7 @@ RaiseWindow (DialogClass dlg) SubstructureRedirectMask | SubstructureNotifyMask, &xev); - XFlush(xDisplay); + XFlush(xDisplay); XSync(xDisplay, False); } @@ -486,7 +683,8 @@ GenericPopDown (Widget w, XEvent *event, String *prms, Cardinal *nprms) { // to cause popdown through a translation (Delete Window button!) int dlg = atoi(prms[0]); Widget sh = shells[dlg]; - if(shellUp[BrowserDlg] && dlg != BrowserDlg || dialogError) return; // prevent closing dialog when it has an open file-browse daughter + if(shellUp[BrowserDlg] && dlg != BrowserDlg || dialogError || dlg == MasterDlg && shellUp[TransientDlg]) + return; // prevent closing dialog when it has an open file-browse or transient daughter shells[dlg] = w; PopDown(dlg); shells[dlg] = sh; // restore @@ -568,8 +766,15 @@ GraphEventProc(Widget widget, caddr_t client_data, XEvent *event) // to give drawing routines opportunity to use it before first expose event // (which are only processed when main gets to the event loop, so after all init!) // so only change when size is no longer good + cairo_t *cr; if(graph->choice) cairo_surface_destroy((cairo_surface_t *) graph->choice); graph->choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h); + // paint white, to prevent weirdness when people maximize window and drag pieces over space next to board + cr = cairo_create ((cairo_surface_t *) graph->choice); + cairo_rectangle (cr, 0, 0, w, h); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); + cairo_fill(cr); + cairo_destroy (cr); break; } w = ((XExposeEvent*)event)->width; @@ -624,7 +829,7 @@ GenericCallback (Widget w, XtPointer client_data, XtPointer call_data) currentOption = dialogOptions[dlg=data>>16]; data &= 0xFFFF; oldSh = shells[dlg]; shells[dlg] = sh; // bow to reality if (data == 30000) { // cancel - PopDown(dlg); + PopDown(dlg); } else if (data == 30001) { // save buttons imply OK if(GenericReadout(currentOption, -1)) PopDown(dlg); // calls OK-proc after full readout, but no popdown if it returns false @@ -773,6 +978,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent shellUp[dlgNr] = True; return 0; } + if(dlgNr == TransientDlg && parent == BoardWindow && shellUp[MasterDlg]) parent = MasterDlg; // MasterDlg can always take role of main window dialogOptions[dlgNr] = option; // make available to callback // post currentOption globally, so Spin and Combo callbacks can already use it @@ -781,7 +987,6 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent if(engineDlg) { // Settings popup for engine: format through heuristic int n = currentCps->nrOptions; - if(!n) { DisplayNote(_("Engine has no options")); currentCps = NULL; return 0; } if(n > 50) width = 4; else if(n>24) width = 2; else width = 1; height = n / width + 1; if(n && (currentOption[n-1].type == Button || currentOption[n-1].type == SaveButton)) currentOption[n].min = SAME_ROW; // OK on same line @@ -818,7 +1023,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent for(h=0; h 33) w += (squareSize - 33)/2; j = SetPositionAndSize(args, dialog, last, 1 /* border */, w /* w */, option[i].type == TextBox ? option[i].value : 0 /* h */, 0x91 /* chain full width */); if(option[i].type == TextBox) { // decorations for multi-line text-edits @@ -860,7 +1066,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent XtSetArg(args[j], XtNdisplayCaret, False); j++; XtSetArg(args[j], XtNresizable, True); j++; XtSetArg(args[j], XtNinsertPosition, 9999); j++; - XtSetArg(args[j], XtNstring, option[i].type==Spin || option[i].type==Fractional ? def : + XtSetArg(args[j], XtNstring, option[i].type==Spin || option[i].type==Fractional ? def : engineDlg ? option[i].textValue : *(char**)option[i].target); j++; edit = last; option[i].handle = (void*) @@ -910,6 +1116,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent XtAddEventHandler(last, ButtonPressMask, False, CheckCallback, (XtPointer)(intptr_t) i + 256*dlgNr); shrink = TRUE; // following buttons must get text height break; + case Icon: case Label: msg = option[i].name; if(!msg) break; @@ -927,7 +1134,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent XtSetArg(args[j], XtNlabel, _(msg)); j++; option[i].handle = (void*) (last = XtCreateManagedWidget("label", labelWidgetClass, form, args, j)); if(option[i].target) // allow user to specify event handler for button presses - XtAddEventHandler(last, ButtonPressMask, False, CheckCallback, (XtPointer)(intptr_t) i + 256*dlgNr); + XtAddEventHandler(last, ButtonPressMask, False, LabelCallback, (XtPointer)(intptr_t) i + 256*dlgNr); break; case SaveButton: case Button: @@ -938,9 +1145,11 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent j = SetPositionAndSize(args, last, lastrow, 3 /* border */, option[i].max /* w */, shrink ? textHeight : 0 /* h */, option[i].min & 0xE | chain /* chain */); XtSetArg(args[j], XtNlabel, _(option[i].name)); j++; - if(option[i].textValue) { // special for buttons of New Variant dialog - XtSetArg(args[j], XtNsensitive, appData.noChessProgram || option[i].value < 0 - || strstr(first.variants, VariantName(option[i].value))); j++; + if(option[i].textValue && *option[i].textValue == '#') { // special for buttons of New Variant dialog + char *p = NULL, *v, n = option[i].value; + if(n >= 0) v = VariantName(n), p = strstr(first.variants, v); + XtSetArg(args[j], XtNsensitive, option[i].value >= 0 && (appData.noChessProgram + || p && (!*v || strlen(p) == strlen(v) || p[strlen(v)] == ','))); j++; XtSetArg(args[j], XtNborderWidth, (gameInfo.variant == option[i].value)+1); j++; } option[i].handle = (void*) @@ -950,7 +1159,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent XtAddEventHandler(option[i-1].handle, KeyReleaseMask, False, ColorChanged, (XtPointer)(intptr_t) i-1); } XtAddCallback(last, XtNcallback, GenericCallback, (XtPointer)(intptr_t) i + (dlgNr<<16)); // invokes user callback - if(option[i].textValue) SetColor( option[i].textValue, &option[i]); // for new-variant buttons + if(option[i].textValue && *option[i].textValue == '#') SetColor( option[i].textValue, &option[i]); // for new-variant buttons break; case ComboBox: j = SetPositionAndSize(args, last, lastrow, 0 /* border */, @@ -1009,6 +1218,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent case PopUp: // note: used only after Graph, so 'last' refers to the Graph widget option[i].handle = (void*) CreateComboPopup(last, option + i, i + 256*dlgNr, TRUE, option[i].value); break; + case BarBegin: case BoxBegin: if(option[i].min & SAME_ROW) forelast = lastrow; j = SetPositionAndSize(args, last, lastrow, 0 /* border */, @@ -1025,12 +1235,18 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent 0 /* w */, 0 /* h */, 1 /* chain (always on same row) */); forelast = lastrow; msg = _(option[i].name); // write name on the menu button + if(msg) { if(*msg == '_') msg++; else if(msg[1] == '_') { // kludge to remove GTK shortkut-key indicators + static char buf[MSG_SIZ]; + strncpy(buf, msg, MSG_SIZ); msg = buf + 1; + *msg = *buf; + }} XtSetArg(args[j], XtNmenuName, XtNewString(option[i].name)); j++; XtSetArg(args[j], XtNlabel, msg); j++; option[i].handle = (void*) (last = XtCreateManagedWidget(option[i].name, menuButtonWidgetClass, form, args, j)); option[i].textValue = (char*) CreateComboPopup(last, option + i, i + 256*dlgNr, FALSE, -1); break; + case BarEnd: case BoxEnd: XtManageChildren(&form, 1); SqueezeIntoBox(&option[box], i-box, option[box].max); @@ -1038,6 +1254,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent last = form; lastrow = oldLastRow; form = oldForm; forelast = oldForeLast; break; case Break: + if(c) break; width++; height = i+1; stack = !(option[i].min & SAME_ROW); @@ -1121,7 +1338,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent XtAddCallback(b_ok, XtNcallback, GenericCallback, (XtPointer)(intptr_t) (30001 + (dlgNr<<16))); if(!(option[i].min & NO_CANCEL)) { XtSetArg(args[1], XtNfromHoriz, b_ok); // overwrites! - b_cancel = XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j); + b_cancel = XtCreateManagedWidget(_("Cancel"), commandWidgetClass, form, args, j); XtAddCallback(b_cancel, XtNcallback, GenericCallback, (XtPointer)(intptr_t) (30000 + (dlgNr<<16))); } } @@ -1142,13 +1359,17 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent shellUp[dlgNr]++; // count rather than flag previous = NULL; if(textField) SetFocus(textField, popup, (XEvent*) NULL, False); - if(dlgNr && wp[dlgNr] && wp[dlgNr]->width > 0) { // if persistent window-info available, reposition + if(dlgNr && wp[dlgNr]) { // if persistent window-info available, reposition j = 0; - XtSetArg(args[j], XtNheight, (Dimension) (wp[dlgNr]->height)); j++; - XtSetArg(args[j], XtNwidth, (Dimension) (wp[dlgNr]->width)); j++; - XtSetArg(args[j], XtNx, (Position) (wp[dlgNr]->x)); j++; - XtSetArg(args[j], XtNy, (Position) (wp[dlgNr]->y)); j++; - XtSetValues(popup, args, j); + if(wp[dlgNr]->width > 0 && wp[dlgNr]->height > 0) { + XtSetArg(args[j], XtNheight, (Dimension) (wp[dlgNr]->height)); j++; + XtSetArg(args[j], XtNwidth, (Dimension) (wp[dlgNr]->width)); j++; + } + if(wp[dlgNr]->x > 0 && wp[dlgNr]->y > 0) { + XtSetArg(args[j], XtNx, (Position) (wp[dlgNr]->x)); j++; + XtSetArg(args[j], XtNy, (Position) (wp[dlgNr]->y)); j++; + } + if(j) XtSetValues(popup, args, j); } RaiseWindow(dlgNr); return 1; // tells caller he must do initialization (e.g. add specific event handlers) @@ -1188,6 +1409,11 @@ void SetInsertPos (Option *opt, int pos) { Arg args[16]; + if(pos == 999999) { // this kludge to indicate end in GTK is fatal in Xaw + char *s; + GetWidgetText(opt, &s); + pos = strlen(s) - 1; + } XtSetArg(args[0], XtNinsertPosition, pos); XtSetValues(opt->handle, args, 1); // SetFocus(opt->handle, shells[InputBoxDlg], NULL, False); // No idea why this does not work, and the following is needed: @@ -1199,6 +1425,8 @@ TypeInProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) { // can be used as handler for any text edit in any dialog (from GenericPopUp, that is) int n = prms[0][0] - '0'; Widget sh = XtParent(XtParent(XtParent(w))); // popup shell + extern int hidden; + hidden = 0; if(n<2) { // Enter or Esc typed from primed text widget: treat as if dialog OK or cancel button hit. int dlgNr; // figure out what the dialog number is by comparing shells (because we must pass it :( ) @@ -1208,9 +1436,18 @@ TypeInProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) } void -HardSetFocus (Option *opt) +HardSetFocus (Option *opt, DialogClass dlg) { XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime); } +void +FileNamePopUpWrapper (char *label, char *def, char *filter, FileProc proc, Boolean pathFlag, char *openMode, char **openName, FILE **openFP) +{ + Browse(BoardWindow, label, (def[0] ? def : NULL), filter, False, openMode, openName, openFP); +} +void +LockBoardSize (int after) +{ +}