1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-08 08:58:00 +00:00

dialog system: add a side-by-side alignment feature.

This will let us put two controls side by side (e.g. in disjoint
columns of a multi-col layout) and indicate that instead of the
default behaviour of aligning their top edges, their centreline (or,
even better if available, font baseline) should be aligned.

NFC: nothing uses this yet.
This commit is contained in:
Simon Tatham 2021-04-03 17:45:31 +01:00
parent d33f889a56
commit 1276c13e6a
5 changed files with 103 additions and 4 deletions

View File

@ -221,6 +221,7 @@ static union control *ctrl_new(struct controlset *s, int type,
c->generic.handler = handler;
c->generic.context = context;
c->generic.label = NULL;
c->generic.align_next_to = NULL;
return c;
}

View File

@ -113,7 +113,8 @@ typedef void (*handler_fn)(union control *ctrl, dlgparam *dp,
int column; \
handler_fn handler; \
intorptr context; \
intorptr helpctx
intorptr helpctx; \
union control *align_next_to
union control {
/*
@ -179,6 +180,18 @@ union control {
* to ensure it brings up the right piece of help text.
*/
intorptr helpctx;
/*
* Setting this to non-NULL coerces two controls to have their
* y-coordinates adjusted so that they can sit alongside each
* other and look nicely aligned, even if they're different
* heights.
*
* Set this field on the _second_ control of the pair (in
* terms of order in the data structure), so that when it's
* instantiated, the first one is already there to be referred
* to.
*/
union control *align_next_to;
} generic;
struct {
STANDARD_PREFIX;

View File

@ -2491,6 +2491,28 @@ GtkWidget *layout_ctrls(
COLUMN_SPAN(ctrl->generic.column));
if (left)
columns_force_left_align(cols, w);
if (ctrl->generic.align_next_to) {
/*
* Implement align_next_to by simply forcing the two
* controls to have the same height of size allocation. At
* least for the controls we're currently doing this with,
* the GTK layout system will automatically vertically
* centre each control within its allocation, which will
* get the two controls aligned alongside each other
* reasonably well.
*/
struct uctrl *uc2 = dlg_find_byctrl(
dp, ctrl->generic.align_next_to);
assert(uc2);
columns_force_same_height(cols, w, uc2->toplevel);
#if GTK_CHECK_VERSION(3, 10, 0)
/* Slightly nicer to align baselines than just vertically
* centring, where the option is available */
gtk_widget_set_valign(w, GTK_ALIGN_BASELINE);
gtk_widget_set_valign(uc2->toplevel, GTK_ALIGN_BASELINE);
#endif
}
gtk_widget_show(w);
uc->toplevel = w;

View File

@ -1325,6 +1325,28 @@ struct winctrl *winctrl_findbyindex(struct winctrls *wc, int index)
return index234(wc->byid, index);
}
static void move_windows(HWND hwnd, int base_id, int num_ids, LONG dy)
{
if (!dy)
return;
for (int i = 0; i < num_ids; i++) {
HWND win = GetDlgItem(hwnd, base_id + i);
RECT rect;
if (!GetWindowRect(win, &rect))
continue;
POINT p;
p.x = rect.left;
p.y = rect.top + dy;
if (!ScreenToClient(hwnd, &p))
continue;
SetWindowPos(win, NULL, p.x, p.y, 0, 0,
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
}
}
void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
struct ctlpos *cp, struct controlset *s, int *id)
{
@ -1340,7 +1362,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
char shortcuts[MAX_SHORTCUTS_PER_CTRL];
int nshortcuts;
char *escaped;
int i, actual_base_id, base_id, num_ids;
int i, actual_base_id, base_id, num_ids, align_id_relative;
void *data;
base_id = *id;
@ -1349,7 +1371,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
if (s->boxname && *s->boxname) {
struct winctrl *c = snew(struct winctrl);
c->ctrl = NULL;
c->base_id = base_id;
c->base_id = c->align_id = base_id;
c->num_ids = 1;
c->data = NULL;
memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
@ -1362,7 +1384,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
if (!s->boxname && s->boxtitle) {
struct winctrl *c = snew(struct winctrl);
c->ctrl = NULL;
c->base_id = base_id;
c->base_id = c->align_id = base_id;
c->num_ids = 1;
c->data = dupstr(s->boxtitle);
memset(c->shortcuts, NO_SHORTCUT, lenof(c->shortcuts));
@ -1491,6 +1513,11 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
/* Almost all controls start at base_id. */
actual_base_id = base_id;
/* For vertical alignment purposes, the most relevant control
* in a group is usually the last one. But that can be
* overridden occasionally. */
align_id_relative = -1;
/*
* Now we're ready to actually create the control, by
* switching on its type.
@ -1659,6 +1686,10 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
unreachable("bad control type in winctrl_layout");
}
/* Translate the original align_id_relative of -1 into n-1 */
if (align_id_relative < 0)
align_id_relative += num_ids;
/*
* Create a `struct winctrl' for this control, and advance
* the dialog ID counter, if it's actually been created
@ -1669,6 +1700,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
c->ctrl = ctrl;
c->base_id = actual_base_id;
c->align_id = c->base_id + align_id_relative;
c->num_ids = num_ids;
c->data = data;
memcpy(c->shortcuts, shortcuts, sizeof(shortcuts));
@ -1676,6 +1708,31 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
winctrl_add_shortcuts(dp, c);
if (actual_base_id == base_id)
base_id += num_ids;
if (ctrl->generic.align_next_to) {
/*
* Implement align_next_to by looking at the y extents
* of the two controls now that both are created, and
* moving one or the other downwards so that they're
* centred on a common horizontal line.
*/
struct winctrl *c2 = winctrl_findbyctrl(
wc, ctrl->generic.align_next_to);
HWND win1 = GetDlgItem(pos.hwnd, c->align_id);
HWND win2 = GetDlgItem(pos.hwnd, c2->align_id);
RECT rect1, rect2;
if (win1 && win2 &&
GetWindowRect(win1, &rect1) &&
GetWindowRect(win2, &rect2)) {
LONG top = (rect1.top < rect2.top ? rect1.top : rect2.top);
LONG bottom = (rect1.bottom > rect2.bottom ?
rect1.bottom : rect2.bottom);
move_windows(pos.hwnd, c->base_id, c->num_ids,
(top + bottom - rect1.top - rect1.bottom)/2);
move_windows(pos.hwnd, c2->base_id, c2->num_ids,
(top + bottom - rect2.top - rect2.bottom)/2);
}
}
} else {
sfree(data);
}

View File

@ -491,6 +491,12 @@ struct winctrl {
*/
int base_id;
int num_ids;
/*
* For vertical alignment, the id of a particular representative
* control that has the y-extent of the sensible part of the
* control.
*/
int align_id;
/*
* Remember what keyboard shortcuts were used by this control,
* so that when we remove it again we can take them out of the