Rev 21 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | // window_chat.cpp |
2 | |||
3 | #include "../common.h" |
||
4 | |||
5 | // WARNING: OLE-enabled RichEdit control needs a C++ compiler! |
||
6 | #include <richole.h> |
||
7 | |||
8 | |||
9 | // window parameters |
||
10 | #define WINDOW_CLASSNAME PROGRAM_NAME L" Chat WndClass" |
||
11 | #define WINDOW_DEFAULT_WIDTH 520 |
||
12 | #define WINDOW_DEFAULT_HEIGHT 400 |
||
13 | #define WINDOW_MIN_WIDTH 480 |
||
14 | #define WINDOW_MIN_HEIGHT 330 |
||
15 | |||
16 | |||
17 | // local definitions |
||
18 | #define WINDOW_TEXT_QUESTION 1 |
||
19 | #define WINDOW_EDITBOX_DISCUSSION 2 |
||
20 | #define WINDOW_EDITBOX_MESSAGETOSEND 3 |
||
21 | #define WINDOW_BITMAP_OPPONENTSTATUS 4 |
||
22 | #define WINDOW_BUTTON_INVITE 5 |
||
23 | #define WINDOW_BUTTON_PLAYERINFO 6 |
||
24 | #define WINDOW_BUTTON_SEND 7 |
||
25 | #define WINDOW_TEXT_STATUSBAR 8 |
||
26 | #define WINDOW_TIMER_REFRESH 1 |
||
27 | |||
28 | |||
29 | // RichEdit OLE callback interface structure definition |
||
30 | struct RichEditOLECallback : IRichEditOleCallback |
||
31 | { |
||
32 | // this structure derives from the IRichEditOleCallback structure, which itself derives |
||
33 | // from the IUnknown structure. So we define IN THIS VERY ORDER the members of the |
||
34 | // IUnknown structure first, THEN the members of the IRichEditOleCallback structure, |
||
35 | // THEN our own members. |
||
36 | |||
37 | // constructor/destructor |
||
38 | RichEditOLECallback () { reference_count = 0; } |
||
39 | ~RichEditOLECallback () { } |
||
40 | |||
41 | // members of the IUnknown structure |
||
42 | ULONG CALLBACK AddRef (void) { reference_count++; return (reference_count); } |
||
43 | ULONG CALLBACK Release (void) { reference_count--; return (reference_count); } |
||
44 | HRESULT CALLBACK QueryInterface (REFIID iid, void **ppvObject) |
||
45 | { |
||
46 | if ((iid != IID_IUnknown) && (iid != IID_IRichEditOleCallback)) |
||
47 | return (E_NOINTERFACE); |
||
48 | |||
49 | *ppvObject = this; |
||
50 | reference_count++; |
||
51 | return (S_OK); |
||
52 | } |
||
53 | |||
54 | // members of the IRichEditOleCallback structure |
||
55 | HRESULT CALLBACK ContextSensitiveHelp (BOOL fEnterMode) { return (E_NOTIMPL); } |
||
56 | HRESULT CALLBACK DeleteObject (IOleObject *lpoleobj) { return (E_NOTIMPL); } |
||
57 | HRESULT CALLBACK GetClipboardData (CHARRANGE *lpchrg, DWORD reco, IDataObject **lplpdataobj) { return (E_NOTIMPL); } |
||
58 | HRESULT CALLBACK GetContextMenu (WORD seltype, IOleObject *lpoleobj, CHARRANGE *lpchrg, HMENU *lphmenu) { return (E_NOTIMPL); } |
||
59 | HRESULT CALLBACK GetDragDropEffect (BOOL fDrag, DWORD grfKeyState, DWORD *pdwEffect) { return (E_NOTIMPL); } |
||
60 | HRESULT CALLBACK GetInPlaceContext (IOleInPlaceFrame **lplpFrame, IOleInPlaceUIWindow **lplpDoc, tagOIFI *lpFrameInfo) { return (E_NOTIMPL); } |
||
61 | HRESULT CALLBACK GetNewStorage (IStorage **storage) |
||
62 | { |
||
63 | // initialize a storage object in memory |
||
64 | |||
65 | ILockBytes *lock_bytes; |
||
66 | HRESULT ret; |
||
67 | |||
68 | if ((ret = CreateILockBytesOnHGlobal (NULL, TRUE, &lock_bytes)) != S_OK) |
||
69 | return (ret); |
||
70 | if ((ret = StgCreateDocfileOnILockBytes (lock_bytes, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, storage)) != S_OK) |
||
71 | lock_bytes->Release (); |
||
72 | return (ret); |
||
73 | } |
||
74 | HRESULT CALLBACK QueryAcceptData (IDataObject *lpdataobj, CLIPFORMAT *lpcfFormat, DWORD reco, BOOL fReally, HANDLE hMetaPict) { return (E_NOTIMPL); } |
||
75 | HRESULT CALLBACK QueryInsertObject (LPCLSID lpclsid, IStorage *storage, LONG cp) { return (S_OK); } |
||
76 | HRESULT CALLBACK ShowContainerUI (BOOL fShow) { return (E_NOTIMPL); } |
||
77 | |||
78 | // our own data |
||
79 | ULONG reference_count; |
||
80 | }; |
||
81 | |||
82 | |||
83 | // global variables used in this module only |
||
84 | static bool is_classregistered = false; |
||
85 | static PROC WindowProc_MessageToSend_DefaultProc; |
||
86 | static RichEditOLECallback *richedit_oleinterface = NULL; |
||
87 | |||
88 | |||
89 | // prototypes of local functions |
||
90 | static LRESULT CALLBACK WindowProc_ThisWindow (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam); |
||
91 | static LRESULT CALLBACK WindowProc_MessageToSend (HWND hDlg, unsigned int message, WPARAM wParam, LPARAM lParam); |
||
92 | |||
93 | |||
94 | void Window_Chat (int interlocutor_index) |
||
95 | { |
||
96 | // helper function to fire up the child window |
||
97 | |||
98 | WNDCLASSEX wc; |
||
99 | player_t *network_player; |
||
100 | |||
101 | // if the REOLECallback class instance hasn't been instantiated yet, do it |
||
102 | if (richedit_oleinterface == NULL) |
||
103 | richedit_oleinterface = new RichEditOLECallback; |
||
104 | |||
105 | network_player = Player_FindByType (PLAYER_INTERNET); // quick access to network player |
||
106 | if (network_player == NULL) |
||
107 | return; // consistency check |
||
108 | |||
109 | if (lastonlineplayers_time + 5.0f < current_time) |
||
110 | Player_SendBuffer_Add (network_player, 1000, L"who\n"); // request a players list update |
||
111 | |||
112 | if (!interlocutors[interlocutor_index].is_active) |
||
113 | return; // consistency check |
||
114 | |||
115 | // is the window class NOT registered yet ? |
||
116 | if (!is_classregistered) |
||
117 | { |
||
118 | // if so, register the window class once and for all |
||
119 | memset (&wc, 0, sizeof (wc)); |
||
120 | wc.cbSize = sizeof (wc); |
||
121 | wc.style = CS_HREDRAW | CS_VREDRAW; |
||
122 | wc.lpfnWndProc = WindowProc_ThisWindow; |
||
123 | wc.hInstance = hAppInstance; |
||
124 | wc.hIcon = LoadIcon (hAppInstance, (wchar_t *) ICON_MAIN); |
||
125 | wc.hCursor = LoadCursor (NULL, IDC_ARROW); |
||
126 | wc.hbrBackground = GetSysColorBrush (COLOR_3DFACE); |
||
127 | wc.lpszClassName = WINDOW_CLASSNAME; |
||
128 | RegisterClassEx (&wc); |
||
129 | |||
130 | is_classregistered = true; // remember this window class is registered |
||
131 | } |
||
132 | |||
133 | // create the window as an application-level window (not child) |
||
134 | interlocutors[interlocutor_index].hWnd = CreateWindowEx (WS_EX_CLIENTEDGE, WINDOW_CLASSNAME, L"", WS_OVERLAPPEDWINDOW, |
||
135 | CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT, |
||
136 | NULL, NULL, hAppInstance, NULL); |
||
137 | interlocutors[interlocutor_index].update_dialog = true; // and update this interlocutor's dialog |
||
138 | |||
139 | return; // finished, the window is fired up |
||
140 | } |
||
141 | |||
142 | |||
143 | void Window_Chat_Validated (void) |
||
144 | { |
||
145 | // callback function called by the main game thread when the window is validated |
||
146 | |||
147 | // remember this callback is no longer to be called |
||
148 | is_window_chat_validated = false; |
||
149 | |||
150 | return; // finished |
||
151 | } |
||
152 | |||
153 | |||
154 | static LRESULT CALLBACK WindowProc_ThisWindow (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam) |
||
155 | { |
||
156 | // message handler for the child window |
||
157 | |||
158 | unsigned short wParam_hiword; |
||
159 | unsigned short wParam_loword; |
||
160 | wchar_t temp_string[256]; |
||
161 | wchar_t *text_buffer; |
||
162 | char *cstring_buffer; |
||
163 | interlocutor_t *interlocutor; |
||
164 | onlineplayer_t *onlineplayer; |
||
165 | challenge_t *challenge; |
||
166 | player_t *remote_player; |
||
167 | player_t *local_player; |
||
168 | MINMAXINFO *minmax; |
||
169 | FLASHWINFO flashinfo; |
||
170 | RECT client_rect; |
||
171 | HWND hEditWnd; |
||
172 | int display_picture; |
||
173 | int player_index; |
||
174 | int char_index; |
||
175 | int length; |
||
176 | bool is_invitable; |
||
177 | |||
178 | // filter out the commonly used message values |
||
179 | wParam_hiword = HIWORD (wParam); |
||
180 | wParam_loword = LOWORD (wParam); |
||
181 | |||
182 | // have we just fired up this window ? |
||
183 | if (message == WM_CREATE) |
||
184 | { |
||
185 | // center the window |
||
186 | CenterWindow (hWnd, hMainWnd); |
||
187 | |||
188 | // populate the window |
||
189 | CreateWindowEx (0, L"static", L"", |
||
190 | WS_CHILD | WS_VISIBLE, |
||
191 | 0, 0, 0, 0, hWnd, (HMENU) WINDOW_TEXT_QUESTION, hAppInstance, NULL); |
||
192 | |||
193 | LoadLibrary (L"riched20.dll"); // ensure the RichEdit controls DLL is loaded |
||
194 | hEditWnd = CreateWindowEx (0, L"RichEdit20A", L"", // for some reason, only the ANSI version of this control accepts RTF data :( |
||
195 | WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | ES_SELECTIONBAR | ES_SUNKEN, |
||
196 | 0, 0, 0, 0, hWnd, (HMENU) WINDOW_EDITBOX_DISCUSSION, hAppInstance, NULL); |
||
197 | SendMessage (hEditWnd, EM_SETOLECALLBACK, 0, (LPARAM) richedit_oleinterface); |
||
198 | |||
199 | hEditWnd = CreateWindowEx (WS_EX_CLIENTEDGE, L"edit", L"", |
||
200 | WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL, |
||
201 | 0, 0, 0, 0, hWnd, (HMENU) WINDOW_EDITBOX_MESSAGETOSEND, hAppInstance, NULL); |
||
202 | WindowProc_MessageToSend_DefaultProc = (PROC) GetWindowLong (hEditWnd, GWL_WNDPROC); // save this edit box's window proc |
||
203 | SetWindowLong (hEditWnd, GWL_WNDPROC, (long) WindowProc_MessageToSend); // replace this edit box's window proc by ours |
||
204 | |||
205 | CreateWindowEx (0, L"static", L"", |
||
206 | WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_SUNKEN, |
||
207 | 0, 0, 0, 0, hWnd, (HMENU) WINDOW_BITMAP_OPPONENTSTATUS, hAppInstance, NULL); |
||
208 | CreateWindowEx (0, L"button", L"", |
||
209 | WS_CHILD | WS_VISIBLE | WS_DISABLED, // initially disabled |
||
210 | 0, 0, 0, 0, hWnd, (HMENU) WINDOW_BUTTON_INVITE, hAppInstance, NULL); |
||
211 | CreateWindowEx (0, L"button", L"", |
||
212 | WS_CHILD | WS_VISIBLE | WS_DISABLED, // initially disabled |
||
213 | 0, 0, 0, 0, hWnd, (HMENU) WINDOW_BUTTON_PLAYERINFO, hAppInstance, NULL); |
||
214 | CreateWindowEx (0, L"button", L"", |
||
215 | WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, |
||
216 | 0, 0, 0, 0, hWnd, (HMENU) WINDOW_BUTTON_SEND, hAppInstance, NULL); |
||
217 | CreateWindowEx (WS_EX_RIGHT, L"static", L"", |
||
218 | WS_CHILD | WS_VISIBLE, |
||
219 | 0, 0, 0, 0, hWnd, (HMENU) WINDOW_TEXT_STATUSBAR, hAppInstance, NULL); |
||
220 | |||
221 | // set the chat text font |
||
222 | SendMessage (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), WM_SETFONT, (WPARAM) hFontChat, false); |
||
223 | |||
224 | // associate the default GUI font with the leading caption |
||
225 | SendMessage (GetDlgItem (hWnd, WINDOW_TEXT_QUESTION), WM_SETFONT, (WPARAM) GetStockObject (DEFAULT_GUI_FONT), false); |
||
226 | |||
227 | // associate the default GUI font with the invite button and set its text |
||
228 | SendMessage (GetDlgItem (hWnd, WINDOW_BUTTON_INVITE), WM_SETFONT, (WPARAM) GetStockObject (DEFAULT_GUI_FONT), false); |
||
229 | SetDlgItemText (hWnd, WINDOW_BUTTON_INVITE, LOCALIZE (L"Chat_Invite")); |
||
230 | |||
231 | // associate the default GUI font with the player info button and set its text |
||
232 | SendMessage (GetDlgItem (hWnd, WINDOW_BUTTON_PLAYERINFO), WM_SETFONT, (WPARAM) GetStockObject (DEFAULT_GUI_FONT), false); |
||
233 | SetDlgItemText (hWnd, WINDOW_BUTTON_PLAYERINFO, LOCALIZE (L"Chat_GetInfo")); |
||
234 | |||
235 | // associate the default GUI font with the send button and set its text |
||
236 | SendMessage (GetDlgItem (hWnd, WINDOW_BUTTON_SEND), WM_SETFONT, (WPARAM) GetStockObject (DEFAULT_GUI_FONT), false); |
||
237 | SetDlgItemText (hWnd, WINDOW_BUTTON_SEND, LOCALIZE (L"Button_Send")); |
||
238 | |||
239 | // associate the default GUI font with the status bar and set its text |
||
240 | SendMessage (GetDlgItem (hWnd, WINDOW_TEXT_STATUSBAR), WM_SETFONT, (WPARAM) GetStockObject (DEFAULT_GUI_FONT), false); |
||
241 | SetDlgItemText (hWnd, WINDOW_TEXT_STATUSBAR, LOCALIZE (L"Chat_StatusBar")); |
||
242 | |||
243 | // refresh the server message area every second |
||
244 | SetTimer (hWnd, WINDOW_TIMER_REFRESH, 1000, NULL); |
||
245 | SendMessage (hWnd, WM_TIMER, WINDOW_TIMER_REFRESH, 0); // but call it now |
||
246 | |||
247 | // convert the status bar message to a hyperlink |
||
248 | ConvertStaticToHyperlink (GetDlgItem (hWnd, WINDOW_TEXT_STATUSBAR)); |
||
249 | |||
250 | // now show the window |
||
251 | ShowWindow (hWnd, SW_SHOW); |
||
252 | } |
||
253 | |||
254 | // else did we click the close button on the title bar ? |
||
255 | else if (message == WM_CLOSE) |
||
21 | pmbaty | 256 | DestroyWindow (hWnd); // close the window |
1 | pmbaty | 257 | |
258 | // else are we destroying this window ? |
||
259 | else if (message == WM_DESTROY) |
||
260 | { |
||
261 | KillTimer (hWnd, WINDOW_TIMER_REFRESH); // destroy the timer we used to refresh the dialog text |
||
262 | |||
263 | interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is |
||
264 | if (interlocutor != NULL) |
||
265 | interlocutor->is_active = false; // remember interlocutor has gone away |
||
266 | |||
267 | is_window_chat_validated = true; |
||
124 | pmbaty | 268 | the_board.reevaluate = true; // refresh the GUI buttons if needed |
1 | pmbaty | 269 | } |
270 | |||
271 | // else are we resizing the window ? |
||
272 | else if (message == WM_SIZE) |
||
273 | { |
||
274 | // get the new window size |
||
275 | GetClientRect (hWnd, &client_rect); |
||
276 | |||
277 | // position the window elements |
||
278 | SetWindowPos (GetDlgItem (hWnd, WINDOW_TEXT_QUESTION), NULL, 16, 16, client_rect.right - 148, 16, SWP_NOZORDER); |
||
279 | SetWindowPos (GetDlgItem (hWnd, WINDOW_EDITBOX_DISCUSSION), NULL, 16, 40, client_rect.right - 148, client_rect.bottom - 136, SWP_NOZORDER); |
||
280 | SetWindowPos (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), NULL, 16, client_rect.bottom - 80, client_rect.right - 148, 64, SWP_NOZORDER); |
||
281 | SetWindowPos (GetDlgItem (hWnd, WINDOW_BITMAP_OPPONENTSTATUS), NULL, client_rect.right - 116, 16, 100, 100, SWP_NOZORDER); |
||
282 | SetWindowPos (GetDlgItem (hWnd, WINDOW_BUTTON_INVITE), NULL, client_rect.right - 116, 124, 100, 32, SWP_NOZORDER); |
||
283 | SetWindowPos (GetDlgItem (hWnd, WINDOW_BUTTON_PLAYERINFO), NULL, client_rect.right - 116, 162, 100, 32, SWP_NOZORDER); |
||
284 | SetWindowPos (GetDlgItem (hWnd, WINDOW_BUTTON_SEND), NULL, client_rect.right - 116, client_rect.bottom - 80, 100, 64, SWP_NOZORDER); |
||
285 | SetWindowPos (GetDlgItem (hWnd, WINDOW_TEXT_STATUSBAR), NULL, 0, client_rect.bottom - 16, client_rect.right, 16, SWP_NOZORDER); |
||
286 | } |
||
287 | |||
288 | // else are we asking how big/small we can resize ? |
||
289 | else if (message == WM_GETMINMAXINFO) |
||
290 | { |
||
291 | minmax = (MINMAXINFO *) lParam; // get a pointer to the min/max info structure |
||
292 | |||
293 | minmax->ptMinTrackSize.x = WINDOW_MIN_WIDTH; |
||
294 | minmax->ptMinTrackSize.y = WINDOW_MIN_HEIGHT; |
||
295 | } |
||
296 | |||
297 | // else did we take action on one of the controls ? |
||
298 | else if (message == WM_COMMAND) |
||
299 | { |
||
300 | // was it the "invite" button ? |
||
301 | if (wParam_loword == WINDOW_BUTTON_INVITE) |
||
302 | { |
||
303 | interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is |
||
304 | if (interlocutor != NULL) |
||
305 | { |
||
306 | // player is available for an invitation. Is he already inviting us ? |
||
307 | challenge = Challenge_Find (interlocutor->nickname); |
||
308 | if ((challenge != NULL) && challenge->is_active && IsWindow (challenge->hWnd)) |
||
309 | EndDialog (challenge->hWnd, 0); // if so, close the challenge dialog box (this will also make us decline it properly) |
||
310 | |||
311 | DialogBox_SendChallenge (interlocutor->nickname); // fire up the dialog box |
||
312 | } |
||
313 | } |
||
314 | |||
315 | // else did we click the "get player info" button ? |
||
316 | else if (wParam_loword == WINDOW_BUTTON_PLAYERINFO) |
||
317 | { |
||
318 | interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is |
||
319 | if (interlocutor != NULL) |
||
320 | PlayerCard_FindOrCreate (interlocutor->nickname); // fire up the dialog box |
||
321 | } |
||
322 | |||
323 | // else was it the "send" button ? |
||
324 | else if (wParam_loword == WINDOW_BUTTON_SEND) |
||
325 | { |
||
326 | // grab the text to send from the edit box and empty the box |
||
327 | length = SendMessage (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), WM_GETTEXTLENGTH, 0, 0); // get text length |
||
328 | text_buffer = (wchar_t *) SAFE_malloc (length + 1, sizeof (wchar_t), false); // allocate space |
||
329 | GetDlgItemText (hWnd, WINDOW_EDITBOX_MESSAGETOSEND, text_buffer, length + 1); // copy text |
||
330 | |||
331 | // is there actually something to send ? |
||
332 | if (text_buffer[0] != 0) |
||
333 | { |
||
334 | // drop all accents by converting to 7-bit US-ASCII and then back to wide char |
||
335 | cstring_buffer = (char *) SAFE_malloc (2 * (length + 1), sizeof (char), false); |
||
336 | ConvertTo7BitASCII (cstring_buffer, 2 * (length + 1), text_buffer); |
||
337 | ConvertToWideChar (text_buffer, length + 1, cstring_buffer); |
||
338 | SAFE_free ((void **) &cstring_buffer); |
||
339 | |||
340 | // convert some dangerous characters |
||
341 | length = wcslen (text_buffer); |
||
342 | for (char_index = 0; char_index < length; char_index++) |
||
343 | if ((text_buffer[char_index] == L'\r') || (text_buffer[char_index] == L'\n')) |
||
344 | text_buffer[char_index] = L' '; |
||
345 | else if (text_buffer[char_index] == L'%') |
||
346 | text_buffer[char_index] = L'¤'; // percent signs are nasty for the varargs, so remove them |
||
347 | |||
348 | // find the local and the network players |
||
349 | if (((remote_player = Player_FindByType (PLAYER_INTERNET)) != NULL) |
||
350 | && ((local_player = Player_FindByType (PLAYER_HUMAN)) != NULL)) |
||
351 | { |
||
352 | interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is |
||
353 | if (interlocutor != NULL) |
||
354 | { |
||
355 | // fill the send buffer and append chat text to interlocutor's chat window |
||
356 | Player_SendBuffer_Add (remote_player, 1000, L"tell %s %s\n", interlocutor->nickname, text_buffer); |
||
357 | Interlocutor_Chat (interlocutor, local_player->name, true, text_buffer); |
||
358 | } |
||
359 | } |
||
360 | } |
||
361 | |||
362 | SetDlgItemText (hWnd, WINDOW_EDITBOX_MESSAGETOSEND, L""); // reset text in the window |
||
363 | SAFE_free ((void **) &text_buffer); // free the memory space we used |
||
364 | } |
||
365 | |||
366 | // else was it the status bar hyperlink ? |
||
367 | else if (wParam_loword == WINDOW_TEXT_STATUSBAR) |
||
368 | ShellExecute (NULL, L"open", PROGRAM_URL, NULL, NULL, SW_MAXIMIZE); // open the donation page in the default browser, maximized |
||
369 | } |
||
370 | |||
371 | // else is it a timer event AND is it our refresh timer ? |
||
372 | else if ((message == WM_TIMER) && (wParam == WINDOW_TIMER_REFRESH)) |
||
373 | { |
||
374 | interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is |
||
375 | if (interlocutor != NULL) |
||
376 | { |
||
377 | // find interlocutor in online players list |
||
378 | for (player_index = 0; player_index < onlineplayer_count; player_index++) |
||
379 | if (wcscmp (interlocutor->nickname, onlineplayers[player_index].nickname) == 0) |
||
380 | break; // break as soon as we find it |
||
381 | |||
382 | // have we found it ? |
||
383 | if (player_index < onlineplayer_count) |
||
384 | { |
||
385 | onlineplayer = &onlineplayers[player_index]; // quick access to online player |
||
386 | remote_player = Player_FindByType (PLAYER_INTERNET); // find the remote player |
||
387 | |||
388 | // is this talkee our opponent AND are we playing a game AND does its status not reflect it yet ? |
||
389 | if ((remote_player != NULL) && remote_player->is_in_game |
||
390 | && (wcscmp (onlineplayer->nickname, remote_player->name) == 0) |
||
391 | && ((onlineplayer->handlestatus == HANDLESTATUS_UNDEFINED) |
||
392 | || (onlineplayer->handlestatus == HANDLESTATUS_AVAILABLE) |
||
393 | || (onlineplayer->handlestatus == HANDLESTATUS_EXAMININGAGAME) |
||
394 | || (onlineplayer->handlestatus == HANDLESTATUS_NOTOPENFORAMATCH) |
||
395 | || (onlineplayer->handlestatus == HANDLESTATUS_INACTIVEORBUSY))) |
||
396 | onlineplayer->handlestatus = HANDLESTATUS_INGAME; // if so, remember we're playing against it |
||
397 | |||
398 | display_picture = onlineplayer->handlestatus; // if so, use its current status |
||
399 | } |
||
400 | else |
||
401 | display_picture = HANDLESTATUS_OFFLINE; // else flag it as offline |
||
402 | |||
403 | // do we need to change its status ? |
||
404 | if (display_picture != interlocutor->current_displaypicture) |
||
405 | { |
||
406 | // set window icons (small one for title bar & big one for task manager) and avatar |
||
407 | SendMessage (hWnd, WM_SETICON, ICON_SMALL, (LPARAM) handlestatus[display_picture].icon); |
||
408 | SendMessage (hWnd, WM_SETICON, ICON_BIG, (LPARAM) handlestatus[display_picture].icon); |
||
409 | SendMessage (GetDlgItem (hWnd, WINDOW_BITMAP_OPPONENTSTATUS), STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) handlestatus[display_picture].bitmap); |
||
410 | |||
411 | // set window text |
||
412 | swprintf_s (temp_string, WCHAR_SIZEOF (temp_string), L"%s (%s)", interlocutor->nickname, handlestatus[display_picture].text); |
||
413 | SetWindowText (hWnd, temp_string); // set window title |
||
414 | |||
415 | // set window title and parameters |
||
416 | if (display_picture == HANDLESTATUS_OFFLINE) |
||
417 | { |
||
418 | EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_PLAYERINFO), false); // if so, disable buttons |
||
419 | EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_INVITE), false); |
||
420 | EnableWindow (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), false); |
||
421 | EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_SEND), false); |
||
422 | } |
||
423 | else |
||
424 | { |
||
425 | if ((display_picture == HANDLESTATUS_OFFLINE) || (display_picture == HANDLESTATUS_INGAME) || (display_picture == HANDLESTATUS_NOTOPENFORAMATCH)) |
||
426 | is_invitable = false; // this player is NOT invitable |
||
427 | else |
||
428 | is_invitable = true; // all other players are invitable |
||
429 | |||
430 | EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_PLAYERINFO), true); // else enable them |
||
431 | EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_INVITE), is_invitable); |
||
432 | EnableWindow (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), true); |
||
433 | EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_SEND), true); |
||
434 | |||
435 | if (GetForegroundWindow () == hWnd) |
||
436 | SetFocus (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND)); // set keyboard focus to the message editbox |
||
437 | } |
||
438 | |||
439 | interlocutor->current_displaypicture = display_picture; // remember we've done it |
||
440 | } |
||
441 | |||
442 | // do we need to update dialog ? |
||
443 | if (interlocutor->update_dialog) |
||
444 | { |
||
445 | // set the leading caption |
||
446 | swprintf_s (temp_string, WCHAR_SIZEOF (temp_string), LOCALIZE (L"Chat_Question"), interlocutor->nickname); |
||
447 | SetDlgItemText (hWnd, WINDOW_TEXT_QUESTION, temp_string); |
||
448 | |||
449 | // set discussion text and scroll the edit box down |
||
450 | hEditWnd = GetDlgItem (hWnd, WINDOW_EDITBOX_DISCUSSION); |
||
451 | SetWindowText (hEditWnd, interlocutor->dialogtext); |
||
452 | length = GetWindowTextLength (hEditWnd); |
||
453 | //SetFocus (hEditWnd); |
||
454 | Edit_SetSel (hEditWnd, length, length); |
||
455 | Edit_ScrollCaret (hEditWnd); |
||
456 | SetFocus (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND)); |
||
457 | |||
458 | // if we are not the top level window, flash window |
||
459 | if (GetForegroundWindow () != hWnd) |
||
460 | { |
||
461 | memset (&flashinfo, 0, sizeof (flashinfo)); |
||
462 | flashinfo.cbSize = sizeof (flashinfo); |
||
463 | flashinfo.hwnd = hWnd; |
||
464 | flashinfo.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG; // flash until we bring window to foreground |
||
465 | FlashWindowEx (&flashinfo); |
||
466 | } |
||
467 | |||
468 | interlocutor->update_dialog = false; // remember we refreshed dialog text |
||
469 | } |
||
470 | } |
||
471 | } |
||
472 | |||
473 | // call the default dialog message processing function to keep things going |
||
474 | return (DefWindowProc (hWnd, message, wParam, lParam)); |
||
475 | } |
||
476 | |||
477 | |||
478 | static LRESULT CALLBACK WindowProc_MessageToSend (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam) |
||
479 | { |
||
480 | // this is the callback function for the edit box control where the user types its message |
||
481 | |||
482 | // was the enter key pressed ? |
||
483 | if ((message == WM_CHAR) && (wParam == VK_RETURN)) |
||
484 | { |
||
485 | SendMessage (GetParent (hWnd), WM_COMMAND, WINDOW_BUTTON_SEND, 0); // if so, forward it to our parent |
||
486 | return (true); // and prevent this keystroke from being treated |
||
487 | } |
||
488 | |||
489 | // for all other messages, call the default window message processing function |
||
490 | return ((LRESULT) CallWindowProc ((WNDPROC) WindowProc_MessageToSend_DefaultProc, hWnd, message, wParam, lParam)); |
||
491 | } |