/* Join line data. */ void grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl, u_int new_x) { struct grid_line *dst_gl = &dst->linedata[(*py) - 1]; u_int left, to_copy, ox, nx; /* How much is left on the old line? */ left = new_x - dst_gl->cellsize; /* Work out how much to append. */ to_copy = src_gl->cellsize; if (to_copy > left) to_copy = left; ox = dst_gl->cellsize; nx = ox + to_copy; /* Resize the destination line. */ dst_gl->celldata = xreallocarray(dst_gl->celldata, nx, sizeof *dst_gl->celldata); dst_gl->cellsize = nx; /* Append as much as possible. */ grid_reflow_copy(dst_gl, ox, src_gl, 0, to_copy); /* If there is any left in the source, split it. */ if (src_gl->cellsize > to_copy) { dst_gl->flags |= GRID_LINE_WRAPPED; src_gl->cellsize -= to_copy; grid_reflow_split(dst, py, src_gl, new_x, to_copy); } }
/* * Reflow lines from src grid into dst grid of width new_x. Returns number of * lines fewer in the visible area. The source grid is destroyed. */ u_int grid_reflow(struct grid *dst, struct grid *src, u_int new_x) { u_int py, sy, line; int previous_wrapped; struct grid_line *src_gl; py = 0; sy = src->sy; previous_wrapped = 0; for (line = 0; line < sy + src->hsize; line++) { src_gl = src->linedata + line; if (!previous_wrapped) { /* Wasn't wrapped. If smaller, move to destination. */ if (src_gl->cellsize <= new_x) grid_reflow_move(dst, &py, src_gl); else grid_reflow_split(dst, &py, src_gl, new_x, 0); } else { /* Previous was wrapped. Try to join. */ grid_reflow_join(dst, &py, src_gl, new_x); } previous_wrapped = src_gl->flags & GRID_LINE_WRAPPED; } grid_destroy(src); if (py > sy) return (0); return (sy - py); }
/* Reflow lines on grid to new width. */ void grid_reflow(struct grid *gd, u_int sx) { struct grid *target; struct grid_line *gl; struct grid_cell gc; u_int yy, width, i, at, first; /* * Create a destination grid. This is just used as a container for the * line data and may not be fully valid. */ target = grid_create(gd->sx, 0, 0); /* * Loop over each source line. */ for (yy = 0; yy < gd->hsize + gd->sy; yy++) { gl = &gd->linedata[yy]; if (gl->flags & GRID_LINE_DEAD) continue; /* * Work out the width of this line. first is the width of the * first character, at is the point at which the available * width is hit, and width is the full line width. */ first = at = width = 0; if (~gl->flags & GRID_LINE_EXTENDED) { first = 1; width = gl->cellused; if (width > sx) at = sx; else at = width; } else { for (i = 0; i < gl->cellused; i++) { grid_get_cell1(gl, i, &gc); if (i == 0) first = gc.data.width; if (at == 0 && width + gc.data.width > sx) at = i; width += gc.data.width; } } /* * If the line is exactly right or the first character is wider * than the targe width, just move it across unchanged. */ if (width == sx || first > sx) { grid_reflow_move(target, gl); continue; } /* * If the line is too big, it needs to be split, whether or not * it was previously wrapped. */ if (width > sx) { grid_reflow_split(target, gd, sx, yy, at); continue; } /* * If the line was previously wrapped, join as much as possible * of the next line. */ if (gl->flags & GRID_LINE_WRAPPED) grid_reflow_join(target, gd, sx, yy, width, 0); else grid_reflow_move(target, gl); } /* * Replace the old grid with the new. */ if (target->sy < gd->sy) grid_reflow_add(target, gd->sy - target->sy); gd->hsize = target->sy - gd->sy; if (gd->hscrolled > gd->hsize) gd->hscrolled = gd->hsize; free(gd->linedata); gd->linedata = target->linedata; free(target); }
/* Reflow lines on grid to new width. */ void grid_reflow(struct grid *gd, u_int sx, u_int *cursor) { struct grid *target; struct grid_line *gl; struct grid_cell gc; u_int yy, cy, width, i, at, first; struct timeval start, tv; gettimeofday(&start, NULL); log_debug("%s: %u lines, new width %u", __func__, gd->hsize + gd->sy, sx); cy = gd->hsize + (*cursor); /* * Create a destination grid. This is just used as a container for the * line data and may not be fully valid. */ target = grid_create(gd->sx, 0, 0); /* * Loop over each source line. */ for (yy = 0; yy < gd->hsize + gd->sy; yy++) { gl = &gd->linedata[yy]; if (gl->flags & GRID_LINE_DEAD) continue; /* * Work out the width of this line. first is the width of the * first character, at is the point at which the available * width is hit, and width is the full line width. */ first = at = width = 0; if (~gl->flags & GRID_LINE_EXTENDED) { first = 1; width = gl->cellused; if (width > sx) at = sx; else at = width; } else { for (i = 0; i < gl->cellused; i++) { grid_get_cell1(gl, i, &gc); if (i == 0) first = gc.data.width; if (at == 0 && width + gc.data.width > sx) at = i; width += gc.data.width; } } /* * If the line is exactly right or the first character is wider * than the targe width, just move it across unchanged. */ if (width == sx || first > sx) { grid_reflow_move(target, gl); continue; } /* * If the line is too big, it needs to be split, whether or not * it was previously wrapped. */ if (width > sx) { grid_reflow_split(target, gd, sx, yy, at, &cy); continue; } /* * If the line was previously wrapped, join as much as possible * of the next line. */ if (gl->flags & GRID_LINE_WRAPPED) grid_reflow_join(target, gd, sx, yy, width, &cy, 0); else grid_reflow_move(target, gl); } /* * Replace the old grid with the new. */ if (target->sy < gd->sy) grid_reflow_add(target, gd->sy - target->sy); gd->hsize = target->sy - gd->sy; free(gd->linedata); gd->linedata = target->linedata; free(target); /* * Update scrolled and cursor positions. */ if (gd->hscrolled > gd->hsize) gd->hscrolled = gd->hsize; if (cy < gd->hsize) *cursor = 0; else *cursor = cy - gd->hsize; gettimeofday(&tv, NULL); timersub(&tv, &start, &tv); log_debug("%s: now %u lines (in %llu.%06u seconds)", __func__, gd->hsize + gd->sy, (unsigned long long)tv.tv_sec, (u_int)tv.tv_usec); }