*\r
* Author: H.G.Muller (August 2009)\r
*\r
+ * Copyright 2009, 2010, 2011 Free Software Foundation, Inc.\r
+ *\r
* ------------------------------------------------------------------------\r
*\r
* GNU XBoard is free software: you can redistribute it and/or modify\r
#include <malloc.h>\r
#include <commdlg.h>\r
#include <dlgs.h>\r
+#include <Windowsx.h>\r
\r
#include "common.h"\r
-#include "winboard.h"\r
#include "frontend.h"\r
+#include "winboard.h"\r
#include "backend.h"\r
\r
#include "wsnap.h"\r
\r
int chatCount;\r
+static int onTop;\r
extern char chatPartner[MAX_CHAT][MSG_SIZ];\r
HANDLE chatHandle[MAX_CHAT];\r
+static WNDPROC chatInputWindowProc;\r
\r
void SendToICS P((char *s));\r
-void ChatPopUp();\r
+void ChatPopUp P((char *s));\r
void ChatPopDown();\r
\r
/* Imports from backend.c */\r
-char * SavePart(char *str);\r
extern int opponentKibitzes;\r
\r
/* Imports from winboard.c */\r
+VOID SaveInHistory(char *cmd);\r
+char *PrevInHistory(char *cmd);\r
+char *NextInHistory();\r
extern HWND ChatDialog;\r
\r
extern HINSTANCE hInst;\r
-extern HWND hwndMain;\r
+extern HWND hwndConsole;\r
+extern char ics_handle[];\r
\r
extern WindowPlacement wpChat[MAX_CHAT];\r
+extern WindowPlacement wpConsole;\r
\r
extern BoardSize boardSize;\r
\r
SendMessage( hMemo, EM_SCROLLCARET, 0, 0);\r
}\r
\r
+LRESULT CALLBACK\r
+InterceptArrowKeys(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ char buf[MSG_SIZ];\r
+ char *p;\r
+ CHARRANGE sel;\r
+\r
+ switch (message) {\r
+ case WM_KEYDOWN: // cloned from ConsoleInputSubClass()\r
+ switch (wParam) {\r
+ case VK_UP:\r
+ GetWindowText(hwnd, buf, MSG_SIZ);\r
+ p = PrevInHistory(buf);\r
+ if (p != NULL) {\r
+ SetWindowText(hwnd, p);\r
+ sel.cpMin = 999999;\r
+ sel.cpMax = 999999;\r
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ return 0;\r
+ }\r
+ break;\r
+ case VK_DOWN:\r
+ p = NextInHistory();\r
+ if (p != NULL) {\r
+ SetWindowText(hwnd, p);\r
+ sel.cpMin = 999999;\r
+ sel.cpMax = 999999;\r
+ SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+ return 0;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ return (*chatInputWindowProc)(hwnd, message, wParam, lParam);\r
+}\r
+\r
// This seems pure front end\r
LRESULT CALLBACK ChatProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
{\r
static SnapData sd;\r
char buf[MSG_SIZ], mess[MSG_SIZ];\r
- int partner = -1, i;\r
+ int partner = -1, i, x, y;\r
+ static BOOL filterHasFocus[MAX_CHAT];\r
+ WORD wMask;\r
+ HWND hMemo;\r
\r
for(i=0; i<MAX_CHAT; i++) if(hDlg == chatHandle[i]) { partner = i; break; }\r
\r
switch (message) {\r
case WM_INITDIALOG:\r
+ Translate(hDlg, DLG_Chat);\r
if(partner<0) {\r
for(i=0; i<MAX_CHAT; i++) if(chatHandle[i] == NULL) { partner = i; break; }\r
chatHandle[partner] = hDlg;\r
- sprintf(buf, "Chat Window %s", first.tidy);\r
+ snprintf(buf, MSG_SIZ, T_("Chat Window %s"), ics_handle[0] ? ics_handle : first.tidy);\r
SetWindowText(hDlg, buf);\r
}\r
- chatPartner[partner][0] = 0;\r
-\r
+ for(i=0; i<MAX_CHAT; i++) if(chatHandle[i]) {\r
+ if(i == partner) continue;\r
+ // set our button in other open chats\r
+ SetDlgItemText(chatHandle[i], IDC_Focus1+partner-(i<partner), chatPartner[partner]);\r
+ EnableWindow( GetDlgItem(chatHandle[i], IDC_Focus1+partner-(i<partner)), 1 );\r
+ // and buttons for other chats in ours\r
+ SetDlgItemText(hDlg, IDC_Focus1+i-(i>partner), chatPartner[i]);\r
+ } else EnableWindow( GetDlgItem(hDlg, IDC_Focus1+i-(i>partner)), 0 );\r
+ for(i=0; i<MAX_CHAT-1; i++) { Button_SetStyle(GetDlgItem(hDlg, IDC_Focus1+i), BS_PUSHBUTTON|BS_LEFT, TRUE); }\r
+ x = wpConsole.x; y = wpConsole.y; EnsureOnScreen(&x, &y, 0, 0);\r
+ SetWindowPos(hDlg, NULL, x, y, 0, 0, SWP_NOZORDER|SWP_NOSIZE);\r
+ SendMessage( GetDlgItem(hDlg, IDC_ChatPartner), // [HGM] clickbox: initialize with requested handle\r
+ WM_SETTEXT, 0, (LPARAM) chatPartner[partner] );\r
+ filterHasFocus[partner] = TRUE;\r
+ onTop = partner; // a newly opened box becomes top one\r
+ if(chatPartner[partner][0]) {\r
+ filterHasFocus[partner] = FALSE;\r
+ SetFocus( GetDlgItem(hDlg, OPT_ChatInput) );\r
+ }\r
+ hMemo = GetDlgItem(hDlg, IDC_ChatMemo);\r
+ wMask = (WORD) SendMessage(hMemo, EM_GETEVENTMASK, 0, 0L);\r
+ SendMessage(hMemo, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
+ SendMessage(hMemo, EM_AUTOURLDETECT, TRUE, 0L);\r
+ chatInputWindowProc = (WNDPROC) // cloned from ConsoleWndProc(). Assume they all share same proc.\r
+ SetWindowLongPtr(GetDlgItem(hDlg, OPT_ChatInput), GWLP_WNDPROC, (LONG_PTR) InterceptArrowKeys);\r
return FALSE;\r
\r
+ case WM_NOTIFY:\r
+ if (((NMHDR*)lParam)->code == EN_LINK)\r
+ {\r
+ ENLINK *pLink = (ENLINK*)lParam;\r
+ if (pLink->msg == WM_LBUTTONUP)\r
+ {\r
+ TEXTRANGE tr;\r
+\r
+ tr.chrg = pLink->chrg;\r
+ tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);\r
+ SendMessage( GetDlgItem(hDlg, IDC_ChatMemo), EM_GETTEXTRANGE, 0, (LPARAM)&tr);\r
+ ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);\r
+ free(tr.lpstrText);\r
+ }\r
+ }\r
+ break;\r
+\r
case WM_COMMAND:\r
+ /*\r
+ [AS]\r
+ If <Enter> is pressed while editing the filter, it's better to apply\r
+ the filter rather than selecting the current game.\r
+ */\r
+ if( LOWORD(wParam) == IDC_ChatPartner ) {\r
+ switch( HIWORD(wParam) ) {\r
+ case EN_SETFOCUS:\r
+ filterHasFocus[partner] = TRUE;\r
+ break;\r
+ case EN_KILLFOCUS:\r
+ filterHasFocus[partner] = FALSE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if( filterHasFocus[partner] && (LOWORD(wParam) == IDC_Send) ) {\r
+ SetFocus(GetDlgItem(hDlg, OPT_ChatInput));\r
+ wParam = IDC_Change;\r
+ }\r
+ /* [AS] End command replacement */\r
+\r
switch (LOWORD(wParam)) {\r
\r
- case IDCANCEL:\r
- chatHandle[partner] = 0;\r
- chatPartner[partner][0] = 0;\r
- ChatPopDown();\r
- EndDialog(hDlg, TRUE);\r
- break;\r
+ case IDCANCEL: /* let Esc key switch focus back to console */\r
+ SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));\r
+ break;\r
\r
case IDC_Clear:\r
SendMessage( GetDlgItem(hDlg, IDC_ChatMemo), WM_SETTEXT, 0, (LPARAM) "" );\r
\r
case IDC_Change:\r
GetDlgItemText(hDlg, IDC_ChatPartner, chatPartner[partner], MSG_SIZ);\r
+ for(i=0; i<MAX_CHAT; i++) if(chatHandle[i] && i != partner) {\r
+ // set our button in other open chats\r
+ SetDlgItemText(chatHandle[i], IDC_Focus1+partner-(i<partner), chatPartner[partner]);\r
+ }\r
break;\r
\r
case IDC_Send:\r
GetDlgItemText(hDlg, OPT_ChatInput, mess, MSG_SIZ);\r
SetDlgItemText(hDlg, OPT_ChatInput, "");\r
// from here on it could be back-end\r
- if(!strcmp("WHISPER", chatPartner[partner]))\r
- sprintf(buf, "whisper %s\n", mess); // WHISPER box uses "whisper" to send\r
+ SaveInHistory(mess);\r
+ if(!strcmp("whispers", chatPartner[partner]))\r
+ snprintf(buf, MSG_SIZ, "whisper %s\n", mess); // WHISPER box uses "whisper" to send\r
+ else if(!strcmp("shouts", chatPartner[partner]))\r
+ snprintf(buf, MSG_SIZ, "shout %s\n", mess); // SHOUT box uses "shout" to send\r
else {\r
if(!atoi(chatPartner[partner])) {\r
- sprintf(buf, "> %s\n", mess); // echo only tells to handle, not channel\r
+ snprintf(buf, MSG_SIZ, "> %s\r\n", mess); // echo only tells to handle, not channel\r
InsertIntoMemo(hDlg, buf);\r
- }\r
- sprintf(buf, "tell %s %s\n", chatPartner[partner], mess);\r
+ snprintf(buf, MSG_SIZ, "xtell %s %s\n", chatPartner[partner], mess);\r
+ } else\r
+ snprintf(buf, MSG_SIZ, "tell %s %s\n", chatPartner[partner], mess);\r
}\r
SendToICS(buf);\r
break;\r
\r
+ case IDC_Focus1:\r
+ case IDC_Focus2:\r
+ case IDC_Focus3:\r
+ case IDC_Focus4:\r
+ i = LOWORD(wParam) - IDC_Focus1;\r
+ if(i >= partner) i++;\r
+ onTop = i;\r
+ SetFocus(GetDlgItem(hDlg, IDC_Send));\r
+ if(chatHandle[i]) {\r
+ int j;\r
+ for(j=0; j<MAX_CHAT; j++) if(i != j && chatHandle[j])\r
+ Button_SetState(GetDlgItem(chatHandle[j], IDC_Focus1+i-(j<i)), FALSE);\r
+ SetFocus(GetDlgItem(chatHandle[i], OPT_ChatInput));\r
+ }\r
+ break;\r
+\r
default:\r
break;\r
}\r
chatHandle[partner] = 0;\r
chatPartner[partner][0] = 0;\r
ChatPopDown();\r
+ for(i=0; i<MAX_CHAT; i++) if(chatHandle[i] && i != partner) {\r
+ // set our button in other open chats\r
+ SetDlgItemText(chatHandle[i], IDC_Focus1+partner-(i<partner), "");\r
+ EnableWindow( GetDlgItem(chatHandle[i], IDC_Focus1+partner-(i<partner)), 0 );\r
+ }\r
EndDialog(hDlg, TRUE);\r
break;\r
\r
}\r
\r
// front end\r
-void ChatPopUp()\r
+void ChatPopUp(char *icsHandle)\r
{\r
FARPROC lpProc;\r
- \r
- if(chatCount >= MAX_CHAT) return;\r
+ int i, partner = -1;\r
\r
CheckMenuItem(GetMenu(hwndMain), IDM_NewChat, MF_CHECKED);\r
+ for(i=0; i<MAX_CHAT; i++) if(chatHandle[i] == NULL) { partner = i; break; }\r
+ if(partner == -1) { DisplayError("You first have to close a Chat Box\nbefore you can open a new one", 0); return; }\r
+ if(icsHandle) // [HGM] clickbox set handle in advance\r
+ safeStrCpy(chatPartner[partner], icsHandle,\r
+ sizeof(chatPartner[partner])/sizeof(chatPartner[partner][0]) );\r
+ else chatPartner[partner][0] = NULLCHAR;\r
chatCount++;\r
\r
lpProc = MakeProcInstance( (FARPROC) ChatProc, hInst );\r
\r
/* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */\r
- CreateDialog( hInst, MAKEINTRESOURCE(DLG_Chat), hwndMain, (DLGPROC)lpProc );\r
+ CreateDialog( hInst, MAKEINTRESOURCE(DLG_Chat), hwndConsole, (DLGPROC)lpProc );\r
\r
FreeProcInstance(lpProc);\r
\r
\r
void OutputChatMessage(int partner, char *text)\r
{\r
- if(!chatHandle[partner]) return;\r
+ int j, n = strlen(text);\r
\r
+ if(!chatHandle[partner]) return;\r
+ text[n+1] = 0; text[n] = '\n'; text[n-1] = '\r'; // Needs CR to not lose line breaks on copy-paste\r
InsertIntoMemo(chatHandle[partner], text);\r
+ if(partner != onTop) for(j=0; j<MAX_CHAT; j++) if(j != partner && chatHandle[j])\r
+ Button_SetState(GetDlgItem(chatHandle[j], IDC_Focus1+partner-(j<partner)), TRUE);\r
}\r