From 51e9503489f2cee28a076bf52c56185a5283b069 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Mon, 3 Feb 2014 19:45:44 +0100 Subject: [PATCH] Add context menu to ICS console XB-GTK A right-click handler is added to the output memos of the ICS Interaction window. It pops up the ICS text menu. It is remembered whether the menu was already up; if not, it will be popped down after a command is selected from it. Like the WinBoard context menu, the commands will be able to use the clicked word. The -icsMenu 'command' $chat is now recognized as a special case, not to be sent to the ICS, but executed by XBoard. It will assign one of the five chats to the clicked name. If no empty chat is available, the last chat will be used (but not cleared). The -icsMenu in the master config file is now configured to contain this command, but unfortunately this will not become effective for users that already have a settings file. The Text Menu now puts $input commands in ICS Console Input field when the ICS Input Box is not up. The text placed in the input field for completion (as per $input directive) turned out to be selected in GTK, so that when you stated typing, it was erased again! By making the Text menu dialog subject to WindowPlacement control, and interrogating the poition of the ICS Console window, the Text Menu can be popped up such that the mouse pointer is on the bottom-left button. --- common.h | 1 + dialogs.c | 102 +++++++++++++++++++++++++++++++++++++++++++------------ dialogs.h | 1 + gtk/xboard.c | 6 +++ gtk/xoptions.c | 7 ++-- xaw/xboard.c | 6 +++ xboard.conf.in | 1 + 7 files changed, 98 insertions(+), 26 deletions(-) diff --git a/common.h b/common.h index 8cd93ce..2f66365 100644 --- a/common.h +++ b/common.h @@ -856,6 +856,7 @@ extern WindowPlacement wpEvalGraph; extern WindowPlacement wpMoveHistory; extern WindowPlacement wpGameList; extern WindowPlacement wpTags; +extern WindowPlacement wpTextMenu; #define MAXENGINES 2000 diff --git a/dialogs.c b/dialogs.c index af8435a..16d4d19 100644 --- a/dialogs.c +++ b/dialogs.c @@ -966,20 +966,35 @@ BoardOptionsProc () Option textOptions[100]; static void PutText P((char *text, int pos)); +static void NewChat P((char *name)); +static char clickedWord[MSG_SIZ], click; void SendString (char *p) { - char buf[MSG_SIZ], *q; + char buf[MSG_SIZ], buf2[MSG_SIZ], *q; + if(q = strstr(p, "$name")) { // in Xaw this is already intercepted + if(!shellUp[TextMenuDlg] || !clickedWord[0]) return; + strncpy(buf2, p, MSG_SIZ); + snprintf(buf2 + (q-p), MSG_SIZ -(q-p), "%s%s", clickedWord, q+5); + p = buf2; + } + if(!strcmp(p, "$chat")) { // special case for opening chat + NewChat(clickedWord); + } else if(q = strstr(p, "$input")) { if(!shellUp[TextMenuDlg]) return; strncpy(buf, p, MSG_SIZ); strncpy(buf + (q-p), q+6, MSG_SIZ-(q-p)); PutText(buf, q-p); - return; + } else { + snprintf(buf, MSG_SIZ, "%s\n", p); + SendToICS(buf); + } + if(click) { // popped up by memo click + click = clickedWord[0] = 0; + PopDown(TextMenuDlg); } - snprintf(buf, MSG_SIZ, "%s\n", p); - SendToICS(buf); } void @@ -1267,21 +1282,6 @@ IcsKey (int n) SetInsertPos(&boxOptions[INPUT], strlen(val)); } -static void -PutText (char *text, int pos) -{ - char buf[MSG_SIZ], *p; - - if(strstr(text, "$add ") == text) { - GetWidgetText(&boxOptions[INPUT], &p); - snprintf(buf, MSG_SIZ, "%s%s", p, text+5); text = buf; - pos += strlen(p) - 5; - } - SetWidgetText(&boxOptions[INPUT], text, TextMenuDlg); - SetInsertPos(&boxOptions[INPUT], pos); - HardSetFocus(&boxOptions[INPUT]); -} - void ICSInputBoxPopUp () { @@ -1706,7 +1706,7 @@ PromotionPopUp (char choice) //---------------------------- Chat Windows ---------------------------------------------- -static char *line, *memo, *partner, *texts[MAX_CHAT], dirty[MAX_CHAT]; +static char *line, *memo, *chatMemo, *partner, *texts[MAX_CHAT], dirty[MAX_CHAT]; static int activePartner, hidden = 1; void ChatSwitch P((int n)); @@ -1720,6 +1720,34 @@ int ChatOK P((int n)); void PaneSwitch P((void)); +WindowPlacement wpTextMenu; + +int +ContextMenu (Option *opt, int button, int x, int y, char *text, int index) +{ // callback for ICS-output clicks; handles button 3, passes on other events + char *start, *end; + int h; + if(button == -3) return TRUE; // supress default GTK context menu on up-click + if(button != 3) return FALSE; + start = end = text + index; // figure out what text was clicked + while(isalnum(*end)) end++; + while(start > text && isalnum(start[-1])) start--; + clickedWord[0] = NULLCHAR; + if(end-start >= 80) end = start + 80; // intended for small words and numbers + strncpy(clickedWord, start, end-start); clickedWord[end-start] = NULLCHAR; + click = !shellUp[TextMenuDlg]; // request auto-popdown of textmenu when we popped it up + h = wpTextMenu.height; // remembered height of text menu + if(h <= 0) h = 65; // when not available, position w.r.t. top + GetPlacement(ChatDlg, &wpTextMenu); + if(opt->target == (void*) &chatMemo) wpTextMenu.y += (wpTextMenu.height - 30)/2; // click in chat + wpTextMenu.x += x - 50; wpTextMenu.y += y - h + 50; // request positioning + if(wpTextMenu.x < 0) wpTextMenu.x = 0; + if(wpTextMenu.y < 0) wpTextMenu.y = 0; + wpTextMenu.width = wpTextMenu.height = -1; + IcsTextProc(); + return TRUE; +} + Option chatOptions[] = { { 0, 0, 0, NULL, NULL, "", NULL, Label , N_("Chats:") }, { 1, SAME_ROW|TT, 75, NULL, (void*) &ChatSwitch, NULL, NULL, Button, N_("New Chat") }, @@ -1727,16 +1755,35 @@ Option chatOptions[] = { { 3, SAME_ROW|TT, 75, NULL, (void*) &ChatSwitch, NULL, NULL, Button, N_("New Chat") }, { 4, SAME_ROW|TT, 75, NULL, (void*) &ChatSwitch, NULL, NULL, Button, N_("New Chat") }, { 5, SAME_ROW|TT, 75, NULL, (void*) &ChatSwitch, NULL, NULL, Button, N_("New Chat") }, -{ 250, T_VSCRL | T_FILL | T_WRAP | T_TOP, 510, NULL, (void*) &memo, NULL, NULL, TextBox, "" }, +{ 250, T_VSCRL | T_FILL | T_WRAP | T_TOP, 510, NULL, (void*) &memo, NULL, (void*) &ContextMenu, TextBox, "" }, { 0, 0, 0, NULL, NULL, "", NULL, Break , "" }, { 0, T_TOP, 100, NULL, (void*) &partner, NULL, NULL, TextBox, N_("Chat partner:") }, { 0, SAME_ROW, 0, NULL, (void*) &PaneSwitch, NULL, NULL, Button, N_("Hide") }, -{ 250, T_VSCRL | T_FILL | T_WRAP | T_TOP, 510, NULL, (void*) &memo, NULL, NULL, TextBox, "" }, +{ 250, T_VSCRL | T_FILL | T_WRAP | T_TOP, 510, NULL, (void*) &chatMemo, NULL, (void*) &ContextMenu, TextBox, "" }, { 0, 0, 0, NULL, NULL, "", NULL, Break , "" }, { 0, 0, 510, NULL, (void*) &line, NULL, NULL, TextBox, "" }, { 0, NO_OK|SAME_ROW, 0, NULL, (void*) &ChatOK, NULL, NULL, EndMark , "" } }; +static void +PutText (char *text, int pos) +{ + char buf[MSG_SIZ], *p; + DialogClass dlg = ChatDlg; + Option *opt = &chatOptions[CHAT_IN]; + + if(strstr(text, "$add ") == text) { + GetWidgetText(&boxOptions[INPUT], &p); + snprintf(buf, MSG_SIZ, "%s%s", p, text+5); text = buf; + pos += strlen(p) - 5; + } + if(shellUp[InputBoxDlg]) opt = &boxOptions[INPUT], dlg = InputBoxDlg; // for the benefit of Xaw give priority to ICS Input Box + SetWidgetText(opt, text, dlg); + SetInsertPos(opt, pos); + HardSetFocus(opt); + CursorAtEnd(opt); +} + void IcsHist (int n, Option *opt, DialogClass dlg) { // [HGM] input: let up-arrow recall previous line from history @@ -1783,7 +1830,7 @@ ChatOK (int n) safeStrCpy(chatPartner[activePartner], partner, MSG_SIZ); SetWidgetText(&chatOptions[CHAT_OUT], "", -1); // clear text if we alter partner SetWidgetText(&chatOptions[CHAT_IN], "", ChatDlg); // clear text if we alter partner - SetWidgetLabel(&chatOptions[activePartner+1], chatPartner[activePartner] ? chatPartner[activePartner] : _("New Chat")); + SetWidgetLabel(&chatOptions[activePartner+1], chatPartner[activePartner][0] ? chatPartner[activePartner] : _("New Chat")); HardSetFocus(&chatOptions[CHAT_IN]); } if(line[0] || hidden) { // something was typed (for ICS commands we also allow empty line!) @@ -1842,6 +1889,15 @@ PaneSwitch () Show(&chatOptions[CHAT_PANE], hidden = 1); // hide } +static void +NewChat (char *name) +{ // open a chat on program request. If no empty one available, use last + int i; + for(i=0; i