From 58d0585eaacc9d6eb9de7f871f04d370e8b01412 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 24 Dec 2019 15:28:00 +0100 Subject: [PATCH] - replaced EDuke's game selector with GZDoom's. --- source/CMakeLists.txt | 11 - source/common/gamecontrol.cpp | 55 +- source/common/gamecontrol.h | 5 + source/platform/gtk/startgtk.game.cpp | 892 ------------------- source/platform/macos/GameListSource.game.h | 26 - source/platform/macos/GameListSource.game.mm | 77 -- source/platform/macos/GrpFile.game.h | 26 - source/platform/macos/GrpFile.game.mm | 44 - source/platform/macos/startosx.game.mm | 711 --------------- source/platform/win32/game.bmp | Bin 336054 -> 0 bytes source/platform/win32/gameres.rc | 74 +- source/platform/win32/i_main.cpp | 4 +- source/platform/win32/i_system.cpp | 148 +++ source/platform/win32/resource.h | 32 +- source/platform/win32/startwin.game.cpp | 598 ------------- source/platform/win32/startwin.game.h | 121 --- 16 files changed, 254 insertions(+), 2570 deletions(-) delete mode 100644 source/platform/gtk/startgtk.game.cpp delete mode 100644 source/platform/macos/GameListSource.game.h delete mode 100644 source/platform/macos/GameListSource.game.mm delete mode 100644 source/platform/macos/GrpFile.game.h delete mode 100644 source/platform/macos/GrpFile.game.mm delete mode 100644 source/platform/macos/startosx.game.mm delete mode 100644 source/platform/win32/game.bmp delete mode 100644 source/platform/win32/startwin.game.cpp delete mode 100644 source/platform/win32/startwin.game.h diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 40acb40e8..f816f17cb 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -470,7 +470,6 @@ endif() # Start defining source files for Demolition set( PLAT_WIN32_SOURCES - platform/win32/startwin.game.cpp platform/win32/base_sysfb.cpp platform/win32/gl_sysfb.cpp platform/win32/hardware.cpp @@ -484,21 +483,14 @@ set( PLAT_WIN32_SOURCES platform/win32/i_specialpaths.cpp platform/win32/i_system.cpp platform/win32/i_xinput.cpp - platform/win32/startwin.game.cpp platform/win32/st_start.cpp platform/win32/st_start_util.cpp platform/win32/win32basevideo.cpp platform/win32/win32glvideo.cpp platform/win32/win32vulkanvideo.cpp - - # This needs a rework anyway in order to consolidate the startup dialogs so don't bother to sort in properly. - #startosx.game.mm - #sw/src/startgtk.game.cpp - ) set( PLAT_POSIX_SOURCES - #platform/gtk/startgtk.game.cpp ) set( PLAT_SDL_SOURCES @@ -517,9 +509,6 @@ set( PLAT_OSX_SOURCES ) set( PLAT_COCOA_SOURCES - #platform/macos/startosx.game.mm - #platform/macos/GrpFile.game.mm - #platform/macos/GameListSource.game.mm ) diff --git a/source/common/gamecontrol.cpp b/source/common/gamecontrol.cpp index f3c64222c..0c797a2b9 100644 --- a/source/common/gamecontrol.cpp +++ b/source/common/gamecontrol.cpp @@ -74,8 +74,11 @@ TMap NameToTileIndex; // for assigning names to tiles. The menu // Todo: Add additional definition file for the other games or textures not in that list so that the menu does not have to rely on indices. CVAR(Int, cl_defaultconfiguration, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) - - +CVAR(Bool, queryiwad, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(String, defaultiwad, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, disableautoload, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) +//CVAR(Bool, autoloadbrightmaps, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) // hopefully this is an option for later +//CVAR(Bool, autoloadlights, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) UserConfig userConfig; @@ -194,8 +197,8 @@ void UserConfig::ProcessOptions() nomusic = Args->CheckParm("-nomusic"); nosound = Args->CheckParm("-nosfx"); if (Args->CheckParm("-nosound")) nomusic = nosound = true; - if (Args->CheckParm("-setup")) setupstate = 1; - else if (Args->CheckParm("-nosetup")) setupstate = 0; + if (Args->CheckParm("-setup")) queryiwad = 1; + else if (Args->CheckParm("-nosetup")) queryiwad = 0; if (Args->CheckParm("-file")) @@ -386,8 +389,48 @@ static TArray SetupGame() g++; } } - if (groupno == -1 || userConfig.setupstate == 1) - groupno = ShowStartupWindow(groups); + + + if (groupno == -1) + { + int pick = 0; + + // We got more than one so present the IWAD selection box. + if (groups.Size() > 1) + { + // Locate the user's prefered IWAD, if it was found. + if (defaultiwad[0] != '\0') + { + for (unsigned i = 0; i < groups.Size(); ++i) + { + FString& basename = groups[i].FileName; + if (stricmp(basename, defaultiwad) == 0) + { + pick = i; + break; + } + } + } + if (groups.Size() > 1) + { + TArray wads; + for (auto& found : groups) + { + WadStuff stuff; + stuff.Name = found.FileInfo.name; + stuff.Path = ExtractFileBase(found.FileName); + wads.Push(stuff); + } + pick = I_PickIWad(&wads[0], (int)wads.Size(), queryiwad, pick); + if (pick >= 0) + { + // The newly selected IWAD becomes the new default + defaultiwad = groups[pick].FileName; + } + groupno = pick; + } + } + } if (groupno == -1) return TArray(); auto& group = groups[groupno]; diff --git a/source/common/gamecontrol.h b/source/common/gamecontrol.h index e0ab76c49..d79eddaa7 100644 --- a/source/common/gamecontrol.h +++ b/source/common/gamecontrol.h @@ -126,6 +126,11 @@ struct GrpInfo }; +struct WadStuff +{ + FString Path; + FString Name; +}; struct GrpEntry { diff --git a/source/platform/gtk/startgtk.game.cpp b/source/platform/gtk/startgtk.game.cpp deleted file mode 100644 index 8f363973b..000000000 --- a/source/platform/gtk/startgtk.game.cpp +++ /dev/null @@ -1,892 +0,0 @@ -//------------------------------------------------------------------------- -/* -Copyright (C) 2010 EDuke32 developers and contributors - -This file is part of EDuke32. - -EDuke32 is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -//------------------------------------------------------------------------- - -#include "ns.h" // Must come before everything else! - -#include "build.h" -#include "cmdline.h" -#include "common.h" -#include "common_game.h" -#include "compat.h" -#include "duke3d.h" -#include "dynamicgtk.h" -#include "game.h" -#include "grpscan.h" -#include "gtkpixdata.h" - -BEGIN_DUKE_NS - -enum -{ - NONE, - ALL, - POPULATE_VIDEO, - POPULATE_CONFIG, - POPULATE_GAME, -}; - -enum -{ - TAB_CONFIG, - TAB_GAME, - TAB_MESSAGES, -}; - -enum -{ - INPUT_KB, - INPUT_MOUSE, - INPUT_JOYSTICK, - INPUT_ALL, -}; - -static struct -{ - GtkWidget *startwin; - GtkWidget *hlayout; - GtkWidget *banner; - GtkWidget *vlayout; - GtkWidget *tabs; - GtkWidget *configtlayout; - GtkWidget *displayvlayout; - GtkWidget *vmode3dlabel; - GtkWidget *vmode3dcombo; - GtkWidget *fullscreencheck; -#ifdef POLYMER - GtkWidget *polymercheck; -#endif - GtkWidget *inputdevlabel; - GtkWidget *inputdevcombo; - GtkWidget *custommodlabel; - GtkWidget *custommodcombo; - GtkWidget *emptyhlayout; - GtkWidget *autoloadcheck; - GtkWidget *alwaysshowcheck; - GtkWidget *configtab; - GtkWidget *gamevlayout; - GtkWidget *gamelabel; - GtkWidget *gamescroll; - GtkWidget *gamelist; - GtkWidget *gametab; - GtkWidget *messagesscroll; - GtkWidget *messagestext; - GtkWidget *messagestab; - GtkWidget *buttons; - GtkWidget *cancelbutton; - GtkWidget *cancelbuttonalign; - GtkWidget *cancelbuttonlayout; - GtkWidget *cancelbuttonicon; - GtkWidget *cancelbuttonlabel; - GtkWidget *startbutton; - GtkWidget *startbuttonalign; - GtkWidget *startbuttonlayout; - GtkWidget *startbuttonicon; - GtkWidget *startbuttonlabel; -} stwidgets; - -static struct -{ - grpfile_t const * grp; - char *gamedir; - ud_setup_t shared; -#ifdef POLYMER - int polymer; -#endif -} settings; - -static int32_t retval = -1, mode = TAB_MESSAGES; -extern int32_t gtkenabled; -static void PopulateForm(unsigned char pgs); - - -// -- EVENT CALLBACKS AND CREATION STUFF -------------------------------------- - -static void on_vmode3dcombo_changed(GtkComboBox *combobox, gpointer user_data) -{ - GtkTreeModel *data; - GtkTreeIter iter; - int32_t val; - UNREFERENCED_PARAMETER(user_data); - - if (!gtk_combo_box_get_active_iter(combobox, &iter)) return; - if (!(data = gtk_combo_box_get_model(combobox))) return; - gtk_tree_model_get(data, &iter, 1, &val, -1); - settings.shared.xdim = validmode[val].xdim; - settings.shared.ydim = validmode[val].ydim; - settings.shared.bpp = validmode[val].bpp; -} - -static void on_fullscreencheck_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - UNREFERENCED_PARAMETER(user_data); - settings.shared.fullscreen = gtk_toggle_button_get_active(togglebutton); - PopulateForm(POPULATE_VIDEO); -} - -#ifdef POLYMER -static void on_polymercheck_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - UNREFERENCED_PARAMETER(user_data); - if (gtk_toggle_button_get_active(togglebutton)) - { - glrendmode = REND_POLYMER; - settings.polymer = TRUE; - if (settings.shared.bpp == 8) - { - settings.shared.bpp = 32; - PopulateForm(POPULATE_VIDEO); - } - } - else - { - glrendmode = REND_POLYMOST; - settings.polymer = FALSE; - } -} -#endif - -static void on_inputdevcombo_changed(GtkComboBox *combobox, gpointer user_data) -{ - UNREFERENCED_PARAMETER(user_data); - switch (gtk_combo_box_get_active(combobox)) - { - case 0: settings.shared.usemouse = 0; settings.shared.usejoystick = 0; break; - case 1: settings.shared.usemouse = 1; settings.shared.usejoystick = 0; break; - case 2: settings.shared.usemouse = 0; settings.shared.usejoystick = 1; break; - case 3: settings.shared.usemouse = 1; settings.shared.usejoystick = 1; break; - } -} - -static void on_custommodcombo_changed(GtkComboBox *combobox, gpointer user_data) -{ - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreePath *path; - char *value; - UNREFERENCED_PARAMETER(user_data); - - if (gtk_combo_box_get_active_iter(combobox, &iter)) - { - model = gtk_combo_box_get_model(combobox); - gtk_tree_model_get(model, &iter, 0,&value, -1); - path = gtk_tree_model_get_path(model, &iter); - - if (*gtk_tree_path_get_indices(path) == NONE) - settings.gamedir = NULL; - else settings.gamedir = value; - } -} - -static void on_autoloadcheck_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - UNREFERENCED_PARAMETER(user_data); - settings.shared.noautoload = !gtk_toggle_button_get_active(togglebutton); -} - -static void on_alwaysshowcheck_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - UNREFERENCED_PARAMETER(user_data); - settings.shared.forcesetup = gtk_toggle_button_get_active(togglebutton); -} - -static void on_cancelbutton_clicked(GtkButton *button, gpointer user_data) -{ - UNREFERENCED_PARAMETER(button); - UNREFERENCED_PARAMETER(user_data); - if (mode == TAB_CONFIG) { retval = 0; gtk_main_quit(); } - else quitevent++; -} - -static void on_startbutton_clicked(GtkButton *button, gpointer user_data) -{ - UNREFERENCED_PARAMETER(button); - UNREFERENCED_PARAMETER(user_data); - retval = 1; - gtk_main_quit(); -} - -static void on_gamelist_selection_changed(GtkTreeSelection *selection, gpointer user_data) -{ - GtkTreeIter iter; - GtkTreeModel *model; - UNREFERENCED_PARAMETER(user_data); - - if (gtk_tree_selection_get_selected(selection, &model, &iter)) - { - grpfile_t const *fg; - gtk_tree_model_get(model, &iter, 2, (gpointer)&fg, -1); - settings.grp = fg; - } -} - -static gboolean on_startwin_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) -{ - UNREFERENCED_PARAMETER(widget); - UNREFERENCED_PARAMETER(event); - UNREFERENCED_PARAMETER(user_data); - if (mode == TAB_CONFIG) { retval = 0; gtk_main_quit(); } - else quitevent++; - return TRUE; // FALSE would let the event go through. we want the game to decide when to close -} - - -// -- SUPPORT FUNCTIONS ------------------------------------------------------- - -static GdkPixbuf *load_banner(void) -{ - return gdk_pixbuf_from_pixdata((GdkPixdata const *)&startbanner_pixdata, FALSE, NULL); -} - -static void SetPage(int32_t n) -{ - if (!gtkenabled || !stwidgets.startwin) return; - mode = n; - gtk_notebook_set_current_page(GTK_NOTEBOOK(stwidgets.tabs), n); - - // each control in the config page vertical layout plus the start button should be made (in)sensitive - if (n == TAB_CONFIG) n = TRUE; else n = FALSE; - gtk_widget_set_sensitive(stwidgets.startbutton, n); - gtk_container_foreach(GTK_CONTAINER(stwidgets.configtlayout), - (GtkCallback)gtk_widget_set_sensitive, - (gpointer)&n); -} - -static unsigned char GetModsDirNames(GtkListStore *list) -{ - char *homedir; - char pdir[BMAX_PATH]; - unsigned char iternumb = 0; - BUILDVFS_FIND_REC *dirs = NULL; - GtkTreeIter iter; - - pathsearchmode = 1; - - if ((homedir = Bgethomedir())) - { - Bsnprintf(pdir, sizeof(pdir), "%s/" ".eduke32", homedir); - dirs = klistpath(pdir, "*", BUILDVFS_FIND_DIR); - for (; dirs != NULL; dirs=dirs->next) - { - if ((Bstrcmp(dirs->name, "autoload") == 0) || - (Bstrcmp(dirs->name, "..") == 0) || - (Bstrcmp(dirs->name, ".") == 0)) - continue; - else - { - gtk_list_store_append(list, &iter); - gtk_list_store_set(list, &iter, 0,dirs->name, -1); - iternumb++; - } - } - } - - klistfree(dirs); - dirs = NULL; - - return iternumb; -} - -static void PopulateForm(unsigned char pgs) -{ - if ((pgs == ALL) || (pgs == POPULATE_VIDEO)) - { - int32_t mode3d, i; - GtkListStore *modes3d; - GtkTreeIter iter; - char buf[64]; - - mode3d = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, settings.shared.bpp, settings.shared.fullscreen, 1); - if (mode3d < 0) - { - int32_t i, cd[] = { 32, 24, 16, 15, 8, 0 }; - - for (i=0; cd[i];) { if (cd[i] >= settings.shared.bpp) i++; else break; } - for (; cd[i]; i++) - { - mode3d = videoCheckMode(&settings.shared.xdim, &settings.shared.ydim, cd[i], settings.shared.fullscreen, 1); - if (mode3d < 0) continue; - settings.shared.bpp = cd[i]; - break; - } - } - - modes3d = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(stwidgets.vmode3dcombo))); - gtk_list_store_clear(modes3d); - - for (i=0; inext) - { - gtk_list_store_append(list, &iter); - gtk_list_store_set(list, &iter, 0, fg->type->name, 1, fg->filename, 2, (void const *)fg, -1); - if (settings.grp == fg) - { - GtkTreeSelection *sel = gtk_tree_view_get_selection(gamelist); - g_signal_handlers_block_by_func(sel, (gpointer)on_gamelist_selection_changed, NULL); - gtk_tree_selection_select_iter(sel, &iter); - g_signal_handlers_unblock_by_func(sel, (gpointer)on_gamelist_selection_changed, NULL); - } - } - } -} - -static gint name_sorter(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) -{ - gchar *as, *bs; - gint r; - UNREFERENCED_PARAMETER(user_data); - gtk_tree_model_get(model, a, 0, &as, -1); - gtk_tree_model_get(model, b, 0, &bs, -1); - - r = g_utf8_collate(as,bs); - - g_free(as); - g_free(bs); - - return r; -} - -static GtkWidget *create_window(void) -{ - // Basic window - stwidgets.startwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(stwidgets.startwin), apptitle); // NOTE: use global app title - gtk_window_set_position(GTK_WINDOW(stwidgets.startwin), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(stwidgets.startwin), FALSE); - gtk_window_set_type_hint(GTK_WINDOW(stwidgets.startwin), GDK_WINDOW_TYPE_HINT_DIALOG); - - // Horizontal layout of banner and controls - stwidgets.hlayout = gtk_hbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(stwidgets.startwin), stwidgets.hlayout); - - // banner - { - GdkPixbuf *pixbuf = load_banner(); - stwidgets.banner = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref((gpointer)pixbuf); - } - gtk_box_pack_start(GTK_BOX(stwidgets.hlayout), stwidgets.banner, FALSE, FALSE, 0); - gtk_misc_set_alignment(GTK_MISC(stwidgets.banner), 0.5, 0); - - // Vertical layout of tab control and start+cancel buttons - stwidgets.vlayout = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(stwidgets.hlayout), stwidgets.vlayout, TRUE, TRUE, 0); - - // Tab control - stwidgets.tabs = gtk_notebook_new(); - gtk_box_pack_start(GTK_BOX(stwidgets.vlayout), stwidgets.tabs, TRUE, TRUE, 0); - gtk_container_set_border_width(GTK_CONTAINER(stwidgets.tabs), 4); - - // layout table of config page - stwidgets.configtlayout = gtk_table_new(6, 3, FALSE); - gtk_container_add(GTK_CONTAINER(stwidgets.tabs), stwidgets.configtlayout); - - // 3D video mode LabelText - stwidgets.vmode3dlabel = gtk_label_new_with_mnemonic("_Video mode:"); - gtk_misc_set_alignment(GTK_MISC(stwidgets.vmode3dlabel), 0.3, 0); -#ifdef POLYMER - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dlabel, 0,1, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 0); -#else - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dlabel, 0,1, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 7); -#endif - - // 3D video mode combo - { - GtkListStore *list = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); - GtkCellRenderer *cell; - - stwidgets.vmode3dcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list)); - g_object_unref(G_OBJECT(list)); - - cell = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.vmode3dcombo), cell, FALSE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.vmode3dcombo), cell, "text", 0, NULL); - } - -#ifdef POLYMER - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dcombo, 1,2, 0,1, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 0); -#else - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.vmode3dcombo, 1,2, 0,1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 7); -#endif - - // Fullscreen checkbox - stwidgets.displayvlayout = gtk_vbox_new(TRUE, 0); -#ifdef POLYMER - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.displayvlayout, 2,3, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 0); -#else - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.displayvlayout, 2,3, 0,1, GTK_FILL, (GtkAttachOptions)0, 4, 7); -#endif - - stwidgets.fullscreencheck = gtk_check_button_new_with_mnemonic("_Fullscreen"); - gtk_box_pack_start(GTK_BOX(stwidgets.displayvlayout), stwidgets.fullscreencheck, FALSE, FALSE, 0); - -#ifdef POLYMER - // Polymer checkbox - stwidgets.polymercheck = gtk_check_button_new_with_mnemonic("_Polymer"); - gtk_box_pack_start(GTK_BOX(stwidgets.displayvlayout), stwidgets.polymercheck, FALSE, FALSE, 0); -#endif - - // Input devices LabelText - stwidgets.inputdevlabel = gtk_label_new_with_mnemonic("_Input devices:"); - gtk_misc_set_alignment(GTK_MISC(stwidgets.inputdevlabel), 0.3, 0); - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.inputdevlabel, 0,1, 1,2, GTK_FILL, (GtkAttachOptions)0, 4, 0); - - // Input devices combo - { - GtkListStore *list = gtk_list_store_new(1, G_TYPE_STRING); - GtkCellRenderer *cell; - - stwidgets.inputdevcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list)); - g_object_unref(G_OBJECT(list)); - - cell = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.inputdevcombo), cell, FALSE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.inputdevcombo), cell, "text", 0, NULL); - } - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.inputdevcombo, 1,2, 1,2, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 0); - - // Custom mod LabelText - stwidgets.custommodlabel = gtk_label_new_with_mnemonic("Custom _game:"); - gtk_misc_set_alignment(GTK_MISC(stwidgets.custommodlabel), 0.3, 0); - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.custommodlabel, 0,1, 2,3, GTK_FILL, (GtkAttachOptions)0, 4, 7); - - // Custom mod combo - { - GtkListStore *list = gtk_list_store_new(1, G_TYPE_STRING); - GtkCellRenderer *cell; - - stwidgets.custommodcombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list)); - g_object_unref(G_OBJECT(list)); - - cell = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stwidgets.custommodcombo), cell, FALSE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(stwidgets.custommodcombo), cell, "text", 0, NULL); - } - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.custommodcombo, 1,2, 2,3, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 7); - - // Empty horizontal layout - stwidgets.emptyhlayout = gtk_hbox_new(TRUE, 0); - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.emptyhlayout, 0,3, 3,4, (GtkAttachOptions)0, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 4, 0); - - // Autoload checkbox - stwidgets.autoloadcheck = gtk_check_button_new_with_mnemonic("_Enable \"autoload\" folder"); - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.autoloadcheck, 0,3, 4,5, GTK_FILL, (GtkAttachOptions)0, 2, 2); - - // Always show config checkbox - stwidgets.alwaysshowcheck = gtk_check_button_new_with_mnemonic("_Always show this window at startup"); - gtk_table_attach(GTK_TABLE(stwidgets.configtlayout), stwidgets.alwaysshowcheck, 0,3, 5,6, GTK_FILL, (GtkAttachOptions)0, 2, 2); - - // Configuration tab - stwidgets.configtab = gtk_label_new("Configuration"); - gtk_notebook_set_tab_label(GTK_NOTEBOOK(stwidgets.tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(stwidgets.tabs), 0), stwidgets.configtab); - - // Game data layout - stwidgets.gamevlayout = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(stwidgets.tabs), stwidgets.gamevlayout); - gtk_container_set_border_width(GTK_CONTAINER(stwidgets.gamevlayout), 4); - - // Game data field LabelText - stwidgets.gamelabel = gtk_label_new_with_mnemonic("_Game:"); - gtk_box_pack_start(GTK_BOX(stwidgets.gamevlayout), stwidgets.gamelabel, FALSE, FALSE, 0); - gtk_misc_set_alignment(GTK_MISC(stwidgets.gamelabel), 0, 0.5); - - // Game data scrollable area - stwidgets.gamescroll = gtk_scrolled_window_new(NULL, NULL); - gtk_box_pack_start(GTK_BOX(stwidgets.gamevlayout), stwidgets.gamescroll, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(stwidgets.gamescroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(stwidgets.gamescroll), GTK_SHADOW_IN); - - // Game data list - { - GtkListStore *list = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); - GtkCellRenderer *cell; - GtkTreeViewColumn *col; - - gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list), 0, name_sorter, NULL, NULL); - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(list), 0, GTK_SORT_ASCENDING); - - stwidgets.gamelist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list)); - g_object_unref(G_OBJECT(list)); - - cell = gtk_cell_renderer_text_new(); - col = gtk_tree_view_column_new_with_attributes("Game", cell, "text", 0, NULL); - gtk_tree_view_column_set_expand(col, TRUE); - gtk_tree_view_append_column(GTK_TREE_VIEW(stwidgets.gamelist), col); - col = gtk_tree_view_column_new_with_attributes("GRP file", cell, "text", 1, NULL); - gtk_tree_view_column_set_min_width(col, 64); - gtk_tree_view_append_column(GTK_TREE_VIEW(stwidgets.gamelist), col); - } - gtk_container_add(GTK_CONTAINER(stwidgets.gamescroll), stwidgets.gamelist); - - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(stwidgets.gamelist), FALSE); - gtk_tree_view_set_enable_search(GTK_TREE_VIEW(stwidgets.gamelist), FALSE); - - // Game tab - stwidgets.gametab = gtk_label_new("Game"); - gtk_notebook_set_tab_label(GTK_NOTEBOOK(stwidgets.tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(stwidgets.tabs), 1), stwidgets.gametab); - - // Messages scrollable area - stwidgets.messagesscroll = gtk_scrolled_window_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(stwidgets.tabs), stwidgets.messagesscroll); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(stwidgets.messagesscroll), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - - // Messages text area - stwidgets.messagestext = gtk_text_view_new(); - gtk_container_add(GTK_CONTAINER(stwidgets.messagesscroll), stwidgets.messagestext); - gtk_text_view_set_editable(GTK_TEXT_VIEW(stwidgets.messagestext), FALSE); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(stwidgets.messagestext), GTK_WRAP_WORD); - gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(stwidgets.messagestext), FALSE); - gtk_text_view_set_left_margin(GTK_TEXT_VIEW(stwidgets.messagestext), 2); - gtk_text_view_set_right_margin(GTK_TEXT_VIEW(stwidgets.messagestext), 2); - - // Messages tab - stwidgets.messagestab = gtk_label_new("Messages"); - gtk_notebook_set_tab_label(GTK_NOTEBOOK(stwidgets.tabs), gtk_notebook_get_nth_page(GTK_NOTEBOOK(stwidgets.tabs), 2), stwidgets.messagestab); - - // Dialogue box buttons layout - stwidgets.buttons = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(stwidgets.vlayout), stwidgets.buttons, FALSE, TRUE, 0); - gtk_container_set_border_width(GTK_CONTAINER(stwidgets.buttons), 3); - gtk_button_box_set_layout(GTK_BUTTON_BOX(stwidgets.buttons), GTK_BUTTONBOX_END); - - // Cancel button - stwidgets.cancelbutton = gtk_button_new(); - gtk_container_add(GTK_CONTAINER(stwidgets.buttons), stwidgets.cancelbutton); - GTK_WIDGET_SET_FLAGS(stwidgets.cancelbutton, GTK_CAN_DEFAULT); - - stwidgets.cancelbuttonalign = gtk_alignment_new(0.5, 0.5, 0, 0); - gtk_container_add(GTK_CONTAINER(stwidgets.cancelbutton), stwidgets.cancelbuttonalign); - - stwidgets.cancelbuttonlayout = gtk_hbox_new(FALSE, 2); - gtk_container_add(GTK_CONTAINER(stwidgets.cancelbuttonalign), stwidgets.cancelbuttonlayout); - - stwidgets.cancelbuttonicon = gtk_image_new_from_stock("gtk-cancel", GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start(GTK_BOX(stwidgets.cancelbuttonlayout), stwidgets.cancelbuttonicon, FALSE, FALSE, 0); - - stwidgets.cancelbuttonlabel = gtk_label_new_with_mnemonic("_Cancel"); - gtk_box_pack_start(GTK_BOX(stwidgets.cancelbuttonlayout), stwidgets.cancelbuttonlabel, FALSE, FALSE, 0); - - // Start button - stwidgets.startbutton = gtk_button_new(); - gtk_container_add(GTK_CONTAINER(stwidgets.buttons), stwidgets.startbutton); - GTK_WIDGET_SET_FLAGS(stwidgets.startbutton, GTK_CAN_DEFAULT); - - gtk_window_set_default(GTK_WINDOW(stwidgets.startwin), stwidgets.startbutton); - - stwidgets.startbuttonalign = gtk_alignment_new(0.5, 0.5, 0, 0); - gtk_container_add(GTK_CONTAINER(stwidgets.startbutton), stwidgets.startbuttonalign); - - stwidgets.startbuttonlayout = gtk_hbox_new(FALSE, 2); - gtk_container_add(GTK_CONTAINER(stwidgets.startbuttonalign), stwidgets.startbuttonlayout); - - stwidgets.startbuttonicon = gtk_image_new_from_stock("gtk-execute", GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start(GTK_BOX(stwidgets.startbuttonlayout), stwidgets.startbuttonicon, FALSE, FALSE, 0); - - stwidgets.startbuttonlabel = gtk_label_new_with_mnemonic("_Start"); - gtk_box_pack_start(GTK_BOX(stwidgets.startbuttonlayout), stwidgets.startbuttonlabel, FALSE, FALSE, 0); - - // Wire up the signals - g_signal_connect((gpointer) stwidgets.startwin, "delete_event", - G_CALLBACK(on_startwin_delete_event), - NULL); - g_signal_connect((gpointer) stwidgets.vmode3dcombo, "changed", - G_CALLBACK(on_vmode3dcombo_changed), - NULL); - g_signal_connect((gpointer) stwidgets.fullscreencheck, "toggled", - G_CALLBACK(on_fullscreencheck_toggled), - NULL); -#ifdef POLYMER - g_signal_connect((gpointer) stwidgets.polymercheck, "toggled", - G_CALLBACK(on_polymercheck_toggled), - NULL); -#endif - g_signal_connect((gpointer) stwidgets.inputdevcombo, "changed", - G_CALLBACK(on_inputdevcombo_changed), - NULL); - g_signal_connect((gpointer) stwidgets.custommodcombo, "changed", - G_CALLBACK(on_custommodcombo_changed), - NULL); - g_signal_connect((gpointer) stwidgets.autoloadcheck, "toggled", - G_CALLBACK(on_autoloadcheck_toggled), - NULL); - g_signal_connect((gpointer) stwidgets.alwaysshowcheck, "toggled", - G_CALLBACK(on_alwaysshowcheck_toggled), - NULL); - g_signal_connect((gpointer) stwidgets.cancelbutton, "clicked", - G_CALLBACK(on_cancelbutton_clicked), - NULL); - g_signal_connect((gpointer) stwidgets.startbutton, "clicked", - G_CALLBACK(on_startbutton_clicked), - NULL); - { - GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(stwidgets.gamelist)); - gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); - g_signal_connect((gpointer) sel, "changed", - G_CALLBACK(on_gamelist_selection_changed), - NULL); - } - - // Associate labels with their controls - gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.vmode3dlabel), stwidgets.vmode3dcombo); - gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.inputdevlabel), stwidgets.inputdevcombo); - gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.custommodlabel), stwidgets.custommodcombo); - gtk_label_set_mnemonic_widget(GTK_LABEL(stwidgets.gamelabel), stwidgets.gamelist); - - return stwidgets.startwin; -} - - -// -- BUILD ENTRY POINTS ------------------------------------------------------ - -int32_t startwin_open(void) -{ - if (!gtkenabled) return 0; - if (stwidgets.startwin) return 1; - - stwidgets.startwin = create_window(); - if (stwidgets.startwin) - { - SetPage(TAB_MESSAGES); - gtk_widget_show_all(stwidgets.startwin); - gtk_main_iteration_do(FALSE); - return 0; - } - return -1; -} - -int32_t startwin_close(void) -{ - if (!gtkenabled) return 0; - if (!stwidgets.startwin) return 1; - gtk_widget_destroy(stwidgets.startwin); - stwidgets.startwin = NULL; - return 0; -} - -int32_t startwin_puts(const char *str) -{ - GtkWidget *textview; - GtkTextBuffer *textbuffer; - GtkTextIter enditer; - GtkTextMark *mark; - const char *aptr, *bptr; - - if (!gtkenabled || !str) return 0; - if (!stwidgets.startwin) return 1; - if (!(textview = stwidgets.messagestext)) return -1; - textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); - - gtk_text_buffer_get_end_iter(textbuffer, &enditer); - for (aptr = bptr = str; *aptr != 0;) - { - switch (*bptr) - { - case '\b': - if (bptr > aptr) - gtk_text_buffer_insert(textbuffer, &enditer, (const gchar *)aptr, (gint)(bptr-aptr)-1); -#if GTK_CHECK_VERSION(2,6,0) - gtk_text_buffer_backspace(textbuffer, &enditer, FALSE, TRUE); -#else - { - GtkTextIter iter2 = enditer; - gtk_text_iter_backward_cursor_position(&iter2); - //FIXME: this seems be deleting one too many chars somewhere! - if (!gtk_text_iter_equal(&iter2, &enditer)) - gtk_text_buffer_delete_interactive(textbuffer, &iter2, &enditer, TRUE); - } -#endif - aptr = ++bptr; - break; - case 0: - if (bptr > aptr) - gtk_text_buffer_insert(textbuffer, &enditer, (const gchar *)aptr, (gint)(bptr-aptr)); - aptr = bptr; - break; - case '\r': // FIXME - default: - bptr++; - break; - } - } - - mark = gtk_text_buffer_create_mark(textbuffer, NULL, &enditer, 1); - gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview), mark, 0.0, FALSE, 0.0, 1.0); - gtk_text_buffer_delete_mark(textbuffer, mark); - - return 0; -} - -int32_t startwin_settitle(const char *title) -{ - if (!gtkenabled) return 0; - if (!stwidgets.startwin) return 1; - gtk_window_set_title(GTK_WINDOW(stwidgets.startwin), title); - return 0; -} - -int32_t startwin_idle(void *s) -{ - UNREFERENCED_PARAMETER(s); - if (!gtkenabled) return 0; - //if (!stwidgets.startwin) return 1; - gtk_main_iteration_do(FALSE); - return 0; -} - -int32_t startwin_run(void) -{ - if (!gtkenabled) return 1; - if (!stwidgets.startwin) return 1; - - SetPage(TAB_CONFIG); - - settings.shared = ud.setup; - settings.gamedir = g_modDir; - settings.grp = g_selectedGrp; -#ifdef POLYMER - settings.polymer = (glrendmode == REND_POLYMER) & (settings.shared.bpp != 8); -#endif - PopulateForm(ALL); - - gtk_main(); - - SetPage(TAB_MESSAGES); - if (retval) // launch the game with these parameters - { - ud.setup = settings.shared; -#ifdef POLYMER - glrendmode = (settings.polymer) ? REND_POLYMER : REND_POLYMOST; -#endif - g_selectedGrp = settings.grp; - - Bstrcpy(g_modDir, (g_noSetup == 0 && settings.gamedir != NULL) ? settings.gamedir : "/"); - } - - return retval; -} -END_DUKE_NS diff --git a/source/platform/macos/GameListSource.game.h b/source/platform/macos/GameListSource.game.h deleted file mode 100644 index 58eece51a..000000000 --- a/source/platform/macos/GameListSource.game.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * GameListSource.game.h - * duke3d - * - * Created by Jonathon Fowler on 24/07/09. - * Copyright 2009 __MyCompanyName__. All rights reserved. - * - */ - -#import -#import - -@interface GameListSource : NSObject -{ - NSMutableArray *list; -} -- (id)init; -- (void)dealloc; -- (GrpFile*)grpAtIndex:(int)index; -- (int)findIndexForGrpname:(NSString*)grpname; -- (id)tableView:(NSTableView *)aTableView -objectValueForTableColumn:(NSTableColumn *)aTableColumn - row:(NSInteger)rowIndex; -- (int)numberOfRowsInTableView:(NSTableView *)aTableView; -@end - diff --git a/source/platform/macos/GameListSource.game.mm b/source/platform/macos/GameListSource.game.mm deleted file mode 100644 index 148a3c055..000000000 --- a/source/platform/macos/GameListSource.game.mm +++ /dev/null @@ -1,77 +0,0 @@ -/* - * GameListSource.game.m - * duke3d - * - * Created by Jonathon Fowler on 24/07/09. - * Copyright 2009 __MyCompanyName__. All rights reserved. - * - */ - -#import - -#include "ns.h" // Must come before everything else! - -#include "compat.h" - -#import "GrpFile.game.h" -#import "GameListSource.game.h" - -@implementation GameListSource -- (id)init -{ - self = [super init]; - if (self) { - list = [[NSMutableArray alloc] init]; - - for (grpfile_t const *p = foundgrps; p; p=p->next) { - [list addObject:[[GrpFile alloc] initWithGrpfile:p]]; - } - } - - return self; -} - -- (void)dealloc -{ - [list release]; - [super dealloc]; -} - -- (GrpFile*)grpAtIndex:(int)index -{ - return [list objectAtIndex:index]; -} - -- (int)findIndexForGrpname:(NSString*)grpname -{ - NSUInteger i, listcount = [list count]; - for (i=0; i - -#include "grpscan.h" - -@interface GrpFile : NSObject -{ - NSString *namestring; - NSString *grpnamestring; - grpfile_t const *fg; -} -- (id)initWithGrpfile:(grpfile_t const *)grpfile; -- (void)dealloc; -- (NSString *)name; -- (NSString *)grpname; -- (grpfile_t const *)entryptr; -@end - diff --git a/source/platform/macos/GrpFile.game.mm b/source/platform/macos/GrpFile.game.mm deleted file mode 100644 index ac28b5f49..000000000 --- a/source/platform/macos/GrpFile.game.mm +++ /dev/null @@ -1,44 +0,0 @@ -/* - * GrpFile.game.m - * duke3d - * - * Created by Jonathon Fowler on 24/07/09. - * Copyright 2009 __MyCompanyName__. All rights reserved. - * - */ -#include "ns.h" // Must come before everything else! - -#include "GrpFile.game.h" - -@implementation GrpFile -- (id)initWithGrpfile:(grpfile_t const *)grpfile -{ - self = [super init]; - if (self) { - fg = grpfile; - namestring = [NSString stringWithCString:fg->type->name encoding:NSUTF8StringEncoding]; - [namestring retain]; - grpnamestring = [NSString stringWithCString:fg->filename encoding:NSUTF8StringEncoding]; - [grpnamestring retain]; - } - return self; -} -- (void)dealloc -{ - [namestring release]; - [grpnamestring release]; - [super dealloc]; -} -- (NSString *)name -{ - return namestring; -} -- (NSString *)grpname -{ - return grpnamestring; -} -- (grpfile_t const *)entryptr -{ - return fg; -} -@end diff --git a/source/platform/macos/startosx.game.mm b/source/platform/macos/startosx.game.mm deleted file mode 100644 index b88b589e8..000000000 --- a/source/platform/macos/startosx.game.mm +++ /dev/null @@ -1,711 +0,0 @@ - -#import - -#include "ns.h" // Must come before everything else! - -#include "duke3d.h" -#include "game.h" -#include "common.h" -#include "common_game.h" -#include "build.h" -#include "compat.h" -#include "baselayer.h" -#include "grpscan.h" -#include "osxbits.h" - -#import "GrpFile.game.h" -#import "GameListSource.game.h" - -#ifndef MAC_OS_X_VERSION_10_5 -# define NSImageScaleNone NSScaleNone -#endif - -#ifndef MAC_OS_X_VERSION_10_12 -# define NSEventModifierFlagOption NSAlternateKeyMask -# define NSEventModifierFlagCommand NSCommandKeyMask -# define NSEventMaskAny NSAnyEventMask -# define NSWindowStyleMaskTitled NSTitledWindowMask -# define NSWindowStyleMaskClosable NSClosableWindowMask -# define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask -# define NSWindowStyleMaskResizable NSResizableWindowMask -# define NSAlertStyleInformational NSInformationalAlertStyle -# define NSControlSizeSmall NSSmallControlSize -#endif - -#ifndef MAC_OS_X_VERSION_10_14 -# define NSButtonTypeSwitch NSSwitchButton -# define NSBezelStyleRounded NSRoundedBezelStyle -# define NSControlStateValueOn NSOnState -# define NSControlStateValueOff NSOffState -#endif - -static NSRect NSRectChangeXY(NSRect const rect, CGFloat const x, CGFloat const y) -{ - return NSMakeRect(x, y, rect.size.width, rect.size.height); -} -static NSRect NSSizeAddXY(NSSize const size, CGFloat const x, CGFloat const y) -{ - return NSMakeRect(x, y, size.width, size.height); -} -#if 0 -static CGFloat NSRightEdge(NSRect rect) -{ - return rect.origin.x + rect.size.width; -} -#endif -static CGFloat NSTopEdge(NSRect rect) -{ - return rect.origin.y + rect.size.height; -} - -static void setFontToSmall(id control) -{ - [control setFont:[NSFont fontWithDescriptor:[[control font] fontDescriptor] size:[NSFont smallSystemFontSize]]]; -} - -static void setControlToSmall(id control) -{ - [control setControlSize:NSControlSizeSmall]; -} - -static NSTextField * makeLabel(NSString * labelText) -{ - NSTextField *textField = [[NSTextField alloc] init]; - setFontToSmall(textField); - setControlToSmall([textField cell]); - [textField setStringValue:labelText]; - [textField setBezeled:NO]; - [textField setDrawsBackground:NO]; - [textField setEditable:NO]; - [textField setSelectable:NO]; - [textField sizeToFit]; - return textField; -} - -static NSButton * makeCheckbox(NSString * labelText) -{ - NSButton *checkbox = [[NSButton alloc] init]; - setFontToSmall(checkbox); - setControlToSmall([checkbox cell]); - [checkbox setTitle:labelText]; - [checkbox setButtonType:NSButtonTypeSwitch]; - [checkbox sizeToFit]; - return checkbox; -} - -static NSPopUpButton * makeComboBox(void) -{ - NSPopUpButton *comboBox = [[NSPopUpButton alloc] init]; - [comboBox setPullsDown:NO]; - setFontToSmall(comboBox); - setControlToSmall([comboBox cell]); - [comboBox setBezelStyle:NSBezelStyleRounded]; - [comboBox setPreferredEdge:NSMaxYEdge]; - [[comboBox cell] setArrowPosition:NSPopUpArrowAtCenter]; - [comboBox sizeToFit]; - return comboBox; -} - -/* setAppleMenu disappeared from the headers in 10.4 */ -@interface NSApplication(NSAppleMenu) -- (void)setAppleMenu:(NSMenu *)menu; -@end - -static NSString * GetApplicationName(void) -{ - NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; - if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; - if (![appName length]) - appName = [[NSProcessInfo processInfo] processName]; - - return appName; -} - -static void CreateApplicationMenus(void) -{ - NSString *appName; - NSString *title; - NSMenu *rootMenu; - NSMenu *serviceMenu; - NSMenuItem *menuItem; - - NSMenu *mainMenu = [[NSMenu alloc] init]; - - /* Create the application menu */ - appName = GetApplicationName(); - rootMenu = [[NSMenu alloc] init]; - - /* Put menu into the menubar */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:rootMenu]; - [mainMenu addItem:menuItem]; - [menuItem release]; - - /* Add menu items */ - title = [@"About " stringByAppendingString:appName]; - [rootMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; - - [rootMenu addItem:[NSMenuItem separatorItem]]; - - serviceMenu = [[NSMenu alloc] init]; - menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:serviceMenu]; - - [nsapp setServicesMenu:serviceMenu]; - [serviceMenu release]; - - [rootMenu addItem:[NSMenuItem separatorItem]]; - - title = [@"Hide " stringByAppendingString:appName]; - [rootMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; - - menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; - [menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption|NSEventModifierFlagCommand)]; - - [rootMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; - - [rootMenu addItem:[NSMenuItem separatorItem]]; - - title = [@"Quit " stringByAppendingString:appName]; - [rootMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; - - /* Create the main menu bar */ - [nsapp setMainMenu:mainMenu]; - [mainMenu release]; /* we're done with it, let NSApp own it. */ - - /* Tell the application object that this is now the application menu */ - [nsapp setAppleMenu:rootMenu]; - [rootMenu release]; -} - -static int retval = -1; - -static struct { - grpfile_t const * grp; - int fullscreen; - int xdim3d, ydim3d, bpp3d; - int forcesetup; -} settings; - -@interface StartupWindow : NSWindow -{ - NSMutableArray *modeslist3d; - GameListSource *gamelistsrc; - - NSButton *alwaysShowButton; - NSButton *fullscreenButton; - NSTextView *messagesView; - NSTabView *tabView; - NSTabViewItem *tabViewItemSetup; - NSTabViewItem *tabViewItemMessageLog; - NSPopUpButton *videoMode3DPUButton; - NSScrollView *gameList; - - NSButton *cancelButton; - NSButton *startButton; -} - -- (StartupWindow *)init; - -- (void)dealloc; -- (void)populateVideoModes:(BOOL)firstTime; - -- (void)fullscreenClicked:(id)sender; - -- (void)cancel:(id)sender; -- (void)start:(id)sender; - -- (void)setupRunMode; -- (void)setupMessagesMode; - -- (void)putsMessage:(NSString *)str; - -@end - -@implementation StartupWindow : NSWindow - -- (StartupWindow *)init -{ - NSUInteger const style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; - NSRect const windowFrame = NSMakeRect(0, 0, 480, 280); - self = [super initWithContentRect:windowFrame styleMask:style backing:NSBackingStoreBuffered defer:NO]; - - if (self) - { - // window properties - [self setDelegate:self]; - [self setReleasedWhenClosed:NO]; -#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3 - [self setContentMinSize:[[self contentView] frame].size]; -#else - [self setMinSize:[NSWindow frameRectForContentRect:[[self contentView] frame] styleMask:[self styleMask]].size]; -#endif - - - // image on the left - NSRect const imageFrame = NSMakeRect(0, 0, 100, 280); - NSImageView * imageView = [[NSImageView alloc] initWithFrame:imageFrame]; - [imageView setImageScaling:NSImageScaleNone]; - [imageView setImage:[NSImage imageNamed:@"game"]]; - [[self contentView] addSubview:imageView]; - [imageView setAutoresizingMask:NSViewMaxXMargin | NSViewHeightSizable]; - - - // buttons - CGFloat const buttonWidth = 80; - CGFloat const buttonHeight = 32; - - NSRect const startButtonFrame = NSMakeRect(windowFrame.size.width - buttonWidth, 0, buttonWidth, buttonHeight); - startButton = [[NSButton alloc] initWithFrame:startButtonFrame]; - [[self contentView] addSubview:startButton]; - [startButton setTitle:@"Start"]; - [startButton setTarget:self]; - [startButton setAction:@selector(start:)]; - [startButton setBezelStyle:NSBezelStyleRounded]; - [startButton setKeyEquivalent:@"\r"]; - [startButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin]; - - NSRect const cancelButtonFrame = NSMakeRect(startButtonFrame.origin.x - buttonWidth, 0, buttonWidth, buttonHeight); - cancelButton = [[NSButton alloc] initWithFrame:cancelButtonFrame]; - [[self contentView] addSubview:cancelButton]; - [cancelButton setTitle:@"Cancel"]; - [cancelButton setTarget:self]; - [cancelButton setAction:@selector(cancel:)]; - [cancelButton setBezelStyle:NSBezelStyleRounded]; - [cancelButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin]; - - - // tab frame - NSRect const tabViewFrame = NSMakeRect(imageFrame.size.width, buttonHeight, windowFrame.size.width - imageFrame.size.width, windowFrame.size.height - buttonHeight - 5); - tabView = [[NSTabView alloc] initWithFrame:tabViewFrame]; - [[self contentView] addSubview:tabView]; - setFontToSmall(tabView); - setControlToSmall(tabView); - [tabView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - - - // setup tab - - tabViewItemSetup = [[NSTabViewItem alloc] init]; - [tabView addTabViewItem:tabViewItemSetup]; - [tabViewItemSetup setLabel:@"Setup"]; - NSRect const tabViewItemSetupFrame = [[tabViewItemSetup view] frame]; - - - // always show checkbox - alwaysShowButton = makeCheckbox(@"Always show this window at startup"); - [[tabViewItemSetup view] addSubview:alwaysShowButton]; - NSSize const alwaysShowButtonSize = [alwaysShowButton frame].size; - NSRect const alwaysShowButtonFrame = NSSizeAddXY(alwaysShowButtonSize, tabViewItemSetupFrame.size.width - alwaysShowButtonSize.width, 0); - [alwaysShowButton setFrame:alwaysShowButtonFrame]; - [alwaysShowButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin]; - - - // video mode selectors and labels - NSTextField * labelVideoMode = makeLabel(@"Video mode:"); - [[tabViewItemSetup view] addSubview:labelVideoMode]; - NSSize const labelVideoModeSize = [labelVideoMode frame].size; - [labelVideoMode setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; - - fullscreenButton = makeCheckbox(@"Fullscreen"); - [[tabViewItemSetup view] addSubview:fullscreenButton]; - NSSize const fullscreenButtonSize = [fullscreenButton frame].size; - [fullscreenButton setAction:@selector(fullscreenClicked:)]; - [fullscreenButton setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; - - videoMode3DPUButton = makeComboBox(); - [[tabViewItemSetup view] addSubview:videoMode3DPUButton]; - NSSize const videoMode3DPUButtonSize = [videoMode3DPUButton frame].size; - CGFloat const videoMode3DButtonX = labelVideoModeSize.width; // NSRightEdge(labelVideoModeFrame); - NSRect const videoMode3DPUButtonFrame = NSMakeRect(videoMode3DButtonX, tabViewItemSetupFrame.size.height - videoMode3DPUButtonSize.height, tabViewItemSetupFrame.size.width - videoMode3DButtonX - fullscreenButtonSize.width, videoMode3DPUButtonSize.height); - [videoMode3DPUButton setFrame:videoMode3DPUButtonFrame]; - [videoMode3DPUButton setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; - - NSRect const labelVideoModeFrame = NSSizeAddXY(labelVideoModeSize, 0, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - labelVideoModeSize.height) * 0.5f) + 1); - [labelVideoMode setFrame:labelVideoModeFrame]; - - NSRect const fullscreenButtonFrame = NSSizeAddXY(fullscreenButtonSize, tabViewItemSetupFrame.size.width - fullscreenButtonSize.width, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - fullscreenButtonSize.height) * 0.5f) + 1); - [fullscreenButton setFrame:fullscreenButtonFrame]; - - - // game selector and label - NSTextField * labelGame = makeLabel(@"Game:"); - [[tabViewItemSetup view] addSubview:labelGame]; - NSSize const labelGameSize = [labelGame frame].size; - NSRect const labelGameFrame = NSSizeAddXY(labelGameSize, 0, videoMode3DPUButtonFrame.origin.y - labelGameSize.height); - [labelGame setFrame:labelGameFrame]; - [labelGame setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; - - CGFloat const gameListVerticalPadding = 3; - CGFloat const gameListY = NSTopEdge(alwaysShowButtonFrame) + gameListVerticalPadding; - NSRect const gameListFrame = NSMakeRect(0, gameListY, tabViewItemSetupFrame.size.width, labelGameFrame.origin.y - gameListY - gameListVerticalPadding); - gameList = [[NSScrollView alloc] initWithFrame:gameListFrame]; - [[tabViewItemSetup view] addSubview:gameList]; - [gameList setBorderType:NSBezelBorder]; - [gameList setHasVerticalScroller:YES]; - [gameList setHasHorizontalScroller:NO]; - setControlToSmall([[gameList verticalScroller] cell]); - NSSize const gameListContentSize = [gameList contentSize]; - [gameList setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - - NSTableView * gameListTable = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, gameListContentSize.width, gameListContentSize.height)]; - [gameList setDocumentView:gameListTable]; - - NSTableColumn * nameColumn = [[NSTableColumn alloc] initWithIdentifier:@"0"]; - [gameListTable addTableColumn:nameColumn]; - NSTableColumn * fileColumn = [[NSTableColumn alloc] initWithIdentifier:@"1"]; - [gameListTable addTableColumn:fileColumn]; - [nameColumn setEditable:NO]; - [[nameColumn headerCell] setStringValue:@"Name"]; - [nameColumn setWidth:gameListContentSize.width * (2.f/3.f)]; - [fileColumn setEditable:NO]; - [[fileColumn headerCell] setStringValue:@"File"]; - [gameListTable sizeLastColumnToFit]; - [gameListTable setAutoresizingMask:NSViewWidthSizable]; - - - // message log tab - - tabViewItemMessageLog = [[NSTabViewItem alloc] init]; - [tabView addTabViewItem:tabViewItemMessageLog]; - [tabViewItemMessageLog setLabel:@"Message Log"]; - NSRect const tabViewItemMessageLogFrame = [[tabViewItemMessageLog view] frame]; - - - // message log - NSScrollView * messagesScrollView = [[NSScrollView alloc] initWithFrame:NSRectChangeXY(tabViewItemMessageLogFrame, 0, 0)]; - [[tabViewItemMessageLog view] addSubview:messagesScrollView]; - [messagesScrollView setBorderType:NSBezelBorder]; - [messagesScrollView setHasVerticalScroller:YES]; - [messagesScrollView setHasHorizontalScroller:NO]; - setControlToSmall([[messagesScrollView verticalScroller] cell]); - NSSize const messagesScrollViewContentSize = [messagesScrollView contentSize]; - [messagesScrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - - messagesView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, messagesScrollViewContentSize.width, messagesScrollViewContentSize.height)]; - [messagesScrollView setDocumentView:messagesView]; - [messagesView setEditable:NO]; - [messagesView setRichText:NO]; - setFontToSmall(messagesView); - [messagesView setMinSize:NSMakeSize(0.0, messagesScrollViewContentSize.height)]; - [messagesView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; - [messagesView setVerticallyResizable:YES]; - [messagesView setHorizontallyResizable:NO]; - [messagesView setAutoresizingMask:NSViewWidthSizable]; - - [[messagesView textContainer] setContainerSize:NSMakeSize(messagesScrollViewContentSize.width, FLT_MAX)]; - [[messagesView textContainer] setWidthTracksTextView:YES]; - } - - return self; -} - -- (BOOL)canBecomeKeyWindow -{ - return YES; -} - -- (BOOL)canBecomeMainWindow -{ - return YES; -} - -- (BOOL) windowShouldClose:(id)sender -{ - UNREFERENCED_PARAMETER(sender); - - retval = 0; - - return YES; -} - -- (void)dealloc -{ - [gamelistsrc release]; - [modeslist3d release]; - [super dealloc]; -} - -- (void)populateVideoModes:(BOOL)firstTime -{ - int i, mode3d, fullscreen = ([fullscreenButton state] == NSControlStateValueOn); - int idx3d = -1; - int xdim = 0, ydim = 0, bpp = 0; - - if (firstTime) { - xdim = settings.xdim3d; - ydim = settings.ydim3d; - bpp = settings.bpp3d; - } else { - mode3d = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue]; - if (mode3d >= 0) { - xdim = validmode[mode3d].xdim; - ydim = validmode[mode3d].ydim; - bpp = validmode[mode3d].bpp; - } - - } - mode3d = videoCheckMode(&xdim, &ydim, bpp, fullscreen, 1); - if (mode3d < 0) { - int i, cd[] = { 32, 24, 16, 15, 8, 0 }; - for (i=0; cd[i]; ) { if (cd[i] >= bpp) i++; else break; } - for ( ; cd[i]; i++) { - mode3d = videoCheckMode(&xdim, &ydim, cd[i], fullscreen, 1); - if (mode3d < 0) continue; - break; - } - } - - [modeslist3d release]; - [videoMode3DPUButton removeAllItems]; - - modeslist3d = [[NSMutableArray alloc] init]; - - for (i = 0; i < validmodecnt; i++) { - if (fullscreen == validmode[i].fs) { - if (i == mode3d) idx3d = [modeslist3d count]; - [modeslist3d addObject:[NSNumber numberWithInt:i]]; - [videoMode3DPUButton addItemWithTitle:[NSString stringWithFormat:@"%d %C %d %d-bpp", - validmode[i].xdim, 0xd7, validmode[i].ydim, validmode[i].bpp]]; - } - } - - if (idx3d >= 0) [videoMode3DPUButton selectItemAtIndex:idx3d]; -} - -- (void)fullscreenClicked:(id)sender -{ - UNREFERENCED_PARAMETER(sender); - - [self populateVideoModes:NO]; -} - -- (void)cancel:(id)sender -{ - UNREFERENCED_PARAMETER(sender); - - retval = 0; -} - -- (void)start:(id)sender -{ - UNREFERENCED_PARAMETER(sender); - - int mode = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue]; - if (mode >= 0) { - settings.xdim3d = validmode[mode].xdim; - settings.ydim3d = validmode[mode].ydim; - settings.bpp3d = validmode[mode].bpp; - settings.fullscreen = validmode[mode].fs; - } - - int row = [[gameList documentView] selectedRow]; - if (row >= 0) { - settings.grp = [[gamelistsrc grpAtIndex:row] entryptr]; - } - - settings.forcesetup = [alwaysShowButton state] == NSControlStateValueOn; - - retval = 1; -} - -- (void)setupRunMode -{ - videoGetModes(); - - [fullscreenButton setState: (settings.fullscreen ? NSControlStateValueOn : NSControlStateValueOff)]; - [alwaysShowButton setState: (settings.forcesetup ? NSControlStateValueOn : NSControlStateValueOff)]; - [self populateVideoModes:YES]; - - // enable all the controls on the Configuration page - NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator]; - NSControl *control; - while ((control = [enumerator nextObject])) - { - if ([control respondsToSelector:@selector(setEnabled:)]) - [control setEnabled:true]; - } - - gamelistsrc = [[GameListSource alloc] init]; - [[gameList documentView] setDataSource:gamelistsrc]; - [[gameList documentView] deselectAll:nil]; - - if (settings.grp) - { - int row = [gamelistsrc findIndexForGrpname:[NSString stringWithUTF8String:settings.grp->filename]]; - if (row >= 0) - { - [[gameList documentView] scrollRowToVisible:row]; -#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3 - [[gameList documentView] selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO]; -#else - [[gameList documentView] selectRow:row byExtendingSelection:NO]; -#endif - } - } - - [cancelButton setEnabled:true]; - [startButton setEnabled:true]; - - [tabView selectTabViewItem:tabViewItemSetup]; - [NSCursor unhide]; // Why should I need to do this? -} - -- (void)setupMessagesMode -{ - [tabView selectTabViewItem:tabViewItemMessageLog]; - - // disable all the controls on the Configuration page except "always show", so the - // user can enable it if they want to while waiting for something else to happen - NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator]; - NSControl *control; - while ((control = [enumerator nextObject])) - { - if (control != alwaysShowButton && [control respondsToSelector:@selector(setEnabled:)]) - [control setEnabled:false]; - } - - [cancelButton setEnabled:false]; - [startButton setEnabled:false]; -} - -- (void)putsMessage:(NSString *)str -{ - NSRange end; - NSTextStorage *text = [messagesView textStorage]; - BOOL shouldAutoScroll; - - shouldAutoScroll = ((int)NSMaxY([messagesView bounds]) == (int)NSMaxY([messagesView visibleRect])); - - end.location = [text length]; - end.length = 0; - - [text beginEditing]; - [messagesView replaceCharactersInRange:end withString:str]; - [text endEditing]; - - if (shouldAutoScroll) { - end.location = [text length]; - end.length = 0; - [messagesView scrollRangeToVisible:end]; - } -} - -@end - -static StartupWindow *startwin = nil; - -int startwin_open(void) -{ - if (startwin != nil) return 1; - - startwin = [[StartupWindow alloc] init]; - if (startwin == nil) return -1; - - [startwin setupMessagesMode]; - - [startwin center]; - [startwin makeKeyAndOrderFront:nil]; - - CreateApplicationMenus(); - - return 0; -} - -int startwin_close(void) -{ - if (startwin == nil) return 1; - - [startwin close]; - [startwin release]; - startwin = nil; - - return 0; -} - -int startwin_puts(const char *s) -{ - NSString *ns; - - if (!s) return -1; - if (startwin == nil) return 1; - - ns = [NSString stringWithUTF8String:s]; - [startwin putsMessage:ns]; - [ns release]; - - return 0; -} - -int startwin_settitle(const char *s) -{ - NSString *ns; - - if (!s) return -1; - if (startwin == nil) return 1; - - ns = [NSString stringWithUTF8String:s]; - [startwin setTitle:ns]; - [ns release]; - - return 0; -} - -int startwin_idle(void *v) -{ - UNREFERENCED_PARAMETER(v); - - if (startwin) - { - NSEvent *event; - do - { - event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate date] inMode:NSDefaultRunLoopMode dequeue:YES]; - [nsapp sendEvent:event]; - } - while (event != nil); - - [startwin displayIfNeeded]; - [nsapp updateWindows]; - } - - return 0; -} - - -int startwin_run(void) -{ - if (startwin == nil) return 0; - - settings.fullscreen = ud.setup.fullscreen; - settings.xdim3d = ud.setup.xdim; - settings.ydim3d = ud.setup.ydim; - settings.bpp3d = ud.setup.bpp; - settings.forcesetup = ud.setup.forcesetup; - settings.grp = g_selectedGrp; - - [startwin setupRunMode]; - - do - { - NSEvent *event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES]; - [nsapp sendEvent:event]; - [nsapp updateWindows]; - } - while (retval == -1); - - [startwin setupMessagesMode]; - [nsapp updateWindows]; - - if (retval) { - ud.setup.fullscreen = settings.fullscreen; - ud.setup.xdim = settings.xdim3d; - ud.setup.ydim = settings.ydim3d; - ud.setup.bpp = settings.bpp3d; - ud.setup.forcesetup = settings.forcesetup; - g_selectedGrp = settings.grp; - } - - return retval; -} diff --git a/source/platform/win32/game.bmp b/source/platform/win32/game.bmp deleted file mode 100644 index 51f4a38058bb11e722b40fa015b12371540277db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336054 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 a5P$##AOHafKmY;|fB*y_009ULA@Dyq8zvzD diff --git a/source/platform/win32/gameres.rc b/source/platform/win32/gameres.rc index a6b893658..8a8b332ea 100644 --- a/source/platform/win32/gameres.rc +++ b/source/platform/win32/gameres.rc @@ -1,40 +1,34 @@ -#define NEED_COMMCTRL_H -#include "../../build/include/windows_inc.h" -#include "startwin.game.h" +#include "afxres.h" +#include "resource.h" +#include "../../common/version.h" +#include "../../gitinfo.h" -RSRC_ICON ICON "game_icon.ico" -RSRC_BMP BITMAP "game.bmp" +IDI_ICON1 ICON "game_icon.ico" -WIN_STARTWIN DIALOGEX DISCARDABLE 20, 40, 260, 200 -STYLE DS_MODALFRAME | DS_CENTER | DS_SETFONT | DS_FIXEDSYS | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU -CAPTION "Startup" -FONT 8, "MS Shell Dlg" +IDD_IWADDIALOG DIALOGEX 0, 0, 224, 249 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Welcome" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN - CONTROL "", WIN_STARTWIN_BITMAP, "STATIC", SS_BITMAP | SS_CENTERIMAGE | WS_CHILD | WS_VISIBLE, 0, 0, 66, 172 - CONTROL "", WIN_STARTWIN_TABCTL, WC_TABCONTROL, WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 5, 250, 170 - CONTROL "&Start", WIN_STARTWIN_START, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 180, 48, 14 - CONTROL "&Cancel", WIN_STARTWIN_CANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 207, 180, 48, 14 - - CONTROL "", WIN_STARTWIN_MESSAGES, "EDIT", ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VSCROLL, 0, 0, 32, 32 -END -WIN_STARTWINPAGE_CONFIG DIALOGEX DISCARDABLE 20, 40, 279, 168 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD -CAPTION "Dialog" -FONT 8, "MS Shell Dlg" -BEGIN - CONTROL "&Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 6, 50, 8 - CONTROL "", IDCVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 4, 86, 56 - CONTROL "&Fullscreen", IDCFULLSCREEN, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 6, 46, 10 -//#if defined POLYMER && POLYMER != 0 -// CONTROL "&Polymer", IDCPOLYMER, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 203, 6, 40, 10 -//#endif - CONTROL "&Game:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 35, 100, 8 - CONTROL "", IDCDATA, "LISTBOX", LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS | LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 10, 45, 226, 43 - - CONTROL "Custom game content &directory:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 90, 160, 8 - CONTROL "", IDCGAMEDIR, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 10, 99, 226, 156 - CONTROL "&Enable ""autoload"" folder", IDCAUTOLOAD, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 116, 100, 8 - CONTROL "&Always show this window at startup", IDCALWAYSSHOW, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 118, 116, 140, 8 + ICON IDI_ICON1,IDC_STATIC,7,7,20,20 + LTEXT "Welcome to Demolition!",IDC_STATIC,42,8,180,8 + LTEXT "",IDC_WELCOME_VERSION,42,18,180,8 + GROUPBOX "Game selection",IDC_STATIC,8,32,208,117 + LTEXT "Select which game file (GRP) to run.",IDC_STATIC,12,44,190,8 + LISTBOX IDC_IWADLIST,12,56,200,87,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Video settings",IDC_STATIC,8,155,109,52 + CONTROL "Fullscreen",IDC_WELCOME_FULLSCREEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,65,167,48,10 + GROUPBOX "Resource settings",IDC_STATIC,123,155,95,52 + CONTROL "Disable autoload",IDC_WELCOME_NOAUTOLOAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,170,65,10 + //CONTROL "Load lights",IDC_WELCOME_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,180,51,10 + //CONTROL "Load brightmaps",IDC_WELCOME_BRIGHTMAPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,190,65,10 + CONTROL "Don't ask me this again",IDC_DONTASKIWAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,73,211,87,10 + DEFPUSHBUTTON "Play Demolition",IDOK,8,228,90,14 + PUSHBUTTON "Exit",IDCANCEL,166,228,50,14 + CONTROL "OpenGL",IDC_WELCOME_VULKAN1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,167,41,10 + CONTROL "Vulkan",IDC_WELCOME_VULKAN2,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,13,177,37,10 + CONTROL "SoftPoly",IDC_WELCOME_VULKAN3,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,13,188,43,10 END IDD_CRASHDIALOG DIALOGEX 0, 0, 415, 308 @@ -54,7 +48,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN EDITTEXT IDC_CRASHINFO,7,126,377,90,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL CONTROL "",IDC_PLEASETELLUS,"RichEdit20A",ES_MULTILINE | ES_READONLY,7,50,377,54,WS_EX_TRANSPARENT - LTEXT "(Optional) To help diagnose the cause of this error, please describe what you were doing when the error occured. If you were playing with custom wads, please also indicate where to obtain them:",IDC_STATIC,7,108,377,16,0,WS_EX_TRANSPARENT + LTEXT "(Optional) To help diagnose the cause of this error, please describe what you were doing when the error occured. If you were playing with custom data, please also indicate where to obtain them:",IDC_STATIC,7,108,377,16,0,WS_EX_TRANSPARENT CONTROL 131,IDC_DEADGUYVIEWER,"Static",SS_BITMAP,345,7,23,26 CONTROL "",IDC_CRASHHEADER,"RichEdit20A",ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY,18,13,306,25,WS_EX_TRANSPARENT CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,42,407,1 @@ -104,14 +98,14 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "FileDescription", "Demolition" - VALUE "FileVersion", STRFILEVER + VALUE "FileDescription", "Demolition " GIT_DESCRIPTION + VALUE "FileVersion", GIT_DESCRIPTION VALUE "InternalName", "Demolition" - VALUE "LegalCopyright", "Copyright © 2019 Christoph Oelckers, Copyright © 2018 EDuke32 Developers, 1996, 2003 3D Realms Entertainment" - VALUE "LegalTrademarks", "Duke Nukem® is a Registered Trademark of Gearbox Software, LLC." + VALUE "LegalCopyright", "Copyright © 2019 Christoph Oelckers, Copyright © 2018 EDuke32 Developers, 1996, 2003, 2005 3D Realms Entertainment" + VALUE "LegalTrademarks", "Duke Nukem® is a Registered Trademark of Gearbox Software, LLC.; Shadow Warrior® is a Registered Trademark of GHI Media LLC." VALUE "OriginalFilename", "demolition.exe" VALUE "ProductName", "Demolition" - VALUE "ProductVersion", STRPRODUCTVER + VALUE "ProductVersion", GIT_DESCRIPTION END END BLOCK "VarFileInfo" diff --git a/source/platform/win32/i_main.cpp b/source/platform/win32/i_main.cpp index 91f354f73..b02c25e1e 100644 --- a/source/platform/win32/i_main.cpp +++ b/source/platform/win32/i_main.cpp @@ -76,7 +76,7 @@ #include "s_music.h" #include "stats.h" -//#include "st_start.h" +#include "st_start.h" // MACROS ------------------------------------------------------------------ @@ -537,7 +537,7 @@ void RestoreConView() ShowWindow (GameTitleWindow, SW_SHOW); I_ShutdownInput (); // Make sure the mouse pointer is available. // Make sure the progress bar isn't visible. - //DeleteStartupScreen(); + DeleteStartupScreen(); } //========================================================================== diff --git a/source/platform/win32/i_system.cpp b/source/platform/win32/i_system.cpp index ea795c021..5af77c428 100644 --- a/source/platform/win32/i_system.cpp +++ b/source/platform/win32/i_system.cpp @@ -69,6 +69,7 @@ #include "stats.h" #include "v_text.h" #include "utf8.h" +#include "gamecontrol.h" #include "i_input.h" #include "c_dispatch.h" @@ -494,6 +495,153 @@ static void SetQueryIWad(HWND dialog) queryiwad = query; } +//========================================================================== +// +// IWADBoxCallback +// +// Dialog proc for the IWAD selector. +// +//========================================================================== + +BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND ctrl; + int i; + + switch (message) + { + case WM_INITDIALOG: + // Add our program name to the window title + { + WCHAR label[256]; + FString newlabel; + + GetWindowTextW(hDlg, label, countof(label)); + FString alabel(label); + newlabel.Format(GAMENAME " %s: %s", GetVersionString(), alabel.GetChars()); + auto wlabel = newlabel.WideString(); + SetWindowTextW(hDlg, wlabel.c_str()); + } + + // [SP] Upstreamed from Zandronum + char szString[256]; + + // Check the current video settings. + //SendDlgItemMessage( hDlg, vid_renderer ? IDC_WELCOME_OPENGL : IDC_WELCOME_SOFTWARE, BM_SETCHECK, BST_CHECKED, 0 ); + SendDlgItemMessage( hDlg, IDC_WELCOME_FULLSCREEN, BM_SETCHECK, vid_fullscreen ? BST_CHECKED : BST_UNCHECKED, 0 ); + switch (vid_preferbackend) + { + case 1: + SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN2, BM_SETCHECK, BST_CHECKED, 0 ); + break; + case 2: + SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN3, BM_SETCHECK, BST_CHECKED, 0 ); + break; + default: + SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN1, BM_SETCHECK, BST_CHECKED, 0 ); + break; + } + + + // [SP] This is our's + SendDlgItemMessage( hDlg, IDC_WELCOME_NOAUTOLOAD, BM_SETCHECK, disableautoload ? BST_CHECKED : BST_UNCHECKED, 0 ); + //SendDlgItemMessage( hDlg, IDC_WELCOME_LIGHTS, BM_SETCHECK, autoloadlights ? BST_CHECKED : BST_UNCHECKED, 0 ); + //SendDlgItemMessage( hDlg, IDC_WELCOME_BRIGHTMAPS, BM_SETCHECK, autoloadbrightmaps ? BST_CHECKED : BST_UNCHECKED, 0 ); + + // Set up our version string. + sprintf(szString, "Version %s.", GetVersionString()); + SetDlgItemTextA (hDlg, IDC_WELCOME_VERSION, szString); + + // Populate the list with all the IWADs found + ctrl = GetDlgItem(hDlg, IDC_IWADLIST); + for (i = 0; i < NumWads; i++) + { + const char *filepart = strrchr(WadList[i].Path, '/'); + if (filepart == NULL) + filepart = WadList[i].Path; + else + filepart++; + FStringf work("%s (%s)", WadList[i].Name.GetChars(), filepart); + std::wstring wide = work.WideString(); + SendMessage(ctrl, LB_ADDSTRING, 0, (LPARAM)wide.c_str()); + SendMessage(ctrl, LB_SETITEMDATA, i, (LPARAM)i); + } + SendMessage(ctrl, LB_SETCURSEL, DefaultWad, 0); + SetFocus(ctrl); + // Set the state of the "Don't ask me again" checkbox + ctrl = GetDlgItem(hDlg, IDC_DONTASKIWAD); + SendMessage(ctrl, BM_SETCHECK, queryiwad ? BST_UNCHECKED : BST_CHECKED, 0); + // Make sure the dialog is in front. If SHIFT was pressed to force it visible, + // then the other window will normally be on top. + SetForegroundWindow(hDlg); + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDCANCEL) + { + EndDialog (hDlg, -1); + } + else if (LOWORD(wParam) == IDOK || + (LOWORD(wParam) == IDC_IWADLIST && HIWORD(wParam) == LBN_DBLCLK)) + { + SetQueryIWad(hDlg); + // [SP] Upstreamed from Zandronum + vid_fullscreen = SendDlgItemMessage( hDlg, IDC_WELCOME_FULLSCREEN, BM_GETCHECK, 0, 0 ) == BST_CHECKED; + if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN3, BM_GETCHECK, 0, 0) == BST_CHECKED) + vid_preferbackend = 2; + else if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN2, BM_GETCHECK, 0, 0) == BST_CHECKED) + vid_preferbackend = 1; + else if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN1, BM_GETCHECK, 0, 0) == BST_CHECKED) + vid_preferbackend = 0; + + // [SP] This is our's. + disableautoload = SendDlgItemMessage( hDlg, IDC_WELCOME_NOAUTOLOAD, BM_GETCHECK, 0, 0 ) == BST_CHECKED; + //autoloadlights = SendDlgItemMessage( hDlg, IDC_WELCOME_LIGHTS, BM_GETCHECK, 0, 0 ) == BST_CHECKED; + //autoloadbrightmaps = SendDlgItemMessage( hDlg, IDC_WELCOME_BRIGHTMAPS, BM_GETCHECK, 0, 0 ) == BST_CHECKED; + ctrl = GetDlgItem (hDlg, IDC_IWADLIST); + EndDialog(hDlg, SendMessage (ctrl, LB_GETCURSEL, 0, 0)); + } + break; + } + return FALSE; +} + +//========================================================================== +// +// I_PickIWad +// +// Open a dialog to pick the IWAD, if there is more than one found. +// +//========================================================================== + +int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad) +{ + int vkey; + + if (stricmp(queryiwad_key, "shift") == 0) + { + vkey = VK_SHIFT; + } + else if (stricmp(queryiwad_key, "control") == 0 || stricmp (queryiwad_key, "ctrl") == 0) + { + vkey = VK_CONTROL; + } + else + { + vkey = 0; + } + if (showwin || (vkey != 0 && GetAsyncKeyState(vkey))) + { + WadList = wads; + NumWads = numwads; + DefaultWad = defaultiwad; + + return (int)DialogBox(g_hInst, MAKEINTRESOURCE(IDD_IWADDIALOG), + (HWND)Window, (DLGPROC)IWADBoxCallback); + } + return defaultiwad; +} + //========================================================================== // // I_SetCursor diff --git a/source/platform/win32/resource.h b/source/platform/win32/resource.h index 3a11a0c81..f6eff6188 100644 --- a/source/platform/win32/resource.h +++ b/source/platform/win32/resource.h @@ -89,10 +89,13 @@ #define IDC_NETSTARTPROGRESS 1079 #define IDC_NETSTARTMESSAGE 1080 #define IDC_NETSTARTCOUNT 1081 -#define IDC_STATIC_TITLE 1082 -#define IDC_STATIC_STARTUP 1083 +#define IDC_STATIC_TITLE 1082 +#define IDC_STATIC_STARTUP 1083 #define IDCE_ENVIRONMENTDIFFUSION 1085 +#define IDC_WELCOME_VULKAN2 1085 #define IDCS_ENVIRONMENTDIFFUSION 1086 +#define IDC_RADIO3 1086 +#define IDC_WELCOME_VULKAN3 1086 #define IDCE_ROOM 1087 #define IDCS_ROOM 1088 #define IDCE_ROOMHF 1089 @@ -143,26 +146,23 @@ #define IDCS_ROOMROLLOFFFACTOR 1134 #define IDCS_REFLECTIONSDELAY2 1135 #define IDCE_MODULATIONTIME2 1135 +#define IDC_WELCOME_VERSION 4019 +#define IDC_WELCOME_OPENGL 4020 +#define IDC_WELCOME_SOFTWARE 4021 +#define IDC_WELCOME_FULLSCREEN 4022 +#define IDC_WELCOME_NOAUTOLOAD 4023 +#define IDC_WELCOME_LIGHTS 4024 +#define IDC_WELCOME_BRIGHTMAPS 4025 +#define IDC_WELCOME_VULKAN 4026 +#define IDC_WELCOME_VULKAN1 4026 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 151 +#define _APS_NEXT_RESOURCE_VALUE 152 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1084 +#define _APS_NEXT_CONTROL_VALUE 1087 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif - -// [SP] Upstreamed from Zandronum -#define IDC_WELCOME_VERSION 4019 // [RC] "Welcome" screen. -#define IDC_WELCOME_OPENGL 4020 -#define IDC_WELCOME_SOFTWARE 4021 -#define IDC_WELCOME_FULLSCREEN 4022 - -// [SP] This is our's. -#define IDC_WELCOME_NOAUTOLOAD 4023 -#define IDC_WELCOME_LIGHTS 4024 -#define IDC_WELCOME_BRIGHTMAPS 4025 -#define IDC_WELCOME_VULKAN 4026 diff --git a/source/platform/win32/startwin.game.cpp b/source/platform/win32/startwin.game.cpp deleted file mode 100644 index 5853f2891..000000000 --- a/source/platform/win32/startwin.game.cpp +++ /dev/null @@ -1,598 +0,0 @@ -//------------------------------------------------------------------------- -/* -Copyright (C) 2010 EDuke32 developers and contributors - -This file is part of EDuke32. - -EDuke32 is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -//------------------------------------------------------------------------- - -#include "ns.h" // Must come before everything else! - -#ifndef _WIN32 -#error Only for Windows -#endif - -#include "renderlayer.h" - -#ifdef STARTUP_SETUP_WINDOW - -#define NEED_WINDOWSX_H -#define NEED_COMMCTRL_H -#define ONLY_USERDEFS - -#include "build.h" - -#include "compat.h" -#include "startwin.game.h" -#include "windows_inc.h" -#include "gamecontrol.h" - -#pragma warning(disable:4244) // There's just a bit too much of these in here... - - - -#define TAB_CONFIG 0 -#define TAB_MESSAGES 1 - -typedef struct { - int32_t fullscreen; - int32_t xdim; - int32_t ydim; - int32_t bpp; -} ud_setup_t; - -static struct -{ - int grp; - ud_setup_t shared; - int polymer; -} -settings; - -static HWND startupdlg; -static HWND pages[3]; -static int done = -1; -static int mode = TAB_CONFIG; - -static TArray *gamedata; - - -static inline void clearfilenames(void) -{ -} - -static inline void getfilenames(char const *path) -{ -} - -#define POPULATE_VIDEO 1 -#define POPULATE_CONFIG 2 -#define POPULATE_GAME 4 -#define POPULATE_GAMEDIRS 8 - -#ifdef INPUT_MOUSE -#undef INPUT_MOUSE -#endif - -#define INPUT_KB 0 -#define INPUT_MOUSE 1 -#define INPUT_JOYSTICK 2 -#define INPUT_ALL 3 - -// Thanks, Microsoft for not providing alternatives for the dialog control macros. :( -#undef SNDMSG -#define SNDMSG ::SendMessageA - -const char *controlstrings[] = { "Keyboard only", "Keyboard and mouse", "Keyboard and joystick", "All supported devices" }; - -static void PopulateForm(int32_t pgs) -{ - //char buf[512]; - - if (pgs & POPULATE_GAMEDIRS) - { - HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCGAMEDIR); - -#if 0 // This doesn't currently work and in its current form is useless anyway. It should offer a real directory picker. - getfilenames("/"); - (void)ComboBox_ResetContent(hwnd); - int const r = ComboBox_AddString(hwnd, "None"); - (void)ComboBox_SetItemData(hwnd, r, 0); - (void)ComboBox_SetCurSel(hwnd, r); - auto dirs = finddirs; - for (int i=1, j=1; dirs != NULL; dirs=dirs->next) - { - if (Bstrcasecmp(dirs->name, "autoload") == 0) - { - j++; - continue; - } - - (void)ComboBox_AddString(hwnd, dirs->name); - (void)ComboBox_SetItemData(hwnd, i, j); - - i++; - j++; - } -#endif - } - - - if (pgs & POPULATE_GAME) - { - HWND hwnd = GetDlgItem(pages[TAB_CONFIG], IDCDATA); - - int i=0; - for (auto& grp : *gamedata) - { - auto p = grp.FileName.LastIndexOfAny("/\\"); - auto c = grp.FileName.GetChars(); - if (p > 0) c += p+1; - FStringf grpinfo("%s\t%s", grp.FileInfo.name.GetChars(), c); - int const j = ListBox_AddString(hwnd, grpinfo.GetChars()); - (void)ListBox_SetItemData(hwnd, j, i); - i++; - } - } -} - -static INT_PTR CALLBACK ConfigPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDCFULLSCREEN: - settings.shared.fullscreen = !settings.shared.fullscreen; - PopulateForm(POPULATE_VIDEO); - return TRUE; - //case IDCPOLYMER: - // settings.polymer = !settings.polymer; - // if (settings.shared.bpp == 8) settings.shared.bpp = 32; - // PopulateForm(POPULATE_VIDEO); - // return TRUE; - case IDCVMODE: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - int i = ComboBox_GetCurSel((HWND)lParam); - if (i != CB_ERR) i = ComboBox_GetItemData((HWND)lParam, i); - if (i != CB_ERR) - { - settings.shared.xdim = validmode[i].xdim; - settings.shared.ydim = validmode[i].ydim; - settings.shared.bpp = validmode[i].bpp; - } - } - return TRUE; - case IDCALWAYSSHOW: - displaysetup = IsDlgButtonChecked(hwndDlg, IDCALWAYSSHOW) == BST_CHECKED; - return TRUE; - case IDCAUTOLOAD: - noautoload = (IsDlgButtonChecked(hwndDlg, IDCAUTOLOAD) != BST_CHECKED); - return TRUE; - case IDCGAMEDIR: - return TRUE; - case IDCDATA: - { - if (HIWORD(wParam) != LBN_SELCHANGE) break; - intptr_t i = ListBox_GetCurSel((HWND)lParam); - if (i != CB_ERR) i = ListBox_GetItemData((HWND)lParam, i); - if (i != CB_ERR) - { - settings.grp = i; - } - return TRUE; - } - default: - break; - } - break; - default: - break; - } - return FALSE; -} - - -static void SetPage(int pageNum) -{ - HWND tab = GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL); - auto const cur = SendMessageA(tab, TCM_GETCURSEL, 0, 0); - ShowWindow(pages[cur], SW_HIDE); - SendMessageA(tab, TCM_SETCURSEL, pageNum, 0); - ShowWindow(pages[pageNum], SW_SHOW); - mode = pageNum; - - SetFocus(GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL)); -} - -static void EnableConfig(bool n) -{ - //EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_CANCEL), n); - EnableWindow(GetDlgItem(startupdlg, WIN_STARTWIN_START), n); - EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCDATA), n); - EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCFULLSCREEN), n); - EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCGAMEDIR), n); - EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCINPUT), n); - //EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCPOLYMER), n); - EnableWindow(GetDlgItem(pages[TAB_CONFIG], IDCVMODE), n); -} - -static INT_PTR CALLBACK startup_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - static HBITMAP hbmp = NULL; - - switch (uMsg) - { - case WM_INITDIALOG: - { - // Fetch the positions (in screen coordinates) of all the windows we need to tweak - RECT chrome = {}; - AdjustWindowRect(&chrome, GetWindowLong(hwndDlg, GWL_STYLE), FALSE); - RECT rdlg; - GetWindowRect(hwndDlg, &rdlg); - - // Knock off the non-client area of the main dialogue to give just the client area - rdlg.left -= chrome.left; - rdlg.top -= chrome.top; - rdlg.right -= chrome.right; - rdlg.bottom -= chrome.bottom; - - RECT rtab; - GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL), &rtab); - - // Translate them to client-relative coordinates wrt the main dialogue window - rtab.right -= rtab.left - 1; - rtab.bottom -= rtab.top - 1; - rtab.left -= rdlg.left; - rtab.top -= rdlg.top; - - RECT rcancel; - GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_CANCEL), &rcancel); - - rcancel.right -= rcancel.left - 1; - rcancel.bottom -= rcancel.top - 1; - rcancel.left -= rdlg.left; - rcancel.top -= rdlg.top; - - RECT rstart; - GetWindowRect(GetDlgItem(hwndDlg, WIN_STARTWIN_START), &rstart); - - rstart.right -= rstart.left - 1; - rstart.bottom -= rstart.top - 1; - rstart.left -= rdlg.left; - rstart.top -= rdlg.top; - - // And then convert the main dialogue coordinates to just width/length - rdlg.right -= rdlg.left - 1; - rdlg.bottom -= rdlg.top - 1; - rdlg.left = 0; - rdlg.top = 0; - - // Load the bitmap into the bitmap control and fetch its dimensions - hbmp = LoadBitmap((HINSTANCE)GetModuleHandleA(nullptr), MAKEINTRESOURCE(RSRC_BMP)); - - HWND hwnd = GetDlgItem(hwndDlg, WIN_STARTWIN_BITMAP); - SendMessageA(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp); - - RECT r; - GetClientRect(hwnd, &r); - - int const xoffset = r.right; - int const yoffset = r.bottom - rdlg.bottom; - - // Shift and resize the controls that require it - rtab.left += xoffset; - rtab.bottom += yoffset; - rcancel.left += xoffset; - rcancel.top += yoffset; - rstart.left += xoffset; - rstart.top += yoffset; - rdlg.right += xoffset; - rdlg.bottom += yoffset; - - // Move the controls to their new positions - MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL), rtab.left, rtab.top, rtab.right, rtab.bottom, FALSE); - MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_CANCEL), rcancel.left, rcancel.top, rcancel.right, rcancel.bottom, FALSE); - MoveWindow(GetDlgItem(hwndDlg, WIN_STARTWIN_START), rstart.left, rstart.top, rstart.right, rstart.bottom, FALSE); - - // Move the main dialogue to the centre of the screen - HDC hdc = GetDC(NULL); - rdlg.left = (GetDeviceCaps(hdc, HORZRES) - rdlg.right) / 2; - rdlg.top = (GetDeviceCaps(hdc, VERTRES) - rdlg.bottom) / 2; - ReleaseDC(NULL, hdc); - MoveWindow(hwndDlg, rdlg.left + chrome.left, rdlg.top + chrome.left, - rdlg.right + (-chrome.left+chrome.right), rdlg.bottom + (-chrome.top+chrome.bottom), TRUE); - - // Add tabs to the tab control - { - static char textSetup[] = "Setup"; - static char textMessageLog[] = "Message Log"; - - hwnd = GetDlgItem(hwndDlg, WIN_STARTWIN_TABCTL); - - TCITEMA tab = {}; - tab.mask = TCIF_TEXT; - tab.pszText = textSetup; - SendMessageA(hwnd, TCM_INSERTITEMA, (WPARAM)TAB_CONFIG, (LPARAM)&tab); - tab.mask = TCIF_TEXT; - tab.pszText = textMessageLog; - SendMessageA(hwnd, TCM_INSERTITEMA, (WPARAM)TAB_MESSAGES, (LPARAM)&tab); - - // Work out the position and size of the area inside the tab control for the pages - ZeroMemory(&r, sizeof(r)); - GetClientRect(hwnd, &r); - SendMessageA(hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM)&r); - r.right -= r.left-1; - r.bottom -= r.top-1; - r.top += rtab.top; - r.left += rtab.left; - - // Create the pages and position them in the tab control, but hide them - pages[TAB_CONFIG] = CreateDialog((HINSTANCE)GetModuleHandleA(nullptr), MAKEINTRESOURCE(WIN_STARTWINPAGE_CONFIG), hwndDlg, ConfigPageProc); - SetWindowPos(pages[TAB_CONFIG], hwnd, r.left, r.top, r.right, r.bottom, SWP_HIDEWINDOW); - - pages[TAB_MESSAGES] = GetDlgItem(hwndDlg, WIN_STARTWIN_MESSAGES); - SetWindowPos(pages[TAB_MESSAGES], hwnd, r.left, r.top, r.right, r.bottom, SWP_HIDEWINDOW); - - // Tell the editfield acting as the console to exclude the width of the scrollbar - GetClientRect(pages[TAB_MESSAGES], &r); - r.right -= GetSystemMetrics(SM_CXVSCROLL)+4; - r.left = r.top = 0; - SendMessageA(pages[TAB_MESSAGES], EM_SETRECTNP,0,(LPARAM)&r); - - // Set a tab stop in the game data listbox - { - DWORD tabs[1] = { 150 }; - (void)ListBox_SetTabStops(GetDlgItem(pages[TAB_CONFIG], IDCDATA), 1, tabs); - } - - SetFocus(GetDlgItem(hwndDlg, WIN_STARTWIN_START)); - SetWindowTextA(hwndDlg, apptitle); - } - return FALSE; - } - - case WM_NOTIFY: - { - auto nmhdr = (LPNMHDR)lParam; - if (nmhdr->idFrom != WIN_STARTWIN_TABCTL) break; - int const cur = SendMessageA(nmhdr->hwndFrom, TCM_GETCURSEL,0,0); - switch (nmhdr->code) - { - case TCN_SELCHANGING: - case TCN_SELCHANGE: - if (cur < 0 || !pages[cur]) - break; - ShowWindow(pages[cur], nmhdr->code == TCN_SELCHANGING ? SW_HIDE : SW_SHOW); - return TRUE; - } - break; - } - - case WM_CLOSE: - if (mode == TAB_CONFIG) done = 0; - return TRUE; - - case WM_DESTROY: - if (hbmp) - { - DeleteObject(hbmp); - hbmp = NULL; - } - - if (pages[TAB_CONFIG]) - { - DestroyWindow(pages[TAB_CONFIG]); - pages[TAB_CONFIG] = NULL; - } - - startupdlg = NULL; - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case WIN_STARTWIN_CANCEL: - if (mode == TAB_CONFIG) done = 0; - return TRUE; - case WIN_STARTWIN_START: - done = 1; - return TRUE; - } - return FALSE; - - case WM_CTLCOLORSTATIC: - if ((HWND)lParam == pages[TAB_MESSAGES]) - return (BOOL)(intptr_t)GetSysColorBrush(COLOR_WINDOW); - break; - - default: - break; - } - - return FALSE; -} - - -int32_t startwin_open(void) -{ - if (startupdlg) return 1; - INITCOMMONCONTROLSEX icc = { sizeof(icc), ICC_TAB_CLASSES }; - InitCommonControlsEx(&icc); - startupdlg = CreateDialog((HINSTANCE)GetModuleHandleA(nullptr), MAKEINTRESOURCE(WIN_STARTWIN), NULL, startup_dlgproc); - if (startupdlg) - { - SetPage(TAB_MESSAGES); - EnableConfig(0); - return 0; - } - return -1; -} - -int32_t startwin_close(void) -{ - if (!startupdlg) return 1; - DestroyWindow(startupdlg); - startupdlg = NULL; - return 0; -} - -int32_t startwin_puts(const char *buf) -{ - if (!startupdlg) return 1; - - const HWND edctl = pages[TAB_MESSAGES]; - - if (!edctl) return -1; - - static HWND dactrl = NULL; - if (!dactrl) dactrl = GetDlgItem(startupdlg, WIN_STARTWIN_TABCTL); - - int const vis = ((int)SendMessageA(dactrl, TCM_GETCURSEL,0,0) == TAB_MESSAGES); - - if (vis) - SendMessageA(edctl, WM_SETREDRAW, FALSE, 0); - - int const curlen = SendMessageA(edctl, WM_GETTEXTLENGTH, 0,0); - SendMessageA(edctl, EM_SETSEL, (WPARAM)curlen, (LPARAM)curlen); - - int const numlines = SendMessageA(edctl, EM_GETLINECOUNT, 0, 0); - static bool newline = false; - const char *p = buf; - - while (*p) - { - if (newline) - { - SendMessageA(edctl, EM_REPLACESEL, 0, (LPARAM)"\r\n"); - newline = false; - } - const char *q = p; - while (*q && *q != '\n') q++; - static char workbuf[1024]; - Bmemcpy(workbuf, p, q-p); - if (*q == '\n') - { - if (!q[1]) - { - newline = true; - workbuf[q-p] = 0; - } - else - { - workbuf[q-p] = '\r'; - workbuf[q-p+1] = '\n'; - workbuf[q-p+2] = 0; - } - p = q+1; - } - else - { - workbuf[q-p] = 0; - p = q; - } - SendMessageA(edctl, EM_REPLACESEL, 0, (LPARAM)workbuf); - } - - int const newnumlines = SendMessageA(edctl, EM_GETLINECOUNT, 0, 0); - SendMessageA(edctl, EM_LINESCROLL, 0, newnumlines - numlines); - - if (vis) - SendMessageA(edctl, WM_SETREDRAW, TRUE, 0); - - return 0; -} - -int32_t startwin_settitle(const char *str) -{ - if (!startupdlg) return 1; - SetWindowTextA(startupdlg, str); - return 0; -} - -int32_t startwin_idle(void *v) -{ - if (!startupdlg || !IsWindow(startupdlg)) return 0; - if (IsDialogMessage(startupdlg, (MSG *)v)) return 1; - return 0; -} - -int32_t startwin_run(void) -{ - if (!startupdlg) return 1; - - done = -1; - - SetPage(TAB_CONFIG); - EnableConfig(1); - - settings.shared = { 0, 0, 0, 0 }; - settings.grp = 0; - - PopulateForm(-1); - - do - { - MSG msg; - - switch (GetMessage(&msg, NULL, 0,0)) - { - case 0: - done = 1; - break; - case -1: - return -1; - default: - if (IsWindow(startupdlg) && IsDialogMessage(startupdlg, &msg)) - break; - TranslateMessage(&msg); - DispatchMessage(&msg); - break; - } - } - while (done < 0); - - SetPage(TAB_MESSAGES); - EnableConfig(0); - - return done; -} - -int ShowStartupWindow(TArray &groups) -{ - gamedata = &groups; - startwin_open(); - startwin_settitle("Demolition"); - - if (1)//readSetup < 0 || (!g_noSetup && (displaysetup)) || g_commandSetup) - { - auto choice = startwin_run(); - if (choice == 0) - { - startwin_close(); - return - 1; - } - } - startwin_close(); - return settings.grp; -} - -#endif // STARTUP_SETUP_WINDOW - - diff --git a/source/platform/win32/startwin.game.h b/source/platform/win32/startwin.game.h deleted file mode 100644 index 443491bb7..000000000 --- a/source/platform/win32/startwin.game.h +++ /dev/null @@ -1,121 +0,0 @@ -//------------------------------------------------------------------------- -/* -Copyright (C) 2010 EDuke32 developers and contributors -Copyright (C) 2019 Christoph Oelckers - -Demolition is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -//------------------------------------------------------------------------- - -// resource ids -#define WIN_STARTWIN 1000 -#define WIN_STARTWINPAGE_CONFIG 2000 -#define WIN_STARTWIN_BITMAP 100 // banner bitmap -#define WIN_STARTWIN_TABCTL 101 -#define WIN_STARTWIN_CANCEL IDCANCEL -#define WIN_STARTWIN_START IDOK - -#define WIN_STARTWIN_MESSAGES 104 // output list box -#define IDD_CRASHDIALOG 105 -#define IDD_CRASHDETAILS 106 -#define IDD_CRASHOVERVIEW 107 -#define IDD_ERRORPANE 108 - -#define RSRC_ICON 100 -#define RSRC_BMP 200 - -// config page -#define IDCFULLSCREEN 100 -#define IDCVMODE 101 -#define IDCSOUNDDRV 102 -#define IDCMIDIDEV 103 -#define IDCCDADEV 104 -#define IDCALWAYSSHOW 105 -#define IDCDATA 106 -#define IDCGAMEDIR 107 -#define IDCPOLYMER 108 -#define IDCAUTOLOAD 109 -#define IDCINPUT 110 - -#define IDC_STATIC (-1) -#define IDC_ERRORMESSAGE 1004 -#define IDQUIT 1005 -#define IDC_IWADLIST 1006 -#define IDC_DONTASKIWAD 1007 -#define IDC_SPIN1 1010 -#define IDC_SPINID1 1010 -#define IDC_CRASHINFO 1011 -#define IDC_SPINID2 1011 -#define IDC_TOOLTIP1 1012 -#define IDCE_ENVIRONMENTSIZE 1025 -#define IDCS_ENVIRONMENTSIZE 1026 -#define IDC_DECAYTIMESCALE 1027 -#define IDC_REFLECTIONSSCALE 1028 -#define IDC_REFLECTIONSDELAYSCALE 1029 -#define IDC_REVERBSCALE 1030 -#define IDC_REVERBDELAYSCALE 1031 -#define IDC_DECAYHFLIMIT 1032 -#define IDC_ECHOTIMESCALE 1033 -#define IDC_MODULATIONTIMESCALE 1034 -#define IDC_DUMMY 1035 -#define IDC_NEW 1036 -#define IDC_SAVE 1037 -#define IDC_REVERT 1038 -#define IDC_CURRENTENVIRONMENT 1039 -#define IDC_ID2 1040 -#define IDC_ID1 1041 -#define IDC_SHOWIDS 1043 -#define IDC_LIST3 1047 -#define IDC_ENVIRONMENTLIST 1047 -#define IDC_SIZEBOX 1048 -#define IDC_EDIT1 1049 -#define IDC_NEWENVNAME 1049 -#define IDC_CRASHFILECONTENTS 1049 -#define IDC_BOINGEDIT 1049 -#define IDC_EDITID1 1050 -#define IDC_EDITID2 1051 -#define IDC_HOTKEY1 1053 -#define IDC_LIST1 1054 -#define IDC_ENVLIST 1054 -#define IDC_CRASHFILES 1054 -#define IDC_SELECTALL 1055 -#define IDC_SELECTNONE 1056 -#define IDC_SAVEGROUP 1057 -#define IDC_TESTEAX 1058 -#define IDC_RICHEDIT21 1059 -#define IDC_CRASHHEADER 1059 -#define IDC_RICHEDIT22 1061 -#define IDC_PLEASETELLUS 1061 -#define IDC_BUTTON2 1062 -#define IDC_CRASHDETAILS 1062 -#define IDC_DEADGUYVIEWER 1063 -#define IDC_CRASHFILESIZE 1066 -#define IDC_BUTTON1 1071 -#define IDC_BOINGSTATUS 1072 -#define IDC_BOINGPROGRESS 1073 -#define IDC_TAB1 1074 -#define IDC_CRASHTAB 1074 -#define IDC_RICHEDIT23 1075 -#define IDC_CRASHSUMMARY 1075 -#define IDC_ERRORTEXT 1076 -#define IDC_ICONPIC 1077 -#define IDC_DIVIDERBAR 1078 -#define IDC_PROGRESS1 1079 -#define IDC_NETSTARTPROGRESS 1079 -#define IDC_NETSTARTMESSAGE 1080 -#define IDC_NETSTARTCOUNT 1081 -#define IDC_STATIC_TITLE 1082 -#define IDC_STATIC_STARTUP 1083 -#define IDC_SAVEREPORT 1084