#include "dat.h" #include "fn.h" #include "test.h" /* A popup with every section, tall enough for the tests. */ #define Imgh (2*PopupPad + (Maxdisp + 2)*Fontsz + PopupSep) enum { Rgbmask = 0xffffff, }; static u32int pixel(u32int *img, Popup *p, int x, int y) { return img[y*p->w + x] & Rgbmask; } static int rectcolor(u32int *img, Popup *p, int x0, int y0, int x1, int y1, u32int color) { int x, y; color &= Rgbmask; for(y = y0; y < y1; y++) for(x = x0; x < x1; x++) if(pixel(img, p, x, y) != color) return 0; return 1; } static void checkpadding(struct ct *t, u32int *img, Popup *p) { CT_CHECK(t, rectcolor(img, p, 0, 0, p->w, PopupPad, Colbg)); CT_CHECK(t, rectcolor(img, p, 0, p->h - PopupPad, p->w, p->h, Colbg)); CT_CHECK(t, rectcolor(img, p, 0, 0, PopupPad, p->h, Colbg)); CT_CHECK(t, rectcolor(img, p, p->w - PopupPad, 0, p->w, p->h, Colbg)); } void popup_layout(struct ct *t) { static const struct { int first; int shown; int total; char *want; } markers[] = { { 0, 0, 0, "" }, { 0, 9, 9, "" }, { 0, 3, 9, "1-3/9" }, { 8, 1, 9, "9-9/9" }, { 0, 9, 10, "1-9/10" }, { 9, 1, 10, "10-10/10" }, { 0, 9, 18, "1-9/18" }, { 9, 9, 18, "10-18/18" }, { 9, 9, 32, "10-18/32" }, { 18, 9, 32, "19-27/32" }, { 27, 5, 32, "28-32/32" }, }; char buf[32]; Area area, mon[2], out, work; Caret caret; Drawcmd dc; Popup p; Str longrow; u32int c, *img; int i, ink, markink, n, numink, selbg, textink, x, y; for(i = 0; i < nelem(markers); i++){ n = pagemarker(buf, sizeof buf, markers[i].first, markers[i].shown, markers[i].total); CT_EQ_INT(t, strlen(markers[i].want), n); CT_CHECK(t, strcmp(markers[i].want, buf) == 0); } /* Monitor selection retains origins and intersects the EWMH work area. */ mon[0] = (Area){0, 0, 1920, 1080}; mon[1] = (Area){1920, 200, 1280, 1024}; work = (Area){0, 30, 3200, 1070}; popuparea(mon, 2, &work, 2500, 500, &out); CT_EQ_INT(t, 1920, out.x); CT_EQ_INT(t, 200, out.y); CT_EQ_INT(t, 1280, out.w); CT_EQ_INT(t, 900, out.h); work = (Area){60, 0, 3140, 1224}; popuparea(mon, 2, &work, 100, 100, &out); CT_EQ_INT(t, 60, out.x); CT_EQ_INT(t, 0, out.y); CT_EQ_INT(t, 1860, out.w); CT_EQ_INT(t, 1080, out.h); work = (Area){5000, 0, 100, 100}; popuparea(mon, 2, &work, 2500, 500, &out); CT_EQ_INT(t, mon[1].x, out.x); CT_EQ_INT(t, mon[1].y, out.y); CT_EQ_INT(t, mon[1].w, out.w); CT_EQ_INT(t, mon[1].h, out.h); mon[0] = (Area){0, 0, 100, 100}; mon[1] = (Area){200, 0, 100, 100}; popuparea(mon, 2, nil, 150, 50, &out); CT_EQ_INT(t, 0, out.x); memset(&caret, 0, sizeof caret); area = (Area){1920, 30, 1280, 900}; popupposition(&caret, 2000, 50, &area, 100, 60, &x, &y); CT_EQ_INT(t, 2010, x); CT_EQ_INT(t, 60, y); popupposition(&caret, 2000, 900, &area, 100, 60, &x, &y); CT_EQ_INT(t, 830, y); /* above the pointer, not over it */ caret.valid = 1; caret.x = 2100; caret.y = 80; caret.h = 20; popupposition(&caret, 0, 0, &area, 100, 60, &x, &y); CT_EQ_INT(t, 2100, x); CT_EQ_INT(t, 100, y); caret.x = 3150; caret.y = 850; popupposition(&caret, 0, 0, &area, 200, 100, &x, &y); CT_EQ_INT(t, 3000, x); CT_EQ_INT(t, 750, y); /* A popup no larger than a small work area stays inside its origin. */ area = (Area){100, 200, 80, 80}; caret.x = 120; caret.y = 230; caret.h = 20; popupposition(&caret, 0, 0, &area, 80, 80, &x, &y); CT_EQ_INT(t, 100, x); CT_EQ_INT(t, 200, y); textinit(); /* Empty sections reserve nothing. */ memset(&dc, 0, sizeof dc); dc.sel = -1; popuplayout(&dc, PopupBasew, Imgh, &p); CT_EQ_INT(t, 0, p.w); CT_EQ_INT(t, 0, p.h); CT_EQ_INT(t, -1, p.prey); CT_EQ_INT(t, -1, p.rowsy); CT_EQ_INT(t, -1, p.marky); /* Preedit only. */ dc.pre = mkstr("preedit"); popuplayout(&dc, 2*PopupBasew, Imgh, &p); CT_EQ_INT(t, PopupBasew, p.w); CT_EQ_INT(t, PopupPad, p.prey); CT_EQ_INT(t, -1, p.sepy); CT_EQ_INT(t, -1, p.rowsy); CT_EQ_INT(t, -1, p.marky); CT_EQ_INT(t, 2*PopupPad + Fontsz, p.h); /* Candidates only. */ memset(&dc, 0, sizeof dc); dc.sel = -1; dc.nkouho = 2; dc.kouho[0] = mkstr("short"); dc.kouho[1] = mkstr("candidate"); popuplayout(&dc, 2*PopupBasew, Imgh, &p); CT_EQ_INT(t, PopupBasew, p.w); CT_EQ_INT(t, -1, p.prey); CT_EQ_INT(t, -1, p.sepy); CT_EQ_INT(t, PopupPad, p.rowsy); CT_EQ_INT(t, -1, p.marky); CT_EQ_INT(t, 2*PopupPad + 2*Fontsz, p.h); CT_EQ_INT(t, PopupTextw, p.textw); CT_EQ_INT(t, p.w - PopupPad, PopupPad + PopupNumw + p.textw); /* Preedit and candidates meet at one separator, with no empty rows. */ dc.pre = mkstr("preedit"); popuplayout(&dc, 2*PopupBasew, Imgh, &p); CT_EQ_INT(t, PopupBasew, p.w); CT_EQ_INT(t, PopupPad, p.prey); CT_EQ_INT(t, p.prey + Fontsz, p.sepy); CT_EQ_INT(t, p.sepy + PopupSep, p.rowsy); CT_EQ_INT(t, -1, p.marky); CT_EQ_INT(t, p.rowsy + 2*Fontsz + PopupPad, p.h); CT_EQ_INT(t, 2*PopupPad + 3*Fontsz + PopupSep, p.h); /* Long preedit expands to the monitor cap just like a candidate. */ sclear(&longrow); for(i = 0; i < Maxrunes; i++) sputr(&longrow, 'W'); memset(&dc, 0, sizeof dc); dc.pre = longrow; popuplayout(&dc, 2*PopupBasew, Imgh, &p); CT_EQ_INT(t, 2*PopupBasew, p.w); /* The largest panel includes all sections and fits its backing image. */ memset(&dc, 0, sizeof dc); dc.pre = mkstr("preedit"); dc.nkouho = Maxdisp; dc.sel = 4; dc.first = 0; dc.total = Maxdisp + 1; for(i = 0; i < Maxdisp; i++) dc.kouho[i] = mkstr(i == dc.sel ? "M" : "candidate"); dc.kouho[0] = longrow; popuplayout(&dc, 2*PopupBasew, Imgh, &p); CT_EQ_INT(t, Maxdisp, p.n); CT_EQ_INT(t, PopupPad, p.prey); CT_EQ_INT(t, p.prey + Fontsz, p.sepy); CT_EQ_INT(t, p.sepy + PopupSep, p.rowsy); CT_EQ_INT(t, p.rowsy + Maxdisp*Fontsz, p.marky); CT_EQ_INT(t, p.marky + Fontsz + PopupPad, p.h); CT_EQ_INT(t, Imgh, p.h); CT_EQ_INT(t, 2*PopupBasew, p.w); CT_CHECK(t, p.h <= Imgh); CT_EQ_INT(t, p.w - PopupPad, p.markx + p.markw); CT_EQ_INT(t, p.w - 2*PopupPad, p.selw); CT_EQ_INT(t, p.rowsy + dc.sel*Fontsz, p.sely); CT_EQ_INT(t, p.w - PopupPad, PopupPad + PopupNumw + p.textw); img = emalloc(2*PopupBasew*Imgh*sizeof img[0]); popupdraw(img, &dc, &p); checkpadding(t, img, &p); for(x = 0; x < p.w; x++) CT_EQ_UINT(t, x >= PopupPad && x < p.w - PopupPad ? Colsep : Colbg, pixel(img, &p, x, p.sepy)); /* Selection paint and both foreground columns stay inside the row. */ selbg = numink = textink = 0; for(y = p.sely; y < p.sely + Fontsz; y++){ for(x = 0; x < p.w; x++){ c = pixel(img, &p, x, y); if(x < PopupPad || x >= PopupPad + p.selw){ CT_EQ_UINT(t, Colbg, c); continue; } if(c == (Colsel & Rgbmask)){ selbg++; continue; } CT_CHECK(t, (x >= PopupPad && x < PopupPad + PopupNumw) || (x >= (PopupPad + PopupNumw) && x < (PopupPad + PopupNumw) + p.textw)); if(x < PopupPad + PopupNumw) numink++; else textink++; } } CT_CHECK(t, Colsel != Colselfg); CT_CHECK(t, selbg > p.selw*Fontsz/2); CT_CHECK(t, numink > 0); CT_CHECK(t, textink > 0); /* The marker occupies only its compact, right-aligned footer box. */ markink = 0; for(y = p.marky; y < p.marky + Fontsz; y++){ for(x = 0; x < p.w; x++){ if(pixel(img, &p, x, y) == (Colbg & Rgbmask)) continue; markink++; CT_CHECK(t, x >= p.markx && x < p.markx + p.markw); } } CT_CHECK(t, markink > 0); /* A long candidate grows from the stable base to the monitor cap. */ memset(&dc, 0, sizeof dc); dc.sel = -1; dc.nkouho = 1; dc.kouho[0] = longrow; n = textwidth(&longrow); popuplayout(&dc, 2*PopupBasew, Imgh, &p); CT_EQ_INT(t, 2*PopupBasew, p.w); CT_CHECK(t, p.textw > PopupTextw); CT_CHECK(t, n > p.textw); CT_EQ_INT(t, PopupPad, p.rowsy); CT_EQ_INT(t, p.w - PopupPad, PopupPad + PopupNumw + p.textw); popupdraw(img, &dc, &p); ink = 0; for(y = p.rowsy; y < p.rowsy + Fontsz; y++){ for(x = 0; x < p.w; x++){ c = pixel(img, &p, x, y); if(x < PopupPad || x >= p.w - PopupPad) CT_EQ_UINT(t, Colbg, c); if(x >= (PopupPad + PopupNumw) && x < (PopupPad + PopupNumw) + p.textw && c != (Colbg & Rgbmask)) ink++; } } CT_CHECK(t, ink > 0); CT_EQ_INT(t, n, textwidth(&longrow)); popuplayout(&dc, PopupBasew - 1, Imgh, &p); CT_EQ_INT(t, PopupBasew - 1, p.w); /* Height truncation scrolls the row window to the selected candidate. */ memset(&dc, 0, sizeof dc); dc.nkouho = Maxdisp; dc.sel = Maxdisp - 1; dc.total = Maxdisp; for(i = 0; i < Maxdisp; i++) dc.kouho[i] = mkstr("candidate"); popuplayout(&dc, PopupBasew, 2*PopupPad + 2*Fontsz, &p); CT_EQ_INT(t, 1, p.n); CT_EQ_INT(t, Maxdisp - 1, p.row0); CT_EQ_INT(t, PopupPad, p.sely); CT_CHECK(t, p.marky >= 0); CT_CHECK(t, p.h <= 2*PopupPad + 2*Fontsz); popupdraw(img, &dc, &p); numink = 0; for(y = p.rowsy; y < p.rowsy + Fontsz; y++) for(x = PopupPad; x < PopupPad + PopupNumw; x++) if(pixel(img, &p, x, y) != (Colsel & Rgbmask)) numink++; markink = 0; for(y = p.marky; y < p.marky + Fontsz; y++) for(x = p.markx; x < p.markx + p.markw; x++) if(pixel(img, &p, x, y) != (Colbg & Rgbmask)) markink++; CT_CHECK(t, numink > 0); /* full-width 9 */ CT_CHECK(t, markink > 0); /* 9-9/9 */ free(img); }