├── .github └── workflows │ └── ci.yml ├── .gitignore ├── README.md ├── Rebld └── Rebld.dsp ├── Rebuilder.dsw ├── Rebuilder └── Rebuilder.dsp ├── cmn ├── combo.h ├── path.cpp └── path.h ├── ext └── PropertyGrid │ ├── .gitignore │ ├── CMakeLists.txt │ ├── CustomItem.h │ ├── DynDialogEx.cpp │ ├── DynDialogEx.h │ ├── DynDialogItemEx.cpp │ ├── DynDialogItemEx.h │ ├── ListDynDialogEx.cpp │ ├── ListDynDialogEx.h │ ├── PropertyGrid.cpp │ ├── PropertyGrid.h │ ├── PropertyGridCombo.cpp │ ├── PropertyGridCombo.h │ ├── PropertyGridDirectoryPicker.cpp │ ├── PropertyGridDirectoryPicker.h │ ├── PropertyGridInPlaceEdit.cpp │ ├── PropertyGridInPlaceEdit.h │ ├── PropertyGridMonthCalCtrl.cpp │ ├── PropertyGridMonthCalCtrl.h │ ├── README.md │ ├── stdafx.cpp │ ├── stdafx.h │ └── test │ ├── CMakeLists.txt │ ├── CustomTreeCtrl.cpp │ ├── CustomTreeCtrl.h │ ├── GradientItem.cpp │ ├── GradientItem.h │ ├── PropGrid.cpp │ ├── PropGrid.h │ ├── PropGrid.rc │ ├── PropGridDlg.cpp │ ├── PropGridDlg.h │ ├── RectEditDlg.cpp │ ├── RectEditDlg.h │ ├── RectItem.cpp │ ├── RectItem.h │ ├── SerialItem.cpp │ ├── SerialItem.h │ ├── TreeItem.cpp │ ├── TreeItem.h │ ├── res │ ├── PropGrid.ico │ ├── PropGrid.manifest │ └── PropGrid.rc2 │ └── resource.h ├── lib ├── config.cpp ├── config.h ├── dllmain.cpp ├── hooks.cpp ├── hooks.h ├── util.cpp └── util.h ├── pkg └── fade.gif ├── res ├── mama.ico ├── res.manifest ├── res.rc └── resource.h └── src ├── app.cpp ├── app.h ├── clinkstatic.cpp ├── clinkstatic.h ├── launcher.cpp ├── launcher.h ├── patchgrid.cpp ├── patchgrid.h ├── tabs.cpp ├── tabs.h ├── window.cpp └── window.h /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths-ignore: 8 | - 'README.md' 9 | pull_request: 10 | branches: 11 | - master 12 | paths-ignore: 13 | - 'README.md' 14 | 15 | jobs: 16 | 17 | build: 18 | 19 | runs-on: windows-latest 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v2 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: Install Visual C++ 6.0 28 | run: | 29 | git clone --depth 1 https://github.com/itsmattkc/MSVC600 30 | 31 | - name: Build 32 | shell: cmd 33 | run: | 34 | call MSVC600/VC98/Bin/vcvars32.bat 35 | msdev Rebuilder.dsw /make 36 | 37 | - name: Upload a Build Artifact 38 | uses: actions/upload-artifact@v2.2.1 39 | with: 40 | path: 41 | Rebuilder/Release/Rebuilder.exe 42 | 43 | - name: Upload to Releases 44 | shell: bash 45 | if: github.event_name == 'push' 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | TRAVIS_REPO_SLUG: isledecomp/LEGOIslandRebuilder 49 | TRAVIS_COMMIT: ${{ github.sha }} 50 | run: | 51 | curl -fLOSs --retry 2 --retry-delay 60 https://github.com/probonopd/uploadtool/raw/master/upload.sh 52 | ./upload.sh Rebuilder/Release/Rebuilder.exe 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | Debug/ 3 | Release/ 4 | *.user 5 | *.obj 6 | *.dll 7 | *.exp 8 | *.lib 9 | *.exe 10 | *.res 11 | *.plg 12 | *.ncb 13 | *.opt 14 | *.aps 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 |
4 | LEGO Island Rebuilder 5 | LEGO Island Rebuilder 6 |
7 |

8 | 9 |

A launcher and modification/patching tool for the 1997 video game LEGO Island

10 | 11 |

12 | 13 | 14 | 15 | 16 | 17 | 18 |

19 | 20 |

21 | Homepage • 22 | Info • 23 | Download • 24 | Building • 25 | Usage • 26 | Contributing 27 |

28 | 29 |

30 | 31 |

32 | 33 |

Supports Windows 95 - Windows 11 (Linux and macOS through Wine)

34 | 35 | ## Info 36 | 37 | LEGO Island Rebuilder is a launcher and modification tool for Mindscape's 1997 video game LEGO Island. It is the product of in-depth research done on the game; the bulk of which is documented on the [LEGO Island Wiki](https://www.legoisland.org/). 38 | 39 | It includes fixes to numerous bugs in the original game and multiple quality of life patches while making no permanent changes to the game installation. Additionally, Rebuilder acts as a full replacement for the original configuration tool. 40 | 41 | Rebuilder currently supports [all known versions of LEGO Island](https://www.legoisland.org/wiki/index.php/LEGO_Island_Versions). 42 | 43 | ## Download 44 | 45 | The latest binaries are available on the [releases page](https://github.com/itsmattkc/LEGOIslandRebuilder/releases/tag/continuous). 46 | 47 | ## Building 48 | 49 | LEGO Island Rebuilder specifically targets Microsoft Visual C++ 6.0 in order to retain compatibility with Windows 95. It is highly recommended to use this compiler at all times, as code written for newer compilers may not be compatible with this version. 50 | 51 | Rebuilder can be built with the standard Visual C++ 6.0 IDE. Since the MSVC 6.0 installer is known to have issues on newer versions of Windows, a portable version of MSVC 6.0 is available [here](https://github.com/itsmattkc/MSVC600). 52 | 53 | Since the IDE is old and somewhat archaic, you may wish to use a more modern IDE/code editor. This can be done by using the following commands as your build step in the IDE of your choice: 54 | 55 | ``` 56 | # Enter Visual C++ 6.0 build environment 57 | /VC98/bin/VCVARS32.BAT 58 | 59 | # Build the project 60 | msdev Rebuilder.dsw /make 61 | ``` 62 | 63 | (Replace `` with the directory you installed/cloned MSVC 6.0 to) 64 | 65 | Rebuilder can only be built in "Release" mode. This is because it utilizes DLL injection to modify LEGO Island in memory, and with MSVC, "Debug" code is incompatible with "Release" code (which is what LEGO Island was naturally compiled as). 66 | 67 | ## Usage 68 | 69 | By default, Rebuilder opens a graphical interface which can be used to set the patch configuration and to launch the game. However, command line arguments are also supported: 70 | 71 | * `-r/--run`: Runs LEGO Island with the currently saved configuration, bypassing Rebuilder's interface entirely. 72 | * `-h/--help`: Shows a help screen with usage details. 73 | 74 | ### Linux and macOS 75 | 76 | Rebuilder works on non-Windows platforms using Wine. Ensure LEGO Island is installed into the same prefix you're running Rebuilder in, and it should work identically to Windows. 77 | 78 | ## Contributing 79 | 80 | Contributions like code changes, documentation, or findings and research about the game are welcome. The best way of contributing code to Rebuilder is to open a [pull request](https://github.com/itsmattkc/LEGOIslandRebuilder/pulls). 81 | -------------------------------------------------------------------------------- /Rebld/Rebld.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="Rebld" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 6 | 7 | CFG=REBLD - WIN32 RELEASE 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "Rebld.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "Rebld.mak" CFG="REBLD - WIN32 RELEASE" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "Rebld - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") 21 | !MESSAGE 22 | 23 | # Begin Project 24 | # PROP AllowPerConfigDependencies 0 25 | # PROP Scc_ProjName "" 26 | # PROP Scc_LocalPath "" 27 | CPP=cl.exe 28 | MTL=midl.exe 29 | RSC=rc.exe 30 | # PROP BASE Use_MFC 0 31 | # PROP BASE Use_Debug_Libraries 0 32 | # PROP BASE Output_Dir "Release" 33 | # PROP BASE Intermediate_Dir "Release" 34 | # PROP BASE Target_Dir "" 35 | # PROP Use_MFC 0 36 | # PROP Use_Debug_Libraries 0 37 | # PROP Output_Dir "Release" 38 | # PROP Intermediate_Dir "Release" 39 | # PROP Ignore_Export_Lib 0 40 | # PROP Target_Dir "" 41 | # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "REBLD_EXPORTS" /YX /FD /c 42 | # ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "REBLD_EXPORTS" /YX /FD /c 43 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 44 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 45 | # ADD BASE RSC /l 0x409 /d "NDEBUG" 46 | # ADD RSC /l 0x409 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LINK32=link.exe 51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 52 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib shlwapi.lib winmm.lib dxguid.lib /nologo /dll /machine:I386 53 | # Begin Target 54 | 55 | # Name "Rebld - Win32 Release" 56 | # Begin Group "Source Files" 57 | 58 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 59 | # Begin Source File 60 | 61 | SOURCE=..\lib\config.cpp 62 | # End Source File 63 | # Begin Source File 64 | 65 | SOURCE=..\lib\dllmain.cpp 66 | # End Source File 67 | # Begin Source File 68 | 69 | SOURCE=..\lib\hooks.cpp 70 | # End Source File 71 | # Begin Source File 72 | 73 | SOURCE=..\cmn\path.cpp 74 | # End Source File 75 | # Begin Source File 76 | 77 | SOURCE=..\lib\util.cpp 78 | # End Source File 79 | # End Group 80 | # Begin Group "Header Files" 81 | 82 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 83 | # Begin Source File 84 | 85 | SOURCE=..\cmn\combo.h 86 | # End Source File 87 | # Begin Source File 88 | 89 | SOURCE=..\lib\config.h 90 | # End Source File 91 | # Begin Source File 92 | 93 | SOURCE=..\lib\hooks.h 94 | # End Source File 95 | # Begin Source File 96 | 97 | SOURCE=..\cmn\path.h 98 | # End Source File 99 | # Begin Source File 100 | 101 | SOURCE=..\lib\util.h 102 | # End Source File 103 | # End Group 104 | # Begin Group "Resource Files" 105 | 106 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 107 | # End Group 108 | # End Target 109 | # End Project 110 | -------------------------------------------------------------------------------- /Rebuilder.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "Rebld"=.\Rebld\Rebld.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Project: "Rebuilder"=.\Rebuilder\Rebuilder.dsp - Package Owner=<4> 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<4> 25 | {{{ 26 | Begin Project Dependency 27 | Project_Dep_Name Rebld 28 | End Project Dependency 29 | }}} 30 | 31 | ############################################################################### 32 | 33 | Global: 34 | 35 | Package=<5> 36 | {{{ 37 | }}} 38 | 39 | Package=<3> 40 | {{{ 41 | }}} 42 | 43 | ############################################################################### 44 | 45 | -------------------------------------------------------------------------------- /Rebuilder/Rebuilder.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="Rebuilder" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Application" 0x0101 6 | 7 | CFG=REBUILDER - WIN32 RELEASE 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "Rebuilder.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "Rebuilder.mak" CFG="REBUILDER - WIN32 RELEASE" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "Rebuilder - Win32 Release" (based on "Win32 (x86) Application") 21 | !MESSAGE 22 | 23 | # Begin Project 24 | # PROP AllowPerConfigDependencies 0 25 | # PROP Scc_ProjName "" 26 | # PROP Scc_LocalPath "" 27 | CPP=cl.exe 28 | MTL=midl.exe 29 | RSC=rc.exe 30 | # PROP BASE Use_MFC 0 31 | # PROP BASE Use_Debug_Libraries 0 32 | # PROP BASE Output_Dir "Release" 33 | # PROP BASE Intermediate_Dir "Release" 34 | # PROP BASE Target_Dir "" 35 | # PROP Use_MFC 1 36 | # PROP Use_Debug_Libraries 0 37 | # PROP Output_Dir "Release" 38 | # PROP Intermediate_Dir "Release" 39 | # PROP Ignore_Export_Lib 0 40 | # PROP Target_Dir "" 41 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c 42 | # ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c 43 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 44 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 45 | # ADD BASE RSC /l 0x409 /d "NDEBUG" 46 | # ADD RSC /l 0x409 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LINK32=link.exe 51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 52 | # ADD LINK32 shlwapi.lib ddraw.lib dxguid.lib /nologo /subsystem:windows /machine:I386 53 | # Begin Target 54 | 55 | # Name "Rebuilder - Win32 Release" 56 | # Begin Group "Source Files" 57 | 58 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 59 | # Begin Source File 60 | 61 | SOURCE=..\src\app.cpp 62 | # End Source File 63 | # Begin Source File 64 | 65 | SOURCE=..\src\clinkstatic.cpp 66 | # End Source File 67 | # Begin Source File 68 | 69 | SOURCE=..\ext\PropertyGrid\DynDialogEx.cpp 70 | # End Source File 71 | # Begin Source File 72 | 73 | SOURCE=..\ext\PropertyGrid\DynDialogItemEx.cpp 74 | # End Source File 75 | # Begin Source File 76 | 77 | SOURCE=..\src\launcher.cpp 78 | # End Source File 79 | # Begin Source File 80 | 81 | SOURCE=..\ext\PropertyGrid\ListDynDialogEx.cpp 82 | # End Source File 83 | # Begin Source File 84 | 85 | SOURCE=..\src\patchgrid.cpp 86 | # End Source File 87 | # Begin Source File 88 | 89 | SOURCE=..\cmn\path.cpp 90 | # End Source File 91 | # Begin Source File 92 | 93 | SOURCE=..\ext\PropertyGrid\PropertyGrid.cpp 94 | # End Source File 95 | # Begin Source File 96 | 97 | SOURCE=..\ext\PropertyGrid\PropertyGridCombo.cpp 98 | # End Source File 99 | # Begin Source File 100 | 101 | SOURCE=..\ext\PropertyGrid\PropertyGridDirectoryPicker.cpp 102 | # End Source File 103 | # Begin Source File 104 | 105 | SOURCE=..\ext\PropertyGrid\PropertyGridInPlaceEdit.cpp 106 | # End Source File 107 | # Begin Source File 108 | 109 | SOURCE=..\ext\PropertyGrid\PropertyGridMonthCalCtrl.cpp 110 | # End Source File 111 | # Begin Source File 112 | 113 | SOURCE=..\res\res.rc 114 | # End Source File 115 | # Begin Source File 116 | 117 | SOURCE=..\ext\PropertyGrid\stdafx.cpp 118 | # End Source File 119 | # Begin Source File 120 | 121 | SOURCE=..\src\tabs.cpp 122 | # End Source File 123 | # Begin Source File 124 | 125 | SOURCE=..\src\window.cpp 126 | # End Source File 127 | # End Group 128 | # Begin Group "Header Files" 129 | 130 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 131 | # Begin Source File 132 | 133 | SOURCE=..\src\app.h 134 | # End Source File 135 | # Begin Source File 136 | 137 | SOURCE=..\src\clinkstatic.h 138 | # End Source File 139 | # Begin Source File 140 | 141 | SOURCE=..\cmn\combo.h 142 | # End Source File 143 | # Begin Source File 144 | 145 | SOURCE=..\ext\PropertyGrid\CustomItem.h 146 | # End Source File 147 | # Begin Source File 148 | 149 | SOURCE=..\ext\PropertyGrid\DynDialogEx.h 150 | # End Source File 151 | # Begin Source File 152 | 153 | SOURCE=..\ext\PropertyGrid\DynDialogItemEx.h 154 | # End Source File 155 | # Begin Source File 156 | 157 | SOURCE=..\src\launcher.h 158 | # End Source File 159 | # Begin Source File 160 | 161 | SOURCE=..\ext\PropertyGrid\ListDynDialogEx.h 162 | # End Source File 163 | # Begin Source File 164 | 165 | SOURCE=..\src\patchgrid.h 166 | # End Source File 167 | # Begin Source File 168 | 169 | SOURCE=..\cmn\path.h 170 | # End Source File 171 | # Begin Source File 172 | 173 | SOURCE=..\ext\PropertyGrid\PropertyGrid.h 174 | # End Source File 175 | # Begin Source File 176 | 177 | SOURCE=..\ext\PropertyGrid\PropertyGridCombo.h 178 | # End Source File 179 | # Begin Source File 180 | 181 | SOURCE=..\ext\PropertyGrid\PropertyGridDirectoryPicker.h 182 | # End Source File 183 | # Begin Source File 184 | 185 | SOURCE=..\ext\PropertyGrid\PropertyGridInPlaceEdit.h 186 | # End Source File 187 | # Begin Source File 188 | 189 | SOURCE=..\ext\PropertyGrid\PropertyGridMonthCalCtrl.h 190 | # End Source File 191 | # Begin Source File 192 | 193 | SOURCE=..\res\resource.h 194 | # End Source File 195 | # Begin Source File 196 | 197 | SOURCE=..\ext\PropertyGrid\stdafx.h 198 | # End Source File 199 | # Begin Source File 200 | 201 | SOURCE=..\src\tabs.h 202 | # End Source File 203 | # Begin Source File 204 | 205 | SOURCE=..\src\window.h 206 | # End Source File 207 | # End Group 208 | # Begin Group "Resource Files" 209 | 210 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 211 | # Begin Source File 212 | 213 | SOURCE=..\res\mama.ico 214 | # End Source File 215 | # End Group 216 | # Begin Source File 217 | 218 | SOURCE=..\res\res.manifest 219 | # End Source File 220 | # End Target 221 | # End Project 222 | -------------------------------------------------------------------------------- /cmn/combo.h: -------------------------------------------------------------------------------- 1 | #ifndef COMBO_H 2 | #define COMBO_H 3 | 4 | enum ModelQuality { 5 | kModelQualityInfinite, 6 | kModelQualityHigh, 7 | kModelQualityMedium, 8 | kModelQualityLow 9 | }; 10 | 11 | #endif // COMBO_H 12 | -------------------------------------------------------------------------------- /cmn/path.cpp: -------------------------------------------------------------------------------- 1 | #include "path.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | LPCTSTR appName = TEXT("Rebuilder"); 9 | 10 | BOOL DirectoryExists(LPCTSTR szPath) 11 | { 12 | return PathFileExists(szPath) && PathIsDirectory(szPath); 13 | } 14 | 15 | BOOL RecursivelyCreateDirectory(LPCTSTR directory) 16 | { 17 | if (DirectoryExists(directory)) { 18 | // Directory already exists, do nothing 19 | return TRUE; 20 | } else { 21 | // Determine directory of this directory 22 | std::basic_string copy = directory; 23 | PathRemoveFileSpec(©[0]); 24 | 25 | // Create if necessary 26 | if (RecursivelyCreateDirectory(copy.c_str())) { 27 | return CreateDirectory(directory, NULL); 28 | } else { 29 | return FALSE; 30 | } 31 | } 32 | } 33 | 34 | #ifdef UNICODE 35 | typedef BOOL (WINAPI *SHGetSpecialFolderPath_t)(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate); 36 | #else 37 | typedef BOOL (WINAPI *SHGetSpecialFolderPath_t)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); 38 | #endif 39 | BOOL GetAppDataPath(LPTSTR s) 40 | { 41 | // Dynamically link to SHGetSpecialFolderPath because not all versions of Windows have it 42 | #ifdef UNICODE 43 | LPCSTR functionName = "SHGetSpecialFolderPathW"; 44 | #else 45 | LPCSTR functionName = "SHGetSpecialFolderPathA"; 46 | #endif 47 | 48 | SHGetSpecialFolderPath_t getSpecialFolderPath = (SHGetSpecialFolderPath_t)GetProcAddress(LoadLibrary(_T("SHELL32.DLL")), functionName); 49 | BOOL haveDir = FALSE; 50 | BOOL usedShell = FALSE; 51 | if (getSpecialFolderPath) { 52 | haveDir = getSpecialFolderPath(NULL, s, CSIDL_APPDATA, TRUE); 53 | usedShell = TRUE; 54 | } else { 55 | // Assume we're on Windows 95 which has no application data folder, we bodge it to write to 56 | // "C:\Windows\Application Data" which is roughly where 98/Me would do it 57 | GetWindowsDirectory(s, MAX_PATH); 58 | _tcscat(s, _T("\\Application Data")); 59 | haveDir = TRUE; 60 | } 61 | 62 | return haveDir; 63 | } 64 | 65 | BOOL GetConfigFilename(LPTSTR s) 66 | { 67 | if (GetAppDataPath(s)) { 68 | _tcscat(s, _T("\\LEGOIslandRebuilder")); 69 | if (RecursivelyCreateDirectory(s)) { 70 | _tcscat(s, _T("\\settings.ini")); 71 | return TRUE; 72 | } 73 | } 74 | 75 | return FALSE; 76 | } 77 | 78 | BOOL GetSafeLEGOIslandSavePath(LPTSTR s) 79 | { 80 | if (GetAppDataPath(s)) { 81 | _tcscat(s, _T("\\LEGO Island")); 82 | if (RecursivelyCreateDirectory(s)) { 83 | return TRUE; 84 | } 85 | } 86 | 87 | return FALSE; 88 | } 89 | -------------------------------------------------------------------------------- /cmn/path.h: -------------------------------------------------------------------------------- 1 | #ifndef PATH_H 2 | #define PATH_H 3 | 4 | #include 5 | 6 | BOOL GetSafeLEGOIslandSavePath(LPTSTR s); 7 | 8 | BOOL GetConfigFilename(LPTSTR s); 9 | 10 | extern LPCTSTR appName; 11 | 12 | #endif // PATH_H 13 | -------------------------------------------------------------------------------- /ext/PropertyGrid/.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | *.user 3 | -------------------------------------------------------------------------------- /ext/PropertyGrid/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(PropertyGrid LANGUAGES CXX) 4 | 5 | set(CMAKE_MFC_FLAG 2) 6 | add_compile_definitions(_AFXDLL) 7 | 8 | option(PROPERTYGRID_BUILD_APP "Build with test application" ON) 9 | 10 | add_library(PropertyGrid STATIC 11 | CustomItem.h 12 | DynDialogEx.cpp 13 | DynDialogEx.h 14 | DynDialogItemEx.cpp 15 | DynDialogItemEx.h 16 | ListDynDialogEx.cpp 17 | ListDynDialogEx.h 18 | PropertyGrid.cpp 19 | PropertyGrid.h 20 | PropertyGridCombo.cpp 21 | PropertyGridCombo.h 22 | PropertyGridDirectoryPicker.cpp 23 | PropertyGridDirectoryPicker.h 24 | PropertyGridInPlaceEdit.cpp 25 | PropertyGridInPlaceEdit.h 26 | PropertyGridMonthCalCtrl.cpp 27 | PropertyGridMonthCalCtrl.h 28 | stdafx.cpp 29 | stdafx.h 30 | ) 31 | 32 | target_link_libraries(PropertyGrid PRIVATE shlwapi.lib) 33 | 34 | if (PROPERTYGRID_BUILD_APP) 35 | add_subdirectory(test) 36 | endif() 37 | -------------------------------------------------------------------------------- /ext/PropertyGrid/CustomItem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PropertyGrid.h" 3 | 4 | class ICustomItem 5 | { 6 | public: 7 | // basic required stuff 8 | virtual CPropertyGrid::EEditMode GetEditMode() = 0; 9 | virtual void DrawItem(CDC& dc, CRect rc, bool focused) = 0; 10 | 11 | // validation 12 | virtual void ValidateChanges() {} 13 | 14 | // mouse stuff 15 | virtual bool OnLButtonDown(CRect rc, CPoint pt) { return false; } 16 | virtual void OnMouseMove(CRect rc, CPoint pt) {} 17 | virtual void OnLButtonUp(CRect rc, CPoint pt) {} 18 | 19 | // in-place edit 20 | virtual string GetStringForInPlaceEdit() { return ""; } 21 | virtual bool OnItemEdited(string strNewValue) { return false; } 22 | 23 | // dropdown edit 24 | virtual void ShowDropDown(CRect rc) {} 25 | 26 | // modal edit 27 | virtual bool OnEditItem() { return false; } 28 | 29 | protected: 30 | friend class CPropertyGrid; 31 | CPropertyGrid* m_pGrid; 32 | }; 33 | -------------------------------------------------------------------------------- /ext/PropertyGrid/DynDialogEx.cpp: -------------------------------------------------------------------------------- 1 | // DynDialogItemEx.cpp: implementation of the CDynDialogItemEx class. 2 | // 3 | // Written by Marcel Scherpenisse 4 | // mailto:Marcel_Scherpenisse@insad.nl 5 | // 6 | // This code may be used in compiled form in any way you desire. This 7 | // file may be redistributed unmodified by any means PROVIDING it is 8 | // not sold for profit without the authors written consent, and 9 | // providing that this notice and the authors name and all copyright 10 | // notices remains intact. If the source code in this file is used in 11 | // any commercial application then a statement along the lines of 12 | // "Portions copyright (c) Marcel Scherpenisse, 2002" must be included in 13 | // the startup banner, "About" box or printed documentation. An email 14 | // letting me know that you are using it would be nice as well. 15 | // 16 | // This file is provided "as is" with no expressed or implied warranty. 17 | // The author accepts no liability for any damage/loss of business that 18 | // this product may cause. 19 | // 20 | // Expect bugs! 21 | ////////////////////////////////////////////////////////////////////// 22 | 23 | 24 | #include "stdafx.h" 25 | #include "DynDialogEx.h" 26 | 27 | #ifdef _DEBUG 28 | #define new DEBUG_NEW 29 | #undef THIS_FILE 30 | static char THIS_FILE[] = __FILE__; 31 | #endif 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | // CDynDialogEx dialog 35 | 36 | 37 | CDynDialogEx::CDynDialogEx(CWnd* pParent /*=NULL*/) 38 | : CDialog() 39 | { 40 | //{{AFX_DATA_INIT(CDynDialogEx) 41 | // NOTE: the ClassWizard will add member initialization here 42 | //}}AFX_DATA_INIT 43 | 44 | m_DialogTemplate.style = WS_CAPTION | WS_SYSMENU | WS_VISIBLE | DS_SETFONT; 45 | m_DialogTemplate.dwExtendedStyle = WS_EX_DLGMODALFRAME; 46 | m_DialogTemplate.x = 0; 47 | m_DialogTemplate.y = 0; 48 | m_DialogTemplate.cx = 0; // 4 horizontal units are the width of one character 49 | m_DialogTemplate.cy = 0; // 8 vertical units are the height of one character 50 | m_DialogTemplate.cdit = 0; // nr of dialog items in the dialog 51 | 52 | m_pParentWnd = pParent; 53 | m_strCaption = _T(""); 54 | m_pFont = NULL; 55 | m_wFontSize = 0; 56 | m_nCurRow = FIRSTROW1; 57 | m_bAddSystemButtons = TRUE; 58 | 59 | m_bIsFontCreated = FALSE; 60 | m_bModelessDlg = FALSE; 61 | } 62 | 63 | CDynDialogEx::~CDynDialogEx() 64 | { 65 | CDynDialogItemEx *pDynDialogItemEx = NULL; 66 | for (INT_PTR i = m_arrDlgItemPtr.size() - 1; i >= 0; i--) { 67 | pDynDialogItemEx = m_arrDlgItemPtr[i]; 68 | if (pDynDialogItemEx != NULL) { 69 | delete pDynDialogItemEx; 70 | pDynDialogItemEx = NULL; 71 | } 72 | } 73 | 74 | if (m_bIsFontCreated) { 75 | delete m_pFont; 76 | } 77 | } 78 | 79 | CWnd *CDynDialogEx::GetParent() 80 | { 81 | return m_pParentWnd; 82 | } 83 | 84 | void CDynDialogEx::AddStyles(DWORD dwStyles) 85 | { 86 | m_DialogTemplate.style |= dwStyles; 87 | } 88 | 89 | void CDynDialogEx::RemoveStyles(DWORD dwStyles) 90 | { 91 | m_DialogTemplate.style &= (~dwStyles); 92 | } 93 | 94 | void CDynDialogEx::DoDataExchange(CDataExchange* pDX) 95 | { 96 | CDialog::DoDataExchange(pDX); 97 | //{{AFX_DATA_MAP(CDynDialogEx) 98 | // NOTE: the ClassWizard will add DDX and DDV calls here 99 | //}}AFX_DATA_MAP 100 | 101 | CDynDialogItemEx *pDynDialogItemEx = NULL; 102 | for (INT_PTR i = m_arrDlgItemPtr.size() - 1; i >= 0; i--) { 103 | pDynDialogItemEx = m_arrDlgItemPtr[i]; 104 | if (pDynDialogItemEx != NULL) { 105 | pDynDialogItemEx->DoDataExchange(pDX); 106 | } 107 | } 108 | } 109 | 110 | BEGIN_MESSAGE_MAP(CDynDialogEx, CDialog) 111 | //{{AFX_MSG_MAP(CDynDialogEx) 112 | ON_WM_CREATE() 113 | //}}AFX_MSG_MAP 114 | ON_MESSAGE(WM_HELP, OnHelpMsg) 115 | ON_WM_MEASUREITEM() // TMB! 06-12-2001 Adjusted.. was wrongly an ON_MESSAGE()!! 116 | ON_WM_DRAWITEM() // TMB! 06-12-2001 Adjusted.. was wrongly an ON_MESSAGE()!! 117 | END_MESSAGE_MAP() 118 | 119 | ///////////////////////////////////////////////////////////////////////////// 120 | // CDynDialogEx message handlers 121 | 122 | int CDynDialogEx::OnCreate(LPCREATESTRUCT lpCreateStruct) 123 | { 124 | if (CDialog::OnCreate(lpCreateStruct) == -1) 125 | return -1; 126 | 127 | //if we have no font, create one here 128 | if (m_pFont == NULL) { 129 | LOGFONT LogFont; 130 | 131 | // Can do better??? 132 | memset(&LogFont, 0x00, sizeof(LogFont)); 133 | strncpy(LogFont.lfFaceName, _T("MS Sans Serif"), LF_FACESIZE); 134 | LogFont.lfHeight = 8; 135 | 136 | m_pFont = new CFont; 137 | m_pFont->CreateFontIndirect(&LogFont); 138 | SetFont(m_pFont); 139 | m_bIsFontCreated = TRUE; 140 | } 141 | 142 | //Create all the controls on the dialog 143 | CDynDialogItemEx *pDynDialogItemEx = NULL; 144 | for (int i = 0; i < m_arrDlgItemPtr.size(); i++) { 145 | pDynDialogItemEx = m_arrDlgItemPtr[i]; 146 | if (pDynDialogItemEx != NULL) { 147 | if (!pDynDialogItemEx->IsDlgItemSubclassed()) { 148 | if (!pDynDialogItemEx->CreateEx(this)) { 149 | AfxMessageBox(_T("Failed to create DlgItem.")); 150 | } 151 | else if (pDynDialogItemEx->GetSafeHwnd() != NULL) { 152 | pDynDialogItemEx->SetFont(m_pFont, FALSE); 153 | } 154 | } 155 | } 156 | } 157 | 158 | return 0; 159 | } 160 | 161 | BOOL CDynDialogEx::OnInitDialog() 162 | { 163 | //Reposition all the controls on the dialog... 164 | CDynDialogItemEx *pDynDialogItemEx = NULL; 165 | for (int i = 0; i < m_arrDlgItemPtr.size(); i++) { 166 | pDynDialogItemEx = m_arrDlgItemPtr[i]; 167 | if (pDynDialogItemEx != NULL) { 168 | if (!pDynDialogItemEx->IsDlgItemSubclassed() && !pDynDialogItemEx->SetWindowPos(this)) { 169 | CString strMessage; 170 | strMessage.Format(_T("Failed SetWindowPos for control %s."), pDynDialogItemEx->GetClassName()); 171 | AfxMessageBox(strMessage); 172 | } 173 | } 174 | } 175 | 176 | CDialog::OnInitDialog(); 177 | 178 | CenterWindow(); 179 | 180 | return TRUE; // return TRUE unless you set the focus to a control 181 | // EXCEPTION: OCX Property Pages should return FALSE 182 | } 183 | 184 | int CDynDialogEx::DoModal() 185 | { 186 | //Do we need OK and Cancel buttons?? 187 | if (m_bAddSystemButtons) { 188 | AddSystemButtons(); 189 | } 190 | 191 | // 192 | // Get font info from mainwindow of the application 193 | // 194 | CFont* pParentFont = m_pFont; 195 | if (pParentFont == NULL && m_pParentWnd != NULL) { 196 | pParentFont = m_pParentWnd->GetFont(); 197 | } 198 | if (pParentFont == NULL && AfxGetApp()->m_pActiveWnd != NULL) { 199 | pParentFont = AfxGetApp()->m_pActiveWnd->GetFont(); 200 | } 201 | LOGFONT LogFont; 202 | memset(&LogFont, 0x00, sizeof(LogFont)); 203 | if (pParentFont != NULL) { 204 | pParentFont->GetLogFont(&LogFont); 205 | } 206 | else { 207 | // Can do better??? 208 | strncpy(LogFont.lfFaceName, _T("MS Sans Serif"), LF_FACESIZE); 209 | LogFont.lfHeight = 8; 210 | } 211 | 212 | //Prework for setting font in dialog... 213 | int cWC = MultiByteToWideChar(CP_ACP, 0, LogFont.lfFaceName, -1, NULL, 0); 214 | int nFontNameLen = cWC + 1; 215 | WCHAR *szFontName = new WCHAR[nFontNameLen]; 216 | // Copy the string 217 | MultiByteToWideChar(CP_ACP, 0, LogFont.lfFaceName, -1, (LPWSTR) szFontName, cWC); 218 | szFontName[cWC] = 0; 219 | nFontNameLen = (cWC) * sizeof(WCHAR); 220 | 221 | if (m_wFontSize == 0) { 222 | m_wFontSize = (unsigned short)LogFont.lfHeight; 223 | } 224 | 225 | //Prework for setting caption in dialog... 226 | cWC = MultiByteToWideChar(CP_ACP, 0, m_strCaption, -1, NULL, 0); 227 | int szBoxLen = cWC + 1; 228 | WCHAR *szBoxCaption = new WCHAR[szBoxLen]; 229 | // Copy the string 230 | MultiByteToWideChar(CP_ACP, 0, m_strCaption, -1, (LPWSTR) szBoxCaption, cWC); 231 | szBoxCaption[cWC] = 0; 232 | szBoxLen = (cWC) * sizeof(WCHAR); 233 | 234 | INT_PTR iRet = -1; 235 | //Here 's the stuff to build the dialog template in memory 236 | //without the controls being in the template 237 | //(Our first try, was this same template with some additional code 238 | //for each control placed on it, that's why this class is cold Ex :) 239 | //This gave some problems on WIN9x systems, where EDIT boxes 240 | //were not shown with 3D-look, but as flat controls) 241 | int nBufferSize = sizeof(DLGTEMPLATE) + (2 * sizeof(WORD)) /*menu and class*/ + szBoxLen /*size of caption*/ 242 | + sizeof(WORD) /*fontsize*/ + nFontNameLen /*size of fontname*/; 243 | 244 | //Are there any subclassed controls... 245 | if (m_DialogTemplate.cdit > 0) { 246 | nBufferSize = (nBufferSize + 3) & ~3; // adjust size to make first control DWORD aligned 247 | 248 | CDynDialogItemEx *pDynDialogItemEx = NULL; 249 | for (int i = 0; i < m_arrDlgItemPtr.size(); i++) { 250 | pDynDialogItemEx = m_arrDlgItemPtr[i]; 251 | if (pDynDialogItemEx != NULL) { 252 | if (pDynDialogItemEx->IsDlgItemSubclassed()) { 253 | int nItemLength = sizeof(DLGITEMTEMPLATE) + 3 * sizeof(WORD); 254 | nItemLength += (pDynDialogItemEx->GetCaptionLength() + 1) * sizeof(WCHAR); 255 | 256 | if (i != m_DialogTemplate.cdit - 1) { // the last control does not need extra bytes 257 | nItemLength = (nItemLength + 3) & ~3; // take into account gap so next control is DWORD aligned 258 | } 259 | nBufferSize += nItemLength; 260 | } 261 | } 262 | } 263 | } 264 | 265 | HLOCAL hLocal = LocalAlloc(LHND, nBufferSize); 266 | if (hLocal != NULL) { 267 | BYTE* pBuffer = (BYTE*)LocalLock(hLocal); 268 | if (pBuffer == NULL) { 269 | LocalFree(hLocal); 270 | AfxMessageBox(_T("CDynDialogEx::DoModal() : LocalLock Failed")); 271 | } 272 | 273 | BYTE *pdest = pBuffer; 274 | // transfer DLGTEMPLATE structure to the buffer 275 | memcpy(pdest, &m_DialogTemplate, sizeof(DLGTEMPLATE)); // DLGTemplate 276 | pdest += sizeof(DLGTEMPLATE); 277 | *(WORD*)pdest = 0; // no menu -- WORD to say it is 0 bytes 278 | pdest += sizeof(WORD); // Increment 279 | *(WORD*)(pdest + 1) = 0; // use default window class -- WORD to say it is 0 bytes 280 | pdest += sizeof(WORD); // Increment 281 | memcpy(pdest, szBoxCaption, szBoxLen); // Caption 282 | pdest += szBoxLen; 283 | 284 | *(WORD*)pdest = m_wFontSize; // font size 285 | pdest += sizeof(WORD); 286 | memcpy(pdest, szFontName, nFontNameLen); // font name 287 | pdest += nFontNameLen; 288 | 289 | // will now transfer the information for each one of subclassed controls... 290 | if (m_DialogTemplate.cdit > 0) { 291 | CDynDialogItemEx *pDynDialogItemEx = NULL; 292 | for (int i = 0; i < m_arrDlgItemPtr.size(); i++) { 293 | pDynDialogItemEx = m_arrDlgItemPtr[i]; 294 | if (pDynDialogItemEx != NULL) { 295 | if (pDynDialogItemEx->IsDlgItemSubclassed()) { 296 | pdest = pDynDialogItemEx->FillBufferWithItemTemplate(pdest); 297 | } 298 | } 299 | } 300 | } 301 | ASSERT(pdest - pBuffer == nBufferSize); // just make sure we did not overrun the heap 302 | 303 | //Next lines to make sure that MFC makes no ASSERTION when PREVIOUS/NEXT is pressed:) 304 | if (m_lpDialogTemplate != NULL) { 305 | m_lpDialogTemplate = NULL; 306 | } 307 | 308 | //These are the MFC functions, which do the job... 309 | if (m_bModelessDlg) { 310 | iRet = CreateIndirect((LPDLGTEMPLATE)pBuffer, m_pParentWnd); 311 | } 312 | else { 313 | InitModalIndirect((LPDLGTEMPLATE)pBuffer, m_pParentWnd); 314 | iRet = CDialog::DoModal(); 315 | } 316 | 317 | LocalUnlock(hLocal); 318 | LocalFree(hLocal); 319 | 320 | delete [] szBoxCaption; 321 | delete [] szFontName; 322 | return iRet; 323 | } 324 | else { 325 | AfxMessageBox(_T("CDynDialogEx::DoModal() : LocalAllock Failed")); 326 | return -1; 327 | } 328 | } 329 | 330 | void CDynDialogEx::SetFont(CFont *pFont) 331 | { 332 | m_pFont = pFont; 333 | } 334 | 335 | CFont *CDynDialogEx::GetFont() 336 | { 337 | return m_pFont; 338 | } 339 | 340 | void CDynDialogEx::SetFontSize(WORD wSize) 341 | { 342 | m_wFontSize = wSize; 343 | } 344 | 345 | WORD CDynDialogEx::GetFontSize() 346 | { 347 | return m_wFontSize; 348 | } 349 | 350 | void CDynDialogEx::SetUseSystemButtons(BOOL bUse /*= TRUE*/) 351 | { 352 | m_bAddSystemButtons = bUse; 353 | } 354 | 355 | void CDynDialogEx::GetDlgRect(LPRECT lpRect) 356 | { 357 | ASSERT(lpRect); 358 | lpRect->left = m_DialogTemplate.x; 359 | lpRect->top = m_DialogTemplate.y; 360 | lpRect->right = lpRect->left + m_DialogTemplate.cx; 361 | lpRect->bottom = lpRect->top + m_DialogTemplate.cy; 362 | } 363 | 364 | void CDynDialogEx::SetDlgRect(LPRECT lpRect) 365 | { 366 | ASSERT(lpRect); 367 | //#pragma warning(disable : 4244) 368 | m_DialogTemplate.cx = (short)(lpRect->right - lpRect->left); 369 | m_DialogTemplate.cy = (short)(lpRect->bottom - lpRect->top); 370 | m_DialogTemplate.x = (short)(lpRect->left); 371 | m_DialogTemplate.y = (short)(lpRect->top); 372 | //#pragma warning(default : 4244) 373 | } 374 | 375 | void CDynDialogEx::SetDlgRectangle(LPRECT pRect) 376 | { 377 | RECT rect; 378 | 379 | GetDlgRect(&rect); 380 | if (rect.left > pRect->left) { 381 | rect.left = pRect->left; 382 | } 383 | if (rect.right < pRect->right) { 384 | rect.right = pRect->right + 5; 385 | } 386 | if (rect.top > pRect->top) { 387 | rect.top = pRect->top; 388 | } 389 | if (rect.bottom < pRect->bottom) { 390 | rect.bottom = pRect->bottom + 5; 391 | } 392 | SetDlgRect(&rect); 393 | } 394 | 395 | UINT CDynDialogEx::AddDlgControl(DLGITEMTEMPLATECONTROLS TypeControl, 396 | LPCTSTR lpszCaption, 397 | DWORD dwStyle, 398 | DWORD dwExtendedStyle, 399 | LPRECT pRect /*= NULL*/, 400 | void *pData /*= NULL*/, 401 | UINT nID /*= 0*/) 402 | { 403 | UINT nRet = 0; 404 | //In case no rectangle given create our own... 405 | CRect Rect(FIXEDCOL1, m_nCurRow, FIXEDCOL2, m_nCurRow + ROWSTEPSIZE); 406 | 407 | //if no rectangle given use our own... 408 | if (pRect == NULL) { 409 | pRect = &Rect; 410 | } 411 | // else { 412 | // m_nCurRow = max(m_nCurRow, pRect->bottom) - m_nCurRow; 413 | // } 414 | 415 | m_nCurRow += (ROWSTEPSIZE); 416 | 417 | //Update dialogtemplate boundaries 418 | SetDlgRectangle(pRect); 419 | 420 | //Create control and add to array of controls 421 | CDynDialogItemEx *pDynDialogItemEx = new CDynDialogItemEx; 422 | if (pDynDialogItemEx != NULL) { 423 | nRet = pDynDialogItemEx->InitDialogItem(TypeControl, dwStyle, dwExtendedStyle, pRect, lpszCaption, nID, FALSE, pData); 424 | m_arrDlgItemPtr.push_back(pDynDialogItemEx); 425 | } 426 | 427 | //Return ID of Control we created. 428 | return nRet; 429 | } 430 | 431 | UINT CDynDialogEx::AddDlgControl(LPCSTR lpszClassName, 432 | LPCTSTR lpszCaption, 433 | DWORD dwStyle, 434 | DWORD dwExtendedStyle, 435 | LPRECT pRect /*= NULL*/, 436 | void *pData /*= NULL*/, 437 | UINT nID /*= 0*/) 438 | { 439 | UINT nRet = 0; 440 | //In case no rectangle given create our own... 441 | CRect Rect(FIXEDCOL1, m_nCurRow, FIXEDCOL2, m_nCurRow + ROWSTEPSIZE); 442 | 443 | //if no rectangle given use our own... 444 | if (pRect == NULL) { 445 | pRect = &Rect; 446 | Rect.right += INPUTCOL; 447 | } 448 | // else { 449 | // m_nCurRow = max(m_nCurRow, pRect->bottom) - m_nCurRow; 450 | // } 451 | 452 | m_nCurRow += (ROWSTEPSIZE); 453 | 454 | //Update dialogtemplate boundaries 455 | SetDlgRectangle(pRect); 456 | 457 | //Create control and add to array of controls 458 | CDynDialogItemEx *pDynDialogItemEx = new CDynDialogItemEx; 459 | if (pDynDialogItemEx != NULL) { 460 | nRet = pDynDialogItemEx->InitDialogItem(lpszClassName, dwStyle, dwExtendedStyle, pRect, lpszCaption, nID, FALSE, pData); 461 | m_arrDlgItemPtr.push_back(pDynDialogItemEx); 462 | } 463 | 464 | //Return ID of Control we created. 465 | return nRet; 466 | } 467 | 468 | UINT CDynDialogEx::AddSubclassedDlgControl(LPCSTR lpszClassName, 469 | LPCTSTR lpszCaption, 470 | DWORD dwStyle, 471 | DWORD dwExtendedStyle, 472 | LPRECT pRect /*= NULL*/, 473 | UINT nID /*= 0*/) 474 | { 475 | UINT nRet = 0; 476 | //In case no rectangle given create our own... 477 | CRect Rect(FIXEDCOL1, m_nCurRow, FIXEDCOL2, m_nCurRow + ROWSTEPSIZE); 478 | 479 | //if no rectangle given use our own... 480 | if (pRect == NULL) { 481 | pRect = &Rect; 482 | Rect.right += INPUTCOL; 483 | } 484 | // else { 485 | // m_nCurRow = max(m_nCurRow, pRect->bottom) - m_nCurRow; 486 | // } 487 | 488 | m_nCurRow += (ROWSTEPSIZE); 489 | 490 | //Update dialogtemplate boundaries 491 | SetDlgRectangle(pRect); 492 | 493 | //Create control and add to array of controls 494 | CDynDialogItemEx *pDynDialogItemEx = new CDynDialogItemEx; 495 | if (pDynDialogItemEx != NULL) { 496 | nRet = pDynDialogItemEx->InitDialogItem(lpszClassName, dwStyle, dwExtendedStyle, pRect, lpszCaption, nID, TRUE); 497 | m_arrDlgItemPtr.push_back(pDynDialogItemEx); 498 | m_DialogTemplate.cdit++; 499 | } 500 | 501 | //Return ID of Control we created. 502 | return nRet; 503 | } 504 | 505 | void CDynDialogEx::AddSystemButtons() 506 | { 507 | m_nCurRow += 6; // Leave some room! 508 | CRect rect(FIXEDCOL1, m_nCurRow, FIXEDCOL2 - 60, m_nCurRow + (long)(ROWSTEPSIZE * 1.2)); 509 | 510 | AddDlgControl(BUTTON, _T("OK"), STYLE_BUTTON, EXSTYLE_BUTTON, &rect, NULL, IDOK); 511 | 512 | // This has to be revised later. 513 | rect.left += 55; 514 | rect.right += 55; 515 | AddDlgControl(BUTTON, _T("Annuleren"), STYLE_BUTTON, EXSTYLE_BUTTON, &rect, NULL, IDCANCEL); 516 | 517 | } 518 | 519 | void CDynDialogEx::SetWindowTitle(LPCSTR lpszCaption) 520 | { 521 | m_strCaption = lpszCaption; 522 | } 523 | 524 | void CDynDialogEx::SetUseModeless(BOOL bModelessDlg /*= TRUE*/) 525 | { 526 | m_bModelessDlg = bModelessDlg; 527 | } 528 | 529 | void CDynDialogEx::OnCancel() 530 | { 531 | if (m_bModelessDlg) { 532 | DestroyWindow(); 533 | } 534 | else { 535 | CDialog::OnCancel(); 536 | } 537 | } 538 | 539 | void CDynDialogEx::OnOK() 540 | { 541 | if (m_bModelessDlg) { 542 | DestroyWindow(); 543 | } 544 | else { 545 | CDialog::OnOK(); 546 | } 547 | } 548 | 549 | BOOL CDynDialogEx::OnCommand(WPARAM wParam, LPARAM lParam) 550 | { 551 | //wParam 552 | //The low-order word of wParam identifies the command ID of the menu item, control, or accelerator. 553 | //The high-order word of wParam specifies the notification message if the message is from a control. 554 | //If the message is from an accelerator, the high-order word is 1. 555 | //If the message is from a menu, the high-order word is 0. 556 | 557 | //lParam 558 | //Identifies the control that sends the message if the message is from a control. Otherwise, lParam is 0. 559 | 560 | WORD wControlID = LOWORD(wParam); 561 | WORD wMessageID = HIWORD(wParam); 562 | 563 | if (wControlID != 0) { 564 | switch (wControlID) { 565 | case IDOK: 566 | OnOK(); 567 | return TRUE; 568 | break; 569 | case IDCANCEL: 570 | OnCancel(); 571 | return TRUE; 572 | break; 573 | default: 574 | //if we have a parent send the message to the parent, so we can handle the message over there. 575 | if (m_pParentWnd != NULL) { 576 | ::SendMessage(m_pParentWnd->GetSafeHwnd(), WM_COMMAND, wParam, lParam); 577 | } 578 | break; 579 | } 580 | } 581 | 582 | return CDialog::OnCommand(wParam, lParam); 583 | } 584 | 585 | // Hellup! 586 | afx_msg LRESULT CDynDialogEx::OnHelpMsg(WPARAM wParam, LPARAM lParam) 587 | { 588 | //lParam <<-- Contains: (LPHELPINFO)lParam 589 | // >> typedef struct tagHELPINFO { 590 | // UINT cbSize; 591 | // int iContextType 592 | // int iCtrlId; 593 | // HANDLE hItemHandle; 594 | // DWORD dwContextId; 595 | // POINT MousePos; 596 | // } HELPINFO, FAR *LPHELPINFO; 597 | 598 | // 599 | // User pressed F1 in dialog, call the OnHelp() function, this can be overridden... 600 | // 601 | OnHelp(); 602 | return TRUE; 603 | } 604 | 605 | // Default implementation of the OnHelp() 606 | // This one is to be overridden by a caller ;) 607 | void CDynDialogEx::OnHelp() 608 | { 609 | CDialog::OnHelp(); 610 | } 611 | -------------------------------------------------------------------------------- /ext/PropertyGrid/DynDialogEx.h: -------------------------------------------------------------------------------- 1 | #if !defined(AFX_DYNDIALOGEX_H__CF5AF5E8_BD00_11D3_AA7C_0008C7083CA9__INCLUDED_) 2 | #define AFX_DYNDIALOGEX_H__CF5AF5E8_BD00_11D3_AA7C_0008C7083CA9__INCLUDED_ 3 | 4 | #if _MSC_VER > 1000 5 | #pragma once 6 | #endif // _MSC_VER > 1000 7 | // DynDialogEx.h : header file 8 | // 9 | 10 | #include 11 | #include "DynDialogItemEx.h" 12 | 13 | // Control styles 14 | #define STYLE_EDIT (WS_VISIBLE | WS_CHILD | WS_TABSTOP | SS_LEFT) 15 | #define STYLE_MULTIEDIT (WS_VISIBLE | WS_CHILD | WS_TABSTOP | SS_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | ES_WANTRETURN) 16 | #define STYLE_STATIC (WS_VISIBLE | WS_CHILD | SS_LEFT) 17 | #define STYLE_STATIC_CENTER (WS_VISIBLE | WS_CHILD | SS_CENTER) 18 | #define STYLE_STATIC_RIGHT (WS_VISIBLE | WS_CHILD | SS_RIGHT) 19 | #define STYLE_RADIO (WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON) 20 | #define STYLE_RADIO_GROUP (STYLE_RADIO| WS_GROUP | WS_TABSTOP) 21 | #define STYLE_BUTTON (WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_PUSHBUTTON) 22 | #define STYLE_GROUPBOX (WS_VISIBLE | WS_CHILD | BS_GROUPBOX) 23 | #define STYLE_CHECKBOX (WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | BS_AUTOCHECKBOX) 24 | #define STYLE_COMBOBOX_DROPDOWN (WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | WS_VSCROLL | CBS_DROPDOWN | CBS_SORT | CBS_AUTOHSCROLL) // | CBS_DISABLENOSCROLL) 25 | #define STYLE_COMBOBOX_DROPDOWN_NOSORT (WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | WS_VSCROLL | CBS_DROPDOWN | CBS_AUTOHSCROLL) // | CBS_DISABLENOSCROLL) 26 | #define STYLE_COMBOBOX_SIMPLE (WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | WS_VSCROLL | CBS_SIMPLE | CBS_SORT | CBS_AUTOHSCROLL) // | CBS_DISABLENOSCROLL) 27 | #define STYLE_COMBOBOX_SIMPLE_NOSORT (WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | WS_VSCROLL | CBS_SIMPLE | CBS_AUTOHSCROLL) // | CBS_DISABLENOSCROLL) 28 | #define STYLE_COMBOBOX_DROPDOWNLIST (WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_SORT | CBS_AUTOHSCROLL) // | CBS_DISABLENOSCROLL) 29 | #define STYLE_COMBOBOX_DROPDOWNLIST_NOSORT (WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_AUTOHSCROLL) // | CBS_DISABLENOSCROLL) 30 | #define STYLE_LISTBOX (WS_VISIBLE | WS_CHILD | WS_TABSTOP | LBS_STANDARD) 31 | 32 | #define STYLE_DATETIMEPICKER (WS_VISIBLE | WS_CHILD | WS_TABSTOP | DTS_RIGHTALIGN) 33 | #define STYLE_TIMEPICKER (WS_VISIBLE | WS_CHILD | WS_TABSTOP | DTS_RIGHTALIGN | DTS_TIMEFORMAT) 34 | // Default combo-style 35 | #define STYLE_COMBOBOX (STYLE_COMBOBOX_DROPDOWNLIST) 36 | #define STYLE_COMBOBOX_NOSORT (STYLE_COMBOBOX_DROPDOWNLIST_NOSORT) 37 | 38 | // Control Extended styles 39 | #define EXSTYLE_EDIT (WS_EX_CLIENTEDGE) 40 | #define EXSTYLE_MULTIEDIT (WS_EX_CLIENTEDGE) 41 | #define EXSTYLE_LISTBOX (WS_EX_CLIENTEDGE) 42 | #define EXSTYLE_STATIC (0) 43 | #define EXSTYLE_RADIO (0) 44 | #define EXSTYLE_BUTTON (0) 45 | #define EXSTYLE_GROUPBOX (0) 46 | #define EXSTYLE_CHECKBOX (0) 47 | #define EXSTYLE_COMBOBOX (0) 48 | #define EXSTYLE_DATETIMEPICKER (0) 49 | #define EXSTYLE_TIMEPICKER (0) 50 | 51 | #define ROWSTEPSIZE 12 52 | #define FIRSTROW1 10 53 | #define FIRSTROW2 37 54 | #define FIXEDCOL1 10 55 | #define FIXEDCOL2 120 56 | #define INPUTCOL 150 57 | #define GROWLIMIT 6 58 | 59 | #define MAX_COLS_PER_DESCR 25 // Just a number.. 60 | 61 | ///////////////////////////////////////////////////////////////////////////// 62 | // CDynDialogEx dialog 63 | 64 | class CDynDialogEx : public CDialog 65 | { 66 | // Construction 67 | public: 68 | CDynDialogEx(CWnd* pParent = NULL); // standard constructor 69 | ~CDynDialogEx(); 70 | 71 | virtual CWnd *GetParent(); 72 | 73 | // Dialog Data 74 | //{{AFX_DATA(CDynDialogEx) 75 | // NOTE: the ClassWizard will add data members here 76 | //}}AFX_DATA 77 | 78 | virtual UINT AddDlgControl(DLGITEMTEMPLATECONTROLS TypeControl, 79 | LPCTSTR lpszCaption, 80 | DWORD dwStyle, 81 | DWORD dwExtendedStyle, 82 | LPRECT pRect = NULL, 83 | void *pData = NULL, 84 | UINT nID = 0); 85 | virtual UINT AddDlgControl(LPCSTR lpszClassName, 86 | LPCTSTR lpszCaption, 87 | DWORD dwStyle, 88 | DWORD dwExtendedStyle, 89 | LPRECT pRect = NULL, 90 | void *pData = NULL, 91 | UINT nID = 0); 92 | virtual UINT AddSubclassedDlgControl(LPCSTR lpszClassName, 93 | LPCTSTR lpszCaption, 94 | DWORD dwStyle, 95 | DWORD dwExtendedStyle, 96 | LPRECT pRect = NULL, 97 | UINT nID = 0); 98 | void SetWindowTitle(LPCSTR lpszCaption); 99 | void SetFont(CFont *pFont); 100 | CFont *GetFont(); 101 | void SetFontSize(WORD wSize); 102 | WORD GetFontSize(); 103 | void SetUseSystemButtons(BOOL bUse = TRUE); 104 | void SetUseModeless(BOOL bModelessDlg = TRUE); 105 | long GetNumberOfConrols() {return long(m_arrDlgItemPtr.size());} 106 | 107 | //Additional functions by Tom Daffin 108 | void AddStyles(DWORD dwStyles); 109 | void RemoveStyles(DWORD dwStyles); 110 | 111 | // Overrides 112 | // ClassWizard generated virtual function overrides 113 | //{{AFX_VIRTUAL(CDynDialogEx) 114 | public: 115 | virtual int DoModal(); 116 | protected: 117 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 118 | virtual void OnCancel(); 119 | virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); 120 | virtual void OnOK(); 121 | //}}AFX_VIRTUAL 122 | virtual void OnHelp(); // To be overridden.. 123 | 124 | protected: 125 | CWnd *m_pParentWnd; 126 | CString m_strCaption; 127 | CFont *m_pFont; 128 | WORD m_wFontSize; 129 | long m_nCurRow; 130 | BOOL m_bAddSystemButtons; 131 | BOOL m_bIsFontCreated; 132 | BOOL m_bModelessDlg; 133 | 134 | DLGTEMPLATE m_DialogTemplate; 135 | 136 | // DOWNGRADE: Switch from CArray to std::vector because MFC 4.2 doesn't have CArray 137 | std::vector m_arrDlgItemPtr; 138 | 139 | // Implementation 140 | protected: 141 | void AddSystemButtons(); 142 | void GetDlgRect(LPRECT lpRect); 143 | void SetDlgRect(LPRECT lpRect); 144 | void SetDlgRectangle(LPRECT pRect); 145 | 146 | 147 | // Generated message map functions 148 | //{{AFX_MSG(CDynDialogEx) 149 | virtual BOOL OnInitDialog(); 150 | afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 151 | //}}AFX_MSG 152 | afx_msg LRESULT OnHelpMsg(WPARAM wParam, LPARAM lParam); 153 | 154 | DECLARE_MESSAGE_MAP() 155 | }; 156 | 157 | //{{AFX_INSERT_LOCATION}} 158 | // Microsoft Visual C++ will insert additional declarations immediately before the previous line. 159 | 160 | #endif // !defined(AFX_DYNDIALOGEX_H__CF5AF5E8_BD00_11D3_AA7C_0008C7083CA9__INCLUDED_) 161 | -------------------------------------------------------------------------------- /ext/PropertyGrid/DynDialogItemEx.cpp: -------------------------------------------------------------------------------- 1 | // DynDialogItemEx.cpp: implementation of the CDynDialogItemEx class. 2 | // 3 | // Written by Marcel Scherpenisse 4 | // mailto:Marcel_Scherpenisse@insad.nl 5 | // 6 | // This code may be used in compiled form in any way you desire. This 7 | // file may be redistributed unmodified by any means PROVIDING it is 8 | // not sold for profit without the authors written consent, and 9 | // providing that this notice and the authors name and all copyright 10 | // notices remains intact. If the source code in this file is used in 11 | // any commercial application then a statement along the lines of 12 | // "Portions copyright (c) Marcel Scherpenisse, 2002" must be included in 13 | // the startup banner, "About" box or printed documentation. An email 14 | // letting me know that you are using it would be nice as well. 15 | // 16 | // This file is provided "as is" with no expressed or implied warranty. 17 | // The author accepts no liability for any damage/loss of business that 18 | // this product may cause. 19 | // 20 | // Expect bugs! 21 | ////////////////////////////////////////////////////////////////////// 22 | 23 | 24 | #include "stdafx.h" 25 | #include "DynDialogItemEx.h" 26 | 27 | #ifdef _DEBUG 28 | #undef THIS_FILE 29 | static char THIS_FILE[]=__FILE__; 30 | #define new DEBUG_NEW 31 | #endif 32 | 33 | struct _RuntimeLicense { 34 | LPCTSTR lpszRegisteredControlName; 35 | WCHAR *wchLicenseKey; 36 | long lLicenseLength; 37 | }_TAGRUNTIMELICENSE; 38 | 39 | /*mgkgtgnnmnmninigthkgogggvmkhinjggnvm*/ //(MS Multimedia MCI Control - mci32.ocx) 40 | WCHAR pwchMCIMMControl1LicenseKey[] = 41 | { 42 | 0x006D, 0x0067, 0x006B, 0x0067, 0x0074, 0x0067, 43 | 0x006E, 0x006E, 0x006D, 0x006E, 0x006D, 0x006E, 44 | 0x0069, 0x006E, 0x0069, 0x0067, 0x0074, 0x0068, 45 | 0x006B, 0x0067, 0x006F, 0x0067, 0x0067, 0x0067, 46 | 0x0076, 0x006D, 0x006B, 0x0068, 0x0069, 0x006E, 47 | 0x006A, 0x0067, 0x0067, 0x006E, 0x0076, 0x006D 48 | }; 49 | 50 | /*Copyright (c) 1994 */ //(MS Communications Control - mscomm32.ocx) 51 | WCHAR pwchMSCOMMLibMSComm1LicenseKey[] = 52 | { 53 | 0x0043, 0x006F, 0x0070, 0x0079, 0x0072, 0x0069, 54 | 0x0067, 0x0068, 0x0074, 0x0020, 0x0028, 0x0063, 55 | 0x0029, 0x0020, 0x0031, 0x0039, 0x0039, 0x0034, 56 | 0x0020 57 | }; 58 | 59 | /*72E67120-5959-11cf-91F6-C2863C385E30*/ //(MS Flex Grid Control - msflxgrd.ocx) 60 | WCHAR pwchMSFlexGridLibMSFlexGrid1LicenseKey[] = 61 | { 62 | 0x0037, 0x0032, 0x0045, 0x0036, 0x0037, 0x0031, 63 | 0x0032, 0x0030, 0x002D, 0x0035, 0x0039, 0x0035, 64 | 0x0039, 0x002D, 0x0031, 0x0031, 0x0063, 0x0066, 65 | 0x002D, 0x0039, 0x0031, 0x0046, 0x0036, 0x002D, 66 | 0x0043, 0x0032, 0x0038, 0x0036, 0x0033, 0x0043, 67 | 0x0033, 0x0038, 0x0035, 0x0045, 0x0033, 0x0030 68 | }; 69 | 70 | /*mgkgtgnnmnmninigthkgogggvmkhinjggnvm*/ //(MS Masked Edit - msmask32.ocx) 71 | WCHAR pwchMSMaskMaskEdBox1LicenseKey[] = 72 | { 73 | 0x006D, 0x0067, 0x006B, 0x0067, 0x0074, 0x0067, 74 | 0x006E, 0x006E, 0x006D, 0x006E, 0x006D, 0x006E, 75 | 0x0069, 0x006E, 0x0069, 0x0067, 0x0074, 0x0068, 76 | 0x006B, 0x0067, 0x006F, 0x0067, 0x0067, 0x0067, 77 | 0x0076, 0x006D, 0x006B, 0x0068, 0x0069, 0x006E, 78 | 0x006A, 0x0067, 0x0067, 0x006E, 0x0076, 0x006D 79 | }; 80 | 81 | /*GL........*/ //(MS Grid Control - grid32.ocx) 82 | WCHAR pwchMSDBGridDBGridLicenseKey[] = 83 | { 84 | 0x0047, 0x004C, 0x0005, 0x0008, 0x0001, 0x0005, 85 | 0x0002, 0x0008, 0x0001, 0x0004 86 | }; 87 | 88 | /*DB4C0D09-400B-101B-A3C9-08002B2F49FB*/ //(MS Picture Clip Control - picclp32.ocx) 89 | WCHAR pwchPicClipPictureClip1LicenseKey[] = 90 | { 91 | 0x0044, 0x0042, 0x0034, 0x0043, 0x0030, 0x0044, 92 | 0x0030, 0x0039, 0x002D, 0x0034, 0x0030, 0x0030, 93 | 0x0042, 0x002D, 0x0031, 0x0030, 0x0031, 0x0042, 94 | 0x002D, 0x0041, 0x0033, 0x0043, 0x0039, 0x002D, 95 | 0x0030, 0x0038, 0x0030, 0x0030, 0x0032, 0x0042, 96 | 0x0032, 0x0046, 0x0034, 0x0039, 0x0046, 0x0042 97 | }; 98 | 99 | /*04746E60CE4F11CDB23C0000C076FE*/ //(MS Tab Control - tabctl32.ocx) 100 | static WCHAR pwchTabDlgSSTab1LicenseKey[] = 101 | { 102 | 0x0030, 0x0034, 0x0037, 0x0034, 0x0036, 0x0045, 103 | 0x0036, 0x0030, 0x0043, 0x0045, 0x0034, 0x0046, 104 | 0x0031, 0x0031, 0x0043, 0x0044, 0x0042, 0x0032, 105 | 0x0033, 0x0043, 0x0030, 0x0030, 0x0030, 0x0030, 106 | 0x0043, 0x0030, 0x0037, 0x0036, 0x0046, 0x0045 107 | }; 108 | 109 | static _RuntimeLicense RuntimeLicenses[] = 110 | { 111 | {_T("MCI.MMControl.1"), pwchMCIMMControl1LicenseKey, sizeof(pwchMCIMMControl1LicenseKey)}, 112 | {_T("MSCOMMLib.MSComm.1"), pwchMSCOMMLibMSComm1LicenseKey, sizeof(pwchMSCOMMLibMSComm1LicenseKey)}, 113 | {_T("MSFlexGridLib.MSFlexGrid.1"), pwchMSFlexGridLibMSFlexGrid1LicenseKey, sizeof(pwchMSFlexGridLibMSFlexGrid1LicenseKey)}, 114 | {_T("MSMask.MaskEdBox.1"), pwchMSMaskMaskEdBox1LicenseKey, sizeof(pwchMSMaskMaskEdBox1LicenseKey)}, 115 | {_T("MSDBGrid.DBGrid"), pwchMSDBGridDBGridLicenseKey, sizeof(pwchMSDBGridDBGridLicenseKey)}, 116 | {_T("PicClip.PictureClip.1"), pwchPicClipPictureClip1LicenseKey, sizeof(pwchPicClipPictureClip1LicenseKey)}, 117 | {_T("TabDlg.SSTab.1"), pwchTabDlgSSTab1LicenseKey, sizeof(pwchTabDlgSSTab1LicenseKey)}, 118 | {NULL, NULL, 0} 119 | }; 120 | 121 | static UINT glb_nNextID = WM_USER; // We have to start somewhere... 122 | 123 | UINT GetNewUniqueID(void) 124 | { 125 | glb_nNextID++; 126 | return glb_nNextID - 1; 127 | } 128 | 129 | ////////////////////////////////////////////////////////////////////// 130 | // Construction/Destruction 131 | ////////////////////////////////////////////////////////////////////// 132 | 133 | CDynDialogItemEx::CDynDialogItemEx() 134 | : CWnd() 135 | { 136 | m_eTypeControl = NOCONTROL; 137 | m_strClassName = _T(""); 138 | m_dwStyle = 0; 139 | m_dwStyleEx = 0; 140 | m_strCaption = _T(""); 141 | m_ControlID = 0; 142 | m_pData = NULL; 143 | m_bSubclassed = FALSE; 144 | } 145 | 146 | void CDynDialogItemEx::DoDataExchange(CDataExchange *pDX) 147 | { 148 | if (m_pData != NULL) { 149 | switch(m_eTypeControl) { 150 | case BUTTON: 151 | if ((m_dwStyle & BS_AUTORADIOBUTTON) == BS_AUTORADIOBUTTON) { 152 | DDX_Radio(pDX, m_ControlID, *(int*)m_pData); 153 | } 154 | else if ((m_dwStyle & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX) { 155 | DDX_Check(pDX, m_ControlID, *(int*)m_pData); 156 | } 157 | else { 158 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 159 | } 160 | break; 161 | case EDITCONTROL: 162 | DDX_Text(pDX, m_ControlID, *(CString*)m_pData); 163 | break; 164 | case STATICTEXT: 165 | DDX_Text(pDX, m_ControlID, *(CString*)m_pData); 166 | break; 167 | case LISTBOX: 168 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 169 | break; 170 | case HSCROLL: 171 | DDX_Scroll(pDX, m_ControlID, *(int*)m_pData); 172 | break; 173 | case COMBOBOX: 174 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 175 | break; 176 | case SPIN: 177 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 178 | break; 179 | case PROGRES: 180 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 181 | break; 182 | case SLIDER: 183 | DDX_Slider(pDX, m_ControlID, *(int*)m_pData); 184 | break; 185 | case HOTKEY: 186 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 187 | break; 188 | case LISTCTRL: 189 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 190 | break; 191 | case TREECTRL: 192 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 193 | break; 194 | case TABCTRL: 195 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 196 | break; 197 | case ANIMATE: 198 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 199 | break; 200 | case RICHEDIT: 201 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 202 | break; 203 | case DATETIMEPICKER: 204 | if ((m_dwStyle & DTS_TIMEFORMAT) == DTS_TIMEFORMAT) { 205 | DDX_DateTimeCtrl(pDX, m_ControlID, *(CTime*)m_pData); 206 | } 207 | else { 208 | DDX_DateTimeCtrl(pDX, m_ControlID, *(COleDateTime*)m_pData); 209 | } 210 | break; 211 | case MONTHCALENDER: 212 | DDX_MonthCalCtrl(pDX, m_ControlID, *(COleDateTime*)m_pData); 213 | break; 214 | case IPADRESS: 215 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 216 | break; 217 | case COMBOBOXEX: 218 | DDX_Control(pDX, m_ControlID, *(CWnd*)m_pData); 219 | break; 220 | default: 221 | break; 222 | } 223 | } 224 | CWnd::DoDataExchange(pDX); 225 | } 226 | 227 | BEGIN_MESSAGE_MAP(CDynDialogItemEx, CWnd) 228 | //{{AFX_MSG_MAP(CDynDialogItemEx) 229 | //}}AFX_MSG_MAP 230 | END_MESSAGE_MAP() 231 | 232 | char* CDynDialogItemEx::GetClassNameByType(DLGITEMTEMPLATECONTROLS TypeControl) 233 | { 234 | switch(TypeControl) { 235 | case BUTTON: 236 | return _T("BUTTON"); 237 | case EDITCONTROL: 238 | return _T("EDIT"); 239 | case STATICTEXT: 240 | return _T("STATIC"); 241 | case LISTBOX: 242 | return _T("LISTBOX"); 243 | case HSCROLL: 244 | return _T("SCROLLBAR"); 245 | case COMBOBOX: 246 | return _T("COMBOBOX"); 247 | case SPIN: 248 | return _T("msctls_updown32"); 249 | case PROGRES: 250 | return _T("msctls_progress32"); 251 | case SLIDER: 252 | return _T("msctls_trackbar32"); 253 | case HOTKEY: 254 | return _T("msctls_hotkey32"); 255 | case LISTCTRL: 256 | return _T("SysListView32"); 257 | case TREECTRL: 258 | return _T("SysTreeView32"); 259 | case TABCTRL: 260 | return _T("SysTabControl32"); 261 | case ANIMATE: 262 | return _T("SysAnimate32"); 263 | case RICHEDIT: 264 | return _T("RICHEDIT"); 265 | case DATETIMEPICKER: 266 | return _T("SysDateTimePick32"); 267 | case MONTHCALENDER: 268 | return _T("SysMonthCal32"); 269 | case IPADRESS: 270 | return _T("SysIPAddress32"); 271 | case COMBOBOXEX: 272 | return _T("ComboBoxEx32"); 273 | } 274 | return _T(""); 275 | } 276 | 277 | DLGITEMTEMPLATECONTROLS CDynDialogItemEx::GetClassTypeByName(LPCSTR lpszClassName) 278 | { 279 | if (memcmp(lpszClassName, _T("BUTTON"), 6) == 0) { 280 | return BUTTON; 281 | } 282 | else if (memcmp(lpszClassName, _T("EDIT"), 4) == 0) { 283 | return EDITCONTROL; 284 | } 285 | else if (memcmp(lpszClassName, _T("STATIC"), 6) == 0) { 286 | return STATICTEXT; 287 | } 288 | else if (memcmp(lpszClassName, _T("LISTBOX"), 7) == 0) { 289 | return LISTBOX; 290 | } 291 | else if (memcmp(lpszClassName, _T("SCROLLBAR"), 9) == 0) { 292 | return HSCROLL; 293 | } 294 | else if (memcmp(lpszClassName, _T("COMBOBOX"), 8) == 0) { 295 | return COMBOBOX; 296 | } 297 | else if (memcmp(lpszClassName, _T("msctls_updown32"), 15) == 0) { 298 | return SPIN; 299 | } 300 | else if (memcmp(lpszClassName, _T("msctls_progress32"), 17) == 0) { 301 | return PROGRES; 302 | } 303 | else if (memcmp(lpszClassName, _T("msctls_trackbar32"), 17) == 0) { 304 | return SLIDER; 305 | } 306 | else if (memcmp(lpszClassName, _T("msctls_hotkey32"), 15) == 0) { 307 | return HOTKEY; 308 | } 309 | else if (memcmp(lpszClassName, _T("SysListView32"), 13) == 0) { 310 | return LISTCTRL; 311 | } 312 | else if (memcmp(lpszClassName, _T("SysTreeView32"), 13) == 0) { 313 | return TREECTRL; 314 | } 315 | else if (memcmp(lpszClassName, _T("SysTabControl32"), 15) == 0) { 316 | return TABCTRL; 317 | } 318 | else if (memcmp(lpszClassName, _T("SysAnimate32"), 12) == 0) { 319 | return ANIMATE; 320 | } 321 | else if (memcmp(lpszClassName, _T("RICHEDIT"), 8) == 0) { 322 | return RICHEDIT; 323 | } 324 | else if (memcmp(lpszClassName, _T("SysDateTimePick32"), 17) == 0) { 325 | return DATETIMEPICKER; 326 | } 327 | else if (memcmp(lpszClassName, _T("SysMonthCal32"), 13) == 0) { 328 | return MONTHCALENDER; 329 | } 330 | else if (memcmp(lpszClassName, _T("SysIPAddress32"), 14) == 0) { 331 | return IPADRESS; 332 | } 333 | else if (memcmp(lpszClassName, _T("ComboBoxEx32"), 12) == 0) { 334 | return COMBOBOXEX; 335 | } 336 | 337 | return NOCONTROL; 338 | } 339 | 340 | UINT CDynDialogItemEx::InitDialogItem(DLGITEMTEMPLATECONTROLS TypeControl, 341 | DWORD dwStyle, 342 | DWORD dwExtendedStyle, 343 | LPRECT pRect, 344 | LPCTSTR lpszCaption, 345 | UINT nID /*= 0*/, 346 | BOOL bSubclassed /*= FALSE*/, 347 | void *pData /*= NULL*/) 348 | { 349 | m_eTypeControl = TypeControl; 350 | m_strClassName = GetClassNameByType(m_eTypeControl); 351 | m_dwStyle = dwStyle; 352 | m_dwStyleEx = dwExtendedStyle; 353 | m_Rect = pRect; 354 | m_strCaption = lpszCaption; 355 | m_bSubclassed = bSubclassed; 356 | m_pData = pData; 357 | if (nID == 0) { 358 | m_ControlID = ::GetNewUniqueID(); 359 | } 360 | else { 361 | m_ControlID = nID; 362 | } 363 | return m_ControlID; 364 | } 365 | 366 | UINT CDynDialogItemEx::InitDialogItem(LPCSTR lpszClassName, 367 | DWORD dwStyle, 368 | DWORD dwExtendedStyle, 369 | LPRECT pRect, 370 | LPCTSTR lpszCaption, 371 | UINT nID /*= 0*/, 372 | BOOL bSubclassed /*= FALSE*/, 373 | void *pData /*= NULL*/) 374 | { 375 | m_strClassName = lpszClassName; 376 | m_eTypeControl = GetClassTypeByName(lpszClassName); 377 | m_dwStyle = dwStyle; 378 | m_dwStyleEx = dwExtendedStyle; 379 | m_Rect = pRect; 380 | m_strCaption = lpszCaption; 381 | m_bSubclassed = bSubclassed; 382 | m_pData = pData; 383 | if (nID == 0) { 384 | m_ControlID = ::GetNewUniqueID(); 385 | } 386 | else { 387 | m_ControlID = nID; 388 | } 389 | return m_ControlID; 390 | } 391 | 392 | BOOL CDynDialogItemEx::CreateEx(CWnd *pParent) 393 | { 394 | BOOL bRet = FALSE; 395 | if (m_eTypeControl == NOCONTROL) { //It will probably be an OCX... 396 | // 397 | // Create the control later.... 398 | // if it's created here then the rectangle is not OK and SetWindowPos doesn't work on OCX's???? 399 | // 400 | bRet = TRUE; 401 | } 402 | else if (m_pData != NULL && IsDataMemberPointerToWnd()) { 403 | bRet = ((CWnd*)m_pData)->CreateEx(m_dwStyleEx, m_strClassName, m_strCaption, m_dwStyle, m_Rect, pParent, m_ControlID); 404 | } 405 | else { 406 | bRet = CWnd::CreateEx(m_dwStyleEx, m_strClassName, m_strCaption, m_dwStyle, m_Rect, pParent, m_ControlID); 407 | } 408 | 409 | return bRet; 410 | } 411 | 412 | BOOL CDynDialogItemEx::SetWindowPos(CWnd *pParent) 413 | { 414 | BOOL bRet = FALSE; 415 | //Conversion of Dialog units to screenunits 416 | CRect rect(m_Rect); 417 | ((CDialog *)pParent)->MapDialogRect(&rect); 418 | ASSERT(rect.IsRectEmpty() == FALSE); 419 | 420 | if (m_eTypeControl == NOCONTROL) { 421 | BSTR bstrLicKey = GetRuntimeLicense(m_strClassName); 422 | bRet = CreateControl(m_strClassName, m_strCaption, m_dwStyle, rect, pParent, m_ControlID, NULL, FALSE, bstrLicKey); 423 | if (bstrLicKey != NULL) { 424 | ::SysFreeString(bstrLicKey); 425 | } 426 | } 427 | else if (m_pData != NULL && IsDataMemberPointerToWnd()) { 428 | bRet = ((CWnd*)m_pData)->SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER); 429 | } 430 | else { 431 | bRet = CWnd::SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER); 432 | } 433 | 434 | return bRet; 435 | } 436 | 437 | void CDynDialogItemEx::SetFont(CFont* pFont, BOOL bRedraw /*= TRUE*/) 438 | { 439 | if (m_pData != NULL && IsDataMemberPointerToWnd()) { 440 | ((CWnd*)m_pData)->SetFont(pFont, bRedraw); 441 | } 442 | else { 443 | CWnd::SetFont(pFont, bRedraw); 444 | } 445 | } 446 | 447 | PBYTE CDynDialogItemEx::FillBufferWithItemTemplate(BYTE *pdest) 448 | { 449 | pdest = (BYTE*)(((DWORD)pdest + 3) & ~3); // make the pointer DWORD aligned 450 | 451 | DLGITEMTEMPLATE dlgItemTemplate; 452 | dlgItemTemplate.x = (short)m_Rect.left; 453 | dlgItemTemplate.y = (short)m_Rect.top; 454 | dlgItemTemplate.cx = (short)m_Rect.Width(); 455 | dlgItemTemplate.cy = (short)m_Rect.Height(); 456 | dlgItemTemplate.style = m_dwStyle; 457 | dlgItemTemplate.dwExtendedStyle = m_dwStyleEx; 458 | dlgItemTemplate.id = (USHORT)m_ControlID; 459 | 460 | memcpy(pdest, (void *)&dlgItemTemplate, sizeof(DLGITEMTEMPLATE)); 461 | pdest += sizeof(DLGITEMTEMPLATE); 462 | *(WORD*)pdest = 0xFFFF; // indicating atom value 463 | pdest += sizeof(WORD); 464 | *(WORD*)pdest = (USHORT)m_eTypeControl; // atom value for the control 465 | pdest += sizeof(WORD); 466 | 467 | // transfer the caption even when it is an empty string 468 | WCHAR* pchCaption; 469 | int nChars, nActualChars; 470 | 471 | nChars = m_strCaption.GetLength() + 1; 472 | pchCaption = new WCHAR[nChars]; 473 | nActualChars = MultiByteToWideChar(CP_ACP, 0, m_strCaption, -1, pchCaption, nChars); 474 | ASSERT(nActualChars > 0); 475 | memcpy(pdest, pchCaption, nActualChars * sizeof(WCHAR)); 476 | pdest += nActualChars * sizeof(WCHAR); 477 | delete pchCaption; 478 | 479 | *(WORD*)pdest = 0; // How many bytes in data for control 480 | pdest += sizeof(WORD); 481 | 482 | return pdest; 483 | } 484 | 485 | BSTR CDynDialogItemEx::GetRuntimeLicense(CString &strControlName) 486 | { 487 | BSTR bstrLicKey = NULL; 488 | int i = 0; 489 | while (RuntimeLicenses[i].lpszRegisteredControlName != NULL) { 490 | if (strControlName.Compare(RuntimeLicenses[i].lpszRegisteredControlName) == 0) { 491 | bstrLicKey = ::SysAllocStringLen(RuntimeLicenses[i].wchLicenseKey, RuntimeLicenses[i].lLicenseLength/sizeof(WCHAR)); 492 | break; 493 | } 494 | i++; 495 | } 496 | return bstrLicKey; 497 | } 498 | 499 | BOOL CDynDialogItemEx::IsDataMemberPointerToWnd() 500 | { 501 | BOOL bRet = TRUE; 502 | switch(m_eTypeControl) 503 | { 504 | case BUTTON: 505 | if ((m_dwStyle & BS_AUTORADIOBUTTON) == BS_AUTORADIOBUTTON) { 506 | bRet = FALSE; 507 | } 508 | else if ((m_dwStyle & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX) { 509 | bRet = FALSE; 510 | } 511 | break; 512 | case EDITCONTROL: 513 | bRet = FALSE; 514 | break; 515 | case STATICTEXT: 516 | bRet = FALSE; 517 | break; 518 | case HSCROLL: 519 | bRet = FALSE; 520 | break; 521 | case SLIDER: 522 | bRet = FALSE; 523 | break; 524 | case DATETIMEPICKER: 525 | bRet = FALSE; 526 | break; 527 | case MONTHCALENDER: 528 | bRet = FALSE; 529 | break; 530 | default: 531 | break; 532 | } 533 | return bRet; 534 | } 535 | -------------------------------------------------------------------------------- /ext/PropertyGrid/DynDialogItemEx.h: -------------------------------------------------------------------------------- 1 | // DynDialogItemEx.h: interface for the CDynDialogItemEx class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #if !defined(AFX_DYNDIALOGITEMEX_H__CF5AF5E9_BD00_11D3_AA7C_0008C7083CA9__INCLUDED_) 6 | #define AFX_DYNDIALOGITEMEX_H__CF5AF5E9_BD00_11D3_AA7C_0008C7083CA9__INCLUDED_ 7 | 8 | #if _MSC_VER > 1000 9 | #pragma once 10 | #endif // _MSC_VER > 1000 11 | 12 | typedef enum { 13 | NOCONTROL = 0, 14 | BUTTON = 0x0080, 15 | EDITCONTROL = 0x0081, 16 | STATICTEXT = 0x0082, 17 | LISTBOX = 0x0083, 18 | HSCROLL = 0x0084, 19 | COMBOBOX = 0x0085, 20 | SPIN, 21 | PROGRES, 22 | SLIDER, 23 | HOTKEY, 24 | LISTCTRL, 25 | TREECTRL, 26 | TABCTRL, 27 | ANIMATE, 28 | RICHEDIT, 29 | DATETIMEPICKER, 30 | MONTHCALENDER, 31 | IPADRESS, 32 | COMBOBOXEX 33 | } DLGITEMTEMPLATECONTROLS; 34 | 35 | class CDynDialogItemEx : public CWnd 36 | { 37 | public: 38 | // Construction 39 | CDynDialogItemEx(); 40 | // Operations 41 | public: 42 | UINT InitDialogItem(DLGITEMTEMPLATECONTROLS TypeControl, 43 | DWORD dwStyle, 44 | DWORD dwExtendedStyle, 45 | LPRECT pRect, 46 | LPCTSTR lpszCaption, 47 | UINT nID = 0, 48 | BOOL bSubclassed = FALSE, 49 | void *pData = NULL); 50 | UINT InitDialogItem(LPCSTR lpszClassName, 51 | DWORD dwStyle, 52 | DWORD dwExtendedStyle, 53 | LPRECT pRect, 54 | LPCTSTR lpszCaption, 55 | UINT nID = 0, 56 | BOOL bSubclassed = FALSE, 57 | void *pData = NULL); 58 | BOOL CreateEx(CWnd *pParent); 59 | void SetFont(CFont* pFont, BOOL bRedraw = TRUE); 60 | 61 | // Operations 62 | public: 63 | virtual void DoDataExchange(CDataExchange* pDX); 64 | 65 | // Overrides 66 | // ClassWizard generated virtual function overrides 67 | //{{AFX_VIRTUAL(CDynDialogItemEx) 68 | //}}AFX_VIRTUAL 69 | 70 | // Implementation 71 | public: 72 | //virtual ~CDynDialogItemEx(); 73 | BOOL SetWindowPos(CWnd *pParent); 74 | PBYTE FillBufferWithItemTemplate(BYTE* pdest); 75 | 76 | UINT GetControlID() {return m_ControlID;} 77 | DLGITEMTEMPLATECONTROLS GetControlType() {return m_eTypeControl;} 78 | long GetCaptionLength() {return m_strCaption.GetLength();} 79 | BOOL IsDlgItemSubclassed() {return m_bSubclassed;} 80 | CString GetClassName() {return m_strClassName;} 81 | 82 | protected: 83 | DLGITEMTEMPLATECONTROLS GetClassTypeByName(LPCSTR lpszClassName); 84 | 85 | CString m_strClassName; 86 | DLGITEMTEMPLATECONTROLS m_eTypeControl; 87 | UINT m_ControlID; 88 | UINT m_dwStyle; 89 | UINT m_dwStyleEx; 90 | CRect m_Rect; 91 | CString m_strCaption; 92 | void *m_pData; 93 | BOOL m_bSubclassed; 94 | 95 | // Generated message map functions 96 | protected: 97 | BOOL IsDataMemberPointerToWnd(); 98 | BSTR GetRuntimeLicense(CString &strControlName); 99 | char* GetClassNameByType(DLGITEMTEMPLATECONTROLS TypeControl); 100 | 101 | //{{AFX_MSG(CDynDialogItemEx) 102 | // NOTE - the ClassWizard will add and remove member functions here. 103 | //}}AFX_MSG 104 | DECLARE_MESSAGE_MAP() 105 | }; 106 | 107 | #endif // !defined(AFX_DYNDIALOGITEMEX_H__CF5AF5E9_BD00_11D3_AA7C_0008C7083CA9__INCLUDED_) 108 | -------------------------------------------------------------------------------- /ext/PropertyGrid/ListDynDialogEx.cpp: -------------------------------------------------------------------------------- 1 | // ListDynDialogEx.cpp: implementation of the CListDynDialogEx class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #include "stdafx.h" 6 | #include "ListDynDialogEx.h" 7 | 8 | #ifdef _DEBUG 9 | #undef THIS_FILE 10 | static char THIS_FILE[]=__FILE__; 11 | #define new DEBUG_NEW 12 | #endif 13 | 14 | #define IDC_LIST1 1600 15 | ////////////////////////////////////////////////////////////////////// 16 | // Construction/Destruction 17 | ////////////////////////////////////////////////////////////////////// 18 | 19 | CListDynDialogEx::CListDynDialogEx(CWnd* pParent /*= NULL*/) 20 | : CDynDialogEx(pParent) 21 | { 22 | m_bAddSystemButtons = FALSE; 23 | } 24 | 25 | CListDynDialogEx::~CListDynDialogEx() 26 | { 27 | } 28 | 29 | BEGIN_MESSAGE_MAP(CListDynDialogEx, CDynDialogEx) 30 | //{{AFX_MSG_MAP(CListDynDialogEx) 31 | ON_LBN_DBLCLK(IDC_LIST1, OnDblclkList) 32 | //}}AFX_MSG_MAP 33 | END_MESSAGE_MAP() 34 | 35 | BOOL CListDynDialogEx::OnInitDialog() 36 | { 37 | BOOL bRet = CDynDialogEx::OnInitDialog(); 38 | 39 | m_lstBox.AddString(_T("First String")); 40 | m_lstBox.AddString(_T("Second String")); 41 | 42 | return bRet; 43 | } 44 | 45 | int CListDynDialogEx::DoModal() 46 | { 47 | CRect rect(7,7,150,150); 48 | AddDlgControl(_T("LISTBOX"), _T("ListboxText"), STYLE_LISTBOX, EXSTYLE_LISTBOX, &rect, &m_lstBox, IDC_LIST1); 49 | return CDynDialogEx::DoModal(); 50 | } 51 | 52 | void CListDynDialogEx::OnDblclkList() 53 | { 54 | CString strBuf; 55 | int nIndex = m_lstBox.GetCurSel(); 56 | m_lstBox.GetText(nIndex, strBuf); 57 | AfxMessageBox(strBuf); 58 | OnOK(); 59 | } 60 | -------------------------------------------------------------------------------- /ext/PropertyGrid/ListDynDialogEx.h: -------------------------------------------------------------------------------- 1 | // ListDynDialogEx.h: interface for the CListDynDialogEx class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #if !defined(AFX_LISTDYNDIALOGEX_H__57BA7AFA_B679_4FAC_B6BE_1AD925E45194__INCLUDED_) 6 | #define AFX_LISTDYNDIALOGEX_H__57BA7AFA_B679_4FAC_B6BE_1AD925E45194__INCLUDED_ 7 | 8 | #if _MSC_VER > 1000 9 | #pragma once 10 | #endif // _MSC_VER > 1000 11 | 12 | #include "dyndialogex.h" 13 | 14 | class CListDynDialogEx : public CDynDialogEx 15 | { 16 | public: 17 | CListDynDialogEx(CWnd* pParent = NULL); 18 | virtual ~CListDynDialogEx(); 19 | 20 | CListBox m_lstBox; 21 | 22 | // Overrides 23 | // ClassWizard generated virtual function overrides 24 | //{{AFX_VIRTUAL(CListDynDialogEx) 25 | public: 26 | virtual int DoModal(); 27 | //}}AFX_VIRTUAL 28 | 29 | // Implementation 30 | protected: 31 | 32 | // Generated message map functions 33 | //{{AFX_MSG(CListDynDialogEx) 34 | virtual BOOL OnInitDialog(); 35 | afx_msg void OnDblclkList(); 36 | //}}AFX_MSG 37 | DECLARE_MESSAGE_MAP() 38 | }; 39 | 40 | #endif // !defined(AFX_LISTDYNDIALOGEX_H__57BA7AFA_B679_4FAC_B6BE_1AD925E45194__INCLUDED_) 41 | -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGrid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PropertyGridCombo.h" 3 | #include "PropertyGridInPlaceEdit.h" 4 | 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | // CPropertyGrid 11 | 12 | #define WM_PG_ITEMCHANGED WM_USER+486 13 | #define WM_PG_SELECTIONCHANGED WM_USER+487 14 | 15 | typedef UINT HSECTION; 16 | typedef UINT HITEM; 17 | 18 | class ICustomItem; 19 | 20 | class CPropertyGrid : public CWnd 21 | { 22 | DECLARE_DYNAMIC(CPropertyGrid) 23 | 24 | public: 25 | // display mode 26 | enum EDisplayMode 27 | { 28 | DM_CATEGORIZED = 0, 29 | DM_ALPHABETICAL, 30 | DM_NOSORT 31 | }; 32 | 33 | // editing 34 | enum EEditMode 35 | { 36 | EM_CUSTOM = 0, 37 | EM_INPLACE, 38 | EM_DROPDOWN, 39 | EM_MODAL 40 | }; 41 | 42 | enum EItemType 43 | { 44 | IT_CUSTOM = 0, 45 | IT_STRING, 46 | IT_TEXT, 47 | IT_INTEGER, 48 | IT_DOUBLE, 49 | IT_COMBO, 50 | IT_BOOLEAN, 51 | IT_DATE, 52 | IT_DATETIME, 53 | IT_FILE, 54 | IT_FOLDER, 55 | IT_COLOR, 56 | IT_FONT 57 | }; 58 | 59 | public: 60 | CPropertyGrid(); 61 | virtual ~CPropertyGrid(); 62 | 63 | // customization 64 | bool GetShadeTitles(); 65 | void SetShadeTitles(bool shade_titles); 66 | bool GetDrawLines(); 67 | void SetDrawLines(bool draw_lines); 68 | bool GetDrawGutter(); 69 | void SetDrawGutter(bool draw_gutter); 70 | bool GetFocusDisabled(); 71 | void SetFocusDisabled(bool focus_disabled); 72 | bool GetBoldModified(); 73 | void SetBoldModified(bool bold_modified); 74 | bool GetBoldEditables(); 75 | void SetBoldEditables(bool bold_editables); 76 | 77 | // gutter width 78 | int GetGutterWidth(); 79 | void SetGutterWidth(int gutter_width); 80 | 81 | // custom colors 82 | void SetTextColor(COLORREF clrText); 83 | void SetTitleColor(COLORREF clrText); 84 | void SetBackColor(COLORREF clrBack); 85 | void SetShadeColor(COLORREF clrShade); 86 | void SetFocusColor(COLORREF clrFocus); 87 | void SetHiliteColor(COLORREF clrHilite); 88 | void SetEditableColor(COLORREF clrEditable); 89 | void SetDisabledColor(COLORREF clrDisabled); 90 | 91 | // localization 92 | void SetTrueFalseStrings(string strTrue, string strFalse); 93 | void SetOkCancelStrings(string strOk, string strCancel); 94 | void SetDateTimeStrings(string strDate, string strTime); 95 | void SetUndefinedString(string strUndefined); 96 | void SetEmptyString(string strEmpty); 97 | 98 | // add a section 99 | HSECTION AddSection(string title, bool collapsed = false, HSECTION after = -1); 100 | 101 | // add items 102 | HITEM AddCustomItem(HSECTION, string name, ICustomItem* pItem, bool editable = true, HITEM after = -1); 103 | HITEM AddStringItem(HSECTION section, string name, string value, bool editable = true, HITEM after = -1); 104 | HITEM AddTextItem(HSECTION section, string name, string value, bool editable = true, HITEM after = -1); 105 | HITEM AddIntegerItem(HSECTION section, string name, int value, string format = "", bool editable = true, bool undefined = false, HITEM after = -1); 106 | HITEM AddDoubleItem(HSECTION section, string name, double value, string format = "", bool editable = true, bool undefined = false, HITEM after = -1); 107 | HITEM AddComboItem(HSECTION section, string name, const vector& values, int cur, bool editable = true, bool undefined = false, HITEM after = -1); 108 | HITEM AddBoolItem(HSECTION section, string name, bool value, bool editable = true, bool undefined = false, HITEM after = -1); 109 | HITEM AddDateItem(HSECTION section, string name, COleDateTime value, string format = "", bool editable = true, bool undefined = false, HITEM after = -1); 110 | HITEM AddDateTimeItem(HSECTION section, string name, COleDateTime value, string format = "", bool editable = true, bool undefined = false, HITEM after = -1); 111 | HITEM AddFileItem(HSECTION section, string name, string value, string filter = "", bool editable = true, HITEM after = -1); 112 | HITEM AddFolderItem(HSECTION section, string name, string value, string title = "", bool editable = true, HITEM after = -1); 113 | HITEM AddColorItem(HSECTION section, string name, COLORREF value, bool editable = true, bool undefined = false, HITEM after = -1); 114 | HITEM AddFontItem(HSECTION section, string name, LOGFONT value, bool editable = true, bool undefined = false, HITEM after = -1); 115 | 116 | // contents 117 | void ResetContents(); 118 | bool RemoveSection(HSECTION hs); 119 | bool RemoveItem(HITEM item); 120 | void ValidateChanges(); 121 | 122 | // status 123 | int GetNumSections(); 124 | int GetSectionSize(HSECTION hs); 125 | 126 | // get item value 127 | bool GetItemValue(HITEM item, string& strValue) const; 128 | bool GetItemValue(HITEM item, int& nValue) const; 129 | bool GetItemValue(HITEM item, double& dValue) const; 130 | bool GetItemValue(HITEM item, bool& bValue) const; 131 | bool GetItemValue(HITEM item, COleDateTime& dtValue) const; 132 | bool GetItemValue(HITEM item, COLORREF& clrValue) const; 133 | bool GetItemValue(HITEM item, LOGFONT& lfValue) const; 134 | 135 | // set item value 136 | bool SetItemValue(HITEM item, const string strValue); 137 | bool SetItemValue(HITEM item, const int nValue); 138 | bool SetItemValue(HITEM item, const double nValue); 139 | bool SetItemValue(HITEM item, const bool bValue); 140 | bool SetItemValue(HITEM item, const COleDateTime dtValue); 141 | bool SetItemValue(HITEM item, const COLORREF clrValue); 142 | bool SetItemValue(HITEM item, const LOGFONT lfValue); 143 | 144 | // for custom items 145 | int GetTextMargin(); 146 | CFont* GetFontNormal(); 147 | CFont* GetFontBold(); 148 | 149 | // appearance stuff 150 | void SetDisplayMode(EDisplayMode display_mode); 151 | void ExpandAll(bool expand); 152 | void ExpandSection(HSECTION hs, bool expand); 153 | bool IsSectionCollapsed(HSECTION hs); 154 | 155 | std::string GetItemText(HITEM hItem); 156 | 157 | protected: 158 | class CItem 159 | { 160 | public: 161 | HITEM m_id; 162 | bool m_editable; 163 | bool m_undefined; 164 | EItemType m_type; 165 | string m_name; 166 | 167 | vector m_options; 168 | 169 | int m_nValue; 170 | double m_dValue; 171 | string m_strValue; 172 | bool m_bValue; 173 | COleDateTime m_dtValue; 174 | COLORREF m_clrValue; 175 | LOGFONT m_lfValue; 176 | ICustomItem* m_pCustom; 177 | 178 | bool m_undefined_old; 179 | int m_nValue_old; 180 | double m_dValue_old; 181 | string m_strValue_old; 182 | bool m_bValue_old; 183 | COleDateTime m_dtValue_old; 184 | COLORREF m_clrValue_old; 185 | LOGFONT m_lfValue_old; 186 | 187 | CRect m_rcName; 188 | CRect m_rcValue; 189 | 190 | bool operator==(const HITEM& item) const; 191 | bool operator==(const string& name) const; 192 | 193 | void ValidateChanges(); 194 | }; 195 | 196 | // DOWNGRADE: Commented out to prevent "undefined identifier CPropertyGrid" error 197 | //friend bool item_alpha_sort(vector::iterator it1, vector::iterator it2); 198 | 199 | class CSection 200 | { 201 | public: 202 | HSECTION m_id; 203 | string m_title; 204 | bool m_collapsed; 205 | vector m_items; 206 | 207 | CRect m_rcSign; 208 | CRect m_rcTitle; 209 | 210 | bool operator==(const HSECTION& section) const; 211 | }; 212 | 213 | vector m_sections; 214 | 215 | HSECTION m_focused_section; 216 | HITEM m_focused_item; 217 | 218 | EDisplayMode m_display_mode; 219 | 220 | bool m_shade_titles; 221 | bool m_draw_lines; 222 | bool m_draw_gutter; 223 | bool m_focus_disabled; 224 | bool m_bold_modified; 225 | bool m_bold_editables; 226 | 227 | int m_gutter_width; 228 | bool m_resizing_gutter; 229 | CPoint m_ptLast; 230 | 231 | CFont m_fntNormal; 232 | CFont m_fntBold; 233 | 234 | int m_line_height; 235 | 236 | CRect m_rect_button; 237 | CWnd* m_control; 238 | bool m_button_pushed; 239 | bool m_button_depressed; 240 | bool m_value_clicked; 241 | bool m_custom_tracking; 242 | 243 | HSECTION m_section_id; 244 | HITEM m_item_id; 245 | 246 | string m_strTrue; 247 | string m_strFalse; 248 | string m_strOk; 249 | string m_strCancel; 250 | string m_strDate; 251 | string m_strTime; 252 | string m_strUndefined; 253 | string m_strEmpty; 254 | 255 | COLORREF m_clrText; 256 | COLORREF m_clrTitle; 257 | COLORREF m_clrBack; 258 | COLORREF m_clrShade; 259 | COLORREF m_clrFocus; 260 | COLORREF m_clrHilite; 261 | COLORREF m_clrEditable; 262 | COLORREF m_clrDisabled; 263 | 264 | protected: 265 | DECLARE_MESSAGE_MAP() 266 | 267 | // init control 268 | void InitControl(); 269 | 270 | // drawing 271 | void DrawItem(CDC& dc, int w, int x, int y, vector::iterator& it); 272 | 273 | // item management 274 | CSection* FindSection(HSECTION hs) const; 275 | CItem* FindItem(HITEM hi) const; 276 | HITEM AddItem(HSECTION hs, EItemType type, string name, void* pValue, bool editable, bool undefined, HITEM after); 277 | 278 | // scrolling stuff 279 | CScrollBar m_scrollbar; 280 | bool m_scroll_enabled; 281 | int GetScrollOffset(); 282 | void RecalcLayout(); 283 | 284 | // editing 285 | EEditMode GetEditMode(CItem& item); 286 | void DeleteEditControl(); 287 | void EditFocusedItem(); 288 | 289 | // movement in list 290 | void MoveForward(HSECTION& focused_section, HITEM& focused_item); 291 | 292 | // keyboard 293 | void FocusNextItem(); 294 | void FocusPrevItem(); 295 | 296 | protected: 297 | virtual void PreSubclassWindow(); 298 | public: 299 | afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 300 | afx_msg void OnDestroy(); 301 | afx_msg BOOL OnEraseBkgnd(CDC* pDC); 302 | afx_msg void OnPaint(); 303 | afx_msg void OnLButtonDown(UINT nFlags, CPoint point); 304 | afx_msg void OnMouseMove(UINT nHitTest, CPoint point); 305 | afx_msg void OnLButtonUp(UINT nFlags, CPoint point); 306 | afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); 307 | afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); 308 | afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); 309 | afx_msg LRESULT OnComboSelChanged(WPARAM wParam, LPARAM lParam); 310 | afx_msg LRESULT OnEditChanged(WPARAM wParam, LPARAM lParam); 311 | afx_msg LRESULT OnDateChanged(WPARAM wParam, LPARAM lParam); 312 | afx_msg void OnSize(UINT nType, int cx, int cy); 313 | afx_msg UINT OnGetDlgCode(); 314 | afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); 315 | afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); 316 | }; 317 | -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGridCombo.cpp: -------------------------------------------------------------------------------- 1 | // PropertyGridCombo.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "PropertyGridCombo.h" 6 | 7 | #ifdef _DEBUG 8 | #define new DEBUG_NEW 9 | #undef THIS_FILE 10 | static char THIS_FILE[] = __FILE__; 11 | #endif 12 | 13 | static const int margin = 2; 14 | 15 | // CPropertyGridCombo 16 | 17 | IMPLEMENT_DYNCREATE(CPropertyGridCombo, CWnd) 18 | 19 | CPropertyGridCombo::CPropertyGridCombo() 20 | { 21 | m_pFont = NULL; 22 | m_nSelected = -1; 23 | m_bTracking = false; 24 | 25 | m_clrBack = GetSysColor(COLOR_WINDOW); 26 | m_clrText = GetSysColor(COLOR_WINDOWTEXT); 27 | m_clrFocus = GetSysColor(COLOR_HIGHLIGHT); 28 | m_clrHilite = GetSysColor(COLOR_HIGHLIGHTTEXT); 29 | } 30 | 31 | CPropertyGridCombo::~CPropertyGridCombo() 32 | { 33 | } 34 | 35 | // 36 | // content management 37 | // 38 | 39 | void CPropertyGridCombo::AddString(string strItem) 40 | { 41 | m_Items.push_back(strItem); 42 | } 43 | 44 | void CPropertyGridCombo::SetCurSel(int nItem) 45 | { 46 | m_nSelected = nItem; 47 | } 48 | 49 | 50 | BEGIN_MESSAGE_MAP(CPropertyGridCombo, CWnd) 51 | ON_WM_PAINT() 52 | ON_WM_SHOWWINDOW() 53 | ON_WM_LBUTTONDOWN() 54 | ON_WM_MOUSEMOVE() 55 | ON_WM_LBUTTONUP() 56 | ON_WM_DESTROY() 57 | ON_WM_KILLFOCUS() 58 | ON_WM_KEYDOWN() 59 | ON_WM_GETDLGCODE() 60 | END_MESSAGE_MAP() 61 | 62 | // 63 | // creation 64 | // 65 | 66 | BOOL CPropertyGridCombo::Create(DWORD dwStyle, CRect& rc, CWnd* pParent, int nId) 67 | { 68 | pParent->ClientToScreen(&rc); 69 | BOOL ret = CWnd::CreateEx(0, AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW), "", dwStyle|WS_POPUP, rc, pParent->GetParent(), nId); 70 | if (ret) SetOwner(pParent); 71 | return ret; 72 | } 73 | 74 | void CPropertyGridCombo::SetFont(CFont* pFont, BOOL bRedraw) 75 | { 76 | m_pFont = pFont; 77 | CWnd::SetFont(pFont, bRedraw); 78 | } 79 | 80 | void CPropertyGridCombo::SetColors(COLORREF clrBack, COLORREF clrText, COLORREF clrFocus, COLORREF clrHilite) 81 | { 82 | m_clrBack = clrBack; 83 | m_clrText = clrText; 84 | m_clrFocus = clrFocus; 85 | m_clrHilite = clrHilite; 86 | } 87 | 88 | void CPropertyGridCombo::OnShowWindow(BOOL bShow, UINT nStatus) 89 | { 90 | if (bShow) 91 | { 92 | // get line height 93 | CDC* pDC = GetDC(); 94 | int save = pDC->SaveDC(); 95 | pDC->SelectObject(m_pFont?m_pFont:GetFont()); 96 | m_line_height = pDC->GetTextExtent("Gg").cy + 2*margin; 97 | pDC->RestoreDC(save); 98 | ReleaseDC(pDC); 99 | 100 | // size control 101 | CRect rc; 102 | GetWindowRect(&rc); 103 | SetWindowPos(NULL, 0, 0, rc.Width(), int(m_Items.size())*m_line_height+2, SWP_NOOWNERZORDER|SWP_NOZORDER|SWP_NOMOVE); 104 | SetFocus(); 105 | } 106 | 107 | CWnd::OnShowWindow(bShow, nStatus); 108 | } 109 | 110 | void CPropertyGridCombo::OnDestroy() 111 | { 112 | CWnd::OnDestroy(); 113 | } 114 | 115 | void CPropertyGridCombo::OnKillFocus(CWnd* pNewWnd) 116 | { 117 | CWnd::OnKillFocus(pNewWnd); 118 | DestroyWindow(); 119 | } 120 | 121 | // 122 | // painting 123 | // 124 | 125 | void CPropertyGridCombo::OnPaint() 126 | { 127 | // check 128 | if (m_nSelected<0) m_nSelected = 0; 129 | if (m_nSelected>int(m_Items.size())-1) m_nSelected = int(m_Items.size())-1; 130 | 131 | // client rect 132 | CRect rc; 133 | GetClientRect(&rc); 134 | 135 | // brush 136 | CBrush brush; 137 | brush.CreateSolidBrush(m_clrBack); 138 | 139 | // pen 140 | CPen pen; 141 | pen.CreatePen(PS_SOLID, 1, m_clrText); 142 | 143 | // the dc 144 | CPaintDC dc(this); 145 | CBrush* pOldBrush = dc.SelectObject(&brush); 146 | CPen* pOldPen = dc.SelectObject(&pen); 147 | CFont* pOldFont = dc.SelectObject(m_pFont); 148 | 149 | // draw 150 | dc.SelectObject(&brush); 151 | dc.SelectObject(&pen); 152 | dc.Rectangle(rc); 153 | 154 | // put items 155 | int i = 0; 156 | int y = 1; 157 | dc.SelectObject(m_pFont); 158 | dc.SetBkMode(TRANSPARENT); 159 | for (vector::iterator it = m_Items.begin(); it != m_Items.end(); ++it) 160 | { 161 | CRect rcItem(0, y, rc.Width(), y+m_line_height); 162 | rcItem.DeflateRect(1,0,1,0); 163 | 164 | if (i == m_nSelected) 165 | { 166 | dc.DrawFocusRect(rcItem); 167 | dc.SetTextColor(m_clrHilite); 168 | 169 | CRect rc = rcItem; 170 | rc.DeflateRect(1,1); 171 | dc.FillSolidRect(rc, m_clrFocus); 172 | } 173 | else 174 | { 175 | dc.SetTextColor(m_clrText); 176 | } 177 | 178 | // do it 179 | rcItem.left += 2*margin; 180 | dc.DrawText(it->c_str(), rcItem, DT_SINGLELINE|DT_VCENTER|DT_LEFT|DT_NOPREFIX); 181 | y += m_line_height; 182 | i++; 183 | } 184 | 185 | // clean up 186 | dc.SelectObject(pOldFont); 187 | dc.SelectObject(pOldPen); 188 | dc.SelectObject(pOldBrush); 189 | } 190 | 191 | // 192 | // mouse interaction 193 | // 194 | 195 | void CPropertyGridCombo::OnLButtonDown(UINT nFlags, CPoint point) 196 | { 197 | m_nSelected = point.y/m_line_height; 198 | m_bTracking = true; 199 | SetCapture(); 200 | Invalidate(); 201 | 202 | CWnd::OnLButtonDown(nFlags, point); 203 | } 204 | 205 | void CPropertyGridCombo::OnMouseMove(UINT nFlags, CPoint point) 206 | { 207 | if (m_bTracking) 208 | { 209 | m_nSelected = point.y/m_line_height; 210 | Invalidate(); 211 | } 212 | CWnd::OnMouseMove(nFlags, point); 213 | } 214 | 215 | void CPropertyGridCombo::OnLButtonUp(UINT nFlags, CPoint point) 216 | { 217 | if (m_bTracking) 218 | { 219 | ReleaseCapture(); 220 | m_bTracking = false; 221 | Invalidate(); 222 | } 223 | 224 | GetOwner()->SendMessage(WM_PG_COMBOSELCHANGED, m_nSelected, 0); 225 | } 226 | 227 | // 228 | // keyboard interaction 229 | // 230 | 231 | UINT CPropertyGridCombo::OnGetDlgCode() 232 | { 233 | return DLGC_WANTALLKEYS; 234 | } 235 | 236 | void CPropertyGridCombo::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 237 | { 238 | if (nChar == VK_LEFT || nChar == VK_UP) 239 | { 240 | m_nSelected = max(0, m_nSelected-1); 241 | Invalidate(); 242 | } 243 | else if (nChar == VK_RIGHT || nChar == VK_DOWN) 244 | { 245 | m_nSelected = min(int(m_Items.size())-1, m_nSelected+1); 246 | Invalidate(); 247 | } 248 | else if (nChar == VK_ESCAPE) 249 | { 250 | DestroyWindow(); 251 | return; 252 | } 253 | else if (nChar == VK_RETURN || nChar == VK_EXECUTE) 254 | { 255 | GetOwner()->SendMessage(WM_PG_COMBOSELCHANGED, m_nSelected, 0); 256 | return; 257 | } 258 | 259 | CWnd::OnKeyDown(nChar, nRepCnt, nFlags); 260 | } 261 | -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGridCombo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // CPropertyGridCombo frame 7 | 8 | #define WM_PG_COMBOSELCHANGED WM_USER+487 9 | 10 | class CPropertyGridCombo : public CWnd 11 | { 12 | DECLARE_DYNCREATE(CPropertyGridCombo) 13 | 14 | public: 15 | CPropertyGridCombo(); 16 | virtual ~CPropertyGridCombo(); 17 | 18 | BOOL Create(DWORD dwStyle, CRect& rc, CWnd* pParent, int nId); 19 | void SetFont(CFont* pFont, BOOL bRedraw = TRUE); 20 | void SetColors(COLORREF clrBack, COLORREF clrText, COLORREF clrFocus, COLORREF clrHilite); 21 | 22 | void AddString(string strItem); 23 | void SetCurSel(int nItem); 24 | 25 | protected: 26 | vector m_Items; 27 | int m_nSelected; 28 | 29 | CFont* m_pFont; 30 | int m_line_height; 31 | 32 | bool m_bTracking; 33 | 34 | COLORREF m_clrBack; 35 | COLORREF m_clrText; 36 | COLORREF m_clrFocus; 37 | COLORREF m_clrHilite; 38 | 39 | protected: 40 | DECLARE_MESSAGE_MAP() 41 | 42 | public: 43 | afx_msg void OnPaint(); 44 | afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); 45 | afx_msg void OnLButtonDown(UINT nFlags, CPoint point); 46 | afx_msg void OnMouseMove(UINT nFlags, CPoint point); 47 | afx_msg void OnLButtonUp(UINT nFlags, CPoint point); 48 | afx_msg void OnDestroy(); 49 | afx_msg void OnKillFocus(CWnd* pNewWnd); 50 | afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); 51 | afx_msg UINT OnGetDlgCode(); 52 | }; 53 | 54 | 55 | -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGridDirectoryPicker.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (C) 2001, nabocorp 4 | // All Rights Reserved 5 | // 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | #include "stdafx.h" 9 | #include "shlobj.h" 10 | #include "PropertyGridDirectoryPicker.h" 11 | 12 | #define BIF_NEWDIALOGSTYLE 0x0040 13 | 14 | std::string CPropertyGridDirectoryPicker::m_strTitle = "Choose a directory"; 15 | 16 | CPropertyGridDirectoryPicker::CPropertyGridDirectoryPicker() 17 | { 18 | } 19 | 20 | CPropertyGridDirectoryPicker::~CPropertyGridDirectoryPicker() 21 | { 22 | } 23 | 24 | int CALLBACK CPropertyGridDirectoryPicker::BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lp, LPARAM pData) 25 | { 26 | switch(uMsg) 27 | { 28 | // If the dialog is being initialised 29 | case BFFM_INITIALIZED: 30 | { 31 | // Send a SetSelection message on the passed directory 32 | SendMessage(hwnd,BFFM_SETSELECTION,TRUE,pData); 33 | break; 34 | } 35 | } 36 | return 0; 37 | } 38 | 39 | bool CPropertyGridDirectoryPicker::PickDirectory(std::string &directory, HWND hwnd) 40 | { 41 | char pszBuffer[MAX_PATH]; 42 | pszBuffer[0] = '\0'; 43 | 44 | // Gets the Shell's default allocator 45 | LPMALLOC pMalloc; 46 | if (::SHGetMalloc(&pMalloc) == NOERROR) 47 | { 48 | BROWSEINFO bi; 49 | LPITEMIDLIST pidl; 50 | 51 | // Get help on BROWSEINFO struct 52 | bi.hwndOwner = hwnd; 53 | bi.pidlRoot = NULL; 54 | bi.pszDisplayName = pszBuffer; 55 | bi.lpszTitle = m_strTitle.c_str(); 56 | bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE ; 57 | 58 | // The callback function initialises the dialog with the passed value 59 | bi.lpfn = BrowseCallbackProc; 60 | bi.lParam = LPARAM(directory.c_str()); 61 | 62 | // This next call issues the dialog box. 63 | if ((pidl = ::SHBrowseForFolder(&bi)) != NULL) 64 | { 65 | // Get the full path into pszBuffer 66 | ::SHGetPathFromIDList(pidl, pszBuffer); 67 | // Free the PIDL allocated by SHBrowseForFolder. 68 | pMalloc->Free(pidl); 69 | } 70 | // Release the shell's allocator. 71 | pMalloc->Release(); 72 | } 73 | 74 | // get the result 75 | if (strlen(pszBuffer) != 0) 76 | { 77 | directory = pszBuffer; 78 | return TRUE; 79 | } 80 | return FALSE; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGridDirectoryPicker.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright (C) 2001, nabocorp 4 | // All Rights Reserved 5 | // 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | #if !defined(AFX_DIRECTORYPICKER_H__CBBD1C74_A552_11D2_8ECA_00104BDC35E6__INCLUDED_) 9 | #define AFX_DIRECTORYPICKER_H__CBBD1C74_A552_11D2_8ECA_00104BDC35E6__INCLUDED_ 10 | 11 | #if _MSC_VER > 1000 12 | #pragma once 13 | #endif // _MSC_VER > 1000 14 | 15 | class CPropertyGridDirectoryPicker 16 | { 17 | public: 18 | CPropertyGridDirectoryPicker(); 19 | virtual ~CPropertyGridDirectoryPicker(); 20 | 21 | static bool PickDirectory(std::string&, HWND hwnd); 22 | static std::string m_strTitle; 23 | 24 | protected: 25 | static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lp, LPARAM pData); 26 | }; 27 | 28 | #endif // !defined(AFX_DIRECTORYPICKER_H__CBBD1C74_A552_11D2_8ECA_00104BDC35E6__INCLUDED_) 29 | -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGridInPlaceEdit.cpp: -------------------------------------------------------------------------------- 1 | // InPlaceEdit.cpp : implementation file 2 | // 3 | // Adapted by Chris Maunder 4 | // Copyright (c) 1998-2002. All Rights Reserved. 5 | // 6 | // The code contained in this file is based on the original 7 | // CPropertyGridInPlaceEdit from http://www.codeguru.com/listview/edit_subitems.shtml 8 | // 9 | // This code may be used in compiled form in any way you desire. This 10 | // file may be redistributed unmodified by any means PROVIDING it is 11 | // not sold for profit without the authors written consent, and 12 | // providing that this notice and the authors name and all copyright 13 | // notices remains intact. 14 | // 15 | // An email letting me know how you are using it would be nice as well. 16 | // 17 | // This file is provided "as is" with no expressed or implied warranty. 18 | // The author accepts no liability for any damage/loss of business that 19 | // this product may cause. 20 | // 21 | // For use with CGridCtrl v2.10+ 22 | // 23 | // History: 24 | // 10 May 1998 Uses GVN_ notifications instead of LVN_, 25 | // Sends notification messages to the parent, 26 | // instead of the parent's parent. 27 | // 15 May 1998 There was a problem when editing with the in-place editor, 28 | // there arises a general protection fault in user.exe, with a 29 | // few qualifications: 30 | // (1) This only happens with owner-drawn buttons; 31 | // (2) This only happens in Win95 32 | // (3) This only happens if the handler for the button does not 33 | // create a new window (even an AfxMessageBox will avoid the 34 | // crash) 35 | // (4) This will not happen if Spy++ is running. 36 | // PreTranslateMessage was added to route messages correctly. 37 | // (Matt Weagle found and fixed this problem) 38 | // 26 Jul 1998 Removed the ES_MULTILINE style - that fixed a few probs! 39 | // 6 Aug 1998 Added nID to the constructor param list 40 | // 6 Sep 1998 Space no longer clears selection when starting edit (Franco Bez) 41 | // 10 Apr 1999 Enter, Tab and Esc key prob fixed (Koay Kah Hoe) 42 | // Workaround for bizzare "shrinking window" problem in CE 43 | // 44 | ///////////////////////////////////////////////////////////////////////////// 45 | 46 | #include "stdafx.h" 47 | #include "TCHAR.h" 48 | #include "PropertyGridInPlaceEdit.h" 49 | 50 | #ifdef _DEBUG 51 | #define new DEBUG_NEW 52 | #undef THIS_FILE 53 | static char THIS_FILE[] = __FILE__; 54 | #endif 55 | 56 | ///////////////////////////////////////////////////////////////////////////// 57 | // CPropertyGridInPlaceEdit 58 | 59 | CPropertyGridInPlaceEdit::CPropertyGridInPlaceEdit(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID, string sInitText) 60 | { 61 | m_sInitText = sInitText.c_str(); 62 | m_bExitOnArrows = FALSE; 63 | m_Rect = rect; // For bizarre CE bug. 64 | 65 | DWORD dwEditStyle = /*WS_BORDER|*/WS_CHILD|/*WS_VISIBLE|*/ES_AUTOHSCROLL|dwStyle; 66 | if (!Create(dwEditStyle, rect, pParent, nID)) 67 | return; 68 | 69 | m_clrBack = GetSysColor(COLOR_WINDOW); 70 | m_clrText = GetSysColor(COLOR_WINDOWTEXT); 71 | m_Brush.CreateSolidBrush(m_clrBack); 72 | 73 | SetFont(pParent->GetFont()); 74 | 75 | SetWindowText(m_sInitText); 76 | SetFocus(); 77 | 78 | SetSel(0, -1); 79 | SetSel(-1, 0); 80 | } 81 | 82 | CPropertyGridInPlaceEdit::~CPropertyGridInPlaceEdit() 83 | { 84 | } 85 | 86 | void CPropertyGridInPlaceEdit::SetColors(COLORREF clrBack, COLORREF clrText) 87 | { 88 | m_clrBack = clrBack; 89 | m_clrText = clrText; 90 | m_Brush.DeleteObject(); 91 | m_Brush.CreateSolidBrush(m_clrBack); 92 | } 93 | 94 | BEGIN_MESSAGE_MAP(CPropertyGridInPlaceEdit, CEdit) 95 | //{{AFX_MSG_MAP(CPropertyGridInPlaceEdit) 96 | ON_WM_KILLFOCUS() 97 | ON_WM_CHAR() 98 | ON_WM_KEYDOWN() 99 | ON_WM_GETDLGCODE() 100 | ON_WM_CREATE() 101 | ON_WM_CTLCOLOR_REFLECT( ) 102 | //}}AFX_MSG_MAP 103 | END_MESSAGE_MAP() 104 | 105 | //////////////////////////////////////////////////////////////////////////// 106 | // CPropertyGridInPlaceEdit message handlers 107 | 108 | // If an arrow key (or associated) is pressed, then exit if 109 | // a) The Ctrl key was down, or 110 | // b) m_bExitOnArrows == TRUE 111 | void CPropertyGridInPlaceEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 112 | { 113 | if ((nChar == VK_PRIOR || nChar == VK_NEXT || 114 | nChar == VK_DOWN || nChar == VK_UP || 115 | nChar == VK_RIGHT || nChar == VK_LEFT) && 116 | (m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0)) 117 | { 118 | GetParent()->SetFocus(); 119 | return; 120 | } 121 | 122 | CEdit::OnKeyDown(nChar, nRepCnt, nFlags); 123 | } 124 | 125 | // As soon as this edit loses focus, kill it. 126 | void CPropertyGridInPlaceEdit::OnKillFocus(CWnd* pNewWnd) 127 | { 128 | CEdit::OnKillFocus(pNewWnd); 129 | EndEdit(); 130 | } 131 | 132 | void CPropertyGridInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 133 | { 134 | if (nChar == VK_TAB || nChar == VK_RETURN) 135 | { 136 | GetParent()->SetFocus(); // This will destroy this window 137 | return; 138 | } 139 | if (nChar == VK_ESCAPE) 140 | { 141 | CancelEdit(); 142 | return; 143 | } 144 | 145 | CEdit::OnChar(nChar, nRepCnt, nFlags); 146 | 147 | //// Resize edit control if needed 148 | // 149 | //// Get text extent 150 | //CString str; 151 | //GetWindowText( str ); 152 | 153 | //// add some extra buffer 154 | //str += _T(" "); 155 | // 156 | //CWindowDC dc(this); 157 | //CFont *pFontDC = dc.SelectObject(GetFont()); 158 | //CSize size = dc.GetTextExtent( str ); 159 | //dc.SelectObject( pFontDC ); 160 | // 161 | //// Get client rect 162 | //CRect ParentRect; 163 | //GetParent()->GetClientRect( &ParentRect ); 164 | // 165 | //// Check whether control needs to be resized 166 | //// and whether there is space to grow 167 | //if (size.cx > m_Rect.Width()) 168 | //{ 169 | // if( size.cx + m_Rect.left < ParentRect.right ) 170 | // m_Rect.right = m_Rect.left + size.cx; 171 | // else 172 | // m_Rect.right = ParentRect.right; 173 | // MoveWindow( &m_Rect ); 174 | //} 175 | } 176 | 177 | UINT CPropertyGridInPlaceEdit::OnGetDlgCode() 178 | { 179 | return DLGC_WANTALLKEYS; 180 | } 181 | 182 | //////////////////////////////////////////////////////////////////////////// 183 | // CPropertyGridInPlaceEdit overrides 184 | 185 | // Stoopid win95 accelerator key problem workaround - Matt Weagle. 186 | BOOL CPropertyGridInPlaceEdit::PreTranslateMessage(MSG* pMsg) 187 | { 188 | // Catch the Alt key so we don't choke if focus is going to an owner drawn button 189 | if (pMsg->message == WM_SYSCHAR) 190 | return TRUE; 191 | return CEdit::PreTranslateMessage(pMsg); 192 | } 193 | 194 | //////////////////////////////////////////////////////////////////////////// 195 | // CPropertyGridInPlaceEdit implementation 196 | 197 | void CPropertyGridInPlaceEdit::CancelEdit() 198 | { 199 | // restore previous text 200 | if (IsWindow(GetSafeHwnd())) 201 | { 202 | SetWindowText(m_sInitText); 203 | SendMessage(WM_CLOSE, 0, 0); 204 | } 205 | } 206 | 207 | void CPropertyGridInPlaceEdit::EndEdit() 208 | { 209 | CString str; 210 | 211 | // EFW - BUG FIX - Clicking on a grid scroll bar in a derived class 212 | // that validates input can cause this to get called multiple times 213 | // causing assertions because the edit control goes away the first time. 214 | static BOOL bAlreadyEnding = FALSE; 215 | 216 | if(bAlreadyEnding) 217 | return; 218 | 219 | bAlreadyEnding = TRUE; 220 | GetWindowText(str); 221 | 222 | CWnd* pOwner = GetOwner(); 223 | if (pOwner) 224 | pOwner->SendMessage(WM_PG_ENDLABELEDIT, (WPARAM) LPCTSTR(str), NULL ); 225 | 226 | // Close this window (PostNcDestroy will delete this) 227 | if (IsWindow(GetSafeHwnd())) 228 | SendMessage(WM_CLOSE, 0, 0); 229 | bAlreadyEnding = FALSE; 230 | } 231 | 232 | HBRUSH CPropertyGridInPlaceEdit::CtlColor ( CDC* pDC, UINT nCtlColor ) 233 | { 234 | pDC->SetTextColor(m_clrText); 235 | pDC->SetBkColor(m_clrBack); 236 | return m_Brush; 237 | } -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGridInPlaceEdit.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // InPlaceEdit.h : header file 3 | // 4 | // MFC Grid Control - inplace editing class 5 | // 6 | // Written by Chris Maunder 7 | // Copyright (c) 1998-2002. All Rights Reserved. 8 | // 9 | // This code may be used in compiled form in any way you desire. This 10 | // file may be redistributed unmodified by any means PROVIDING it is 11 | // not sold for profit without the authors written consent, and 12 | // providing that this notice and the authors name and all copyright 13 | // notices remains intact. 14 | // 15 | // An email letting me know how you are using it would be nice as well. 16 | // 17 | // This file is provided "as is" with no expressed or implied warranty. 18 | // The author accepts no liability for any damage/loss of business that 19 | // this product may cause. 20 | // 21 | // For use with CGridCtrl v2.10+ 22 | // 23 | ////////////////////////////////////////////////////////////////////// 24 | 25 | #if !defined(AFX_GRIDINPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_) 26 | #define AFX_GRIDINPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_ 27 | 28 | #if _MSC_VER >= 1000 29 | #pragma once 30 | #endif // _MSC_VER >= 1000 31 | 32 | #include 33 | using namespace std; 34 | 35 | #define WM_PG_ENDLABELEDIT WM_USER+488 36 | 37 | class CPropertyGridInPlaceEdit : public CEdit 38 | { 39 | // Construction 40 | public: 41 | CPropertyGridInPlaceEdit(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID, string sInitText); 42 | void SetColors(COLORREF clrBack, COLORREF clrText); 43 | 44 | // Attributes 45 | public: 46 | 47 | // Operations 48 | public: 49 | void CancelEdit(); 50 | void EndEdit(); 51 | 52 | // Overrides 53 | // ClassWizard generated virtual function overrides 54 | //{{AFX_VIRTUAL(CPropertyGridInPlaceEdit) 55 | public: 56 | virtual BOOL PreTranslateMessage(MSG* pMsg); 57 | //}}AFX_VIRTUAL 58 | 59 | // Implementation 60 | public: 61 | virtual ~CPropertyGridInPlaceEdit(); 62 | 63 | // Generated message map functions 64 | protected: 65 | //{{AFX_MSG(CPropertyGridInPlaceEdit) 66 | afx_msg void OnKillFocus(CWnd* pNewWnd); 67 | afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); 68 | afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); 69 | afx_msg UINT OnGetDlgCode(); 70 | afx_msg HBRUSH CtlColor ( CDC* pDC, UINT nCtlColor ); 71 | //}}AFX_MSG 72 | DECLARE_MESSAGE_MAP() 73 | 74 | private: 75 | CString m_sInitText; 76 | BOOL m_bExitOnArrows; 77 | CRect m_Rect; 78 | 79 | COLORREF m_clrBack; 80 | COLORREF m_clrText; 81 | CBrush m_Brush; 82 | }; 83 | 84 | ///////////////////////////////////////////////////////////////////////////// 85 | 86 | //{{AFX_INSERT_LOCATION}} 87 | // Microsoft Developer Studio will insert additional declarations immediately before the previous line. 88 | 89 | #endif // !defined(AFX_GRIDINPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_) 90 | -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGridMonthCalCtrl.cpp: -------------------------------------------------------------------------------- 1 | // PropertyGridMonthCalCtrl.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "PropertyGridMonthCalCtrl.h" 6 | 7 | 8 | // CPropertyGridMonthCalCtrl 9 | 10 | // DOWNGRADE: Commented out to prevent link error where CRuntimeStatic for CMonthCalCtrl is unresolved 11 | //IMPLEMENT_DYNAMIC(CPropertyGridMonthCalCtrl, CMonthCalCtrl) 12 | CPropertyGridMonthCalCtrl::CPropertyGridMonthCalCtrl() 13 | { 14 | } 15 | 16 | CPropertyGridMonthCalCtrl::~CPropertyGridMonthCalCtrl() 17 | { 18 | } 19 | 20 | 21 | BEGIN_MESSAGE_MAP(CPropertyGridMonthCalCtrl, CMonthCalCtrl) 22 | ON_WM_KILLFOCUS() 23 | ON_NOTIFY_REFLECT(MCN_SELECT, OnMcnSelect) 24 | ON_WM_GETDLGCODE() 25 | ON_WM_KEYDOWN() 26 | END_MESSAGE_MAP() 27 | 28 | 29 | 30 | // CPropertyGridMonthCalCtrl message handlers 31 | 32 | 33 | void CPropertyGridMonthCalCtrl::OnKillFocus(CWnd* pNewWnd) 34 | { 35 | CMonthCalCtrl::OnKillFocus(pNewWnd); 36 | CWnd* pParent = pNewWnd ? pNewWnd->GetParent() : NULL; 37 | if (pParent != this) 38 | DestroyWindow(); 39 | } 40 | 41 | void CPropertyGridMonthCalCtrl::OnMcnSelect(NMHDR *pNMHDR, LRESULT *pResult) 42 | { 43 | LPNMSELCHANGE pSelChange = reinterpret_cast(pNMHDR); 44 | GetOwner()->SendMessage(WM_PG_DATESELCHANGED); 45 | *pResult = 0; 46 | } 47 | 48 | UINT CPropertyGridMonthCalCtrl::OnGetDlgCode() 49 | { 50 | return DLGC_WANTALLKEYS; 51 | } 52 | 53 | void CPropertyGridMonthCalCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 54 | { 55 | if (nChar == VK_ESCAPE) 56 | { 57 | DestroyWindow(); 58 | return; 59 | } 60 | else if (nChar == VK_RETURN || nChar == VK_EXECUTE) 61 | { 62 | GetOwner()->SendMessage(WM_PG_DATESELCHANGED); 63 | return; 64 | } 65 | 66 | CMonthCalCtrl::OnKeyDown(nChar, nRepCnt, nFlags); 67 | } 68 | -------------------------------------------------------------------------------- /ext/PropertyGrid/PropertyGridMonthCalCtrl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WM_PG_DATESELCHANGED WM_USER+489 4 | 5 | // CPropertyGridMonthCalCtrl 6 | 7 | class CPropertyGridMonthCalCtrl : public CMonthCalCtrl 8 | { 9 | // DOWNGRADE: Commented out to prevent link error where CRuntimeStatic for CMonthCalCtrl is unresolved 10 | //DECLARE_DYNAMIC(CPropertyGridMonthCalCtrl) 11 | 12 | public: 13 | CPropertyGridMonthCalCtrl(); 14 | virtual ~CPropertyGridMonthCalCtrl(); 15 | 16 | protected: 17 | DECLARE_MESSAGE_MAP() 18 | public: 19 | afx_msg void OnKillFocus(CWnd* pNewWnd); 20 | afx_msg void OnMcnSelect(NMHDR *pNMHDR, LRESULT *pResult); 21 | afx_msg UINT OnGetDlgCode(); 22 | afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); 23 | }; 24 | 25 | 26 | -------------------------------------------------------------------------------- /ext/PropertyGrid/README.md: -------------------------------------------------------------------------------- 1 | # Fully customizable PropertyGrid for MFC 4.2 2 | 3 | Original project by Nicolas Bonamy at CodeProject: https://www.codeproject.com/Articles/18933/A-fully-customizable-PropertyGrid 4 | 5 | This is a port of that project to CMake with minor changes so it can compile with Visual C++ 6.0. 6 | -------------------------------------------------------------------------------- /ext/PropertyGrid/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // PropGrid.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | 8 | -------------------------------------------------------------------------------- /ext/PropertyGrid/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #if !defined(AFX_STDAFX_H__8E104244_6D3A_49FB_B014_338D08085215__INCLUDED_) 7 | #define AFX_STDAFX_H__8E104244_6D3A_49FB_B014_338D08085215__INCLUDED_ 8 | 9 | #if _MSC_VER > 1000 10 | #pragma once 11 | #endif // _MSC_VER > 1000 12 | 13 | #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 14 | 15 | #include // MFC core and standard components 16 | #include // MFC extensions 17 | #include // MFC Automation classes 18 | #include // MFC support for Internet Explorer 4 Common Controls 19 | #ifndef _AFX_NO_AFXCMN_SUPPORT 20 | #include // MFC support for Windows Common Controls 21 | #endif // _AFX_NO_AFXCMN_SUPPORT 22 | 23 | 24 | #include 25 | #include 26 | //{{AFX_INSERT_LOCATION}} 27 | // Microsoft Visual C++ will insert additional declarations immediately before the previous line. 28 | 29 | #endif // !defined(AFX_STDAFX_H__8E104244_6D3A_49FB_B014_338D08085215__INCLUDED_) 30 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(PropGrid WIN32 2 | CustomTreeCtrl.cpp 3 | CustomTreeCtrl.h 4 | GradientItem.cpp 5 | GradientItem.h 6 | PropGrid.cpp 7 | PropGrid.h 8 | PropGrid.rc 9 | PropGridDlg.cpp 10 | PropGridDlg.h 11 | RectEditDlg.cpp 12 | RectEditDlg.h 13 | RectItem.cpp 14 | RectItem.h 15 | resource.h 16 | SerialItem.cpp 17 | SerialItem.h 18 | TreeItem.cpp 19 | TreeItem.h 20 | ) 21 | 22 | target_include_directories(PropGrid PRIVATE "..") 23 | target_link_libraries(PropGrid PRIVATE PropertyGrid) 24 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/CustomTreeCtrl.cpp: -------------------------------------------------------------------------------- 1 | // CustomTreeCtrl.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "PropGrid.h" 6 | #include "CustomTreeCtrl.h" 7 | #include "TreeItem.h" 8 | #include ".\customtreectrl.h" 9 | 10 | 11 | // CCustomTreeCtrl 12 | 13 | IMPLEMENT_DYNAMIC(CCustomTreeCtrl, CTreeCtrl) 14 | CCustomTreeCtrl::CCustomTreeCtrl() 15 | { 16 | } 17 | 18 | CCustomTreeCtrl::~CCustomTreeCtrl() 19 | { 20 | } 21 | 22 | 23 | BEGIN_MESSAGE_MAP(CCustomTreeCtrl, CTreeCtrl) 24 | ON_WM_GETDLGCODE() 25 | ON_WM_KILLFOCUS() 26 | ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnTvnSelchanged) 27 | ON_WM_KEYDOWN() 28 | END_MESSAGE_MAP() 29 | 30 | 31 | 32 | // CCustomTreeCtrl message handlers 33 | 34 | 35 | UINT CCustomTreeCtrl::OnGetDlgCode() 36 | { 37 | return DLGC_WANTALLKEYS; 38 | } 39 | 40 | void CCustomTreeCtrl::OnKillFocus(CWnd* pNewWnd) 41 | { 42 | CTreeCtrl::OnKillFocus(pNewWnd); 43 | DestroyWindow(); 44 | } 45 | 46 | void CCustomTreeCtrl::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult) 47 | { 48 | LPNMTREEVIEW pNMTreeView = reinterpret_cast(pNMHDR); 49 | if (pNMTreeView->action == TVC_BYMOUSE) 50 | Validate(); 51 | *pResult = 0; 52 | } 53 | 54 | void CCustomTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 55 | { 56 | if (nChar == VK_ESCAPE) 57 | { 58 | DestroyWindow(); 59 | return; 60 | } 61 | else if (nChar == VK_RETURN || nChar == VK_EXECUTE) 62 | { 63 | Validate(); 64 | return; 65 | } 66 | 67 | CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags); 68 | } 69 | 70 | void CCustomTreeCtrl::Validate() 71 | { 72 | if (GetSafeHwnd()) 73 | { 74 | HTREEITEM hItem = GetSelectedItem(); 75 | if (hItem && !ItemHasChildren(hItem)) 76 | { 77 | CString strText = GetItemText(hItem); 78 | m_item->SetValue(LPCTSTR(strText)); 79 | DestroyWindow(); 80 | } 81 | } 82 | } 83 | 84 | void CCustomTreeCtrl::PostNcDestroy() 85 | { 86 | CTreeCtrl::PostNcDestroy(); 87 | delete this; 88 | } 89 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/CustomTreeCtrl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "..\PropertyGrid.h" 3 | 4 | class CTreeItem; 5 | 6 | // CCustomTreeCtrl 7 | 8 | class CCustomTreeCtrl : public CTreeCtrl 9 | { 10 | DECLARE_DYNAMIC(CCustomTreeCtrl) 11 | 12 | public: 13 | CCustomTreeCtrl(); 14 | virtual ~CCustomTreeCtrl(); 15 | 16 | CTreeItem* m_item; 17 | 18 | protected: 19 | DECLARE_MESSAGE_MAP() 20 | 21 | void Validate(); 22 | 23 | public: 24 | afx_msg UINT OnGetDlgCode(); 25 | afx_msg void OnKillFocus(CWnd* pNewWnd); 26 | afx_msg void OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult); 27 | afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); 28 | protected: 29 | virtual void PostNcDestroy(); 30 | }; 31 | 32 | 33 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/GradientItem.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "GradientItem.h" 3 | 4 | CGradientItem::CGradientItem(void) 5 | { 6 | m_clrLeft = RGB(0,0,0); 7 | m_clrRight = RGB(0,255,0); 8 | m_nButtonPushed = 0; 9 | } 10 | 11 | CPropertyGrid::EEditMode CGradientItem::GetEditMode() 12 | { 13 | return CPropertyGrid::EM_CUSTOM; 14 | } 15 | 16 | void CGradientItem::DrawItem(CDC& dc, CRect rc, bool focused) 17 | { 18 | CRect rect = rc; 19 | rect.DeflateRect(focused?rc.Height()+2:2, 2); 20 | 21 | CBrush brush; 22 | brush.CreateSolidBrush(GetSysColor(COLOR_WINDOWTEXT)); 23 | dc.FrameRect(rect, &brush); 24 | 25 | rect.DeflateRect(1,1); 26 | 27 | TRIVERTEX vert[2] ; 28 | GRADIENT_RECT gRect; 29 | vert [0] .x = rect.left; 30 | vert [0] .y = rect.top; 31 | vert [0] .Red = GetRValue(m_clrLeft)*256; 32 | vert [0] .Green = GetGValue(m_clrLeft)*256; 33 | vert [0] .Blue = GetBValue(m_clrLeft)*256; 34 | vert [0] .Alpha = 0x0000; 35 | 36 | vert [1] .x = rect.right; 37 | vert [1] .y = rect.bottom; 38 | vert [1] .Red = GetRValue(m_clrRight)*256; 39 | vert [1] .Green = GetGValue(m_clrRight)*256; 40 | vert [1] .Blue = GetBValue(m_clrRight)*256; 41 | vert [1] .Alpha = 0x0000; 42 | 43 | gRect.UpperLeft = 0; 44 | gRect.LowerRight = 1; 45 | 46 | // DOWNGRADE: Commented out because MFC 4.2 doesn't have GradientFill 47 | //dc.GradientFill(vert,2,&gRect,1,GRADIENT_FILL_RECT_H); 48 | 49 | if (focused) 50 | { 51 | // for propert clean up 52 | CFont* pOldFont = dc.SelectObject(m_pGrid->GetFontBold()); 53 | 54 | // the left button 55 | CRect rc1 = rc; 56 | rc1.right = rc1.left + rc1.Height(); 57 | dc.DrawFrameControl(rc1, DFC_BUTTON, DFCS_BUTTONPUSH|(m_nButtonPushed==1?DFCS_PUSHED:0)); 58 | dc.SelectObject(m_pGrid->GetFontBold()); 59 | dc.DrawText("...", rc1, DT_CENTER|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX); 60 | 61 | // the right button 62 | CRect rc2 = rc; 63 | rc2.left = rc2.right - rc2.Height(); 64 | dc.DrawFrameControl(rc2, DFC_BUTTON, DFCS_BUTTONPUSH|(m_nButtonPushed==2?DFCS_PUSHED:0)); 65 | dc.SelectObject(m_pGrid->GetFontBold()); 66 | dc.DrawText("...", rc2, DT_CENTER|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX); 67 | 68 | // clean up 69 | dc.SelectObject(pOldFont); 70 | } 71 | } 72 | 73 | bool CGradientItem::OnLButtonDown(CRect rc, CPoint pt) 74 | { 75 | m_nButtonPushed = 0; 76 | if (rc.PtInRect(pt)) 77 | { 78 | if (pt.x<=rc.left+rc.Height()) 79 | { 80 | m_nButtonPushed = 1; 81 | return true; 82 | } 83 | if (pt.x>=rc.right-rc.Height()) 84 | { 85 | m_nButtonPushed = 2; 86 | return true; 87 | } 88 | } 89 | return false; 90 | } 91 | 92 | void CGradientItem::OnMouseMove(CRect rc, CPoint pt) 93 | { 94 | OnLButtonDown(rc, pt); 95 | } 96 | 97 | void CGradientItem::OnLButtonUp(CRect rc, CPoint pt) 98 | { 99 | COLORREF& clr = (m_nButtonPushed==1) ? m_clrLeft : m_clrRight; 100 | m_nButtonPushed = 0; 101 | CColorDialog dlg(clr, 0, m_pGrid); 102 | if (dlg.DoModal() == IDOK) 103 | { 104 | clr = dlg.GetColor(); 105 | m_pGrid->Invalidate(); 106 | } 107 | } 108 | 109 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/GradientItem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "..\CustomItem.h" 3 | 4 | class CGradientItem : 5 | public ICustomItem 6 | { 7 | public: 8 | CGradientItem(void); 9 | 10 | public: 11 | virtual CPropertyGrid::EEditMode GetEditMode(); 12 | virtual void DrawItem(CDC& dc, CRect rc, bool focused); 13 | virtual bool OnLButtonDown(CRect rc, CPoint pt); 14 | virtual void OnMouseMove(CRect rc, CPoint pt); 15 | virtual void OnLButtonUp(CRect rc, CPoint pt); 16 | 17 | protected: 18 | COLORREF m_clrLeft; 19 | COLORREF m_clrRight; 20 | int m_nButtonPushed; //0: none, 1: left, 2:right 21 | }; 22 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/PropGrid.cpp: -------------------------------------------------------------------------------- 1 | // PropGrid.cpp : Defines the class behaviors for the application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "PropGrid.h" 6 | #include "PropGridDlg.h" 7 | 8 | #ifdef _DEBUG 9 | #define new DEBUG_NEW 10 | #endif 11 | 12 | 13 | // CPropGridApp 14 | 15 | BEGIN_MESSAGE_MAP(CPropGridApp, CWinApp) 16 | ON_COMMAND(ID_HELP, CWinApp::OnHelp) 17 | END_MESSAGE_MAP() 18 | 19 | 20 | // CPropGridApp construction 21 | 22 | CPropGridApp::CPropGridApp() 23 | { 24 | // TODO: add construction code here, 25 | // Place all significant initialization in InitInstance 26 | } 27 | 28 | 29 | // The one and only CPropGridApp object 30 | 31 | CPropGridApp theApp; 32 | 33 | 34 | // CPropGridApp initialization 35 | 36 | BOOL CPropGridApp::InitInstance() 37 | { 38 | // InitCommonControls() is required on Windows XP if an application 39 | // manifest specifies use of ComCtl32.dll version 6 or later to enable 40 | // visual styles. Otherwise, any window creation will fail. 41 | InitCommonControls(); 42 | 43 | CWinApp::InitInstance(); 44 | 45 | // Standard initialization 46 | // If you are not using these features and wish to reduce the size 47 | // of your final executable, you should remove from the following 48 | // the specific initialization routines you do not need 49 | // Change the registry key under which our settings are stored 50 | // TODO: You should modify this string to be something appropriate 51 | // such as the name of your company or organization 52 | SetRegistryKey(_T("Local AppWizard-Generated Applications")); 53 | 54 | CPropGridDlg dlg; 55 | m_pMainWnd = &dlg; 56 | INT_PTR nResponse = dlg.DoModal(); 57 | if (nResponse == IDOK) 58 | { 59 | // TODO: Place code here to handle when the dialog is 60 | // dismissed with OK 61 | } 62 | else if (nResponse == IDCANCEL) 63 | { 64 | // TODO: Place code here to handle when the dialog is 65 | // dismissed with Cancel 66 | } 67 | 68 | // Since the dialog has been closed, return FALSE so that we exit the 69 | // application, rather than start the application's message pump. 70 | return FALSE; 71 | } 72 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/PropGrid.h: -------------------------------------------------------------------------------- 1 | // PropGrid.h : main header file for the PROJECT_NAME application 2 | // 3 | 4 | #pragma once 5 | 6 | #ifndef __AFXWIN_H__ 7 | #error include 'stdafx.h' before including this file for PCH 8 | #endif 9 | 10 | #include "resource.h" // main symbols 11 | 12 | 13 | // CPropGridApp: 14 | // See PropGrid.cpp for the implementation of this class 15 | // 16 | 17 | class CPropGridApp : public CWinApp 18 | { 19 | public: 20 | CPropGridApp(); 21 | 22 | // Overrides 23 | public: 24 | virtual BOOL InitInstance(); 25 | 26 | // Implementation 27 | 28 | DECLARE_MESSAGE_MAP() 29 | }; 30 | 31 | extern CPropGridApp theApp; -------------------------------------------------------------------------------- /ext/PropertyGrid/test/PropGrid.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "afxres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (U.S.) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | #ifdef _WIN32 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | #pragma code_page(1252) 22 | #endif //_WIN32 23 | 24 | ///////////////////////////////////////////////////////////////////////////// 25 | // 26 | // Dialog 27 | // 28 | 29 | IDD_PROPGRID_DIALOG DIALOGEX 0, 0, 358, 188 30 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | 31 | WS_CAPTION | WS_SYSMENU 32 | EXSTYLE WS_EX_APPWINDOW 33 | CAPTION "PropGrid" 34 | FONT 8, "MS Shell Dlg", 400, 0, 0x0 35 | BEGIN 36 | CONTROL "Categorized",IDC_CATEGORIZED,"Button", 37 | BS_AUTORADIOBUTTON | WS_GROUP,272,22,55,10 38 | CONTROL "Alphabetical",IDC_ALPHABETICAL,"Button", 39 | BS_AUTORADIOBUTTON,272,35,55,10 40 | CONTROL "No Sort",IDC_NOSORT,"Button",BS_AUTORADIOBUTTON,272,48, 41 | 55,10 42 | CONTROL "Custom colors",IDC_CUSTOM_COLORS,"Button", 43 | BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,256,72,95,10 44 | PUSHBUTTON "Collapse",IDC_COLLAPSE_ALL,256,85,45,14 45 | PUSHBUTTON "Expand",IDC_EXPAND_ALL,306,85,45,14 46 | DEFPUSHBUTTON "OK",IDOK,301,144,50,16 47 | CONTROL "",IDC_GRID,"Static",SS_BLACKFRAME | SS_NOTIFY,7,7,239, 48 | 174,WS_EX_TRANSPARENT | WS_EX_CLIENTEDGE 49 | GROUPBOX "Display Mode",IDC_STATIC,256,7,95,63 50 | PUSHBUTTON "Cancel",IDCANCEL,301,165,50,16 51 | END 52 | 53 | IDD_RECT_EDIT DIALOGEX 0, 0, 123, 114 54 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 55 | WS_SYSMENU 56 | CAPTION "Rectangle" 57 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 58 | BEGIN 59 | DEFPUSHBUTTON "OK",IDOK,9,92,50,14 60 | PUSHBUTTON "Cancel",IDCANCEL,63,92,50,14 61 | RTEXT "Left",IDC_STATIC,20,18,24,8 62 | RTEXT "Top",IDC_STATIC,20,33,24,8 63 | RTEXT "Right",IDC_STATIC,20,48,24,8 64 | RTEXT "Bottom",IDC_STATIC,20,63,24,8 65 | EDITTEXT IDC_LEFT,52,15,53,14,ES_AUTOHSCROLL 66 | EDITTEXT IDC_TOP,52,30,53,14,ES_AUTOHSCROLL 67 | EDITTEXT IDC_RIGHT,52,45,53,14,ES_AUTOHSCROLL 68 | EDITTEXT IDC_BOTTOM,52,60,53,14,ES_AUTOHSCROLL 69 | GROUPBOX "",IDC_STATIC,7,3,109,80 70 | END 71 | 72 | 73 | ///////////////////////////////////////////////////////////////////////////// 74 | // 75 | // Version 76 | // 77 | 78 | VS_VERSION_INFO VERSIONINFO 79 | FILEVERSION 1,0,0,1 80 | PRODUCTVERSION 1,0,0,1 81 | FILEFLAGSMASK 0x3fL 82 | #ifdef _DEBUG 83 | FILEFLAGS 0x1L 84 | #else 85 | FILEFLAGS 0x0L 86 | #endif 87 | FILEOS 0x4L 88 | FILETYPE 0x1L 89 | FILESUBTYPE 0x0L 90 | BEGIN 91 | BLOCK "StringFileInfo" 92 | BEGIN 93 | BLOCK "040904e4" 94 | BEGIN 95 | VALUE "CompanyName", "TODO: " 96 | VALUE "FileDescription", "TODO: " 97 | VALUE "FileVersion", "1.0.0.1" 98 | VALUE "InternalName", "PropGrid.exe" 99 | VALUE "LegalCopyright", "TODO: (c) . All rights reserved." 100 | VALUE "OriginalFilename", "PropGrid.exe" 101 | VALUE "ProductName", "TODO: " 102 | VALUE "ProductVersion", "1.0.0.1" 103 | END 104 | END 105 | BLOCK "VarFileInfo" 106 | BEGIN 107 | VALUE "Translation", 0x409, 1252 108 | END 109 | END 110 | 111 | 112 | ///////////////////////////////////////////////////////////////////////////// 113 | // 114 | // DESIGNINFO 115 | // 116 | 117 | #ifdef APSTUDIO_INVOKED 118 | GUIDELINES DESIGNINFO 119 | BEGIN 120 | IDD_PROPGRID_DIALOG, DIALOG 121 | BEGIN 122 | LEFTMARGIN, 7 123 | RIGHTMARGIN, 351 124 | TOPMARGIN, 7 125 | BOTTOMMARGIN, 181 126 | END 127 | 128 | IDD_RECT_EDIT, DIALOG 129 | BEGIN 130 | LEFTMARGIN, 7 131 | RIGHTMARGIN, 116 132 | TOPMARGIN, 7 133 | BOTTOMMARGIN, 107 134 | END 135 | END 136 | #endif // APSTUDIO_INVOKED 137 | 138 | #endif // English (U.S.) resources 139 | ///////////////////////////////////////////////////////////////////////////// 140 | 141 | 142 | ///////////////////////////////////////////////////////////////////////////// 143 | // French (France) resources 144 | 145 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) 146 | #ifdef _WIN32 147 | LANGUAGE LANG_FRENCH, SUBLANG_FRENCH 148 | #pragma code_page(1252) 149 | #endif //_WIN32 150 | 151 | #ifdef APSTUDIO_INVOKED 152 | ///////////////////////////////////////////////////////////////////////////// 153 | // 154 | // TEXTINCLUDE 155 | // 156 | 157 | 1 TEXTINCLUDE 158 | BEGIN 159 | "resource.h\0" 160 | END 161 | 162 | 2 TEXTINCLUDE 163 | BEGIN 164 | "#include ""afxres.h""\r\n" 165 | "\0" 166 | END 167 | 168 | 3 TEXTINCLUDE 169 | BEGIN 170 | "#define _AFX_NO_SPLITTER_RESOURCES\r\n" 171 | "#define _AFX_NO_OLE_RESOURCES\r\n" 172 | "#define _AFX_NO_TRACKER_RESOURCES\r\n" 173 | "#define _AFX_NO_PROPERTY_RESOURCES\r\n" 174 | "\r\n" 175 | "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" 176 | "LANGUAGE 9, 1\r\n" 177 | "#pragma code_page(1252)\r\n" 178 | "#include ""res\\PropGrid.rc2"" // non-Microsoft Visual C++ edited resources\r\n" 179 | "#include ""afxres.rc"" // Standard components\r\n" 180 | "#endif\r\n" 181 | "\0" 182 | END 183 | 184 | #endif // APSTUDIO_INVOKED 185 | 186 | 187 | ///////////////////////////////////////////////////////////////////////////// 188 | // 189 | // Icon 190 | // 191 | 192 | // Icon with lowest ID value placed first to ensure application icon 193 | // remains consistent on all systems. 194 | IDR_MAINFRAME ICON "res\\PropGrid.ico" 195 | #endif // French (France) resources 196 | ///////////////////////////////////////////////////////////////////////////// 197 | 198 | 199 | 200 | #ifndef APSTUDIO_INVOKED 201 | ///////////////////////////////////////////////////////////////////////////// 202 | // 203 | // Generated from the TEXTINCLUDE 3 resource. 204 | // 205 | #define _AFX_NO_SPLITTER_RESOURCES 206 | #define _AFX_NO_OLE_RESOURCES 207 | #define _AFX_NO_TRACKER_RESOURCES 208 | #define _AFX_NO_PROPERTY_RESOURCES 209 | 210 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 211 | LANGUAGE 9, 1 212 | #pragma code_page(1252) 213 | #include "res\PropGrid.rc2" // non-Microsoft Visual C++ edited resources 214 | #include "afxres.rc" // Standard components 215 | #endif 216 | 217 | ///////////////////////////////////////////////////////////////////////////// 218 | #endif // not APSTUDIO_INVOKED 219 | 220 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/PropGridDlg.cpp: -------------------------------------------------------------------------------- 1 | // PropGridDlg.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "PropGrid.h" 6 | #include "PropGridDlg.h" 7 | #include ".\propgriddlg.h" 8 | 9 | #ifdef _DEBUG 10 | #define new DEBUG_NEW 11 | #endif 12 | 13 | 14 | // CPropGridDlg dialog 15 | 16 | 17 | 18 | CPropGridDlg::CPropGridDlg(CWnd* pParent /*=NULL*/) 19 | : CDialog(CPropGridDlg::IDD, pParent) 20 | { 21 | m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 22 | } 23 | 24 | void CPropGridDlg::DoDataExchange(CDataExchange* pDX) 25 | { 26 | CDialog::DoDataExchange(pDX); 27 | DDX_Control(pDX, IDC_GRID, m_ctrlGrid); 28 | } 29 | 30 | BEGIN_MESSAGE_MAP(CPropGridDlg, CDialog) 31 | ON_WM_PAINT() 32 | ON_WM_QUERYDRAGICON() 33 | ON_BN_CLICKED(IDOK, OnBnClickedOk) 34 | ON_MESSAGE(WM_PG_ITEMCHANGED, OnItemChanged) 35 | ON_BN_CLICKED(IDC_COLLAPSE_ALL, OnBnClickedCollapseAll) 36 | ON_BN_CLICKED(IDC_EXPAND_ALL, OnBnClickedExpandAll) 37 | ON_BN_CLICKED(IDC_CUSTOM_COLORS, OnBnClickedCustomColors) 38 | ON_BN_CLICKED(IDC_CATEGORIZED, OnBnClickedCategorized) 39 | ON_BN_CLICKED(IDC_ALPHABETICAL, OnBnClickedAlphabetical) 40 | ON_BN_CLICKED(IDC_NOSORT, OnBnClickedNosort) 41 | END_MESSAGE_MAP() 42 | 43 | 44 | // CPropGridDlg message handlers 45 | 46 | BOOL CPropGridDlg::OnInitDialog() 47 | { 48 | CDialog::OnInitDialog(); 49 | 50 | // Set the icon for this dialog. The framework does this automatically 51 | // when the application's main window is not a dialog 52 | SetIcon(m_hIcon, TRUE); // Set big icon 53 | SetIcon(m_hIcon, FALSE); // Set small icon 54 | 55 | // basic items 56 | HSECTION hs = m_ctrlGrid.AddSection("Basic Items"); 57 | m_ctrlGrid.AddStringItem(hs, "String", "A single line string item"); 58 | m_ctrlGrid.AddTextItem(hs, "Text", "A multi line text item.\r\nSecond line..."); 59 | m_ctrlGrid.AddStringItem(hs, "Disabled item", "A disabled item", false); 60 | m_ctrlGrid.AddIntegerItem(hs, "Integer", 10); 61 | m_ctrlGrid.AddIntegerItem(hs, "Formatted Integer", 8, "%d inches"); 62 | m_ctrlGrid.AddDoubleItem(hs, "Double", 7.33); 63 | m_ctrlGrid.AddDoubleItem(hs, "Formatted Double", 10.25, "%gmm"); 64 | m_ctrlGrid.AddBoolItem(hs, "Boolean", true); 65 | 66 | // custom items 67 | hs = m_ctrlGrid.AddSection("Custom Items"); 68 | m_ctrlGrid.AddCustomItem(hs, "Custom In-place Edit", &m_item_serial); 69 | m_ctrlGrid.AddCustomItem(hs, "Custom Modal Edit", &m_item_rect); 70 | m_ctrlGrid.AddCustomItem(hs, "Ccustom Dropdown Edit", &m_item_tree); 71 | m_ctrlGrid.AddCustomItem(hs, "Full Custom Edit", &m_item_gradient); 72 | 73 | // more items inserted before the custom ones 74 | hs = m_ctrlGrid.AddSection("More Items", true, hs); 75 | 76 | // a combo 77 | vector v; 78 | v.push_back("English"); 79 | v.push_back("French"); 80 | v.push_back("German"); 81 | v.push_back("Spanish"); 82 | m_ctrlGrid.AddComboItem(hs, "Combo", v, 2, true); 83 | 84 | // some "simple" 85 | m_ctrlGrid.AddDateItem(hs, "Date", COleDateTime::GetCurrentTime()); 86 | m_ctrlGrid.AddDateItem(hs, "Formatted Date", COleDateTime::GetCurrentTime(), "%A, %d %B %Y"); 87 | m_ctrlGrid.AddDateTimeItem(hs, "Date Time", COleDateTime::GetCurrentTime()); 88 | m_ctrlGrid.AddColorItem(hs, "Color", RGB(255,156,12)); 89 | m_ctrlGrid.AddFileItem(hs, "File", "C:\\AUTOEXEC.BAT", "All Files (*.*)|*.*||"); 90 | m_ctrlGrid.AddFolderItem(hs, "Folder", "C:\\", "Select a folder"); 91 | 92 | // a font 93 | LOGFONT lf; 94 | CFont font; 95 | font.CreatePointFont(80, "Tahoma"); 96 | font.GetLogFont(&lf); 97 | m_ctrlGrid.AddFontItem(hs, "Font", lf, true); 98 | 99 | // customization 100 | hs = m_ctrlGrid.AddSection("Grid customization"); 101 | m_hItemShade = m_ctrlGrid.AddBoolItem(hs, "Shade titles", m_ctrlGrid.GetShadeTitles()); 102 | m_hItemLines = m_ctrlGrid.AddBoolItem(hs, "Draw lines", m_ctrlGrid.GetDrawLines()); 103 | m_hItemGutter = m_ctrlGrid.AddBoolItem(hs, "Draw gutter", m_ctrlGrid.GetDrawGutter()); 104 | m_hItemFocusDis = m_ctrlGrid.AddBoolItem(hs, "Focus disabled items", m_ctrlGrid.GetFocusDisabled()); 105 | 106 | // stuff 107 | m_ctrlGrid.SetOkCancelStrings("OK", "Annuler"); 108 | m_ctrlGrid.SetDateTimeStrings("Date", "Heure"); 109 | 110 | // 111 | ((CButton*)GetDlgItem(IDC_CATEGORIZED))->SetCheck(1); 112 | 113 | return TRUE; // return TRUE unless you set the focus to a control 114 | } 115 | 116 | // If you add a minimize button to your dialog, you will need the code below 117 | // to draw the icon. For MFC applications using the document/view model, 118 | // this is automatically done for you by the framework. 119 | 120 | void CPropGridDlg::OnPaint() 121 | { 122 | if (IsIconic()) 123 | { 124 | CPaintDC dc(this); // device context for painting 125 | 126 | SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); 127 | 128 | // Center icon in client rectangle 129 | int cxIcon = GetSystemMetrics(SM_CXICON); 130 | int cyIcon = GetSystemMetrics(SM_CYICON); 131 | CRect rect; 132 | GetClientRect(&rect); 133 | int x = (rect.Width() - cxIcon + 1) / 2; 134 | int y = (rect.Height() - cyIcon + 1) / 2; 135 | 136 | // Draw the icon 137 | dc.DrawIcon(x, y, m_hIcon); 138 | } 139 | else 140 | { 141 | CDialog::OnPaint(); 142 | } 143 | } 144 | 145 | // The system calls this function to obtain the cursor to display while the user drags 146 | // the minimized window. 147 | HCURSOR CPropGridDlg::OnQueryDragIcon() 148 | { 149 | return static_cast(m_hIcon); 150 | } 151 | 152 | void CPropGridDlg::OnBnClickedOk() 153 | { 154 | //string strValue; 155 | //if (m_ctrlGrid.GetItemValue(m_hItem, strValue)) 156 | // AfxMessageBox(strValue.c_str()); 157 | OnOK(); 158 | } 159 | 160 | LRESULT CPropGridDlg::OnItemChanged(WPARAM wParam, LPARAM lParam) 161 | { 162 | if (wParam == m_hItemLines) 163 | { 164 | bool draw_lines; 165 | m_ctrlGrid.GetItemValue(m_hItemLines, draw_lines); 166 | m_ctrlGrid.SetDrawLines(draw_lines); 167 | } 168 | else if (wParam == m_hItemShade) 169 | { 170 | bool shade_titles; 171 | m_ctrlGrid.GetItemValue(m_hItemShade, shade_titles); 172 | m_ctrlGrid.SetShadeTitles(shade_titles); 173 | } 174 | else if (wParam == m_hItemGutter) 175 | { 176 | bool draw_gutter; 177 | m_ctrlGrid.GetItemValue(m_hItemGutter, draw_gutter); 178 | m_ctrlGrid.SetDrawGutter(draw_gutter); 179 | } 180 | else if (wParam == m_hItemFocusDis) 181 | { 182 | bool focus_disabled; 183 | m_ctrlGrid.GetItemValue(m_hItemFocusDis, focus_disabled); 184 | m_ctrlGrid.SetFocusDisabled(focus_disabled); 185 | } 186 | 187 | return 0; 188 | } 189 | 190 | void CPropGridDlg::OnBnClickedCollapseAll() 191 | { 192 | m_ctrlGrid.ExpandAll(false); 193 | } 194 | 195 | void CPropGridDlg::OnBnClickedExpandAll() 196 | { 197 | m_ctrlGrid.ExpandAll(true); 198 | } 199 | 200 | void CPropGridDlg::OnBnClickedCustomColors() 201 | { 202 | CButton* pBtn = (CButton*) GetDlgItem(IDC_CUSTOM_COLORS); 203 | if (pBtn->GetCheck() == 0) 204 | { 205 | m_ctrlGrid.SetBackColor(GetSysColor(COLOR_WINDOW)); 206 | m_ctrlGrid.SetShadeColor(GetSysColor(COLOR_3DFACE)); 207 | m_ctrlGrid.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); 208 | m_ctrlGrid.SetTitleColor(GetSysColor(COLOR_WINDOWTEXT)); 209 | } 210 | else 211 | { 212 | m_ctrlGrid.SetBackColor(RGB(0xFF, 0xFF, 0xE0)); 213 | m_ctrlGrid.SetShadeColor(RGB(0,187,94)); 214 | m_ctrlGrid.SetTextColor(RGB(0,0,192)); 215 | m_ctrlGrid.SetTitleColor(RGB(255,255,255)); 216 | } 217 | } 218 | 219 | void CPropGridDlg::OnBnClickedCategorized() 220 | { 221 | m_ctrlGrid.SetDisplayMode(CPropertyGrid::DM_CATEGORIZED); 222 | GetDlgItem(IDC_EXPAND_ALL)->EnableWindow(TRUE); 223 | GetDlgItem(IDC_COLLAPSE_ALL)->EnableWindow(TRUE); 224 | } 225 | 226 | void CPropGridDlg::OnBnClickedAlphabetical() 227 | { 228 | m_ctrlGrid.SetDisplayMode(CPropertyGrid::DM_ALPHABETICAL); 229 | GetDlgItem(IDC_EXPAND_ALL)->EnableWindow(FALSE); 230 | GetDlgItem(IDC_COLLAPSE_ALL)->EnableWindow(FALSE); 231 | } 232 | 233 | void CPropGridDlg::OnBnClickedNosort() 234 | { 235 | m_ctrlGrid.SetDisplayMode(CPropertyGrid::DM_NOSORT); 236 | GetDlgItem(IDC_EXPAND_ALL)->EnableWindow(FALSE); 237 | GetDlgItem(IDC_COLLAPSE_ALL)->EnableWindow(FALSE); 238 | } 239 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/PropGridDlg.h: -------------------------------------------------------------------------------- 1 | // PropGridDlg.h : header file 2 | // 3 | 4 | #pragma once 5 | #include "..\PropertyGrid.h" 6 | #include "GradientItem.h" 7 | #include "SerialItem.h" 8 | #include "RectItem.h" 9 | #include "TreeItem.h" 10 | 11 | // CPropGridDlg dialog 12 | class CPropGridDlg : public CDialog 13 | { 14 | // Construction 15 | public: 16 | CPropGridDlg(CWnd* pParent = NULL); // standard constructor 17 | 18 | // Dialog Data 19 | enum { IDD = IDD_PROPGRID_DIALOG }; 20 | 21 | protected: 22 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 23 | 24 | protected: 25 | CGradientItem m_item_gradient; 26 | CSerialItem m_item_serial; 27 | CRectItem m_item_rect; 28 | CTreeItem m_item_tree; 29 | 30 | // Implementation 31 | protected: 32 | HICON m_hIcon; 33 | HITEM m_hItemLines; 34 | HITEM m_hItemShade; 35 | HITEM m_hItemGutter; 36 | HITEM m_hItemFocusDis; 37 | 38 | // Generated message map functions 39 | virtual BOOL OnInitDialog(); 40 | afx_msg void OnPaint(); 41 | afx_msg HCURSOR OnQueryDragIcon(); 42 | DECLARE_MESSAGE_MAP() 43 | 44 | public: 45 | CPropertyGrid m_ctrlGrid; 46 | afx_msg LRESULT OnItemChanged(WPARAM, LPARAM); 47 | afx_msg void OnBnClickedOk(); 48 | afx_msg void OnBnClickedCollapseAll(); 49 | afx_msg void OnBnClickedExpandAll(); 50 | afx_msg void OnBnClickedCustomColors(); 51 | afx_msg void OnBnClickedCategorized(); 52 | afx_msg void OnBnClickedAlphabetical(); 53 | afx_msg void OnBnClickedNosort(); 54 | }; 55 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/RectEditDlg.cpp: -------------------------------------------------------------------------------- 1 | // RectEditDlg.cpp : implementation file 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "PropGrid.h" 6 | #include "RectEditDlg.h" 7 | 8 | 9 | // CRectEditDlg dialog 10 | 11 | IMPLEMENT_DYNAMIC(CRectEditDlg, CDialog) 12 | CRectEditDlg::CRectEditDlg(CWnd* pParent /*=NULL*/) 13 | : CDialog(CRectEditDlg::IDD, pParent) 14 | , m_left(10) 15 | , m_top(10) 16 | , m_right(10) 17 | , m_bottom(10) 18 | { 19 | } 20 | 21 | CRectEditDlg::~CRectEditDlg() 22 | { 23 | } 24 | 25 | void CRectEditDlg::DoDataExchange(CDataExchange* pDX) 26 | { 27 | CDialog::DoDataExchange(pDX); 28 | DDX_Text(pDX, IDC_LEFT, m_left); 29 | DDV_MinMaxInt(pDX, m_left, 1, 1000); 30 | DDX_Text(pDX, IDC_TOP, m_top); 31 | DDV_MinMaxInt(pDX, m_top, 1, 1000); 32 | DDX_Text(pDX, IDC_RIGHT, m_right); 33 | DDV_MinMaxInt(pDX, m_right, 1, 1000); 34 | DDX_Text(pDX, IDC_BOTTOM, m_bottom); 35 | DDV_MinMaxInt(pDX, m_bottom, 1, 1000); 36 | } 37 | 38 | 39 | BEGIN_MESSAGE_MAP(CRectEditDlg, CDialog) 40 | END_MESSAGE_MAP() 41 | 42 | 43 | // CRectEditDlg message handlers 44 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/RectEditDlg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "resource.h" 3 | 4 | // CRectEditDlg dialog 5 | 6 | class CRectEditDlg : public CDialog 7 | { 8 | DECLARE_DYNAMIC(CRectEditDlg) 9 | 10 | public: 11 | CRectEditDlg(CWnd* pParent = NULL); // standard constructor 12 | virtual ~CRectEditDlg(); 13 | 14 | // Dialog Data 15 | enum { IDD = IDD_RECT_EDIT }; 16 | 17 | protected: 18 | virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support 19 | 20 | DECLARE_MESSAGE_MAP() 21 | public: 22 | int m_left; 23 | int m_top; 24 | int m_right; 25 | int m_bottom; 26 | }; 27 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/RectItem.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "RectItem.h" 3 | #include "RectEditDlg.h" 4 | 5 | CRectItem::CRectItem(void) 6 | { 7 | m_left = 20; 8 | m_top = 20; 9 | m_right = 100; 10 | m_bottom = 100; 11 | } 12 | 13 | CRectItem::~CRectItem(void) 14 | { 15 | } 16 | 17 | CPropertyGrid::EEditMode CRectItem::GetEditMode() 18 | { 19 | return CPropertyGrid::EM_MODAL; 20 | } 21 | 22 | void CRectItem::DrawItem(CDC& dc, CRect rc, bool focused) 23 | { 24 | CString str; 25 | str.Format("%d; %d; %d; %d", m_left, m_top, m_right, m_bottom); 26 | rc.left += m_pGrid->GetTextMargin(); 27 | dc.DrawText(str, rc, DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_END_ELLIPSIS|DT_NOPREFIX); 28 | } 29 | 30 | bool CRectItem::OnEditItem() 31 | { 32 | CRectEditDlg dlg(m_pGrid); 33 | dlg.m_left = m_left; 34 | dlg.m_top = m_top; 35 | dlg.m_right = m_right; 36 | dlg.m_bottom = m_bottom; 37 | if (dlg.DoModal() == IDOK) 38 | { 39 | m_left = dlg.m_left; 40 | m_top = dlg.m_top; 41 | m_right = dlg.m_right; 42 | m_bottom = dlg.m_bottom; 43 | return true; 44 | } 45 | return false; 46 | } 47 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/RectItem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "..\CustomItem.h" 3 | 4 | class CRectItem : public ICustomItem 5 | { 6 | public: 7 | CRectItem(void); 8 | ~CRectItem(void); 9 | 10 | virtual CPropertyGrid::EEditMode GetEditMode(); 11 | virtual void DrawItem(CDC& dc, CRect rc, bool focused); 12 | virtual bool OnEditItem(); 13 | 14 | protected: 15 | int m_left; 16 | int m_top; 17 | int m_right; 18 | int m_bottom; 19 | }; 20 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/SerialItem.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include ".\serialitem.h" 3 | 4 | CSerialItem::CSerialItem(void) 5 | { 6 | m_serial = "12348765"; 7 | } 8 | 9 | CSerialItem::~CSerialItem(void) 10 | { 11 | } 12 | 13 | CPropertyGrid::EEditMode CSerialItem::GetEditMode() 14 | { 15 | return CPropertyGrid::EM_INPLACE; 16 | } 17 | 18 | void CSerialItem::DrawItem(CDC& dc, CRect rc, bool focused) 19 | { 20 | string serial = m_serial; 21 | while (serial.length()<8) serial += " "; 22 | serial = serial.substr(0,4) + "-" + serial.substr(4,4); 23 | rc.left += m_pGrid->GetTextMargin(); 24 | dc.DrawText(serial.c_str(), rc, DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_END_ELLIPSIS|DT_NOPREFIX); 25 | } 26 | 27 | string CSerialItem::GetStringForInPlaceEdit() 28 | { 29 | return m_serial; 30 | } 31 | 32 | bool CSerialItem::OnItemEdited(string strNewValue) 33 | { 34 | if (strNewValue.length()!=8) 35 | { 36 | AfxMessageBox("Invalid serial number"); 37 | return false; 38 | } 39 | else 40 | { 41 | m_serial = strNewValue; 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/SerialItem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "..\CustomItem.h" 3 | 4 | class CSerialItem : public ICustomItem 5 | { 6 | public: 7 | CSerialItem(void); 8 | ~CSerialItem(void); 9 | virtual CPropertyGrid::EEditMode GetEditMode(); 10 | virtual void DrawItem(CDC& dc, CRect rc, bool focused); 11 | virtual string GetStringForInPlaceEdit(); 12 | virtual bool OnItemEdited(string strNewValue); 13 | 14 | protected: 15 | string m_serial; 16 | }; 17 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/TreeItem.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include ".\treeitem.h" 3 | 4 | CTreeItem::CTreeItem(void) 5 | { 6 | } 7 | 8 | CTreeItem::~CTreeItem(void) 9 | { 10 | } 11 | 12 | void CTreeItem::SetValue(string value) 13 | { 14 | m_value = value; 15 | m_pGrid->Invalidate(); 16 | } 17 | 18 | CPropertyGrid::EEditMode CTreeItem::GetEditMode() 19 | { 20 | return CPropertyGrid::EM_DROPDOWN; 21 | } 22 | 23 | void CTreeItem::DrawItem(CDC& dc, CRect rc, bool focused) 24 | { 25 | rc.left += m_pGrid->GetTextMargin(); 26 | dc.DrawText(m_value.c_str(), rc, DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_END_ELLIPSIS|DT_NOPREFIX); 27 | } 28 | 29 | void CTreeItem::ShowDropDown(CRect rc) 30 | { 31 | rc.top += rc.Height(); 32 | rc.bottom = rc.top + 100; 33 | m_pGrid->ClientToScreen(&rc); 34 | m_tree = new CCustomTreeCtrl; 35 | m_tree->m_item = this; 36 | m_tree->CWnd::CreateEx(0, WC_TREEVIEW, NULL, WS_POPUP|WS_BORDER|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT, rc, m_pGrid->GetParent(), 0); 37 | m_tree->SetOwner(m_pGrid->GetParent()); 38 | HTREEITEM hf = m_tree->InsertItem("Folder 1"); 39 | m_tree->InsertItem("Item 1", hf); 40 | m_tree->InsertItem("Item 2", hf); 41 | m_tree->Expand(hf, TVE_EXPAND); 42 | hf = m_tree->InsertItem("Folder 2"); 43 | m_tree->InsertItem("Item 3", hf); 44 | m_tree->Expand(hf, TVE_EXPAND); 45 | m_tree->ShowWindow(SW_SHOW); 46 | m_tree->RedrawWindow(); 47 | } 48 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/TreeItem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "..\customitem.h" 3 | #include "CustomTreeCtrl.h" 4 | 5 | class CTreeItem : 6 | public ICustomItem 7 | { 8 | public: 9 | CTreeItem(void); 10 | ~CTreeItem(void); 11 | 12 | virtual CPropertyGrid::EEditMode GetEditMode(); 13 | virtual void DrawItem(CDC& dc, CRect rc, bool focused); 14 | virtual void ShowDropDown(CRect rc); 15 | 16 | void SetValue(string value); 17 | 18 | protected: 19 | string m_value; 20 | CCustomTreeCtrl* m_tree; 21 | }; 22 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/res/PropGrid.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isledecomp/LEGOIslandRebuilder/6e1c7cd263330eb466aed970f469a704ef3aad4d/ext/PropertyGrid/test/res/PropGrid.ico -------------------------------------------------------------------------------- /ext/PropertyGrid/test/res/PropGrid.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | Your app description here 10 | 11 | 12 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/res/PropGrid.rc2: -------------------------------------------------------------------------------- 1 | // 2 | // PropGrid.RC2 - resources Microsoft Visual C++ does not edit directly 3 | // 4 | 5 | #ifdef APSTUDIO_INVOKED 6 | #error this file is not editable by Microsoft Visual C++ 7 | #endif //APSTUDIO_INVOKED 8 | 9 | 10 | ///////////////////////////////////////////////////////////////////////////// 11 | // Add manually edited resources here... 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | -------------------------------------------------------------------------------- /ext/PropertyGrid/test/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by PropGrid.rc 4 | // 5 | #define IDD_PROPGRID_DIALOG 102 6 | #define IDR_MAINFRAME 128 7 | #define IDD_RECT_EDIT 129 8 | #define IDC_GRID 1000 9 | #define IDC_COMBO1 1001 10 | #define IDC_LEFT 1002 11 | #define IDC_TOP 1003 12 | #define IDC_COLLAPSE_ALL 1003 13 | #define IDC_RIGHT 1004 14 | #define IDC_EXPAND_ALL 1004 15 | #define IDC_BOTTOM 1005 16 | #define IDC_CUSTOM_COLORS 1005 17 | #define IDC_CATEGORIZED 1010 18 | #define IDC_ALPHABETICAL 1011 19 | #define IDC_NOSORT 1012 20 | #define IDC_DATETIMEPICKER1 1013 21 | 22 | // Next default values for new objects 23 | // 24 | #ifdef APSTUDIO_INVOKED 25 | #ifndef APSTUDIO_READONLY_SYMBOLS 26 | #define _APS_NEXT_RESOURCE_VALUE 130 27 | #define _APS_NEXT_COMMAND_VALUE 32771 28 | #define _APS_NEXT_CONTROL_VALUE 1014 29 | #define _APS_NEXT_SYMED_VALUE 101 30 | #endif 31 | #endif 32 | -------------------------------------------------------------------------------- /lib/config.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../cmn/path.h" 8 | 9 | Config config; 10 | 11 | Config::Config() 12 | { 13 | 14 | } 15 | 16 | BOOL Config::Load() 17 | { 18 | // Get config file 19 | m_configFile.resize(MAX_PATH); 20 | if (!GetConfigFilename(&m_configFile[0])) { 21 | MessageBox(0, "Failed to generate configuration filename", 0, 0); 22 | return FALSE; 23 | } 24 | 25 | if (!PathFileExists(m_configFile.c_str())) { 26 | char buf[300]; 27 | sprintf(buf, "Failed to find configuration file \"%s\".", m_configFile.c_str()); 28 | MessageBox(0, buf, 0, 0); 29 | return FALSE; 30 | } 31 | 32 | return TRUE; 33 | } 34 | 35 | UINT Config::GetInt(LPCTSTR name, UINT defaultValue) 36 | { 37 | return GetPrivateProfileInt(appName, name, defaultValue, m_configFile.c_str()); 38 | } 39 | 40 | float Config::GetFloat(LPCTSTR name, float defaultValue) 41 | { 42 | // Convert float to string 43 | std::ostringstream oss; 44 | oss << defaultValue; 45 | std::string defaultStr = oss.str(); 46 | 47 | std::string currentStr = GetString(name, defaultStr); 48 | 49 | // Convert to float 50 | return atof(currentStr.c_str()); 51 | } 52 | 53 | std::string Config::GetString(LPCTSTR name, const std::string &defaultValue) 54 | { 55 | const int max_string_sz = 100; 56 | std::string s; 57 | s.resize(max_string_sz); 58 | 59 | DWORD count = GetPrivateProfileString(appName, name, defaultValue.c_str(), &s[0], max_string_sz, m_configFile.c_str()); 60 | 61 | s.resize(count); 62 | 63 | return s; 64 | } 65 | -------------------------------------------------------------------------------- /lib/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Config 9 | { 10 | public: 11 | Config(); 12 | 13 | BOOL Load(); 14 | 15 | UINT GetInt(LPCTSTR name, UINT defaultValue = 0); 16 | 17 | float GetFloat(LPCTSTR name, float defaultValue = 0.0f); 18 | 19 | std::string GetString(LPCTSTR name, const std::string &defaultValue = std::string()); 20 | 21 | private: 22 | std::basic_string m_configFile; 23 | 24 | }; 25 | 26 | extern Config config; 27 | 28 | #endif // CONFIG_H 29 | -------------------------------------------------------------------------------- /lib/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "config.h" 7 | #include "hooks.h" 8 | #include "util.h" 9 | 10 | __declspec(dllexport) DWORD WINAPI Patch() 11 | { 12 | if (!config.Load()) { 13 | MessageBoxA(0, "Failed to find Rebuilder configuration. No patches will be active.", 0, 0); 14 | return 1; 15 | } 16 | 17 | // Hook import address table 18 | LPVOID exeBase = GetModuleHandle(TEXT("ISLE.EXE")); 19 | LPVOID dllBase = GetModuleHandle(TEXT("LEGO1.DLL")); 20 | 21 | // Redirect various imports 22 | OverwriteImport(exeBase, "CreateWindowExA", (LPVOID)InterceptCreateWindowExA); 23 | OverwriteImport(dllBase, "OutputDebugStringA", (LPVOID)InterceptOutputDebugStringA); 24 | OverwriteImport(exeBase, "RegQueryValueExA", (LPVOID)InterceptRegQueryValueExA); 25 | OverwriteImport(exeBase, "RegisterClassA", (LPVOID)InterceptRegisterClassA); 26 | OverwriteImport(dllBase, "Sleep", (LPVOID)InterceptSleep); 27 | OverwriteImport(exeBase, "Sleep", (LPVOID)InterceptSleep); 28 | OverwriteImport(dllBase, "GetAsyncKeyState", (LPVOID)InterceptGetAsyncKeyState); 29 | ddCreateOriginal = (ddCreateFunction)OverwriteImport(dllBase, "DirectDrawCreate", (LPVOID)InterceptDirectDrawCreate); 30 | d3drmCreateOriginal = (d3drmCreateFunction)OverwriteImport(dllBase, "Direct3DRMCreate", (LPVOID)InterceptDirect3DRMCreate); 31 | dsCreateOriginal = (dsCreateFunction)OverwriteImport(dllBase, "DirectSoundCreate", (LPVOID)InterceptDirectSoundCreate); 32 | dinputCreateOriginal = (dinputCreateFunction)OverwriteImport(dllBase, "DirectInputCreateA", (LPVOID)InterceptDirectInputCreateA); 33 | 34 | // Flip surfaces is incompatible with full screen, if these options are set, warn the user 35 | if (config.GetInt(_T("FlipSurfaces")) && !config.GetInt(_T("FullScreen"))) { 36 | if (MessageBoxA(0, "The setting 'Flip Video Memory Pages' is incompatible with LEGO Island's windowed mode. " 37 | "LEGO Island will likely fail to start up unless you disable 'Flip Video Memory Pages' " 38 | "or run in full screen mode. Do you wish to continue?", "Warning", MB_YESNO) == IDNO) { 39 | TerminateProcess(GetCurrentProcess(), 0); 40 | } 41 | } 42 | 43 | // Stay active when defocused 44 | if (config.GetInt(_T("StayActiveWhenDefocused"))) { 45 | // Patch jump if window isn't active (TODO: Replace with C++ patch) 46 | SearchReplacePattern(exeBase, "\x89\x58\x70", "\x90\x90\x90", 3); 47 | } 48 | 49 | // Allow multiple instances 50 | if (config.GetInt(_T("MultipleInstances"))) { 51 | // Patch FindWindowA import to always tell ISLE that no other ISLE window exists 52 | OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA); 53 | } 54 | 55 | // Speed up startup 56 | if (config.GetInt(_T("SpeedUpStartUp"))) { 57 | // Replace "200" frame wait value with "1" 58 | const char *speedup_pattern = "\xC8\x00\x00\x00\x00\x00\x00\x00"; 59 | const char *speedup_replace = "\x01\x00\x00\x00\x00\x00\x00\x00"; 60 | 61 | SearchReplacePattern(exeBase, speedup_pattern, speedup_replace, 8, TRUE); 62 | } 63 | 64 | // Debug mode 65 | if (config.GetInt(_T("DebugToggle"))) { 66 | // LEGO1 uses a string pointer to know if OGEL has been typed, if the string pointer sees 0x0 67 | // (null-terminator/end of string), then debug mode is enabled. So we just replace the first 68 | // character with 0x0 and it's permanently on. 69 | SearchReplacePattern(dllBase, "OGEL", "\x0GEL", 4, TRUE); 70 | } 71 | 72 | // If using WASD, swap debug keys 73 | if (config.GetInt(_T("UseWASD"))) { 74 | const char *dbg_map_pattern = "\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x18\x18\x18\x18\x18\x18\x18\x02\x18\x03\x04\x18\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x18\x0E\x18\x18\x0F\x18"; 75 | const char *dbg_map_replace = "\x02\x18\x04\x0F\x18\x18\x18\x18\x18\x18\x18\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x18\x18\x18\x18\x18\x18\x18\x18\x18\x03\x18\x18\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x18\x0E\x18\x18\x18\x18"; 76 | SearchReplacePattern(dllBase, dbg_map_pattern, dbg_map_replace, 48, TRUE); 77 | } 78 | 79 | // Exit crash fix 80 | if (config.GetInt(_T("ExitCrashFix"))) { 81 | const char *buffer_pattern = "\x50\x52\x51\x8B\x01\xFF\x50\x2C\x85\xC0\x75\x67\x8B\x7C\x24\x14\x8B\x74\x24\x30\x8B\xCB\xC1\xE9\x02\xF3\xA5\x8B\xCB\x83\xE1\x03\xF3\xA4\x8B\x55\x60"; 82 | const char *buffer_replace = "\x53\x52\x51\x8B\x01\xFF\x50\x2C\x85\xC0\x75\x67\x8B\x7C\x24\x14\x8B\x74\x24\x30\x8B\x55\x60\x3B\xD3\x7C\x04\x8B\xCB\xEB\x02\x8B\xCA\x90\x90\xF3\xA4"; 83 | 84 | const char *wndproc_pattern = "\xC6\x44\x24\x00\x00\x53\x56\x57"; 85 | const char *wndproc_replace = "\xC6\x44\x24\x00\x0A\x53\x56\x57"; 86 | 87 | SearchReplacePattern(dllBase, buffer_pattern, buffer_replace, 37, TRUE); 88 | SearchReplacePattern(exeBase, wndproc_pattern, wndproc_replace, 8, TRUE); 89 | } 90 | 91 | // Disable SMK scaling 92 | if (config.GetInt(_T("NativeSMK"))) { 93 | const char *smk_pattern = "\x8A\x4C\x24\x0C\x51"; 94 | const char *smk_replace = "\xB1\x00\x90\x90\x51"; 95 | SearchReplacePattern(dllBase, smk_pattern, smk_replace, 5, TRUE); 96 | } 97 | 98 | // Disable auto-finish in build sections 99 | if (config.GetInt(_T("DisableAutoFinishBuilding"))) { 100 | // Pattern used in August build (jump is much shorter so it uses a different opcode) 101 | const char *autofinish_pattern = "\x66\x39\x90\xBE\x00\x00\x00\x75"; 102 | const char *autofinish_replace = "\x66\x39\x90\xBE\x00\x00\x00\xEB"; 103 | 104 | if (SearchReplacePattern(dllBase, autofinish_pattern, autofinish_replace, 8) == 0) { 105 | // Pattern used in September build (jump is much longer) 106 | autofinish_pattern = "\x66\x39\x90\xBE\x00\x00\x00\x0F\x85\x86\x00\x00\x00"; 107 | autofinish_replace = "\x66\x39\x90\xBE\x00\x00\x00\xE9\x87\x00\x00\x00\x90"; 108 | SearchReplacePattern(dllBase, autofinish_pattern, autofinish_replace, 13); 109 | } 110 | } 111 | 112 | // Unhook turn speed 113 | float turn_max_spd = config.GetFloat(_T("TurnMaxSpeed"), 20.0f); 114 | 115 | if (config.GetInt(_T("UnhookTurnSpeed"))) { 116 | LPVOID code_offset = SearchPattern(dllBase, "\x74\x26\xD9\x46\x34", 5); 117 | if (code_offset) { 118 | const char *new_code = "\xD9\x46\x24\xD8\x4C\x24\x14\xD8\x4E\x34\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; 119 | WriteMemory(code_offset, (LPVOID)new_code, 36); 120 | turn_max_spd *= 2.0f; 121 | } else { 122 | printf("Failed to find code for unhooking turn speed\n"); 123 | } 124 | } 125 | 126 | // Patch navigation 127 | { 128 | const int nav_block_sz = 0x30; 129 | const char *nav_block_src = "\x28\x00\x00\x00\x6F\x12\x83\x3A\x00\x00\x20\x42\x00\x00\xA0\x41\x00\x00\x70\x41\x00\x00\xF0\x41\x00\x00\x80\x40\x00\x00\x70\x41\x00\x00\x48\x42\x00\x00\x48\x42\xCD\xCC\xCC\x3E\x00\x00\x00\x00"; 130 | char nav_block_dst[nav_block_sz]; 131 | memcpy(nav_block_dst, nav_block_src, nav_block_sz); 132 | 133 | UINT32 mouse_deadzone = config.GetInt(_T("MouseDeadzone"), 40); 134 | memcpy(nav_block_dst+0x0, &mouse_deadzone, sizeof(mouse_deadzone)); 135 | 136 | float movement_max_spd = config.GetFloat(_T("MovementMaxSpeed"), 40.0f); 137 | memcpy(nav_block_dst+0x8, &movement_max_spd, sizeof(movement_max_spd)); 138 | 139 | // Value retrieved above 140 | memcpy(nav_block_dst+0xC, &turn_max_spd, sizeof(turn_max_spd)); 141 | 142 | float movement_max_accel = config.GetFloat(_T("MovementMaxAcceleration"), 15.0f); 143 | memcpy(nav_block_dst+0x10, &movement_max_accel, sizeof(movement_max_accel)); 144 | 145 | float turn_max_accel = config.GetFloat(_T("TurnMaxAcceleration"), 30.0f); 146 | memcpy(nav_block_dst+0x14, &turn_max_accel, sizeof(turn_max_accel)); 147 | 148 | float movement_min_accel = config.GetFloat(_T("MovementMinAcceleration"), 4.0f); 149 | memcpy(nav_block_dst+0x18, &movement_min_accel, sizeof(movement_min_accel)); 150 | 151 | float turn_min_accel = config.GetFloat(_T("TurnMinAcceleration"), 15.0f); 152 | memcpy(nav_block_dst+0x1C, &turn_min_accel, sizeof(turn_min_accel)); 153 | 154 | float movement_decel = config.GetFloat(_T("MovementDeceleration"), 50.0f); 155 | memcpy(nav_block_dst+0x20, &movement_decel, sizeof(movement_decel)); 156 | 157 | float turn_decel = config.GetFloat(_T("TurnDeceleration"), 50.0f); 158 | memcpy(nav_block_dst+0x24, &turn_decel, sizeof(turn_decel)); 159 | 160 | UINT32 turn_use_velocity = config.GetInt(_T("TurnUseVelocity"), FALSE); 161 | memcpy(nav_block_dst+0x2C, &turn_use_velocity, sizeof(turn_use_velocity)); 162 | 163 | SearchReplacePattern(dllBase, nav_block_src, nav_block_dst, nav_block_sz); 164 | } 165 | 166 | // Model Quality 167 | std::string model_quality = config.GetString("ModelQuality"); 168 | float mq_val = 3.6f; 169 | if (model_quality == "Infinite") { 170 | mq_val = 999999.0f; 171 | } else if (model_quality == "High") { 172 | mq_val = 5.0f; 173 | } else if (model_quality == "Medium") { 174 | mq_val = 3.6f; 175 | } else if (model_quality == "Low") { 176 | mq_val = 0.0f; 177 | } 178 | const char *mq_pattern = "\x00\x00\x80\x40\x66\x66\x66\x40"; 179 | char mq_replace[8]; 180 | memcpy(mq_replace, mq_pattern, 8); 181 | memcpy(mq_replace+4, &mq_val, sizeof(mq_val)); 182 | SearchReplacePattern(dllBase, mq_pattern, mq_replace, 8); 183 | 184 | // Transition Animation 185 | LPCVOID start_transition_offset = SearchPattern(dllBase, "\x89\x46\x2C\x8A\x44\x24\x14\x32\xC1\x24\x01\x32\xC1", 13); 186 | 187 | MxResult (MxTransitionManager::* pFunc)(TransitionType, int, byte, bool) = &MxTransitionManager::InterceptStartTransition; 188 | OverwriteAllCalls(dllBase, (char*)start_transition_offset - 40, (void*&) pFunc); 189 | 190 | startTransitionOriginal = PointerToMemberFunction((char*)start_transition_offset - 40); 191 | 192 | 193 | // Field of view 194 | const char *fov_pattern = "\x00\x00\x00\x3F\x17\x6C\xC1\x16\x6C\xC1\x76\x3F"; 195 | char fov_replace[12]; 196 | float fov; 197 | memcpy(fov_replace, fov_pattern, 12); // Make editable copy of pattern 198 | memcpy(&fov, fov_replace, sizeof(fov)); // Get float from bytes 199 | fov *= 1.0f/config.GetFloat(_T("FOVMultiplier")); // Multiply FOV 200 | memcpy(fov_replace, &fov, sizeof(fov)); // Store back into bytes 201 | SearchReplacePattern(dllBase, fov_pattern, fov_replace, 12); 202 | 203 | // FPS Cap 204 | std::string fps_behavior = config.GetString(_T("FPSLimit")); 205 | if (fps_behavior != "Default") { 206 | UINT32 frame_delta; 207 | 208 | if (fps_behavior == "Limited") { 209 | frame_delta = 1000.0f / config.GetFloat(_T("CustomFPS")); 210 | } else { 211 | frame_delta = 0; 212 | } 213 | 214 | WriteMemory((char*)exeBase+0x10B4, &frame_delta, sizeof(UINT32)); 215 | } 216 | 217 | // Window size hack 218 | /*SearchReplacePattern(exeBase, 219 | "\x80\x02\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00", 220 | "\x40\x01\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00", 24);*/ 221 | 222 | // Buffer overflow fix 223 | LPVOID fread_offset = SearchPattern(dllBase, "\x24\x10\x6A\x01\x50\x51", 6); 224 | freadOriginal = (freadFunction)OverwriteCall((char*)fread_offset + 6, (LPVOID)InterceptFread); 225 | 226 | return 0; 227 | } 228 | 229 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 230 | { 231 | switch (ul_reason_for_call) { 232 | case DLL_PROCESS_ATTACH: 233 | // Allocate console 234 | AllocConsole(); 235 | 236 | // Direct stdin/stderr/stdout to console 237 | _tfreopen(TEXT("CONIN$"), TEXT("r"), stdin); 238 | _tfreopen(TEXT("CONOUT$"), TEXT("w"), stderr); 239 | _tfreopen(TEXT("CONOUT$"), TEXT("w"), stdout); 240 | 241 | // Print success line 242 | printf("Injected successfully\n"); 243 | 244 | Patch(); 245 | break; 246 | } 247 | 248 | return TRUE; 249 | } 250 | -------------------------------------------------------------------------------- /lib/hooks.h: -------------------------------------------------------------------------------- 1 | #ifndef HOOKS_H 2 | #define HOOKS_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void InterceptOutputDebugStringA(LPCSTR s); 13 | 14 | HWND WINAPI InterceptCreateWindowExA( 15 | DWORD dwExStyle, 16 | LPCSTR lpClassName, 17 | LPCSTR lpWindowName, 18 | DWORD dwStyle, 19 | int X, 20 | int Y, 21 | int nWidth, 22 | int nHeight, 23 | HWND hWndParent, 24 | HMENU hMenu, 25 | HINSTANCE hInstance, 26 | LPVOID lpParam 27 | ); 28 | 29 | 30 | 31 | LONG 32 | APIENTRY 33 | InterceptRegQueryValueExA ( 34 | HKEY hKey, 35 | LPCSTR lpValueName, 36 | LPDWORD lpReserved, 37 | LPDWORD lpType, 38 | LPBYTE lpData, 39 | LPDWORD lpcbData 40 | ); 41 | 42 | ATOM WINAPI InterceptRegisterClassA(const WNDCLASSA *c); 43 | 44 | HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName); 45 | 46 | typedef HRESULT (WINAPI *ddCreateFunction)(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUnknown *pUnkOuterS); 47 | extern ddCreateFunction ddCreateOriginal; 48 | HRESULT WINAPI InterceptDirectDrawCreate(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUnknown *pUnkOuter); 49 | 50 | HRESULT WINAPI InterceptSurfaceGetDesc(LPDIRECTDRAWSURFACE lpDDSurface, LPDDSURFACEDESC lpDDSurfaceDesc); 51 | 52 | VOID WINAPI InterceptSleep(DWORD dwMilliseconds); 53 | 54 | typedef HRESULT (WINAPI *d3drmCreateFunction)(LPDIRECT3DRM FAR *lplpDirect3DRM); 55 | extern d3drmCreateFunction d3drmCreateOriginal; 56 | HRESULT WINAPI InterceptDirect3DRMCreate(LPDIRECT3DRM FAR *lplpDirect3DRM); 57 | 58 | typedef HRESULT (WINAPI *dsCreateFunction)(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter ); 59 | extern dsCreateFunction dsCreateOriginal; 60 | HRESULT WINAPI InterceptDirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter ); 61 | 62 | SHORT WINAPI InterceptGetAsyncKeyState(int vKey); 63 | 64 | typedef HRESULT (WINAPI *dinputCreateFunction)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter); 65 | extern dinputCreateFunction dinputCreateOriginal; 66 | HRESULT WINAPI InterceptDirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter); 67 | 68 | typedef _CRTIMP size_t (__cdecl *freadFunction)(void *buffer, size_t size, size_t count, FILE *stream); 69 | extern freadFunction freadOriginal; 70 | _CRTIMP size_t __cdecl InterceptFread(void *buffer, size_t size, size_t count, FILE *stream); 71 | 72 | enum MxResult 73 | { 74 | SUCCESS = 0, 75 | FAILURE = 0xFFFFFFFF 76 | }; 77 | 78 | enum TransitionType 79 | { 80 | NOT_TRANSITIONING = 0, 81 | NO_ANIMATION = 1, 82 | DISSOLVE = 2, 83 | MOSAIC = 3, 84 | WIPE_DOWN = 4, 85 | WINDOW = 5, 86 | BROKEN = 6 87 | }; 88 | 89 | class MxTransitionManager 90 | { 91 | public: 92 | MxResult InterceptStartTransition(TransitionType animationType, int speed, byte unk, bool playMusicInTransition); 93 | }; 94 | 95 | typedef MxResult (MxTransitionManager::* startTransitionFunction)(TransitionType, int, byte, bool); 96 | extern startTransitionFunction startTransitionOriginal; 97 | 98 | #endif // HOOKS_H 99 | -------------------------------------------------------------------------------- /lib/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include 4 | 5 | BOOL WriteMemory(LPVOID destination, LPVOID source, size_t length, LPVOID oldData) 6 | { 7 | DWORD oldProtec; 8 | 9 | if (VirtualProtect(destination, length, PAGE_EXECUTE_READWRITE, &oldProtec)) { 10 | // Read data out if requested 11 | if (oldData) { 12 | memcpy(oldData, destination, length); 13 | } 14 | 15 | // Write data if provided 16 | if (source) { 17 | memcpy(destination, source, length); 18 | } 19 | 20 | // Restore original protection 21 | VirtualProtect(destination, length, oldProtec, &oldProtec); 22 | 23 | return TRUE; 24 | } else { 25 | return FALSE; 26 | } 27 | } 28 | 29 | SIZE_T SearchReplacePattern(LPVOID imageBase, LPCVOID search, LPCVOID replace, SIZE_T count, BOOL only_once) 30 | { 31 | SIZE_T instances = 0; 32 | 33 | HANDLE process = GetCurrentProcess(); 34 | 35 | MEMORY_BASIC_INFORMATION mbi = {0}; 36 | 37 | // Loop through memory pages 38 | UINT_PTR addr = (UINT_PTR)imageBase; 39 | while ((!instances || !only_once) && VirtualQueryEx(process, (LPVOID)addr, &mbi, sizeof(mbi)) && mbi.AllocationBase == imageBase) { 40 | if (mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS) { 41 | DWORD oldProtec; 42 | 43 | // Try to gain access to this memory page 44 | if (VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &oldProtec)) { 45 | // Loop through every byte to find the pattern 46 | SIZE_T maxOffset = mbi.RegionSize - count; 47 | for (SIZE_T i=0; ie_lfanew); 79 | 80 | // Retrieve imports directory 81 | IMAGE_DATA_DIRECTORY importsDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 82 | 83 | // Retrieve import descriptor 84 | PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((UINT_PTR)imageBase + importsDirectory.VirtualAddress); 85 | 86 | while (importDescriptor->Name != NULL) { 87 | LPCSTR libraryName = (LPCSTR)importDescriptor->Name + (UINT_PTR)imageBase; 88 | HMODULE library = LoadLibraryA(libraryName); 89 | 90 | if (library) { 91 | PIMAGE_THUNK_DATA originalFirstThunk = (PIMAGE_THUNK_DATA)((UINT_PTR)imageBase + importDescriptor->OriginalFirstThunk); 92 | PIMAGE_THUNK_DATA firstThunk = (PIMAGE_THUNK_DATA)((UINT_PTR)imageBase + importDescriptor->FirstThunk); 93 | 94 | while (originalFirstThunk->u1.AddressOfData != NULL) { 95 | PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((UINT_PTR)imageBase + (UINT_PTR)originalFirstThunk->u1.AddressOfData); 96 | 97 | if (!strcmp((const char*)functionName->Name, overrideFunction)) { 98 | // Write to memory 99 | LPVOID originalFunction; 100 | WriteMemory(&firstThunk->u1.Function, &override, sizeof(LPVOID), &originalFunction); 101 | 102 | // Return original function and end loop here 103 | printf("Hooked %s\n", overrideFunction); 104 | return originalFunction; 105 | } 106 | ++originalFirstThunk; 107 | ++firstThunk; 108 | } 109 | } 110 | 111 | importDescriptor++; 112 | } 113 | 114 | return NULL; 115 | } 116 | 117 | LPVOID OverwriteVirtualTable(LPVOID object, SIZE_T methodIndex, LPVOID overrideFunction) 118 | { 119 | LPVOID *vtable = ((LPVOID**)(object))[0]; 120 | LPVOID &functionAddress = vtable[methodIndex]; 121 | LPVOID originalFunction = NULL; 122 | 123 | WriteMemory(&functionAddress, overrideFunction ? &overrideFunction : NULL, sizeof(LPVOID), &originalFunction); 124 | 125 | return originalFunction; 126 | } 127 | 128 | LPVOID OverwriteCall(LPVOID destination, LPVOID localCall) 129 | { 130 | char originalFunction[5]; 131 | char callInst[5]; 132 | 133 | callInst[0] = '\xE8'; 134 | 135 | *(DWORD*)(&callInst[1]) = (DWORD)localCall - ((DWORD)destination + 5); 136 | 137 | if (!WriteMemory(destination, callInst, 5, originalFunction)) { 138 | return NULL; 139 | } 140 | 141 | return (LPVOID)((*(DWORD *)(originalFunction + 1)) + ((DWORD)destination + 5)); 142 | } 143 | 144 | int OverwriteAllCalls(LPVOID imageBase, LPCVOID from, LPCVOID to) 145 | { 146 | int count = 0; 147 | 148 | HANDLE process = GetCurrentProcess(); 149 | MEMORY_BASIC_INFORMATION mbi = {0}; 150 | 151 | DWORD fromAddr = (DWORD) from; 152 | DWORD toAddr = (DWORD) to; 153 | 154 | // Loop through memory pages 155 | UINT_PTR addr = (UINT_PTR)imageBase; 156 | while (VirtualQueryEx(process, (LPVOID)addr, &mbi, sizeof(mbi)) && mbi.AllocationBase == imageBase) { 157 | if (mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS) { 158 | DWORD oldProtec; 159 | 160 | // Try to gain access to this memory page 161 | if (VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &oldProtec)) { 162 | // Loop through every byte to find x86 calls 163 | SIZE_T maxOffset = mbi.RegionSize - count; 164 | for (SIZE_T i=0; i 5 | 6 | BOOL WriteMemory(LPVOID destination, LPVOID source, size_t length, LPVOID oldData = NULL); 7 | 8 | LPVOID OverwriteCall(LPVOID destination, LPVOID localCall); 9 | 10 | int OverwriteAllCalls(LPVOID imageBase, LPCVOID from, LPCVOID to); 11 | 12 | LPVOID SearchPattern(LPVOID imageBase, LPCVOID search, SIZE_T count); 13 | 14 | SIZE_T SearchReplacePattern(LPVOID imageBase, LPCVOID search, LPCVOID replace, SIZE_T count, BOOL only_once = FALSE); 15 | 16 | LPVOID OverwriteImport(LPVOID imageBase, LPCSTR overrideFunction, LPVOID override); 17 | 18 | template 19 | T PointerToMemberFunction(LPVOID ptr) 20 | { 21 | union U { 22 | LPVOID in; 23 | T out; 24 | }; 25 | 26 | U u; 27 | u.in = ptr; 28 | return u.out; 29 | } 30 | 31 | LPVOID OverwriteVirtualTable(LPVOID object, SIZE_T methodIndex, LPVOID overrideFunction); 32 | 33 | #endif // UTIL_H 34 | -------------------------------------------------------------------------------- /pkg/fade.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isledecomp/LEGOIslandRebuilder/6e1c7cd263330eb466aed970f469a704ef3aad4d/pkg/fade.gif -------------------------------------------------------------------------------- /res/mama.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isledecomp/LEGOIslandRebuilder/6e1c7cd263330eb466aed970f469a704ef3aad4d/res/mama.ico -------------------------------------------------------------------------------- /res/res.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LEGO Island modding tool and launcher. 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | true 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /res/res.rc: -------------------------------------------------------------------------------- 1 | #include "resource.h" 2 | 3 | // Application icon 4 | IDI_ICON1 ICON DISCARDABLE "mama.ico" 5 | 6 | // Manifest to enable visual styles 7 | 1 RC_MANIFEST "res.manifest" 8 | 9 | // Include worker DLL in executable for better portability 10 | WORKER_DLL RCDATA "../Rebld/Release/rebld.dll" 11 | -------------------------------------------------------------------------------- /res/resource.h: -------------------------------------------------------------------------------- 1 | #ifndef RESOURCE_H 2 | #define RESOURCE_H 3 | 4 | #define RC_MANIFEST 24 5 | 6 | #define WORKER_DLL 300 7 | 8 | #endif // RESOURCE_H 9 | -------------------------------------------------------------------------------- /src/app.cpp: -------------------------------------------------------------------------------- 1 | #include "app.h" 2 | 3 | #include "launcher.h" 4 | #include "window.h" 5 | 6 | CRebuilderApp g_AppInstance; 7 | 8 | CRebuilderApp::CRebuilderApp() 9 | { 10 | } 11 | 12 | BOOL CRebuilderApp::InitInstance() 13 | { 14 | bool run_only = false; 15 | 16 | char *tokens = strtok(m_lpCmdLine, " "); 17 | while (tokens) { 18 | if (!strcmp(tokens, "--run") || !strcmp(tokens, "-r")) { 19 | run_only = true; 20 | } else if (!strcmp(tokens, "--help") || !strcmp(tokens, "-h")) { 21 | ::MessageBoxA(0, "LEGO Island Rebuilder\n" 22 | "\n" 23 | "Supported arguments:\n" 24 | "\n" 25 | "--help, -h\n" 26 | "Displays this help page.\n" 27 | "\n" 28 | "--run, -r\n" 29 | "Run LEGO Island immediately with the last used configuration.", 30 | "Command Line Argument Help", 0); 31 | return false; 32 | } 33 | 34 | tokens = strtok(NULL, " "); 35 | } 36 | 37 | if (!run_only) { 38 | m_pMainWnd = new CRebuilderWindow(); 39 | m_pMainWnd->ShowWindow(m_nCmdShow); 40 | m_pMainWnd->UpdateWindow(); 41 | 42 | return TRUE; 43 | } else { 44 | Launcher::Launch(NULL); 45 | return FALSE; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/app.h: -------------------------------------------------------------------------------- 1 | #ifndef REBUILDERAPP_H 2 | #define REBUILDERAPP_H 3 | 4 | #include 5 | 6 | class CRebuilderApp : public CWinApp 7 | { 8 | public: 9 | CRebuilderApp(); 10 | 11 | virtual BOOL InitInstance(); 12 | 13 | }; 14 | 15 | #endif // REBUILDERAPP_H 16 | -------------------------------------------------------------------------------- /src/clinkstatic.cpp: -------------------------------------------------------------------------------- 1 | #include "clinkstatic.h" 2 | 3 | #define super CStatic 4 | 5 | #ifndef IDC_HAND 6 | #define IDC_HAND MAKEINTRESOURCE(32649) 7 | #endif 8 | 9 | CLinkStatic::CLinkStatic() 10 | { 11 | // We want a pointing hand cursor and different Windows versions provide this differently 12 | OSVERSIONINFO info; 13 | ZeroMemory(&info, sizeof(info)); 14 | info.dwOSVersionInfoSize = sizeof(info); 15 | GetVersionEx(&info); 16 | 17 | if (info.dwMajorVersion <= 4) { 18 | // Windows 9x didn't have a pointing hand cursor so we'll pull it from winhlp32 19 | CString strWndDir; 20 | GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH); 21 | strWndDir.ReleaseBuffer(); 22 | 23 | strWndDir += _T("\\winhlp32.exe"); 24 | HMODULE hModule = LoadLibrary(strWndDir); 25 | if (hModule) { 26 | HCURSOR hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106)); 27 | if (hHandCursor) 28 | m_hPointHand = CopyCursor(hHandCursor); 29 | } 30 | FreeLibrary(hModule); 31 | } else { 32 | // With NT5+, we can use IDC_HAND 33 | m_hPointHand = LoadCursor(NULL, IDC_HAND); 34 | } 35 | } 36 | 37 | BOOL CLinkStatic::OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message) 38 | { 39 | ::SetCursor(m_hPointHand); 40 | return TRUE; 41 | } 42 | 43 | HBRUSH CLinkStatic::CtlColor(CDC *pDC, UINT nCtlColor) 44 | { 45 | pDC->SetTextColor(RGB(0, 0, 240)); 46 | pDC->SetBkMode(TRANSPARENT); 47 | 48 | return (HBRUSH) GetStockObject(NULL_BRUSH); 49 | } 50 | 51 | BOOL CLinkStatic::OnEraseBkgnd(CDC*) 52 | { 53 | return TRUE; 54 | } 55 | 56 | BEGIN_MESSAGE_MAP(CLinkStatic, super) 57 | ON_WM_SETCURSOR() 58 | ON_WM_CTLCOLOR_REFLECT() 59 | ON_WM_ERASEBKGND() 60 | END_MESSAGE_MAP() 61 | -------------------------------------------------------------------------------- /src/clinkstatic.h: -------------------------------------------------------------------------------- 1 | #ifndef CLINKSTATIC_H 2 | #define CLINKSTATIC_H 3 | 4 | #include 5 | 6 | class CLinkStatic : public CStatic 7 | { 8 | public: 9 | CLinkStatic(); 10 | 11 | afx_msg BOOL OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message); 12 | 13 | afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor); 14 | 15 | afx_msg BOOL OnEraseBkgnd(CDC*); 16 | 17 | private: 18 | HCURSOR m_hPointHand; 19 | 20 | DECLARE_MESSAGE_MAP() 21 | 22 | }; 23 | 24 | #endif // CLINKSTATIC_H 25 | -------------------------------------------------------------------------------- /src/launcher.cpp: -------------------------------------------------------------------------------- 1 | #include "launcher.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../cmn/path.h" 8 | #include "../res/resource.h" 9 | 10 | typedef DWORD (WINAPI *GetLongPathName_t)(LPCSTR lpszShortPath, LPSTR lpszLongPath, DWORD cchBuffer); 11 | HANDLE Launcher::Launch(HWND parent) 12 | { 13 | // Find the installation 14 | TCHAR filename[MAX_PATH]; 15 | if (!FindInstallation(parent, filename)) { 16 | // Don't show error message because presumably the user cancelled out of looking for ISLE 17 | return NULL; 18 | } 19 | 20 | // Set compatibility flags 21 | OSVERSIONINFO info; 22 | ZeroMemory(&info, sizeof(OSVERSIONINFO)); 23 | info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 24 | GetVersionEx(&info); 25 | 26 | if (info.dwMajorVersion >= 5) { 27 | HKEY hKey; 28 | std::string compat = "~ HIGHDPIAWARE"; 29 | 30 | TCHAR configPath[MAX_PATH]; 31 | GetConfigFilename(configPath); 32 | 33 | // If windowed, force a bit depth 34 | if (!GetPrivateProfileInt(appName, "FullScreen", true, configPath)) { 35 | if (info.dwMajorVersion >= 8) { 36 | compat += " 16BITCOLOR"; 37 | } else { 38 | compat += " 256COLOR"; 39 | } 40 | compat += " DWM8And16BitMitigation"; 41 | } 42 | 43 | if (RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) { 44 | // Often we seem to get an 8.3 path which is not valid here, so resolve the full path now 45 | TCHAR full_path[MAX_PATH]; 46 | GetLongPathName_t getLongPathName = (GetLongPathName_t) GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "GetLongPathNameA"); 47 | getLongPathName(filename, full_path, MAX_PATH); 48 | 49 | LONG ret = RegSetValueEx(hKey, full_path, 0, REG_SZ, (const BYTE *) &compat[0], compat.size()+1); 50 | if (ret != ERROR_SUCCESS) { 51 | char buf[100]; 52 | sprintf(buf, "Failed to set compatibility flags: 0x%x. This may cause issues on newer versions of Windows.", ret); 53 | MessageBox(parent, buf, 0, 0); 54 | } 55 | 56 | RegCloseKey(hKey); 57 | } 58 | } 59 | 60 | 61 | // Extract REBLD.DLL which contains our patches 62 | TCHAR libraryFile[MAX_PATH]; 63 | if (!ExtractLibrary(libraryFile, MAX_PATH)) { 64 | MessageBox(parent, "Failed to extract to temp", NULL, 0); 65 | return NULL; 66 | } 67 | 68 | // Get ISLE directory only 69 | TCHAR srcDir[MAX_PATH]; 70 | _tcscpy(srcDir, filename); 71 | PathRemoveFileSpec(srcDir); 72 | 73 | // Detect incompatible versions of ISLE 74 | HANDLE hIsle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 75 | DWORD dwSize = GetFileSize(hIsle, NULL); 76 | if (dwSize > 100000) { 77 | char buf[200]; 78 | sprintf(buf, "ISLE.EXE is abnormally large (%d KB). This executable might be protected with SecuROM, " 79 | "which could cause unexpected behavior with LEGO Island Rebuilder. " 80 | "It is recommended to replace ISLE.EXE with an untampered version (usually around 85 KB) " 81 | "to use Rebuilder with this installation of LEGO Island.\n\nClick OK if you would like to continue anyway.", dwSize / 1024); 82 | 83 | int result = MessageBox(parent, buf, "Warning", MB_ICONWARNING | MB_OKCANCEL); 84 | if (result == IDCANCEL) { 85 | return NULL; 86 | } 87 | } 88 | 89 | CloseHandle(hIsle); 90 | 91 | // Start launching our copy 92 | PROCESS_INFORMATION pi; 93 | if (!TryCreateProcess(parent, filename, srcDir, TRUE, &pi)) { 94 | return NULL; 95 | } 96 | 97 | UINT_PTR inject_addr = 0x0040843A; 98 | UINT_PTR old_addr; 99 | ReadProcessMemory(pi.hProcess, (LPVOID) inject_addr, &old_addr, sizeof(UINT_PTR), NULL); 100 | old_addr += inject_addr + 4; 101 | 102 | // Set up x86 code template 103 | char *inject_func = "\x68\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xE9\xBA\xBA\xBA\xBA"; 104 | size_t inject_func_sz = 15; 105 | 106 | // Write DLL address 107 | UINT_PTR addr = (UINT_PTR) 0x0040E5D6; 108 | UINT_PTR string_addr = addr + inject_func_sz; 109 | int dllPathLength = strlen(libraryFile) + 1; 110 | WriteProcessMemory(pi.hProcess, (LPVOID) string_addr, libraryFile, dllPathLength, NULL); 111 | 112 | // Fill in addresses in code template 113 | memcpy(inject_func + 1, &string_addr, sizeof(string_addr)); 114 | UINT_PTR loadLibrary = (UINT_PTR) GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "LoadLibraryA"); 115 | loadLibrary -= addr + 10; 116 | memcpy(inject_func + 6, &loadLibrary, sizeof(loadLibrary)); 117 | old_addr -= addr + 15; 118 | memcpy(inject_func + 11, &old_addr, sizeof(old_addr)); 119 | 120 | // Write code 121 | WriteProcessMemory(pi.hProcess, (LPVOID) addr, inject_func, inject_func_sz, NULL); 122 | 123 | // Replace function call 124 | addr -= (UINT_PTR)(inject_addr) + 4; 125 | WriteProcessMemory(pi.hProcess, (LPVOID) inject_addr, &addr, sizeof(addr), NULL); 126 | 127 | // Resume process thread 128 | ResumeThread(pi.hThread); 129 | 130 | return pi.hProcess; 131 | } 132 | 133 | BOOL Launcher::FindInstallation(HWND parent, LPTSTR str) 134 | { 135 | // Search for LEGO Island disk path 136 | DWORD value_sz; 137 | 138 | BOOL success = TRUE; 139 | 140 | // Start with empty string 141 | str[0] = 0; 142 | 143 | // On install, LEGO Island records its installation directory in the registry 144 | HKEY hKey; 145 | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Mindscape\\LEGO Island", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { 146 | LONG ret = RegQueryValueEx(hKey, "diskpath", NULL, NULL, NULL, &value_sz); 147 | if (ret == ERROR_SUCCESS) { 148 | // Get value from registry 149 | RegQueryValueEx(hKey, "diskpath", NULL, NULL, (BYTE*)str, &value_sz); 150 | 151 | // Append ISLE.EXE to diskpath 152 | _tcscat(str, "\\ISLE.EXE"); 153 | } 154 | 155 | RegCloseKey(hKey); 156 | } 157 | 158 | // Validate diskpath, either we couldn't find the registry entry or it was incorrect somehow 159 | while (!_tcslen(str) || !PathFileExists(str)) { 160 | // Ask user where LEGO Island is installed 161 | OPENFILENAME fn; 162 | ZeroMemory(&fn, sizeof(fn)); 163 | fn.hwndOwner = parent; 164 | fn.lStructSize = sizeof(fn); 165 | fn.lpstrFile = str; 166 | fn.lpstrFile[0] = '\0'; 167 | fn.nMaxFile = MAX_PATH; 168 | fn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 169 | fn.lpstrTitle = "Where is LEGO Island installed?"; 170 | fn.lpstrFilter = "ISLE.EXE\0ISLE.EXE\0"; 171 | 172 | if (!GetOpenFileName(&fn)) { 173 | // If they cancelled the dialog, break out of the loop 174 | success = FALSE; 175 | break; 176 | } 177 | } 178 | 179 | return success; 180 | } 181 | 182 | BOOL Launcher::ExtractLibrary(LPTSTR str, SIZE_T len) 183 | { 184 | // Find temporary location to store DLL 185 | if (!GetTempPath(len, str)) { 186 | return FALSE; 187 | } 188 | 189 | _tcscat(str, "REBLD.DLL"); 190 | 191 | // Open file 192 | HANDLE file = CreateFile(str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 193 | if (!file) { 194 | return FALSE; 195 | } 196 | 197 | // Extract DLL which should have been compiled in as a resource 198 | HRSRC res = FindResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(WORKER_DLL), RT_RCDATA); 199 | if (!res) { 200 | return FALSE; 201 | } 202 | 203 | HGLOBAL res_resource = LoadResource(NULL, res); 204 | if (!res_resource) { 205 | return FALSE; 206 | } 207 | 208 | LPVOID res_data = LockResource(res_resource); 209 | DWORD res_sz = SizeofResource(NULL, res); 210 | 211 | DWORD writtenBytes; 212 | BOOL success = WriteFile(file, res_data, res_sz, &writtenBytes, NULL); 213 | 214 | UnlockResource(res_resource); 215 | 216 | FreeResource(res_resource); 217 | 218 | CloseHandle(file); 219 | 220 | return success; 221 | } 222 | 223 | BOOL Launcher::CopyIsleToTemp(LPCTSTR src, LPTSTR dst) 224 | { 225 | BOOL success = FALSE; 226 | 227 | TCHAR tempDir[MAX_PATH]; 228 | if (GetTempPath(MAX_PATH, tempDir)) { 229 | _tcscpy(dst, tempDir); 230 | _tcscat(dst, "ISLE.EXE"); 231 | if (CopyFile(src, dst, FALSE)) { 232 | // Force our copy to load our DLL 233 | success = TRUE; 234 | } 235 | } 236 | 237 | return success; 238 | } 239 | 240 | BOOL Launcher::ReplacePatternInFile(HANDLE file, const char *pattern, const char *replace, LONG sz) 241 | { 242 | BOOL success = FALSE; 243 | 244 | SetFilePointer(file, 0, 0, FILE_BEGIN); 245 | 246 | char *data = new char[sz]; 247 | 248 | // Find pattern in the file 249 | DWORD nbBytesRead; 250 | do { 251 | ReadFile(file, data, sz, &nbBytesRead, NULL); 252 | SetFilePointer(file, -sz + 1, 0, FILE_CURRENT); 253 | } while ((LONG)nbBytesRead == sz && memcmp(data, pattern, sz)); 254 | 255 | if ((LONG)nbBytesRead == sz) { 256 | // Must have found pattern 257 | SetFilePointer(file, -1, 0, FILE_CURRENT); 258 | 259 | // Overwrite with replace 260 | DWORD nbBytesWritten; // We don't use this value, but Windows 95 will fail without it 261 | if (WriteFile(file, replace, sz, &nbBytesWritten, NULL)) { 262 | success = TRUE; 263 | } else { 264 | char buf[200]; 265 | sprintf(buf, "Failed to write to file with error: %lx", GetLastError()); 266 | MessageBoxA(0, buf, 0, 0); 267 | } 268 | } 269 | 270 | delete [] data; 271 | 272 | return success; 273 | } 274 | 275 | BOOL Launcher::TryCreateProcess(HWND parent, LPSTR filename, LPCSTR working_dir, BOOL suspended, PROCESS_INFORMATION *pi) 276 | { 277 | STARTUPINFO si; 278 | 279 | ZeroMemory(pi, sizeof(PROCESS_INFORMATION)); 280 | ZeroMemory(&si, sizeof(si)); 281 | 282 | if (!CreateProcess(NULL, filename, NULL, NULL, FALSE, suspended ? CREATE_SUSPENDED : 0, NULL, working_dir, &si, pi)) { 283 | TCHAR err[2048]; 284 | _stprintf(err, "Failed to create process with error 0x%lx", GetLastError()); 285 | MessageBox(parent, err, NULL, 0); 286 | return FALSE; 287 | } 288 | 289 | return TRUE; 290 | } 291 | -------------------------------------------------------------------------------- /src/launcher.h: -------------------------------------------------------------------------------- 1 | #ifndef LAUNCHER_H 2 | #define LAUNCHER_H 3 | 4 | #include 5 | 6 | class Launcher 7 | { 8 | public: 9 | Launcher(); 10 | 11 | static HANDLE Launch(HWND parent); 12 | 13 | private: 14 | static BOOL FindInstallation(HWND parent, LPTSTR isle_diskpath); 15 | 16 | static BOOL ExtractLibrary(LPTSTR str, SIZE_T len); 17 | 18 | static BOOL CopyIsleToTemp(LPCTSTR src, LPTSTR dst); 19 | 20 | static BOOL ReplacePatternInFile(HANDLE file, const char *pattern, const char *replace, LONG sz); 21 | 22 | static BOOL TryCreateProcess(HWND parent, LPSTR filename, LPCSTR working_dir, BOOL suspended, PROCESS_INFORMATION *pi); 23 | 24 | }; 25 | 26 | #endif // LAUNCHER_H 27 | -------------------------------------------------------------------------------- /src/patchgrid.cpp: -------------------------------------------------------------------------------- 1 | #include "patchgrid.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../cmn/path.h" 9 | 10 | HRESULT CALLBACK ReceiveD3DDevice(GUID *lpGuid, LPSTR szDeviceDescription, LPSTR szDeviceName, LPD3DDEVICEDESC pD3DDD1, LPD3DDEVICEDESC pD3DDD2, LPVOID lpContext) 11 | { 12 | char buf[256]; 13 | 14 | // NOTE: Not really sure where the "0" comes from. I'm guessing it's the index of the ddraw 15 | // device, but I don't have any hardware that has a second one (I only have "Primary 16 | // Display Driver") so I can't experiment. 17 | sprintf(buf, "0 0x%lx 0x%x%x 0x%lx 0x%lx", lpGuid->Data1, lpGuid->Data3, lpGuid->Data2, 18 | *((DWORD*)&lpGuid->Data4), *((DWORD*)&lpGuid->Data4[4])); 19 | 20 | PatchGrid *p = (PatchGrid*)lpContext; 21 | p->AddD3DDevice(szDeviceName, buf); 22 | 23 | return DDENUMRET_OK; 24 | } 25 | 26 | BOOL CALLBACK ReceiveDDrawDevice(GUID *lpGuid, LPSTR szDesc, LPSTR szName, LPVOID lpContext) 27 | { 28 | LPDIRECTDRAW dd; 29 | LPDIRECT3D2 d3d2; 30 | 31 | DirectDrawCreate(lpGuid, &dd, NULL); 32 | 33 | dd->QueryInterface(IID_IDirect3D2, (void**)&d3d2); 34 | d3d2->EnumDevices(ReceiveD3DDevice, lpContext); 35 | 36 | d3d2->Release(); 37 | dd->Release(); 38 | 39 | return DDENUMRET_OK; 40 | } 41 | 42 | PatchGrid::PatchGrid() 43 | { 44 | SetBoldModified(true); 45 | 46 | // General section 47 | HSECTION sectionGeneral = AddSection("General"); 48 | 49 | AddPatch("DebugToggle", 50 | "Enables the in-game debug mode automatically without the need to type OGEL.", 51 | AddBoolItem(sectionGeneral, "Debug Mode", false)); 52 | 53 | AddPatch("MultipleInstances", 54 | "By default, LEGO Island will allow only one instance of itself to run. " 55 | "This patch allows infinite instances of LEGO Island to run.", 56 | AddBoolItem(sectionGeneral, "Allow Multiple Instances", false)); 57 | 58 | AddPatch("SpeedUpStartUp", 59 | "By default, LEGO Island waits 200 frames to ensure everything is initialized before starting. " 60 | "That interval can be skipped without consequence in many cases.", 61 | AddBoolItem(sectionGeneral, "Speed Up Startup", false)); 62 | 63 | AddPatch("StayActiveWhenDefocused", 64 | "By default, LEGO Island pauses when it's not the active window. " 65 | "This patch prevents that behavior.", 66 | AddBoolItem(sectionGeneral, "Stay Active When Defocused", false)); 67 | 68 | AddPatch("RedirectSaveData", 69 | "By default LEGO Island saves its game data in its Program Files folder. In newer versions of " 70 | "Windows, this folder is considered privileged access, necessitating running LEGO Island as administrator " 71 | "to save here. This patch sets LEGO Island's save location to %APPDATA% instead, which is an accessible and " 72 | "standard location that most modern games and apps save to.", 73 | AddBoolItem(sectionGeneral, "Redirect Save Files to %APPDATA%", false)); 74 | 75 | AddPatch("DisableAutoFinishBuilding", 76 | "In LEGO Island v1.1, placing the last block when building will automatically end the building section. While convenient, " 77 | "this prevents players from making any further changes after placing the last brick. It also notably defies what Bill Ding says - you " 78 | "don't hit the triangle when you're finished building.\n\nThis patch restores the functionality in v1.0 where placing the last block " 79 | "will not automatically finish the build section.", 80 | AddBoolItem(sectionGeneral, "Disable Auto-Finish Building Section", false)); 81 | 82 | AddPatch("ExitCrashFix", 83 | "LEGO Island contains a bug that frequently crashes the game when trying " 84 | "to exit. This is particularly prevalent on newer versions of Windows and Wine. This " 85 | "patch will fix the crash and the associated animation glitches and audio buzzes.", 86 | AddBoolItem(sectionGeneral, "Exit Crash Fix", false)); 87 | 88 | // Controls section 89 | HSECTION sectionControls = AddSection("Controls"); 90 | 91 | AddPatch("UseWASD", 92 | "Enables the use of WASD keys for movement rather than the arrow keys. " 93 | "NOTE: When using Debug Mode, this patch will re-map the conflicting debug keys to the arrow keys.", 94 | AddBoolItem(sectionControls, "Use WASD", false)); 95 | AddPatch("UseJoystick", 96 | "Enables Joystick functionality.", 97 | AddBoolItem(sectionControls, "Use Joystick", false)); 98 | AddPatch("MouseDeadzone", 99 | "Sets the radius from the center of the screen where the mouse will do nothing (40 = default).", 100 | AddIntegerItem(sectionControls, "Mouse Deadzone", 40)); 101 | AddPatch("UnhookTurnSpeed", 102 | "LEGO Island contains a bug where the turning speed is influenced by the frame rate. Enable this to make the turn speed independent of the frame rate.", 103 | AddBoolItem(sectionControls, "Unhook Turning From Frame Rate", false)); 104 | AddPatch("TurnUseVelocity", 105 | "By default, LEGO Island ignores the turning acceleration/deceleration values. Set this to TRUE to utilize them (Default = FALSE)", 106 | AddBoolItem(sectionControls, "Enable Turning Velocity", false)); 107 | 108 | // Navigation section 109 | HSECTION sectionNavigation = AddSection("Navigation"); 110 | 111 | AddPatch("TurnMaxSpeed", 112 | "Set the maximum turning speed. (Default = 20.0)", 113 | AddDoubleItem(sectionNavigation, "Turning: Max Speed", 20.0)); 114 | AddPatch("TurnMaxAcceleration", 115 | "Set the speed at which turning accelerates (requires 'Turning: Enable Velocity') (Default = 30.0)", 116 | AddDoubleItem(sectionNavigation, "Turning: Max Acceleration", 30.0)); 117 | AddPatch("TurnMinAcceleration", 118 | "Set the speed at which turning accelerates (requires 'Turning: Enable Velocity') (Default = 15.0)", 119 | AddDoubleItem(sectionNavigation, "Turning: Min Acceleration", 15.0)); 120 | AddPatch("TurnDeceleration", 121 | "Set the speed at which turning decelerates (requires 'Turning: Enable Velocity') (Default = 50.0)", 122 | AddDoubleItem(sectionNavigation, "Turning: Deceleration", 50.0)); 123 | AddPatch("MovementMaxSpeed", 124 | "Set the movement maximum speed. (Default = 40.0)", 125 | AddDoubleItem(sectionNavigation, "Movement: Max Speed", 40.0)); 126 | AddPatch("MovementMaxAcceleration", 127 | "Set the movement acceleration speed (i.e. how long it takes to go from not moving to top speed) (Default = 15.0)", 128 | AddDoubleItem(sectionNavigation, "Movement: Max Acceleration", 15.0)); 129 | AddPatch("MovementMinAcceleration", 130 | "Set the movement acceleration speed (i.e. how long it takes to go from not moving to top speed) (Default = 4.0)", 131 | AddDoubleItem(sectionNavigation, "Movement: Min Acceleration", 4.0)); 132 | AddPatch("MovementDeceleration", 133 | "Set the movement deceleration speed (i.e. how long it takes to slow to a stop after releasing the controls). " 134 | "Increase this value to stop faster, decrease it to stop slower. " 135 | "Usually this is set to a very high value making deceleration almost instant. (Default = 50.0)", 136 | AddDoubleItem(sectionNavigation, "Movement: Deceleration", 50.0)); 137 | 138 | // Graphics Section 139 | HSECTION sectionGraphics = AddSection("Graphics"); 140 | 141 | DirectDrawEnumerateA(ReceiveDDrawDevice, this); 142 | m_d3dDeviceItem = AddComboItem(sectionGraphics, "Direct3D Device", m_d3dDeviceNames, 0); 143 | 144 | AddPatch("D3DDevice", 145 | "Set which Direct3D device to use with LEGO Island.", 146 | m_d3dDeviceItem); 147 | 148 | AddPatch("FullScreen", 149 | "Allows you to change modes without administrator privileges and registry editing. NOTE: Windowed mode is NOT compatible with \"Flip Video Memory Pages\".", 150 | AddBoolItem(sectionGraphics, "Run in Full Screen", true)); 151 | 152 | AddPatch("DrawCursor", 153 | "Renders a custom in-game cursor, rather than a standard Windows pointer.", 154 | AddBoolItem(sectionGraphics, "Draw Cursor", false)); 155 | 156 | AddPatch("FlipSurfaces", 157 | "", // FIXME: Write description for this 158 | AddBoolItem(sectionGraphics, "Flip Video Memory Pages", false)); 159 | 160 | AddPatch("BackBuffersInVRAM", 161 | "", // FIXME: Write description for this 162 | AddBoolItem(sectionGraphics, "Draw 3D to Video Memory", false)); 163 | 164 | vector fpsList; 165 | fpsList.push_back("Default"); 166 | fpsList.push_back("Uncapped"); 167 | fpsList.push_back("Limited"); 168 | AddPatch("FPSLimit", 169 | "Modify LEGO Island's frame rate cap", 170 | AddComboItem(sectionGraphics, "FPS Cap", fpsList, 0)); 171 | 172 | AddPatch("CustomFPS", 173 | "If 'FPS Cap' is set to 'Limited', this will be the frame rate used.", 174 | AddDoubleItem(sectionGraphics, "FPS Cap - Custom Limit", 24.0)); 175 | 176 | vector qualityList; 177 | qualityList.push_back("Infinite"); 178 | qualityList.push_back("High"); 179 | qualityList.push_back("Medium"); 180 | qualityList.push_back("Low"); 181 | AddPatch("ModelQuality", 182 | "Change LEGO Island's default model quality", 183 | AddComboItem(sectionGraphics, "Model Quality", qualityList, 2)); 184 | 185 | vector animationList; 186 | animationList.push_back("No Animation"); 187 | animationList.push_back("Dissolve"); 188 | animationList.push_back("Mosaic"); 189 | animationList.push_back("Wipe Down"); 190 | animationList.push_back("Window"); 191 | animationList.push_back("Random"); 192 | AddPatch("TransitionType", 193 | "Change LEGO Island's transition animation.", 194 | AddComboItem(sectionGraphics, "Transition Type", animationList, 2)); 195 | 196 | AddPatch("TransitionSpeed", 197 | "Sets the speed of LEGO Island's transition animations.\n\n(50 = default; lower = faster, higher = slower)", 198 | AddIntegerItem(sectionGraphics, "Transition Speed", 50)); 199 | 200 | AddPatch("FOVMultiplier", 201 | "Globally adjusts the field of view by a multiplier\n\n" 202 | "1.0 = Default (greater than 1.0 is zoomed in, less than 1.0 is zoomed out)", 203 | AddDoubleItem(sectionGraphics, "Field of View Adjustment", 1.0)); 204 | 205 | AddPatch("NativeSMK", 206 | "Very few of LEGO Island's movies are actually the same resolution as the game. This patch disables scaling of these movies, causing LEGO Island to play them at their native resolutions.", 207 | AddBoolItem(sectionGraphics, "Play Movies at Native Resolution", false)); 208 | 209 | // Audio section 210 | HSECTION sectionMusic = AddSection("Audio"); 211 | 212 | AddPatch("MusicToggle", 213 | "Turns in-game music on or off.", 214 | AddBoolItem(sectionMusic, "Play Music", true)); 215 | } 216 | 217 | template 218 | std::string toString(const T &value) 219 | { 220 | std::ostringstream oss; 221 | oss << value; 222 | return oss.str(); 223 | } 224 | 225 | void PatchGrid::LoadConfiguration(LPCTSTR filename) 226 | { 227 | for (std::map::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) { 228 | CItem *item = FindItem(it->second); 229 | 230 | std::string value; 231 | value.resize(1024); 232 | 233 | char buf[1024]; 234 | 235 | DWORD sz = GetPrivateProfileString(appName, it->first.c_str(), NULL, &value[0], value.size(), filename); 236 | 237 | // If this entry wasn't in the profile, skip it 238 | if (!sz) { 239 | continue; 240 | } 241 | 242 | value.resize(sz); 243 | 244 | // Convert value to string 245 | switch (item->m_type) { 246 | case IT_STRING: 247 | case IT_TEXT: 248 | case IT_FILE: 249 | case IT_FOLDER: 250 | case IT_COMBO: 251 | SetItemValue(it->second, value); 252 | break; 253 | case IT_BOOLEAN: 254 | SetItemValue(it->second, (bool)StrToIntA(value.c_str())); 255 | break; 256 | case IT_INTEGER: 257 | SetItemValue(it->second, StrToIntA(value.c_str())); 258 | break; 259 | case IT_DOUBLE: 260 | SetItemValue(it->second, atof(value.c_str())); 261 | break; 262 | case IT_COLOR: 263 | SetItemValue(it->second, (COLORREF) StrToIntA(value.c_str())); 264 | break; 265 | case IT_CUSTOM: 266 | case IT_DATE: 267 | case IT_DATETIME: 268 | case IT_FONT: 269 | { 270 | // Report inability to serialize 271 | TCHAR buf[200]; 272 | sprintf(buf, "Failed to serialize %s from string.", it->first.c_str()); 273 | MessageBox(buf); 274 | break; 275 | } 276 | } 277 | } 278 | } 279 | 280 | BOOL PatchGrid::SaveConfiguration(LPCTSTR filename) 281 | { 282 | for (std::map::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) { 283 | CItem *item = FindItem(it->second); 284 | 285 | std::string value; 286 | 287 | // Convert value to string 288 | switch (item->m_type) { 289 | case IT_STRING: 290 | case IT_TEXT: 291 | case IT_FILE: 292 | case IT_FOLDER: 293 | case IT_COMBO: 294 | GetItemValue(it->second, value); 295 | break; 296 | case IT_BOOLEAN: 297 | { 298 | bool b; 299 | GetItemValue(it->second, b); 300 | value = toString(b); 301 | break; 302 | } 303 | case IT_INTEGER: 304 | int i; 305 | GetItemValue(it->second, i); 306 | value = toString(i); 307 | break; 308 | case IT_DOUBLE: 309 | double d; 310 | GetItemValue(it->second, d); 311 | value = toString(d); 312 | break; 313 | case IT_COLOR: 314 | COLORREF c; 315 | GetItemValue(it->second, c); 316 | value = toString(c); 317 | break; 318 | case IT_CUSTOM: 319 | case IT_DATE: 320 | case IT_DATETIME: 321 | case IT_FONT: 322 | { 323 | // Report inability to serialize 324 | TCHAR buf[200]; 325 | sprintf(buf, "Failed to serialize %s to string.", it->first.c_str()); 326 | MessageBox(buf); 327 | break; 328 | } 329 | } 330 | 331 | if (!WritePrivateProfileString(appName, it->first.c_str(), value.c_str(), filename)) { 332 | return FALSE; 333 | } 334 | 335 | if (it->second == m_d3dDeviceItem) { 336 | int device_index; 337 | GetItemValue(it->second, device_index); 338 | WritePrivateProfileString(appName, "D3DDeviceID", m_d3dDeviceIDs.at(device_index).c_str(), filename); 339 | } 340 | } 341 | 342 | return TRUE; 343 | } 344 | 345 | void PatchGrid::AddD3DDevice(const string &name, const string &id) 346 | { 347 | m_d3dDeviceNames.push_back(name); 348 | m_d3dDeviceIDs.push_back(id); 349 | } 350 | 351 | CString PatchGrid::GetItemDescription(HITEM item) 352 | { 353 | for (std::map::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) { 354 | if (it->second == item) { 355 | return GetItemDescription(it->first); 356 | } 357 | } 358 | return CString(); 359 | } 360 | 361 | void PatchGrid::AddPatch(const string &id, const CString &description, HITEM item) 362 | { 363 | m_mPatchItems[id] = item; 364 | m_mPatchDescriptions[id] = description; 365 | } 366 | -------------------------------------------------------------------------------- /src/patchgrid.h: -------------------------------------------------------------------------------- 1 | #ifndef PATCHGRID_H 2 | #define PATCHGRID_H 3 | 4 | #include "../ext/PropertyGrid/stdafx.h" 5 | #include "../ext/PropertyGrid/PropertyGrid.h" 6 | 7 | class PatchGrid : public CPropertyGrid 8 | { 9 | public: 10 | PatchGrid(); 11 | 12 | void LoadConfiguration(LPCTSTR filename); 13 | BOOL SaveConfiguration(LPCTSTR filename); 14 | 15 | void AddD3DDevice(const std::string &name, const std::string &id); 16 | 17 | CString GetItemDescription(HITEM item); 18 | CString GetItemDescription(const std::string &key) 19 | { 20 | return m_mPatchDescriptions[key]; 21 | } 22 | 23 | private: 24 | void AddPatch(const std::string &id, const CString &description, HITEM item); 25 | 26 | std::map m_mPatchItems; 27 | std::map m_mPatchDescriptions; 28 | 29 | HITEM m_d3dDeviceItem; 30 | 31 | std::vector m_d3dDeviceNames; 32 | std::vector m_d3dDeviceIDs; 33 | 34 | }; 35 | 36 | #endif // PATCHGRID_H 37 | -------------------------------------------------------------------------------- /src/tabs.cpp: -------------------------------------------------------------------------------- 1 | #include "tabs.h" 2 | 3 | void TabCtrl::CreateChildren() 4 | { 5 | // Create property grid 6 | m_cPatchGrid.Create(AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW), "Patch Grid", WS_CHILD | WS_VISIBLE, CRect(), this, ID_PATCHGRID); 7 | m_cPatchTitle.Create(CString("Welcome to LEGO Island Rebuilder"), WS_CHILD | WS_VISIBLE, CRect(), this, ID_PATCHTITLE); 8 | m_cPatchDesc.Create(CString("Select a patch to get started."), WS_CHILD | WS_VISIBLE, CRect(), this, ID_PATCHDESC); 9 | 10 | m_cMusicLink.Create("Coming back soon. If you need music replacement, download the old .NET version here.", 11 | WS_CHILD | SS_CENTER | SS_NOTIFY, CRect(), this, ID_MUSICLINK); 12 | } 13 | 14 | HBRUSH TabCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 15 | { 16 | HBRUSH hbr = CWnd::OnCtlColor(pDC, pWnd, nCtlColor); 17 | 18 | if (pWnd->GetDlgCtrlID() == ID_MUSICLINK 19 | || pWnd->GetDlgCtrlID() == ID_PATCHTITLE 20 | || pWnd->GetDlgCtrlID() == ID_PATCHDESC) { 21 | pDC->SetBkMode(TRANSPARENT); 22 | return (HBRUSH) GetStockObject(NULL_BRUSH); 23 | } 24 | 25 | return hbr; 26 | } 27 | 28 | LRESULT TabCtrl::OnGridSelChange(WPARAM wParam, LPARAM lParam) 29 | { 30 | HITEM hItem = (HITEM) wParam; 31 | 32 | m_cPatchTitle.SetWindowText(m_cPatchGrid.GetItemText(hItem).c_str()); 33 | m_cPatchDesc.SetWindowText(m_cPatchGrid.GetItemDescription(hItem)); 34 | 35 | CRect rect; 36 | m_cPatchTitle.GetWindowRect(&rect); 37 | ScreenToClient(&rect); 38 | InvalidateRect(&rect); 39 | UpdateWindow(); 40 | 41 | m_cPatchDesc.GetWindowRect(&rect); 42 | ScreenToClient(&rect); 43 | InvalidateRect(&rect); 44 | UpdateWindow(); 45 | 46 | return 0; 47 | } 48 | 49 | void TabCtrl::OnMusicLinkClick() 50 | { 51 | ShellExecute(NULL, _T("open"), _T("https://github.com/itsmattkc/LEGOIslandRebuilder/releases/tag/lastnet"), NULL, NULL, SW_SHOWNORMAL); 52 | } 53 | 54 | BEGIN_MESSAGE_MAP(TabCtrl, CTabCtrl) 55 | ON_WM_CTLCOLOR() 56 | ON_BN_CLICKED(ID_MUSICLINK, OnMusicLinkClick) 57 | ON_MESSAGE(WM_PG_SELECTIONCHANGED, OnGridSelChange) 58 | END_MESSAGE_MAP() 59 | -------------------------------------------------------------------------------- /src/tabs.h: -------------------------------------------------------------------------------- 1 | #ifndef CREBUILDERTABS_H 2 | #define CREBUILDERTABS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "clinkstatic.h" 9 | #include "patchgrid.h" 10 | 11 | class TabCtrl : public CTabCtrl 12 | { 13 | public: 14 | enum { 15 | ID_PATCHGRID = 1000, 16 | ID_PATCHTITLE, 17 | ID_PATCHDESC, 18 | ID_MUSICLINK, 19 | ID_COUNT 20 | }; 21 | 22 | void CreateChildren(); 23 | 24 | afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); 25 | 26 | afx_msg LRESULT OnGridSelChange(WPARAM, LPARAM); 27 | 28 | afx_msg void OnSize(UINT type, int width, int height); 29 | 30 | afx_msg void OnMusicLinkClick(); 31 | 32 | PatchGrid &GetPatchGrid() { return m_cPatchGrid; } 33 | CStatic &GetPatchTitle() { return m_cPatchTitle; } 34 | CStatic &GetPatchDesc() { return m_cPatchDesc; } 35 | CStatic &GetMusicLink() { return m_cMusicLink; } 36 | 37 | private: 38 | PatchGrid m_cPatchGrid; 39 | CStatic m_cPatchTitle; 40 | CStatic m_cPatchDesc; 41 | 42 | CLinkStatic m_cMusicLink; 43 | 44 | DECLARE_MESSAGE_MAP() 45 | 46 | }; 47 | 48 | #endif // CREBUILDERWINDOW_H 49 | -------------------------------------------------------------------------------- /src/window.cpp: -------------------------------------------------------------------------------- 1 | #include "window.h" 2 | 3 | #include 4 | 5 | #include "../cmn/path.h" 6 | #include "launcher.h" 7 | #include "../res/resource.h" 8 | 9 | #define super CWnd 10 | 11 | static const int WM_CHILD_CLOSED = WM_USER + 1; 12 | 13 | CString GetResourceString(UINT id) 14 | { 15 | CString cstr; 16 | cstr.LoadString(id); 17 | return cstr; 18 | } 19 | 20 | CRebuilderWindow::CRebuilderWindow() 21 | { 22 | // Register custom window class 23 | LPCTSTR wndclass = AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 24 | LoadCursor(NULL, IDC_ARROW), 25 | GetSysColorBrush(COLOR_3DFACE), 26 | LoadIcon(AfxGetInstanceHandle(), "IDI_ICON1")); 27 | 28 | const char *title = "LEGO Island Rebuilder"; 29 | 30 | // Create form 31 | CreateEx(WS_EX_OVERLAPPEDWINDOW, wndclass, title, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL); 32 | ModifyStyleEx(WS_EX_CLIENTEDGE, 0, 0); 33 | 34 | // Create title 35 | m_cTopLevelTitle.Create(title, WS_CHILD | WS_VISIBLE | SS_CENTER, CRect(), this); 36 | 37 | // Create subtitle 38 | m_cTopLevelSubtitle.Create("by MattKC and Ramen2X", WS_CHILD | WS_VISIBLE | SS_CENTER | SS_NOTIFY, CRect(), this, ID_SUBTITLE); 39 | 40 | // Create tab control 41 | m_cTabCtrl.Create(WS_CHILD | WS_VISIBLE, CRect(), this, ID_TABCTRL); 42 | m_cTabCtrl.CreateChildren(); 43 | 44 | // Initialize common TCITEM 45 | TCITEM tabItem; 46 | ZeroMemory(&tabItem, sizeof(tabItem)); 47 | tabItem.mask |= TCIF_TEXT; 48 | 49 | tabItem.pszText = "Patches"; 50 | m_cTabCtrl.InsertItem(TAB_PATCHES, &tabItem); 51 | 52 | tabItem.pszText = "Music"; 53 | m_cTabCtrl.InsertItem(TAB_MUSIC, &tabItem); 54 | 55 | // Create run button 56 | m_cRunBtn.Create("Run", WS_CHILD | WS_VISIBLE, CRect(), this, ID_RUN); 57 | 58 | // Create run button 59 | m_cKillBtn.Create("Kill", WS_CHILD, CRect(), this, ID_KILL); 60 | 61 | // Set fonts 62 | SetGUIFonts(); 63 | 64 | // Call this after all UI objects are created because this will call LayoutObjects 65 | static const UINT defaultWindowWidth = 32; 66 | static const UINT defaultWindowHeight = 32; 67 | SetWindowPos(NULL, 0, 0, m_nFontHeight * defaultWindowWidth, m_nFontHeight * defaultWindowHeight, 0); 68 | CenterWindow(NULL); 69 | 70 | // Set column width 71 | RECT patchGridClientRect; 72 | m_cTabCtrl.GetPatchGrid().GetClientRect(&patchGridClientRect); 73 | m_cTabCtrl.GetPatchGrid().SetGutterWidth((patchGridClientRect.right - patchGridClientRect.left) / 2); 74 | 75 | TCHAR configPath[MAX_PATH]; 76 | if (GetConfigFilename(configPath)) { 77 | m_cTabCtrl.GetPatchGrid().LoadConfiguration(configPath); 78 | } 79 | } 80 | 81 | CRebuilderWindow::~CRebuilderWindow() 82 | { 83 | TrySaving(); 84 | OnKillClick(); 85 | } 86 | 87 | DWORD WINAPI WaitForProcessToClose(HANDLE hProcess) 88 | { 89 | WaitForSingleObject(hProcess, INFINITE); 90 | AfxGetMainWnd()->PostMessage(WM_CHILD_CLOSED, (WPARAM)hProcess); 91 | 92 | return 0; 93 | } 94 | 95 | BOOL CRebuilderWindow::TrySaving() 96 | { 97 | TCHAR configPath[MAX_PATH]; 98 | 99 | if (GetConfigFilename(configPath)) { 100 | if (m_cTabCtrl.GetPatchGrid().SaveConfiguration(configPath)) { 101 | return TRUE; 102 | } else { 103 | MessageBox("Failed to save configuration file."); 104 | } 105 | } else { 106 | MessageBox("Failed to determine configuration path."); 107 | } 108 | 109 | return FALSE; 110 | } 111 | 112 | void CRebuilderWindow::OnRunClick() 113 | { 114 | if (TrySaving()) { 115 | if (HANDLE proc = Launcher::Launch(this->GetSafeHwnd())) { 116 | m_lProcesses.push_back(proc); 117 | SwitchButtonMode(TRUE); 118 | 119 | // Register callback when process exits 120 | DWORD threadId; // We don't use this, but Windows 95 will fail without it 121 | CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WaitForProcessToClose, proc, 0, &threadId)); 122 | } 123 | } 124 | } 125 | 126 | void CRebuilderWindow::OnKillClick() 127 | { 128 | for (std::vector::iterator it=m_lProcesses.begin(); it!=m_lProcesses.end(); it++) { 129 | TerminateProcess(*it, 0); 130 | } 131 | m_lProcesses.clear(); 132 | 133 | SwitchButtonMode(FALSE); 134 | } 135 | 136 | void CRebuilderWindow::OnSubtitleClick() 137 | { 138 | ShellExecute(NULL, "open", "https://legoisland.org/", NULL, NULL, SW_SHOWNORMAL); 139 | } 140 | 141 | void CRebuilderWindow::OnSize(UINT type, int width, int height) 142 | { 143 | const int padding = m_nFontHeight/2; 144 | const int dblPadding = padding * 2; 145 | 146 | int y, h; 147 | 148 | // Top labels 149 | y = padding; 150 | h = m_nFontHeight*2; 151 | 152 | m_cTopLevelTitle.SetWindowPos(NULL, 0, y, width, h, 0); 153 | 154 | y += h; 155 | h = m_nFontHeight*1; 156 | 157 | m_cTopLevelSubtitle.SetWindowPos(NULL, 0, y, width, h, 0); 158 | 159 | y += h; 160 | y += padding; 161 | 162 | // Bottom buttons 163 | const int btnHeight = m_nFontHeight*18/10; 164 | int btnY = height - btnHeight - padding; 165 | int btnWidth = width - dblPadding; 166 | m_cRunBtn.SetWindowPos(NULL, padding, btnY, btnWidth, btnHeight, 0); 167 | m_cKillBtn.SetWindowPos(NULL, padding, btnY, btnWidth, btnHeight, 0); 168 | 169 | h = btnY - y - padding; 170 | m_cTabCtrl.SetWindowPos(NULL, padding, y, btnWidth, h, 0); 171 | 172 | // Generate internal rect 173 | RECT inner; 174 | m_cTabCtrl.GetClientRect(&inner); 175 | m_cTabCtrl.AdjustRect(FALSE, &inner); 176 | 177 | int w = inner.right - inner.left; 178 | 179 | h = m_nFontHeight*5; 180 | int patchDescY = inner.bottom - h - padding; 181 | m_cTabCtrl.GetPatchDesc().SetWindowPos(NULL, inner.left, patchDescY, w, h, 0); 182 | 183 | h = m_nFontHeight; 184 | patchDescY -= h; 185 | m_cTabCtrl.GetPatchTitle().SetWindowPos(NULL, inner.left, patchDescY, w, h, 0); 186 | 187 | // Consume remaining space with patch grid 188 | h = patchDescY - inner.top - padding; 189 | m_cTabCtrl.GetPatchGrid().SetWindowPos(NULL, inner.left, inner.top, w, h, 0); 190 | 191 | h = inner.bottom - inner.top; 192 | int musicLinkWidth = w/4*3; 193 | m_cTabCtrl.GetMusicLink().SetWindowPos(NULL, inner.left + w/2 - musicLinkWidth/2, inner.top + m_nFontHeight, musicLinkWidth, h, 0); 194 | } 195 | 196 | void CRebuilderWindow::OnGetMinMaxInfo(MINMAXINFO *info) 197 | { 198 | static const LONG minimumWindowWidth = 12; 199 | static const LONG minimumWindowHeight = 12; 200 | 201 | info->ptMinTrackSize.x = m_nFontHeight * minimumWindowWidth; 202 | info->ptMinTrackSize.y = m_nFontHeight * minimumWindowHeight; 203 | } 204 | 205 | void CRebuilderWindow::OnTabSelChange(NMHDR *pNMHDR, LRESULT *pResult) 206 | { 207 | int tab = m_cTabCtrl.GetCurSel(); 208 | 209 | m_cTabCtrl.GetPatchGrid().ShowWindow((tab == TAB_PATCHES) ? SW_SHOWNORMAL : SW_HIDE); 210 | m_cTabCtrl.GetPatchTitle().ShowWindow((tab == TAB_PATCHES) ? SW_SHOWNORMAL : SW_HIDE); 211 | m_cTabCtrl.GetPatchDesc().ShowWindow((tab == TAB_PATCHES) ? SW_SHOWNORMAL : SW_HIDE); 212 | m_cTabCtrl.GetMusicLink().ShowWindow((tab == TAB_MUSIC) ? SW_SHOWNORMAL : SW_HIDE); 213 | } 214 | 215 | BOOL CRebuilderWindow::SetFont(HWND child, LPARAM font) 216 | { 217 | ::SendMessage(child, WM_SETFONT, font, true); 218 | return true; 219 | } 220 | 221 | LRESULT CRebuilderWindow::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) 222 | { 223 | if (uMsg == WM_CHILD_CLOSED) { 224 | HANDLE hProcess = (HANDLE)wParam; 225 | 226 | for (std::vector::iterator it=m_lProcesses.begin(); it!=m_lProcesses.end(); it++) { 227 | if (*it == hProcess) { 228 | m_lProcesses.erase(it); 229 | break; 230 | } 231 | } 232 | 233 | if (m_lProcesses.empty()) { 234 | SwitchButtonMode(FALSE); 235 | } 236 | 237 | return 0; 238 | } else { 239 | return super::WindowProc(uMsg, wParam, lParam); 240 | } 241 | } 242 | 243 | void CRebuilderWindow::SetGUIFonts() 244 | { 245 | // Retrieve default GUI font 246 | HFONT defaultFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); 247 | 248 | // Set on all UI objects 249 | EnumChildWindows(this->GetSafeHwnd(), (WNDENUMPROC)SetFont, (LPARAM)defaultFont); 250 | 251 | // Get LOGFONT to create bold variant 252 | LOGFONT lf; 253 | GetObject(defaultFont, sizeof(lf), &lf); 254 | lf.lfWeight = FW_BOLD; 255 | 256 | // Create font from LOGFONT 257 | HFONT bold = CreateFontIndirect(&lf); 258 | 259 | // Set bold variant on relevant objects 260 | SetFont(m_cTopLevelTitle.GetSafeHwnd(), (LPARAM)bold); 261 | SetFont(m_cRunBtn.GetSafeHwnd(), (LPARAM)bold); 262 | SetFont(m_cKillBtn.GetSafeHwnd(), (LPARAM)bold); 263 | SetFont(m_cTabCtrl.GetPatchTitle().GetSafeHwnd(), (LPARAM)bold); 264 | 265 | // Create link variant for subtitle 266 | lf.lfWeight = FW_NORMAL; 267 | lf.lfUnderline = TRUE; 268 | 269 | HFONT link = CreateFontIndirect(&lf); 270 | SetFont(m_cTopLevelSubtitle.GetSafeHwnd(), (LPARAM)link); 271 | SetFont(m_cTabCtrl.GetMusicLink().GetSafeHwnd(), (LPARAM)link); 272 | 273 | // While here, get height of font for layout purposes 274 | HDC hDC = ::GetDC(NULL); 275 | HGDIOBJ hFontOld = SelectObject(hDC, defaultFont); 276 | TEXTMETRIC tm; 277 | GetTextMetrics(hDC, &tm); 278 | m_nFontHeight = tm.tmHeight + tm.tmExternalLeading; 279 | SelectObject(hDC, hFontOld); 280 | ::ReleaseDC(NULL, hDC); 281 | } 282 | 283 | void CRebuilderWindow::SwitchButtonMode(BOOL running) 284 | { 285 | if (running) { 286 | m_cRunBtn.ShowWindow(SW_HIDE); 287 | m_cKillBtn.ShowWindow(SW_SHOWNORMAL); 288 | } else { 289 | m_cKillBtn.ShowWindow(SW_HIDE); 290 | m_cRunBtn.ShowWindow(SW_SHOWNORMAL); 291 | } 292 | } 293 | 294 | BEGIN_MESSAGE_MAP(CRebuilderWindow, super) 295 | ON_WM_SIZE() 296 | ON_WM_GETMINMAXINFO() 297 | ON_BN_CLICKED(ID_RUN, OnRunClick) 298 | ON_BN_CLICKED(ID_KILL, OnKillClick) 299 | ON_BN_CLICKED(ID_SUBTITLE, OnSubtitleClick) 300 | ON_NOTIFY(TCN_SELCHANGE, ID_TABCTRL, OnTabSelChange) 301 | END_MESSAGE_MAP() 302 | -------------------------------------------------------------------------------- /src/window.h: -------------------------------------------------------------------------------- 1 | #ifndef CREBUILDERWINDOW_H 2 | #define CREBUILDERWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "clinkstatic.h" 9 | #include "patchgrid.h" 10 | #include "tabs.h" 11 | 12 | class CRebuilderWindow : public CFrameWnd 13 | { 14 | public: 15 | CRebuilderWindow(); 16 | 17 | ~CRebuilderWindow(); 18 | 19 | afx_msg void OnRunClick(); 20 | 21 | afx_msg void OnKillClick(); 22 | 23 | afx_msg void OnSubtitleClick(); 24 | 25 | afx_msg void OnSize(UINT type, int width, int height); 26 | 27 | afx_msg void OnGetMinMaxInfo(MINMAXINFO *info); 28 | 29 | afx_msg void OnTabSelChange(NMHDR* pNMHDR, LRESULT* pResult); 30 | 31 | static BOOL CALLBACK SetFont(HWND child, LPARAM font); 32 | 33 | virtual LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); 34 | 35 | private: 36 | void SetGUIFonts(); 37 | 38 | void SwitchButtonMode(BOOL running); 39 | 40 | BOOL TrySaving(); 41 | 42 | enum { 43 | ID_RUN = 1000, 44 | ID_KILL, 45 | ID_TABCTRL, 46 | ID_SUBTITLE, 47 | ID_COUNT 48 | }; 49 | 50 | enum Tab { 51 | TAB_PATCHES, 52 | TAB_MUSIC 53 | }; 54 | 55 | UINT m_nFontHeight; 56 | 57 | CStatic m_cTopLevelTitle; 58 | CLinkStatic m_cTopLevelSubtitle; 59 | 60 | TabCtrl m_cTabCtrl; 61 | 62 | CButton m_cRunBtn; 63 | CButton m_cKillBtn; 64 | 65 | std::vector m_lProcesses; 66 | 67 | DECLARE_MESSAGE_MAP() 68 | 69 | }; 70 | 71 | #endif // CREBUILDERWINDOW_H 72 | --------------------------------------------------------------------------------