Change the translation of the "Help" menu item to "?", so that the menu can be displa...
[reactos.git] / rosapps / smartpdf / baseutils / win_util.c
1 /* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
2 The author disclaims copyright to this source code. */
3 #include "base_util.h"
4 #include "win_util.h"
5 #include "tstr_util.h"
6
7 #ifdef _WIN32_WCE
8 #include <aygshell.h>
9 #include <Shlobj.h>
10 #endif
11
12 // Hmm, why have to redefine here (?!)
13 #ifdef __GNUC__
14 #define LVM_GETSELECTIONMARK (LVM_FIRST+66)
15 #define ListView_GetSelectionMark(w) (INT)SNDMSG((w),LVM_GETSELECTIONMARK,0,0)
16 #endif
17
18 int rect_dx(RECT *r)
19 {
20 int dx = r->right - r->left;
21 assert(dx >= 0);
22 return dx;
23 }
24
25 int rect_dy(RECT *r)
26 {
27 int dy = r->bottom - r->top;
28 assert(dy >= 0);
29 return dy;
30 }
31
32 void rect_set(RECT *r, int x, int y, int dx, int dy)
33 {
34 r->left = x;
35 r->top = y;
36 r->right = x + dx;
37 r->bottom = y + dy;
38 }
39
40 void win_set_font(HWND hwnd, HFONT font)
41 {
42 SendMessage(hwnd, WM_SETFONT, (WPARAM)font, 0);
43 }
44
45 int win_get_text_len(HWND hwnd)
46 {
47 return (int)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
48 }
49
50 void win_set_text(HWND hwnd, const TCHAR *txt)
51 {
52 SendMessage(hwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)txt);
53 }
54
55 /* return a text in edit control represented by hwnd
56 return NULL in case of error (couldn't allocate memory)
57 caller needs to free() the text */
58 TCHAR *win_get_text(HWND hwnd)
59 {
60 int cchTxtLen = win_get_text_len(hwnd);
61 TCHAR * txt = (TCHAR*)malloc((cchTxtLen+1)*sizeof(TCHAR));
62
63 if (NULL == txt)
64 return NULL;
65
66 SendMessage(hwnd, WM_GETTEXT, cchTxtLen + 1, (LPARAM)txt);
67 txt[cchTxtLen] = 0;
68 return txt;
69 }
70
71 void win_edit_set_selection(HWND hwnd, DWORD selStart, DWORD selEnd)
72 {
73 SendMessage(hwnd, EM_SETSEL, (WPARAM)selStart, (WPARAM)selEnd);
74 }
75
76 void win_edit_select_all(HWND hwnd)
77 {
78 win_edit_set_selection(hwnd, 0, -1);
79 }
80
81 LRESULT lv_delete_all_items(HWND hwnd)
82 {
83 return SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
84 }
85
86 LRESULT lv_set_items_count(HWND hwnd, int items_count)
87 {
88 #ifdef __GNUC__
89 ListView_SetItemCount(hwnd, items_count);
90 #else
91 return ListView_SetItemCount(hwnd, items_count);
92 #endif
93 }
94
95 int lv_get_items_count(HWND hwnd)
96 {
97 LRESULT count = ListView_GetItemCount(hwnd);
98 if (LB_ERR == count)
99 return 0;
100 return (int)count;
101 }
102
103 LRESULT lv_insert_column(HWND hwnd, int col, LVCOLUMN *lvc)
104 {
105 return SendMessage(hwnd, LVM_INSERTCOLUMN, col, (LPARAM)lvc);
106 }
107
108 LRESULT lv_set_column(HWND hwnd, int col, LVCOLUMN *lvc)
109 {
110 return SendMessage(hwnd, LVM_SETCOLUMN, col, (LPARAM)lvc);
111 }
112
113 LRESULT lv_set_column_dx(HWND hwnd, int col, int dx)
114 {
115 return ListView_SetColumnWidth(hwnd, col, dx);
116 }
117
118 LRESULT lv_insert_item(HWND hwnd, int row, LVITEM *lvi)
119 {
120 lvi->iItem = row;
121 lvi->iSubItem = 0;
122 return SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)lvi);
123 }
124
125 LRESULT lb_delete_string(HWND hwnd, int pos)
126 {
127 return SendMessage(hwnd, LB_DELETESTRING, pos, 0);
128 }
129
130 LRESULT lb_delete_all_items(HWND hwnd)
131 {
132 #if 1
133 LRESULT remaining_count;
134 for (;;) {
135 remaining_count = lb_delete_string(hwnd, 0);
136 if ((LB_ERR == remaining_count) || (0 == remaining_count))
137 break;
138 }
139 return 0;
140 #else
141 LRESULT count;
142 int i;
143
144 count = lb_get_items_count(hwnd);
145 if (LB_ERR == count)
146 return LB_ERR;
147
148 for (i=count-1; i--; i>=0) {
149 lb_delete_string(hwnd, i);
150 }
151 assert(0 == lb_get_items_count(hwnd);
152 #endif
153 }
154
155 #if 0
156 LRESULT lb_set_items_count(HWND hwnd, int items_count)
157 {
158 return SendMessage(hwnd, LB_SETCOUNT, items_count, 0);
159 }
160 #endif
161
162 LRESULT lb_get_items_count(HWND hwnd)
163 {
164 return SendMessage(hwnd, LB_GETCOUNT, 0, 0);
165 }
166
167 LRESULT lb_insert_item_text(HWND hwnd, int row, const TCHAR *txt)
168 {
169 return SendMessage(hwnd, LB_INSERTSTRING, (WPARAM)row, (LPARAM)txt);
170 }
171
172 LRESULT lb_append_string_no_sort(HWND hwnd, const TCHAR *txt)
173 {
174 return lb_insert_item_text(hwnd, -1, txt);
175 }
176
177 /* lb_get_selection and lb_set_selection only work for single-selection listbox */
178 LRESULT lb_get_selection(HWND hwnd)
179 {
180 return SendMessage(hwnd, LB_GETCURSEL, 0, 0);
181 }
182
183 LRESULT lb_set_selection(HWND hwnd, int item)
184 {
185 assert(item >= 0);
186 return SendMessage(hwnd, LB_SETCURSEL, (WPARAM)item, 0);
187 }
188
189 LRESULT lv_insert_item_text(HWND hwnd, int row, const TCHAR *txt)
190 {
191 LVITEM lvi = {0};
192
193 assert(txt);
194 if (!txt)
195 return -1; /* means failure */
196 lvi.mask = LVIF_TEXT;
197 lvi.pszText = (LPTSTR)txt;
198 return lv_insert_item(hwnd, row, &lvi);
199 }
200
201 /* Returns a selected item or -1 if no selection.
202 Assumes that the list is single-sel */
203 int lv_get_selection_pos(HWND hwnd)
204 {
205 int selection;
206 int selected_count = ListView_GetSelectedCount(hwnd);
207 assert(selected_count <= 1);
208 if (0 == selected_count)
209 return -1;
210 selection = ListView_GetSelectionMark(hwnd);
211 return selection;
212 }
213
214 int font_get_dy_from_dc(HDC hdc, HFONT font)
215 {
216 TEXTMETRIC tm;
217 HFONT font_prev;
218 int font_dy;
219
220 font_prev = (HFONT)SelectObject(hdc, font);
221 GetTextMetrics(hdc, &tm);
222 font_dy = tm.tmAscent + tm.tmDescent;
223 SelectObject(hdc, font_prev);
224 return font_dy;
225 }
226
227 int font_get_dy(HWND hwnd, HFONT font)
228 {
229 HDC hdc;
230 int font_dy = 0;
231
232 hdc = GetDC(hwnd);
233 if (hdc)
234 font_dy = font_get_dy_from_dc(hdc, font);
235 ReleaseDC(hwnd, hdc);
236 return font_dy;
237 }
238
239 #ifdef _WIN32_WCE
240 /* see http://pocketpcdn.com/articles/wordcompletion.html for details
241 edit boxes on pocket pc by default have spelling suggestion/completion.
242 Sometimes we want/need to disable that and this is a function to do it. */
243 void sip_completion_disable(void)
244 {
245 SIPINFO info;
246
247 SHSipInfo(SPI_GETSIPINFO, 0, &info, 0);
248 info.fdwFlags |= SIPF_DISABLECOMPLETION;
249 SHSipInfo(SPI_SETSIPINFO, 0, &info, 0);
250 }
251
252 void sip_completion_enable(void)
253 {
254 SIPINFO info;
255
256 SHSipInfo(SPI_GETSIPINFO, 0, &info, 0);
257 info.fdwFlags &= ~SIPF_DISABLECOMPLETION;
258 SHSipInfo(SPI_SETSIPINFO, 0, &info, 0);
259 }
260 #endif
261
262 void launch_url(const TCHAR *url)
263 {
264 SHELLEXECUTEINFO sei;
265 BOOL res;
266
267 if (NULL == url)
268 return;
269
270 ZeroMemory(&sei, sizeof(sei));
271 sei.cbSize = sizeof(sei);
272 sei.fMask = SEE_MASK_FLAG_NO_UI;
273 sei.lpVerb = TEXT("open");
274 sei.lpFile = url;
275 sei.nShow = SW_SHOWNORMAL;
276
277 res = ShellExecuteEx(&sei);
278 return;
279 }
280
281 /* On windows those are defined as:
282 #define CSIDL_PROGRAMS 0x0002
283 #define CSIDL_PERSONAL 0x0005
284 #define CSIDL_APPDATA 0x001a
285 see shlobj.h for more */
286
287 #ifdef CSIDL_APPDATA
288 /* this doesn't seem to be defined on sm 2002 */
289 #define SPECIAL_FOLDER_PATH CSIDL_APPDATA
290 #endif
291
292 #ifdef CSIDL_PERSONAL
293 /* this is defined on sm 2002 and goes to "\My Documents".
294 Not sure if I should use it */
295 #ifndef SPECIAL_FOLDER_PATH
296 #define SPECIAL_FOLDER_PATH CSIDL_PERSONAL
297 #endif
298 #endif
299
300 /* see http://www.opennetcf.org/Forums/post.asp?method=TopicQuote&TOPIC_ID=95&FORUM_ID=12
301 for more possibilities
302 return false on failure, true if ok. Even if returns false, it'll return root ("\")
303 directory so that clients can ignore failures from this function
304 */
305 TCHAR *get_app_data_folder_path(BOOL f_create)
306 {
307 #ifdef SPECIAL_FOLDER_PATH
308 BOOL f_ok;
309 TCHAR path[MAX_PATH];
310
311 f_ok = SHGetSpecialFolderPath(NULL, path, SPECIAL_FOLDER_PATH, f_create);
312 if (f_ok)
313 return tstr_dup(path);
314 else
315 return tstr_dup(_T(""));
316 #else
317 /* if all else fails, just use root ("\") directory */
318 return (TCHAR*)str_dup(_T("")); /* @note: mingw doesn't support tstr_dup */
319 #endif
320 }
321
322 void screen_get_dx_dy(int *dx_out, int *dy_out)
323 {
324 if (dx_out)
325 *dx_out = GetSystemMetrics(SM_CXSCREEN);
326 if (dy_out)
327 *dy_out = GetSystemMetrics(SM_CYSCREEN);
328 }
329
330 int screen_get_dx(void)
331 {
332 return (int)GetSystemMetrics(SM_CXSCREEN);
333 }
334
335 int screen_get_dy(void)
336 {
337 return (int)GetSystemMetrics(SM_CYSCREEN);
338 }
339
340 int screen_get_menu_dy(void)
341 {
342 return GetSystemMetrics(SM_CYMENU);
343 }
344
345 int screen_get_caption_dy(void)
346 {
347 return GetSystemMetrics(SM_CYCAPTION);
348 }
349
350 /* given a string id 'strId' from resources, get the string in a dynamically
351 allocated string.
352 Returns the string or NULL if error.
353 Caller needs to free() the string.
354 TODO: string is limited to BUF_CCH_SIZE. Could do it better by dynamically
355 allocating more memory if needed */
356 #define BUF_CCH_SIZE 256
357 TCHAR *load_string_dup(int str_id)
358 {
359 TCHAR buf[BUF_CCH_SIZE] = {0};
360 LoadString(NULL, str_id, buf, BUF_CCH_SIZE);
361 if (0 == tstr_len(buf))
362 {
363 assert(0);
364 return NULL;
365 }
366 return (TCHAR*)str_dup(buf); /* @note: mingw doesn't support tstr_dup */
367 }
368
369 const TCHAR *load_string(int str_id)
370 {
371 int res;
372 const TCHAR *str;
373
374 /* little-known hack: when lpBuffer is NULL, LoadString() returns
375 a pointer to a string, that can be cast to TCHAR * (LPCTSTR)
376 requires -n option to RC (resource compiler)
377 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdk40/html/cerefLoadString.asp */
378 res = LoadString(NULL, str_id, NULL, 0);
379 if (0 == res)
380 return NULL;
381 str = (const TCHAR*)res;
382 return str;
383 }
384
385 // A helper to set a string, null-terminated 'keyValue' for a given 'keyName'
386 // in 'keyPath'/'keyClass'
387 // if 'keyName' is NULL then we set the default value for 'keyPath'
388 // Returns false if there was any error (can be ignored)
389 int regkey_set_str(HKEY key_class, TCHAR *key_path, TCHAR *key_name, TCHAR *key_value)
390 {
391 HKEY hkey = NULL;
392 DWORD size = 0;
393 BOOL f_ok;
394
395 if (ERROR_SUCCESS != RegCreateKeyEx(key_class, key_path, 0, NULL, 0, 0, NULL, &hkey, NULL))
396 return FALSE;
397
398 f_ok = TRUE;
399 size = (DWORD)(tstr_len(key_value)*sizeof(TCHAR));
400 if (ERROR_SUCCESS != RegSetValueEx(hkey, key_name, 0, REG_SZ, (LPBYTE)key_value, size))
401 f_ok = FALSE;
402 RegCloseKey(hkey);
403
404 return f_ok;
405 }
406
407 int regkey_set_dword(HKEY key_class, TCHAR *key_path, TCHAR *key_name, DWORD key_value)
408 {
409 HKEY hkey = NULL;
410 DWORD size = 0;
411 BOOL f_ok;
412
413 if (ERROR_SUCCESS != RegCreateKeyEx(key_class, key_path, 0, NULL, 0, 0, NULL, &hkey, NULL))
414 return FALSE;
415
416 f_ok = TRUE;
417 size = sizeof(DWORD);
418 if (ERROR_SUCCESS != RegSetValueEx(hkey, key_name, 0, REG_DWORD, (LPBYTE)&key_value, size))
419 f_ok = FALSE;
420 RegCloseKey(hkey);
421
422 return f_ok;
423 }
424
425 static void rect_client_to_screen(RECT *r, HWND hwnd)
426 {
427 POINT p1 = {r->left, r->top};
428 POINT p2 = {r->right, r->bottom};
429 ClientToScreen(hwnd, &p1);
430 ClientToScreen(hwnd, &p2);
431 r->left = p1.x;
432 r->top = p1.y;
433 r->right = p2.x;
434 r->bottom = p2.y;
435 }
436
437 void paint_round_rect_around_hwnd(HDC hdc, HWND hwnd_edit_parent, HWND hwnd_edit, COLORREF col)
438 {
439 RECT r;
440 HBRUSH br;
441 HBRUSH br_prev;
442 HPEN pen;
443 HPEN pen_prev;
444 GetClientRect(hwnd_edit, &r);
445 br = CreateSolidBrush(col);
446 if (!br) return;
447 pen = CreatePen(PS_SOLID, 1, col);
448 pen_prev = SelectObject(hdc, pen);
449 br_prev = SelectObject(hdc, br);
450 rect_client_to_screen(&r, hwnd_edit_parent);
451 /* TODO: the roundness value should probably be calculated from the dy of the rect */
452 /* TODO: total hack: I manually adjust rectangle to values that fit g_hwnd_edit, as
453 found by experimentation. My mapping of coordinates isn't right (I think I need
454 mapping from window to window but even then it wouldn't explain -3 for y axis */
455 RoundRect(hdc, r.left+4, r.top-3, r.right+12, r.bottom-3, 8, 8);
456 if (br_prev)
457 SelectObject(hdc, br_prev);
458 if (pen_prev)
459 SelectObject(hdc, pen_prev);
460 DeleteObject(pen);
461 DeleteObject(br);
462 }
463