1 /* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
2 The author disclaims copyright to this source code. */
12 // Hmm, why have to redefine here (?!)
14 #define LVM_GETSELECTIONMARK (LVM_FIRST+66)
15 #define ListView_GetSelectionMark(w) (INT)SNDMSG((w),LVM_GETSELECTIONMARK,0,0)
20 int dx
= r
->right
- r
->left
;
27 int dy
= r
->bottom
- r
->top
;
32 void rect_set(RECT
*r
, int x
, int y
, int dx
, int dy
)
40 void win_set_font(HWND hwnd
, HFONT font
)
42 SendMessage(hwnd
, WM_SETFONT
, (WPARAM
)font
, 0);
45 int win_get_text_len(HWND hwnd
)
47 return (int)SendMessage(hwnd
, WM_GETTEXTLENGTH
, 0, 0);
50 void win_set_text(HWND hwnd
, const TCHAR
*txt
)
52 SendMessage(hwnd
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)txt
);
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
)
60 int cchTxtLen
= win_get_text_len(hwnd
);
61 TCHAR
* txt
= (TCHAR
*)malloc((cchTxtLen
+1)*sizeof(TCHAR
));
66 SendMessage(hwnd
, WM_GETTEXT
, cchTxtLen
+ 1, (LPARAM
)txt
);
71 void win_edit_set_selection(HWND hwnd
, DWORD selStart
, DWORD selEnd
)
73 SendMessage(hwnd
, EM_SETSEL
, (WPARAM
)selStart
, (WPARAM
)selEnd
);
76 void win_edit_select_all(HWND hwnd
)
78 win_edit_set_selection(hwnd
, 0, -1);
81 LRESULT
lv_delete_all_items(HWND hwnd
)
83 return SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
86 LRESULT
lv_set_items_count(HWND hwnd
, int items_count
)
89 ListView_SetItemCount(hwnd
, items_count
);
91 return ListView_SetItemCount(hwnd
, items_count
);
95 int lv_get_items_count(HWND hwnd
)
97 LRESULT count
= ListView_GetItemCount(hwnd
);
103 LRESULT
lv_insert_column(HWND hwnd
, int col
, LVCOLUMN
*lvc
)
105 return SendMessage(hwnd
, LVM_INSERTCOLUMN
, col
, (LPARAM
)lvc
);
108 LRESULT
lv_set_column(HWND hwnd
, int col
, LVCOLUMN
*lvc
)
110 return SendMessage(hwnd
, LVM_SETCOLUMN
, col
, (LPARAM
)lvc
);
113 LRESULT
lv_set_column_dx(HWND hwnd
, int col
, int dx
)
115 return ListView_SetColumnWidth(hwnd
, col
, dx
);
118 LRESULT
lv_insert_item(HWND hwnd
, int row
, LVITEM
*lvi
)
122 return SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)lvi
);
125 LRESULT
lb_delete_string(HWND hwnd
, int pos
)
127 return SendMessage(hwnd
, LB_DELETESTRING
, pos
, 0);
130 LRESULT
lb_delete_all_items(HWND hwnd
)
133 LRESULT remaining_count
;
135 remaining_count
= lb_delete_string(hwnd
, 0);
136 if ((LB_ERR
== remaining_count
) || (0 == remaining_count
))
144 count
= lb_get_items_count(hwnd
);
148 for (i
=count
-1; i
--; i
>=0) {
149 lb_delete_string(hwnd
, i
);
151 assert(0 == lb_get_items_count(hwnd
);
156 LRESULT
lb_set_items_count(HWND hwnd
, int items_count
)
158 return SendMessage(hwnd
, LB_SETCOUNT
, items_count
, 0);
162 LRESULT
lb_get_items_count(HWND hwnd
)
164 return SendMessage(hwnd
, LB_GETCOUNT
, 0, 0);
167 LRESULT
lb_insert_item_text(HWND hwnd
, int row
, const TCHAR
*txt
)
169 return SendMessage(hwnd
, LB_INSERTSTRING
, (WPARAM
)row
, (LPARAM
)txt
);
172 LRESULT
lb_append_string_no_sort(HWND hwnd
, const TCHAR
*txt
)
174 return lb_insert_item_text(hwnd
, -1, txt
);
177 /* lb_get_selection and lb_set_selection only work for single-selection listbox */
178 LRESULT
lb_get_selection(HWND hwnd
)
180 return SendMessage(hwnd
, LB_GETCURSEL
, 0, 0);
183 LRESULT
lb_set_selection(HWND hwnd
, int item
)
186 return SendMessage(hwnd
, LB_SETCURSEL
, (WPARAM
)item
, 0);
189 LRESULT
lv_insert_item_text(HWND hwnd
, int row
, const TCHAR
*txt
)
195 return -1; /* means failure */
196 lvi
.mask
= LVIF_TEXT
;
197 lvi
.pszText
= (LPTSTR
)txt
;
198 return lv_insert_item(hwnd
, row
, &lvi
);
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
)
206 int selected_count
= ListView_GetSelectedCount(hwnd
);
207 assert(selected_count
<= 1);
208 if (0 == selected_count
)
210 selection
= ListView_GetSelectionMark(hwnd
);
214 int font_get_dy_from_dc(HDC hdc
, HFONT font
)
220 font_prev
= (HFONT
)SelectObject(hdc
, font
);
221 GetTextMetrics(hdc
, &tm
);
222 font_dy
= tm
.tmAscent
+ tm
.tmDescent
;
223 SelectObject(hdc
, font_prev
);
227 int font_get_dy(HWND hwnd
, HFONT font
)
234 font_dy
= font_get_dy_from_dc(hdc
, font
);
235 ReleaseDC(hwnd
, hdc
);
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)
247 SHSipInfo(SPI_GETSIPINFO
, 0, &info
, 0);
248 info
.fdwFlags
|= SIPF_DISABLECOMPLETION
;
249 SHSipInfo(SPI_SETSIPINFO
, 0, &info
, 0);
252 void sip_completion_enable(void)
256 SHSipInfo(SPI_GETSIPINFO
, 0, &info
, 0);
257 info
.fdwFlags
&= ~SIPF_DISABLECOMPLETION
;
258 SHSipInfo(SPI_SETSIPINFO
, 0, &info
, 0);
262 void launch_url(const TCHAR
*url
)
264 SHELLEXECUTEINFO sei
;
270 ZeroMemory(&sei
, sizeof(sei
));
271 sei
.cbSize
= sizeof(sei
);
272 sei
.fMask
= SEE_MASK_FLAG_NO_UI
;
273 sei
.lpVerb
= TEXT("open");
275 sei
.nShow
= SW_SHOWNORMAL
;
277 res
= ShellExecuteEx(&sei
);
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 */
288 /* this doesn't seem to be defined on sm 2002 */
289 #define SPECIAL_FOLDER_PATH CSIDL_APPDATA
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
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
305 TCHAR
*get_app_data_folder_path(BOOL f_create
)
307 #ifdef SPECIAL_FOLDER_PATH
309 TCHAR path
[MAX_PATH
];
311 f_ok
= SHGetSpecialFolderPath(NULL
, path
, SPECIAL_FOLDER_PATH
, f_create
);
313 return tstr_dup(path
);
315 return tstr_dup(_T(""));
317 /* if all else fails, just use root ("\") directory */
318 return (TCHAR
*)str_dup(_T("")); /* @note: mingw doesn't support tstr_dup */
322 void screen_get_dx_dy(int *dx_out
, int *dy_out
)
325 *dx_out
= GetSystemMetrics(SM_CXSCREEN
);
327 *dy_out
= GetSystemMetrics(SM_CYSCREEN
);
330 int screen_get_dx(void)
332 return (int)GetSystemMetrics(SM_CXSCREEN
);
335 int screen_get_dy(void)
337 return (int)GetSystemMetrics(SM_CYSCREEN
);
340 int screen_get_menu_dy(void)
342 return GetSystemMetrics(SM_CYMENU
);
345 int screen_get_caption_dy(void)
347 return GetSystemMetrics(SM_CYCAPTION
);
350 /* given a string id 'strId' from resources, get the string in a dynamically
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
)
359 TCHAR buf
[BUF_CCH_SIZE
] = {0};
360 LoadString(NULL
, str_id
, buf
, BUF_CCH_SIZE
);
361 if (0 == tstr_len(buf
))
366 return (TCHAR
*)str_dup(buf
); /* @note: mingw doesn't support tstr_dup */
369 const TCHAR
*load_string(int str_id
)
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);
381 str
= (const TCHAR
*)res
;
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
)
395 if (ERROR_SUCCESS
!= RegCreateKeyEx(key_class
, key_path
, 0, NULL
, 0, 0, NULL
, &hkey
, NULL
))
399 size
= (DWORD
)(tstr_len(key_value
)*sizeof(TCHAR
));
400 if (ERROR_SUCCESS
!= RegSetValueEx(hkey
, key_name
, 0, REG_SZ
, (LPBYTE
)key_value
, size
))
407 int regkey_set_dword(HKEY key_class
, TCHAR
*key_path
, TCHAR
*key_name
, DWORD key_value
)
413 if (ERROR_SUCCESS
!= RegCreateKeyEx(key_class
, key_path
, 0, NULL
, 0, 0, NULL
, &hkey
, NULL
))
417 size
= sizeof(DWORD
);
418 if (ERROR_SUCCESS
!= RegSetValueEx(hkey
, key_name
, 0, REG_DWORD
, (LPBYTE
)&key_value
, size
))
425 static void rect_client_to_screen(RECT
*r
, HWND hwnd
)
427 POINT p1
= {r
->left
, r
->top
};
428 POINT p2
= {r
->right
, r
->bottom
};
429 ClientToScreen(hwnd
, &p1
);
430 ClientToScreen(hwnd
, &p2
);
437 void paint_round_rect_around_hwnd(HDC hdc
, HWND hwnd_edit_parent
, HWND hwnd_edit
, COLORREF col
)
444 GetClientRect(hwnd_edit
, &r
);
445 br
= CreateSolidBrush(col
);
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);
457 SelectObject(hdc
, br_prev
);
459 SelectObject(hdc
, pen_prev
);