Rev 478 | Rev 492 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
439 | daniel-mar | 1 | /* |
2 | This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop |
||
3 | Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au |
||
4 | Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft |
||
5 | |||
6 | This program is free software; you can redistribute it and/or modify |
||
7 | it under the terms of the GNU General Public License as published by |
||
8 | the Free Software Foundation; either version 2 of the License, or |
||
9 | (at your option) any later version. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | GNU General Public License for more details. |
||
15 | |||
16 | You should have received a copy of the GNU General Public License |
||
17 | along with this program; if not, write to the Free Software |
||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
19 | */ |
||
20 | |||
21 | #include "ff.h" |
||
443 | daniel-mar | 22 | #include "slider_win.h" |
439 | daniel-mar | 23 | |
470 | daniel-mar | 24 | // More information about the PLUGIN.DLL sliders: |
25 | // https://misc.daniel-marschall.de/projects/filter_factory/sliders.html |
||
26 | |||
439 | daniel-mar | 27 | // PLUGIN.DLL Sliders: This method will register the "slider" class used in dialogs. |
477 | daniel-mar | 28 | #ifdef use_plugin_dll_sliders |
469 | daniel-mar | 29 | typedef BOOL(__cdecl* f_RegisterSlider)(HINSTANCE hInstanceDll, DWORD* MessageID); |
478 | daniel-mar | 30 | BOOL PluginDll_RegisterSlider(HINSTANCE hInstanceDll, DWORD* MessageID) { |
439 | daniel-mar | 31 | f_RegisterSlider fRegisterSlider; |
470 | daniel-mar | 32 | BOOL res; |
439 | daniel-mar | 33 | |
477 | daniel-mar | 34 | if (!gdata->pluginDllSliderInfo.hLib) return false; |
35 | fRegisterSlider = (f_RegisterSlider)(void*)GetProcAddress(gdata->pluginDllSliderInfo.hLib, "RegisterSlider"); |
||
470 | daniel-mar | 36 | res = (fRegisterSlider != 0) ? fRegisterSlider(hInstanceDll, MessageID) : false; |
37 | return res; |
||
439 | daniel-mar | 38 | } |
477 | daniel-mar | 39 | #endif |
439 | daniel-mar | 40 | |
41 | // PLUGIN.DLL Sliders: This method will unregister the "slider" class used in dialogs. |
||
477 | daniel-mar | 42 | #ifdef use_plugin_dll_sliders |
471 | daniel-mar | 43 | typedef BOOL(__cdecl* f_UnRegisterSlider)(HINSTANCE hInstanceDll); |
478 | daniel-mar | 44 | BOOL PluginDll_UnRegisterSlider(HINSTANCE hInstanceDll) { |
471 | daniel-mar | 45 | f_UnRegisterSlider fUnRegisterSlider; |
470 | daniel-mar | 46 | BOOL res; |
439 | daniel-mar | 47 | |
477 | daniel-mar | 48 | if (!gdata->pluginDllSliderInfo.hLib) return false; |
49 | fUnRegisterSlider = (f_UnRegisterSlider)(void*)GetProcAddress(gdata->pluginDllSliderInfo.hLib, "UnRegisterSlider"); |
||
471 | daniel-mar | 50 | res = (fUnRegisterSlider != 0) ? fUnRegisterSlider(hInstanceDll) : false; |
470 | daniel-mar | 51 | return res; |
439 | daniel-mar | 52 | } |
477 | daniel-mar | 53 | #endif |
439 | daniel-mar | 54 | |
55 | // PLUGIN.DLL Sliders: Set slider range (min/max) |
||
477 | daniel-mar | 56 | #ifdef use_plugin_dll_sliders |
439 | daniel-mar | 57 | typedef int(__cdecl* f_SetSliderRange)(HWND hWnd, int nMin, int nMax); |
478 | daniel-mar | 58 | int PluginDll_SetSliderRange(HWND hWnd, int nMin, int nMax) { |
439 | daniel-mar | 59 | f_SetSliderRange fSetSliderRange; |
470 | daniel-mar | 60 | int res; |
439 | daniel-mar | 61 | |
477 | daniel-mar | 62 | if (!gdata->pluginDllSliderInfo.hLib) return 0; |
63 | fSetSliderRange = (f_SetSliderRange)(void*)GetProcAddress(gdata->pluginDllSliderInfo.hLib, "SetSliderRange"); |
||
470 | daniel-mar | 64 | res = (fSetSliderRange != 0) ? fSetSliderRange(hWnd, nMin, nMax) : 0; |
65 | return res; |
||
439 | daniel-mar | 66 | } |
477 | daniel-mar | 67 | #endif |
439 | daniel-mar | 68 | |
69 | // PLUGIN.DLL Sliders : Sets slider position |
||
477 | daniel-mar | 70 | #ifdef use_plugin_dll_sliders |
439 | daniel-mar | 71 | typedef int(__cdecl* f_SetSliderPos)(HWND hWnd, int nPos, BOOL bRepaint); |
478 | daniel-mar | 72 | int PluginDll_SetSliderPos(HWND hWnd, int nPos, BOOL bRepaint) { |
439 | daniel-mar | 73 | f_SetSliderPos fSetSliderPos; |
470 | daniel-mar | 74 | int res; |
439 | daniel-mar | 75 | |
477 | daniel-mar | 76 | if (!gdata->pluginDllSliderInfo.hLib) return 0; |
77 | fSetSliderPos = (f_SetSliderPos)(void*)GetProcAddress(gdata->pluginDllSliderInfo.hLib, "SetSliderPos"); |
||
470 | daniel-mar | 78 | res = (fSetSliderPos != 0) ? fSetSliderPos(hWnd, nPos, bRepaint) : 0; |
79 | return res; |
||
439 | daniel-mar | 80 | } |
477 | daniel-mar | 81 | #endif |
439 | daniel-mar | 82 | |
83 | // PLUGIN.DLL Sliders : Get slider position |
||
477 | daniel-mar | 84 | #ifdef use_plugin_dll_sliders |
439 | daniel-mar | 85 | typedef int(__cdecl* f_GetSliderPos)(HWND hWnd, BOOL bPixelPosition); |
478 | daniel-mar | 86 | int PluginDll_GetSliderPos(HWND hWnd, BOOL bPixelPosition) { |
439 | daniel-mar | 87 | f_GetSliderPos fGetSliderPos; |
470 | daniel-mar | 88 | int res; |
439 | daniel-mar | 89 | |
477 | daniel-mar | 90 | if (!gdata->pluginDllSliderInfo.hLib) return 0; |
91 | fGetSliderPos = (f_GetSliderPos)(void*)GetProcAddress(gdata->pluginDllSliderInfo.hLib, "GetSliderPos"); |
||
470 | daniel-mar | 92 | res = (fGetSliderPos != 0) ? fGetSliderPos(hWnd, bPixelPosition) : 0; |
93 | return res; |
||
439 | daniel-mar | 94 | } |
477 | daniel-mar | 95 | #endif |
439 | daniel-mar | 96 | |
478 | daniel-mar | 97 | void FF_SetSliderRange(HWND hDlg, int nIDDlgItem, int min, int max) { |
98 | if (!gdata->pluginDllSliderInfo.initialized) { |
||
99 | // Non PLUGIN.DLL sliders |
||
100 | SetWindowLongPtr(GetDlgItem(hDlg, nIDDlgItem), GWL_STYLE, TBS_HORZ | TBS_AUTOTICKS | WS_CHILD | WS_VISIBLE); |
||
101 | SendDlgItemMessage(hDlg, nIDDlgItem, TBM_SETRANGE, TRUE, MAKELONG(min, max)); |
||
102 | SendDlgItemMessage(hDlg, nIDDlgItem, TBM_SETTICFREQ, SLIDERPAGE, 0); |
||
103 | SendDlgItemMessage(hDlg, nIDDlgItem, TBM_SETPAGESIZE, 0, SLIDERPAGE); |
||
104 | } |
||
105 | else { |
||
106 | // PLUGIN.DLL sliders |
||
107 | #ifdef use_plugin_dll_sliders |
||
108 | PluginDll_SetSliderRange(GetDlgItem(hDlg, nIDDlgItem), min, max); |
||
109 | #endif |
||
110 | } |
||
111 | } |
||
112 | |||
113 | int FF_GetSliderPos(HWND hDlg, int nIDDlgItem) { |
||
114 | if (gdata->pluginDllSliderInfo.initialized) { |
||
115 | return PluginDll_GetSliderPos(GetDlgItem(hDlg, nIDDlgItem), false); |
||
116 | } |
||
117 | else if (gdata->comctlSliderInfo.initialized) { |
||
118 | return (int)SendDlgItemMessage(hDlg, nIDDlgItem, TBM_GETPOS, 0, 0); |
||
119 | } |
||
120 | else { |
||
121 | return 0; |
||
122 | } |
||
123 | } |
||
124 | |||
125 | void FF_SetSliderPos(HWND hDlg, int nIDDlgItem, int pos) { |
||
126 | if (gdata->pluginDllSliderInfo.initialized) { |
||
127 | PluginDll_SetSliderPos(GetDlgItem(hDlg, nIDDlgItem), pos, true); |
||
128 | } |
||
129 | else if (gdata->comctlSliderInfo.initialized) { |
||
130 | SendDlgItemMessage(hDlg, nIDDlgItem, TBM_SETPOS, TRUE, pos); |
||
131 | } |
||
132 | } |
||
133 | |||
460 | daniel-mar | 134 | LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { |
135 | return DefWindowProc(hwnd, uMsg, wParam, lParam); |
||
136 | } |
||
137 | |||
461 | daniel-mar | 138 | void Win32sFixSuperclassing(HWND hDlg, int destItem, int sourceItem) { |
139 | // Win32s (Win3.11) compatibility fix: Since GetClassInfo(WC_BUTTON) and GetClassInfo(WC_STATIC) won't work, |
||
140 | // we had replaced the WndProc by a dummy. Now, we find out the real Button and Static WndProcs and give them |
||
141 | // to our classes, making them the intended superclasses. Messages which have been sent in between were lost, |
||
142 | // though... |
||
143 | |||
144 | WNDPROC wndProc; |
||
145 | #ifdef _WIN64 |
||
146 | wndProc = (WNDPROC)GetWindowLongPtr(GetDlgItem(hDlg, destItem), GWLP_WNDPROC); |
||
147 | if (wndProc == DummyWndProc) { |
||
148 | wndProc = (WNDPROC)GetWindowLongPtr(GetDlgItem(hDlg, sourceItem), GWLP_WNDPROC); |
||
149 | SetWindowLongPtr(GetDlgItem(hDlg, destItem), GWLP_WNDPROC, (LONG_PTR)wndProc); |
||
150 | } |
||
151 | #else |
||
152 | wndProc = (WNDPROC)GetWindowLongPtr(GetDlgItem(hDlg, destItem), GWL_WNDPROC); |
||
153 | if (wndProc == DummyWndProc) { |
||
154 | wndProc = (WNDPROC)GetWindowLongPtr(GetDlgItem(hDlg, sourceItem), GWL_WNDPROC); |
||
155 | SetWindowLongPtr(GetDlgItem(hDlg, destItem), GWL_WNDPROC, (LONG_PTR)wndProc); |
||
156 | } |
||
157 | #endif |
||
158 | } |
||
159 | |||
444 | daniel-mar | 160 | Boolean MakeSimpleSubclass(LPCTSTR targetClass, LPCTSTR sourceClass) { |
439 | daniel-mar | 161 | WNDCLASS clx; |
162 | |||
444 | daniel-mar | 163 | if (GetClassInfo(hDllInstance, sourceClass, &clx) != 0) { |
439 | daniel-mar | 164 | clx.lpszClassName = targetClass; |
165 | if (RegisterClass(&clx) == 0) { |
||
444 | daniel-mar | 166 | TCHAR s[0x300]; |
167 | xstrcpy(s, (TCHAR*)TEXT("RegisterClass failed: ")); |
||
454 | daniel-mar | 168 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, s + xstrlen(s), 0x300 - (DWORD)xstrlen(s), NULL); |
482 | daniel-mar | 169 | simplealert(&s[0]); |
439 | daniel-mar | 170 | return false; |
171 | } |
||
172 | else { |
||
173 | return true; |
||
174 | } |
||
175 | } |
||
176 | else { |
||
460 | daniel-mar | 177 | if ((xstrcmp(sourceClass, WC_BUTTON) == 0) || (xstrcmp(sourceClass, WC_STATIC) == 0)) { |
178 | // GetClassInfo(WC_STATIC) and GetClassInfo(WC_BUTTON) fail on Win32s (Windows 3.11) |
||
179 | // So we create a fake-class now. It will be replaced with the real Button/Static WndProc later! |
||
180 | clx.style = 0; |
||
181 | clx.lpfnWndProc = DummyWndProc; |
||
182 | clx.cbClsExtra = 0; |
||
183 | clx.cbWndExtra = 0; |
||
184 | clx.hInstance = hDllInstance; |
||
185 | clx.hIcon = 0; |
||
186 | clx.hCursor = 0; |
||
187 | clx.hbrBackground = 0; |
||
188 | clx.lpszMenuName = 0; |
||
189 | clx.lpszClassName = targetClass; |
||
190 | |||
191 | if (RegisterClass(&clx) == 0) { |
||
192 | TCHAR s[0x300]; |
||
193 | xstrcpy(s, (TCHAR*)TEXT("RegisterClass failed: ")); |
||
194 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, s + xstrlen(s), 0x300 - (DWORD)xstrlen(s), NULL); |
||
482 | daniel-mar | 195 | simplealert(&s[0]); |
460 | daniel-mar | 196 | return false; |
197 | } |
||
198 | else { |
||
199 | return true; |
||
200 | } |
||
201 | } |
||
202 | else { |
||
463 | daniel-mar | 203 | simplealert((TCHAR*)TEXT("GetClassInfo failed")); |
460 | daniel-mar | 204 | } |
439 | daniel-mar | 205 | return false; |
206 | } |
||
207 | } |
||
208 | |||
476 | daniel-mar | 209 | Boolean Slider_Init_PluginDll(LPCTSTR targetClass) { |
210 | |||
439 | daniel-mar | 211 | #ifndef use_plugin_dll_sliders |
476 | daniel-mar | 212 | return false; |
439 | daniel-mar | 213 | #else |
477 | daniel-mar | 214 | if (gdata->pluginDllSliderInfo.initialized) return true; |
476 | daniel-mar | 215 | |
477 | daniel-mar | 216 | if (!gdata->pluginDllSliderInfo.hLib) { |
476 | daniel-mar | 217 | // DM 16.04.2022 : It is important that PLUGIN.DLL stays loaded, otherwise |
218 | // DialogBoxParamA crashes. Can be reproduced if all 8BX modules are disabled in Photoshop 7 |
||
219 | // (they keep PLUGIN.DLL loaded). |
||
477 | daniel-mar | 220 | gdata->pluginDllSliderInfo.hLib = LoadLibrary(TEXT("Plugin.dll")); |
439 | daniel-mar | 221 | } |
476 | daniel-mar | 222 | |
478 | daniel-mar | 223 | if (gdata->pluginDllSliderInfo.hLib && PluginDll_RegisterSlider(hDllInstance, &gdata->pluginDllSliderInfo.messageId)) { |
476 | daniel-mar | 224 | // Make "FoundrySlider" a subclass of "slider" then |
477 | daniel-mar | 225 | if (MakeSimpleSubclass(targetClass, TEXT("slider"))) { |
226 | gdata->pluginDllSliderInfo.initialized = true; |
||
227 | return true; |
||
228 | } |
||
229 | else { |
||
230 | return false; |
||
231 | } |
||
476 | daniel-mar | 232 | } |
233 | else { |
||
234 | // This can happen if PLUGIN.DLL is not existing |
||
235 | // It will also happen if a previous uninitialization failed (or was forgotten) |
||
236 | return false; // Fall back to Windows sliders |
||
237 | } |
||
439 | daniel-mar | 238 | #endif |
239 | |||
240 | } |
||
241 | |||
476 | daniel-mar | 242 | void Slider_Uninit_PluginDll() { |
439 | daniel-mar | 243 | #ifndef use_plugin_dll_sliders |
476 | daniel-mar | 244 | return; |
439 | daniel-mar | 245 | #else |
477 | daniel-mar | 246 | if (!gdata->pluginDllSliderInfo.initialized) return; |
476 | daniel-mar | 247 | |
478 | daniel-mar | 248 | if (!PluginDll_UnRegisterSlider(hDllInstance)) { |
477 | daniel-mar | 249 | simplealert((TCHAR*)TEXT("UnRegisterSlider failed")); |
250 | return; |
||
469 | daniel-mar | 251 | } |
477 | daniel-mar | 252 | |
253 | gdata->pluginDllSliderInfo.initialized = false; |
||
254 | |||
255 | if (gdata->pluginDllSliderInfo.hLib) { |
||
256 | FreeLibrary(gdata->pluginDllSliderInfo.hLib); |
||
257 | gdata->pluginDllSliderInfo.hLib = 0; |
||
258 | } |
||
439 | daniel-mar | 259 | #endif |
260 | } |
||
261 | |||
262 | typedef void(__stdcall* f_InitCommonControls)(); |
||
263 | typedef BOOL(__stdcall* f_InitCommonControlsEx)(const INITCOMMONCONTROLSEX* picce); |
||
444 | daniel-mar | 264 | Boolean Slider_Init_MsTrackbar(LPCTSTR targetClass) { |
439 | daniel-mar | 265 | f_InitCommonControls fInitCommonControls; |
266 | f_InitCommonControlsEx fInitCommonControlsEx; |
||
267 | |||
477 | daniel-mar | 268 | if (gdata->comctlSliderInfo.initialized) return true; |
269 | |||
439 | daniel-mar | 270 | // Make sure that Comctl32 is loaded |
477 | daniel-mar | 271 | if (!gdata->comctlSliderInfo.hLib) { |
272 | gdata->comctlSliderInfo.hLib = LoadLibrary(TEXT("Comctl32.dll")); |
||
476 | daniel-mar | 273 | } |
477 | daniel-mar | 274 | if (gdata->comctlSliderInfo.hLib) { |
275 | fInitCommonControlsEx = (f_InitCommonControlsEx)(void*)GetProcAddress(gdata->comctlSliderInfo.hLib, "InitCommonControlsEx"); |
||
439 | daniel-mar | 276 | if (fInitCommonControlsEx != 0) { |
277 | INITCOMMONCONTROLSEX icce; |
||
278 | icce.dwSize = sizeof(INITCOMMONCONTROLSEX); |
||
279 | icce.dwICC = ICC_BAR_CLASSES; |
||
280 | fInitCommonControlsEx(&icce); |
||
281 | } |
||
282 | else { |
||
477 | daniel-mar | 283 | fInitCommonControls = (f_InitCommonControls)(void*)GetProcAddress(gdata->comctlSliderInfo.hLib, "InitCommonControls"); |
439 | daniel-mar | 284 | if (fInitCommonControls != 0) { |
285 | fInitCommonControls(); |
||
286 | } |
||
287 | } |
||
476 | daniel-mar | 288 | |
289 | // Make "FoundrySlider" a subclass of "msctls_trackbar32" then |
||
477 | daniel-mar | 290 | if (MakeSimpleSubclass(targetClass, TEXT("msctls_trackbar32"))) { |
291 | gdata->comctlSliderInfo.initialized = true; |
||
292 | return true; |
||
293 | } |
||
294 | else { |
||
295 | return false; |
||
296 | } |
||
439 | daniel-mar | 297 | } |
476 | daniel-mar | 298 | else { |
299 | return false; |
||
300 | } |
||
301 | } |
||
439 | daniel-mar | 302 | |
476 | daniel-mar | 303 | void Slider_Uninit_MsTrackbar() { |
477 | daniel-mar | 304 | if (!gdata->comctlSliderInfo.initialized) return; |
305 | |||
306 | gdata->comctlSliderInfo.initialized = false; |
||
307 | |||
308 | if (gdata->comctlSliderInfo.hLib != 0) { |
||
309 | FreeLibrary(gdata->comctlSliderInfo.hLib); |
||
310 | gdata->comctlSliderInfo.hLib = 0; |
||
476 | daniel-mar | 311 | } |
439 | daniel-mar | 312 | } |
313 | |||
444 | daniel-mar | 314 | Boolean Slider_Init_None(LPCTSTR targetClass) { |
439 | daniel-mar | 315 | // Make "FoundrySlider" a subclass of "STATIC" (making it invisible) |
477 | daniel-mar | 316 | |
317 | if (gdata->noneSliderInfo.initialized) return true; |
||
318 | |||
319 | if (MakeSimpleSubclass(targetClass, WC_STATIC)) { |
||
320 | gdata->noneSliderInfo.initialized = true; |
||
321 | return true; |
||
322 | } |
||
323 | else { |
||
324 | return false; |
||
325 | } |
||
439 | daniel-mar | 326 | } |
476 | daniel-mar | 327 | |
328 | void Slider_Uninit_None() { |
||
477 | daniel-mar | 329 | if (!gdata->noneSliderInfo.initialized) return; |
330 | |||
476 | daniel-mar | 331 | // Nothing here |
332 | } |