Subversion Repositories Games.Chess Giants

Rev

Rev 1 | Go to most recent revision | 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;
268
   }
269
 
270
   // else are we resizing the window ?
271
   else if (message == WM_SIZE)
272
   {
273
      // get the new window size
274
      GetClientRect (hWnd, &client_rect);
275
 
276
      // position the window elements
277
      SetWindowPos (GetDlgItem (hWnd, WINDOW_TEXT_QUESTION), NULL, 16, 16, client_rect.right - 148, 16, SWP_NOZORDER);
278
      SetWindowPos (GetDlgItem (hWnd, WINDOW_EDITBOX_DISCUSSION), NULL, 16, 40, client_rect.right - 148, client_rect.bottom - 136, SWP_NOZORDER);
279
      SetWindowPos (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), NULL, 16, client_rect.bottom - 80, client_rect.right - 148, 64, SWP_NOZORDER);
280
      SetWindowPos (GetDlgItem (hWnd, WINDOW_BITMAP_OPPONENTSTATUS), NULL, client_rect.right - 116, 16, 100, 100, SWP_NOZORDER);
281
      SetWindowPos (GetDlgItem (hWnd, WINDOW_BUTTON_INVITE), NULL, client_rect.right - 116, 124, 100, 32, SWP_NOZORDER);
282
      SetWindowPos (GetDlgItem (hWnd, WINDOW_BUTTON_PLAYERINFO), NULL, client_rect.right - 116, 162, 100, 32, SWP_NOZORDER);
283
      SetWindowPos (GetDlgItem (hWnd, WINDOW_BUTTON_SEND), NULL, client_rect.right - 116, client_rect.bottom - 80, 100, 64, SWP_NOZORDER);
284
      SetWindowPos (GetDlgItem (hWnd, WINDOW_TEXT_STATUSBAR), NULL, 0, client_rect.bottom - 16, client_rect.right, 16, SWP_NOZORDER);
285
   }
286
 
287
   // else are we asking how big/small we can resize ?
288
   else if (message == WM_GETMINMAXINFO)
289
   {
290
      minmax = (MINMAXINFO *) lParam; // get a pointer to the min/max info structure
291
 
292
      minmax->ptMinTrackSize.x = WINDOW_MIN_WIDTH;
293
      minmax->ptMinTrackSize.y = WINDOW_MIN_HEIGHT;
294
   }
295
 
296
   // else did we take action on one of the controls ?
297
   else if (message == WM_COMMAND)
298
   {
299
      // was it the "invite" button ?
300
      if (wParam_loword == WINDOW_BUTTON_INVITE)
301
      {
302
         interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is
303
         if (interlocutor != NULL)
304
         {
305
            // player is available for an invitation. Is he already inviting us ?
306
            challenge = Challenge_Find (interlocutor->nickname);
307
            if ((challenge != NULL) && challenge->is_active && IsWindow (challenge->hWnd))
308
               EndDialog (challenge->hWnd, 0); // if so, close the challenge dialog box (this will also make us decline it properly)
309
 
310
            DialogBox_SendChallenge (interlocutor->nickname); // fire up the dialog box
311
         }
312
      }
313
 
314
      // else did we click the "get player info" button ?
315
      else if (wParam_loword == WINDOW_BUTTON_PLAYERINFO)
316
      {
317
         interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is
318
         if (interlocutor != NULL)
319
            PlayerCard_FindOrCreate (interlocutor->nickname); // fire up the dialog box
320
      }
321
 
322
      // else was it the "send" button ?
323
      else if (wParam_loword == WINDOW_BUTTON_SEND)
324
      {
325
         // grab the text to send from the edit box and empty the box
326
         length = SendMessage (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), WM_GETTEXTLENGTH, 0, 0); // get text length
327
         text_buffer = (wchar_t *) SAFE_malloc (length + 1, sizeof (wchar_t), false); // allocate space
328
         GetDlgItemText (hWnd, WINDOW_EDITBOX_MESSAGETOSEND, text_buffer, length + 1); // copy text
329
 
330
         // is there actually something to send ?
331
         if (text_buffer[0] != 0)
332
         {
333
            // drop all accents by converting to 7-bit US-ASCII and then back to wide char
334
            cstring_buffer = (char *) SAFE_malloc (2 * (length + 1), sizeof (char), false);
335
            ConvertTo7BitASCII (cstring_buffer, 2 * (length + 1), text_buffer);
336
            ConvertToWideChar (text_buffer, length + 1, cstring_buffer);
337
            SAFE_free ((void **) &cstring_buffer);
338
 
339
            // convert some dangerous characters
340
            length = wcslen (text_buffer);
341
            for (char_index = 0; char_index < length; char_index++)
342
               if ((text_buffer[char_index] == L'\r') || (text_buffer[char_index] == L'\n'))
343
                  text_buffer[char_index] = L' ';
344
               else if (text_buffer[char_index] == L'%')
345
                  text_buffer[char_index] = L'¤'; // percent signs are nasty for the varargs, so remove them
346
 
347
            // find the local and the network players
348
            if (((remote_player = Player_FindByType (PLAYER_INTERNET)) != NULL)
349
                && ((local_player = Player_FindByType (PLAYER_HUMAN)) != NULL))
350
            {
351
               interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is
352
               if (interlocutor != NULL)
353
               {
354
                  // fill the send buffer and append chat text to interlocutor's chat window
355
                  Player_SendBuffer_Add (remote_player, 1000, L"tell %s %s\n", interlocutor->nickname, text_buffer);
356
                  Interlocutor_Chat (interlocutor, local_player->name, true, text_buffer);
357
               }
358
            }
359
         }
360
 
361
         SetDlgItemText (hWnd, WINDOW_EDITBOX_MESSAGETOSEND, L""); // reset text in the window
362
         SAFE_free ((void **) &text_buffer); // free the memory space we used
363
      }
364
 
365
      // else was it the status bar hyperlink ?
366
      else if (wParam_loword == WINDOW_TEXT_STATUSBAR)
367
         ShellExecute (NULL, L"open", PROGRAM_URL, NULL, NULL, SW_MAXIMIZE); // open the donation page in the default browser, maximized
368
   }
369
 
370
   // else is it a timer event AND is it our refresh timer ?
371
   else if ((message == WM_TIMER) && (wParam == WINDOW_TIMER_REFRESH))
372
   {
373
      interlocutor = Interlocutor_FindByWindowHandle (hWnd); // find the interlocutor it is
374
      if (interlocutor != NULL)
375
      {
376
         // find interlocutor in online players list
377
         for (player_index = 0; player_index < onlineplayer_count; player_index++)
378
            if (wcscmp (interlocutor->nickname, onlineplayers[player_index].nickname) == 0)
379
               break; // break as soon as we find it
380
 
381
         // have we found it ?
382
         if (player_index < onlineplayer_count)
383
         {
384
            onlineplayer = &onlineplayers[player_index]; // quick access to online player
385
            remote_player = Player_FindByType (PLAYER_INTERNET); // find the remote player
386
 
387
            // is this talkee our opponent AND are we playing a game AND does its status not reflect it yet ?
388
            if ((remote_player != NULL) && remote_player->is_in_game
389
                && (wcscmp (onlineplayer->nickname, remote_player->name) == 0)
390
                && ((onlineplayer->handlestatus == HANDLESTATUS_UNDEFINED)
391
                    || (onlineplayer->handlestatus == HANDLESTATUS_AVAILABLE)
392
                    || (onlineplayer->handlestatus == HANDLESTATUS_EXAMININGAGAME)
393
                    || (onlineplayer->handlestatus == HANDLESTATUS_NOTOPENFORAMATCH)
394
                    || (onlineplayer->handlestatus == HANDLESTATUS_INACTIVEORBUSY)))
395
               onlineplayer->handlestatus = HANDLESTATUS_INGAME; // if so, remember we're playing against it
396
 
397
            display_picture = onlineplayer->handlestatus; // if so, use its current status
398
         }
399
         else
400
            display_picture = HANDLESTATUS_OFFLINE; // else flag it as offline
401
 
402
         // do we need to change its status ?
403
         if (display_picture != interlocutor->current_displaypicture)
404
         {
405
            // set window icons (small one for title bar & big one for task manager) and avatar
406
            SendMessage (hWnd, WM_SETICON, ICON_SMALL, (LPARAM) handlestatus[display_picture].icon);
407
            SendMessage (hWnd, WM_SETICON, ICON_BIG, (LPARAM) handlestatus[display_picture].icon);
408
            SendMessage (GetDlgItem (hWnd, WINDOW_BITMAP_OPPONENTSTATUS), STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) handlestatus[display_picture].bitmap);
409
 
410
            // set window text
411
            swprintf_s (temp_string, WCHAR_SIZEOF (temp_string), L"%s (%s)", interlocutor->nickname, handlestatus[display_picture].text);
412
            SetWindowText (hWnd, temp_string); // set window title
413
 
414
            // set window title and parameters
415
            if (display_picture == HANDLESTATUS_OFFLINE)
416
            {
417
               EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_PLAYERINFO), false); // if so, disable buttons
418
               EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_INVITE), false);
419
               EnableWindow (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), false);
420
               EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_SEND), false);
421
            }
422
            else
423
            {
424
               if ((display_picture == HANDLESTATUS_OFFLINE) || (display_picture == HANDLESTATUS_INGAME) || (display_picture == HANDLESTATUS_NOTOPENFORAMATCH))
425
                  is_invitable = false; // this player is NOT invitable
426
               else
427
                  is_invitable = true; // all other players are invitable
428
 
429
               EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_PLAYERINFO), true); // else enable them
430
               EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_INVITE), is_invitable);
431
               EnableWindow (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND), true);
432
               EnableWindow (GetDlgItem (hWnd, WINDOW_BUTTON_SEND), true);
433
 
434
               if (GetForegroundWindow () == hWnd)
435
                  SetFocus (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND)); // set keyboard focus to the message editbox
436
            }
437
 
438
            interlocutor->current_displaypicture = display_picture; // remember we've done it
439
         }
440
 
441
         // do we need to update dialog ?
442
         if (interlocutor->update_dialog)
443
         {
444
            // set the leading caption
445
            swprintf_s (temp_string, WCHAR_SIZEOF (temp_string), LOCALIZE (L"Chat_Question"), interlocutor->nickname);
446
            SetDlgItemText (hWnd, WINDOW_TEXT_QUESTION, temp_string);
447
 
448
            // set discussion text and scroll the edit box down
449
            hEditWnd = GetDlgItem (hWnd, WINDOW_EDITBOX_DISCUSSION);
450
            SetWindowText (hEditWnd, interlocutor->dialogtext);
451
            length = GetWindowTextLength (hEditWnd);
452
            //SetFocus (hEditWnd);
453
            Edit_SetSel (hEditWnd, length, length);
454
            Edit_ScrollCaret (hEditWnd);
455
            SetFocus (GetDlgItem (hWnd, WINDOW_EDITBOX_MESSAGETOSEND));
456
 
457
            // if we are not the top level window, flash window
458
            if (GetForegroundWindow () != hWnd)
459
            {
460
               memset (&flashinfo, 0, sizeof (flashinfo));
461
               flashinfo.cbSize = sizeof (flashinfo);
462
               flashinfo.hwnd = hWnd;
463
               flashinfo.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG; // flash until we bring window to foreground
464
               FlashWindowEx (&flashinfo);
465
            }
466
 
467
            interlocutor->update_dialog = false; // remember we refreshed dialog text
468
         }
469
      }
470
   }
471
 
472
   // call the default dialog message processing function to keep things going
473
   return (DefWindowProc (hWnd, message, wParam, lParam));
474
}
475
 
476
 
477
static LRESULT CALLBACK WindowProc_MessageToSend (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam)
478
{
479
   // this is the callback function for the edit box control where the user types its message
480
 
481
   // was the enter key pressed ?
482
   if ((message == WM_CHAR) && (wParam == VK_RETURN))
483
   {
484
      SendMessage (GetParent (hWnd), WM_COMMAND, WINDOW_BUTTON_SEND, 0); // if so, forward it to our parent
485
      return (true); // and prevent this keystroke from being treated
486
   }
487
 
488
   // for all other messages, call the default window message processing function
489
   return ((LRESULT) CallWindowProc ((WNDPROC) WindowProc_MessageToSend_DefaultProc, hWnd, message, wParam, lParam));
490
}