9 #define WIN_STYLE WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME
17 struct wgt_widget *wlist;
20 int (*cb_close)(struct wgt_window*);
27 struct wgt_window *win;
28 struct wgt_widget *next;
35 wgt_callback cb_click;
36 wgt_callback cb_modify;
40 static LRESULT WINAPI event_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam);
41 static struct wgt_widget *find_widget(struct wgt_window *win, HWND handle);
44 void *wgt_window_handle(struct wgt_window *win)
49 void *wgt_widget_handle(struct wgt_widget *w)
54 unsigned int wgt_window_xid(struct wgt_window *win)
59 unsigned int wgt_widget_xid(struct wgt_widget *w)
65 struct wgt_window *wgt_window(const char *title, int width, int height)
67 struct wgt_window *win;
74 if(!(win = calloc(1, sizeof *win))) {
75 fprintf(stderr, "wgl_create_window: failed to allocate window structure\n");
78 win->close_quit = 1; /* by default quit when the window closes */
81 if(tlen > sizeof win->cname - 10) {
82 tlen = sizeof win->cname - 10;
84 strcpy(win->cname, "WGTCLASS-");
85 memcpy(win->cname + 9, title, tlen);
86 win->cname[tlen + 9] = 0;
88 hinst = GetModuleHandle(0);
90 memset(&wc, 0, sizeof wc);
92 wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
93 wc.hCursor = LoadCursor(0, IDC_ARROW);
94 wc.hIcon = LoadIcon(0, IDI_APPLICATION);
95 wc.lpszClassName = win->cname;
96 wc.lpfnWndProc = event_handler;
98 if(!RegisterClass(&wc)) {
99 fprintf(stderr, "wgt_create_window: failed to register window class\n");
103 rect.left = rect.top = 0;
105 rect.bottom = height;
106 AdjustWindowRect(&rect, WIN_STYLE, FALSE);
108 if(!(win->handle = CreateWindow(win->cname, title, WIN_STYLE, CW_USEDEFAULT,
109 CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top,
111 fprintf(stderr, "wgt_create_window: failed to create window\n");
112 UnregisterClass(title, hinst);
115 win->dc = GetDC(win->handle);
117 if(!SetWindowLong(win->handle, GWL_USERDATA, (long)win) && (err = GetLastError())) {
118 fprintf(stderr, "wgt_create_window: failed to store window user data (err: %d)\n", (int)err);
119 UnregisterClass(title, hinst);
120 DestroyWindow(win->handle);
123 ShowWindow(win->handle, 1);
125 GetWindowRect(win->handle, &rect);
127 win->rect.x = rect.left;
128 win->rect.y = rect.top;
129 win->rect.width = rect.right - rect.left;
130 win->rect.height = rect.bottom - rect.top;
135 void wgt_destroy_window(struct wgt_window *win)
138 struct wgt_widget *w = win->wlist;
139 win->wlist = win->wlist->next;
140 wgt_destroy_widget(w);
145 ReleaseDC(win->handle, win->dc);
146 DestroyWindow(win->handle);
147 UnregisterClass(win->cname, GetModuleHandle(0));
151 void wgt_free_window(struct wgt_window *win)
153 wgt_destroy_window(win);
157 void wgt_destroy_widget(struct wgt_widget *w)
159 DestroyWindow(w->handle);
163 void wgt_resize_window(struct wgt_window *win, int width, int height)
167 win->rect.width = width;
168 win->rect.height = height;
170 rect.left = win->rect.x;
171 rect.top = win->rect.y;
172 rect.right = rect.left + width;
173 rect.bottom = rect.top + height;
174 if(AdjustWindowRect(&rect, WIN_STYLE, FALSE)) {
175 width = rect.right - rect.left;
176 height = rect.bottom - rect.top;
178 MoveWindow(win->handle, win->rect.x, win->rect.y, width, height, TRUE);
181 void wgt_quit_on_close(struct wgt_window *win, int quit)
183 win->close_quit = quit;
186 void wgt_close_action(struct wgt_window *win, int (*func)(struct wgt_window*))
188 win->cb_close = func;
191 void wgt_enable_widget(struct wgt_widget *w)
194 EnableWindow(w->handle, 1);
197 void wgt_disable_widget(struct wgt_widget *w)
200 EnableWindow(w->handle, 0);
203 int wgt_widget_enabled(struct wgt_widget *w)
208 struct wgt_window *wgt_widget_window(struct wgt_widget *w)
213 struct wgt_rect *wgt_widget_rect(struct wgt_widget *w, struct wgt_rect *rect)
221 void wgt_move_widget(struct wgt_widget *w, int x, int y)
223 MoveWindow(w->handle, x, y, w->rect.width, w->rect.height, TRUE);
228 void wgt_resize_widget(struct wgt_widget *w, int width, int height)
230 MoveWindow(w->handle, w->rect.x, w->rect.y, width, height, TRUE);
231 w->rect.width = width;
232 w->rect.height = height;
235 int wgt_xpos_after(struct wgt_widget *w, int pad)
237 if(pad == WGT_AUTO) {
240 return w->rect.x + w->rect.width + pad;
243 int wgt_ypos_after(struct wgt_widget *w, int pad)
245 if(pad == WGT_AUTO) {
248 return w->rect.y + w->rect.height + pad;
251 int wgt_string_size(struct wgt_window *win, const char *s, struct wgt_rect *rect)
255 GetTextExtentPoint32(win->dc, (char*)s, strlen(s), &sz);
257 rect->x = rect->y = 0;
259 rect->height = sz.cy;
265 struct wgt_widget *wgt_label(struct wgt_window *win, const char *text, int x, int y)
267 struct wgt_widget *w;
268 struct wgt_rect textsz;
270 if(!(w = calloc(1, sizeof *w))) {
271 fprintf(stderr, "wgt_label: failed to allocate widget structure\n");
276 wgt_string_size(win, text, &textsz);
278 if(!(w->handle = CreateWindow("STATIC", text, WS_CHILD | WS_VISIBLE | SS_SIMPLE,
279 x, y, textsz.width, textsz.height, win->handle, 0, GetModuleHandle(0), 0))) {
280 fprintf(stderr, "wgt_label: failed to create window\n");
287 w->rect.width = textsz.width;
288 w->rect.height = textsz.height;
290 w->next = win->wlist;
295 struct wgt_widget *wgt_button(struct wgt_window *win, const char *text, int x, int y,
296 int width, int height, wgt_callback clickfunc)
298 struct wgt_widget *w;
299 struct wgt_rect textsz;
301 if(!(w = calloc(1, sizeof *w))) {
302 fprintf(stderr, "wgt_button: failed to allocate widget structure\n");
307 if(width < 0 || height < 0) {
308 wgt_string_size(win, text, &textsz);
309 if(width < 0) width = textsz.width * 5 / 3;
310 if(height < 0) height = textsz.height * 10 / 7;
313 if(!(w->handle = CreateWindow("BUTTON", text, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
314 x, y, width, height, win->handle, 0, GetModuleHandle(0), 0))) {
315 fprintf(stderr, "wgt_button: failed to create window\n");
322 w->rect.width = width;
323 w->rect.height = height;
325 w->cb_click = clickfunc;
326 w->next = win->wlist;
331 struct wgt_widget *wgt_checkbox(struct wgt_window *win, const char *text, int on,
332 int x, int y, int width, int height, wgt_callback modfunc)
334 struct wgt_widget *w;
335 struct wgt_rect textsz;
338 if(!(w = calloc(1, sizeof *w))) {
339 fprintf(stderr, "wgt_checkbox: failed to allocate widget structure\n");
344 check_width = GetSystemMetrics(SM_CXMENUCHECK);
346 if(width < 0 || height < 0) {
347 wgt_string_size(win, text, &textsz);
348 if(width < 0) width = textsz.width + check_width + 10;
349 if(height < 0) height = textsz.height;
352 if(!(w->handle = CreateWindow("BUTTON", text, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
353 x, y, width, height, win->handle, 0, GetModuleHandle(0), 0))) {
354 fprintf(stderr, "wgt_checkbox: failed to create window\n");
358 SendMessage(w->handle, BM_SETCHECK, on ? BST_CHECKED : BST_UNCHECKED, 0);
362 w->rect.width = width;
363 w->rect.height = height;
365 w->cb_click = modfunc; /* BN_CLICKED is sent for checkbox state changes */
366 w->next = win->wlist;
371 static void combosize(struct wgt_window *win, HWND cbwnd, const char **items, int num_items,
372 int width, int height, struct wgt_rect *sz)
374 int i, max_width, sum_height;
375 struct wgt_rect textsz;
377 wgt_string_size(win, "00", &textsz);
378 max_width = width < 0 && width != WGT_AUTO ? -width : textsz.width;
380 /* first get the height of the editbox */
381 sum_height = SendMessage(cbwnd, CB_GETITEMHEIGHT, -1, 0);
383 /* then add the height of the dropdown list items */
384 /* XXX I can't figure out why, but it's not sufficient to show all items
385 * without some more height, so let's double it...
388 sum_height += SendMessage(cbwnd, CB_GETITEMHEIGHT, 0, 0) * num_items;
389 sum_height += GetSystemMetrics(SM_CYEDGE) * 2;
393 for(i=0; i<num_items; i++) {
394 wgt_string_size(win, items[i], &textsz);
395 if(textsz.width > max_width) max_width = textsz.width;
397 sbar_width = GetSystemMetrics(SM_CXVSCROLL);
398 width = max_width + sbar_width + GetSystemMetrics(SM_CXEDGE) * 2;
400 if(height < 0) height = sum_height;
406 struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num_items,
407 int sel, int x, int y, int width, int height, wgt_callback modfunc)
409 struct wgt_widget *w;
410 struct wgt_rect rect;
412 if(!(w = calloc(1, sizeof *w))) {
413 fprintf(stderr, "wgt_combo: failed to allocate widget structure\n");
418 if(!(w->handle = CreateWindow("COMBOBOX", items[0] ? items[0] : "",
419 WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
420 x, y, 16, 16, win->handle, 0, GetModuleHandle(0), 0))) {
421 fprintf(stderr, "wgt_combo: failed to create window\n");
426 combosize(win, w->handle, items, num_items, width, height, &rect);
429 w->rect.width = rect.width;
430 w->rect.height = rect.y; /* single line height for layout purposes */
431 MoveWindow(w->handle, x, y, rect.width, rect.height, FALSE);
433 wgt_combo_setitems(w, items, num_items);
436 if(sel >= num_items) sel = num_items - 1;
438 SendMessage(w->handle, CB_SETCURSEL, sel, 0);
441 w->cb_modify = modfunc;
442 w->next = win->wlist;
447 struct wgt_widget *wgt_progbar(struct wgt_window *win, int x, int y, int width, int height, int p)
449 struct wgt_widget *w;
450 INITCOMMONCONTROLSEX commctrl;
452 commctrl.dwSize = sizeof commctrl;
453 commctrl.dwICC = ICC_PROGRESS_CLASS;
454 InitCommonControlsEx(&commctrl);
456 if(!(w = calloc(1, sizeof *w))) {
457 fprintf(stderr, "wgt_progbar: failed to allocate widget structure\n");
463 height = GetSystemMetrics(SM_CYVSCROLL);
466 if(!(w->handle = CreateWindow(PROGRESS_CLASS, 0, WS_CHILD | WS_VISIBLE, x, y,
467 width, height, win->handle, 0, GetModuleHandle(0), 0))) {
468 fprintf(stderr, "wgt_progbar: failed to create window\n");
474 SendMessage(w->handle, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
475 SendMessage(w->handle, PBM_SETSTEP, 1, 0);
477 SendMessage(w->handle, PBM_SETPOS, p, 0);
481 w->rect.width = width;
482 w->rect.height = height;
484 w->next = win->wlist;
489 void wgt_set_text(struct wgt_widget *w, const char *text)
491 SendMessage(w->handle, WM_SETTEXT, 0, (long)text);
493 w->rect.width = wgt_string_size(w->win, text, 0);
494 MoveWindow(w->handle, w->rect.x, w->rect.y, w->rect.width, w->rect.height, TRUE);
497 void wgt_checkbox_check(struct wgt_widget *w)
499 SendMessage(w->handle, BM_SETCHECK, BST_CHECKED, 0);
502 void wgt_checkbox_uncheck(struct wgt_widget *w)
504 SendMessage(w->handle, BM_SETCHECK, BST_UNCHECKED, 0);
507 int wgt_checkbox_checked(struct wgt_widget *w)
509 return SendMessage(w->handle, BM_GETCHECK, 0, 0) == BST_CHECKED;
512 int wgt_combo_setitems(struct wgt_widget *w, const char **items, int num_items)
516 struct wgt_rect size;
518 if(!(newit = malloc(num_items * sizeof *newit))) {
519 fprintf(stderr, "wgt_combo_setitems: failed to allocate item list\n");
522 for(i=0; i<num_items; i++) {
523 if(!(newit[i] = strdup(items[i]))) {
524 fprintf(stderr, "wgt_combo_setitems: failed to allocate item\n");
533 for(i=0; i<w->num_items; i++) {
534 free(w->itemlist[i]);
537 SendMessage(w->handle, CB_RESETCONTENT, 0, 0);
540 w->num_items = num_items;
542 for(i=0; i<num_items; i++) {
543 SendMessage(w->handle, CB_ADDSTRING, 0, (long)w->itemlist[i]);
546 combosize(w->win, w->handle, items, num_items, w->rect.width, WGT_AUTO, &size);
547 MoveWindow(w->handle, w->rect.x, w->rect.y, w->rect.width, size.height, TRUE);
549 SendMessage(w->handle, CB_SETCURSEL, 0, 0);
553 int wgt_combo_selected(struct wgt_widget *w)
555 int sel = SendMessage(w->handle, CB_GETCURSEL, 0, 0);
556 if(sel == CB_ERR) return -1;
560 const char *wgt_get_combo_item(struct wgt_widget *w, int idx)
562 if(idx < 0 || idx >= w->num_items) {
565 return w->itemlist[idx];
568 void wgt_set_progress(struct wgt_widget *w, int p)
570 SendMessage(w->handle, PBM_SETPOS, p, 0);
573 static LRESULT WINAPI event_handler(HWND wnd, unsigned int msg, WPARAM wparam, LPARAM lparam)
576 struct wgt_widget *w;
577 struct wgt_window *win;
579 win = (struct wgt_window*)GetWindowLong(wnd, GWL_USERDATA);
583 if(!win->cb_close || win->cb_close(win)) {
585 int quit = win->close_quit;
586 wgt_destroy_window(win);
587 memset(win, 0, sizeof *win);
588 win->close_quit = quit;
596 if(win && win->close_quit) {
602 if(!win || !(w = find_widget(win, (HWND)lparam))) {
605 ncode = HIWORD(wparam);
625 return DefWindowProc(wnd, msg, wparam, lparam);
630 static struct wgt_widget *find_widget(struct wgt_window *win, HWND handle)
632 struct wgt_widget *w;
636 if(w->handle == handle) return w;