n_wrap regression: where the lines break, and the properties a height cache depends on (measure == draw, always >= 1 line, no infinite loop on an over-wide item).
n_wrap regression: where the lines break, and the properties a height cache depends on (measure == draw, always >= 1 line, no infinite loop on an over-wide item).
#define CHECK(cond, msg) \
do { \
if (!(cond)) { \
n_log(LOG_ERR, "FAIL: %s", (msg)); \
failures++; \
} \
} while (0)
#define MAX_LINES 16
typedef struct {
size_t n;
static void collect(
size_t first,
size_t last,
size_t line,
double width,
void* user) {
}
}
}
typedef struct {
size_t n;
}
}
size_t lines, counted;
CHECK(lines == counted,
"measure pass and emit pass agree on line count");
return lines;
}
static int eq(
double a,
double b) {
double d = a - b;
return d < 0.0001 && d > -0.0001;
}
{
CHECK(
run(it, 3, 10.0, &c) == 1,
"fits -> 1 line");
}
{
{2.0, 0},
{2.0, 0}};
CHECK(
run(it, 5, 5.0, &c) == 2,
"space wrap -> 2 lines");
CHECK(c.
n == 2,
"space wrap -> 2 emitted");
CHECK(
eq(c.
width[0], 5.0),
"line 0 width excludes the break space");
"line 1 starts AFTER the dropped space");
}
{
CHECK(
run(it, 3, 5.0, &c) == 3,
"unbroken run -> one item per line");
CHECK(c.
first[1] == 1 && c.
last[1] == 2,
"mid-run break keeps order");
}
{
CHECK(
run(it, 1, 5.0, &c) == 1,
"over-wide item -> 1 line");
"over-wide item is placed alone");
CHECK(
eq(c.
width[0], 10.0),
"over-wide line reports its real width");
}
{
CHECK(
run(it, 2, 5.0, &c) == 2,
"narrow + over-wide -> 2 lines");
CHECK(c.
first[1] == 1 && c.
last[1] == 2,
"over-wide item on its own");
}
{
CHECK(
run(it, 3, 100.0, &c) == 2,
"newline -> 2 lines");
CHECK(c.
first[0] == 0 && c.
last[0] == 1,
"newline ends line 0 before it");
}
{
CHECK(
run(it, 2, 100.0, &c) == 2,
"trailing newline -> 2 lines counted");
CHECK(c.
n == 1,
"trailing newline emits only the non-empty line");
}
{
{1.0, 0}};
CHECK(
run(it, 3, 100.0, &c) == 3,
"blank line -> 3 lines");
}
{
CHECK(
run(it, 2, 5.0, &c) == 2,
"leading space -> 2 lines");
CHECK(c.
first[0] == 0 && c.
last[0] == 1,
"the leading space is kept");
}
{
CHECK(
run(it, 0, 5.0, &c) == 1,
"empty -> 1 line");
CHECK(c.
n == 0,
"empty emits nothing");
(void)it;
}
{
"NULL items -> 1 line");
CHECK(c.
n == 0,
"NULL items emit nothing");
}
{
size_t lines =
run(it, 3, 0.0, &c);
CHECK(lines >= 1 && lines <= 3,
"zero width terminates");
}
{
{2.0, 0},
{2.0, 0},
{2.0, 0}};
"index_at: line start -> 0");
"index_at: left half of 'a' -> before it");
"index_at: right half of 'a' -> after it");
"index_at: right half of 'b' -> line end");
"index_at: past line 0's end -> its end, not the next line");
"index_at: line 1 starts after the dropped space");
"index_at: left half of 'd'");
"index_at: right half of 'd' -> count");
"index_at: above the text -> 0");
"index_at: below the text -> count");
"index_at: NULL items -> 0");
}
{
"index_at: left half of a cell -> before it");
"index_at: right half of a cell -> after it");
}
{
"index_at: empty line after a trailing break -> count");
}
{
{2.0, 0},
{2.0, 0},
{2.0, 0}};
"span_rects: 'b cd'-ish span crosses the break -> 2 rects");
"span_rects: line 0 covers 'b' only");
"span_rects: line 1 covers 'c' only");
"span_rects: reversed bounds are the same span");
"span_rects: only the dropped space -> nothing to paint");
"span_rects: empty span -> 0");
"span_rects: hi clamps to count");
}
return 1;
}
return 0;
}
static N_GUI_MOUSE_EVENT last
the last event the widget was told of, and how many
static void rect_collect(size_t line, double x0, double x1, void *user)
static int eq(double a, double b)
void line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color)
draw a line
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
#define LOG_NOTICE
normal but significant condition
static int collect(const char *path, const char *dir, const PK_OBJ *o, const char *prefix, N_PTH *pth, int depth)
collect the tensors under a dictionary, depth first
size_t n_wrap_layout(const n_wrap_item *items, size_t count, double max_width, n_wrap_emit emit, void *user)
Break items into lines no wider than max_width.
size_t n_wrap_span_rects(const n_wrap_item *items, size_t count, double max_width, size_t lo, size_t hi, n_wrap_rect_emit emit, void *user)
The rectangles that cover the items [lo, hi): one per line the range touches, in order,...
size_t n_wrap_index_at(const n_wrap_item *items, size_t count, double max_width, double line_height, double x, double y)
The item boundary nearest a point: the inverse of n_wrap_layout(), for turning a click or a drag into...
Greedy word-wrap over pre-measured, styled items.
#define N_WRAP_SPACE
the item is a legal break point (typically a space); it is DROPPED when a line breaks there,...
#define N_WRAP_NEWLINE
the item is a hard line break; it ends the line and occupies no cell
One pre-measured layout item: a glyph, an emoji cell, an inline image, or a whole word,...