Make a kind of ICS text menu in XBoard as a dialog
authorH.G. Muller <h.g.muller@hccnet.nl>
Sat, 5 Mar 2011 22:27:48 +0000 (23:27 +0100)
committerArun Persaud <apersaud@lbl.gov>
Thu, 7 Apr 2011 05:21:41 +0000 (22:21 -0700)
The dialog with buttons can be opened from the View menu. It is
configured by the option -icsMenu; a default setting for this is
included in the master settings file.
  The commands specified by the -icsMenu can now contain $name and $input
keywords, which will be replaced by the current primary selection, or
text the user types, respectively. Commands that contain $name will not
be sent when the current selection is empty. Commands that do not
contain $input will be sent to the ICS immediately; otherwise they will
be placed in the ICS Input Box, with the cursor at the point of the
$input, and input focus given to the Input Box, so the user can start
typing. When a command is prefixed by "$add " it will be appended to the
existing ICS Input Box contents, rather than replace it.
  The items now have to be separated by ";\n", and button text from
command by ';' (with optional linefeed). This allows configuring of
multi-line commands, as a single linefeed no longer has special
sigificance.

xboard.c
xboard.conf.in
xoptions.c

index 7b55b63..e967626 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -454,6 +454,7 @@ void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
+void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
@@ -646,6 +647,7 @@ MenuItem viewMenu[] = {
     {N_("Move History       Alt+Shift+H"),   "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
     {N_("Evaluation Graph  Alt+Shift+E"),    "Show Evaluation Graph", EvalGraphProc},
     {N_("Game List            Alt+Shift+G"), "Show Game List", ShowGameListProc},
     {N_("Move History       Alt+Shift+H"),   "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
     {N_("Evaluation Graph  Alt+Shift+E"),    "Show Evaluation Graph", EvalGraphProc},
     {N_("Game List            Alt+Shift+G"), "Show Game List", ShowGameListProc},
+    {N_("ICS text menu"), "ICStex", IcsTextProc},
     {"----", NULL, NothingProc},
     {N_("Tags"),             "Show Tags", EditTagsProc},
     {N_("Comments"),         "Show Comments", EditCommentProc},
     {"----", NULL, NothingProc},
     {N_("Tags"),             "Show Tags", EditTagsProc},
     {N_("Comments"),         "Show Comments", EditCommentProc},
@@ -2793,6 +2795,7 @@ Enables ncpEnables[] = {
     { "menuMode.Two Machines", False },
     { "menuMode.Machine Match", False },
     { "menuMode.ICS Client", False },
     { "menuMode.Two Machines", False },
     { "menuMode.Machine Match", False },
     { "menuMode.ICS Client", False },
+    { "menuView.ICStex", False },
     { "menuView.ICS Input Box", False },
     { "Action", False },
     { "menuEdit.Revert", False },
     { "menuView.ICS Input Box", False },
     { "Action", False },
     { "menuEdit.Revert", False },
@@ -2801,10 +2804,10 @@ Enables ncpEnables[] = {
     { "menuEngine.Engine #2 Settings", False },
     { "menuEngine.Move Now", False },
     { "menuEngine.Retract Move", False },
     { "menuEngine.Engine #2 Settings", False },
     { "menuEngine.Move Now", False },
     { "menuEngine.Retract Move", False },
+    { "menuOptions.ICS", False },
 #ifndef OPTIONSDIALOG
     { "menuOptions.Auto Flag", False },
     { "menuOptions.Auto Flip View", False },
 #ifndef OPTIONSDIALOG
     { "menuOptions.Auto Flag", False },
     { "menuOptions.Auto Flip View", False },
-    { "menuOptions.ICS", False },
 //    { "menuOptions.ICS Alarm", False },
     { "menuOptions.Move Sound", False },
     { "menuOptions.Hide Thinking", False },
 //    { "menuOptions.ICS Alarm", False },
     { "menuOptions.Move Sound", False },
     { "menuOptions.Hide Thinking", False },
@@ -2818,6 +2821,7 @@ Enables ncpEnables[] = {
 
 Enables gnuEnables[] = {
     { "menuMode.ICS Client", False },
 
 Enables gnuEnables[] = {
     { "menuMode.ICS Client", False },
+    { "menuView.ICStex", False },
     { "menuView.ICS Input Box", False },
     { "menuAction.Accept", False },
     { "menuAction.Decline", False },
     { "menuView.ICS Input Box", False },
     { "menuAction.Accept", False },
     { "menuAction.Decline", False },
index 1c0b737..590f5a5 100644 (file)
 -materialDraws true
 -trivialDraws false
 ;
 -materialDraws true
 -trivialDraws false
 ;
+; Configure the ICS text menu
+;
+-icsMenu {Give me;ptell Please give me $input;
+Avoid;ptell Please don't let him get $input;
+Q;$add a Queen $input;
+R;$add a Rook $input;
+B;$add a Bishop $input;
+N;$add a Knight $input;
+P;$add a Pawn $input;
+Dead;ptell I will be checkmated;
+MultiLine;
+set open 0
+set seek 0
+set tell 1;
+Kill;ptell I will checkmate him!;
+Who;who;\r
+Finger (name);finger $name;\r
+Players;players;\r
+Vars (name);vars $name;\r
+Games;games;\r
+Observe (name);observe $name;\r
+Sought;sought;\r
+Match (name);match $name;\r
+Tell (name);tell $name $input;\r
+Play (name);play $name;\r
+Message (name);message $name $input;\r
+}
+;
 ; Save user settings.
 ; Must be last in file to make user options prevail over system-wide settings!
 ;
 ; Save user settings.
 ; Must be last in file to make user options prevail over system-wide settings!
 ;
index 8dbf32a..b41f007 100644 (file)
@@ -50,6 +50,7 @@ extern char *getenv();
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
 #include <X11/Shell.h>
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
 #include <X11/Shell.h>
+#include <X11/Xatom.h>
 #include <X11/Xaw/Dialog.h>
 #include <X11/Xaw/Form.h>
 #include <X11/Xaw/List.h>
 #include <X11/Xaw/Dialog.h>
 #include <X11/Xaw/Form.h>
 #include <X11/Xaw/List.h>
@@ -1665,6 +1666,87 @@ void MatchOptionsProc(w, event, prms, nprms)
    GenericPopUp(matchOptions, _("Match Options"), 0);
 }
 
    GenericPopUp(matchOptions, _("Match Options"), 0);
 }
 
+Option textOptions[100];
+extern char *icsTextMenuString;
+void PutText P((char *text, int pos));
+
+SendString(char *p)
+{
+    char buf[MSG_SIZ], *q;
+    if(q = strstr(p, "$input")) {
+       if(!shellUp[4]) return;
+       strncpy(buf, p, MSG_SIZ);
+       strncpy(buf + (q-p), q+6, MSG_SIZ-(q-p));
+       PutText(buf, q-p);
+       return;
+    }
+    snprintf(buf, MSG_SIZ, "%s\n", p);
+    SendToICS(buf);
+}
+
+/* function called when the data to Paste is ready */
+static void
+SendTextCB(Widget w, XtPointer client_data, Atom *selection,
+          Atom *type, XtPointer value, unsigned long *len, int *format)
+{
+  char buf[MSG_SIZ], *p = (char*) textOptions[(int) client_data].choice, *name = (char*) value, *q;
+  if (value==NULL || *len==0) return; /* nothing selected, abort */
+  name[*len]='\0';
+  strncpy(buf, p, MSG_SIZ);
+  q = strstr(p, "$name");
+  snprintf(buf + (q-p), MSG_SIZ -(q-p), "%s%s", name, q+5);
+  SendString(buf);
+  XtFree(value);
+}
+
+void SendText(int n)
+{
+    char *p = (char*) textOptions[n].choice;
+    if(strstr(p, "$name")) {
+       XtGetSelectionValue(menuBarWidget,
+         XA_PRIMARY, XA_STRING,
+         /* (XtSelectionCallbackProc) */ SendTextCB,
+         (XtPointer) n, /* client_data passed to PastePositionCB */
+         CurrentTime
+       );
+    } else SendString(p);
+}
+
+void IcsTextProc(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{
+   int i=0, j;
+   char *p, *q, *r;
+   if((p = icsTextMenuString) == NULL) return;
+   do {
+       q = r = p; while(*p && *p != ';') p++;
+       for(j=0; j<p-q; j++) textOptions[i].name[j] = *r++;
+       textOptions[i].name[j++] = 0;
+       if(!*p) break;
+       if(*++p == '\n') p++; // optional linefeed after button-text terminating semicolon
+       q = p;
+       textOptions[i].choice = (char**) (r = textOptions[i].name + j);
+       while(*p && (*p != ';' || p[1] != '\n')) textOptions[i].name[j++] = *p++;
+       textOptions[i].name[j++] = 0;
+       if(*p) p += 2;
+       textOptions[i].max = 135;
+       textOptions[i].min = i&1;
+       textOptions[i].handle = NULL;
+       textOptions[i].target = &SendText;
+       textOptions[i].textValue = strstr(r, "$input") ? "#80FF80" : strstr(r, "$name") ? "#FF8080" : "#FFFFFF";
+       textOptions[i].type = Button;
+   } while(++i < 99 && *p);
+   if(i == 0) return;
+   textOptions[i].type = EndMark;
+   textOptions[i].target = NULL;
+   textOptions[i].min = 2;
+   MarkMenu("menuView.ICStex", 3);
+   GenericPopUp(textOptions, _("ICS text menu"), 3);
+}
+
 extern char ICSInputTranslations[];
 char *icsText;
 
 extern char ICSInputTranslations[];
 char *icsText;
 
@@ -1673,15 +1755,28 @@ Option boxOptions[] = {
 {   0,  3,    0, NULL, NULL, "", NULL, EndMark , "" }
 };
 
 {   0,  3,    0, NULL, NULL, "", NULL, EndMark , "" }
 };
 
-void InputBoxPopup()
+void PutText(char *text, int pos)
 {
     Widget edit;
     Arg args[16];
 {
     Widget edit;
     Arg args[16];
+    char buf[MSG_SIZ], *p;
 
 
-    if(shells[4]) { // if already exists, clear content
-       XtSetArg(args[0], XtNstring, "");
-       XtSetValues(boxOptions[0].handle, args, 1);
+    if(strstr(text, "$add ") == text) {
+       XtSetArg(args[0], XtNstring, &p);
+       XtGetValues(boxOptions[0].handle, args, 1);
+       snprintf(buf, MSG_SIZ, "%s%s", p, text+5); text = buf;
+       pos += strlen(p) - 5;
     }
     }
+    XtSetArg(args[0], XtNstring, text);
+    XtSetValues(boxOptions[0].handle, args, 1);
+    XtSetArg(args[0], XtNinsertPosition, pos);
+    XtSetValues(boxOptions[0].handle, args, 1);
+//    SetFocus(boxOptions[0].handle, shells[4], NULL, False); // No idea why this does not work, and the following is needed:
+    XSetInputFocus(xDisplay, XtWindow(boxOptions[0].handle), RevertToPointerRoot, CurrentTime);
+}
+
+void InputBoxPopup()
+{
     MarkMenu("menuView.ICS Input Box", 4);
     if(GenericPopUp(boxOptions, _("ICS input box"), 4))
        XtOverrideTranslations(boxOptions[0].handle, XtParseTranslationTable(ICSInputTranslations));
     MarkMenu("menuView.ICS Input Box", 4);
     if(GenericPopUp(boxOptions, _("ICS input box"), 4))
        XtOverrideTranslations(boxOptions[0].handle, XtParseTranslationTable(ICSInputTranslations));