📄 winctrls.c
字号:
/* Squirrel away IDs. */
hdl->listid = listid;
hdl->upbid = upbid;
hdl->dnbid = dnbid;
/* The static label. */
if (stext != NULL) {
r.left = GAPBETWEEN;
r.top = cp->ypos;
r.right = cp->width;
r.bottom = STATICHEIGHT;
cp->ypos += r.bottom + GAPWITHIN;
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
}
if (listheight > BTNSHEIGHT) {
totalheight = listheight;
buttonpos = (listheight - BTNSHEIGHT) / 2;
} else {
totalheight = BTNSHEIGHT;
buttonpos = 0;
}
for (i=0; i<3; i++) {
int left, wid;
xpos = (cp->width + GAPBETWEEN) * percent / 100;
left = xpos + GAPBETWEEN;
percent += percents[i];
xpos = (cp->width + GAPBETWEEN) * percent / 100;
wid = xpos - left;
switch (i) {
case 1:
/* The drag list box. */
r.left = left; r.right = wid;
r.top = cp->ypos; r.bottom = listheight;
{
HWND ctl;
ctl = doctl(cp, r, "LISTBOX",
WS_CHILD | WS_VISIBLE | WS_TABSTOP |
WS_VSCROLL | LBS_HASSTRINGS | LBS_USETABSTOPS,
WS_EX_CLIENTEDGE,
"", listid);
MakeDragList(ctl);
}
break;
case 2:
/* The "Up" and "Down" buttons. */
/* XXX worry about accelerators if we have more than one
* prefslist on a panel */
r.left = left; r.right = wid;
r.top = cp->ypos + buttonpos; r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
BS_NOTIFY | WS_CHILD | WS_VISIBLE |
WS_TABSTOP | BS_PUSHBUTTON,
0, "&Up", upbid);
r.left = left; r.right = wid;
r.top = cp->ypos + buttonpos + PUSHBTNHEIGHT + GAPBETWEEN;
r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
BS_NOTIFY | WS_CHILD | WS_VISIBLE |
WS_TABSTOP | BS_PUSHBUTTON,
0, "&Down", dnbid);
break;
}
}
cp->ypos += totalheight + GAPBETWEEN;
}
/*
* Helper function for prefslist: move item in list box.
*/
static void pl_moveitem(HWND hwnd, int listid, int src, int dst)
{
int tlen, val;
char *txt;
/* Get the item's data. */
tlen = SendDlgItemMessage (hwnd, listid, LB_GETTEXTLEN, src, 0);
txt = snewn(tlen+1, char);
SendDlgItemMessage (hwnd, listid, LB_GETTEXT, src, (LPARAM) txt);
val = SendDlgItemMessage (hwnd, listid, LB_GETITEMDATA, src, 0);
/* Deselect old location. */
SendDlgItemMessage (hwnd, listid, LB_SETSEL, FALSE, src);
/* Delete it at the old location. */
SendDlgItemMessage (hwnd, listid, LB_DELETESTRING, src, 0);
/* Insert it at new location. */
SendDlgItemMessage (hwnd, listid, LB_INSERTSTRING, dst,
(LPARAM) txt);
SendDlgItemMessage (hwnd, listid, LB_SETITEMDATA, dst,
(LPARAM) val);
/* Set selection. */
SendDlgItemMessage (hwnd, listid, LB_SETCURSEL, dst, 0);
sfree (txt);
}
int pl_itemfrompt(HWND hwnd, POINT cursor, BOOL scroll)
{
int ret;
POINT uppoint, downpoint;
int updist, downdist, upitem, downitem, i;
/*
* Ghastly hackery to try to figure out not which
* _item_, but which _gap between items_, the user
* is pointing at. We do this by first working out
* which list item is under the cursor, and then
* working out how far the cursor would have to
* move up or down before the answer was different.
* Then we put the insertion point _above_ the
* current item if the upper edge is closer than
* the lower edge, or _below_ it if vice versa.
*/
ret = LBItemFromPt(hwnd, cursor, scroll);
if (ret == -1)
return ret;
ret = LBItemFromPt(hwnd, cursor, FALSE);
updist = downdist = 0;
for (i = 1; i < 4096 && (!updist || !downdist); i++) {
uppoint = downpoint = cursor;
uppoint.y -= i;
downpoint.y += i;
upitem = LBItemFromPt(hwnd, uppoint, FALSE);
downitem = LBItemFromPt(hwnd, downpoint, FALSE);
if (!updist && upitem != ret)
updist = i;
if (!downdist && downitem != ret)
downdist = i;
}
if (downdist < updist)
ret++;
return ret;
}
/*
* Handler for prefslist above.
*
* Return value has bit 0 set if the dialog box procedure needs to
* return TRUE from handling this message; it has bit 1 set if a
* change may have been made in the contents of the list.
*/
int handle_prefslist(struct prefslist *hdl,
int *array, int maxmemb,
int is_dlmsg, HWND hwnd,
WPARAM wParam, LPARAM lParam)
{
int i;
int ret = 0;
if (is_dlmsg) {
if ((int)wParam == hdl->listid) {
DRAGLISTINFO *dlm = (DRAGLISTINFO *)lParam;
int dest = 0; /* initialise to placate gcc */
switch (dlm->uNotification) {
case DL_BEGINDRAG:
hdl->dummyitem =
SendDlgItemMessage(hwnd, hdl->listid,
LB_ADDSTRING, 0, (LPARAM) "");
hdl->srcitem = LBItemFromPt(dlm->hWnd, dlm->ptCursor, TRUE);
hdl->dragging = 0;
/* XXX hack Q183115 */
SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
ret |= 1; break;
case DL_CANCELDRAG:
DrawInsert(hwnd, dlm->hWnd, -1); /* Clear arrow */
SendDlgItemMessage(hwnd, hdl->listid,
LB_DELETESTRING, hdl->dummyitem, 0);
hdl->dragging = 0;
ret |= 1; break;
case DL_DRAGGING:
hdl->dragging = 1;
dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, TRUE);
if (dest > hdl->dummyitem) dest = hdl->dummyitem;
DrawInsert (hwnd, dlm->hWnd, dest);
if (dest >= 0)
SetWindowLong(hwnd, DWL_MSGRESULT, DL_MOVECURSOR);
else
SetWindowLong(hwnd, DWL_MSGRESULT, DL_STOPCURSOR);
ret |= 1; break;
case DL_DROPPED:
if (hdl->dragging) {
dest = pl_itemfrompt(dlm->hWnd, dlm->ptCursor, TRUE);
if (dest > hdl->dummyitem) dest = hdl->dummyitem;
DrawInsert (hwnd, dlm->hWnd, -1);
}
SendDlgItemMessage(hwnd, hdl->listid,
LB_DELETESTRING, hdl->dummyitem, 0);
if (hdl->dragging) {
hdl->dragging = 0;
if (dest >= 0) {
/* Correct for "missing" item. */
if (dest > hdl->srcitem) dest--;
pl_moveitem(hwnd, hdl->listid, hdl->srcitem, dest);
}
ret |= 2;
}
ret |= 1; break;
}
}
} else {
if (((LOWORD(wParam) == hdl->upbid) ||
(LOWORD(wParam) == hdl->dnbid)) &&
((HIWORD(wParam) == BN_CLICKED) ||
(HIWORD(wParam) == BN_DOUBLECLICKED))) {
/* Move an item up or down the list. */
/* Get the current selection, if any. */
int selection = SendDlgItemMessage (hwnd, hdl->listid, LB_GETCURSEL, 0, 0);
if (selection == LB_ERR) {
MessageBeep(0);
} else {
int nitems;
/* Get the total number of items. */
nitems = SendDlgItemMessage (hwnd, hdl->listid, LB_GETCOUNT, 0, 0);
/* Should we do anything? */
if (LOWORD(wParam) == hdl->upbid && (selection > 0))
pl_moveitem(hwnd, hdl->listid, selection, selection - 1);
else if (LOWORD(wParam) == hdl->dnbid && (selection < nitems - 1))
pl_moveitem(hwnd, hdl->listid, selection, selection + 1);
ret |= 2;
}
}
}
if (array) {
/* Update array to match the list box. */
for (i=0; i < maxmemb; i++)
array[i] = SendDlgItemMessage (hwnd, hdl->listid, LB_GETITEMDATA,
i, 0);
}
return ret;
}
/*
* A progress bar (from Common Controls). We like our progress bars
* to be smooth and unbroken, without those ugly divisions; some
* older compilers may not support that, but that's life.
*/
void progressbar(struct ctlpos *cp, int id)
{
RECT r;
r.left = GAPBETWEEN;
r.top = cp->ypos;
r.right = cp->width;
r.bottom = PROGBARHEIGHT;
cp->ypos += r.bottom + GAPBETWEEN;
doctl(cp, r, PROGRESS_CLASS, WS_CHILD | WS_VISIBLE
#ifdef PBS_SMOOTH
| PBS_SMOOTH
#endif
, WS_EX_CLIENTEDGE, "", id);
}
/* ----------------------------------------------------------------------
* Platform-specific side of portable dialog-box mechanism.
*/
/*
* This function takes a string, escapes all the ampersands, and
* places a single (unescaped) ampersand in front of the first
* occurrence of the given shortcut character (which may be
* NO_SHORTCUT).
*
* Return value is a malloc'ed copy of the processed version of the
* string.
*/
static char *shortcut_escape(char *text, char shortcut)
{
char *ret;
char *p, *q;
if (!text)
return NULL; /* sfree won't choke on this */
ret = snewn(2*strlen(text)+1, char); /* size potentially doubles! */
shortcut = tolower((unsigned char)shortcut);
p = text;
q = ret;
while (*p) {
if (shortcut != NO_SHORTCUT &&
tolower((unsigned char)*p) == shortcut) {
*q++ = '&';
shortcut = NO_SHORTCUT; /* stop it happening twice */
} else if (*p == '&') {
*q++ = '&';
}
*q++ = *p++;
}
*q = '\0';
return ret;
}
void winctrl_add_shortcuts(struct dlgparam *dp, struct winctrl *c)
{
int i;
for (i = 0; i < lenof(c->shortcuts); i++)
if (c->shortcuts[i] != NO_SHORTCUT) {
unsigned char s = tolower((unsigned char)c->shortcuts[i]);
assert(!dp->shortcuts[s]);
dp->shortcuts[s] = TRUE;
}
}
void winctrl_rem_shortcuts(struct dlgparam *dp, struct winctrl *c)
{
int i;
for (i = 0; i < lenof(c->shortcuts); i++)
if (c->shortcuts[i] != NO_SHORTCUT) {
unsigned char s = tolower((unsigned char)c->shortcuts[i]);
assert(dp->shortcuts[s]);
dp->shortcuts[s] = FALSE;
}
}
static int winctrl_cmp_byctrl(void *av, void *bv)
{
struct winctrl *a = (struct winctrl *)av;
struct winctrl *b = (struct winctrl *)bv;
if (a->ctrl < b->ctrl)
return -1;
else if (a->ctrl > b->ctrl)
return +1;
else
return 0;
}
static int winctrl_cmp_byid(void *av, void *bv)
{
struct winctrl *a = (struct winctrl *)av;
struct winctrl *b = (struct winctrl *)bv;
if (a->base_id < b->base_id)
return -1;
else if (a->base_id > b->base_id)
return +1;
else
return 0;
}
static int winctrl_cmp_byctrl_find(void *av, void *bv)
{
union control *a = (union control *)av;
struct winctrl *b = (struct winctrl *)bv;
if (a < b->ctrl)
return -1;
else if (a > b->ctrl)
return +1;
else
return 0;
}
static int winctrl_cmp_byid_find(void *av, void *bv)
{
int *a = (int *)av;
struct winctrl *b = (struct winctrl *)bv;
if (*a < b->base_id)
return -1;
else if (*a >= b->base_id + b->num_ids)
return +1;
else
return 0;
}
void winctrl_init(struct winctrls *wc)
{
wc->byctrl = newtree234(winctrl_cmp_byctrl);
wc->byid = newtree234(winctrl_cmp_byid);
}
void winctrl_cleanup(struct winctrls *wc)
{
struct winctrl *c;
while ((c = index234(wc->byid, 0)) != NULL) {
winctrl_remove(wc, c);
sfree(c->data);
sfree(c);
}
freetree234(wc->byctrl);
freetree234(wc->byid);
wc->byctrl = wc->byid = NULL;
}
void winctrl_add(struct winctrls *wc, struct winctrl *c)
{
struct winctrl *ret;
if (c->ctrl) {
ret = add234(wc->byctrl, c);
assert(ret == c);
}
ret = add234(wc->byid, c);
assert(ret == c);
}
void winctrl_remove(struct winctrls *wc, struct winctrl *c)
{
struct winctrl *ret;
ret = del234(wc->byctrl, c);
ret = del234(wc->byid, c);
assert(ret == c);
}
struct winctrl *winctrl_findbyctrl(struct winctrls *wc, union control *ctrl)
{
return find234(wc->byctrl, ctrl, winctrl_cmp_byctrl_find);
}
struct winctrl *winctrl_findbyid(struct winctrls *wc, int id)
{
return find234(wc->byid, &id, winctrl_cmp_byid_find);
}
struct winctrl *winctrl_findbyindex(struct winctrls *wc, int index)
{
return index234(wc->byid, index);
}
void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
struct ctlpos *cp, struct controlset *s, int *id)
{
struct ctlpos columns[16];
int ncols, colstart, colspan;
struct ctlpos tabdelays[16];
union control *tabdelayed[16];
int ntabdelays;
struct ctlpos pos;
char shortcuts[MAX_SHORTCUTS_PER_CTRL];
int nshortcuts;
char *escaped;
int i, actual_base_id, base_id, num_ids;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -