/* * set the topmost selectable unit in window as the selection * * if bExtend is TRUE, then extend the selection to include this, rather * than replacing the existing selection. Note that (startrow, startcell) * is always the anchor point - ie most recently selected end, and the * (nrows, ncells) can be + or - to extend the selection downwards or upwards. */ void gtab_selhome(HWND hwnd, lpTable ptab, BOOL bExtend) { long startrow, startcell, ncells; if (ptab->hdr.selectmode & TM_ROW) { ncells = ptab->hdr.ncols; } else { ncells = 1; } startcell = 0; if (ptab->hdr.fixedselectable) { startrow = gtab_linetorow(hwnd, ptab, 0); } else { startrow = gtab_linetorow(hwnd, ptab, ptab->hdr.fixedrows); if (!(ptab->hdr.selectmode & TM_ROW)) { startcell = ptab->hdr.fixedcols; } } if (bExtend) { gtab_extendsel(hwnd, ptab, startrow, startcell, TRUE); } else { gtab_select(hwnd, ptab, startrow, startcell, 1, ncells, TRUE); } }
/* * called on right-click events. Select the cell clicked on, and if * valid, send on to owner for any context-menu type operation */ void gtab_rightclick(HWND hwnd, lpTable ptab, int x, int y) { long cell, ncells; long row; HWND hOwner; /* find which col, row he selected */ cell = gtab_xtocol(hwnd, ptab, x); if (cell == -1) { return; } row = gtab_linetorow(hwnd, ptab, gtab_ytoline(hwnd, ptab, y)); /* is he selecting a disabled fixed area ? */ if ( (row < ptab->hdr.fixedrows) || (cell < ptab->hdr.fixedcols)) { if (ptab->hdr.fixedselectable == FALSE) { return; } } // ignore if beyond data if ((row >= ptab->hdr.nrows) || (cell >= ptab->hdr.ncols)) { return; } /* is this within the already-selected area? */ if (!gtab_insideselection(ptab, row, cell)) { // no selection, or clicked outside the selection - make new selection // before sending the right-click // if shift is down, extend selection if (GetKeyState(VK_SHIFT) & 0x8000) { gtab_extendsel(hwnd, ptab, row, cell, TRUE); } else { /* record and paint new selection */ if (ptab->hdr.selectmode & TM_ROW) { cell = 0; ncells = ptab->hdr.ncols; } else { ncells = 1; } gtab_select(hwnd, ptab, row, cell, 1, ncells, TRUE); } } // now we have sent the selection, pass the message onto him hOwner = (HWND) GetWindowLongPtr(hwnd, WW_OWNER); SendMessage(hOwner, WM_RBUTTONDOWN, 0, MAKELONG( (short)x, (short)y)); }
LRESULT gtab_wndproc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { CREATESTRUCT FAR * csp; HWND hOwner; lpTable ptab; lpTableSelection pselect; long oldtop; long change; switch (msg) { case WM_CREATE: /* create window. set the wnd extra bytes to * contain the owner window and a null table. * Owner window is either in lParam or the parent. * Then wait for TM_NEWID. */ csp = (CREATESTRUCT FAR *) lParam; if (csp->lpCreateParams == NULL) { hOwner = GetParent(hwnd); } else { hOwner = (HWND) csp->lpCreateParams; } ptab = NULL; SetWindowLongPtr(hwnd, WL_TABLE, (LONG_PTR) ptab); SetWindowLongPtr(hwnd, WW_OWNER, (LONG_PTR) hOwner); SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE); SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE); break; case TM_NEWID: /* complete change of table. * close old table, discard memory and * build new table */ ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_sendtq(hwnd, TQ_CLOSE, ptab->hdr.id); gtab_deltable(hwnd, ptab); SetCursor((HCURSOR)hNormCurs); SetWindowLongPtr(hwnd, WL_TABLE, 0); } if ( (ptab = gtab_buildtable(hwnd, (DWORD_PTR)lParam)) != NULL) { SetWindowLongPtr(hwnd, WL_TABLE, (LONG_PTR) ptab); gtab_setsize(hwnd, ptab); } else { SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE); SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE); } InvalidateRect(hwnd, NULL, TRUE); break; case TM_NEWLAYOUT: /* change of layout but for same id. no TQ_CLOSE, * but otherwise same as TM_NEWID */ ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_deltable(hwnd, ptab); SetCursor((HCURSOR)hNormCurs); SetWindowLongPtr(hwnd, WL_TABLE, 0); } if ( (ptab = gtab_buildtable(hwnd, (DWORD_PTR)lParam)) != NULL) { SetWindowLongPtr(hwnd, WL_TABLE, (LONG_PTR) ptab); gtab_setsize(hwnd, ptab); } else { SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE); SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE); } InvalidateRect(hwnd, NULL, TRUE); break; case TM_REFRESH: /* data in table has changed. nrows may have * changed. ncols and col types have not changed */ ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_newsize(hwnd, ptab); gtab_sendtq(hwnd, TQ_SHOWWHITESPACE, (LPARAM) &ptab->show_whitespace); } InvalidateRect(hwnd, NULL, TRUE); break; case TM_SELECT: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { pselect = (lpTableSelection) lParam; gtab_select(hwnd, ptab, pselect->startrow, pselect->startcell, pselect->nrows, pselect->ncells, TRUE); gtab_showsel_middle(hwnd, ptab, pselect->dyRowsFromTop); } break; case TM_GETSELECTION: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { pselect = (lpTableSelection) lParam; *pselect = ptab->select; } break; case TM_PRINT: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { return gtab_print(hwnd, ptab, (lpPrintContext) lParam); } return FALSE; case TM_SETTABWIDTH: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (!ptab) return 0; ptab->tabchars = (int)lParam; InvalidateRect(hwnd, NULL, FALSE); break; case TM_TOPROW: /* return top row. if wParam is TRUE, set lParam * as the new toprow */ ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab == NULL) { return(0); } oldtop = ptab->toprow; if ((wParam) && (lParam < ptab->hdr.nrows)) { change = (long)lParam - ptab->toprow; change -= ptab->hdr.fixedrows; gtab_dovscroll(hwnd, ptab, change); } return(oldtop); case TM_ENDROW: /* return the last visible row in the window */ ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab == NULL) { return(0); } return(ptab->nlines + ptab->toprow - 1); case TM_APPEND: /* new rows have been added to the end of the * table, but the rest of the table has not * been changed. Update without forcing redraw of * everything. * lParam contains the new total nr of rows */ ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_append(hwnd, ptab, (int) wParam, (DWORD_PTR)lParam); return(TRUE); } break; case WM_SIZE: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_setsize(hwnd, ptab); } break; case WM_ERASEBKGND: return TRUE; case WM_DESTROY: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_sendtq(hwnd, TQ_CLOSE, ptab->hdr.id); gtab_deltable(hwnd, ptab); } break; case WM_SYSCOLORCHANGE: InvalidateRect(hwnd, NULL, TRUE); break; case WM_PAINT: gtab_paint(hwnd); break; case WM_HSCROLL: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_msg_hscroll(hwnd, ptab, GET_SCROLL_OPCODE(wParam, lParam), GET_SCROLL_POS(wParam, lParam)); } break; case WM_VSCROLL: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_msg_vscroll(hwnd, ptab, GET_SCROLL_OPCODE(wParam, lParam), GET_SCROLL_POS(wParam, lParam)); } break; case WM_MOUSEMOVE: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_move(hwnd, ptab, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)); } else { SetCursor((HCURSOR)hNormCurs); } break; case WM_LBUTTONDOWN: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_press(hwnd, ptab, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)); } break; case WM_RBUTTONDOWN: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_rightclick(hwnd, ptab, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)); } break; case WM_LBUTTONUP: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_release(hwnd, ptab, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)); } break; case WM_LBUTTONDBLCLK: ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { gtab_dblclick(hwnd, ptab, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)); } break; case WM_KEYDOWN: /* handle key presses for cursor movement about * the table, and return/space for selection. * Any key we don't handle is passed to the owner window * for him to handle. * The table window should have the focus */ ptab = (lpTable) GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { if (gtab_key(hwnd, ptab, (int)wParam) != 0) { hOwner = (HWND) GetWindowLongPtr(hwnd, WW_OWNER); return(SendMessage(hOwner, WM_KEYDOWN, wParam, lParam)); } else { return(0); } } break; #ifdef WM_MOUSEWHEEL case WM_MOUSEWHEEL: ptab = (lpTable)GetWindowLongPtr(hwnd, WL_TABLE); if (ptab != NULL) { if (gtab_mousewheel(hwnd,ptab, LOWORD(wParam), (short)HIWORD(wParam))) { hOwner = (HWND)GetWindowLongPtr(hwnd, WW_OWNER); return SendMessage(hOwner, WM_MOUSEWHEEL, wParam, lParam); } } break; #endif default: return(DefWindowProc(hwnd, msg, wParam, lParam)); } return(TRUE); }
/* * build up a Table struct (excluding data allocation and * anything to do with font or window size). * return ptr to this or NULL if error */ lpTable gtab_buildtable( HWND hwnd, DWORD_PTR id ) { lpTable ptab; int ncols, i; ColPropsList cplist; ptab = (lpTable) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Table)); if (ptab == NULL) { return(NULL); } // get the tab width. most clients will not support this if (gtab_sendtq(hwnd, TQ_TABS, (LPARAM) &ptab->tabchars) == FALSE) { ptab->tabchars = TABWIDTH_DEFAULT; } // get the show whitespace value if (gtab_sendtq(hwnd, TQ_SHOWWHITESPACE, (LPARAM) &ptab->show_whitespace) == FALSE) { ptab->show_whitespace = FALSE; } /* get the row/column count from owner window */ ptab->hdr.id = id; ptab->hdr.props.valid = 0; ptab->hdr.sendscroll = FALSE; if (gtab_sendtq(hwnd, TQ_GETSIZE, (LPARAM) &ptab->hdr) == FALSE) { return(NULL); } ncols = ptab->hdr.ncols; ptab->pcolhdr = (lpColProps) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ColProps) * ncols); if (ptab->pcolhdr == NULL) { /* should prob send TQ_CLOSE at this point */ return(NULL); } /* init col properties to default */ for (i=0; i < ncols; i++) { ptab->pcolhdr[i].props.valid = 0; ptab->pcolhdr[i].nchars = 0; } /* get the column props from owner */ cplist.plist = ptab->pcolhdr; cplist.id = id; cplist.startcol = 0; cplist.ncols = ncols; gtab_sendtq(hwnd, TQ_GETCOLPROPS, (LPARAM) &cplist); /* init remaining fields */ ptab->pcellpos = (lpCellPos) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CellPos) * ncols); if (ptab->pcellpos == NULL) { return(NULL); } ptab->scrollscale = 1; ptab->scroll_dx = 0; ptab->toprow = 0; ptab->pdata = NULL; ptab->nlines = 0; ptab->trackmode = TRACK_NONE; /* we have to notify owner of the current selection * whenever it is changed */ ptab->select.id = id; gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE); /* calc ave height/width, cell widths and min height. * these change only when cell properties / col count changes - * ie only on rebuild-header events */ gtab_calcwidths(hwnd, ptab); return(ptab); }
/* * extend the selection to set the new anchor point as startrow, startcell. * * nrows and ncells will then be set to include the end row of the previous * selection. nrows, ncells < 0 indicate left and up. -1 and +1 both indicate * just one cell or row selected. */ VOID gtab_extendsel( HWND hwnd, lpTable ptab, long startrow, long startcell, BOOL bNotify ) { long endrow, endcell, nrows, ncells; /* * if no current selection, then just select the new anchor point */ if (ptab->select.nrows == 0) { gtab_select(hwnd, ptab, startrow, startcell, 1, (ptab->hdr.selectmode & TM_ROW) ? ptab->hdr.ncols:1, bNotify); return; } if (startrow >= ptab->hdr.nrows) { startrow = ptab->hdr.nrows -1; } else if (startrow < 0) { startrow = 0; } if (startcell >= ptab->hdr.ncols) { startcell = ptab->hdr.ncols-1; } else if (startcell < 0) { startcell = 0; } /* calculate the row just beyond the selection * this is one above for upwards sels, and one below for * downard-extending sels. Then adjust down or up one * to be the actual (inclusive) last row. */ endrow = ptab->select.startrow + ptab->select.nrows; if (ptab->select.nrows < 0) { endrow++; } else { endrow--; } if (endrow >= ptab->hdr.nrows) { endrow = ptab->hdr.nrows-1; } nrows = endrow - startrow; if (nrows >= 0) { // convert from exclusive to inclusive nrows++; } else { // convert from exclusive to inclusive nrows--; } /* same calculation for cells */ endcell = ptab->select.startcell + ptab->select.ncells; if (ptab->select.ncells < 0) { endcell++; } else { endcell--; } ncells = endcell - startcell; if (ncells >= 0) { ncells++; } else { ncells--; } gtab_select(hwnd, ptab, startrow, startcell, nrows, ncells, bNotify); }
/* * called on mouse-up. complete any tracking that was happening */ void gtab_release(HWND hwnd, lpTable ptab, int x, int y) { lpCellPos ppos; lpProps pprop; long row, cell; int cx; switch(ptab->trackmode) { case TRACK_NONE: return; case TRACK_COLUMN: /* erase marker lines */ gtab_drawvertline(hwnd, ptab); ReleaseCapture(); ptab->trackmode = TRACK_NONE; /* adjust cell width */ ppos = &ptab->pcellpos[ptab->tracknr]; cx = ptab->trackline1 - ppos->start; pprop = &ptab->pcolhdr[ptab->tracknr].props; pprop->valid |= P_WIDTH; pprop->width = cx; gtab_calcwidths(hwnd, ptab); gtab_setsize(hwnd, ptab); InvalidateRect(hwnd, NULL, FALSE); return; case TRACK_CELL: row = gtab_linetorow(hwnd, ptab, gtab_ytoline(hwnd, ptab, y)); cell = gtab_xtocol(hwnd, ptab, x); ReleaseCapture(); ptab->trackmode = TRACK_NONE; // ignore if before or beyond data if ( (row < ptab->hdr.fixedrows) || (cell < ptab->hdr.fixedcols)) { if (ptab->hdr.fixedselectable == FALSE) { gtab_select( hwnd, ptab, ptab->select.startrow, ptab->select.startcell, ptab->select.nrows, ptab->select.ncells, TRUE); return; } } if ((row >= ptab->hdr.nrows) || (cell >= ptab->hdr.ncols)) { gtab_select( hwnd, ptab, ptab->select.startrow, ptab->select.startcell, ptab->select.nrows, ptab->select.ncells, TRUE); return; } /* * Extend to this new selection end point * we used to only do this if shift key pressed, but that * is not a good UI. */ gtab_extendsel(hwnd, ptab, row, cell, TRUE); return; } }
/* * called on mouse-down events. decide what to start tracking. */ void gtab_press(HWND hwnd, lpTable ptab, int x, int y) { long cell, ncells; long row; if (ptab->trackmode != TRACK_NONE) { return; } /* has he grabbed a cell-edge to resize ? */ cell = gtab_xtocol(hwnd, ptab, x); if (cell == -1) { return; } if (gtab_isborder(hwnd, ptab, x, cell)) { gtab_trackcol(hwnd, ptab, cell, x); return; } if ( (cell > 0) && gtab_isborder(hwnd, ptab, x, cell-1)) { gtab_trackcol(hwnd, ptab, cell, x); return; } /* find which line he selected */ row = gtab_linetorow(hwnd, ptab, gtab_ytoline(hwnd, ptab, y)); /* is he selecting a disabled fixed area ? */ if ( (row < ptab->hdr.fixedrows) || (cell < ptab->hdr.fixedcols)) { if (ptab->hdr.fixedselectable == FALSE) { return; } } // ignore if beyond data if ((row >= ptab->hdr.nrows) || (cell >= ptab->hdr.ncols)) { return; } /* ok, start cell selection */ ptab->trackmode = TRACK_CELL; SetCapture(hwnd); /* record and paint new selection */ if (ptab->hdr.selectmode & TM_ROW) { cell = 0; ncells = ptab->hdr.ncols; } else { ncells = 1; } /* * if the shift key is down, then extend the selection to this * new anchor point, rather than create a new selection */ if (GetKeyState(VK_SHIFT) & 0x8000) { gtab_extendsel(hwnd, ptab, row, cell, FALSE); } else { gtab_select(hwnd, ptab, row, cell, 1, ncells, FALSE); } return; }
/* handle key-down events - scroll windows and/or move selection */ int gtab_key(HWND hwnd, lpTable ptab, int vkey) { long startrow, ncells, startcell; BOOL bControl = FALSE; BOOL bShift = FALSE; if (GetKeyState(VK_CONTROL) & 0x8000) { bControl = TRUE; } if (GetKeyState(VK_SHIFT) & 0x8000) { /* ignore shift key here if TM_MANY -multiple selection flag- is * not selected */ if (ptab->hdr.selectmode & TM_MANY) { bShift = TRUE; } } switch(vkey) { case VK_UP: if (bControl) { /* control-uparrow scrolls window without selection. * the selection is de-selected (to avoid surprises * moving back to it). */ gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE); gtab_dovscroll(hwnd, ptab, -1); } else { /* uparrow moves selection up one line */ gtab_changesel(hwnd, ptab, -1, 0, FALSE, bShift); } return(0); case VK_DOWN: if (bControl) { /* control downarrow scrolls window without * a selection. */ gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE); gtab_dovscroll(hwnd, ptab, 1); } else { /* the normal gtab_changesel behaviour is * that if the selected line is not visible now, * we scroll it to the top of the window. This is fine * in most cases but causes unacceptable jumps when * repeatedly scrolling down with the down key. * * Thus we now have an argument to changesel to say * that in this case, if you need to move the line onto * the window, move it to the bottom and not the top */ gtab_changesel(hwnd, ptab, 1, 0, TRUE, bShift); } return(0); case VK_LEFT: /* if cell-selection mode, move left one cell. * otherwise the whole row is selected - scroll * the line left a little */ if (ptab->hdr.selectmode & TM_ROW) { if (bControl) { /* ctrl-left moves to start of line */ gtab_dohscroll(hwnd, ptab, -(ptab->scroll_dx)); } else { gtab_dohscroll(hwnd, ptab, -(ptab->avewidth)); } } else { gtab_changesel(hwnd, ptab, 0, -1, FALSE, bShift); } return(0); case VK_RIGHT: /* if cell-selection mode, move right one cell. * otherwise the whole row is selected - scroll * the line right a little */ if (ptab->hdr.selectmode & TM_ROW) { if (bControl) { /* control-right moves to right end of line */ gtab_dohscroll(hwnd, ptab, ptab->rowwidth - ptab->winwidth); } else { gtab_dohscroll(hwnd, ptab, ptab->avewidth); } } else { gtab_changesel(hwnd, ptab, 0, 1, TRUE, bShift); } return(0); case VK_HOME: if (bControl) { /* control-home == top of file */ gtab_dovscroll(hwnd, ptab, -(ptab->toprow)); } /* top of window */ gtab_selhome(hwnd, ptab, bShift); gtab_showsel(hwnd, ptab, FALSE); return(0); case VK_END: if (bControl) { /* control-end -> end of file */ startrow = ptab->hdr.nrows-1; } else { startrow = gtab_linetorow(hwnd, ptab, ptab->nlines - 1); if (startrow >= ptab->hdr.nrows) { startrow = ptab->hdr.nrows-1; } } startcell = 0; ncells = ptab->hdr.ncols; if (!(ptab->hdr.selectmode & TM_ROW)) { startcell = ptab->hdr.ncols-1; ncells = 1; } if (bShift) { gtab_extendsel(hwnd, ptab, startrow, startcell, TRUE); } else { gtab_select(hwnd, ptab, startrow, startcell, 1, ncells, TRUE); } /* we have selected the bottom line. We don't want to * move it up into the window, since the intended * effect is to select the lowest line. This doesn't * apply to the ctrl-end behaviour (move to bottom of * buffer. */ if (bControl) { /* move the selection to make it visible - but move it * to the bottom and not to the top of the window */ gtab_showsel(hwnd, ptab, TRUE); } return(0); case VK_RETURN: if (ptab->select.nrows != 0) { gtab_showsel(hwnd, ptab, FALSE); gtab_enter(hwnd, ptab, ptab->select.startrow, ptab->select.startcell, ptab->select.nrows, ptab->select.ncells); } return(0); case VK_SPACE: /* toggle the selection */ if (ptab->select.nrows == 0) { /* no selection - make one */ gtab_changesel(hwnd, ptab, 0, 0, TRUE, FALSE); } else { /* there is a selection - deselect it */ gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE); } return(0); case VK_PRIOR: /* page up */ if (ptab->nlines > 3) { gtab_dovscroll(hwnd, ptab, -(ptab->nlines - 3)); } gtab_selhome(hwnd, ptab, bShift); return(0); case VK_NEXT: /* page down */ /* scroll down one page */ if (ptab->nlines > 3) { gtab_dovscroll(hwnd, ptab, (ptab->nlines - 3)); } /* select new bottom line */ startrow = gtab_linetorow(hwnd, ptab, ptab->nlines - 1); if (startrow >= ptab->hdr.nrows) { startrow = ptab->hdr.nrows-1; } startcell = 0; ncells = ptab->hdr.ncols; if (!(ptab->hdr.selectmode & TM_ROW)) { startcell = ptab->hdr.ncols-1; ncells = 1; } /* select bottom line, but don't call showsel * since we don't want to adjust it's position - we * want it to remain at the bottom of the window */ if (bShift) { gtab_extendsel(hwnd, ptab, startrow, startcell, TRUE); } else { gtab_select(hwnd, ptab, startrow, startcell, 1, ncells, TRUE); } return(0); default: return(1); } }
/* move the selection a specified nr of rows or cells * if no selection, select first visible unit * * if bExtend is true and there is a current selection, then extend it rather than * replace it. Note that (startrow, startcell) will always be set to the newly * selected position - this is the anchor point. nrows or ncells may be negative * if the selection extends upwards above the anchor. nrows == -1 is the same * as nrows == 1, meaning only the current row is visible. Similarly * (in TM_CELL mode), ncells may be negative. * * Move the selection (ie anchor point) to make it visible. bToBottom * indicates whether it should be moved to the bottom or the top * of the window. */ VOID gtab_changesel( HWND hwnd, lpTable ptab, long rowincr, int cellincr, BOOL bToBottom, BOOL bExtend ) { long row, col, ncols; /* is there a selection ? */ if (ptab->select.nrows == 0) { /* no selection - force a selection * at the first visible unit */ if (ptab->hdr.fixedselectable) { row = 0; col = 0; } else { row = gtab_linetorow(hwnd, ptab, ptab->hdr.fixedrows); /* should really check for first visible cell */ col = ptab->hdr.fixedcols; } ncols = 1; if (ptab->hdr.selectmode & TM_ROW) { col = 0; ncols = ptab->hdr.ncols; } gtab_select(hwnd, ptab, row, col, 1, ncols, TRUE); } else { /* move the anchor point by rowincr, cellincr */ row = ptab->select.startrow + rowincr; col = ptab->select.startcell + cellincr; /* * ensure that new anchor point is in a valid position */ while (col >= ptab->hdr.ncols) { col -= ptab->hdr.ncols; row++; } while (col < 0) { col += ptab->hdr.ncols; row--; } if (row < 0) { row = 0; } if (row >= ptab->hdr.nrows) { row = ptab->hdr.nrows-1; } /* check we haven't moved into non-selectable region */ if ((row < ptab->hdr.fixedrows) && (!ptab->hdr.fixedselectable)) { row = ptab->hdr.fixedrows; } if (bExtend) { gtab_extendsel(hwnd, ptab, row, col, TRUE); } else { gtab_select( hwnd, ptab, row, col, 1, (ptab->hdr.selectmode & TM_ROW) ? ptab->hdr.ncols : 1, TRUE); } } /* ensure selection visible */ gtab_showsel(hwnd, ptab, bToBottom); }