14 struct wgt_widget *wlist;
21 struct wgt_window *win;
22 struct wgt_widget *next;
27 wgt_callback cb_click;
28 wgt_callback cb_modify;
32 static LRESULT WINAPI event_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam);
33 static struct wgt_widget *find_widget(struct wgt_window *win, HWND handle);
35 struct wgt_window *wgt_window(const char *title, int width, int height)
37 struct wgt_window *win;
44 if(!(win = malloc(sizeof *win))) {
45 fprintf(stderr, "wgl_create_window: failed to allocate window structure\n");
51 if(tlen > sizeof win->cname - 10) {
52 tlen = sizeof win->cname - 10;
54 strcpy(win->cname, "WGTCLASS-");
55 memcpy(win->cname + 9, title, tlen);
56 win->cname[tlen + 9] = 0;
58 hinst = GetModuleHandle(0);
60 memset(&wc, 0, sizeof wc);
62 wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
63 wc.hCursor = LoadCursor(0, IDC_ARROW);
64 wc.hIcon = LoadIcon(0, IDI_APPLICATION);
65 wc.lpszClassName = win->cname;
66 wc.lpfnWndProc = event_handler;
68 if(!RegisterClass(&wc)) {
69 fprintf(stderr, "wgt_create_window: failed to register window class\n");
73 if(!(win->handle = CreateWindow(win->cname, title, WS_OVERLAPPEDWINDOW,
74 CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0, 0, hinst, 0))) {
75 fprintf(stderr, "wgt_create_window: failed to create window\n");
76 UnregisterClass(title, hinst);
79 win->dc = GetDC(win->handle);
81 if(!SetWindowLong(win->handle, GWL_USERDATA, (long)win) && (err = GetLastError())) {
82 fprintf(stderr, "wgt_create_window: failed to store window user data (err: %d)\n", (int)err);
83 UnregisterClass(title, hinst);
84 DestroyWindow(win->handle);
87 ShowWindow(win->handle, 1);
89 GetWindowRect(win->handle, &rect);
91 win->rect.x = rect.left;
92 win->rect.y = rect.top;
93 win->rect.width = rect.right - rect.left;
94 win->rect.height = rect.bottom - rect.top;
99 void wgt_destroy_window(struct wgt_window *win)
102 struct wgt_widget *w = win->wlist;
103 win->wlist = win->wlist->next;
104 wgt_destroy_widget(w);
108 ReleaseDC(win->handle, win->dc);
109 DestroyWindow(win->handle);
110 UnregisterClass(win->cname, GetModuleHandle(0));
115 void wgt_destroy_widget(struct wgt_widget *w)
117 DestroyWindow(w->handle);
121 struct wgt_window *wgt_widget_window(struct wgt_widget *w)
126 struct wgt_rect *wgt_widget_rect(struct wgt_widget *w, struct wgt_rect *rect)
134 int wgt_xpos_after(struct wgt_widget *w, int pad)
136 if(pad == WGT_AUTO) {
139 return w->rect.x + w->rect.width + pad;
142 int wgt_ypos_after(struct wgt_widget *w, int pad)
144 if(pad == WGT_AUTO) {
147 return w->rect.y + w->rect.height + pad;
150 int wgt_string_size(struct wgt_window *win, const char *s, struct wgt_rect *rect)
154 GetTextExtentPoint32(win->dc, (char*)s, strlen(s), &sz);
156 rect->x = rect->y = 0;
158 rect->height = sz.cy;
164 struct wgt_widget *wgt_label(struct wgt_window *win, const char *text, int x, int y)
166 struct wgt_widget *w;
167 struct wgt_rect textsz;
169 if(!(w = calloc(1, sizeof *w))) {
170 fprintf(stderr, "wgt_label: failed to allocate widget structure\n");
175 wgt_string_size(win, text, &textsz);
177 if(!(w->handle = CreateWindow("STATIC", text, WS_CHILD | WS_VISIBLE | SS_SIMPLE,
178 x, y, textsz.width, textsz.height, win->handle, 0, GetModuleHandle(0), 0))) {
179 fprintf(stderr, "wgt_label: failed to create window\n");
186 w->rect.width = textsz.width;
187 w->rect.height = textsz.height;
189 w->next = win->wlist;
194 struct wgt_widget *wgt_button(struct wgt_window *win, const char *text, int x, int y,
195 int width, int height, wgt_callback clickfunc)
197 struct wgt_widget *w;
198 struct wgt_rect textsz;
200 if(!(w = calloc(1, sizeof *w))) {
201 fprintf(stderr, "wgt_button: failed to allocate widget structure\n");
206 if(width < 0 || height < 0) {
207 wgt_string_size(win, text, &textsz);
208 if(width < 0) width = textsz.width * 5 / 3;
209 if(height < 0) height = textsz.height * 10 / 7;
212 if(!(w->handle = CreateWindow("BUTTON", text, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
213 x, y, width, height, win->handle, 0, GetModuleHandle(0), 0))) {
214 fprintf(stderr, "wgt_button: failed to create window\n");
221 w->rect.width = width;
222 w->rect.height = height;
224 w->cb_click = clickfunc;
225 w->next = win->wlist;
230 struct wgt_widget *wgt_checkbox(struct wgt_window *win, const char *text, int on,
231 int x, int y, int width, int height, wgt_callback modfunc)
233 struct wgt_widget *w;
234 struct wgt_rect textsz;
237 if(!(w = calloc(1, sizeof *w))) {
238 fprintf(stderr, "wgt_checkbox: failed to allocate widget structure\n");
243 check_width = GetSystemMetrics(SM_CXMENUCHECK);
245 if(width < 0 || height < 0) {
246 wgt_string_size(win, text, &textsz);
247 if(width < 0) width = textsz.width + check_width + 10;
248 if(height < 0) height = textsz.height;
251 if(!(w->handle = CreateWindow("BUTTON", text, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
252 x, y, width, height, win->handle, 0, GetModuleHandle(0), 0))) {
253 fprintf(stderr, "wgt_checkbox: failed to create window\n");
260 w->rect.width = width;
261 w->rect.height = height;
263 w->cb_click = modfunc; /* BN_CLICKED is sent for checkbox state changes */
264 w->next = win->wlist;
269 struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num_items,
270 int sel, int x, int y, int width, int height, wgt_callback modfunc)
272 int i, max_width, max_height, sum_height, res;
273 struct wgt_widget *w;
274 struct wgt_rect textsz;
276 if(!(w = calloc(1, sizeof *w))) {
277 fprintf(stderr, "wgt_combo: failed to allocate widget structure\n");
282 if(!(w->itemlist = malloc(num_items * sizeof *w->itemlist))) {
283 fprintf(stderr, "wgt_combo: failed to allocate item list\n");
288 max_width = max_height = sum_height = 0;
290 for(i=0; i<num_items; i++) {
291 wgt_string_size(win, items[i], &textsz);
292 if(textsz.width > max_width) max_width = textsz.width;
293 if(textsz.height > max_height) max_height = textsz.height;
294 sum_height += textsz.height;
296 if(width < 0) width = max_width * 3 / 2;
297 if(height < 0) height = sum_height * 2;
300 if(!(w->handle = CreateWindow("COMBOBOX", items[0],
301 WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
302 x, y, width, height, win->handle, 0, GetModuleHandle(0), 0))) {
303 fprintf(stderr, "wgt_combo: failed to create window\n");
308 for(i=0; i<num_items; i++) {
309 if(!(w->itemlist[i] = strdup(items[i]))) {
310 fprintf(stderr, "wgt_combo: failed to allocate item\n");
311 while(--i >= 0) free(w->itemlist[i]);
312 DestroyWindow(w->handle);
317 if((res = SendMessage(w->handle, CB_ADDSTRING, 0, (long)items[i])) != i) {
318 fprintf(stderr, "wgt_combo: failed to add item\n");
321 w->num_items = num_items;
324 if(sel >= num_items) sel = num_items - 1;
325 SendMessage(w->handle, CB_SETCURSEL, sel, 0);
329 w->rect.width = width;
330 w->rect.height = max_height;
332 w->cb_modify = modfunc;
333 w->next = win->wlist;
338 int wgt_combo_selected(struct wgt_widget *w)
340 int sel = SendMessage(w->handle, CB_GETCURSEL, 0, 0);
341 if(sel == CB_ERR) return -1;
345 const char *wgt_get_combo_item(struct wgt_widget *w, int idx)
347 if(idx < 0 || idx >= w->num_items) {
350 return w->itemlist[idx];
353 static LRESULT WINAPI event_handler(HWND wnd, unsigned int msg, WPARAM wparam, LPARAM lparam)
356 struct wgt_widget *w;
357 struct wgt_window *win;
359 win = (struct wgt_window*)GetWindowLong(wnd, GWL_USERDATA);
368 if(!win || !(w = find_widget(win, (HWND)lparam))) {
371 ncode = HIWORD(wparam);
391 return DefWindowProc(wnd, msg, wparam, lparam);
396 static struct wgt_widget *find_widget(struct wgt_window *win, HWND handle)
398 struct wgt_widget *w;
402 if(w->handle == handle) return w;