48d555a122d58944d4da4fc87959c52b5f157131
[xboard.git] / winboard / wchat.c
1 /*\r
2  * Chat window (PV)\r
3  *\r
4  * Author: H.G.Muller (August 2009)\r
5  *\r
6  * ------------------------------------------------------------------------\r
7  *\r
8  * GNU XBoard is free software: you can redistribute it and/or modify\r
9  * it under the terms of the GNU General Public License as published by\r
10  * the Free Software Foundation, either version 3 of the License, or (at\r
11  * your option) any later version.\r
12  *\r
13  * GNU XBoard is distributed in the hope that it will be useful, but\r
14  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
16  * General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU General Public License\r
19  * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
20  *\r
21  *------------------------------------------------------------------------\r
22  ** See the file ChangeLog for a revision history.  */\r
23 \r
24 #include "config.h"\r
25 \r
26 #include <windows.h> /* required for all Windows applications */\r
27 #include <richedit.h>\r
28 #include <stdio.h>\r
29 #include <stdlib.h>\r
30 #include <malloc.h>\r
31 #include <commdlg.h>\r
32 #include <dlgs.h>\r
33 \r
34 #include "common.h"\r
35 #include "frontend.h"\r
36 #include "winboard.h"\r
37 #include "backend.h"\r
38 \r
39 #include "wsnap.h"\r
40 \r
41 int chatCount;\r
42 extern char chatPartner[MAX_CHAT][MSG_SIZ];\r
43 HANDLE chatHandle[MAX_CHAT];\r
44 \r
45 void SendToICS P((char *s));\r
46 void ChatPopUp();\r
47 void ChatPopDown();\r
48 \r
49 /* Imports from backend.c */\r
50 extern int opponentKibitzes;\r
51 \r
52 /* Imports from winboard.c */\r
53 extern HWND ChatDialog;\r
54 \r
55 extern HINSTANCE hInst;\r
56 extern HWND hwndMain;\r
57 \r
58 extern WindowPlacement wpChat[MAX_CHAT];\r
59 \r
60 extern BoardSize boardSize;\r
61 \r
62 /* Module variables */\r
63 #define H_MARGIN            5\r
64 #define V_MARGIN            5\r
65 \r
66 // front end, although we might make GetWindowRect front end instead\r
67 static int GetControlWidth( HWND hDlg, int id )\r
68 {\r
69     RECT rc;\r
70 \r
71     GetWindowRect( GetDlgItem( hDlg, id ), &rc );\r
72 \r
73     return rc.right - rc.left;\r
74 }\r
75 \r
76 // front end?\r
77 static int GetControlHeight( HWND hDlg, int id )\r
78 {\r
79     RECT rc;\r
80 \r
81     GetWindowRect( GetDlgItem( hDlg, id ), &rc );\r
82 \r
83     return rc.bottom - rc.top;\r
84 }\r
85 \r
86 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )\r
87 {\r
88     HWND hControl = GetDlgItem( hDlg, id );\r
89 \r
90     SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );\r
91 }\r
92 \r
93 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine\r
94 static void ResizeWindowControls( HWND hDlg )\r
95 {\r
96     RECT rc;\r
97     int clientWidth;\r
98     int clientHeight;\r
99     int maxControlWidth;\r
100     int buttonWidth, buttonHeight;\r
101 \r
102     /* Initialize variables */\r
103     GetClientRect( hDlg, &rc );\r
104 \r
105     clientWidth = rc.right - rc.left;\r
106     clientHeight = rc.bottom - rc.top;\r
107 \r
108     maxControlWidth = clientWidth - 2*H_MARGIN;\r
109     buttonWidth  = GetControlWidth(hDlg, IDC_Send);\r
110     buttonHeight = GetControlHeight(hDlg, IDC_Send);\r
111 \r
112     /* Resize controls */\r
113     SetControlPos( hDlg, IDC_Clear, maxControlWidth+H_MARGIN-2*buttonWidth-5, V_MARGIN, buttonWidth, buttonHeight );\r
114     SetControlPos( hDlg, IDC_Send, maxControlWidth+H_MARGIN-buttonWidth, V_MARGIN, buttonWidth, buttonHeight );\r
115     SetControlPos( hDlg, IDC_ChatMemo, H_MARGIN, 2*V_MARGIN+buttonHeight, maxControlWidth, clientHeight-3*V_MARGIN-2*buttonHeight );\r
116     SetControlPos( hDlg, OPT_ChatInput, H_MARGIN, clientHeight-V_MARGIN-buttonHeight, maxControlWidth, buttonHeight );\r
117 \r
118 //    InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );\r
119 //    InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );\r
120 }\r
121 \r
122 // front end. Actual printing of PV lines into the output field\r
123 static void InsertIntoMemo( HANDLE hDlg, char * text )\r
124 {\r
125     HANDLE hMemo = GetDlgItem(hDlg, IDC_ChatMemo);\r
126 \r
127     SendMessage( hMemo, EM_SETSEL, 1000000, 1000000 );\r
128 \r
129     SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );\r
130     SendMessage( hMemo, EM_SCROLLCARET, 0, 0);\r
131 }\r
132 \r
133 // This seems pure front end\r
134 LRESULT CALLBACK ChatProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
135 {\r
136     static SnapData sd;\r
137     char buf[MSG_SIZ], mess[MSG_SIZ];\r
138     int partner = -1, i;\r
139     static BOOL filterHasFocus[MAX_CHAT];\r
140 \r
141     for(i=0; i<MAX_CHAT; i++) if(hDlg == chatHandle[i]) { partner = i; break; }\r
142 \r
143     switch (message) {\r
144     case WM_INITDIALOG:\r
145         if(partner<0) {\r
146                 for(i=0; i<MAX_CHAT; i++) if(chatHandle[i] == NULL) { partner = i; break; }\r
147                 chatHandle[partner] = hDlg;\r
148                 sprintf(buf, "Chat Window %s", first.tidy);\r
149                 SetWindowText(hDlg, buf);\r
150         }\r
151         chatPartner[partner][0] = 0;\r
152         filterHasFocus[partner] = FALSE;\r
153 \r
154         return FALSE;\r
155 \r
156     case WM_COMMAND:\r
157       /* \r
158         [AS]\r
159         If <Enter> is pressed while editing the filter, it's better to apply\r
160         the filter rather than selecting the current game.\r
161       */\r
162       if( LOWORD(wParam) == IDC_ChatPartner ) {\r
163           switch( HIWORD(wParam) ) {\r
164           case EN_SETFOCUS:\r
165               filterHasFocus[partner] = TRUE;\r
166               break;\r
167           case EN_KILLFOCUS:\r
168               filterHasFocus[partner] = FALSE;\r
169               break;\r
170           }\r
171       }\r
172 \r
173       if( filterHasFocus[partner] && (LOWORD(wParam) == IDC_Send) ) {\r
174           SetFocus(GetDlgItem(hDlg, OPT_ChatInput));\r
175           wParam = IDC_Change;\r
176       }\r
177       /* [AS] End command replacement */\r
178 \r
179         switch (LOWORD(wParam)) {\r
180 \r
181         case IDCANCEL:\r
182             chatHandle[partner] = 0;\r
183             chatPartner[partner][0] = 0;\r
184             ChatPopDown();\r
185             EndDialog(hDlg, TRUE);\r
186             break;\r
187 \r
188         case IDC_Clear:\r
189             SendMessage( GetDlgItem(hDlg, IDC_ChatMemo), WM_SETTEXT, 0, (LPARAM) "" );\r
190             break;\r
191 \r
192         case IDC_Change:\r
193             GetDlgItemText(hDlg, IDC_ChatPartner, chatPartner[partner], MSG_SIZ);\r
194             break;\r
195 \r
196         case IDC_Send:\r
197             GetDlgItemText(hDlg, OPT_ChatInput, mess, MSG_SIZ);\r
198             SetDlgItemText(hDlg, OPT_ChatInput, "");\r
199             // from here on it could be back-end\r
200             if(!strcmp("WHISPER", chatPartner[partner]))\r
201                 sprintf(buf, "whisper %s\n", mess); // WHISPER box uses "whisper" to send\r
202             else {\r
203                 if(!atoi(chatPartner[partner])) {\r
204                     sprintf(buf, "> %s\n", mess); // echo only tells to handle, not channel\r
205                 InsertIntoMemo(hDlg, buf);\r
206                 sprintf(buf, "xtell %s %s\n", chatPartner[partner], mess);\r
207                 } else\r
208                 sprintf(buf, "tell %s %s\n", chatPartner[partner], mess);\r
209             }\r
210             SendToICS(buf);\r
211             break;\r
212 \r
213         default:\r
214           break;\r
215         }\r
216 \r
217         break;\r
218 \r
219     case WM_CLOSE:\r
220         chatHandle[partner] = 0;\r
221         chatPartner[partner][0] = 0;\r
222         ChatPopDown();\r
223         EndDialog(hDlg, TRUE);\r
224         break;\r
225 \r
226     case WM_SIZE:\r
227         ResizeWindowControls( hDlg );\r
228         break;\r
229 \r
230     case WM_ENTERSIZEMOVE:\r
231         return OnEnterSizeMove( &sd, hDlg, wParam, lParam );\r
232 \r
233     case WM_SIZING:\r
234         return OnSizing( &sd, hDlg, wParam, lParam );\r
235 \r
236     case WM_MOVING:\r
237         return OnMoving( &sd, hDlg, wParam, lParam );\r
238 \r
239     case WM_EXITSIZEMOVE:\r
240         return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
241     }\r
242 \r
243     return FALSE;\r
244 }\r
245 \r
246 // front end\r
247 void ChatPopUp()\r
248 {\r
249   FARPROC lpProc;\r
250   \r
251   if(chatCount >= MAX_CHAT) return;\r
252 \r
253   CheckMenuItem(GetMenu(hwndMain), IDM_NewChat, MF_CHECKED);\r
254   chatCount++;\r
255 \r
256     lpProc = MakeProcInstance( (FARPROC) ChatProc, hInst );\r
257 \r
258     /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */\r
259     CreateDialog( hInst, MAKEINTRESOURCE(DLG_Chat), hwndMain, (DLGPROC)lpProc );\r
260 \r
261     FreeProcInstance(lpProc);\r
262 \r
263 }\r
264 \r
265 // front end\r
266 void ChatPopDown()\r
267 {\r
268   if(--chatCount <= 0)\r
269         CheckMenuItem(GetMenu(hwndMain), IDM_NewChat, MF_UNCHECKED);\r
270 }\r
271 \r
272 \r
273 //------------------------ pure back-end routines -------------------------------\r
274 \r
275 void OutputChatMessage(int partner, char *text)\r
276 {\r
277         if(!chatHandle[partner]) return;\r
278 \r
279         InsertIntoMemo(chatHandle[partner], text);\r
280 }\r