/* * Reflow lines from src grid into dst grid based on width sx. Returns number * of lines fewer in the visible area, or zero. */ u_int grid_reflow(struct grid *dst, const struct grid *src, u_int sx) { u_int px, py, line, cell; int previous_wrapped; struct grid_line *gl; px = py = 0; previous_wrapped = 1; for (line = 0; line < src->sy + src->hsize; line++) { gl = src->linedata + line; if (!previous_wrapped) { px = 0; py++; if (py >= dst->hsize + dst->sy) grid_scroll_history(dst); } for (cell = 0; cell < gl->cellsize; cell++) { if (px == sx) { dst->linedata[py].flags |= GRID_LINE_WRAPPED; px = 0; py++; if (py >= dst->hsize + dst->sy) grid_scroll_history(dst); } grid_set_cell(dst, px, py, gl->celldata + cell); px++; } previous_wrapped = gl->flags & GRID_LINE_WRAPPED; } py++; /* account for final line, which never wraps */ if (py > src->sy) return (0); return (src->sy - py); }
/* Split this line into several new ones */ static void grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy, u_int at) { struct grid_line *gl = &gd->linedata[yy], *first; struct grid_cell gc; u_int line, lines, width, i, xx; u_int used = gl->cellused; int flags = gl->flags; /* How many lines do we need to insert? We know we need at least two. */ if (~gl->flags & GRID_LINE_EXTENDED) lines = 1 + (gl->cellused - 1) / sx; else { lines = 2; width = 0; for (i = at; i < used; i++) { grid_get_cell1(gl, i, &gc); if (width + gc.data.width > sx) { lines++; width = 0; } width += gc.data.width; } } /* Insert new lines. */ line = target->sy + 1; first = grid_reflow_add(target, lines); /* Copy sections from the original line. */ width = 0; xx = 0; for (i = at; i < used; i++) { grid_get_cell1(gl, i, &gc); if (width + gc.data.width > sx) { target->linedata[line].flags |= GRID_LINE_WRAPPED; line++; width = 0; xx = 0; } width += gc.data.width; grid_set_cell(target, xx, line, &gc); xx++; } if (flags & GRID_LINE_WRAPPED) target->linedata[line].flags |= GRID_LINE_WRAPPED; /* Move the remainder of the original line. */ gl->cellsize = gl->cellused = at; gl->flags |= GRID_LINE_WRAPPED; memcpy(first, gl, sizeof *first); grid_reflow_dead(gl); /* Adjust the scroll position. */ if (yy <= gd->hscrolled) gd->hscrolled += lines - 1; /* * If the original line had the wrapped flag and there is still space * in the last new line, try to join with the next lines. */ if (width < sx && (flags & GRID_LINE_WRAPPED)) grid_reflow_join(target, gd, sx, yy, width, 1); }
/* Join line below onto this one. */ static void grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, u_int width, int already) { struct grid_line *gl, *from = NULL; struct grid_cell gc; u_int lines, left, i, to, line, want = 0; u_int at; int wrapped = 1; /* * Add a new target line. */ if (!already) { to = target->sy; gl = grid_reflow_move(target, &gd->linedata[yy]); } else { to = target->sy - 1; gl = &target->linedata[to]; } at = gl->cellused; /* * Loop until no more to consume or the target line is full. */ lines = 0; for (;;) { /* * If this is now the last line, there is nothing more to be * done. */ if (yy + 1 + lines == gd->hsize + gd->sy) break; line = yy + 1 + lines; /* If the next line is empty, skip it. */ if (~gd->linedata[line].flags & GRID_LINE_WRAPPED) wrapped = 0; if (gd->linedata[line].cellused == 0) { if (!wrapped) break; lines++; continue; } /* * Is the destination line now full? Copy the first character * separately because we need to leave "from" set to the last * line if this line is full. */ grid_get_cell1(&gd->linedata[line], 0, &gc); if (width + gc.data.width > sx) break; width += gc.data.width; grid_set_cell(target, at, to, &gc); at++; /* Join as much more as possible onto the current line. */ from = &gd->linedata[line]; for (want = 1; want < from->cellused; want++) { grid_get_cell1(from, want, &gc); if (width + gc.data.width > sx) break; width += gc.data.width; grid_set_cell(target, at, to, &gc); at++; } lines++; /* * If this line wasn't wrapped or we didn't consume the entire * line, don't try to join any further lines. */ if (!wrapped || want != from->cellused || width == sx) break; } if (lines == 0) return; /* * If we didn't consume the entire final line, then remove what we did * consume. If we consumed the entire line and it wasn't wrapped, * remove the wrap flag from this line. */ left = from->cellused - want; if (left != 0) { grid_move_cells(gd, 0, want, yy + lines, left, 8); from->cellsize = from->cellused = left; lines--; } else if (!wrapped) gl->flags &= ~GRID_LINE_WRAPPED; /* Remove the lines that were completely consumed. */ for (i = yy + 1; i < yy + 1 + lines; i++) { free(gd->linedata[i].celldata); free(gd->linedata[i].extddata); grid_reflow_dead(&gd->linedata[i]); } /* Adjust scroll position. */ if (gd->hscrolled > to + lines) gd->hscrolled -= lines; else if (gd->hscrolled > to) gd->hscrolled = to; }
/* Set cell. */ void grid_view_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) { grid_set_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc); }
static LRESULT CALLBACK grid_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp) { grid_t* grid = (grid_t*) GetWindowLongPtr(win, 0); switch(msg) { case WM_PAINT: return generic_paint(win, grid->no_redraw, (grid->style & MC_GS_DOUBLEBUFFER), grid_paint, grid); case WM_PRINTCLIENT: return generic_printclient(win, (HDC) wp, grid_paint, grid); case WM_NCPAINT: return generic_ncpaint(win, grid->theme_listview, (HRGN) wp); case WM_ERASEBKGND: return generic_erasebkgnd(win, grid->theme_listview, (HDC) wp); case MC_GM_GETTABLE: return (LRESULT) grid->table; case MC_GM_SETTABLE: return (grid_set_table(grid, (table_t*) lp) == 0 ? TRUE : FALSE); case MC_GM_GETCOLUMNCOUNT: return grid->col_count; case MC_GM_GETROWCOUNT: return grid->row_count; case MC_GM_RESIZE: return (grid_resize_table(grid, LOWORD(wp), HIWORD(wp)) == 0 ? TRUE : FALSE); case MC_GM_CLEAR: return (grid_clear(grid, wp) == 0 ? TRUE : FALSE); case MC_GM_SETCELLW: case MC_GM_SETCELLA: return (grid_set_cell(grid, LOWORD(wp), HIWORD(wp), (MC_TABLECELL*)lp, (msg == MC_GM_SETCELLW)) == 0 ? TRUE : FALSE); case MC_GM_GETCELLW: case MC_GM_GETCELLA: return (grid_get_cell(grid, LOWORD(wp), HIWORD(wp), (MC_TABLECELL*)lp, (msg == MC_GM_GETCELLW)) == 0 ? TRUE : FALSE); case MC_GM_SETGEOMETRY: return (grid_set_geometry(grid, (MC_GGEOMETRY*)lp, TRUE) == 0 ? TRUE : FALSE); case MC_GM_GETGEOMETRY: return (grid_get_geometry(grid, (MC_GGEOMETRY*)lp) == 0 ? TRUE : FALSE); case MC_GM_REDRAWCELLS: return (grid_redraw_cells(grid, LOWORD(wp), HIWORD(wp), LOWORD(lp), LOWORD(lp)) == 0 ? TRUE : FALSE); case MC_GM_SETCOLUMNWIDTH: return (grid_set_col_width(grid, wp, LOWORD(lp)) == 0 ? TRUE : FALSE); case MC_GM_GETCOLUMNWIDTH: return grid_get_col_width(grid, wp); case MC_GM_SETROWHEIGHT: return (grid_set_row_height(grid, wp, LOWORD(lp)) == 0 ? TRUE : FALSE); case MC_GM_GETROWHEIGHT: return grid_get_row_height(grid, wp); case WM_SETREDRAW: grid->no_redraw = !wp; return 0; case WM_VSCROLL: case WM_HSCROLL: grid_scroll(grid, (msg == WM_VSCROLL), LOWORD(wp), 1); return 0; case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL: grid_mouse_wheel(grid, (msg == WM_MOUSEWHEEL), (int)(SHORT)HIWORD(wp)); return 0; case WM_SIZE: if(!grid->no_redraw) { int old_scroll_x = grid->scroll_x; int old_scroll_y = grid->scroll_y; grid_setup_scrollbars(grid, FALSE); if(grid->scroll_x != old_scroll_x || grid->scroll_y != old_scroll_y) InvalidateRect(win, NULL, TRUE); } return 0; case WM_GETFONT: return (LRESULT) grid->font; case WM_SETFONT: grid->font = (HFONT) wp; if((BOOL) lp && !grid->no_redraw) InvalidateRect(win, NULL, TRUE); return 0; case WM_STYLECHANGED: if(wp == GWL_STYLE) grid_style_changed(grid, (STYLESTRUCT*) lp); break; case WM_THEMECHANGED: grid_close_theme(grid); grid_open_theme(grid); if(!grid->no_redraw) RedrawWindow(win, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE); return 0; case WM_SYSCOLORCHANGE: if(!grid->no_redraw) RedrawWindow(win, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE); return 0; case WM_NOTIFYFORMAT: if(lp == NF_REQUERY) grid_notify_format(grid); return (grid->unicode_notifications ? NFR_UNICODE : NFR_ANSI); case CCM_SETUNICODEFORMAT: { BOOL old = grid->unicode_notifications; grid->unicode_notifications = (wp != 0); return old; } case CCM_GETUNICODEFORMAT: return grid->unicode_notifications; case CCM_SETNOTIFYWINDOW: { HWND old = grid->notify_win; grid->notify_win = (wp ? (HWND) wp : GetAncestor(win, GA_PARENT)); return (LRESULT) old; } case CCM_SETWINDOWTHEME: mcSetWindowTheme(win, (const WCHAR*) lp, NULL); return 0; case WM_NCCREATE: grid = grid_nccreate(win, (CREATESTRUCT*)lp); if(MC_ERR(grid == NULL)) return FALSE; SetWindowLongPtr(win, 0, (LONG_PTR)grid); return TRUE; case WM_CREATE: return (grid_create(grid) == 0 ? 0 : -1); case WM_DESTROY: grid_destroy(grid); return 0; case WM_NCDESTROY: if(grid) grid_ncdestroy(grid); return 0; } return DefWindowProc(win, msg, wp, lp); }