📄 winctrls.c
字号:
void *data;
base_id = *id;
/* Start a containing box, if we have a boxname. */
if (s->boxname && *s->boxname) {
struct winctrl *c = snew(struct winctrl);
c->ctrl = NULL;
c->base_id = base_id;
c->num_ids = 1;
c->data = NULL;
memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
winctrl_add(wc, c);
beginbox(cp, s->boxtitle, base_id);
base_id++;
}
/* Draw a title, if we have one. */
if (!s->boxname && s->boxtitle) {
struct winctrl *c = snew(struct winctrl);
c->ctrl = NULL;
c->base_id = base_id;
c->num_ids = 1;
c->data = dupstr(s->boxtitle);
memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
winctrl_add(wc, c);
paneltitle(cp, base_id);
base_id++;
}
/* Initially we have just one column. */
ncols = 1;
columns[0] = *cp; /* structure copy */
/* And initially, there are no pending tab-delayed controls. */
ntabdelays = 0;
/* Loop over each control in the controlset. */
for (i = 0; i < s->ncontrols; i++) {
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -