startwin.game.cpp
1 //------------------------------------------------------------------------- 2 /* 3 Copyright (C) 2010-2019 EDuke32 developers and contributors 4 Copyright (C) 2019 Nuke.YKT 5 6 This file is part of NBlood. 7 8 NBlood is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License version 2 10 as published by the Free Software Foundation. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 16 See the GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 */ 22 //------------------------------------------------------------------------- 23 24 #ifndef _WIN32 25 #error Only for Windows 26 #endif 27 28 #include "renderlayer.h" 29 30 #ifdef STARTUP_SETUP_WINDOW 31 32 #define NEED_WINDOWSX_H 33 #define NEED_COMMCTRL_H 34 #define ONLY_USERDEFS 35 36 #include "_control.h" 37 #include "build.h" 38 #include "cache1d.h" 39 //#include "cmdline.h" 40 #include "common_game.h" 41 #include "compat.h" 42 #include "control.h" 43 #include "config.h" 44 //#include "function.h" 45 //#include "game.h" 46 //#include "grpscan.h" 47 //#include "inv.h" 48 #include "blood.h" 49 #include "globals.h" 50 #include "keyboard.h" 51 #include "startwin.game.h" 52 #include "windows_inc.h" 53 54 #define TAB_CONFIG 0 55 #define TAB_MESSAGES 1 56 57 static struct 58 { 59 INICHAIN const * ini; 60 char *gamedir; 61 ud_setup_t shared; 62 int polymer; 63 } 64 settings; 65 66 static HWND startupdlg; 67 static HWND pages[3]; 68 static int done = -1; 69 static int mode = TAB_CONFIG; 70 71 static BUILDVFS_FIND_REC *finddirs; 72 73 static inline void clearfilenames(void) 74 { 75 klistfree(finddirs); 76 finddirs = NULL; 77 } 78 79 static inline void getfilenames(char const *path) 80 { 81 clearfilenames(); 82 finddirs = klistpath(path,"*",BUILDVFS_FIND_DIR); 83 } 84 85 #define POPULATE_VIDEO 1 86 #define POPULATE_CONFIG 2 87 #define POPULATE_GAME 4 88 #define POPULATE_GAMEDIRS 8 89 90 #ifdef INPUT_MOUSE 91 #undef INPUT_MOUSE 92 #endif 93 94 #define INPUT_KB 0 95 #define INPUT_MOUSE 1 96 #define INPUT_JOYSTICK 2 97 #define INPUT_ALL 3 98 99 const char *controlstrings[] = { "Keyboard only", "Keyboard and mouse", "Keyboard and joystick", "All supported devices" }; 100 101 static void PopulateForm(int32_t pgs) 102 { 103 char buf[512]; 104 105 if (pgs & POPULATE_GAMEDIRS) 106 { 107 HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCGAMEDIR); 108 109 getfilenames("/"); 110 (void)ComboBox_ResetContent(hwnd); 111 int const r = ComboBox_AddString(hwnd, "None"); 112 (void)ComboBox_SetItemData(hwnd, r, 0); 113 (void)ComboBox_SetCurSel(hwnd, r); 114 auto dirs = finddirs; 115 for (int i=1, j=1; dirs != NULL; dirs=dirs->next) 116 { 117 if (Bstrcasecmp(dirs->name, "autoload") == 0) 118 { 119 j++; 120 continue; 121 } 122 123 (void)ComboBox_AddString(hwnd, dirs->name); 124 (void)ComboBox_SetItemData(hwnd, i, j); 125 if (Bstrcasecmp(dirs->name, settings.gamedir) == 0) 126 (void)ComboBox_SetCurSel(hwnd, i); 127 128 i++; 129 j++; 130 } 131 } 132 133 if (pgs & POPULATE_VIDEO) 134 { 135 HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCVMODE); 136 int mode = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, settings.shared.bpp, settings.shared.fullscreen, 1); 137 138 if (mode < 0 || (settings.shared.bpp < 15 && (settings.polymer))) 139 { 140 int CONSTEXPR cd[] = { 32, 24, 16, 15, 8, 0 }; 141 int i; 142 143 for (i=0; cd[i];) 144 { 145 if (cd[i] >= settings.shared.bpp) i++; 146 else break; 147 } 148 for (; cd[i]; i++) 149 { 150 mode = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, cd[i], settings.shared.fullscreen, 1); 151 if (mode < 0) continue; 152 settings.shared.bpp = cd[i]; 153 break; 154 } 155 } 156 157 Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCFULLSCREEN), ((settings.shared.fullscreen) ? BST_CHECKED : BST_UNCHECKED)); 158 //Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCPOLYMER), ((settings.polymer) ? BST_CHECKED : BST_UNCHECKED)); 159 160 (void)ComboBox_ResetContent(hwnd); 161 162 for (int i=0; i<validmodecnt; i++) 163 { 164 if (validmode[i].fs != (settings.shared.fullscreen)) continue; 165 if ((validmode[i].bpp < 15) && (settings.polymer)) continue; 166 167 // all modes get added to the 3D mode list 168 Bsprintf(buf, "%dx%d %s", validmode[i].xdim, validmode[i].ydim, validmode[i].bpp == 8 ? "software" : "OpenGL"); 169 int const j = ComboBox_AddString(hwnd, buf); 170 (void)ComboBox_SetItemData(hwnd, j, i); 171 if (i == mode)(void)ComboBox_SetCurSel(hwnd, j); 172 } 173 } 174 175 if (pgs & POPULATE_CONFIG) 176 { 177 Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCALWAYSSHOW), (settings.shared.forcesetup ? BST_CHECKED : BST_UNCHECKED)); 178 Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCAUTOLOAD), (!(settings.shared.noautoload) ? BST_CHECKED : BST_UNCHECKED)); 179 Button_SetCheck(GetDlgItem(pages[TAB_CONFIG], IDCQUICKSTART), ((settings.shared.quickstart) ? BST_CHECKED : BST_UNCHECKED)); 180 181 HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCINPUT); 182 183 (void)ComboBox_ResetContent(hwnd); 184 (void)ComboBox_SetCurSel(hwnd, 0); 185 186 int j = 4; 187 188 for (int i=0; i<j; i++) 189 { 190 (void)ComboBox_InsertString(hwnd, i, controlstrings[i]); 191 (void)ComboBox_SetItemData(hwnd, i, i); 192 193 switch (i) 194 { 195 case INPUT_MOUSE: 196 if (settings.shared.usemouse && !settings.shared.usejoystick)(void)ComboBox_SetCurSel(hwnd, i); 197 break; 198 case INPUT_JOYSTICK: 199 if (!settings.shared.usemouse && settings.shared.usejoystick)(void)ComboBox_SetCurSel(hwnd, i); 200 break; 201 case INPUT_ALL: 202 if (settings.shared.usemouse && settings.shared.usejoystick)(void)ComboBox_SetCurSel(hwnd, i); 203 break; 204 } 205 } 206 } 207 208 if (pgs & POPULATE_GAME) 209 { 210 HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCDATA); 211 212 for (auto fg = pINIChain; fg; fg=fg->pNext) 213 { 214 if (fg->pDescription) 215 Bsprintf(buf, "%s\t%s", fg->pDescription->pzName, fg->zName); 216 else 217 Bsprintf(buf, "%s", fg->zName); 218 int const j = ListBox_AddString(hwnd, buf); 219 (void)ListBox_SetItemData(hwnd, j, (LPARAM)fg); 220 if (settings.ini == fg) 221 (void)ListBox_SetCurSel(hwnd, j); 222 } 223 } 224 } 225 226 static INT_PTR CALLBACK ConfigPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 227 { 228 switch (uMsg) 229 { 230 case WM_COMMAND: 231 switch (LOWORD(wParam)) 232 { 233 case IDCFULLSCREEN: 234 settings.shared.fullscreen = !settings.shared.fullscreen; 235 PopulateForm(POPULATE_VIDEO); 236 return TRUE; 237 //case IDCPOLYMER: 238 // settings.polymer = !settings.polymer; 239 // if (settings.shared.bpp == 8) settings.shared.bpp = 32; 240 // PopulateForm(POPULATE_VIDEO); 241 // return TRUE; 242 case IDCVMODE: 243 if (HIWORD(wParam) == CBN_SELCHANGE) 244 { 245 int i = ComboBox_GetCurSel((HWND)lParam); 246 if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i); 247 if (i != CB_ERR) 248 { 249 settings.shared.xdim = validmode[i].xdim; 250 settings.shared.ydim = validmode[i].ydim; 251 settings.shared.bpp = validmode[i].bpp; 252 } 253 } 254 return TRUE; 255 case IDCALWAYSSHOW: 256 settings.shared.forcesetup = IsDlgButtonChecked(hwndDlg, IDCALWAYSSHOW) == BST_CHECKED; 257 return TRUE; 258 case IDCAUTOLOAD: 259 settings.shared.noautoload = (IsDlgButtonChecked(hwndDlg, IDCAUTOLOAD) != BST_CHECKED); 260 return TRUE; 261 case IDCQUICKSTART: 262 settings.shared.quickstart = (IsDlgButtonChecked(hwndDlg, IDCQUICKSTART) == BST_CHECKED); 263 return TRUE; 264 case IDCINPUT: 265 if (HIWORD(wParam) == CBN_SELCHANGE) 266 { 267 int i = ComboBox_GetCurSel((HWND)lParam); 268 if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i); 269 if (i != CB_ERR) 270 { 271 switch (i) 272 { 273 case INPUT_KB: 274 settings.shared.usemouse = settings.shared.usejoystick = 0; 275 break; 276 case INPUT_MOUSE: 277 settings.shared.usemouse = 1; 278 settings.shared.usejoystick = 0; 279 break; 280 case INPUT_JOYSTICK: 281 settings.shared.usemouse = 0; 282 settings.shared.usejoystick = 1; 283 break; 284 case INPUT_ALL: 285 settings.shared.usemouse = settings.shared.usejoystick = 1; 286 break; 287 } 288 } 289 } 290 return TRUE; 291 292 case IDCGAMEDIR: 293 if (HIWORD(wParam) == CBN_SELCHANGE) 294 { 295 int i = ComboBox_GetCurSel((HWND)lParam); 296 if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i); 297 if (i != CB_ERR) 298 { 299 if (i==0) 300 settings.gamedir = NULL; 301 else 302 { 303 BUILDVFS_FIND_REC *dir = finddirs; 304 for (int j = 1; dir != NULL; dir = dir->next, j++) 305 { 306 if (j == i) 307 { 308 settings.gamedir = dir->name; 309 break; 310 } 311 } 312 } 313 } 314 } 315 return TRUE; 316 case IDCDATA: 317 { 318 if (HIWORD(wParam) != LBN_SELCHANGE) break; 319 intptr_t i = ListBox_GetCurSel((HWND)lParam); 320 if (i != CB_ERR) i = ListBox_GetItemData((HWND)lParam, i); 321 if (i != CB_ERR) 322 { 323 settings.ini = (INICHAIN const *)i; 324 325 char szPickedIni[BMAX_PATH] = ""; 326 for (i = 0; (settings.ini->zName[i] != '.') && (settings.ini->zName[i] != '\0'); i++) 327 szPickedIni[i] = settings.ini->zName[i]; 328 if (szPickedIni[0] != '\0') 329 { 330 HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCGAMEDIR); 331 i = ComboBox_SelectString(hwnd, 0, (LPSTR)szPickedIni); 332 if (i == CB_ERR) // could not find potential mod folder, reset back to none 333 { 334 settings.gamedir = NULL; 335 (void)ComboBox_SetCurSel(hwnd, 0); 336 } 337 else 338 { 339 i = ComboBox_GetItemData(hwnd, i); 340 BUILDVFS_FIND_REC *dir = finddirs; 341 for (int j = 1; dir != NULL; dir = dir->next, j++) 342 { 343 if (j == i) 344 { 345 settings.gamedir = dir->name; 346 break; 347 } 348 } 349 } 350 } 351 } 352 return TRUE; 353 } 354 default: 355 break; 356 } 357 break; 358 default: 359 break; 360 } 361 return FALSE; 362 } 363 364 365 static void SetPage(int pageNum) 366 { 367 HWND tab = GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL); 368 auto const cur = SendMessage(tab, TCM_GETCURSEL, 0, 0); 369 ShowWindow(pages[cur], SW_HIDE); 370 SendMessage(tab, TCM_SETCURSEL, pageNum, 0); 371 ShowWindow(pages[pageNum], SW_SHOW); 372 mode = pageNum; 373 374 SetFocus(GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL)); 375 } 376 377 static void EnableConfig(bool n) 378 { 379 #ifndef NETCODE_DISABLE 380 EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_UPDATE), n); 381 #else 382 ShowWindow(GetDlgItem(startupdlg, WIN_STARTWIN_UPDATE), SW_HIDE); 383 #endif 384 //EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_CANCEL), n); 385 EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_START), n); 386 EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCDATA), n); 387 EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCFULLSCREEN), n); 388 EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCGAMEDIR), n); 389 EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCINPUT), n); 390 //EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCPOLYMER), n); 391 EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCQUICKSTART), n); 392 EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCVMODE), n); 393 } 394 395 #ifndef NETCODE_DISABLE 396 bool ExecUpdater(void) 397 { 398 STARTUPINFO si; 399 PROCESS_INFORMATION pi; 400 char szRootDir[BMAX_PATH], szUpdaterPath[BMAX_PATH]; 401 402 ZeroMemory(&si,sizeof(si)); 403 ZeroMemory(&pi,sizeof(pi)); 404 si.cb = sizeof(si); 405 si.dwFlags = STARTF_USESHOWWINDOW; 406 si.wShowWindow = SW_HIDE; 407 408 GetModuleFileName(NULL,szRootDir,BMAX_PATH); 409 Bcorrectfilename(szRootDir,1); 410 Bstrcpy(szUpdaterPath, szRootDir); 411 Bstrcat(szUpdaterPath,"notbloodupdate.exe -RestartIfSuccessful"); 412 413 if (!CreateProcessA(nullptr,(LPSTR)szUpdaterPath,nullptr,nullptr,FALSE,CREATE_NO_WINDOW,nullptr,szRootDir,&si,&pi)) 414 { 415 MessageBox(win_gethwnd(),"Error, could not launch notbloodupdate.exe\n\nPlease reinstall your copy of NotBlood.","Error",MB_OK|MB_ICONERROR); 416 return false; 417 } 418 return true; 419 } 420 #endif 421 422 static INT_PTR CALLBACK startup_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 423 { 424 static HBITMAP hbmp = NULL; 425 426 switch (uMsg) 427 { 428 case WM_INITDIALOG: 429 { 430 // Fetch the positions (in screen coordinates) of all the windows we need to tweak 431 RECT chrome = {}; 432 AdjustWindowRect(&chrome, GetWindowLong(hwndDlg, GWL_STYLE), FALSE); 433 RECT rdlg; 434 GetWindowRect(hwndDlg, &rdlg); 435 436 // Knock off the non-client area of the main dialogue to give just the client area 437 rdlg.left -= chrome.left; 438 rdlg.top -= chrome.top; 439 rdlg.right -= chrome.right; 440 rdlg.bottom -= chrome.bottom; 441 442 RECT rtab; 443 GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL), &rtab); 444 445 // Translate them to client-relative coordinates wrt the main dialogue window 446 rtab.right -= rtab.left - 1; 447 rtab.bottom -= rtab.top - 1; 448 rtab.left -= rdlg.left; 449 rtab.top -= rdlg.top; 450 451 RECT rupdate; 452 GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_UPDATE), &rupdate); 453 454 rupdate.right -= rupdate.left - 1; 455 rupdate.bottom -= rupdate.top - 1; 456 rupdate.left -= rdlg.left; 457 rupdate.top -= rdlg.top; 458 459 RECT rcancel; 460 GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_CANCEL), &rcancel); 461 462 rcancel.right -= rcancel.left - 1; 463 rcancel.bottom -= rcancel.top - 1; 464 rcancel.left -= rdlg.left; 465 rcancel.top -= rdlg.top; 466 467 RECT rstart; 468 GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_START), &rstart); 469 470 rstart.right -= rstart.left - 1; 471 rstart.bottom -= rstart.top - 1; 472 rstart.left -= rdlg.left; 473 rstart.top -= rdlg.top; 474 475 // And then convert the main dialogue coordinates to just width/length 476 rdlg.right -= rdlg.left - 1; 477 rdlg.bottom -= rdlg.top - 1; 478 rdlg.left = 0; 479 rdlg.top = 0; 480 481 // Load the bitmap into the bitmap control and fetch its dimensions 482 hbmp = LoadBitmap((HINSTANCE)win_gethinstance(), MAKEINTRESOURCE(RSRC_BMP)); 483 484 HWND hwnd = GetDlgItem(hwndDlg, WIN_STARTWIN_BITMAP); 485 SendMessage(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp); 486 487 RECT r; 488 GetClientRect(hwnd, &r); 489 490 int const xoffset = r.right; 491 int const yoffset = r.bottom - rdlg.bottom; 492 493 // Shift and resize the controls that require it 494 rtab.left += xoffset; 495 rtab.bottom += yoffset; 496 rupdate.left = r.right-r.left+7; 497 rupdate.top += yoffset; 498 rcancel.left += xoffset; 499 rcancel.top += yoffset; 500 rstart.left += xoffset; 501 rstart.top += yoffset; 502 rdlg.right += xoffset; 503 rdlg.bottom += yoffset; 504 505 // Move the controls to their new positions 506 MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL), rtab.left, rtab.top, rtab.right, rtab.bottom, FALSE); 507 MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_UPDATE), rupdate.left, rupdate.top, rupdate.right, rupdate.bottom, FALSE); 508 MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_CANCEL), rcancel.left, rcancel.top, rcancel.right, rcancel.bottom, FALSE); 509 MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_START), rstart.left, rstart.top, rstart.right, rstart.bottom, FALSE); 510 511 // Move the main dialogue to the centre of the screen 512 HDC hdc = GetDC(NULL); 513 rdlg.left = (GetDeviceCaps(hdc, HORZRES) - rdlg.right) / 2; 514 rdlg.top = (GetDeviceCaps(hdc, VERTRES) - rdlg.bottom) / 2; 515 ReleaseDC(NULL, hdc); 516 MoveWindow(hwndDlg, rdlg.left + chrome.left, rdlg.top + chrome.left, 517 rdlg.right + (-chrome.left+chrome.right), rdlg.bottom + (-chrome.top+chrome.bottom), TRUE); 518 519 // Add tabs to the tab control 520 { 521 static char textSetup[] = TEXT("Setup"); 522 static char textMessageLog[] = TEXT("Message Log"); 523 524 hwnd = GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL); 525 526 TCITEM tab = {}; 527 tab.mask = TCIF_TEXT; 528 tab.pszText = textSetup; 529 SendMessage(hwnd, TCM_INSERTITEM, (WPARAM)TAB_CONFIG, (LPARAM)&tab); 530 tab.mask = TCIF_TEXT; 531 tab.pszText = textMessageLog; 532 SendMessage(hwnd, TCM_INSERTITEM, (WPARAM)TAB_MESSAGES, (LPARAM)&tab); 533 534 // Work out the position and size of the area inside the tab control for the pages 535 ZeroMemory(&r, sizeof(r)); 536 GetClientRect(hwnd, &r); 537 SendMessage(hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM)&r); 538 r.right -= r.left-1; 539 r.bottom -= r.top-1; 540 r.top += rtab.top; 541 r.left += rtab.left; 542 543 // Create the pages and position them in the tab control, but hide them 544 pages[TAB_CONFIG] = CreateDialog((HINSTANCE)win_gethinstance(), MAKEINTRESOURCE(WIN_STARTWINPAGE_CONFIG), hwndDlg, ConfigPageProc); 545 SetWindowPos(pages[TAB_CONFIG], hwnd, r.left, r.top, r.right, r.bottom, SWP_HIDEWINDOW); 546 547 pages[TAB_MESSAGES] = GetDlgItem(hwndDlg, WIN_STARTWIN_MESSAGES); 548 SetWindowPos(pages[TAB_MESSAGES], hwnd, r.left, r.top, r.right, r.bottom, SWP_HIDEWINDOW); 549 550 // Tell the editfield acting as the console to exclude the width of the scrollbar 551 GetClientRect(pages[TAB_MESSAGES], &r); 552 r.right -= GetSystemMetrics(SM_CXVSCROLL)+4; 553 r.left = r.top = 0; 554 SendMessage(pages[TAB_MESSAGES], EM_SETRECTNP,0,(LPARAM)&r); 555 556 // Set a tab stop in the game data listbox 557 { 558 DWORD tabs[1] = { 150 }; 559 (void)ListBox_SetTabStops(GetDlgItem(pages[TAB_CONFIG], IDCDATA), 1, tabs); 560 } 561 562 SetFocus(GetDlgItem(hwndDlg, WIN_STARTWIN_START)); 563 SetWindowText(hwndDlg, apptitle); 564 } 565 return FALSE; 566 } 567 568 case WM_NOTIFY: 569 { 570 auto nmhdr = (LPNMHDR)lParam; 571 if (nmhdr->idFrom != WIN_STARTWIN_TABCTL) break; 572 int const cur = SendMessage(nmhdr->hwndFrom, TCM_GETCURSEL,0,0); 573 switch (nmhdr->code) 574 { 575 case TCN_SELCHANGING: 576 case TCN_SELCHANGE: 577 if (cur < 0 || !pages[cur]) 578 break; 579 ShowWindow(pages[cur], nmhdr->code == TCN_SELCHANGING ? SW_HIDE : SW_SHOW); 580 return TRUE; 581 } 582 break; 583 } 584 585 case WM_CLOSE: 586 if (mode == TAB_CONFIG) done = 0; 587 else quitevent++; 588 return TRUE; 589 590 case WM_DESTROY: 591 if (hbmp) 592 { 593 DeleteObject(hbmp); 594 hbmp = NULL; 595 } 596 597 if (pages[TAB_CONFIG]) 598 { 599 DestroyWindow(pages[TAB_CONFIG]); 600 pages[TAB_CONFIG] = NULL; 601 } 602 603 startupdlg = NULL; 604 return TRUE; 605 606 case WM_COMMAND: 607 switch (LOWORD(wParam)) 608 { 609 case WIN_STARTWIN_UPDATE: 610 #ifndef NETCODE_DISABLE 611 if (!ExecUpdater()) break; 612 done = 0; 613 return TRUE; 614 #else 615 break; 616 #endif 617 case WIN_STARTWIN_CANCEL: 618 if (mode == TAB_CONFIG) done = 0; 619 else quitevent++; 620 return TRUE; 621 case WIN_STARTWIN_START: 622 done = 1; 623 return TRUE; 624 } 625 return FALSE; 626 627 case WM_CTLCOLORSTATIC: 628 if ((HWND)lParam == pages[TAB_MESSAGES]) 629 return (BOOL)(intptr_t)GetSysColorBrush(COLOR_WINDOW); 630 break; 631 632 default: 633 break; 634 } 635 636 return FALSE; 637 } 638 639 bool startwin_isopen(void) 640 { 641 return !!startupdlg; 642 } 643 644 int32_t startwin_open(void) 645 { 646 if (startupdlg) return 1; 647 INITCOMMONCONTROLSEX icc = { sizeof(icc), ICC_TAB_CLASSES }; 648 InitCommonControlsEx(&icc); 649 startupdlg = CreateDialog((HINSTANCE)win_gethinstance(), MAKEINTRESOURCE(WIN_STARTWIN), NULL, startup_dlgproc); 650 if (startupdlg) 651 { 652 SetPage(TAB_MESSAGES); 653 EnableConfig(0); 654 return 0; 655 } 656 return -1; 657 } 658 659 int32_t startwin_close(void) 660 { 661 if (!startupdlg) return 1; 662 DestroyWindow(startupdlg); 663 startupdlg = NULL; 664 return 0; 665 } 666 667 int32_t startwin_puts(const char *buf) 668 { 669 if (!startupdlg) return 1; 670 671 const HWND edctl = pages[TAB_MESSAGES]; 672 673 if (!edctl) return -1; 674 675 static HWND dactrl = NULL; 676 if (!dactrl) dactrl = GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL); 677 678 int const vis = ((int)SendMessage(dactrl, TCM_GETCURSEL,0,0) == TAB_MESSAGES); 679 680 if (vis) 681 SendMessage(edctl, WM_SETREDRAW, FALSE, 0); 682 683 int const curlen = SendMessage(edctl, WM_GETTEXTLENGTH, 0,0); 684 SendMessage(edctl, EM_SETSEL, (WPARAM)curlen, (LPARAM)curlen); 685 686 int const numlines = SendMessage(edctl, EM_GETLINECOUNT, 0, 0); 687 static bool newline = false; 688 const char *p = buf; 689 690 while (*p) 691 { 692 if (newline) 693 { 694 SendMessage(edctl, EM_REPLACESEL, 0, (LPARAM)"\r\n"); 695 newline = false; 696 } 697 const char *q = p; 698 while (*q && *q != '\n') q++; 699 static char workbuf[1024]; 700 Bmemcpy(workbuf, p, q-p); 701 if (*q == '\n') 702 { 703 if (!q[1]) 704 { 705 newline = true; 706 workbuf[q-p] = 0; 707 } 708 else 709 { 710 workbuf[q-p] = '\r'; 711 workbuf[q-p+1] = '\n'; 712 workbuf[q-p+2] = 0; 713 } 714 p = q+1; 715 } 716 else 717 { 718 workbuf[q-p] = 0; 719 p = q; 720 } 721 SendMessage(edctl, EM_REPLACESEL, 0, (LPARAM)workbuf); 722 } 723 724 int const newnumlines = SendMessage(edctl, EM_GETLINECOUNT, 0, 0); 725 SendMessage(edctl, EM_LINESCROLL, 0, newnumlines - numlines); 726 727 if (vis) 728 SendMessage(edctl, WM_SETREDRAW, TRUE, 0); 729 730 return 0; 731 } 732 733 int32_t startwin_settitle(const char *str) 734 { 735 if (!startupdlg) return 1; 736 SetWindowText(startupdlg, str); 737 return 0; 738 } 739 740 int32_t startwin_idle(void *v) 741 { 742 if (!startupdlg || !IsWindow(startupdlg)) return 0; 743 if (IsDialogMessage(startupdlg, (MSG *)v)) return 1; 744 return 0; 745 } 746 747 int32_t startwin_run(void) 748 { 749 if (!startupdlg) return 1; 750 751 done = -1; 752 753 SetPage(TAB_CONFIG); 754 EnableConfig(1); 755 756 #ifdef POLYMER 757 settings.polymer = (glrendmode == REND_POLYMER); 758 #else 759 settings.polymer = 0; 760 #endif 761 762 settings.shared = gSetup; 763 settings.ini = pINISelected; 764 settings.gamedir = g_modDir; 765 766 PopulateForm(-1); 767 768 do 769 { 770 MSG msg; 771 772 switch (GetMessage(&msg, NULL, 0,0)) 773 { 774 case 0: 775 done = 1; 776 break; 777 case -1: 778 return -1; 779 default: 780 if (IsWindow(startupdlg) && IsDialogMessage(startupdlg, &msg)) 781 break; 782 TranslateMessage(&msg); 783 DispatchMessage(&msg); 784 break; 785 } 786 } 787 while (done < 0); 788 789 SetPage(TAB_MESSAGES); 790 EnableConfig(0); 791 792 if (done) 793 { 794 gSetup = settings.shared; 795 #ifdef USE_OPENGL 796 glrendmode = (settings.polymer) ? REND_POLYMER : REND_POLYMOST; 797 #endif 798 pINISelected = settings.ini; 799 if (g_modDir != settings.gamedir) 800 Bstrcpy(g_modDir, (gNoSetup == 0 && settings.gamedir != NULL) ? settings.gamedir : "/"); 801 } 802 803 return done; 804 } 805 806 #endif // STARTUP_SETUP_WINDOW