14 struct wgt_widget *wlist;
21 struct wgt_window *win;
22 struct wgt_widget *next;
29 wgt_callback cb_click;
30 wgt_callback cb_modify;
34 static LRESULT WINAPI event_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam);
35 static struct wgt_widget *find_widget(struct wgt_window *win, HWND handle);
37 struct wgt_window *wgt_window(const char *title, int width, int height)
39 struct wgt_window *win;
46 if(!(win = malloc(sizeof *win))) {
47 fprintf(stderr, "wgl_create_window: failed to allocate window structure\n");
53 if(tlen > sizeof win->cname - 10) {
54 tlen = sizeof win->cname - 10;
56 strcpy(win->cname, "WGTCLASS-");
57 memcpy(win->cname + 9, title, tlen);
58 win->cname[tlen + 9] = 0;
60 hinst = GetModuleHandle(0);
62 memset(&wc, 0, sizeof wc);
64 wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
65 wc.hCursor = LoadCursor(0, IDC_ARROW);
66 wc.hIcon = LoadIcon(0, IDI_APPLICATION);
67 wc.lpszClassName = win->cname;
68 wc.lpfnWndProc = event_handler;
70 if(!RegisterClass(&wc)) {
71 fprintf(stderr, "wgt_create_window: failed to register window class\n");
75 if(!(win->handle = CreateWindow(win->cname, title, WS_OVERLAPPEDWINDOW,
76 CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0, 0, hinst, 0))) {
77 fprintf(stderr, "wgt_create_window: failed to create window\n");
78 UnregisterClass(title, hinst);
81 win->dc = GetDC(win->handle);
83 if(!SetWindowLong(win->handle, GWL_USERDATA, (long)win) && (err = GetLastError())) {
84 fprintf(stderr, "wgt_create_window: failed to store window user data (err: %d)\n", (int)err);
85 UnregisterClass(title, hinst);
86 DestroyWindow(win->handle);
89 ShowWindow(win->handle, 1);
91 GetWindowRect(win->handle, &rect);
93 win->rect.x = rect.left;
94 win->rect.y = rect.top;
95 win->rect.width = rect.right - rect.left;
96 win->rect.height = rect.bottom - rect.top;
101 void wgt_destroy_window(struct wgt_window *win)
104 struct wgt_widget *w = win->wlist;
105 win->wlist = win->wlist->next;
106 wgt_destroy_widget(w);
110 ReleaseDC(win->handle, win->dc);
111 DestroyWindow(win->handle);
112 UnregisterClass(win->cname, GetModuleHandle(0));
117 void wgt_destroy_widget(struct wgt_widget *w)
119 DestroyWindow(w->handle);
123 void wgt_enable_widget(struct wgt_widget *w)
126 EnableWindow(w->handle, 1);
129 void wgt_disable_widget(struct wgt_widget *w)
132 EnableWindow(w->handle, 0);
135 int wgt_widget_enabled(struct wgt_widget *w)
140 struct wgt_window *wgt_widget_window(struct wgt_widget *w)
145 struct wgt_rect *wgt_widget_rect(struct wgt_widget *w, struct wgt_rect *rect)
153 int wgt_xpos_after(struct wgt_widget *w, int pad)
155 if(pad == WGT_AUTO) {
158 return w->rect.x + w->rect.width + pad;
161 int wgt_ypos_after(struct wgt_widget *w, int pad)
163 if(pad == WGT_AUTO) {
166 return w->rect.y + w->rect.height + pad;
169 int wgt_string_size(struct wgt_window *win, const char *s, struct wgt_rect *rect)
173 GetTextExtentPoint32(win->dc, (char*)s, strlen(s), &sz);
175 rect->x = rect->y = 0;
177 rect->height = sz.cy;
183 struct wgt_widget *wgt_label(struct wgt_window *win, const char *text, int x, int y)
185 struct wgt_widget *w;
186 struct wgt_rect textsz;
188 if(!(w = calloc(1, sizeof *w))) {
189 fprintf(stderr, "wgt_label: failed to allocate widget structure\n");
194 wgt_string_size(win, text, &textsz);
196 if(!(w->handle = CreateWindow("STATIC", text, WS_CHILD | WS_VISIBLE | SS_SIMPLE,
197 x, y, textsz.width, textsz.height, win->handle, 0, GetModuleHandle(0), 0))) {
198 fprintf(stderr, "wgt_label: failed to create window\n");
205 w->rect.width = textsz.width;
206 w->rect.height = textsz.height;
208 w->next = win->wlist;
213 struct wgt_widget *wgt_button(struct wgt_window *win, const char *text, int x, int y,
214 int width, int height, wgt_callback clickfunc)
216 struct wgt_widget *w;
217 struct wgt_rect textsz;
219 if(!(w = calloc(1, sizeof *w))) {
220 fprintf(stderr, "wgt_button: failed to allocate widget structure\n");
225 if(width < 0 || height < 0) {
226 wgt_string_size(win, text, &textsz);
227 if(width < 0) width = textsz.width * 5 / 3;
228 if(height < 0) height = textsz.height * 10 / 7;
231 if(!(w->handle = CreateWindow("BUTTON", text, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
232 x, y, width, height, win->handle, 0, GetModuleHandle(0), 0))) {
233 fprintf(stderr, "wgt_button: failed to create window\n");
240 w->rect.width = width;
241 w->rect.height = height;
243 w->cb_click = clickfunc;
244 w->next = win->wlist;
249 struct wgt_widget *wgt_checkbox(struct wgt_window *win, const char *text, int on,
250 int x, int y, int width, int height, wgt_callback modfunc)
252 struct wgt_widget *w;
253 struct wgt_rect textsz;
256 if(!(w = calloc(1, sizeof *w))) {
257 fprintf(stderr, "wgt_checkbox: failed to allocate widget structure\n");
262 check_width = GetSystemMetrics(SM_CXMENUCHECK);
264 if(width < 0 || height < 0) {
265 wgt_string_size(win, text, &textsz);
266 if(width < 0) width = textsz.width + check_width + 10;
267 if(height < 0) height = textsz.height;
270 if(!(w->handle = CreateWindow("BUTTON", text, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
271 x, y, width, height, win->handle, 0, GetModuleHandle(0), 0))) {
272 fprintf(stderr, "wgt_checkbox: failed to create window\n");
279 w->rect.width = width;
280 w->rect.height = height;
282 w->cb_click = modfunc; /* BN_CLICKED is sent for checkbox state changes */
283 w->next = win->wlist;
288 static void combosize(struct wgt_window *win, const char **items, int num_items,
289 int width, int height, struct wgt_rect *sz)
291 int i, max_width, max_height, sum_height;
292 struct wgt_rect textsz;
294 wgt_string_size(win, "00", &textsz);
295 max_width = width < 0 && width != WGT_AUTO ? -width : textsz.width;
296 max_height = height < 0 && height != WGT_AUTO ? -height : textsz.height;
297 sum_height = num_items ? 0 : max_height;
299 for(i=0; i<num_items; i++) {
300 wgt_string_size(win, items[i], &textsz);
301 if(textsz.width > max_width) max_width = textsz.width;
302 if(textsz.height > max_height) max_height = textsz.height;
303 sum_height += textsz.height;
305 if(width < 0) width = max_width * 3 / 2;
306 if(height < 0) height = sum_height * 2;
313 struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num_items,
314 int sel, int x, int y, int width, int height, wgt_callback modfunc)
317 struct wgt_widget *w;
318 struct wgt_rect rect;
320 if(!(w = calloc(1, sizeof *w))) {
321 fprintf(stderr, "wgt_combo: failed to allocate widget structure\n");
326 if(!(w->itemlist = malloc(num_items * sizeof *w->itemlist))) {
327 fprintf(stderr, "wgt_combo: failed to allocate item list\n");
332 combosize(win, items, num_items, width, height, &rect);
334 if(!(w->handle = CreateWindow("COMBOBOX", items[0] ? items[0] : "",
335 WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
336 x, y, rect.width, rect.height, win->handle, 0, GetModuleHandle(0), 0))) {
337 fprintf(stderr, "wgt_combo: failed to create window\n");
342 for(i=0; i<num_items; i++) {
343 if(!(w->itemlist[i] = strdup(items[i]))) {
344 fprintf(stderr, "wgt_combo: failed to allocate item\n");
345 while(--i >= 0) free(w->itemlist[i]);
346 DestroyWindow(w->handle);
351 if((res = SendMessage(w->handle, CB_ADDSTRING, 0, (long)items[i])) != i) {
352 fprintf(stderr, "wgt_combo: failed to add item\n");
355 w->num_items = num_items;
358 if(sel >= num_items) sel = num_items - 1;
360 SendMessage(w->handle, CB_SETCURSEL, sel, 0);
365 w->rect.width = rect.width;
366 w->rect.height = rect.y; /* single line height for layout purposes */
368 w->cb_modify = modfunc;
369 w->next = win->wlist;
374 void wgt_checkbox_check(struct wgt_widget *w)
376 SendMessage(w->handle, BM_SETCHECK, BST_CHECKED, 0);
379 void wgt_checkbox_uncheck(struct wgt_widget *w)
381 SendMessage(w->handle, BM_SETCHECK, BST_UNCHECKED, 0);
384 int wgt_checkbox_checked(struct wgt_widget *w)
386 return SendMessage(w->handle, BM_GETCHECK, 0, 0) == BST_CHECKED;
389 int wgt_combo_setitems(struct wgt_widget *w, const char **items, int num_items)
393 struct wgt_rect size;
395 if(!(newit = malloc(num_items * sizeof *newit))) {
396 fprintf(stderr, "wgt_combo_setitems: failed to allocate item list\n");
399 for(i=0; i<num_items; i++) {
400 if(!(newit[i] = strdup(items[i]))) {
401 fprintf(stderr, "wgt_combo_setitems: failed to allocate item\n");
410 for(i=0; i<w->num_items; i++) {
411 free(w->itemlist[i]);
414 SendMessage(w->handle, CB_RESETCONTENT, 0, 0);
417 w->num_items = num_items;
419 for(i=0; i<num_items; i++) {
420 SendMessage(w->handle, CB_ADDSTRING, 0, (long)w->itemlist[i]);
423 combosize(w->win, items, num_items, w->rect.width, WGT_AUTO, &size);
424 MoveWindow(w->handle, w->rect.x, w->rect.y, w->rect.width, size.height, TRUE);
428 int wgt_combo_selected(struct wgt_widget *w)
430 int sel = SendMessage(w->handle, CB_GETCURSEL, 0, 0);
431 if(sel == CB_ERR) return -1;
435 const char *wgt_get_combo_item(struct wgt_widget *w, int idx)
437 if(idx < 0 || idx >= w->num_items) {
440 return w->itemlist[idx];
443 static LRESULT WINAPI event_handler(HWND wnd, unsigned int msg, WPARAM wparam, LPARAM lparam)
446 struct wgt_widget *w;
447 struct wgt_window *win;
449 win = (struct wgt_window*)GetWindowLong(wnd, GWL_USERDATA);
458 if(!win || !(w = find_widget(win, (HWND)lparam))) {
461 ncode = HIWORD(wparam);
481 return DefWindowProc(wnd, msg, wparam, lparam);
486 static struct wgt_widget *find_widget(struct wgt_window *win, HWND handle)
488 struct wgt_widget *w;
492 if(w->handle == handle) return w;