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 | } |