/* * move selection area to visible part of window. argument bToBottom * indicates whether to move the line onto the bottom or the top of the * window if not visible - this affects the smoothness of scrolling * line-by-line. */ void gtab_showsel(HWND hwnd, lpTable ptab, BOOL bToBottom) { int line; long change; line = gtab_rowtoline(hwnd, ptab, ptab->select.startrow); /* move up if last line or not at all visible */ if ( (line < 0) || line == (ptab->nlines - 1)) { change = ptab->select.startrow - ptab->toprow; if (bToBottom) { /* change to bottom of window. subtract 2 not 1 * since nlines includes one line that is only * partly visible */ change -= (ptab->nlines - 2); } change -= ptab->hdr.fixedrows; gtab_dovscroll(hwnd, ptab, change); } /* add support for TM_CELL here! */ }
/* * mark the selected line, if visible, in the style chosen by the * client app. This can be TM_SOLID, meaning an inversion of * the whole selected area or TM_FOCUS, meaning, inversion of the first * cell, and then a dotted focus rectangle for the rest. * * this function inverts either style, and so will turn the selection * both on and off. */ void gtab_invertsel(HWND hwnd, lpTable ptab, HDC hdc_in) { HDC hdc; int firstline, lastline; long startrow, lastrow, toprow, bottomrow; RECT rc; int lastcell; /* get the selection start and end rows ordered vertically */ if (ptab->select.nrows == 0) { return; } else if (ptab->select.nrows < 0) { startrow = ptab->select.startrow + ptab->select.nrows + 1; lastrow = ptab->select.startrow; } else { startrow = ptab->select.startrow; lastrow = ptab->select.startrow + ptab->select.nrows -1; } /* is selected area (or part of it) visible on screen ? */ firstline = gtab_rowtoline(hwnd, ptab, startrow); lastline = gtab_rowtoline(hwnd, ptab, lastrow); if (firstline < 0) { toprow = gtab_linetorow(hwnd, ptab, ptab->hdr.fixedselectable ? 0: ptab->hdr.fixedrows); if ((toprow >= startrow) && (toprow <= lastrow)) { firstline = gtab_rowtoline(hwnd, ptab, toprow); } else { return; } } else { toprow = 0; } if (lastline < 0) { bottomrow = gtab_linetorow(hwnd, ptab, ptab->nlines-1); if ((bottomrow <= lastrow) && (bottomrow >=startrow)) { lastline = gtab_rowtoline(hwnd, ptab, bottomrow); } else { return; } } rc.top = ptab->pdata[firstline].linepos.clipstart; rc.bottom = ptab->pdata[lastline].linepos.clipend; /* selection mode includes a flag TM_FOCUS indicating we should * use a focus rect instead of the traditional inversion for * selections in this table. This interferes with multiple backgrnd * colours less. However we still do inversion for fixedcols. */ lastcell = (int)(ptab->select.startcell + ptab->select.ncells - 1); /* * invert the whole area for TM_SOLID or just the first * cell for TM_FOCUS */ rc.left = ptab->pcellpos[ptab->select.startcell].clipstart; if (ptab->hdr.selectmode & TM_FOCUS) { rc.right = ptab->pcellpos[ptab->select.startcell].clipend; }else { rc.right = ptab->pcellpos[lastcell].clipend; } if (hdc_in == NULL) { hdc = GetDC(hwnd); } else { hdc = hdc_in; } InvertRect(hdc, &rc); /* * draw focus rectangle around remaining cells on this line, if there * are any */ if (ptab->hdr.selectmode & TM_FOCUS) { /* * now this is a real fudge. if we are drawing TM_FOCUS * selection, and the real top line is off the top of the * window, then the top of the focus rect will be drawn at * the top of our window. If we then scroll up one line, * a new focus rect will be drawn, but the old top of focus * rect line will still be there as junk on the * screen. To fix this, we have 2 choices: we undo the selection * before every scroll (too slow) or we set the focus rect a little * bigger if the real top line is off-window, so that the top line * is clipped (as it should be). This latter is what we do here */ if (toprow > startrow) { rc.top--; } if (ptab->select.ncells > 1) { rc.left = ptab->pcellpos[ptab->select.startcell+1].clipstart; rc.right = ptab->pcellpos[lastcell].clipend; DrawFocusRect(hdc, &rc); } } if (hdc_in == NULL) { ReleaseDC(hwnd, hdc); } }
/* new rows have been added to the table. adjust the scroll range and * position, and redraw the rows if the end of the table is currently * visible. * rows = the new total row count. */ void gtab_append( HWND hwnd, lpTable ptab, int rows, DWORD_PTR id ) { long oldrows; int line, nupdates; RECT rc; SCROLLINFO si; /* change to the new id */ ptab->hdr.id = id; ptab->select.id = id; /* update the header, but remember the old nr of rows * so we know where to start updating */ oldrows = ptab->hdr.nrows; /* check that the new nr of rows is not smaller. */ if (oldrows >= rows) { return; } ptab->hdr.nrows = rows; si.cbSize = sizeof(si); si.fMask = SIF_PAGE|SIF_RANGE; si.nMin = 0; /* set the vertical scroll range */ si.nMax = rows; si.nPage = ptab->nlines; if (si.nMax < 0) { si.nMax = 0; } /* force the scroll range into 16-bits for win 3.1 */ ptab->scrollscale = 1; while (si.nMax > 32766) { ptab->scrollscale *= 16; si.nMax /= 16; si.nPage /= 16; } if (!si.nPage) si.nPage = 1; /* now set the scroll bar range and position */ SetScrollInfo(hwnd, SB_VERT, &si, TRUE); if (si.nMax > 0) { SetScrollPos(hwnd, SB_VERT, (int) (ptab->toprow / ptab->scrollscale), TRUE); } /* calculate which screen lines need to be updated - find what * screen line the start of the new section is at */ line = gtab_rowtoline(hwnd, ptab, oldrows); if (line == -1) { /* not visible -> no more to do */ return; } /* how many lines to update - rest of screen or nr of * new lines if less than rest of screen */ nupdates = min((ptab->nlines - line), (int)(rows - oldrows)); /* invalidate the screen line buffers to indicate data * needs to be refetch from parent window */ gtab_invallines(hwnd, ptab, line, nupdates); /* calculate the region of the screen to be repainted - * left and right are same as window. top and bottom * need to be calculated from screen line height */ GetClientRect(hwnd, &rc); rc.top += line * ptab->rowheight; rc.bottom = rc.top + (nupdates * ptab->rowheight); /* force a repaint of the updated region */ InvalidateRect(hwnd, &rc, FALSE); }