mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-08 05:51:26 +00:00
fb50df2c63
surprised if this doesn't build in Linux right now. The CMakeLists.txt were checked with MinGW and NMake, but how they fair under Linux is an unknown to me at this time. - Converted most sprintf (and all wsprintf) calls to either mysnprintf or FStrings, depending on the situation. - Changed the strings in the wbstartstruct to be FStrings. - Changed myvsnprintf() to output nothing if count is greater than INT_MAX. This is so that I can use a series of mysnprintf() calls and advance the pointer for each one. Once the pointer goes beyond the end of the buffer, the count will go negative, but since it's an unsigned type it will be seen as excessively huge instead. This should not be a problem, as there's no reason for ZDoom to be using text buffers larger than 2 GB anywhere. - Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig(). - Changed CalcMapName() to return an FString instead of a pointer to a static buffer. - Changed startmap in d_main.cpp into an FString. - Changed CheckWarpTransMap() to take an FString& as the first argument. - Changed d_mapname in g_level.cpp into an FString. - Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an FString. - Fixed: The MAPINFO parser wrote into the string buffer to construct a map name when given a Hexen map number. This was fine with the old scanner code, but only a happy coincidence prevents it from crashing with the new code - Added the 'B' conversion specifier to StringFormat::VWorker() for printing binary numbers. - Added CMake support for building with MinGW, MSYS, and NMake. Linux support is probably broken until I get around to booting into Linux again. Niceties provided over the existing Makefiles they're replacing: * All command-line builds can use the same build system, rather than having a separate one for MinGW and another for Linux. * Microsoft's NMake tool is supported as a target. * Progress meters. * Parallel makes work from a fresh checkout without needing to be primed first with a single-threaded make. * Porting to other architectures should be simplified, whenever that day comes. - Replaced the makewad tool with zipdir. This handles the dependency tracking itself instead of generating an external makefile to do it, since I couldn't figure out how to generate a makefile with an external tool and include it with a CMake-generated makefile. Where makewad used a master list of files to generate the package file, zipdir just zips the entire contents of one or more directories. - Added the gdtoa package from netlib's fp library so that ZDoom's printf-style formatting can be entirely independant of the CRT. SVN r1082 (trunk)
1370 lines
39 KiB
C++
1370 lines
39 KiB
C++
#define WIN32_LEAN_AND_MEAN
|
|
#define _WIN32_WINNT 0x0500
|
|
#define _WIN32_IE 0x0500
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
#include <commdlg.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#define USE_WINDOWS_DWORD
|
|
#include "resource.h"
|
|
#include "s_sound.h"
|
|
#include "templates.h"
|
|
#include "cmdlib.h"
|
|
#include "c_dispatch.h"
|
|
#include "c_cvars.h"
|
|
#include "doomstat.h"
|
|
|
|
// More w32api lackings
|
|
#ifndef TTM_SETTITLE
|
|
#define TTM_SETTITLEA (WM_USER+32)
|
|
#define TTM_SETTITLEW (WM_USER+33)
|
|
#ifdef UNICODE
|
|
#define TTM_SETTITLE TTM_SETTITLEW
|
|
#else
|
|
#define TTM_SETTITLE TTM_SETTITLEA
|
|
#endif
|
|
#endif
|
|
#ifndef TTF_TRACK
|
|
#define TTF_TRACK 0x0020
|
|
#endif
|
|
#ifndef TTF_TRANSPARENT
|
|
#define TTF_TRANSPARENT 0x0100
|
|
#endif
|
|
|
|
#ifndef OFN_ENABLESIZING
|
|
#define OFN_ENABLESIZING 0x00800000
|
|
typedef struct w32apiFixedOFNA {
|
|
DWORD lStructSize;
|
|
HWND hwndOwner;
|
|
HINSTANCE hInstance;
|
|
LPCSTR lpstrFilter;
|
|
LPSTR lpstrCustomFilter;
|
|
DWORD nMaxCustFilter;
|
|
DWORD nFilterIndex;
|
|
LPSTR lpstrFile;
|
|
DWORD nMaxFile;
|
|
LPSTR lpstrFileTitle;
|
|
DWORD nMaxFileTitle;
|
|
LPCSTR lpstrInitialDir;
|
|
LPCSTR lpstrTitle;
|
|
DWORD Flags;
|
|
WORD nFileOffset;
|
|
WORD nFileExtension;
|
|
LPCSTR lpstrDefExt;
|
|
LPARAM lCustData;
|
|
LPOFNHOOKPROC lpfnHook;
|
|
LPCSTR lpTemplateName;
|
|
void *pvReserved;
|
|
DWORD dwReserved;
|
|
DWORD FlagsEx;
|
|
} FIXEDOPENFILENAMEA;
|
|
#define OPENFILENAME FIXEDOPENFILENAMEA
|
|
#endif
|
|
|
|
extern HINSTANCE g_hInst;
|
|
extern HWND Window;
|
|
extern bool ForceWindowed;
|
|
EXTERN_CVAR (Bool, fullscreen)
|
|
extern ReverbContainer *ForcedEnvironment;
|
|
|
|
HWND EAXEditWindow;
|
|
HWND hPropList;
|
|
POINT PropListMaxSize;
|
|
LONG PropListHeightDiff;
|
|
POINT EditWindowSize;
|
|
POINT DoneLocation;
|
|
WNDPROC StdEditProc;
|
|
LONG NewLeft;
|
|
LONG SaveLeft;
|
|
LONG RevertLeft;
|
|
POINT TestLocation;
|
|
|
|
bool SpawnEAXWindow;
|
|
|
|
REVERB_PROPERTIES SavedProperties;
|
|
ReverbContainer *CurrentEnv;
|
|
|
|
CUSTOM_CVAR (Bool, eaxedit_test, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
|
{
|
|
if (EAXEditWindow != 0)
|
|
{
|
|
CheckDlgButton (EAXEditWindow, IDC_TESTEAX, self ? BST_CHECKED : BST_UNCHECKED);
|
|
if (self)
|
|
{
|
|
ForcedEnvironment = CurrentEnv;
|
|
}
|
|
else
|
|
{
|
|
ForcedEnvironment = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct MySaveData
|
|
{
|
|
const ReverbContainer *Default;
|
|
const ReverbContainer **Saves;
|
|
UINT NumSaves;
|
|
|
|
MySaveData (const ReverbContainer *def)
|
|
: Default (def), Saves (NULL), NumSaves (0) {}
|
|
~MySaveData ()
|
|
{
|
|
if (Saves) delete[] Saves;
|
|
}
|
|
};
|
|
|
|
struct EnvControl
|
|
{
|
|
const char *Name;
|
|
int EditControl;
|
|
int SliderControl;
|
|
int Min;
|
|
int Max;
|
|
float REVERB_PROPERTIES::*Float;
|
|
int REVERB_PROPERTIES::*Int;
|
|
HWND EditHWND;
|
|
HWND SliderHWND;
|
|
};
|
|
|
|
struct EnvFlag
|
|
{
|
|
const char *Name;
|
|
int CheckboxControl;
|
|
unsigned int Flag;
|
|
HWND CheckboxHWND;
|
|
};
|
|
|
|
void PopulateEnvDropDown (HWND hCtl);
|
|
void SetupEnvControls (HWND hDlg);
|
|
void UpdateControls (const ReverbContainer *env, HWND hDlg);
|
|
void UpdateControl (const EnvControl *control, int value, bool slider);
|
|
|
|
EnvControl EnvControls[] =
|
|
{
|
|
{ "Environment", 0, 0, 0, 25, 0, &REVERB_PROPERTIES::Environment },
|
|
{ "EnvironmentSize", IDCE_ENVIRONMENTSIZE, IDCS_ENVIRONMENTSIZE, 1000, 100000, &REVERB_PROPERTIES::EnvSize, 0 },
|
|
{ "EnvironmentDiffusion", IDCE_ENVIRONMENTDIFFUSION, IDCS_ENVIRONMENTDIFFUSION, 0, 1000, &REVERB_PROPERTIES::EnvDiffusion, 0 },
|
|
{ "Room", IDCE_ROOM, IDCS_ROOM, -10000, 0, 0, &REVERB_PROPERTIES::Room },
|
|
{ "RoomHF", IDCE_ROOMHF, IDCS_ROOMHF, -10000, 0, 0, &REVERB_PROPERTIES::RoomHF },
|
|
{ "RoomLF", IDCE_ROOMLF, IDCS_ROOMLF, -10000, 0, 0, &REVERB_PROPERTIES::RoomLF },
|
|
{ "DecayTime", IDCE_DECAYTIME, IDCS_DECAYTIME, 100, 20000, &REVERB_PROPERTIES::DecayTime, 0 },
|
|
{ "DecayHFRatio", IDCE_DECAYHFRATIO, IDCS_DECAYHFRATIO, 100, 2000, &REVERB_PROPERTIES::DecayHFRatio, 0 },
|
|
{ "DecayLFRatio", IDCE_DECAYLFRATIO, IDCS_DECAYLFRATIO, 100, 2000, &REVERB_PROPERTIES::DecayLFRatio, 0 },
|
|
{ "Reflections", IDCE_REFLECTIONS, IDCS_REFLECTIONS, -10000, 1000, 0, &REVERB_PROPERTIES::Reflections },
|
|
{ "ReflectionsDelay", IDCE_REFLECTIONSDELAY, IDCS_REFLECTIONSDELAY, 0, 300, &REVERB_PROPERTIES::ReflectionsDelay, 0 },
|
|
{ "ReflectionsPanX", IDCE_REFLECTIONSPANX, IDCS_REFLECTIONSPANX, -2000000, 2000000, &REVERB_PROPERTIES::ReflectionsPan0, 0 },
|
|
{ "ReflectionsPanY", IDCE_REFLECTIONSPANY, IDCS_REFLECTIONSPANY, -2000000, 2000000, &REVERB_PROPERTIES::ReflectionsPan1, 0 },
|
|
{ "ReflectionsPanZ", IDCE_REFLECTIONSPANZ, IDCS_REFLECTIONSPANZ, -2000000, 2000000, &REVERB_PROPERTIES::ReflectionsPan2, 0 },
|
|
{ "Reverb", IDCE_REVERB, IDCS_REVERB, -10000, 2000, 0, &REVERB_PROPERTIES::Reverb },
|
|
{ "ReverbDelay", IDCE_REVERBDELAY, IDCS_REVERBDELAY, 0, 100, &REVERB_PROPERTIES::ReverbDelay, 0 },
|
|
{ "ReverbPanX", IDCE_REVERBPANX, IDCS_REVERBPANX, -2000000, 2000000, &REVERB_PROPERTIES::ReverbPan0, 0 },
|
|
{ "ReverbPanY", IDCE_REVERBPANY, IDCS_REVERBPANY, -2000000, 2000000, &REVERB_PROPERTIES::ReverbPan1, 0 },
|
|
{ "ReverbPanZ", IDCE_REVERBPANZ, IDCS_REVERBPANZ, -2000000, 2000000, &REVERB_PROPERTIES::ReverbPan2, 0 },
|
|
{ "EchoTime", IDCE_ECHOTIME, IDCS_ECHOTIME, 75, 250, &REVERB_PROPERTIES::EchoTime, 0 },
|
|
{ "EchoDepth", IDCE_ECHODEPTH, IDCS_ECHODEPTH, 0, 1000, &REVERB_PROPERTIES::EchoDepth, 0 },
|
|
{ "ModulationTime", IDCE_MODULATIONTIME, IDCS_MODULATIONTIME, 40, 4000, &REVERB_PROPERTIES::ModulationTime, 0 },
|
|
{ "ModulationDepth", IDCE_MODULATIONDEPTH, IDCS_MODULATIONDEPTH, 0, 1000, &REVERB_PROPERTIES::ModulationDepth, 0 },
|
|
{ "AirAbsorptionHF", IDCE_AIRABSORPTIONHF, IDCS_AIRABSORPTIONHF, -100000, 0, &REVERB_PROPERTIES::AirAbsorptionHF, 0 },
|
|
{ "HFReference", IDCE_HFREFERENCE, IDCS_HFREFERENCE, 1000000, 20000000, &REVERB_PROPERTIES::HFReference, 0 },
|
|
{ "LFReference", IDCE_LFREFERENCE, IDCS_LFREFERENCE, 20000, 1000000, &REVERB_PROPERTIES::LFReference, 0 },
|
|
{ "RoomRolloffFactor", IDCE_ROOMROLLOFFFACTOR, IDCS_ROOMROLLOFFFACTOR, 0, 10000, &REVERB_PROPERTIES::RoomRolloffFactor, 0 },
|
|
{ "Diffusion", 0, 0, 0, 100000, &REVERB_PROPERTIES::Diffusion, 0 },
|
|
{ "Density", 0, 0, 0, 100000, &REVERB_PROPERTIES::Density, 0 },
|
|
};
|
|
|
|
EnvFlag EnvFlags[] =
|
|
{
|
|
{ "bReflectionsScale", IDC_REFLECTIONSSCALE, REVERB_FLAGS_REFLECTIONSSCALE },
|
|
{ "bReflectionsDelayScale", IDC_REFLECTIONSDELAYSCALE, REVERB_FLAGS_REFLECTIONSDELAYSCALE },
|
|
{ "bDecayTimeScale", IDC_DECAYTIMESCALE, REVERB_FLAGS_DECAYTIMESCALE },
|
|
{ "bDecayHFLimit", IDC_DECAYHFLIMIT, REVERB_FLAGS_DECAYHFLIMIT },
|
|
{ "bReverbScale", IDC_REVERBSCALE, REVERB_FLAGS_REVERBSCALE },
|
|
{ "bReverbDelayScale", IDC_REVERBDELAYSCALE, REVERB_FLAGS_REVERBDELAYSCALE },
|
|
{ "bEchoTimeScale", IDC_ECHOTIMESCALE, REVERB_FLAGS_ECHOTIMESCALE },
|
|
{ "bModulationTimeScale", IDC_MODULATIONTIMESCALE, REVERB_FLAGS_MODULATIONTIMESCALE }
|
|
};
|
|
|
|
LRESULT AddEnvToDropDown (HWND hCtl, bool showID, const ReverbContainer *env)
|
|
{
|
|
char buff[128];
|
|
LRESULT i;
|
|
|
|
if (showID)
|
|
{
|
|
mysnprintf (buff, countof(buff), "(%3d,%3d) %s", HIBYTE(env->ID), LOBYTE(env->ID), env->Name);
|
|
i = SendMessage (hCtl, CB_ADDSTRING, 0, (LPARAM)buff);
|
|
}
|
|
else
|
|
{
|
|
i = SendMessage (hCtl, CB_ADDSTRING, 0, (LPARAM)env->Name);
|
|
}
|
|
SendMessage (hCtl, CB_SETITEMDATA, i, (LPARAM)env);
|
|
return i;
|
|
}
|
|
|
|
void PopulateEnvDropDown (HWND hCtl, bool showIDs, const ReverbContainer *defEnv)
|
|
{
|
|
const ReverbContainer *env;
|
|
WPARAM envCount = 0;
|
|
LPARAM strCount = 0;
|
|
LRESULT i;
|
|
|
|
for (env = Environments; env != NULL; env = env->Next)
|
|
{
|
|
envCount++;
|
|
strCount += strlen (env->Name) + 1;
|
|
}
|
|
|
|
SendMessage (hCtl, WM_SETREDRAW, FALSE, 0);
|
|
SendMessage (hCtl, CB_RESETCONTENT, 0, 0);
|
|
SendMessage (hCtl, CB_INITSTORAGE, envCount, showIDs ?
|
|
strCount + envCount * 10 : strCount);
|
|
|
|
for (env = Environments; env != NULL; env = env->Next)
|
|
{
|
|
AddEnvToDropDown (hCtl, showIDs, env);
|
|
}
|
|
|
|
SendMessage (hCtl, WM_SETREDRAW, TRUE, 0);
|
|
|
|
if (defEnv == NULL)
|
|
{
|
|
SendMessage (hCtl, CB_SETCURSEL, 0, 0);
|
|
SetFocus (hCtl);
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < (LPARAM)envCount; ++i)
|
|
{
|
|
if ((const ReverbContainer *)SendMessage (hCtl, CB_GETITEMDATA, i, 0)
|
|
== defEnv)
|
|
{
|
|
SendMessage (hCtl, CB_SETCURSEL, i, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetIDEdits (HWND hDlg, WORD id)
|
|
{
|
|
char text[4];
|
|
|
|
mysnprintf (text, countof(text), "%d", HIBYTE(id));
|
|
SendMessage (GetDlgItem (hDlg, IDC_EDITID1), WM_SETTEXT, 0, (LPARAM)text);
|
|
mysnprintf (text, countof(text), "%d", LOBYTE(id));
|
|
SendMessage (GetDlgItem (hDlg, IDC_EDITID2), WM_SETTEXT, 0, (LPARAM)text);
|
|
}
|
|
|
|
void PopulateEnvList (HWND hCtl, bool show, const ReverbContainer *defEnv)
|
|
{
|
|
const ReverbContainer *env;
|
|
int i;
|
|
LVITEM item;
|
|
|
|
SendMessage (hCtl, WM_SETREDRAW, FALSE, 0);
|
|
|
|
item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
|
|
item.stateMask = LVIS_SELECTED|LVIS_FOCUSED;
|
|
item.iSubItem = 0;
|
|
|
|
for (env = Environments, i = 0; env != NULL; env = env->Next, ++i)
|
|
{
|
|
if (!env->Builtin || show)
|
|
{
|
|
item.iItem = i;
|
|
item.pszText = (LPSTR)env->Name;
|
|
item.lParam = (LPARAM)env;
|
|
item.state = env == defEnv ? LVIS_SELECTED|LVIS_FOCUSED : 0;
|
|
SendMessage (hCtl, LVM_INSERTITEM, 0, (LPARAM)&item);
|
|
}
|
|
}
|
|
|
|
SendMessage (hCtl, WM_SETREDRAW, TRUE, 0);
|
|
}
|
|
|
|
WORD FirstFreeID (WORD base, bool builtin)
|
|
{
|
|
int tryCount = 0;
|
|
int priID = HIBYTE(base);
|
|
|
|
// If the original sound is built-in, start searching for a new
|
|
// primary ID at 30.
|
|
if (builtin)
|
|
{
|
|
for (priID = 30; priID < 256; ++priID)
|
|
{
|
|
if (S_FindEnvironment (priID << 8) == NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (priID == 256)
|
|
{ // Oh well.
|
|
priID = 30;
|
|
}
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
WORD lastID = Environments->ID;
|
|
const ReverbContainer *env = Environments->Next;
|
|
|
|
// Find the lowest-numbered free ID with the same primary ID as base
|
|
// If none are available, add 100 to base's primary ID and try again.
|
|
// If that fails, then the primary ID gets incremented
|
|
// by 1 until a match is found. If all the IDs searchable by this
|
|
// algorithm are in use, then you're in trouble.
|
|
|
|
while (env != NULL)
|
|
{
|
|
if (HIBYTE(env->ID) > priID)
|
|
{
|
|
break;
|
|
}
|
|
if (HIBYTE(env->ID) == priID)
|
|
{
|
|
if (HIBYTE(lastID) == priID)
|
|
{
|
|
if (LOBYTE(env->ID) - LOBYTE(lastID) > 1)
|
|
{
|
|
return lastID+1;
|
|
}
|
|
}
|
|
lastID = env->ID;
|
|
}
|
|
env = env->Next;
|
|
}
|
|
if (LOBYTE(lastID) == 255)
|
|
{
|
|
if (tryCount == 0)
|
|
{
|
|
base += 100*256;
|
|
tryCount = 1;
|
|
}
|
|
else
|
|
{
|
|
base += 256;
|
|
}
|
|
}
|
|
else if (builtin && lastID == 0)
|
|
{
|
|
return priID << 8;
|
|
}
|
|
else
|
|
{
|
|
return lastID+1;
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CALLBACK EditControlProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
char buff[16];
|
|
double val;
|
|
const EnvControl *env;
|
|
MSG *msg;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_GETDLGCODE:
|
|
msg = (MSG *)lParam;
|
|
if (msg && LOWORD(msg->message) == WM_KEYDOWN)
|
|
{
|
|
// Do not close the dialog if Enter was pressed
|
|
// inside an edit control.
|
|
if (msg->wParam == VK_RETURN || msg->wParam == VK_ESCAPE)
|
|
{
|
|
return DLGC_WANTALLKEYS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_CHAR:
|
|
// Only allow numeric symbols.
|
|
if (wParam >= ' ' && wParam <= 127 &&
|
|
(wParam < '0' || wParam > '9') &&
|
|
wParam != '.' &&
|
|
wParam != '-' &&
|
|
wParam != '+')
|
|
{
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
if (wParam != VK_RETURN)
|
|
{
|
|
if (wParam == VK_ESCAPE)
|
|
{ // Put the original value back in the edit control.
|
|
env = (const EnvControl *)(LONG_PTR)GetWindowLongPtr (hWnd, GWLP_USERDATA);
|
|
int vali = SendMessage (env->SliderHWND, TBM_GETPOS, 0, 0);
|
|
if (env->Float)
|
|
{
|
|
mysnprintf (buff, countof(buff), "%d.%03d", vali/1000, abs(vali%1000));
|
|
}
|
|
else
|
|
{
|
|
mysnprintf (buff, countof(buff), "%d", vali);
|
|
}
|
|
CallWindowProc (StdEditProc, hWnd, WM_SETTEXT, 0, (LPARAM)buff);
|
|
CallWindowProc (StdEditProc, hWnd, EM_SETSEL, 0, -1);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// intentional fallthrough
|
|
|
|
case WM_KILLFOCUS:
|
|
// Validate the new value and update the corresponding slider.
|
|
env = (const EnvControl *)(LONG_PTR)GetWindowLongPtr (hWnd, GWLP_USERDATA);
|
|
val = 0.0;
|
|
if (CallWindowProc (StdEditProc, hWnd, WM_GETTEXT, 16, (LPARAM)buff) > 0)
|
|
{
|
|
val = atof (buff);
|
|
}
|
|
if (env->Float)
|
|
{
|
|
val *= 1000.0;
|
|
}
|
|
if (val < env->Min) val = env->Min;
|
|
else if (val > env->Max) val = env->Max;
|
|
UpdateControl (env, int(val), true);
|
|
break;
|
|
}
|
|
return CallWindowProc (StdEditProc, hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
LRESULT CALLBACK EditControlProcNoDeci (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// This is just like the above WndProc, except it only accepts integers.
|
|
if (uMsg == WM_CHAR && wParam == '.')
|
|
{
|
|
return 0;
|
|
}
|
|
return EditControlProc (hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
void SetupEnvControls (HWND hDlg)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < countof(EnvControls); ++i)
|
|
{
|
|
if (EnvControls[i].EditControl == 0)
|
|
continue;
|
|
|
|
EnvControls[i].EditHWND = GetDlgItem (hDlg, EnvControls[i].EditControl);
|
|
EnvControls[i].SliderHWND = GetDlgItem (hDlg, EnvControls[i].SliderControl);
|
|
SendMessage (EnvControls[i].SliderHWND, TBM_SETRANGEMIN, FALSE, EnvControls[i].Min);
|
|
SendMessage (EnvControls[i].SliderHWND, TBM_SETRANGEMAX, TRUE, EnvControls[i].Max);
|
|
SendMessage (EnvControls[i].EditHWND, EM_LIMITTEXT, 10, 0);
|
|
StdEditProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr (EnvControls[i].EditHWND, GWLP_WNDPROC,
|
|
(LONG_PTR)(EnvControls[i].Float ? EditControlProc : EditControlProcNoDeci));
|
|
SetWindowLongPtr (EnvControls[i].EditHWND, GWLP_USERDATA, (LONG_PTR)&EnvControls[i]);
|
|
SetWindowLongPtr (EnvControls[i].SliderHWND, GWLP_USERDATA, (LONG_PTR)&EnvControls[i]);
|
|
}
|
|
for (i = 0; i < countof(EnvFlags); ++i)
|
|
{
|
|
EnvFlags[i].CheckboxHWND = GetDlgItem (hDlg, EnvFlags[i].CheckboxControl);
|
|
SetWindowLongPtr (EnvFlags[i].CheckboxHWND, GWLP_USERDATA, (LONG_PTR)&EnvFlags[i]);
|
|
}
|
|
}
|
|
|
|
void UpdateControl (const EnvControl *control, int value, bool slider)
|
|
{
|
|
char buff[16];
|
|
|
|
if (slider)
|
|
{
|
|
SendMessage (control->SliderHWND, TBM_SETPOS, TRUE, value);
|
|
}
|
|
if (control->Float)
|
|
{
|
|
mysnprintf (buff, countof(buff), "%d.%03d", value/1000, abs(value%1000));
|
|
if (CurrentEnv != NULL)
|
|
{
|
|
CurrentEnv->Properties.*control->Float = float(value) / 1000.0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mysnprintf (buff, countof(buff), "%d", value);
|
|
if (CurrentEnv != NULL)
|
|
{
|
|
CurrentEnv->Properties.*control->Int = value;
|
|
}
|
|
}
|
|
SendMessage (control->EditHWND, WM_SETTEXT, 0, (LPARAM)buff);
|
|
if (CurrentEnv != NULL)
|
|
{
|
|
CurrentEnv->Modified = true;
|
|
}
|
|
}
|
|
|
|
void UpdateControls (ReverbContainer *env, HWND hDlg)
|
|
{
|
|
char buff[4];
|
|
size_t i;
|
|
|
|
if (env == NULL)
|
|
return;
|
|
|
|
CurrentEnv = NULL;
|
|
|
|
for (i = 0; i < countof(EnvControls); ++i)
|
|
{
|
|
EnvControl *ctrl = &EnvControls[i];
|
|
|
|
if (ctrl->Float)
|
|
{
|
|
float v = env->Properties.*ctrl->Float * 1000;
|
|
UpdateControl (ctrl, int(v >= 0.0 ? v + 0.5 : v - 0.5), true);
|
|
}
|
|
else
|
|
{
|
|
UpdateControl (ctrl, env->Properties.*ctrl->Int, true);
|
|
}
|
|
EnableWindow (ctrl->EditHWND, !env->Builtin);
|
|
EnableWindow (ctrl->SliderHWND, !env->Builtin);
|
|
}
|
|
for (i = 0; i < countof(EnvFlags); ++i)
|
|
{
|
|
SendMessage (EnvFlags[i].CheckboxHWND, BM_SETCHECK,
|
|
(env->Properties.Flags & EnvFlags[i].Flag) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
EnableWindow (EnvFlags[i].CheckboxHWND, !env->Builtin);
|
|
}
|
|
EnableWindow (GetDlgItem (hDlg, IDC_REVERT), !env->Builtin);
|
|
|
|
mysnprintf (buff, countof(buff), "%d", HIBYTE(env->ID));
|
|
SendMessage (GetDlgItem (hDlg, IDC_ID1), WM_SETTEXT, 0, (LPARAM)buff);
|
|
|
|
mysnprintf (buff, countof(buff), "%d", LOBYTE(env->ID));
|
|
SendMessage (GetDlgItem (hDlg, IDC_ID2), WM_SETTEXT, 0, (LPARAM)buff);
|
|
|
|
SavedProperties = env->Properties;
|
|
CurrentEnv = env;
|
|
|
|
if (SendMessage (GetDlgItem (hDlg, IDC_TESTEAX), BM_GETCHECK, 0,0) == BST_CHECKED)
|
|
{
|
|
ForcedEnvironment = env;
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK EAXProp (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
const EnvControl *env;
|
|
SCROLLINFO si;
|
|
int yPos;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
SetupEnvControls (hDlg);
|
|
return FALSE;
|
|
|
|
case WM_VSCROLL:
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_ALL;
|
|
GetScrollInfo (hDlg, SB_VERT, &si);
|
|
yPos = si.nPos;
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case SB_TOP: si.nPos = si.nMin; break;
|
|
case SB_BOTTOM: si.nPos = si.nMax; break;
|
|
case SB_LINEUP: si.nPos -= 16; break;
|
|
case SB_LINEDOWN: si.nPos += 16; break;
|
|
case SB_PAGEUP: si.nPos -= si.nPage; break;
|
|
case SB_PAGEDOWN: si.nPos += si.nPage; break;
|
|
case SB_THUMBTRACK: si.nPos = si.nTrackPos; break;
|
|
}
|
|
si.fMask = SIF_POS;
|
|
SetScrollInfo (hDlg, SB_VERT, &si, TRUE);
|
|
GetScrollInfo (hDlg, SB_VERT, &si);
|
|
if (si.nPos != yPos)
|
|
{
|
|
ScrollWindow (hDlg, 0, yPos - si.nPos, NULL, NULL);
|
|
UpdateWindow (hDlg);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_HSCROLL:
|
|
env = (const EnvControl *)(LONG_PTR)GetWindowLongPtr ((HWND)lParam, GWLP_USERDATA);
|
|
UpdateControl (env, SendMessage ((HWND)lParam, TBM_GETPOS, 0, 0), false);
|
|
return TRUE;
|
|
|
|
case WM_SIZE:
|
|
if (wParam != SIZE_MAXSHOW && wParam != SIZE_MAXHIDE)
|
|
{
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
GetScrollInfo (hDlg, SB_VERT, &si);
|
|
yPos = si.nPos;
|
|
|
|
// If we let the scroll bar disappear, then when that happens,
|
|
// it will resize the window before SetScrollInfo returns.
|
|
// Rather than checking for recursive WM_SIZE messages, I choose
|
|
// to force the scroll bar to always be present. The dialog is
|
|
// really designed with the appearance of the scroll bar in
|
|
// mind anyway, since it does nothing to resize the controls
|
|
// horizontally.
|
|
|
|
si.fMask = SIF_POS|SIF_PAGE|SIF_DISABLENOSCROLL;
|
|
si.nPage = HIWORD(lParam);
|
|
|
|
SetScrollInfo (hDlg, SB_VERT, &si, TRUE);
|
|
GetScrollInfo (hDlg, SB_VERT, &si);
|
|
if (si.nPos != yPos)
|
|
{
|
|
ScrollWindow (hDlg, 0, yPos - si.nPos, NULL, NULL);
|
|
UpdateWindow (hDlg);
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
if (HIWORD(wParam) == BN_CLICKED && CurrentEnv != NULL)
|
|
{
|
|
for (size_t i = 0; i < countof(EnvFlags); ++i)
|
|
{
|
|
if ((HWND)lParam == EnvFlags[i].CheckboxHWND)
|
|
{
|
|
if (SendMessage ((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
|
{
|
|
CurrentEnv->Properties.Flags |= EnvFlags[i].Flag;
|
|
}
|
|
else
|
|
{
|
|
CurrentEnv->Properties.Flags &= ~EnvFlags[i].Flag;
|
|
}
|
|
return TRUE;;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void SuggestNewName (const ReverbContainer *env, HWND hEdit)
|
|
{
|
|
const ReverbContainer *probe = NULL;
|
|
char text[32];
|
|
size_t len;
|
|
int number, numdigits;
|
|
|
|
strncpy (text, env->Name, 31);
|
|
text[31] = 0;
|
|
|
|
len = strlen (text);
|
|
while (text[len-1] >= '0' && text[len-1] <= '9')
|
|
{
|
|
len--;
|
|
}
|
|
number = atoi (text + len);
|
|
if (number < 1)
|
|
{
|
|
number = 1;
|
|
}
|
|
|
|
if (text[len-1] != ' ' && len < 31)
|
|
{
|
|
text[len++] = ' ';
|
|
}
|
|
|
|
for (; number < 100000; ++number)
|
|
{
|
|
if (number < 10) numdigits = 1;
|
|
else if (number < 100) numdigits = 2;
|
|
else if (number < 1000) numdigits = 3;
|
|
else if (number < 10000)numdigits = 4;
|
|
else numdigits = 5;
|
|
if (len + numdigits > 31)
|
|
{
|
|
len = 31 - numdigits;
|
|
}
|
|
mysnprintf (text + len, countof(text) - len, "%d", number);
|
|
|
|
probe = Environments;
|
|
while (probe != NULL)
|
|
{
|
|
if (stricmp (probe->Name, text) == 0)
|
|
break;
|
|
probe = probe->Next;
|
|
}
|
|
if (probe == NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (probe == NULL)
|
|
{
|
|
SetWindowText (hEdit, text);
|
|
}
|
|
}
|
|
|
|
void ShowErrorTip (HWND ToolTip, TOOLINFO &ti, HWND hDlg, const char *title)
|
|
{
|
|
SendMessage (ToolTip, TTM_SETTITLE, 3, (LPARAM)title);
|
|
|
|
ti.cbSize = sizeof(ti);
|
|
ti.hinst = g_hInst;
|
|
SendMessage (ToolTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
|
|
GetClientRect (ti.hwnd, &ti.rect);
|
|
POINT pt = { (ti.rect.left + ti.rect.right) / 2, ti.rect.bottom - 4 };
|
|
ClientToScreen (ti.hwnd, &pt);
|
|
SendMessage (ToolTip, TTM_TRACKACTIVATE, FALSE, 0);
|
|
SendMessage (ToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pt.x, pt.y));
|
|
SendMessage (ToolTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti);
|
|
SetFocus (ti.hwnd);
|
|
SendMessage (ti.hwnd, EM_SETSEL, 0, -1);
|
|
MessageBeep (MB_ICONEXCLAMATION);
|
|
SetTimer (hDlg, 11223, 10000, NULL);
|
|
}
|
|
|
|
INT_PTR CALLBACK NewEAXProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
const ReverbContainer *rev;
|
|
TOOLINFO ti;
|
|
char buff[33], buff4[4];
|
|
int id1, id2;
|
|
static HWND ToolTip;
|
|
HWND hWnd;
|
|
int i;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
hWnd = GetDlgItem (hDlg, IDC_ENVIRONMENTLIST);
|
|
PopulateEnvList (hWnd, true, (const ReverbContainer *)lParam);
|
|
SendMessage (GetDlgItem (hDlg, IDC_SPINID1), UDM_SETRANGE, 0, MAKELONG(255,0));
|
|
SendMessage (GetDlgItem (hDlg, IDC_SPINID2), UDM_SETRANGE, 0, MAKELONG(255,0));
|
|
SendMessage (GetDlgItem (hDlg, IDC_EDITID1), EM_LIMITTEXT, 3, 0);
|
|
SendMessage (GetDlgItem (hDlg, IDC_EDITID2), EM_LIMITTEXT, 3, 0);
|
|
|
|
hWnd = GetDlgItem (hDlg, IDC_NEWENVNAME);
|
|
SendMessage (hWnd, EM_LIMITTEXT, 31, 0);
|
|
SuggestNewName ((const ReverbContainer *)lParam, hWnd);
|
|
SetIDEdits (hDlg, FirstFreeID (((const ReverbContainer *)lParam)->ID,
|
|
((const ReverbContainer *)lParam)->Builtin));
|
|
|
|
ToolTip = CreateWindowEx (WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
|
|
WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP|TTS_BALLOON|TTS_CLOSE,
|
|
0, 0, 0, 0,
|
|
hDlg, NULL, g_hInst, NULL);
|
|
if (ToolTip)
|
|
{
|
|
char zero = '\0';
|
|
ti.cbSize = sizeof(ti);
|
|
ti.uFlags = TTF_TRACK | TTF_TRANSPARENT;
|
|
ti.hinst = g_hInst;
|
|
ti.lpszText = &zero;
|
|
for (i = 0; i < 3; ++i)
|
|
{
|
|
ti.uId = i;
|
|
ti.hwnd = GetDlgItem (hDlg, IDC_NEWENVNAME+i);
|
|
GetClientRect (ti.hwnd, &ti.rect);
|
|
SendMessage (ToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
|
|
case WM_TIMER:
|
|
if (wParam == 11223)
|
|
{
|
|
SendMessage (ToolTip, TTM_TRACKACTIVATE, FALSE, 0);
|
|
KillTimer (hDlg, 11223);
|
|
}
|
|
return 1;
|
|
|
|
case WM_MOVE:
|
|
// Just hide the tool tip if the user moves the window.
|
|
SendMessage (ToolTip, TTM_TRACKACTIVATE, FALSE, 0);
|
|
return 1;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
id1 = 256; id2 = 256;
|
|
buff[0] = 0;
|
|
if (0 == GetWindowText (GetDlgItem (hDlg, IDC_NEWENVNAME), buff, 32) ||
|
|
S_FindEnvironment (buff) != NULL)
|
|
{
|
|
static CHAR text0[] = "That name is already used.";
|
|
static CHAR text1[] = "Please enter a name.";
|
|
ti.uId = 0;
|
|
ti.hwnd = GetDlgItem (hDlg, IDC_NEWENVNAME);
|
|
ti.lpszText = buff[0] ? text0 : text1;
|
|
ShowErrorTip (ToolTip, ti, hDlg, "Bad Name");
|
|
return 0;
|
|
}
|
|
if (0 < GetWindowText (GetDlgItem (hDlg, IDC_EDITID1), buff4, 4))
|
|
{
|
|
id1 = atoi (buff4);
|
|
}
|
|
if (0 < GetWindowText (GetDlgItem (hDlg, IDC_EDITID2), buff4, 4))
|
|
{
|
|
id2 = atoi (buff4);
|
|
}
|
|
if (id1 > 255 || id2 > 255)
|
|
{
|
|
static CHAR text[] = "Please enter a number between 0 and 255.";
|
|
ti.uId = id1 > 255 ? 1 : 2;
|
|
ti.hwnd = GetDlgItem (hDlg, IDC_EDITID1 + ti.uId - 1);
|
|
ti.lpszText = text;
|
|
ShowErrorTip (ToolTip, ti, hDlg, "Bad Value");
|
|
}
|
|
else if (NULL != (rev = S_FindEnvironment (MAKEWORD (id2, id1))))
|
|
{
|
|
static char foo[80];
|
|
ti.uId = 2;
|
|
ti.hwnd = GetDlgItem (hDlg, IDC_EDITID2);
|
|
mysnprintf (foo, countof(foo), "This ID is already used by \"%s\".", rev->Name);
|
|
ti.lpszText = foo;
|
|
ShowErrorTip (ToolTip, ti, hDlg, "Bad ID");
|
|
}
|
|
else
|
|
{
|
|
LVITEM item;
|
|
|
|
hWnd = GetDlgItem (hDlg, IDC_ENVIRONMENTLIST);
|
|
i = SendMessage (hWnd, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_ALL|LVNI_SELECTED);
|
|
|
|
if (i == -1)
|
|
{
|
|
MessageBeep (MB_ICONEXCLAMATION);
|
|
return 0;
|
|
}
|
|
|
|
item.iItem = i;
|
|
item.iSubItem = 0;
|
|
item.mask = LVIF_PARAM;
|
|
if (!SendMessage (hWnd, LVM_GETITEM, 0, (LPARAM)&item))
|
|
{
|
|
MessageBeep (MB_ICONEXCLAMATION);
|
|
return 0;
|
|
}
|
|
|
|
ReverbContainer *env = new ReverbContainer;
|
|
rev = (ReverbContainer *)item.lParam;
|
|
|
|
env->Builtin = false;
|
|
env->ID = MAKEWORD (id2, id1);
|
|
env->Name = copystring (buff);
|
|
env->Next = NULL;
|
|
env->Properties = rev->Properties;
|
|
S_AddEnvironment (env);
|
|
|
|
EndDialog (hDlg, (INT_PTR)env);
|
|
}
|
|
return 0;
|
|
|
|
case IDCANCEL:
|
|
EndDialog (hDlg, 0);
|
|
break;
|
|
}
|
|
return 0;
|
|
|
|
case WM_NOTIFY:
|
|
if (wParam == IDC_ENVIRONMENTLIST && ((LPNMHDR)lParam)->code == LVN_ITEMCHANGED)
|
|
{
|
|
LPNMLISTVIEW nmlv = (LPNMLISTVIEW)lParam;
|
|
|
|
if (nmlv->iItem != -1 &&
|
|
(nmlv->uNewState & LVIS_SELECTED) &&
|
|
!(nmlv->uOldState & LVIS_SELECTED))
|
|
{
|
|
SuggestNewName ((const ReverbContainer *)nmlv->lParam, GetDlgItem (hDlg, IDC_NEWENVNAME));
|
|
SetIDEdits (hDlg, FirstFreeID (((const ReverbContainer *)nmlv->lParam)->ID,
|
|
((const ReverbContainer *)lParam)->Builtin));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
UINT_PTR CALLBACK SaveHookProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static LONG ButtonsLeftOffset;
|
|
static LONG ListRightOffset;
|
|
static LONG GroupRightOffset;
|
|
|
|
MySaveData *msd;
|
|
HWND hWnd;
|
|
LVITEM item;
|
|
int i, count;
|
|
RECT rect1, rect2;
|
|
UINT ns;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
GetClientRect (hDlg, &rect1);
|
|
GetWindowRect (GetDlgItem (hDlg, IDC_SELECTALL), &rect2);
|
|
ScreenToClient (hDlg, (LPPOINT)&rect2.left);
|
|
ButtonsLeftOffset = rect2.left - rect1.right;
|
|
GetWindowRect (GetDlgItem (hDlg, IDC_ENVLIST), &rect2);
|
|
ListRightOffset = (rect2.right - rect2.left) - rect1.right;
|
|
GetWindowRect (GetDlgItem (hDlg, IDC_SAVEGROUP), &rect2);
|
|
GroupRightOffset = (rect2.right - rect2.left) - rect1.right;
|
|
|
|
hWnd = GetDlgItem (hDlg, IDC_ENVLIST);
|
|
PopulateEnvList (hWnd, false,
|
|
((MySaveData *)(((LPOPENFILENAME)lParam)->lCustData))->Default);
|
|
SetWindowLongPtr (hDlg, DWLP_USER, (LONG_PTR)((LPOPENFILENAME)lParam)->lCustData);
|
|
return 1;
|
|
|
|
case WM_ERASEBKGND:
|
|
SetWindowLongPtr (hDlg, DWLP_MSGRESULT, 1);
|
|
return 1;
|
|
|
|
case WM_SIZE:
|
|
if (wParam != SIZE_MAXHIDE && wParam != SIZE_MAXSHOW)
|
|
{
|
|
GetWindowRect (hWnd = GetDlgItem (hDlg, IDC_SAVEGROUP), &rect1);
|
|
SetWindowPos (hWnd, NULL, 0, 0, LOWORD(lParam) + GroupRightOffset, rect1.bottom-rect1.top, SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_DEFERERASE);
|
|
|
|
GetWindowRect (hWnd = GetDlgItem (hDlg, IDC_SELECTALL), &rect1);
|
|
ScreenToClient (hDlg, (LPPOINT)&rect1.left);
|
|
SetWindowPos (hWnd, NULL, LOWORD(lParam)+ButtonsLeftOffset, rect1.top, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER);
|
|
|
|
GetWindowRect (hWnd = GetDlgItem (hDlg, IDC_SELECTNONE), &rect1);
|
|
ScreenToClient (hDlg, (LPPOINT)&rect1.left);
|
|
SetWindowPos (hWnd, NULL, LOWORD(lParam)+ButtonsLeftOffset, rect1.top, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER);
|
|
|
|
GetWindowRect (hWnd = GetDlgItem (hDlg, IDC_ENVLIST), &rect1);
|
|
SetWindowPos (hWnd, NULL, 0, 0, LOWORD(lParam) + ListRightOffset, rect1.bottom-rect1.top, SWP_DEFERERASE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER);
|
|
}
|
|
return 1;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_SELECTALL:
|
|
case IDC_SELECTNONE:
|
|
hWnd = GetDlgItem (hDlg, IDC_ENVLIST);
|
|
SendMessage (hWnd, WM_SETREDRAW, FALSE, 0);
|
|
count = ListView_GetItemCount (hWnd);
|
|
item.iSubItem = 0;
|
|
item.mask = LVIF_STATE;
|
|
item.stateMask = LVIS_SELECTED;
|
|
item.state = LOWORD(wParam)==IDC_SELECTALL ? LVIS_SELECTED : 0;
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
item.iItem = i;
|
|
ListView_SetItem (hWnd, &item);
|
|
}
|
|
if (LOWORD(wParam) == IDC_SELECTALL)
|
|
{
|
|
SetFocus (hWnd);
|
|
}
|
|
SendMessage (hWnd, WM_SETREDRAW, TRUE, 0);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((LPNMHDR)lParam)->code)
|
|
{
|
|
case CDN_INITDONE:
|
|
hWnd = GetParent (hDlg);
|
|
GetWindowRect (hWnd, &rect1);
|
|
GetWindowRect (hDlg, &rect2);
|
|
SetWindowPos (hDlg, NULL, 0, 0, rect1.right-rect1.left, rect2.bottom-rect2.top, SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER);
|
|
return 1;
|
|
|
|
case CDN_FILEOK:
|
|
msd = (MySaveData *)(LONG_PTR)GetWindowLongPtr (hDlg, DWLP_USER);
|
|
hWnd = GetDlgItem (hDlg, IDC_ENVLIST);
|
|
ns = ListView_GetSelectedCount (hWnd);
|
|
if (ns == 0)
|
|
{
|
|
msd->NumSaves = 0;
|
|
if (IDNO == MessageBox (hDlg,
|
|
"You have not selected any EAX environments to save.\n"
|
|
"Do you want to cancel the save operation?",
|
|
"Nothing Selected",
|
|
MB_YESNO|MB_ICONEXCLAMATION|MB_DEFBUTTON2))
|
|
{
|
|
SetWindowLongPtr (hDlg, DWLP_MSGRESULT, 1);
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UINT x;
|
|
msd->Saves = new const ReverbContainer *[ns];
|
|
item.iItem = -1;
|
|
item.iSubItem = 0;
|
|
item.mask = LVIF_PARAM;
|
|
|
|
for (x = 0; x != ns; )
|
|
{
|
|
item.iItem = ListView_GetNextItem (hWnd, item.iItem, LVNI_SELECTED);
|
|
if (item.iItem != -1 && ListView_GetItem (hWnd, &item))
|
|
{
|
|
msd->Saves[x++] = (const ReverbContainer *)item.lParam;
|
|
}
|
|
}
|
|
msd->NumSaves = x;
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void ExportEnvironments (const char *filename, UINT count, const ReverbContainer **envs)
|
|
{
|
|
FILE *f;
|
|
|
|
retry:
|
|
f = fopen (filename, "w");
|
|
|
|
if (f != NULL)
|
|
{
|
|
for (UINT i = 0; i < count; ++i)
|
|
{
|
|
const ReverbContainer *env = envs[i];
|
|
const ReverbContainer *base;
|
|
size_t j;
|
|
|
|
if ((unsigned int)env->Properties.Environment < 26)
|
|
{
|
|
base = DefaultEnvironments[env->Properties.Environment];
|
|
}
|
|
else
|
|
{
|
|
base = NULL;
|
|
}
|
|
fprintf (f, "\"%s\" %u %u\n{\n", env->Name, HIBYTE(env->ID), LOBYTE(env->ID));
|
|
for (j = 0; j < countof(EnvControls); ++j)
|
|
{
|
|
const EnvControl *ctl = &EnvControls[j];
|
|
if (ctl->Name &&
|
|
(j == 0 ||
|
|
(ctl->Float && base->Properties.*ctl->Float != env->Properties.*ctl->Float) ||
|
|
(ctl->Int && base->Properties.*ctl->Int != env->Properties.*ctl->Int))
|
|
)
|
|
{
|
|
fprintf (f, "\t%s ", ctl->Name);
|
|
if (ctl->Float)
|
|
{
|
|
float v = env->Properties.*ctl->Float * 1000;
|
|
int vi = int(v >= 0.0 ? v + 0.5 : v - 0.5);
|
|
fprintf (f, "%d.%03d\n", vi/1000, abs(vi%1000));
|
|
}
|
|
else
|
|
{
|
|
fprintf (f, "%d\n", env->Properties.*ctl->Int);
|
|
}
|
|
}
|
|
}
|
|
for (j = 0; j < countof(EnvFlags); ++j)
|
|
{
|
|
if (EnvFlags[j].Flag & (env->Properties.Flags ^ base->Properties.Flags))
|
|
{
|
|
fprintf (f, "\t%s %s\n", EnvFlags[j].Name,
|
|
EnvFlags[j].Flag & env->Properties.Flags ? "true" : "false");
|
|
}
|
|
}
|
|
fprintf (f, "}\n\n");
|
|
}
|
|
fclose (f);
|
|
}
|
|
else
|
|
{
|
|
LPVOID lpMsgBuf;
|
|
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&lpMsgBuf,
|
|
0,
|
|
NULL);
|
|
if (IDRETRY == MessageBox (EAXEditWindow, (LPCTSTR)lpMsgBuf, "Save Failed!", MB_RETRYCANCEL|MB_ICONERROR))
|
|
{
|
|
LocalFree (lpMsgBuf);
|
|
goto retry;
|
|
}
|
|
LocalFree (lpMsgBuf);
|
|
}
|
|
}
|
|
|
|
void SaveEnvironments (HWND owner, const ReverbContainer *defEnv)
|
|
{
|
|
MySaveData msd (defEnv);
|
|
OPENFILENAME ofn = { sizeof(ofn) };
|
|
char filename[PATH_MAX];
|
|
|
|
ofn.hwndOwner = owner;
|
|
ofn.hInstance = g_hInst;
|
|
ofn.lpstrFilter = "Text Files\0*.txt\0All Files\0*.*\0";
|
|
ofn.lpstrCustomFilter = NULL;
|
|
ofn.nMaxCustFilter = 0;
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = filename;
|
|
ofn.nMaxFile = sizeof(filename);
|
|
ofn.lpstrFileTitle = NULL;
|
|
ofn.nMaxFileTitle = 0;
|
|
ofn.lpstrInitialDir = NULL;
|
|
ofn.lpstrTitle = "Save EAX Environments As...";
|
|
ofn.Flags = OFN_ENABLEHOOK|OFN_ENABLESIZING|OFN_ENABLETEMPLATE|OFN_EXPLORER|
|
|
OFN_NOCHANGEDIR|OFN_OVERWRITEPROMPT;
|
|
ofn.nFileOffset = 0;
|
|
ofn.nFileExtension = 0;
|
|
ofn.lpstrDefExt = "txt";
|
|
ofn.lCustData = (LPARAM)&msd;
|
|
ofn.lpfnHook = SaveHookProc;
|
|
ofn.lpTemplateName = MAKEINTRESOURCE(IDD_SAVEEAX);
|
|
|
|
filename[0] = 0;
|
|
|
|
if (GetSaveFileName ((tagOFNA *)&ofn) && msd.NumSaves != 0)
|
|
{
|
|
ExportEnvironments (filename, msd.NumSaves, msd.Saves);
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK EAXProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
SCROLLINFO scrollInfo;
|
|
HWND hWnd;
|
|
RECT rect;
|
|
POINT ul;
|
|
ReverbContainer *env;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
hPropList = CreateDialog (g_hInst, MAKEINTRESOURCE(IDD_EAXPROPERTYLIST), hDlg, EAXProp);
|
|
hWnd = GetDlgItem (hDlg, IDC_DUMMY);
|
|
GetWindowRect (hPropList, &rect);
|
|
PropListMaxSize.x = rect.right - rect.left;
|
|
PropListMaxSize.y = rect.bottom - rect.top;
|
|
GetWindowRect (hWnd, &rect);
|
|
DestroyWindow (hWnd);
|
|
ul.x = rect.left;
|
|
ul.y = rect.top;
|
|
ScreenToClient (hDlg, &ul);
|
|
PropListMaxSize.x = rect.right - rect.left;
|
|
|
|
scrollInfo.cbSize = sizeof(scrollInfo);
|
|
scrollInfo.fMask = SIF_RANGE|SIF_POS|SIF_PAGE|SIF_DISABLENOSCROLL;
|
|
scrollInfo.nMin = 0;
|
|
scrollInfo.nMax = PropListMaxSize.y;
|
|
scrollInfo.nPos = 0;
|
|
scrollInfo.nPage = rect.bottom - rect.top;
|
|
SetScrollInfo (hPropList, SB_VERT, &scrollInfo, TRUE);
|
|
|
|
MoveWindow (hPropList, ul.x, ul.y, PropListMaxSize.x, rect.bottom - rect.top, FALSE);
|
|
ShowWindow (hPropList, SW_SHOW);
|
|
|
|
// Windows should have a layout control like MUI so that I don't have
|
|
// to do any extra work to make the dialog resizable.
|
|
|
|
GetClientRect (hDlg, &rect);
|
|
PropListHeightDiff = (rect.bottom - rect.top) - scrollInfo.nPage;
|
|
|
|
// Using a scroll bar to create a size box seems like an odd way of
|
|
// doing things.
|
|
|
|
hWnd = CreateWindow(
|
|
"Scrollbar",
|
|
(LPSTR)NULL,
|
|
WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN | WS_CLIPSIBLINGS,
|
|
0,0,rect.right,rect.bottom,
|
|
hDlg,
|
|
(HMENU)IDC_SIZEBOX,
|
|
g_hInst,
|
|
NULL);
|
|
|
|
TestLocation.x = DoneLocation.x = rect.right;
|
|
TestLocation.y = DoneLocation.y = rect.bottom;
|
|
GetWindowRect (GetDlgItem (hDlg, IDOK), &rect);
|
|
ScreenToClient (hDlg, (LPPOINT)&rect.left);
|
|
DoneLocation.x -= rect.left;
|
|
DoneLocation.y -= rect.top;
|
|
|
|
GetWindowRect (GetDlgItem (hDlg, IDC_TESTEAX), &rect);
|
|
ScreenToClient (hDlg, (LPPOINT)&rect.left);
|
|
TestLocation.x -= rect.left;
|
|
TestLocation.y -= rect.top;
|
|
|
|
GetWindowRect (hDlg, &rect);
|
|
EditWindowSize.x = rect.right - rect.left;
|
|
EditWindowSize.y = (rect.bottom - rect.top) - scrollInfo.nPage;
|
|
|
|
GetWindowRect (GetDlgItem (hDlg, IDC_NEW), &rect);
|
|
ScreenToClient (hDlg, (LPPOINT)&rect.left);
|
|
NewLeft = rect.left;
|
|
|
|
GetWindowRect (GetDlgItem (hDlg, IDC_SAVE), &rect);
|
|
ScreenToClient (hDlg, (LPPOINT)&rect.left);
|
|
SaveLeft = rect.left;
|
|
|
|
GetWindowRect (GetDlgItem (hDlg, IDC_REVERT), &rect);
|
|
ScreenToClient (hDlg, (LPPOINT)&rect.left);
|
|
RevertLeft = rect.left;
|
|
|
|
hWnd = GetDlgItem (hDlg, IDC_CURRENTENVIRONMENT);
|
|
PopulateEnvDropDown (hWnd, IsDlgButtonChecked (hDlg, IDC_SHOWIDS)==BST_CHECKED, NULL);
|
|
EAXProc (hDlg, WM_COMMAND, MAKELONG(IDC_CURRENTENVIRONMENT,CBN_SELENDOK), (LPARAM)hWnd);
|
|
|
|
CheckDlgButton (hDlg, IDC_TESTEAX, eaxedit_test ? BST_CHECKED : BST_UNCHECKED);
|
|
return 0;
|
|
|
|
case WM_SIZE:
|
|
if (wParam != SIZE_MAXHIDE && wParam != SIZE_MAXSHOW)
|
|
{
|
|
GetClientRect (hWnd = GetDlgItem (hDlg, IDC_SIZEBOX), &rect);
|
|
SetWindowPos (hWnd, HWND_BOTTOM, LOWORD(lParam)-rect.right, HIWORD(lParam)-rect.bottom, 0, 0, SWP_NOSIZE);
|
|
|
|
SetWindowPos (hPropList, NULL, 0, 0, PropListMaxSize.x, HIWORD(lParam)-PropListHeightDiff, SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_DEFERERASE);
|
|
SetWindowPos (GetDlgItem (hDlg, IDOK), NULL, LOWORD(lParam)-DoneLocation.x, HIWORD(lParam)-DoneLocation.y, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOSIZE);
|
|
SetWindowPos (GetDlgItem (hDlg, IDC_NEW), NULL, NewLeft, HIWORD(lParam)-DoneLocation.y, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOSIZE);
|
|
SetWindowPos (GetDlgItem (hDlg, IDC_SAVE), NULL, SaveLeft, HIWORD(lParam)-DoneLocation.y, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOSIZE);
|
|
SetWindowPos (GetDlgItem (hDlg, IDC_REVERT), NULL, RevertLeft, HIWORD(lParam)-DoneLocation.y, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOSIZE);
|
|
SetWindowPos (GetDlgItem (hDlg, IDC_TESTEAX), NULL, LOWORD(lParam)-TestLocation.x, HIWORD(lParam)-TestLocation.y, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOSIZE);
|
|
}
|
|
return 0;
|
|
|
|
case WM_NCDESTROY:
|
|
EAXEditWindow = 0;
|
|
//new FS_Switcher;
|
|
ForceWindowed = false;
|
|
if (fullscreen)
|
|
{
|
|
setmodeneeded = true;
|
|
}
|
|
ForcedEnvironment = NULL;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
DestroyWindow (hPropList);
|
|
DestroyWindow (hDlg);
|
|
return 1;
|
|
|
|
case IDC_NEW:
|
|
hWnd = GetDlgItem (hDlg, IDC_CURRENTENVIRONMENT);
|
|
env = (ReverbContainer *)DialogBoxParam (g_hInst,
|
|
MAKEINTRESOURCE(IDD_NEWEAX), hDlg, NewEAXProc,
|
|
SendMessage (hWnd, CB_GETITEMDATA,
|
|
SendMessage (hWnd, CB_GETCURSEL, 0, 0), 0));
|
|
if (env != NULL)
|
|
{
|
|
LRESULT i = AddEnvToDropDown (hWnd,
|
|
SendMessage (GetDlgItem (hDlg, IDC_SHOWIDS), BM_GETCHECK, 0, 0)==BST_CHECKED,
|
|
env);
|
|
SendMessage (hWnd, CB_SETCURSEL, i, 0);
|
|
UpdateControls (env, hDlg);
|
|
|
|
hWnd = GetDlgItem (hPropList, IDCE_ENVIRONMENTSIZE);
|
|
SetFocus (hWnd);
|
|
SendMessage (hWnd, EM_SETSEL, 0, -1);
|
|
}
|
|
return 0;
|
|
|
|
case IDC_REVERT:
|
|
hWnd = GetDlgItem (hDlg, IDC_CURRENTENVIRONMENT);
|
|
env = (ReverbContainer *)SendMessage (hWnd, CB_GETITEMDATA,
|
|
SendMessage (hWnd, CB_GETCURSEL, 0, 0), 0);
|
|
env->Properties = SavedProperties;
|
|
UpdateControls (env, hDlg);
|
|
return 0;
|
|
|
|
case IDC_SAVE:
|
|
hWnd = GetDlgItem (hDlg, IDC_CURRENTENVIRONMENT);
|
|
SaveEnvironments (hDlg,
|
|
(ReverbContainer *)SendMessage (hWnd, CB_GETITEMDATA,
|
|
SendMessage (hWnd, CB_GETCURSEL, 0, 0), 0));
|
|
return 0;
|
|
|
|
case IDC_TESTEAX:
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
{
|
|
eaxedit_test = (SendMessage ((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
}
|
|
break;
|
|
|
|
case IDC_SHOWIDS:
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
{
|
|
hWnd = GetDlgItem (hDlg, IDC_CURRENTENVIRONMENT);
|
|
PopulateEnvDropDown (hWnd,
|
|
SendMessage ((HWND)lParam, BM_GETCHECK, 0, 0)==BST_CHECKED,
|
|
(ReverbContainer *)SendMessage (hWnd, CB_GETITEMDATA,
|
|
SendMessage (hWnd, CB_GETCURSEL, 0, 0), 0));
|
|
EAXProc (hDlg, WM_COMMAND, MAKELONG(IDC_CURRENTENVIRONMENT,CBN_SELENDOK),
|
|
(LPARAM)hWnd);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case IDC_CURRENTENVIRONMENT:
|
|
if (HIWORD(wParam) == CBN_SELENDOK)
|
|
{
|
|
env = (ReverbContainer *)SendMessage ((HWND)lParam, CB_GETITEMDATA,
|
|
SendMessage ((HWND)lParam, CB_GETCURSEL, 0, 0), 0);
|
|
UpdateControls (env, hDlg);
|
|
}
|
|
return 0;
|
|
}
|
|
return 1;
|
|
|
|
case WM_GETMINMAXINFO:
|
|
((MINMAXINFO *)lParam)->ptMaxTrackSize.x =
|
|
((MINMAXINFO *)lParam)->ptMinTrackSize.x = EditWindowSize.x;
|
|
((MINMAXINFO *)lParam)->ptMaxTrackSize.y = EditWindowSize.y + PropListMaxSize.y + 5;
|
|
GetClientRect (GetDlgItem (hDlg, IDOK), &rect);
|
|
((MINMAXINFO *)lParam)->ptMinTrackSize.y = rect.bottom * 10;
|
|
return 0;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void ShowEAXEditor ()
|
|
{
|
|
EAXEditWindow = CreateDialog (g_hInst, MAKEINTRESOURCE(IDD_EAXEDIT), Window, EAXProc);
|
|
}
|
|
|
|
CCMD (reverbedit)
|
|
{
|
|
if (EAXEditWindow != 0)
|
|
{
|
|
SetForegroundWindow (EAXEditWindow);
|
|
}
|
|
else
|
|
{
|
|
ForceWindowed = true;
|
|
if (fullscreen)
|
|
{
|
|
setmodeneeded = true;
|
|
SpawnEAXWindow = true;
|
|
}
|
|
else
|
|
{
|
|
ShowEAXEditor ();
|
|
}
|
|
}
|
|
}
|