mirror of
https://github.com/odamex/odamex
synced 2026-08-19 02:23:09 -04:00
656 lines
18 KiB
C++
656 lines
18 KiB
C++
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id$
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
// Copyright (C) 2006-2026 by The Odamex Team.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// 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.
|
|
//
|
|
// DESCRIPTION:
|
|
// Boot GUI for WAD selection.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "odamex.h"
|
|
|
|
#include "gui_boot.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "FL/Fl.H"
|
|
#include "FL/Fl_Box.H"
|
|
#include "FL/Fl_Button.H"
|
|
#include "FL/Fl_Check_Browser.H"
|
|
#include "FL/Fl_Check_Button.H"
|
|
#include "FL/Fl_Hold_Browser.H"
|
|
#include "FL/Fl_Native_File_Chooser.H"
|
|
#include "FL/Fl_Return_Button.H"
|
|
#include "FL/Fl_Tabs.H"
|
|
#include "FL/Fl_Window.H"
|
|
#include "FL/fl_ask.H"
|
|
|
|
#include "gui_common.h"
|
|
|
|
#include "i_system.h"
|
|
#include "w_ident.h"
|
|
|
|
// -- Externals --
|
|
|
|
void CL_QuitCommand();
|
|
EXTERN_CVAR(i_skipbootwin);
|
|
EXTERN_CVAR(waddirs);
|
|
|
|
// ---------------
|
|
|
|
typedef std::vector<scannedIWAD_t> scannedIWADs_t;
|
|
typedef std::vector<std::pair<scannedPWAD_t, bool>> scannedPWADs_t;
|
|
typedef std::vector<scannedPWAD_t*> scannedPWADPtrs_t;
|
|
|
|
// display strings for options tab and their corresponding command line arguments
|
|
const std::vector<std::pair<std::string, std::string> > OPTIONS_LIST = {
|
|
{"No Monsters", "-nomonsters"},
|
|
{"Fast Monsters", "-fast"},
|
|
{"Respawn Monsters", "-respawn"},
|
|
{"Pistol Start", "-pistolstart"},
|
|
{"Spawn Multiplayer Things", "-coop-things"}
|
|
};
|
|
|
|
/**
|
|
* @brief Find the PWAD pointer in the scanned WAD array.
|
|
*/
|
|
static auto FindScanned(const std::vector<std::pair<std::string, int>>& filterIndices, const scannedPWADs_t& pwads, const scannedPWAD_t* pwad)
|
|
{
|
|
int i = 0;
|
|
for (const auto& [name, index] : filterIndices)
|
|
{
|
|
if (name == pwad->filename)
|
|
{
|
|
return std::make_pair(i, index);
|
|
}
|
|
i++;
|
|
}
|
|
i = 0;
|
|
for (const auto& [scannedPWAD, _] : pwads)
|
|
{
|
|
if (&scannedPWAD == pwad)
|
|
{
|
|
return std::make_pair(-1, i);
|
|
}
|
|
i++;
|
|
}
|
|
return std::make_pair(-1, -1);
|
|
}
|
|
|
|
/**
|
|
* @brief Add a scanned PWAD from the pointer list - unless there's a dupe.
|
|
*/
|
|
static void AddSelected(scannedPWADPtrs_t& mut, scannedPWAD_t* pwad)
|
|
{
|
|
scannedPWADPtrs_t::iterator it = std::find(mut.begin(), mut.end(), pwad);
|
|
if (it == mut.end())
|
|
{
|
|
mut.push_back(pwad);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Erase a scanned PWAD from the pointer list.
|
|
*/
|
|
static void EraseSelected(scannedPWADPtrs_t& mut, scannedPWAD_t* pwad)
|
|
{
|
|
scannedPWADPtrs_t::iterator it = std::find(mut.begin(), mut.end(), pwad);
|
|
if (it != mut.end())
|
|
{
|
|
mut.erase(it);
|
|
}
|
|
}
|
|
|
|
const scannedIWAD_t* g_SelectedIWAD;
|
|
scannedWADs_t g_SelectedWADs;
|
|
|
|
constexpr int WINDOW_WIDTH = 425;
|
|
constexpr int WINDOW_HEIGHT = 240;
|
|
|
|
class BootWindow : public Fl_Window
|
|
{
|
|
Fl_Group* m_tabIWAD;
|
|
Fl_Group* m_tabPWADs;
|
|
std::string m_genWADDirs;
|
|
scannedIWADs_t m_IWADs;
|
|
scannedPWADs_t m_PWADs;
|
|
scannedPWADPtrs_t m_selectedPWADs;
|
|
Fl_Hold_Browser* m_IWADBrowser;
|
|
Fl_Check_Browser* m_PWADSelectBrowser;
|
|
Fl_Hold_Browser* m_PWADOrderBrowser;
|
|
Fl_Check_Browser* m_gameOptionsBrowser;
|
|
StringTokens m_WADDirs;
|
|
Fl_Hold_Browser* m_WADDirList;
|
|
Fl_Input* m_searchPWADs;
|
|
std::vector<std::pair<std::string, int>> m_filterIndices;
|
|
|
|
public:
|
|
BootWindow(int X, int Y, int W, int H, const char* L)
|
|
: Fl_Window(X, Y, W, H, L), m_genWADDirs(), m_IWADs(), m_PWADs(), m_selectedPWADs(), m_WADDirs(), m_filterIndices()
|
|
{
|
|
{
|
|
Fl_Tabs* tabs = new Fl_Tabs(0, 0, 425, 200);
|
|
{
|
|
tabs->callback(tabsCB, static_cast<void*>(this));
|
|
tabs->when(FL_WHEN_CHANGED);
|
|
m_tabIWAD = new Fl_Group(0, 25, 425, 175, "Game Select");
|
|
{
|
|
Fl_Box* logo = new Fl_Box(10, 35, 115, 155);
|
|
logo->image(GUIRes::icon_odamex_128());
|
|
logo->align(Fl_Align(512));
|
|
} // Fl_Box* logo
|
|
{
|
|
m_IWADBrowser = new Fl_Hold_Browser(135, 35, 280, 155);
|
|
m_IWADBrowser->callback(BootWindow::doPlayCB, static_cast<void*>(this));
|
|
m_IWADBrowser->when(FL_WHEN_ENTER_KEY);
|
|
} // Fl_Browser* m_IWADBrowser
|
|
m_tabIWAD->end();
|
|
} // Fl_Group* tabIWAD
|
|
{
|
|
m_tabPWADs = new Fl_Group(0, 25, 425, 175, "PWAD Select");
|
|
{
|
|
m_searchPWADs = new Fl_Input(36, 35, 154, 20);
|
|
m_searchPWADs->label("@search");
|
|
m_searchPWADs->callback(BootWindow::doSearchCB, static_cast<void*>(this));
|
|
m_searchPWADs->when(FL_WHEN_CHANGED);
|
|
} // Fl_Input* m_searchPWADs
|
|
{
|
|
m_PWADSelectBrowser = new Fl_Check_Browser(10, 65, 183, 135);
|
|
m_PWADSelectBrowser->callback(BootWindow::scanCheckedPWADsCB,
|
|
static_cast<void*>(this));
|
|
m_PWADSelectBrowser->when(FL_WHEN_CHANGED);
|
|
} // Fl_Check_Browser* m_PWADSelectBrowser
|
|
{
|
|
m_PWADOrderBrowser = new Fl_Hold_Browser(203, 65, 182, 125);
|
|
} // Fl_Hold_Browser* m_PWADOrderBrowser
|
|
{
|
|
Fl_Box* o = new Fl_Box(203, 35, 182, 20, "Change Load Order");
|
|
} // Fl_Box* o
|
|
{
|
|
Fl_Button* doWADUp = new Fl_Button(395, 90, 20, 20, "@2<<");
|
|
doWADUp->callback(BootWindow::doWADUpCB, static_cast<void*>(this));
|
|
} // Fl_Button* doWADUp
|
|
{
|
|
Fl_Button* doWADDown = new Fl_Button(395, 115, 20, 20, "@2>>");
|
|
doWADDown->callback(BootWindow::doWADDownCB,
|
|
static_cast<void*>(this));
|
|
} // Fl_Button* doWADDown
|
|
{
|
|
Fl_Button* doWADRemove = new Fl_Button(395, 140, 20, 20, "@1+");
|
|
doWADRemove->callback(BootWindow::doWADRemoveCB,
|
|
static_cast<void*>(this));
|
|
} // Fl_Button* doWADRemove
|
|
m_tabPWADs->end();
|
|
} // Fl_Group* tabPWADs
|
|
{
|
|
Fl_Group* tabGameOptions =
|
|
new Fl_Group(0, 25, 425, 175, "Game Options");
|
|
{
|
|
Fl_Box* o = new Fl_Box(
|
|
10, 35, 405, 20,
|
|
"Set gameplay options to modify your experience.");
|
|
o->align(Fl_Align(132 | FL_ALIGN_INSIDE));
|
|
} // Fl_Box* o
|
|
{
|
|
m_gameOptionsBrowser = new Fl_Check_Browser(10, 65, 405, 125);
|
|
for (const auto& option : OPTIONS_LIST)
|
|
{
|
|
m_gameOptionsBrowser->add(option.first.c_str());
|
|
}
|
|
}
|
|
tabGameOptions->end();
|
|
|
|
} // Fl_Group* tabGameOptions
|
|
{
|
|
Fl_Group* tabWADDirs =
|
|
new Fl_Group(0, 25, 425, 175, "Resource Locations");
|
|
tabWADDirs->hide();
|
|
{
|
|
Fl_Box* o = new Fl_Box(
|
|
10, 35, 405, 20,
|
|
"Add folders containing WAD files here so Odamex can find them.");
|
|
o->align(Fl_Align(132 | FL_ALIGN_INSIDE));
|
|
} // Fl_Box* o
|
|
{
|
|
m_WADDirList = new Fl_Hold_Browser(10, 65, 375, 125);
|
|
} // Fl_Browser* wadDirList
|
|
{
|
|
Fl_Button* doDirAdd = new Fl_Button(395, 65, 20, 20, "@+");
|
|
doDirAdd->callback(BootWindow::doDirAddCB, static_cast<void*>(this));
|
|
} // Fl_Button* doDirAdd
|
|
{
|
|
Fl_Button* doDirUp = new Fl_Button(395, 90, 20, 20, "@2<<");
|
|
doDirUp->callback(BootWindow::doDirUpCB, static_cast<void*>(this));
|
|
} // Fl_Button* doDirUp
|
|
{
|
|
Fl_Button* doDirDown = new Fl_Button(395, 115, 20, 20, "@2>>");
|
|
doDirDown->callback(BootWindow::doDirDownCB,
|
|
static_cast<void*>(this));
|
|
} // Fl_Button* doDirDown
|
|
{
|
|
Fl_Button* doDirRemove = new Fl_Button(395, 140, 20, 20, "@1+");
|
|
doDirRemove->callback(BootWindow::doDirRemoveCB,
|
|
static_cast<void*>(this));
|
|
} // Fl_Button* doDirRemove
|
|
tabWADDirs->end();
|
|
} // Fl_Group* tabWADDirs
|
|
tabs->end();
|
|
} // Fl_Tabs* tabs
|
|
{
|
|
Fl_Check_Button* notAgain =
|
|
new Fl_Check_Button(10, 210, 20, 20, "Don\'t Show This Again");
|
|
notAgain->down_box(FL_DOWN_BOX);
|
|
notAgain->callback(BootWindow::doDontShowCB);
|
|
notAgain->value(::i_skipbootwin);
|
|
} // Fl_Check_Button* notAgain
|
|
{
|
|
Fl_Button* doQuit = new Fl_Button(275, 210, 65, 20, "Quit");
|
|
doQuit->callback(BootWindow::doQuitCB);
|
|
} // Fl_Button* doQuit
|
|
{
|
|
Fl_Return_Button* doPlay = new Fl_Return_Button(350, 210, 65, 20, "Play!");
|
|
doPlay->callback(BootWindow::doPlayCB, static_cast<void*>(this));
|
|
} // Fl_Return_Button* doPlay
|
|
end();
|
|
callback(BootWindow::doCallback);
|
|
GUI_SetIcon(this);
|
|
}
|
|
|
|
// -- Game Select --
|
|
|
|
static void tabsCB(Fl_Widget* w, void* data)
|
|
{
|
|
Fl_Tabs* tabs = static_cast<Fl_Tabs*>(w);
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
Fl_Group* clicked = static_cast<Fl_Group*>(tabs->value());
|
|
|
|
// Have waddirs changed?
|
|
bool waddirsChanged = boot->m_genWADDirs != ::waddirs;
|
|
|
|
// User clicked on the first tab, regenerate the
|
|
// list of IWADs if waddirs changed.
|
|
if ((clicked == boot->m_tabIWAD) && waddirsChanged)
|
|
{
|
|
boot->rescanIWADs();
|
|
return;
|
|
}
|
|
|
|
bool pwadsIsEmpty = boot->m_PWADSelectBrowser->nitems() == 0;
|
|
|
|
// User clicked on the second tab, regenerate the
|
|
// list of PWADs if waddirs changed or browser is empty.
|
|
if ((clicked == boot->m_tabPWADs) && (pwadsIsEmpty || waddirsChanged))
|
|
{
|
|
boot->rescanPWADs();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void doCallback(Fl_Widget*, void*) { CL_QuitCommand(); }
|
|
|
|
static void doDontShowCB(Fl_Widget* w, void*)
|
|
{
|
|
Fl_Check_Button* check = static_cast<Fl_Check_Button*>(w);
|
|
::i_skipbootwin.Set(check->value());
|
|
}
|
|
|
|
static void doQuitCB(Fl_Widget*, void*) { CL_QuitCommand(); }
|
|
|
|
static void doPlayCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
if (boot->selectedIWAD() == NULL)
|
|
{
|
|
// A valid IWAD isn't selected.
|
|
fl_message_title("Play Odamex");
|
|
fl_alert("Please select a game to play.");
|
|
return;
|
|
}
|
|
|
|
boot->selectedWADs();
|
|
boot->setOptions();
|
|
Fl::delete_widget(boot);
|
|
}
|
|
|
|
// -- PWAD Boot Order --
|
|
|
|
static void doSearchCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
boot->filterPWADs();
|
|
}
|
|
|
|
static void doWADUpCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
const int val = boot->m_PWADOrderBrowser->value() - 1;
|
|
if (val <= 0 || val >= static_cast<int>(boot->m_selectedPWADs.size()))
|
|
return;
|
|
|
|
std::iter_swap(boot->m_selectedPWADs.begin() + val,
|
|
boot->m_selectedPWADs.begin() + val - 1);
|
|
boot->updatePWADOrderBrowser();
|
|
boot->m_PWADOrderBrowser->value(val);
|
|
}
|
|
|
|
static void doWADDownCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
const int val = boot->m_PWADOrderBrowser->value() - 1;
|
|
if (val < 0 || val >= static_cast<int>(boot->m_selectedPWADs.size() - 1))
|
|
return;
|
|
|
|
std::iter_swap(boot->m_selectedPWADs.begin() + val,
|
|
boot->m_selectedPWADs.begin() + val + 1);
|
|
boot->updatePWADOrderBrowser();
|
|
boot->m_PWADOrderBrowser->value(val + 2);
|
|
}
|
|
|
|
/**
|
|
* @brief Removes a WAD from the PWAD selection list.
|
|
*/
|
|
static void doWADRemoveCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
// Figure out which PWAD we're removing.
|
|
const size_t removeIDX = size_t(boot->m_PWADOrderBrowser->value()) - 1;
|
|
if (removeIDX > boot->m_selectedPWADs.size())
|
|
{
|
|
return;
|
|
}
|
|
scannedPWAD_t* selected = boot->m_selectedPWADs[removeIDX];
|
|
|
|
// Uncheck the selected PWAD from the selection array.
|
|
auto [selectIndex, pwadIndex] = FindScanned(boot->m_filterIndices, boot->m_PWADs, selected);
|
|
if (pwadIndex == -1)
|
|
return;
|
|
boot->m_PWADs[pwadIndex].second = false;
|
|
if (selectIndex != -1)
|
|
boot->m_PWADSelectBrowser->checked(selectIndex + 1, 0);
|
|
|
|
// Erase the selected PWAD from the order array.
|
|
EraseSelected(boot->m_selectedPWADs, boot->m_selectedPWADs[removeIDX]);
|
|
boot->updatePWADOrderBrowser();
|
|
}
|
|
|
|
// -- Resource Locations --
|
|
|
|
/**
|
|
* @brief Adds a directory to the WAD dir list.
|
|
*/
|
|
static void doDirAddCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
Fl_Native_File_Chooser chooser;
|
|
chooser.title("Add Directory");
|
|
chooser.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY);
|
|
switch (chooser.show())
|
|
{
|
|
case 1: // Cancelled.
|
|
case -1: // Failed.
|
|
return;
|
|
default: // Picked a directory.
|
|
boot->m_WADDirs.push_back(chooser.filename());
|
|
boot->setWADDirs();
|
|
boot->updateWADDirBrowser();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void doDirUpCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
const int val = boot->m_WADDirList->value() - 1;
|
|
if (val <= 0 || val >= static_cast<int>(boot->m_WADDirs.size()))
|
|
return;
|
|
|
|
std::iter_swap(boot->m_WADDirs.begin() + val, boot->m_WADDirs.begin() + val - 1);
|
|
boot->setWADDirs();
|
|
boot->updateWADDirBrowser();
|
|
boot->m_WADDirList->value(val);
|
|
}
|
|
|
|
static void doDirDownCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
const int val = boot->m_WADDirList->value() - 1;
|
|
if (val < 0 || val >= static_cast<int>(boot->m_WADDirs.size() - 1))
|
|
return;
|
|
|
|
std::iter_swap(boot->m_WADDirs.begin() + val, boot->m_WADDirs.begin() + val + 1);
|
|
boot->setWADDirs();
|
|
boot->updateWADDirBrowser();
|
|
boot->m_WADDirList->value(val + 2);
|
|
}
|
|
|
|
/**
|
|
* @brief Removes a directory from the WAD dir list.
|
|
*/
|
|
static void doDirRemoveCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
const int val = boot->m_WADDirList->value() - 1;
|
|
if (val < 0 || val >= static_cast<int>(boot->m_WADDirs.size()))
|
|
return;
|
|
|
|
boot->m_WADDirs.erase(boot->m_WADDirs.begin() + val);
|
|
boot->setWADDirs();
|
|
boot->updateWADDirBrowser();
|
|
}
|
|
|
|
void rescanIWADs()
|
|
{
|
|
m_IWADBrowser->clear();
|
|
m_IWADs = M_ScanIWADs();
|
|
for (const auto& iwad : m_IWADs)
|
|
{
|
|
m_IWADBrowser->add(iwad.id->mNiceName.c_str(), (void*)iwad.id);
|
|
}
|
|
m_genWADDirs = ::waddirs.str();
|
|
}
|
|
|
|
void rescanPWADs()
|
|
{
|
|
m_PWADSelectBrowser->clear();
|
|
int i = 0;
|
|
for (const auto& pwad : M_ScanPWADs())
|
|
{
|
|
m_PWADs.emplace_back(pwad, false);
|
|
m_PWADSelectBrowser->add(pwad.filename.c_str());
|
|
m_filterIndices.emplace_back(pwad.filename, i);
|
|
i++;
|
|
}
|
|
m_genWADDirs = ::waddirs.str();
|
|
|
|
// clear order browser since selection browser is being reset
|
|
m_PWADOrderBrowser->clear();
|
|
m_selectedPWADs.clear();
|
|
}
|
|
|
|
void filterPWADs()
|
|
{
|
|
m_filterIndices.clear();
|
|
m_PWADSelectBrowser->clear();
|
|
int i = 0;
|
|
for (const auto& [pwad, checked] : m_PWADs)
|
|
{
|
|
if (m_searchPWADs->value()[0] == 0 ||
|
|
StdStringFind(pwad.filename, m_searchPWADs->value(), 0, m_searchPWADs->size(), true) != std::string::npos)
|
|
{
|
|
m_PWADSelectBrowser->add(pwad.filename.c_str(), checked);
|
|
m_filterIndices.emplace_back(pwad.filename, i);
|
|
}
|
|
i++;
|
|
}
|
|
m_PWADSelectBrowser->redraw();
|
|
}
|
|
|
|
/**
|
|
* @brief Places selected PWADs into the order browser for load order selection.
|
|
*/
|
|
static void scanCheckedPWADsCB(Fl_Widget*, void* data)
|
|
{
|
|
BootWindow* boot = static_cast<BootWindow*>(data);
|
|
|
|
// Scan all PWADs in the selection browser to see if they're checked.
|
|
for (size_t i = 1; i <= boot->m_PWADSelectBrowser->nitems(); i++)
|
|
{
|
|
auto& [pwad, selected] = boot->m_PWADs[boot->m_filterIndices[i - 1].second];
|
|
if (boot->m_PWADSelectBrowser->checked(static_cast<int>(i)))
|
|
{
|
|
selected = true;
|
|
AddSelected(boot->m_selectedPWADs, &pwad);
|
|
}
|
|
else
|
|
{
|
|
selected = false;
|
|
EraseSelected(boot->m_selectedPWADs, &pwad);
|
|
}
|
|
}
|
|
|
|
// Update the PWAD order browser.
|
|
boot->updatePWADOrderBrowser();
|
|
}
|
|
|
|
/**
|
|
* @brief Update the visible PWAD order browser widget from the vector.
|
|
*/
|
|
void updatePWADOrderBrowser()
|
|
{
|
|
const int val = m_PWADOrderBrowser->value();
|
|
m_PWADOrderBrowser->clear();
|
|
for (const auto& pwad : m_selectedPWADs)
|
|
{
|
|
m_PWADOrderBrowser->add(pwad->filename.c_str());
|
|
}
|
|
m_PWADOrderBrowser->value(val);
|
|
}
|
|
|
|
/**
|
|
* @brief Get WAD information for selected IWAD.
|
|
*/
|
|
const scannedIWAD_t* selectedIWAD()
|
|
{
|
|
const size_t value = static_cast<size_t>(m_IWADBrowser->value());
|
|
if (value == 0)
|
|
return NULL;
|
|
return &m_IWADs[value - 1];
|
|
}
|
|
|
|
/**
|
|
* @brief Get WAD information for selected WADs.
|
|
*/
|
|
void selectedWADs()
|
|
{
|
|
// IWADs
|
|
const size_t value = static_cast<size_t>(m_IWADBrowser->value());
|
|
scannedIWAD_t iwad = m_IWADs[value - 1];
|
|
g_SelectedWADs.iwad = iwad.path;
|
|
|
|
// PWADs
|
|
for (const auto& pwad : m_selectedPWADs)
|
|
{
|
|
g_SelectedWADs.pwads.push_back(pwad->path);
|
|
}
|
|
}
|
|
|
|
void setOptions()
|
|
{
|
|
for (int i = 1; i <= m_gameOptionsBrowser->nitems(); i++) {
|
|
if (m_gameOptionsBrowser->checked(i))
|
|
g_SelectedWADs.options.push_back(OPTIONS_LIST[i - 1].second);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Update the WAD dir browser widget from the vector.
|
|
*/
|
|
void updateWADDirBrowser()
|
|
{
|
|
const int val = m_WADDirList->value();
|
|
m_WADDirList->clear();
|
|
for (const auto& waddir : m_WADDirs)
|
|
{
|
|
m_WADDirList->add(waddir.c_str());
|
|
}
|
|
m_WADDirList->value(val);
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize WAD directories from CVar.
|
|
*/
|
|
void initWADDirs() { m_WADDirs = TokenizeString(::waddirs.str(), PATHLISTSEP); }
|
|
|
|
/**
|
|
* @brief Update the CVar from WAD directories list.
|
|
*/
|
|
void setWADDirs() { ::waddirs.Set(JoinStrings(m_WADDirs, PATHLISTSEP).c_str()); }
|
|
};
|
|
|
|
/**
|
|
* @brief Shim function to call new BootWindow() with proper params.
|
|
*/
|
|
static BootWindow* MakeBootWindow()
|
|
{
|
|
return new BootWindow(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Odamex " DOTVERSIONSTR);
|
|
}
|
|
|
|
#include "m_argv.h"
|
|
|
|
/**
|
|
* @brief Create the boot window for Odamex.
|
|
*
|
|
* @return The IWAD file to use when starting the game.
|
|
*/
|
|
scannedWADs_t GUI_BootWindow()
|
|
{
|
|
// Scale according to 1600x900.
|
|
Fl::screen_scale(0, MAX(Fl::h() / 900.0f, Fl::screen_scale(0)));
|
|
|
|
// This feature is too clever by half, and in my experience just
|
|
// deforms the window.
|
|
Fl::keyboard_screen_scaling(0);
|
|
|
|
// find arguments for fltk
|
|
DArgs fltkargs = DArgs();
|
|
fltkargs.AppendArg(::Args.GetArg(0));
|
|
const char* rawargs = ::Args.CheckValue("-fltk");
|
|
if (rawargs != nullptr)
|
|
for (auto& arg : TokenizeString(rawargs, " "))
|
|
fltkargs.AppendArg(arg.c_str());
|
|
|
|
BootWindow* win = MakeBootWindow();
|
|
win->initWADDirs();
|
|
win->updateWADDirBrowser();
|
|
win->rescanIWADs();
|
|
win->position((Fl::w() - win->w()) / 2, (Fl::h() - win->h()) / 2);
|
|
win->show(fltkargs.NumArgs(), (char**)fltkargs.GetArgv().data());
|
|
|
|
// Blocks until the boot window has been closed.
|
|
Fl::run();
|
|
|
|
// Return the full IWAD path.
|
|
return g_SelectedWADs;
|
|
}
|