*/
#include <windows.h>
+#include <commctrl.h>
#include "winstuff.h"
#define EDITHEIGHT 12
#define COMBOHEIGHT 12
#define PUSHBTNHEIGHT 14
+#define PROGBARHEIGHT 14
void ctlposinit(struct ctlpos *cp, HWND hwnd,
int leftborder, int rightborder, int topborder) {
/*
* Begin a grouping box, with or without a group title.
*/
-void beginbox(struct ctlpos *cp, char *name, int idbox, int idtext) {
- if (name)
- cp->ypos += STATICHEIGHT/2;
+void beginbox(struct ctlpos *cp, char *name, int idbox) {
cp->boxystart = cp->ypos;
+ if (!name)
+ cp->boxystart -= STATICHEIGHT/2;
if (name)
- cp->ypos += STATICHEIGHT - (STATICHEIGHT/2);
+ cp->ypos += STATICHEIGHT;
cp->ypos += GAPYBOX;
cp->width -= 2*GAPXBOX;
cp->xoff += GAPXBOX;
cp->boxid = idbox;
- cp->boxtextid = idtext;
cp->boxtext = name;
}
cp->ypos += GAPYBOX - GAPBETWEEN;
r.left = GAPBETWEEN; r.right = cp->width;
r.top = cp->boxystart; r.bottom = cp->ypos - cp->boxystart;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDFRAME, 0,
- "", cp->boxid);
- if (cp->boxtext) {
- SIZE s;
- HDC hdc;
- HFONT oldfont, dlgfont;
- hdc = GetDC(cp->hwnd);
- dlgfont = (HFONT)cp->font;
- oldfont = SelectObject(hdc, dlgfont);
- GetTextExtentPoint32(hdc, cp->boxtext, strlen(cp->boxtext), &s);
- SelectObject(hdc, oldfont);
- DeleteDC(hdc);
- r.left = GAPXBOX + GAPBETWEEN;
- r.right = (s.cx * 4 + cp->dlu4inpix-1) / cp->dlu4inpix;
-
- r.top = cp->boxystart - STATICHEIGHT/2; r.bottom = STATICHEIGHT;
- doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
- cp->boxtext, cp->boxtextid);
- }
+ doctl(cp, r, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 0,
+ cp->boxtext ? cp->boxtext : "", cp->boxid);
cp->ypos += GAPYBOX;
}
* (you might want this not to equal the number of buttons if you
* needed to line up some 2s and some 3s to look good in the same
* panel).
+ *
+ * There's a bit of a hack in here to ensure that if nacross
+ * exceeds the actual number of buttons, the rightmost button
+ * really does get all the space right to the edge of the line, so
+ * you can do things like
+ *
+ * (*) Button1 (*) Button2 (*) ButtonWithReallyLongTitle
*/
void radioline(struct ctlpos *cp,
char *text, int id, int nacross, ...) {
va_list ap;
int group;
int i;
+ char *btext;
r.left = GAPBETWEEN; r.top = cp->ypos;
r.right = cp->width; r.bottom = STATICHEIGHT;
va_start(ap, nacross);
group = WS_GROUP;
i = 0;
+ btext = va_arg(ap, char *);
while (1) {
- char *btext;
+ char *nextbtext;
int bid;
- btext = va_arg(ap, char *);
if (!btext)
break;
bid = va_arg(ap, int);
+ nextbtext = va_arg(ap, char *);
r.left = GAPBETWEEN + i * (cp->width+GAPBETWEEN)/nacross;
- r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left;
+ if (nextbtext)
+ r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left;
+ else
+ r.right = cp->width - r.left;
r.top = cp->ypos; r.bottom = RADIOHEIGHT;
doctl(cp, r, "BUTTON",
BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
btext, bid);
group = 0;
i++;
+ btext = nextbtext;
}
va_end(ap);
cp->ypos += r.bottom + GAPBETWEEN;
}
/*
+ * A single standalone static text control.
+ */
+void statictext(struct ctlpos *cp, char *text, int id) {
+ RECT r;
+
+ r.left = GAPBETWEEN; r.top = cp->ypos;
+ r.right = cp->width; r.bottom = STATICHEIGHT;
+ cp->ypos += r.bottom + GAPBETWEEN;
+ doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
+}
+
+/*
* A button on the right hand side, with a static to its left.
*/
void staticbtn(struct ctlpos *cp, char *stext, int sid,
/*
* An edit control on the right hand side, with a static to its left.
*/
-void staticedit(struct ctlpos *cp, char *stext,
- int sid, int eid, int percentedit) {
+static void staticedit_internal(struct ctlpos *cp, char *stext,
+ int sid, int eid, int percentedit,
+ int style) {
const int height = (EDITHEIGHT > STATICHEIGHT ?
EDITHEIGHT : STATICHEIGHT);
RECT r;
r.left = rpos; r.top = cp->ypos + (height-EDITHEIGHT)/2;
r.right = rwid; r.bottom = EDITHEIGHT;
doctl(cp, r, "EDIT",
- WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL | style,
WS_EX_CLIENTEDGE,
"", eid);
cp->ypos += height + GAPBETWEEN;
}
+void staticedit(struct ctlpos *cp, char *stext,
+ int sid, int eid, int percentedit) {
+ staticedit_internal(cp, stext, sid, eid, percentedit, 0);
+}
+
+void staticpassedit(struct ctlpos *cp, char *stext,
+ int sid, int eid, int percentedit) {
+ staticedit_internal(cp, stext, sid, eid, percentedit, ES_PASSWORD);
+}
+
+/*
+ * A big multiline edit control with a static labelling it.
+ */
+void bigeditctrl(struct ctlpos *cp, char *stext,
+ int sid, int eid, int lines) {
+ RECT r;
+
+ 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);
+
+ r.left = GAPBETWEEN; r.top = cp->ypos;
+ r.right = cp->width; r.bottom = EDITHEIGHT + (lines-1) * STATICHEIGHT;
+ cp->ypos += r.bottom + GAPBETWEEN;
+ doctl(cp, r, "EDIT",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | ES_MULTILINE,
+ WS_EX_CLIENTEDGE,
+ "", eid);
+}
+
/*
* A tab-control substitute when a real tab control is unavailable.
*/
r.right = lwid; r.bottom = LISTHEIGHT;
doctl(cp, r, "LISTBOX",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
- LBS_USETABSTOPS,
+ LBS_USETABSTOPS | LBS_NOTIFY,
WS_EX_CLIENTEDGE,
"", listid);
cp->ypos += LISTHEIGHT + GAPBETWEEN;
}
+/*
+ * 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);
+}