/*
* 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
}
void
+WidgetEcho (Option *opt, int state)
+{
+}
+
+void
SetWidgetLabel (Option *opt, char *buf)
{
Arg arg;
}
void
+SetComboChoice (Option *opt, int n)
+{
+ SetWidgetText(opt, opt->choice[n], MasterDlg);
+}
+
+void
SetDialogTitle (DialogClass dlg, char *title)
{
Arg args[16];
{
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
}
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)
}
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);
}
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
return entry;
}
+char *
+format_accel (char *input)
+{
+ char *output;
+ char *key,*test;
+
+ output = strdup("");
+
+ if( strstr(input, "<Ctrl>") )
+ {
+ output = realloc(output, strlen(output) + strlen(_("Ctrl"))+2);
+ strncat(output, _("Ctrl"), strlen(_("Ctrl")) +1);
+ strncat(output, "+", 1);
+ };
+ if( strstr(input, "<Alt>") )
+ {
+ output = realloc(output, strlen(output) + strlen(_("Alt"))+2);
+ strncat(output, _("Alt"), strlen(_("Alt")) +1);
+ strncat(output, "+", 1);
+ };
+ if( strstr(input, "<Shift>") )
+ {
+ 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
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;
}
};
void
-AddHandler (Option *opt, int nr)
+AddHandler (Option *opt, DialogClass dlg, int nr)
{
XtOverrideTranslations(opt->handle, XtParseTranslationTable(translationTable[nr]));
}
SubstructureRedirectMask | SubstructureNotifyMask,
&xev);
- XFlush(xDisplay);
+ XFlush(xDisplay);
XSync(xDisplay, False);
}
{ // 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
// 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;
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
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
for(h=0; h<height || c == width-1; h++) {
i = h + c*height;
if(option[i].type == EndMark) break;
- if(option[i].type == -1) continue;
+ if(option[i].type == Skip) continue;
lastrow = forelast;
forelast = last;
switch(option[i].type) {
} else texts[h] = dialog = NULL; // kludge to position from left margin
w = option[i].type == Spin || option[i].type == Fractional ? 70 : option[i].max ? option[i].max : 205;
if(option[i].type == FileName || option[i].type == PathName) w -= 55;
+ if(squareSize > 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
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*)
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:
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*)
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 */,
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 = form; lastrow = oldLastRow; form = oldForm; forelast = oldForeLast;
break;
case Break:
+ if(c) break;
width++;
height = i+1;
stack = !(option[i].min & SAME_ROW);
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)));
}
}
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)
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:
{ // 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 :( )
}
void
-HardSetFocus (Option *opt)
+HardSetFocus (Option *opt, DialogClass dlg)
{
XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime);
}
void
-FileNamePopUpGTK(char *label, char *def, char *filter, FileProc proc, Boolean pathFlag, char *openMode, char **openName, FILE **openFP)
+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);
}
-