1 /*
2  * Star field screensaver
3  *
4  * Copyright 2011 Carlo Bramini
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #define WIN32_LEAN_AND_MEAN
22 #include <windows.h>
23 #include <tchar.h>
24 #include <commctrl.h>
25 #include <shellapi.h>
26 
27 #include "resource.h"
28 #include "settings.h"
29 
30 #define SIZEOF(_v)  (sizeof(_v) / sizeof(*_v))
31 
32 // Options for the starfield
33 SSSTARS Settings;
34 
35 // Factory default settings.
36 static const SSSTARS FactoryDefaults = {
37     MAX_STARS,
38     20,
39     ROTATION_PERIODIC,
40 
41     TRUE,
42     TRUE,
43     TRUE,
44     TRUE
45 };
46 
47 static const DWORD RotoStrings[] = {
48     IDS_ROTATION_NONE,
49     IDS_ROTATION_LINEAR,
50     IDS_ROTATION_PERIODIC
51 };
52 
53 static DWORD QueryDWORD(HKEY hKey, LPCTSTR pszValueName, DWORD Default)
54 {
55     DWORD dwData, dwType, cbData;
56     LONG  lRes;
57 
58     dwType = REG_DWORD;
59     cbData = sizeof(DWORD);
60 
61     lRes = RegQueryValueEx(
62                 hKey,
63                 pszValueName,
64                 NULL,
65                 &dwType,
66                 (LPBYTE)&dwData,
67                 &cbData);
68 
69     if (lRes != ERROR_SUCCESS || dwType != REG_DWORD)
70         return Default;
71 
72     return dwData;
73 }
74 
75 static void SaveDWORD(HKEY hKey, LPCTSTR pszValueName, DWORD dwValue)
76 {
77     RegSetValueEx(hKey, pszValueName, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
78 }
79 
80 
81 void LoadSettings(void)
82 {
83     HKEY  hKey;
84     LONG  lRes;
85 
86     Settings = FactoryDefaults;
87 
88     lRes = RegCreateKeyEx(
89             HKEY_CURRENT_USER,
90             _T("Software\\Microsoft\\ScreenSavers\\Ssstars"),
91             0,
92             _T(""),
93             0,
94             KEY_READ,
95             NULL,
96             &hKey,
97             NULL);
98 
99     if (lRes != ERROR_SUCCESS)
100         return;
101 
102     Settings.uiNumStars = QueryDWORD(hKey, _T("NumberOfStars"),  Settings.uiNumStars);
103     Settings.uiSpeed    = QueryDWORD(hKey, _T("Speed"),          Settings.uiSpeed);
104     Settings.uiRotation = QueryDWORD(hKey, _T("TypeOfRotation"), Settings.uiRotation);
105 
106     Settings.bDoBlending      = QueryDWORD(hKey, _T("DoBlending"),      Settings.bDoBlending);
107     Settings.bFinePerspective = QueryDWORD(hKey, _T("FinePerspective"), Settings.bFinePerspective);
108     Settings.bEnableFiltering = QueryDWORD(hKey, _T("EnableFiltering"), Settings.bEnableFiltering);
109     Settings.bSmoothShading   = QueryDWORD(hKey, _T("SmoothShading"),   Settings.bSmoothShading);
110 
111     // Check the number of stars to be in range
112     if (Settings.uiNumStars < MIN_STARS)
113         Settings.uiNumStars = MIN_STARS;
114     else
115     if (Settings.uiNumStars > MAX_STARS)
116         Settings.uiNumStars = MAX_STARS;
117 
118     // Check the speed to be in range
119     if (Settings.uiSpeed < MIN_SPEED)
120         Settings.uiSpeed = MIN_SPEED;
121     else
122     if (Settings.uiSpeed > MAX_SPEED)
123         Settings.uiSpeed = MAX_SPEED;
124 
125     // Check type of rotation to be in range
126     if (Settings.uiRotation != ROTATION_NONE &&
127         Settings.uiRotation != ROTATION_LINEAR &&
128         Settings.uiRotation != ROTATION_PERIODIC)
129         Settings.uiRotation = ROTATION_PERIODIC;
130 
131     RegCloseKey(hKey);
132 }
133 
134 void SaveSettings(void)
135 {
136     HKEY  hKey;
137     LONG  lRes;
138 
139     lRes = RegCreateKeyEx(
140             HKEY_CURRENT_USER,
141             _T("Software\\Microsoft\\ScreenSavers\\Ssstars"),
142             0,
143             _T(""),
144             0,
145             KEY_WRITE,
146             NULL,
147             &hKey,
148             NULL);
149 
150     if (lRes != ERROR_SUCCESS)
151         return;
152 
153     SaveDWORD(hKey, _T("NumberOfStars"),  Settings.uiNumStars);
154     SaveDWORD(hKey, _T("Speed"),          Settings.uiSpeed);
155     SaveDWORD(hKey, _T("TypeOfRotation"), Settings.uiRotation);
156 
157     SaveDWORD(hKey, _T("DoBlending"),      Settings.bDoBlending);
158     SaveDWORD(hKey, _T("FinePerspective"), Settings.bFinePerspective);
159     SaveDWORD(hKey, _T("EnableFiltering"), Settings.bEnableFiltering);
160     SaveDWORD(hKey, _T("SmoothShading"),   Settings.bSmoothShading);
161 
162     RegCloseKey(hKey);
163 }
164 
165 static void SetupControls(HWND hWnd)
166 {
167     TCHAR     Strings[256];
168     HINSTANCE hInstance;
169     UINT      x, gap;
170     LOGFONT   lf;
171     HFONT     hFont;
172     HBITMAP   hCosmos;
173     HDC       hDC, hMemDC;
174     HGDIOBJ   hOldBmp, hOldFnt;
175     SIZE      sizeReactOS;
176     SIZE      sizeStarfield;
177     BITMAP    bm;
178 
179     hInstance = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
180 
181     SendDlgItemMessage(hWnd, IDC_SLIDER_NUM_OF_STARS, TBM_SETRANGE, FALSE, MAKELPARAM(MIN_STARS, MAX_STARS));
182 
183     SendDlgItemMessage(hWnd, IDC_SLIDER_SPEED, TBM_SETRANGE, FALSE, MAKELPARAM(1, 100));
184 
185     for (x = 0; x < ROTATION_ITEMS; x++)
186     {
187         LoadString(hInstance, RotoStrings[x], Strings, sizeof(Strings)/sizeof(TCHAR));
188         SendDlgItemMessage(hWnd, IDC_COMBO_ROTATION, CB_ADDSTRING, 0, (LPARAM)Strings);
189     }
190 
191     hCosmos = LoadImage(hInstance, MAKEINTRESOURCE(IDB_COSMOS), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
192 
193     hDC = GetDC(hWnd);
194     hMemDC = CreateCompatibleDC(hDC);
195 
196     // Create the font for the title
197     ZeroMemory(&lf, sizeof(lf));
198 
199     lf.lfWeight  = FW_THIN;
200     lf.lfCharSet = ANSI_CHARSET;
201     lf.lfQuality = PROOF_QUALITY;
202     lf.lfHeight  = 36;
203     _tcscpy(lf.lfFaceName, _T("Tahoma"));
204 
205     hFont = CreateFontIndirect(&lf);
206 
207     hOldBmp = SelectObject(hMemDC, hCosmos);
208     hOldFnt = SelectObject(hMemDC, hFont);
209 
210     SetBkMode(hMemDC, TRANSPARENT);
211     SetTextColor(hMemDC, RGB(0xFF, 0xFF, 0xFF));
212 
213     x = LoadString(hInstance, IDS_DESCRIPTION, Strings, sizeof(Strings)/sizeof(TCHAR));
214 
215     GetTextExtentPoint32(hMemDC, _T("ReactOS"), 7, &sizeReactOS);
216     GetTextExtentPoint32(hMemDC, Strings,       x, &sizeStarfield);
217 
218     GetObject(hCosmos, sizeof(BITMAP), &bm);
219 
220     gap = bm.bmHeight - sizeReactOS.cy - sizeStarfield.cy;
221 
222     TextOut(hMemDC, 16, gap * 2 / 5, _T("ReactOS"), 7);
223     TextOut(hMemDC, 16, gap * 3 / 5 + sizeReactOS.cy, Strings, x);
224 
225     SelectObject(hMemDC, hOldBmp);
226     SelectObject(hMemDC, hOldFnt);
227 
228     DeleteObject(hFont);
229 
230     DeleteDC(hMemDC);
231     ReleaseDC(hWnd, hDC);
232 
233     SendDlgItemMessage(hWnd, IDC_IMAGE_COSMOS, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hCosmos);
234 }
235 
236 static void ApplySettings(HWND hWnd)
237 {
238     SendDlgItemMessage(hWnd, IDC_SLIDER_NUM_OF_STARS, TBM_SETPOS, TRUE, Settings.uiNumStars);
239     SetDlgItemInt(hWnd, IDC_TEXT_NUM_OF_STARS, Settings.uiNumStars, FALSE);
240 
241     SendDlgItemMessage(hWnd, IDC_SLIDER_SPEED, TBM_SETPOS, TRUE, Settings.uiSpeed);
242     SetDlgItemInt(hWnd, IDC_TEXT_SPEED, Settings.uiSpeed, FALSE);
243 
244     SendDlgItemMessage(hWnd, IDC_COMBO_ROTATION, CB_SETCURSEL, (WPARAM)Settings.uiRotation, 0);
245 
246     SendDlgItemMessage(hWnd, IDC_CHECK_DOBLENDING,  BM_SETCHECK, (WPARAM)Settings.bDoBlending, 0);
247     SendDlgItemMessage(hWnd, IDC_CHECK_PERSPECTIVE, BM_SETCHECK, (WPARAM)Settings.bFinePerspective, 0);
248     SendDlgItemMessage(hWnd, IDC_CHECK_FILTERING,   BM_SETCHECK, (WPARAM)Settings.bEnableFiltering, 0);
249     SendDlgItemMessage(hWnd, IDC_CHECK_SHADING,     BM_SETCHECK, (WPARAM)Settings.bSmoothShading, 0);
250 }
251 
252 static void ReadSettings(HWND hWnd)
253 {
254     Settings.uiNumStars = SendDlgItemMessage(hWnd, IDC_SLIDER_NUM_OF_STARS, TBM_GETPOS, 0, 0);
255     SetDlgItemInt(hWnd, IDC_TEXT_NUM_OF_STARS, Settings.uiNumStars, FALSE);
256 
257     Settings.uiSpeed = SendDlgItemMessage(hWnd, IDC_SLIDER_SPEED, TBM_GETPOS, 0, 0);
258     SetDlgItemInt(hWnd, IDC_TEXT_SPEED, Settings.uiSpeed, FALSE);
259 
260     Settings.uiRotation = SendDlgItemMessage(hWnd, IDC_COMBO_ROTATION, CB_GETCURSEL, 0, 0);
261 
262     Settings.bDoBlending      = SendDlgItemMessage(hWnd, IDC_CHECK_DOBLENDING,  BM_GETCHECK, 0, 0);
263     Settings.bFinePerspective = SendDlgItemMessage(hWnd, IDC_CHECK_PERSPECTIVE, BM_GETCHECK, 0, 0);
264     Settings.bEnableFiltering = SendDlgItemMessage(hWnd, IDC_CHECK_FILTERING,   BM_GETCHECK, 0, 0);
265     Settings.bSmoothShading   = SendDlgItemMessage(hWnd, IDC_CHECK_SHADING,     BM_GETCHECK, 0, 0);
266 }
267 
268 static BOOL OnCommandAbout(HWND hWnd)
269 {
270     HINSTANCE hInstance;
271     HICON     hIcon;
272     TCHAR     szAppName[256];
273     TCHAR     szAuthor[256];
274     TCHAR     szLicense[1024];
275 
276     hInstance = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
277 
278     hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_STARFIELD));
279 
280     LoadString(hInstance, IDS_DESCRIPTION, szAppName, SIZEOF(szAppName));
281     LoadString(hInstance, IDS_AUTHOR,      szAuthor,  SIZEOF(szAuthor));
282     LoadString(hInstance, IDS_LICENSE,     szLicense, SIZEOF(szLicense));
283 
284     _tcscat(szAppName, _T("#"));
285     _tcscat(szAppName, szAuthor);
286 
287     ShellAbout(hWnd, szAppName, szLicense, hIcon);
288 
289     return TRUE;
290 }
291 
292 //
293 // Dialogbox procedure for Configuration window
294 //
295 BOOL CALLBACK ScreenSaverConfigureDialog(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
296 {
297     switch (uMsg) {
298     case WM_INITDIALOG:
299         LoadSettings();
300         SetupControls(hDlg);
301         ApplySettings(hDlg);
302         return TRUE;
303 
304     case WM_COMMAND:
305         switch (LOWORD( wParam )) {
306 
307         case IDOK:
308             // Write configuration
309             SaveSettings();
310 
311             // Fall down...
312         case IDCANCEL:
313             EndDialog( hDlg, LOWORD( wParam ));
314             return TRUE;
315 
316         case IDC_BUTTON_ABOUT:
317             return OnCommandAbout(hDlg);
318         }
319 
320     case WM_HSCROLL:
321         ReadSettings(hDlg);
322         return TRUE;
323 
324     }
325 
326     return FALSE;
327 }
328 
329 BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
330 {
331     InitCommonControls();
332 
333     return TRUE;
334 }
335 
336