Big sprawling dialog-box commit covering all sorts of things.
[u/mdw/putty] / winctrls.c
index dc931c8..05c8f0d 100644 (file)
@@ -1331,7 +1331,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
     char shortcuts[MAX_SHORTCUTS_PER_CTRL];
     int nshortcuts;
     char *escaped;
-    int i, base_id, num_ids;
+    int i, actual_base_id, base_id, num_ids;
     void *data;
 
     base_id = *id;
@@ -1479,6 +1479,9 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
        memset(shortcuts, NO_SHORTCUT, lenof(shortcuts));
        nshortcuts = 0;
 
+       /* Almost all controls start at base_id. */
+       actual_base_id = base_id;
+
        /*
         * Now we're ready to actually create the control, by
         * switching on its type.
@@ -1569,8 +1572,10 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
            escaped = shortcut_escape(ctrl->button.label,
                                      ctrl->button.shortcut);
            shortcuts[nshortcuts++] = ctrl->button.shortcut;
+           if (ctrl->button.iscancel)
+               actual_base_id = IDCANCEL;
            num_ids = 1;
-           button(&pos, escaped, base_id, ctrl->button.isdefault);
+           button(&pos, escaped, actual_base_id, ctrl->button.isdefault);
            sfree(escaped);
            break;
          case CTRL_LISTBOX:
@@ -1658,13 +1663,14 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
            struct winctrl *c = smalloc(sizeof(struct winctrl));
 
            c->ctrl = ctrl;
-           c->base_id = base_id;
+           c->base_id = actual_base_id;
            c->num_ids = num_ids;
            c->data = data;
            memcpy(c->shortcuts, shortcuts, sizeof(shortcuts));
            winctrl_add(wc, c);
            winctrl_add_shortcuts(dp, c);
-           base_id += num_ids;
+           if (actual_base_id == base_id)
+               base_id += num_ids;
        }
 
        if (colstart >= 0) {
@@ -1705,10 +1711,10 @@ static void winctrl_set_focus(union control *ctrl, struct dlgparam *dp,
     }
 }
 
-union control *dlg_last_focused(void *dlg)
+union control *dlg_last_focused(union control *ctrl, void *dlg)
 {
     struct dlgparam *dp = (struct dlgparam *)dlg;
-    return dp->lastfocused;
+    return dp->focused == ctrl ? dp->lastfocused : dp->focused;
 }
 
 /*
@@ -2424,3 +2430,99 @@ int dlg_coloursel_results(union control *ctrl, void *dlg,
     } else
        return 0;
 }
+
+struct perctrl_privdata {
+    union control *ctrl;
+    void *data;
+    int needs_free;
+};
+
+static int perctrl_privdata_cmp(void *av, void *bv)
+{
+    struct perctrl_privdata *a = (struct perctrl_privdata *)av;
+    struct perctrl_privdata *b = (struct perctrl_privdata *)bv;
+    if (a->ctrl < b->ctrl)
+       return -1;
+    else if (a->ctrl > b->ctrl)
+       return +1;
+    return 0;
+}
+
+void dp_init(struct dlgparam *dp)
+{
+    dp->nctrltrees = 0;
+    dp->data = NULL;
+    dp->ended = FALSE;
+    dp->focused = dp->lastfocused = NULL;
+    memset(dp->shortcuts, 0, sizeof(dp->shortcuts));
+    dp->hwnd = NULL;
+    dp->errtitle = NULL;
+    dp->privdata = newtree234(perctrl_privdata_cmp);
+}
+
+void dp_add_tree(struct dlgparam *dp, struct winctrls *wc)
+{
+    assert(dp->nctrltrees < lenof(dp->controltrees));
+    dp->controltrees[dp->nctrltrees++] = wc;
+}
+
+void dp_cleanup(struct dlgparam *dp)
+{
+    struct perctrl_privdata *p;
+
+    if (dp->privdata) {
+       while ( (p = index234(dp->privdata, 0)) != NULL ) {
+           del234(dp->privdata, p);
+           if (p->needs_free)
+               sfree(p->data);
+           sfree(p);
+       }
+       freetree234(dp->privdata);
+       dp->privdata = NULL;
+    }
+}
+
+void *dlg_get_privdata(union control *ctrl, void *dlg)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct perctrl_privdata tmp, *p;
+    tmp.ctrl = ctrl;
+    p = find234(dp->privdata, &tmp, NULL);
+    if (p)
+       return p->data;
+    else
+       return NULL;
+}
+
+void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct perctrl_privdata tmp, *p;
+    tmp.ctrl = ctrl;
+    p = find234(dp->privdata, &tmp, NULL);
+    if (!p) {
+       p = smalloc(sizeof(struct perctrl_privdata));
+       p->ctrl = ctrl;
+       p->needs_free = FALSE;
+       add234(dp->privdata, p);
+    }
+    p->data = ptr;
+}
+
+void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct perctrl_privdata tmp, *p;
+    tmp.ctrl = ctrl;
+    p = find234(dp->privdata, &tmp, NULL);
+    if (!p) {
+       p = smalloc(sizeof(struct perctrl_privdata));
+       p->ctrl = ctrl;
+       p->needs_free = FALSE;
+       add234(dp->privdata, p);
+    }
+    assert(!p->needs_free);
+    p->needs_free = TRUE;
+    p->data = smalloc(size);
+    return p->data;
+}