foo
[instimg] / src / widgets.c
index 8ed6d89..2ad9983 100644 (file)
@@ -24,6 +24,8 @@ struct wgt_widget {
        char **itemlist;
        int num_items;
 
+       int disabled;
+
        wgt_callback cb_click;
        wgt_callback cb_modify;
 };
@@ -59,7 +61,7 @@ struct wgt_window *wgt_window(const char *title, int width, int height)
 
        memset(&wc, 0, sizeof wc);
        wc.hInstance = hinst;
-       wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
+       wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
        wc.hCursor = LoadCursor(0, IDC_ARROW);
        wc.hIcon = LoadIcon(0, IDI_APPLICATION);
        wc.lpszClassName = win->cname;
@@ -118,6 +120,23 @@ void wgt_destroy_widget(struct wgt_widget *w)
        free(w->itemlist);
 }
 
+void wgt_enable_widget(struct wgt_widget *w)
+{
+       w->disabled = 0;
+       EnableWindow(w->handle, 1);
+}
+
+void wgt_disable_widget(struct wgt_widget *w)
+{
+       w->disabled = 1;
+       EnableWindow(w->handle, 0);
+}
+
+int wgt_widget_enabled(struct wgt_widget *w)
+{
+       return !w->disabled;
+}
+
 struct wgt_window *wgt_widget_window(struct wgt_widget *w)
 {
        return w->win;
@@ -232,6 +251,7 @@ struct wgt_widget *wgt_checkbox(struct wgt_window *win, const char *text, int on
 {
        struct wgt_widget *w;
        struct wgt_rect textsz;
+       int check_width;
 
        if(!(w = calloc(1, sizeof *w))) {
                fprintf(stderr, "wgt_checkbox: failed to allocate widget structure\n");
@@ -239,9 +259,11 @@ struct wgt_widget *wgt_checkbox(struct wgt_window *win, const char *text, int on
        }
        w->win = win;
 
+       check_width = GetSystemMetrics(SM_CXMENUCHECK);
+
        if(width < 0 || height < 0) {
                wgt_string_size(win, text, &textsz);
-               if(width < 0) width = textsz.width + 32;        /* XXX */
+               if(width < 0) width = textsz.width + check_width + 10;
                if(height < 0) height = textsz.height;
        }
 
@@ -257,18 +279,43 @@ struct wgt_widget *wgt_checkbox(struct wgt_window *win, const char *text, int on
        w->rect.width = width;
        w->rect.height = height;
 
-       w->cb_modify = modfunc;
+       w->cb_click = modfunc;  /* BN_CLICKED is sent for checkbox state changes */
        w->next = win->wlist;
        win->wlist = w;
        return w;
 }
 
+static void combosize(struct wgt_window *win, const char **items, int num_items,
+               int width, int height, struct wgt_rect *sz)
+{
+       int i, max_width, max_height, sum_height;
+       struct wgt_rect textsz;
+
+       wgt_string_size(win, "00", &textsz);
+       max_width = width < 0 && width != WGT_AUTO ? -width : textsz.width;
+       max_height = height < 0 && height != WGT_AUTO ? -height : textsz.height;
+       sum_height = num_items ? 0 : max_height;
+
+       for(i=0; i<num_items; i++) {
+               wgt_string_size(win, items[i], &textsz);
+               if(textsz.width > max_width) max_width = textsz.width;
+               if(textsz.height > max_height) max_height = textsz.height;
+               sum_height += textsz.height;
+       }
+       if(width < 0) width = max_width * 3 / 2;
+       if(height < 0) height = sum_height * 2;
+
+       sz->width = width;
+       sz->y = max_height;
+       sz->height = height;
+}
+
 struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num_items,
                        int sel, int x, int y, int width, int height, wgt_callback modfunc)
 {
-       int i, max_width, max_height, sum_height, res;
+       int i, res;
        struct wgt_widget *w;
-       struct wgt_rect textsz;
+       struct wgt_rect rect;
 
        if(!(w = calloc(1, sizeof *w))) {
                fprintf(stderr, "wgt_combo: failed to allocate widget structure\n");
@@ -282,21 +329,11 @@ struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num
                return 0;
        }
 
-       max_width = max_height = sum_height = 0;
+       combosize(win, items, num_items, width, height, &rect);
 
-       for(i=0; i<num_items; i++) {
-               wgt_string_size(win, items[i], &textsz);
-               if(textsz.width > max_width) max_width = textsz.width;
-               if(textsz.height > max_height) max_height = textsz.height;
-               sum_height += textsz.height;
-       }
-       if(width < 0) width = max_width * 3 / 2;
-       if(height < 0) height = sum_height * 2;
-
-
-       if(!(w->handle = CreateWindow("COMBOBOX", items[0],
+       if(!(w->handle = CreateWindow("COMBOBOX", items[0] ? items[0] : "",
                        WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
-                       x, y, width, height, win->handle, 0, GetModuleHandle(0), 0))) {
+                       x, y, rect.width, rect.height, win->handle, 0, GetModuleHandle(0), 0))) {
                fprintf(stderr, "wgt_combo: failed to create window\n");
                free(w);
                return 0;
@@ -319,12 +356,14 @@ struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num
 
        if(sel < 0) sel = 0;
        if(sel >= num_items) sel = num_items - 1;
-       SendMessage(w->handle, CB_SETCURSEL, sel, 0);
+       if(sel >= 0) {
+               SendMessage(w->handle, CB_SETCURSEL, sel, 0);
+       }
 
        w->rect.x = x;
        w->rect.y = y;
-       w->rect.width = width;
-       w->rect.height = max_height;
+       w->rect.width = rect.width;
+       w->rect.height = rect.y;        /* single line height for layout purposes */
 
        w->cb_modify = modfunc;
        w->next = win->wlist;
@@ -332,6 +371,60 @@ struct wgt_widget *wgt_combo(struct wgt_window *win, const char **items, int num
        return w;
 }
 
+void wgt_checkbox_check(struct wgt_widget *w)
+{
+       SendMessage(w->handle, BM_SETCHECK, BST_CHECKED, 0);
+}
+
+void wgt_checkbox_uncheck(struct wgt_widget *w)
+{
+       SendMessage(w->handle, BM_SETCHECK, BST_UNCHECKED, 0);
+}
+
+int wgt_checkbox_checked(struct wgt_widget *w)
+{
+       return SendMessage(w->handle, BM_GETCHECK, 0, 0) == BST_CHECKED;
+}
+
+int wgt_combo_setitems(struct wgt_widget *w, const char **items, int num_items)
+{
+       int i;
+       char **newit;
+       struct wgt_rect size;
+
+       if(!(newit = malloc(num_items * sizeof *newit))) {
+               fprintf(stderr, "wgt_combo_setitems: failed to allocate item list\n");
+               return -1;
+       }
+       for(i=0; i<num_items; i++) {
+               if(!(newit[i] = strdup(items[i]))) {
+                       fprintf(stderr, "wgt_combo_setitems: failed to allocate item\n");
+                       while(--i >= 0) {
+                               free(newit[i]);
+                       }
+                       free(newit);
+                       return -1;
+               }
+       }
+
+       for(i=0; i<w->num_items; i++) {
+               free(w->itemlist[i]);
+       }
+       free(w->itemlist);
+       SendMessage(w->handle, CB_RESETCONTENT, 0, 0);
+
+       w->itemlist = newit;
+       w->num_items = num_items;
+
+       for(i=0; i<num_items; i++) {
+               SendMessage(w->handle, CB_ADDSTRING, 0, (long)w->itemlist[i]);
+       }
+
+       combosize(w->win, items, num_items, w->rect.width, WGT_AUTO, &size);
+       MoveWindow(w->handle, w->rect.x, w->rect.y, w->rect.width, size.height, TRUE);
+       return 0;
+}
+
 int wgt_combo_selected(struct wgt_widget *w)
 {
        int sel = SendMessage(w->handle, CB_GETCURSEL, 0, 0);
@@ -383,7 +476,7 @@ static LRESULT WINAPI event_handler(HWND wnd, unsigned int msg, WPARAM wparam, L
                default:
                        break;
                }
-       
+
        default:
                return DefWindowProc(wnd, msg, wparam, lparam);
        }