Subversion Repositories Games.Chess Giants

Rev

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
}