📄 winctrls.c
字号:
union control *ctrl = s->ctrls[i]; /* * Generic processing that pertains to all control types. * At the end of this if statement, we'll have produced * `ctrl' (a pointer to the control we have to create, or * think about creating, in this iteration of the loop), * `pos' (a suitable ctlpos with which to position it), and * `c' (a winctrl structure to receive details of the * dialog IDs). Or we'll have done a `continue', if it was * CTRL_COLUMNS and doesn't require any control creation at * all. */ if (ctrl->generic.type == CTRL_COLUMNS) { assert((ctrl->columns.ncols == 1) ^ (ncols == 1)); if (ncols == 1) { /* * We're splitting into multiple columns. */ int lpercent, rpercent, lx, rx, i; ncols = ctrl->columns.ncols; assert(ncols <= lenof(columns)); for (i = 1; i < ncols; i++) columns[i] = columns[0]; /* structure copy */ lpercent = 0; for (i = 0; i < ncols; i++) { rpercent = lpercent + ctrl->columns.percentages[i]; lx = columns[i].xoff + lpercent * (columns[i].width + GAPBETWEEN) / 100; rx = columns[i].xoff + rpercent * (columns[i].width + GAPBETWEEN) / 100; columns[i].xoff = lx; columns[i].width = rx - lx - GAPBETWEEN; lpercent = rpercent; } } else { /* * We're recombining the various columns into one. */ int maxy = columns[0].ypos; int i; for (i = 1; i < ncols; i++) if (maxy < columns[i].ypos) maxy = columns[i].ypos; ncols = 1; columns[0] = *cp; /* structure copy */ columns[0].ypos = maxy; } continue; } else if (ctrl->generic.type == CTRL_TABDELAY) { int i; assert(!ctrl->generic.tabdelay); ctrl = ctrl->tabdelay.ctrl; for (i = 0; i < ntabdelays; i++) if (tabdelayed[i] == ctrl) break; assert(i < ntabdelays); /* we have to have found it */ pos = tabdelays[i]; /* structure copy */ colstart = colspan = -1; /* indicate this was tab-delayed */ } else { /* * If it wasn't one of those, it's a genuine control; * so we'll have to compute a position for it now, by * checking its column span. */ int col; colstart = COLUMN_START(ctrl->generic.column); colspan = COLUMN_SPAN(ctrl->generic.column); pos = columns[colstart]; /* structure copy */ pos.width = columns[colstart+colspan-1].width + (columns[colstart+colspan-1].xoff - columns[colstart].xoff); for (col = colstart; col < colstart+colspan; col++) if (pos.ypos < columns[col].ypos) pos.ypos = columns[col].ypos; /* * If this control is to be tabdelayed, add it to the * tabdelay list, and unset pos.hwnd to inhibit actual * control creation. */ if (ctrl->generic.tabdelay) { assert(ntabdelays < lenof(tabdelays)); tabdelays[ntabdelays] = pos; /* structure copy */ tabdelayed[ntabdelays] = ctrl; ntabdelays++; pos.hwnd = NULL; } } /* Most controls don't need anything in c->data. */ data = NULL; /* And they all start off with no shortcuts registered. */ 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. */ switch (ctrl->generic.type) { case CTRL_TEXT: { char *wrapped, *escaped; int lines; num_ids = 1; wrapped = staticwrap(&pos, cp->hwnd, ctrl->generic.label, &lines); escaped = shortcut_escape(wrapped, NO_SHORTCUT); statictext(&pos, escaped, lines, base_id); sfree(escaped); sfree(wrapped); } break; case CTRL_EDITBOX: num_ids = 2; /* static, edit */ escaped = shortcut_escape(ctrl->editbox.label, ctrl->editbox.shortcut); shortcuts[nshortcuts++] = ctrl->editbox.shortcut; if (ctrl->editbox.percentwidth == 100) { if (ctrl->editbox.has_list) combobox(&pos, escaped, base_id, base_id+1); else multiedit(&pos, ctrl->editbox.password, escaped, base_id, base_id+1, 100, NULL); } else { if (ctrl->editbox.has_list) { staticcombo(&pos, escaped, base_id, base_id+1, ctrl->editbox.percentwidth); } else { (ctrl->editbox.password ? staticpassedit : staticedit) (&pos, escaped, base_id, base_id+1, ctrl->editbox.percentwidth); } } sfree(escaped); break; case CTRL_RADIO: num_ids = ctrl->radio.nbuttons + 1; /* label as well */ { struct radio *buttons; int i; escaped = shortcut_escape(ctrl->radio.label, ctrl->radio.shortcut); shortcuts[nshortcuts++] = ctrl->radio.shortcut; buttons = snewn(ctrl->radio.nbuttons, struct radio); for (i = 0; i < ctrl->radio.nbuttons; i++) { buttons[i].text = shortcut_escape(ctrl->radio.buttons[i], (char)(ctrl->radio.shortcuts ? ctrl->radio.shortcuts[i] : NO_SHORTCUT)); buttons[i].id = base_id + 1 + i; if (ctrl->radio.shortcuts) { assert(nshortcuts < MAX_SHORTCUTS_PER_CTRL); shortcuts[nshortcuts++] = ctrl->radio.shortcuts[i]; } } radioline_common(&pos, escaped, base_id, ctrl->radio.ncolumns, buttons, ctrl->radio.nbuttons); for (i = 0; i < ctrl->radio.nbuttons; i++) { sfree(buttons[i].text); } sfree(buttons); sfree(escaped); } break; case CTRL_CHECKBOX: num_ids = 1; escaped = shortcut_escape(ctrl->checkbox.label, ctrl->checkbox.shortcut); shortcuts[nshortcuts++] = ctrl->checkbox.shortcut; checkbox(&pos, escaped, base_id); sfree(escaped); break; case CTRL_BUTTON: 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, actual_base_id, ctrl->button.isdefault); sfree(escaped); break; case CTRL_LISTBOX: num_ids = 2; escaped = shortcut_escape(ctrl->listbox.label, ctrl->listbox.shortcut); shortcuts[nshortcuts++] = ctrl->listbox.shortcut; if (ctrl->listbox.draglist) { data = snew(struct prefslist); num_ids = 4; prefslist(data, &pos, ctrl->listbox.height, escaped, base_id, base_id+1, base_id+2, base_id+3); shortcuts[nshortcuts++] = 'u'; /* Up */ shortcuts[nshortcuts++] = 'd'; /* Down */ } else if (ctrl->listbox.height == 0) { /* Drop-down list. */ if (ctrl->listbox.percentwidth == 100) { staticddlbig(&pos, escaped, base_id, base_id+1); } else { staticddl(&pos, escaped, base_id, base_id+1, ctrl->listbox.percentwidth); } } else { /* Ordinary list. */ listbox(&pos, escaped, base_id, base_id+1, ctrl->listbox.height, ctrl->listbox.multisel); } if (ctrl->listbox.ncols) { /* * This method of getting the box width is a bit of * a hack; we'd do better to try to retrieve the * actual width in dialog units from doctl() just * before MapDialogRect. But that's going to be no * fun, and this should be good enough accuracy. */ int width = cp->width * ctrl->listbox.percentwidth; int *tabarray; int i, percent; tabarray = snewn(ctrl->listbox.ncols-1, int); percent = 0; for (i = 0; i < ctrl->listbox.ncols-1; i++) { percent += ctrl->listbox.percentages[i]; tabarray[i] = width * percent / 10000; } SendDlgItemMessage(cp->hwnd, base_id+1, LB_SETTABSTOPS, ctrl->listbox.ncols-1, (LPARAM)tabarray); sfree(tabarray); } sfree(escaped); break; case CTRL_FILESELECT: num_ids = 3; escaped = shortcut_escape(ctrl->fileselect.label, ctrl->fileselect.shortcut); shortcuts[nshortcuts++] = ctrl->fileselect.shortcut; editbutton(&pos, escaped, base_id, base_id+1, "Bro&wse...", base_id+2); shortcuts[nshortcuts++] = 'w'; sfree(escaped); break; case CTRL_FONTSELECT: num_ids = 3; escaped = shortcut_escape(ctrl->fontselect.label, ctrl->fontselect.shortcut); shortcuts[nshortcuts++] = ctrl->fontselect.shortcut; statictext(&pos, escaped, 1, base_id); staticbtn(&pos, "", base_id+1, "Change...", base_id+2); sfree(escaped); data = snew(FontSpec); break; default: assert(!"Can't happen"); num_ids = 0; /* placate gcc */ break; } /* * Create a `struct winctrl' for this control, and advance * the dialog ID counter, if it's actually been created * (and isn't tabdelayed). */ if (pos.hwnd) { struct winctrl *c = snew(struct winctrl); c->ctrl = ctrl; 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); if (actual_base_id == base_id) base_id += num_ids; } if (colstart >= 0) { /* * Update the ypos in all columns crossed by this * control. */ int i; for (i = colstart; i < colstart+colspan; i++) columns[i].ypos = pos.ypos; } } /* * We've now finished laying out the controls; so now update * the ctlpos and control ID that were passed in, terminate * any containing box, and return. */ for (i = 0; i < ncols; i++) if (cp->ypos < columns[i].ypos) cp->ypos = columns[i].ypos; *id = base_id; if (s->boxname && *s->boxname) endbox(cp);}static void winctrl_set_focus(union control *ctrl, struct dlgparam *dp, int has_focus){ if (has_focus) { if (dp->focused) dp->lastfocused = dp->focused; dp->focused = ctrl; } else if (!has_focus && dp->focused == ctrl) { dp->lastfocused = dp->focused; dp->focused = NULL; }}union control *dlg_last_focused(union control *ctrl, void *dlg){ struct dlgparam *dp = (struct dlgparam *)dlg; return dp->focused == ctrl ? dp->lastfocused : dp->focused;}/* * The dialog-box procedure calls this function to handle Windows * messages on a control we manage. */int winctrl_handle_command(struct dlgparam *dp, UINT msg, WPARAM wParam, LPARAM lParam){ struct winctrl *c; union control *ctrl; int i, id, ret; static UINT draglistmsg = WM_NULL; /* * Filter out pointless window messages. Our interest is in * WM_COMMAND and the drag list message, and nothing else. */ if (draglistmsg == WM_NULL) draglistmsg = RegisterWindowMessage (DRAGLISTMSGSTRING); if (msg != draglistmsg && msg != WM_COMMAND && msg != WM_DRAWITEM) return 0; /* * Look up the control ID in our data. */ c = NULL; for (i = 0; i < dp->nctrltrees; i++) { c = winctrl_findbyid(dp->controltrees[i], LOWORD(wParam)); if (c) break; } if (!c) return 0; /* we have nothing to do */ if (msg == WM_DRAWITEM) { /* * Owner-draw request for a panel title. */ LPDRAWITEMSTRUCT di = (LPDRAWITEMSTRUCT) lParam; HDC hdc = di->hDC; RECT r = di->rcItem; SIZE s; SetMapMode(hdc, MM_TEXT); /* ensure logical units == pixels */ GetTextExtentPoint32(hdc, (char *)c->data, strlen((char *)c->data), &s); DrawEdge(hdc, &r, EDGE_ETCHED, BF_ADJUST | BF_RECT); TextOut(hdc, r.left + (r.right-r.left-s.cx)/2, r.top + (r.bottom-r.top-s.cy)/2, (char *)c->data, strlen((char *)c->data)); return TRUE; } ctrl = c->ctrl; id = LOWORD(wParam) - c->base_id; if (!ctrl || !ctrl->generic.handler) return 0; /* nothing we can do here */ /* * From here on we do not issue `return' statements until the * very end of the dialog box: any event handler is entitled to * ask for a colour selector, so we _must_ always allow control * to reach the end of this switch statement so that the * subsequent code can test dp->coloursel_wanted(). */ ret = 0; dp->coloursel_wanted = FALSE; /* * Now switch on the control type and the message. */ switch (ctrl->generic.type) { case CTRL_EDITBOX: if (msg == WM_COMMAND && !ctrl->editbox.has_list && (HIWORD(wParam) == EN_SETFOCUS || HIWORD(wParam) == EN_KILLFOCUS)) winctrl_set_focus(ctrl, dp, HIWORD(wParam) == EN_SETFOCUS); if (msg == WM_COMMAND && ctrl->editbox.has_list && (HIWORD(wParam)==CBN_SETFOCUS || HIWORD(wParam)==CBN_KILLFOCUS)) winctrl_set_focus(ctrl, dp, HIWORD(wParam) == CBN_SETFOCUS); if (msg == WM_COMMAND && !ctrl->editbox.has_list && HIWORD(wParam) == EN_CHANGE) ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); if (msg == WM_COMMAND && ctrl->editbox.has_list) { if (HIWORD(wParam) == CBN_SELCHANGE) { int index, len; char *text; index = SendDlgItemMessage(dp->hwnd, c->base_id+1, CB_GETCURSEL, 0, 0); len = SendDlgItemMessage(dp->hwnd, c->base_id+1, CB_GETLBTEXTLEN, index, 0); text = snewn(len+1, char); SendDlgItemMessage(dp->hwnd, c->base_id+1, CB_GETLBTEXT, index, (LPARAM)text); SetDlgItemText(dp->hwnd, c->base_id+1, text); sfree(text); ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); } else if (HIWORD(wParam) == CBN_EDITCHANGE) { ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); } else if (HIWORD(wParam) == CBN_KILLFOCUS) { ctrl->generic.handler(ctrl, dp, dp->data, EVENT_REFRESH); } } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -