Skip to content

Commit

Permalink
Merge pull request #770 from electricbrass/boot-pwad-select
Browse files Browse the repository at this point in the history
[FEATURE] Add PWAD select tab to boot window
  • Loading branch information
AlexMax committed Nov 24, 2022
2 parents 86a1649 + b4152ea commit 84c16ec
Show file tree
Hide file tree
Showing 11 changed files with 426 additions and 36 deletions.
252 changes: 237 additions & 15 deletions client/gui/gui_boot.cpp
Expand Up @@ -30,6 +30,7 @@
#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"
Expand All @@ -51,18 +52,67 @@ EXTERN_CVAR(waddirs);

// ---------------

typedef std::vector<scannedIWAD_t> scannedIWADs_t;
typedef std::vector<scannedPWAD_t> scannedPWADs_t;
typedef std::vector<scannedPWAD_t*> scannedPWADPtrs_t;

/**
* @brief Find the PWAD pointer in the scanned WAD array.
*/
static scannedPWADs_t::iterator FindScanned(scannedPWADs_t& mut, scannedPWAD_t* pwad)
{
for (scannedPWADs_t::iterator it = mut.begin(); it != mut.end(); ++it)
{
if (&*it == pwad)
{
return it;
}
}
return mut.end();
}

/**
* @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;

const int WINDOW_WIDTH = 320;
const int WINDOW_HEIGHT = 240;

class BootWindow : public Fl_Window
{
Fl_Group* m_tabIWAD;
Fl_Group* m_tabPWADs;
std::string m_genWaddirs;
std::vector<scannedIWAD_t> m_IWADs;
scannedIWADs_t m_IWADs;
scannedPWADs_t m_PWADs;
scannedPWADPtrs_t m_selectedPWADs;
Fl_Hold_Browser* m_IWADBrowser;
std::vector<std::string> m_WADDirs;
Fl_Check_Browser* m_PWADSelectBrowser;
Fl_Hold_Browser* m_PWADOrderBrowser;
StringTokens m_WADDirs;
Fl_Hold_Browser* m_WADDirList;

public:
Expand All @@ -85,6 +135,36 @@ class BootWindow : public Fl_Window
} // Fl_Browser* m_IWADBrowser
m_tabIWAD->end();
} // Fl_Group* tabIWAD
{
m_tabPWADs = new Fl_Group(0, 25, 425, 175, "PWAD Select");
{
m_PWADSelectBrowser = new Fl_Check_Browser(10, 35, 183, 155);
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* tabWADDirs =
new Fl_Group(0, 25, 425, 175, "Resource Locations");
Expand Down Expand Up @@ -146,17 +226,28 @@ class BootWindow : public Fl_Window
{
Fl_Tabs* tabs = static_cast<Fl_Tabs*>(w);
BootWindow* boot = static_cast<BootWindow*>(data);

Fl_Group* clicked = static_cast<Fl_Group*>(tabs->value());
if (clicked != boot->m_tabIWAD)
return;

// User clicked on the first tab, see if we need to regenerate the
// list of IWADs.
if (boot->m_genWaddirs == ::waddirs)
// 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;

boot->rescanIWADs();
// User clicked on the second tab, regenerate the
// list of IWADs 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(); }
Expand All @@ -180,10 +271,69 @@ class BootWindow : public Fl_Window
return;
}

::g_SelectedIWAD = boot->selectedIWAD();
boot->selectedWADs();
Fl::delete_widget(boot);
}

// -- PWAD Boot Order --

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 >= 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 >= 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.
scannedPWADs_t::iterator it = FindScanned(boot->m_PWADs, selected);
if (it == boot->m_PWADs.end())
{
return;
}
ptrdiff_t index = it - boot->m_PWADs.begin();
boot->m_PWADSelectBrowser->checked(index + 1, 0);

// Erase the selected PWAD from the order array.
EraseSelected(boot->m_selectedPWADs, boot->m_selectedPWADs[removeIDX]);
boot->updatePWADOrderBrowser();
}

// -- Resource Locations --

/**
Expand Down Expand Up @@ -264,6 +414,61 @@ class BootWindow : public Fl_Window
m_genWaddirs = ::waddirs.str();
}

void rescanPWADs()
{
m_PWADSelectBrowser->clear();
m_PWADs = M_ScanPWADs();
for (scannedPWADs_t::iterator it = m_PWADs.begin(); it != m_PWADs.end(); ++it)
{
m_PWADSelectBrowser->add(it->filename.c_str());
}
m_genWaddirs = ::waddirs.str();

// clear order browser since selection browser is being reset
m_PWADOrderBrowser->clear();
m_selectedPWADs.clear();
}

/**
* @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 (int i = 1; i <= boot->m_PWADSelectBrowser->nitems(); i++)
{
scannedPWAD_t* selected = &boot->m_PWADs[size_t(i) - 1];
if (boot->m_PWADSelectBrowser->checked(i))
{
AddSelected(boot->m_selectedPWADs, selected);
}
else
{
EraseSelected(boot->m_selectedPWADs, selected);
}
}

// 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 (scannedPWADPtrs_t::iterator it = m_selectedPWADs.begin();
it != m_selectedPWADs.end(); ++it)
{
m_PWADOrderBrowser->add((*it)->filename.c_str());
}
m_PWADOrderBrowser->value(val);
}

/**
* @brief Get WAD information for selected IWAD.
*/
Expand All @@ -272,7 +477,24 @@ class BootWindow : public Fl_Window
const size_t value = static_cast<size_t>(m_IWADBrowser->value());
if (value == 0)
return NULL;
return &m_IWADs.at(value - 1);
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());
g_SelectedWADs.iwad = m_IWADs[value - 1].path;

// PWADs
for (scannedPWADPtrs_t::iterator it = m_selectedPWADs.begin();
it != m_selectedPWADs.end(); ++it)
{
g_SelectedWADs.pwads.push_back((*it)->path);
}
}

/**
Expand All @@ -282,9 +504,9 @@ class BootWindow : public Fl_Window
{
const int val = m_WADDirList->value();
m_WADDirList->clear();
for (size_t i = 0; i < m_WADDirs.size(); i++)
for (StringTokens::iterator it = m_WADDirs.begin(); it != m_WADDirs.end(); ++it)
{
m_WADDirList->add(m_WADDirs[i].c_str());
m_WADDirList->add(it->c_str());
}
m_WADDirList->value(val);
}
Expand Down Expand Up @@ -313,7 +535,7 @@ static BootWindow* MakeBootWindow()
*
* @return The IWAD file to use when starting the game.
*/
std::string GUI_BootWindow()
scannedWADs_t GUI_BootWindow()
{
// Scale according to 1600x900.
Fl::screen_scale(0, MAX(Fl::h() / 900.0f, 1.0f));
Expand All @@ -333,5 +555,5 @@ std::string GUI_BootWindow()
Fl::run();

// Return the full IWAD path.
return ::g_SelectedIWAD->path;
return g_SelectedWADs;
}
8 changes: 7 additions & 1 deletion client/gui/gui_boot.h
Expand Up @@ -23,4 +23,10 @@

#pragma once

std::string GUI_BootWindow();
struct scannedWADs_t
{
std::string iwad;
StringTokens pwads;
};

scannedWADs_t GUI_BootWindow();
15 changes: 14 additions & 1 deletion client/src/d_main.cpp
Expand Up @@ -764,6 +764,7 @@ void D_DoomMain()
C_ExecCmdLineParams(true, false); // [RH] do all +set commands on the command line

std::string iwad;
std::vector<std::string> pwads;
const char* iwadParam = Args.CheckValue("-iwad");
if (iwadParam)
{
Expand Down Expand Up @@ -797,7 +798,9 @@ void D_DoomMain()

if (!shouldSkip)
{
iwad = GUI_BootWindow();
scannedWADs_t wads = GUI_BootWindow();
iwad = wads.iwad;
pwads = wads.pwads;
}
}

Expand All @@ -810,6 +813,16 @@ void D_DoomMain()
newwadfiles.push_back(file);
}

if (!pwads.empty())
{
for (size_t i = 0; i < pwads.size(); i++)
{
OWantFile file;
OWantFile::make(file, pwads[i], OFILE_WAD);
newwadfiles.push_back(file);
}
}

D_AddWadCommandLineFiles(newwadfiles);
D_AddDehCommandLineFiles(newpatchfiles);

Expand Down
7 changes: 7 additions & 0 deletions common/c_cvars.cpp
Expand Up @@ -795,6 +795,13 @@ BEGIN_COMMAND(fatalout)
}
END_COMMAND(fatalout)

BEGIN_COMMAND(exceptout)
{
std::string crashma = "What's crashma?";
Printf("%crashma game, lmao.\n", crashma.at(std::string::npos));
}
END_COMMAND(exceptout)

#if defined _WIN32

BEGIN_COMMAND(crashout)
Expand Down

0 comments on commit 84c16ec

Please sign in to comment.