home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / windiff / tscroll.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  38KB  |  1,148 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /****************************** Module Header *******************************
  13. * Module Name: TSCROLL.C
  14. *
  15. * Scrolling and selection routines.
  16. *
  17. * Functions:
  18. *
  19. * gtab_msg_vscroll()
  20. * gtab_msg_hscroll()
  21. * gtab_dovscroll()
  22. * gtab_dohscroll()
  23. * gtab_linetorow()
  24. * gtab_rowtoline()
  25. * gtab_select()
  26. * gtab_ytoline()
  27. * gtab_xtocol()
  28. * gtab_isborder()
  29. * gtab_enter()
  30. * gtab_trackcol()
  31. * gtab_press()
  32. * gtab_release()
  33. * gtab_move()
  34. * gtab_dblclick()
  35. * gtab_showsel()
  36. * gtab_showsel_middle()
  37. * gtab_changesel()
  38. * gtab_selhome()
  39. * gtab_key()
  40. *
  41. * Comments:
  42. *
  43. * This implementation currently only supports TM_SINGLE, not TM_MANY
  44. * modes of selection.
  45. *
  46. ****************************************************************************/
  47.  
  48. #include <windows.h>
  49. #include <commdlg.h>
  50.  
  51. #include "gutils.h"
  52. #include "table.h"
  53. #include "tpriv.h"
  54.  
  55. /***************************************************************************
  56.  * Function: gtab_msg_vscroll
  57.  *
  58.  * Purpose:
  59.  *
  60.  * Handle a vscroll message 
  61.  */
  62. void
  63. gtab_msg_vscroll(HWND hwnd, lpTable ptab, int opcode, int pos)
  64. {
  65.         long change;
  66.  
  67.         switch(opcode) {
  68.         case SB_THUMBPOSITION:
  69.                 change = (pos * ptab->scrollscale) - ptab->toprow;
  70.                 break;
  71.  
  72.         case SB_LINEUP:
  73.                 change = -1;
  74.                 break;
  75.  
  76.         case SB_LINEDOWN:
  77.                 change = 1;
  78.                 break;
  79.  
  80.         case SB_PAGEUP:
  81.                 change = - (ptab->nlines - 3);
  82.                 break;
  83.  
  84.         case SB_PAGEDOWN:
  85.                 change = (ptab->nlines - 3);
  86.                 break;
  87.  
  88.         default:
  89.                 return;
  90.         }
  91.         gtab_dovscroll(hwnd, ptab, change);
  92. }
  93.  
  94. /***************************************************************************
  95.  * Function: gtab_msg_hscroll
  96.  *
  97.  * Purpose:
  98.  *
  99.  * Handle a hscroll message 
  100.  */
  101. void
  102. gtab_msg_hscroll(HWND hwnd, lpTable ptab, int opcode, int pos)
  103. {
  104.         int change;
  105.  
  106.         switch(opcode) {
  107.         case SB_THUMBPOSITION:
  108.                 change = pos - ptab->scroll_dx;
  109.                 break;
  110.  
  111.         case SB_LINEUP:
  112.                 change = -(ptab->avewidth);
  113.                 break;
  114.  
  115.         case SB_LINEDOWN:
  116.                 change = ptab->avewidth;
  117.                 break;
  118.  
  119.         case SB_PAGEUP:
  120.                 change = - (ptab->winwidth * 2 / 3);
  121.                 break;
  122.  
  123.         case SB_PAGEDOWN:
  124.                 change = (ptab->winwidth * 2 / 3);
  125.                 break;
  126.  
  127.         default:
  128.                 return;
  129.         }
  130.         gtab_dohscroll(hwnd, ptab, change);
  131. }
  132.  
  133.  
  134.  
  135. /***************************************************************************
  136.  * Function: gtab_dovscroll
  137.  *
  138.  * Purpose:
  139.  *
  140.  * Set new vertical scroll pos,
  141.  * adjust linedata array
  142.  * set line win-relative start posns & clip top/bottom posns
  143.  * revise display.
  144.  */
  145. void
  146. gtab_dovscroll(HWND hwnd, lpTable ptab, long change)
  147. {
  148.         int cury, i;
  149.         long ncopy;
  150.         lpCellPos cp;
  151.         LineData ldtemp;
  152.         RECT rc, rcpaint;
  153.         long range;
  154.         long newtop;
  155.         int newpos;
  156.  
  157.  
  158.         range = ptab->hdr.nrows - (ptab->nlines - 1);
  159.         newtop = ptab->toprow + change;
  160.         if (range < 0) {
  161.                 range = 0;
  162.         }
  163.         if (newtop > range) {
  164.                 change = range - ptab->toprow;
  165.         } else if (newtop < 0) {
  166.                 change = -(ptab->toprow);
  167.         }
  168.         ptab->toprow += change;
  169.  
  170.         newpos = (int) (newtop / ptab->scrollscale);
  171.         SetScrollPos(hwnd, SB_VERT, newpos, TRUE);
  172.  
  173.         if (ptab->hdr.sendscroll) {
  174.                 gtab_sendtq(hwnd, TQ_SCROLL, ptab->toprow);
  175.         }
  176.  
  177.         /* adjust data ptrs rather than invalidate, to retain the
  178.          * data we know is still valid
  179.          */
  180.         if (abs(change) >= ptab->nlines) {
  181.                 gtab_invallines(hwnd, ptab, ptab->hdr.fixedrows,
  182.                         ptab->nlines - ptab->hdr.fixedrows);
  183.                 InvalidateRect(hwnd, NULL, TRUE);
  184.                 change = 0;
  185.         } else if (change < 0) {
  186.                 /* copy data down */
  187.                 ncopy = (ptab->nlines - ptab->hdr.fixedrows) - abs(change);
  188.                 for (i =  ptab->nlines - 1;
  189.                   i >= (ptab->hdr.fixedrows + abs(change)); i--) {
  190.                         ldtemp = ptab->pdata[i - abs(change)];
  191.                         ptab->pdata[i - abs(change)] = ptab->pdata[i];
  192.                         ptab->pdata[i] = ldtemp;
  193.                 }
  194.                 gtab_invallines(hwnd, ptab,
  195.                         ptab->hdr.fixedrows, (int) abs(change));
  196.         } else if (change > 0) {
  197.                 ncopy = (ptab->nlines - ptab->hdr.fixedrows) - change;
  198.                 for (i = ptab->hdr.fixedrows;
  199.                   i < (ncopy + ptab->hdr.fixedrows); i++) {
  200.                         ldtemp = ptab->pdata[i + change];
  201.                         ptab->pdata[i + change] = ptab->pdata[i];
  202.                         ptab->pdata[i] = ldtemp;
  203.                 }
  204.                 gtab_invallines(hwnd, ptab,
  205.                         (int) ncopy + ptab->hdr.fixedrows, (int) change);
  206.         }
  207.  
  208.         /* scroll window */
  209.         GetClientRect(hwnd, &rc);
  210.         rcpaint = rc;
  211.         if (change > 0) {
  212.                 rc.top += (int) (change + ptab->hdr.fixedrows) * ptab->rowheight;
  213.                 rcpaint.top = (ptab->hdr.fixedrows * ptab->rowheight);
  214.                 rcpaint.top += rc.bottom - rc.top;
  215.         } else if (change < 0) {
  216.                 rc.top += (ptab->hdr.fixedrows * ptab->rowheight);
  217.                 rc.bottom -= (int) (change * ptab->rowheight);
  218.                 rcpaint.bottom -= rc.bottom - rc.top;
  219.         }
  220.  
  221.         /* loop through each line setting relative posn and clipping */
  222.  
  223.         /* set up all rows  - the fixed/moveable difference for
  224.          * rows is made at fetch-time during painting, when we remember
  225.          * which absolute row nr to ask for, for a given screen line
  226.          */
  227.         cury = 0;
  228.         for (i = 0; i < ptab->nlines; i++) {
  229.                 cp = &ptab->pdata[i].linepos;
  230.                 cp->start = cury;
  231.                 cp->clipstart = cury;
  232.                 cp->clipend = cury + cp->size;
  233.                 cury += cp->size;
  234.         }
  235.  
  236.         /* now move and repaint the window */
  237.         if (change != 0) {
  238.                 if (rc.top < rc.bottom) {
  239.                         ScrollWindow(hwnd, 0, (int) -(change * ptab->rowheight),
  240.                                 &rc, NULL);
  241.  
  242.                 }
  243.  
  244.                 /* force repaint now, not just post message for later,
  245.                  * since we want to repaint that line before the next
  246.                  * scroll down occurs
  247.                  */
  248.                 RedrawWindow(hwnd, &rcpaint, NULL,
  249.                         RDW_ERASE | RDW_INVALIDATE|RDW_UPDATENOW);
  250.         }
  251. }
  252.  
  253. /***************************************************************************
  254.  * Function: gtab_dohscroll
  255.  *
  256.  * Purpose:
  257.  *
  258.  * Set new horizontal scroll pos,
  259.  * set col win-relative start posns & clip left/right posns
  260.  * revise display.
  261.  */
  262. void
  263. gtab_dohscroll(HWND hwnd, lpTable ptab, long change)
  264. {
  265.         int curx, i;
  266.         int moveable;
  267.         lpCellPos cp;
  268.         int newdx, range;
  269.  
  270.  
  271.         /* check that the new scroll pos is still within the valid range */
  272.         range = ptab->rowwidth - ptab->winwidth;
  273.         newdx = ptab->scroll_dx + (int) change;
  274.         if (range < 0) {
  275.                 range = 0;
  276.         }
  277.         if (newdx > range) {
  278.                 change = range - ptab->scroll_dx;
  279.         } else if (newdx < 0) {
  280.                 change = -(ptab->scroll_dx);
  281.         }
  282.         ptab->scroll_dx += (int) change;
  283.  
  284.         SetScrollPos(hwnd, SB_HORZ, ptab->scroll_dx, TRUE);
  285.         InvalidateRect(hwnd, NULL, TRUE);
  286.         
  287.         /* loop through each col setting relative posn and clipping */
  288.         /* clip off 1 pixel left and right (we added 2 on to size for this) */
  289.  
  290.         /* first set up fixed columns */
  291.         curx = 0;
  292.         for (i = 0; i < ptab->hdr.fixedcols; i++) {
  293.                 cp = &ptab->pcellpos[i];
  294.                 cp->start = curx + 1;
  295.                 cp->clipstart = cp->start;
  296.                 cp->clipend = cp->start + cp->size - 2;
  297.                 curx += cp->size;
  298.         }
  299.  
  300.         /* now moveable columns. remember start of moveable cols */
  301.         moveable = curx;
  302.         curx = - ptab->scroll_dx;       /* rel. pos of col */
  303.         for (i = ptab->hdr.fixedcols; i < ptab->hdr.ncols; i++) {
  304.                 cp = &ptab->pcellpos[i];
  305.                 cp->start = curx + moveable + 1;
  306.                 cp->clipstart = max(moveable+1, cp->start);
  307.                 cp->clipend = cp->start + cp->size - 2;
  308.                 curx += cp->size;
  309.         }
  310. }
  311.  
  312. /***************************************************************************
  313.  * Function: gtab_linetorow
  314.  *
  315.  * Purpose:
  316.  *
  317.  * Convert screen line nr to table row nr
  318.  */
  319. long
  320. gtab_linetorow(HWND hwnd, lpTable ptab, int line)
  321. {
  322.         if (line < ptab->hdr.fixedrows) {
  323.                 return(line);
  324.         }
  325.  
  326.         return (line + ptab->toprow);
  327. }
  328.  
  329. /***************************************************************************
  330.  * Function: gtab_rowtoline
  331.  *
  332.  * Purpose:
  333.  *
  334.  * Convert table row nr to screen line nr or -1 if not on screen
  335.  */
  336. int
  337. gtab_rowtoline(HWND hwnd, lpTable ptab, long row)
  338. {
  339.         if (row < ptab->hdr.fixedrows) {
  340.                 return( (int) row);
  341.         }
  342.  
  343.         row -= ptab->toprow;
  344.         if ((row >= ptab->hdr.fixedrows) && (row < ptab->nlines)) {
  345.                 return ( (int) row);
  346.         }
  347.         return(-1);
  348. }
  349.  
  350. /***************************************************************************
  351.  * Function: gtab_select
  352.  *
  353.  * Purpose:
  354.  *
  355.  * Replace old selection with new. Notify owner if bNotify. Change
  356.  * display to reflect new display.
  357.  */
  358. void
  359. gtab_select(
  360.         HWND hwnd,
  361.         lpTable ptab,
  362.         long row,
  363.         long col,
  364.         long nrows,
  365.         long ncells,
  366.         BOOL bNotify)
  367. {
  368.         int line;
  369.  
  370.         /* if in ROW mode, force col and ncells to reflect the entire row. */
  371.         if (ptab->hdr.selectmode & TM_ROW) {
  372.                 col = 0;
  373.                 ncells = ptab->hdr.ncols;
  374.         }
  375.  
  376.         /* clear existing sel if valid and visible */
  377.         if ((ptab->select.nrows > 0) && (ptab->selvisible == TRUE)) {
  378.  
  379.                 /* only clear sel if it is different from the new one */
  380.                 if ((ptab->select.startrow != row) ||
  381.                     (ptab->select.startcell != col) ||
  382.                     (ptab->select.nrows != nrows) ||
  383.                     (ptab->select.ncells != ncells)) {
  384.                         line = gtab_rowtoline(hwnd, ptab,
  385.                                 ptab->select.startrow);
  386.                         if (line >= 0) {
  387.                                 gtab_invertsel(hwnd, ptab, NULL);
  388.                         }
  389.                         ptab->selvisible = FALSE;
  390.                 }
  391.         }
  392.  
  393.         /* set select fields and send TQ_SELECT */
  394.         if (row < ptab->hdr.nrows) {
  395.                 ptab->select.startrow = row;
  396.                 ptab->select.startcell = col;
  397.                 ptab->select.nrows = nrows;
  398.                 ptab->select.ncells = ncells;
  399.         } else {
  400.                 ptab->select.nrows = 0;
  401.                 ptab->select.startrow = 0;
  402.                 ptab->select.startcell = 0;
  403.                 ptab->select.ncells = 0;
  404.         }
  405.  
  406.         if (bNotify) {
  407.                 gtab_sendtq(hwnd, TQ_SELECT, (long) (LPSTR) &ptab->select);
  408.         }
  409.  
  410.         /* paint in selection */
  411.         if (nrows > 0) {
  412.                 if (!ptab->selvisible) {
  413.                         gtab_invertsel(hwnd, ptab, NULL);
  414.                         ptab->selvisible = TRUE;
  415.                 }
  416.         } else {
  417.                 if (ptab->selvisible) {
  418.                         gtab_invertsel(hwnd, ptab, NULL);
  419.                         ptab->selvisible = FALSE;
  420.                 }
  421.                 ptab->selvisible = FALSE;
  422.         }
  423. }
  424.  
  425. /***************************************************************************
  426.  * Function: gtab_ytoline
  427.  *
  428.  * Purpose:
  429.  *
  430.  * Convert window y co-ord to a line nr
  431.  */
  432. int
  433. gtab_ytoline(HWND hwnd, lpTable ptab, int y)
  434. {
  435.         return(y / ptab->rowheight);
  436. }
  437.  
  438. /***************************************************************************
  439.  * Function: gtab_xtocol
  440.  *
  441.  * Purpose:
  442.  *
  443.  * Convert window x co-ord to a cell nr
  444.  */
  445. int
  446. gtab_xtocol(HWND hwnd, lpTable ptab, int x)
  447. {
  448.         int i;
  449.         lpCellPos ppos;
  450.  
  451.         for (i = 0; i < ptab->hdr.ncols; i++) {
  452.                 ppos = &ptab->pcellpos[i];
  453.                 if (ppos->clipstart < ppos->clipend) {
  454.                         if ( (x >= ppos->clipstart) && (x < ppos->clipend)) {
  455.                                 return(i);
  456.                         }
  457.                 }
  458.         }
  459.         return(-1);
  460. }
  461.  
  462.  
  463. /***************************************************************************
  464.  * Function: gtab_isborder
  465.  *
  466.  * Purpose:
  467.  *
  468.  * Check if x co-ord is 'near' (+- 2 pixels) the right border of given cell
  469.  */
  470. BOOL
  471. gtab_isborder(HWND hwnd, lpTable ptab, int x, int col)
  472. {
  473.         
  474.         if (abs(ptab->pcellpos[col].clipend - x) < 2) {
  475.                 return(TRUE);
  476.         } else {
  477.                 return(FALSE);
  478.         }
  479. }
  480.  
  481.  
  482. /***************************************************************************
  483.  * Function: gtab_enter
  484.  *
  485.  * Purpose:
  486.  *
  487.  * Set selection and send 'TQ_ENTER' event to owner
  488.  */
  489. void
  490. gtab_enter(HWND hwnd, lpTable ptab, long row, long col, long nrows,
  491.         long ncells)
  492. {
  493.         int line;
  494.  
  495.         /* clear existing sel if valid and visible */
  496.         if ((ptab->select.nrows > 0) && (ptab->selvisible == TRUE)) {
  497.  
  498.                 /* only clear sel if it is different from the new one */
  499.                 if ((ptab->select.startrow != row) ||
  500.                     (ptab->select.startcell != col) ||
  501.                     (ptab->select.nrows != nrows) ||
  502.                     (ptab->select.ncells != ncells)) {
  503.                         line = gtab_rowtoline(hwnd, ptab,
  504.                                 ptab->select.startrow);
  505.                         if (line >= 0) {
  506.                                 gtab_invertsel(hwnd, ptab, NULL);
  507.                         }
  508.                         ptab->selvisible = FALSE;
  509.                 }
  510.         }
  511.  
  512.         /* set select fields and send TQ_SELECT */
  513.         if (row < ptab->hdr.nrows) {
  514.                 ptab->select.startrow = row;
  515.                 ptab->select.startcell = col;
  516.                 ptab->select.nrows = nrows;
  517.                 ptab->select.ncells = ncells;
  518.         } else {
  519.                 ptab->select.nrows = 0;
  520.                 ptab->select.startrow = 0;
  521.                 ptab->select.startcell = 0;
  522.                 ptab->select.ncells = 0;
  523.         }
  524.  
  525.         /* paint in selection */
  526.         if (nrows > 0) {
  527.                 if (!ptab->selvisible) {
  528.                         gtab_invertsel(hwnd, ptab, NULL);
  529.                         ptab->selvisible = TRUE;
  530.                 }
  531.                 /* do this at end because it could cause a layout-change */
  532.                 gtab_sendtq(hwnd, TQ_ENTER, (long) (LPSTR) &ptab->select);
  533.         } else {
  534.                 if (ptab->selvisible) {
  535.                         gtab_invertsel(hwnd, ptab, NULL);
  536.                 }
  537.                 ptab->selvisible = FALSE;
  538.         }
  539. }
  540.  
  541.  
  542. /***************************************************************************
  543.  * Function: gtab_trackcol
  544.  *
  545.  * Purpose:
  546.  *
  547.  * Start re-sizing a column
  548.  */
  549. void
  550. gtab_trackcol(HWND hwnd, lpTable ptab, int col, int x)
  551. {
  552.  
  553.         /* ensure we see the mouse-up */
  554.         SetCapture(hwnd);
  555.         ptab->trackmode = TRACK_COLUMN;
  556.         ptab->tracknr = col;
  557.         ptab->trackline1 = x;
  558.  
  559.         /* if line at other side of cell is visible, draw that too */
  560.         if (ptab->pcellpos[col].start >= ptab->pcellpos[col].clipstart) {
  561.                 ptab->trackline2 = ptab->pcellpos[col].start;
  562.         } else {
  563.                 ptab->trackline2 = -1;
  564.         }
  565.         gtab_drawvertline(hwnd, ptab);
  566. }
  567.  
  568.  
  569.  
  570. /***************************************************************************
  571.  * Function: gtab_press
  572.  *
  573.  * Purpose:
  574.  *
  575.  * Called on mouse-down events. decide what to start tracking.
  576.  */
  577. void
  578. gtab_press(HWND hwnd, lpTable ptab, int x, int y)
  579. {
  580.         int cell;
  581.         long row;
  582.  
  583.         if (ptab->trackmode != TRACK_NONE) {
  584.                 return;
  585.         }
  586.  
  587.         /* has he grabbed a cell-edge to resize ? */
  588.         cell = gtab_xtocol(hwnd, ptab, x);
  589.         if (cell == -1) {
  590.                 return;
  591.         }
  592.         if (gtab_isborder(hwnd, ptab, x, cell)) {
  593.                 gtab_trackcol(hwnd, ptab, cell, x);
  594.                 return;
  595.         }
  596.         if ( (cell > 0) && gtab_isborder(hwnd, ptab, x, cell-1)) {
  597.                 gtab_trackcol(hwnd, ptab, cell, x);
  598.                 return;
  599.         }
  600.  
  601.         /* find which line he selected */
  602.         row = gtab_linetorow(hwnd, ptab, gtab_ytoline(hwnd, ptab, y));
  603.  
  604.         /* is he selecting a disabled fixed area ? */
  605.         if ( (row < ptab->hdr.fixedrows) || (cell < ptab->hdr.fixedcols)) {
  606.                 if (ptab->hdr.fixedselectable == FALSE) {
  607.                         return;
  608.                 }
  609.         }
  610.  
  611.         /* ok, start cell selection */
  612.         ptab->trackmode = TRACK_CELL;
  613.         SetCapture(hwnd);
  614.  
  615.         /* record and paint new selection */
  616.         if (ptab->hdr.selectmode & TM_ROW) {
  617.                 gtab_select(hwnd, ptab, row, 0, 1, ptab->hdr.ncols, FALSE);
  618.         } else {
  619.                 gtab_select(hwnd, ptab, row, cell, 1, 1, FALSE);
  620.         }
  621.         return;
  622. }
  623.  
  624. /***************************************************************************
  625.  * Function: gtab_release
  626.  *
  627.  * Purpose:
  628.  *
  629.  * Called on mouse-up. complete any tracking that was happening
  630.  */
  631. void
  632. gtab_release(HWND hwnd, lpTable ptab, int x, int y)
  633. {
  634.         lpCellPos ppos;
  635.         lpProps pprop;
  636.         long row;
  637.         int cx;
  638.  
  639.         switch(ptab->trackmode) {
  640.  
  641.         case TRACK_NONE:
  642.                 return;
  643.         
  644.         case TRACK_COLUMN:
  645.                 /* erase marker lines */
  646.                 gtab_drawvertline(hwnd, ptab);
  647.                 ReleaseCapture();
  648.                 ptab->trackmode = TRACK_NONE;
  649.  
  650.                 /* adjust cell width */
  651.                 ppos = &ptab->pcellpos[ptab->tracknr];
  652.                 cx = ptab->trackline1 - ppos->start;
  653.                 pprop = &ptab->pcolhdr[ptab->tracknr].props;
  654.                 pprop->valid |= P_WIDTH;
  655.                 pprop->width = cx;
  656.                 gtab_calcwidths(hwnd, ptab);
  657.                 gtab_setsize(hwnd, ptab);
  658.                 InvalidateRect(hwnd, NULL, TRUE);
  659.                 return;
  660.  
  661.         case TRACK_CELL:
  662.                 row = gtab_linetorow(hwnd, ptab, gtab_ytoline(hwnd, ptab, y));
  663.                 ReleaseCapture();
  664.                 ptab->trackmode = TRACK_NONE;
  665.  
  666.                 /* keep the same selection. if the mouse is still
  667.                  * in the box, select it, otherwise de-select it
  668.                  */
  669.                 if ((row == ptab->select.startrow) &&
  670.                   ( (ptab->hdr.selectmode & TM_ROW) ||
  671.                     (ptab->select.startcell == gtab_xtocol(hwnd, ptab, x))) ) {
  672.  
  673.                         gtab_select(hwnd, ptab, ptab->select.startrow,
  674.                                 ptab->select.startcell,
  675.                                 ptab->select.nrows, ptab->select.ncells, TRUE);
  676.                 } else {
  677.                         gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE);
  678.                 }
  679.                 return;
  680.         }
  681. }
  682.  
  683.  
  684. /***************************************************************************
  685.  * Function: gtab_move
  686.  *
  687.  * Purpose:
  688.  *
  689.  * Called on mouse-move. if tracking - adjust position, if not,
  690.  * set correct cursor
  691.  */
  692. void
  693. gtab_move(HWND hwnd, lpTable ptab, int x, int y)
  694. {
  695.         BOOL fOK;
  696.         long row;
  697.         int col;
  698.         lpCellPos ppos;
  699.  
  700.         switch(ptab->trackmode) {
  701.  
  702.         case TRACK_NONE:
  703.                 col = gtab_xtocol(hwnd, ptab, x);
  704.                 if (col == -1) {
  705.                         SetCursor(hNormCurs);
  706.                         return;
  707.                 }
  708.                 if (gtab_isborder(hwnd, ptab, x, col)) {
  709.                         SetCursor(hVertCurs);
  710.                         return;
  711.                 }
  712.                 if ( (col > 0) && gtab_isborder(hwnd, ptab, x, col-1)) {
  713.                         SetCursor(hVertCurs);
  714.                         return;
  715.                 }
  716.                 SetCursor(hNormCurs);
  717.                 return;
  718.  
  719.         case TRACK_CELL:
  720.                 row = gtab_linetorow(hwnd, ptab, gtab_ytoline(hwnd, ptab, y));
  721.  
  722.                 /* keep the same selection. if the mouse is still
  723.                  * in the box, select it, otherwise de-select it
  724.                  */
  725.                 if ((row == ptab->select.startrow) &&
  726.                   ( (ptab->hdr.selectmode & TM_ROW) ||
  727.                     (ptab->select.startcell == gtab_xtocol(hwnd, ptab, x))) ) {
  728.  
  729.                         if (!ptab->selvisible) {
  730.                                 gtab_invertsel(hwnd, ptab, NULL);
  731.                                 ptab->selvisible = TRUE;
  732.                         }
  733.                 } else {
  734.                         if (ptab->selvisible) {
  735.                                 gtab_invertsel(hwnd, ptab, NULL);
  736.                                 ptab->selvisible = FALSE;
  737.                         }
  738.                 }
  739.                 return;
  740.         
  741.         case TRACK_COLUMN:
  742.                 /* check that new x is still visible/valid */
  743.                 ppos = &ptab->pcellpos[ptab->tracknr];
  744.                 fOK = FALSE;
  745.  
  746.                 if (ptab->tracknr < ptab->hdr.fixedcols)  {
  747.                         if ((x > ppos->start) && (x < ptab->winwidth)) {
  748.                                 fOK = TRUE;
  749.                         }
  750.                 } else {
  751.                         if ((x > ppos->clipstart) && (x < ptab->winwidth)) {
  752.                                 fOK = TRUE;
  753.                         }
  754.                 }
  755.                 if (fOK == TRUE) {
  756.                         gtab_drawvertline(hwnd, ptab);
  757.                         ptab->trackline1 = x;
  758.                         gtab_drawvertline(hwnd, ptab);
  759.                 }
  760.                 return;
  761.         }
  762. }
  763.  
  764. /***************************************************************************
  765.  * Function: gtab_dblclick
  766.  *
  767.  * Purpose:
  768.  *
  769.  * dbl-click - send an TQ_ENTER event to the owner (if valid) 
  770.  */
  771. void
  772. gtab_dblclick(HWND hwnd, lpTable ptab, int x, int y)
  773. {
  774.         int cell, line;
  775.         long row;
  776.  
  777.         line = gtab_ytoline(hwnd, ptab, y);
  778.         cell = gtab_xtocol(hwnd, ptab, x);
  779.         if ( (line < ptab->hdr.fixedrows) || (cell < ptab->hdr.fixedcols) ) {
  780.                 if (!ptab->hdr.fixedselectable) {
  781.                         return;
  782.                 }
  783.         }
  784.         row = gtab_linetorow(hwnd, ptab, line);
  785.  
  786.         if (ptab->hdr.selectmode & TM_ROW) {
  787.                 gtab_enter(hwnd, ptab, row, 0, 1, ptab->hdr.ncols);
  788.         } else {
  789.                 gtab_enter(hwnd, ptab, row, cell, 1, 1);
  790.         }
  791. }
  792.  
  793. /***************************************************************************
  794.  * Function: gtab_showsel
  795.  *
  796.  * Purpose:
  797.  *
  798.  * Move selection area to visible part of window. Argument bToBottom
  799.  * indicates whether to move the line onto the bottom or the top of the
  800.  * window if not visible - this affects the smoothness of scrolling
  801.  * line-by-line.
  802.  */
  803. void
  804. gtab_showsel(HWND hwnd, lpTable ptab, BOOL bToBottom)
  805. {
  806.         int line;
  807.         long change;
  808.  
  809.         line = gtab_rowtoline(hwnd, ptab, ptab->select.startrow);
  810.  
  811.         /* move up if last line or not at all visible */
  812.         if ( (line < 0) || line == (ptab->nlines - 1)) {
  813.                 change = ptab->select.startrow - ptab->toprow;
  814.                 if (bToBottom) {
  815.                         /* change to bottom of window. subtract 2 not 1
  816.                          * since nlines includes one line that is only
  817.                          * partly visible
  818.                          */
  819.                         change -= (ptab->nlines - 2);
  820.                 }
  821.                 change -= ptab->hdr.fixedrows;
  822.                 gtab_dovscroll(hwnd, ptab, change);
  823.         }
  824.         /* add support for TM_CELL here! */
  825. }
  826.  
  827. /***************************************************************************
  828.  * Function: gtab_showsel_middle
  829.  *
  830.  * Purpose:
  831.  *
  832.  * Scroll the window so that if possible, the selected row is in the
  833.  * middle 60% of the screen so that context around it is visible.
  834.  */
  835. void
  836. gtab_showsel_middle(HWND hwnd, lpTable ptab)
  837. {
  838.         int line;
  839.         long change;
  840.         int mid_top, mid_end;
  841.  
  842.         line = gtab_rowtoline(hwnd, ptab, ptab->select.startrow);
  843.  
  844.  
  845.         /* is this within the middle 60 % ?  */
  846.         mid_top = ptab->nlines * 20 / 100;
  847.         mid_end = ptab->nlines * 80 / 100;
  848.         if ((line < mid_top) || (line > mid_end)) {
  849.  
  850.                 /* no - scroll so that selected line is at
  851.                  * the 20% mark
  852.                  */
  853.                 change = (ptab->select.startrow - mid_top) - ptab->toprow;              
  854.                 change -= ptab->hdr.fixedrows;
  855.                 gtab_dovscroll(hwnd, ptab, change);
  856.         }
  857.         /* again - need code here for TM_CELL mode to ensure that
  858.          * active cell is horizontally scrolled correctly
  859.          */
  860. }
  861.  
  862.  
  863.  
  864. /***************************************************************************
  865.  * Function: gtab_changesel
  866.  *
  867.  * Purpose:
  868.  *
  869.  * Move the selection a specified nr of rows or cells
  870.  * if no selection, select first visible unit
  871.  */
  872. VOID
  873. gtab_changesel(HWND hwnd, lpTable ptab, long rowincr, int cellincr, BOOL bToBottom)
  874. {
  875.         long row, col, nrows, ncols;
  876.  
  877.         /* is there a selection ? */
  878.         if (ptab->select.nrows < 1) {
  879.  
  880.                 /* no selection - force a selection
  881.                  * at the first visible unit
  882.                  */
  883.                 if (ptab->hdr.fixedselectable) {
  884.                         row = 0;
  885.                         col = 0;
  886.                 } else {
  887.                         row = gtab_linetorow(hwnd, ptab, ptab->hdr.fixedrows);
  888.                         /* should really check for first visible cell */
  889.                         col = ptab->hdr.fixedcols;
  890.                 }
  891.                 nrows = 1;
  892.                 ncols = 1;
  893.                 if (ptab->hdr.selectmode & TM_ROW) {
  894.                         col = 0;
  895.                         ncols = ptab->hdr.ncols;
  896.                 }
  897.         } else {
  898.                 row = ptab->select.startrow + rowincr;
  899.                 col = ptab->select.startcell + cellincr;
  900.                 while (col >= ptab->hdr.ncols) {
  901.                         col -= ptab->hdr.ncols;
  902.                         row++;
  903.                 }
  904.                 while (col < 0) {
  905.                         col += ptab->hdr.ncols;
  906.                         row--;
  907.                 }
  908.                 if (row < 0) {
  909.                         row = 0;
  910.                 }
  911.                 if (row >= ptab->hdr.nrows) {
  912.                         row = ptab->hdr.nrows-1;
  913.                 }
  914.                 /* check we haven't moved into non-selectable region */
  915.                 if ((row < ptab->hdr.fixedrows) &&
  916.                         (!ptab->hdr.fixedselectable)) {
  917.                                 row = ptab->hdr.fixedrows;
  918.                 }
  919.                 nrows = ptab->select.nrows;
  920.                 ncols = ptab->select.ncells;
  921.         }
  922.         gtab_select(hwnd, ptab, row, col, nrows, ncols, TRUE);
  923.         /* ensure selection visible */
  924.         gtab_showsel(hwnd, ptab, bToBottom);
  925. }
  926.  
  927. /***************************************************************************
  928.  * Function: gtab_selhome
  929.  *
  930.  * Purpose:
  931.  *
  932.  * Set the topmost selectable unit in window as the selection 
  933.  */
  934. void
  935. gtab_selhome(HWND hwnd, lpTable ptab)
  936. {
  937.         long row;
  938.  
  939.         if (ptab->hdr.fixedselectable) {
  940.                 row = gtab_linetorow(hwnd, ptab, 0);
  941.                 if (ptab->hdr.selectmode & TM_ROW) {
  942.                         gtab_select(hwnd, ptab, row, 0, 1,
  943.                                 ptab->hdr.ncols, TRUE);
  944.                 } else {
  945.                         gtab_select(hwnd, ptab, row, 0, 1, 1, TRUE);
  946.                 }
  947.         } else {
  948.                 row = gtab_linetorow(hwnd, ptab, ptab->hdr.fixedrows);
  949.                 if (ptab->hdr.selectmode & TM_ROW) {
  950.                         gtab_select(hwnd, ptab, row, 0, 1,
  951.                                 ptab->hdr.ncols, TRUE);
  952.                 } else {
  953.                         gtab_select(hwnd, ptab, row,
  954.                                 ptab->hdr.fixedcols, 1, 1, TRUE);
  955.                 }
  956.         }
  957. }
  958.  
  959.  
  960. /***************************************************************************
  961.  * Function: gtab_key
  962.  *
  963.  * Purpose:
  964.  *
  965.  * Handle key-down events - scroll windows and/or move selection 
  966.  */
  967. int
  968. gtab_key(HWND hwnd, lpTable ptab, int vkey)
  969. {
  970.         long row;
  971.         BOOL bControl = FALSE;
  972.  
  973.         if (GetKeyState(VK_CONTROL) & 0x8000) {
  974.                 bControl = TRUE;
  975.         }
  976.  
  977.         switch(vkey) {
  978.  
  979.         case VK_UP:
  980.                 if (bControl) {
  981.                         /* control-uparrow scrolls window without selection.
  982.                          * the selection is de-selected (to avoid surprises
  983.                          * moving back to it).
  984.                          */
  985.                         gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE);
  986.                         gtab_dovscroll(hwnd, ptab, -1);
  987.                 } else {
  988.                         /* uparrow moves selection up one line */
  989.                         gtab_changesel(hwnd, ptab, -1, 0, FALSE);
  990.                 }
  991.                 return(0);
  992.  
  993.         case VK_DOWN:
  994.                 if (bControl) {
  995.                         /* control downarrow scrolls window without
  996.                          * a selection.
  997.                          */
  998.                         gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE);
  999.                         gtab_dovscroll(hwnd, ptab, 1);
  1000.                 } else {
  1001.                         /* the normal gtab_changesel behaviour is
  1002.                          * that if the selected line is not visible now,
  1003.                          * we scroll it to the top of the window. This is fine
  1004.                          * in most cases but causes unacceptable jumps when
  1005.                          * repeatedly scrolling down with the down key.
  1006.                          *
  1007.                          * Thus we now have an argument to changesel to say
  1008.                          * that in this case, if you need to move the line onto
  1009.                          * the window, move it to the bottom and not the top
  1010.                          */
  1011.                         gtab_changesel(hwnd, ptab, 1, 0, TRUE);
  1012.                 }
  1013.                 return(0);
  1014.  
  1015.         case VK_LEFT:
  1016.                 /* if cell-selection mode, move left one cell.
  1017.                  * otherwise the whole row is selected - scroll
  1018.                  * the line left a little
  1019.                  */
  1020.  
  1021.                 if (ptab->hdr.selectmode & TM_ROW) {
  1022.                         if (bControl) {
  1023.                                 /* ctrl-left moves to start of line */
  1024.                                 gtab_dohscroll(hwnd, ptab, -(ptab->scroll_dx));
  1025.                         } else {
  1026.                                 gtab_dohscroll(hwnd, ptab, -(ptab->avewidth));
  1027.                         }
  1028.                 } else {
  1029.                         gtab_changesel(hwnd, ptab, 0, -1, FALSE);
  1030.                 }
  1031.                 return(0);
  1032.  
  1033.         case VK_RIGHT:
  1034.                 /* if cell-selection mode, move right one cell.
  1035.                  * otherwise the whole row is selected - scroll
  1036.                  * the line right a little
  1037.                  */
  1038.                 if (ptab->hdr.selectmode & TM_ROW) {
  1039.                         if (bControl) {
  1040.                                 /* control-right moves to right end of line */
  1041.                                 gtab_dohscroll(hwnd, ptab, ptab->rowwidth -
  1042.                                                 ptab->winwidth);
  1043.                         } else {
  1044.                                 gtab_dohscroll(hwnd, ptab, ptab->avewidth);
  1045.                         }
  1046.                 } else {
  1047.                         gtab_changesel(hwnd, ptab, 0, 1, TRUE);
  1048.                 }
  1049.                 return(0);
  1050.  
  1051.         case VK_HOME:
  1052.                 if (bControl) {
  1053.                         /* control-home == top of file */
  1054.                         gtab_dovscroll(hwnd, ptab, -(ptab->toprow));
  1055.                 }
  1056.                 /* top of window */
  1057.                 gtab_selhome(hwnd, ptab);
  1058.                 gtab_showsel(hwnd, ptab, FALSE);
  1059.                 
  1060.                 return(0);
  1061.  
  1062.         case VK_END:
  1063.                 if (bControl) {
  1064.                         /* control-end -> end of file */
  1065.                         row = ptab->hdr.nrows-1;
  1066.                 } else {
  1067.                         row = gtab_linetorow(hwnd, ptab, ptab->nlines - 1);
  1068.                         if (row >= ptab->hdr.nrows) {
  1069.                                 row = ptab->hdr.nrows-1;
  1070.                         }
  1071.                 }
  1072.                 if (ptab->hdr.selectmode & TM_ROW) {
  1073.                         gtab_select(hwnd, ptab, row, 0, 1,
  1074.                                 ptab->hdr.ncols, TRUE);
  1075.                 } else {
  1076.                         gtab_select(hwnd, ptab, row,
  1077.                                 ptab->hdr.ncols-1, 1, 1, TRUE);
  1078.                 }
  1079.                 /* we have selected the bottom line. We don't want to
  1080.                  * move it up into the window, since the intended
  1081.                  * effect is to select the lowest line. This doesn't
  1082.                  * apply to the ctrl-end behaviour (move to bottom of
  1083.                  * buffer.
  1084.                  */
  1085.                 if (bControl) {
  1086.                         /* move the selection to make it visible - but move it
  1087.                          * to the bottom and not to the top of the window
  1088.                          */
  1089.                         gtab_showsel(hwnd, ptab, TRUE);
  1090.                 }
  1091.                 return(0);
  1092.  
  1093.         case VK_RETURN:
  1094.                 if (ptab->select.nrows > 0) {
  1095.                         gtab_showsel(hwnd, ptab, FALSE);
  1096.                         gtab_enter(hwnd, ptab, ptab->select.startrow,
  1097.                                 ptab->select.startcell,
  1098.                                 ptab->select.nrows, ptab->select.ncells);
  1099.                 }
  1100.                 return(0);
  1101.  
  1102.         case VK_SPACE:
  1103.                 /* toggle the selection */
  1104.                 if (ptab->select.nrows < 1) {
  1105.                         /* no selection - make one */
  1106.                         gtab_changesel(hwnd, ptab, 0, 0, TRUE);
  1107.                 } else {
  1108.                         /* there is a selection - deselect it */
  1109.                         gtab_select(hwnd, ptab, 0, 0, 0, 0, TRUE);
  1110.                 }
  1111.                 return(0);
  1112.  
  1113.         case VK_PRIOR:          /* page up */
  1114.  
  1115.                 gtab_dovscroll(hwnd, ptab, -(ptab->nlines - 3));
  1116.                 gtab_selhome(hwnd, ptab);
  1117.                 return(0);
  1118.  
  1119.         case VK_NEXT:           /* page down */
  1120.  
  1121.                 /* scroll down one page */
  1122.                 gtab_dovscroll(hwnd, ptab, (ptab->nlines - 3));
  1123.  
  1124.                 /* select new bottom line */
  1125.                 row = gtab_linetorow(hwnd, ptab, ptab->nlines - 1);
  1126.                 if (row >= ptab->hdr.nrows) {
  1127.                         row = ptab->hdr.nrows-1;
  1128.                 }
  1129.                 /* select bottom line, but don't call showsel
  1130.                  * since we don't want to adjust it's position - we
  1131.                  * want it to remain at the bottom of the window
  1132.                  */
  1133.                 if (ptab->hdr.selectmode & TM_ROW) {
  1134.                         gtab_select(hwnd, ptab, row, 0, 1,
  1135.                                 ptab->hdr.ncols, TRUE);
  1136.                 } else {
  1137.                         gtab_select(hwnd, ptab, row,
  1138.                                 ptab->hdr.ncols-1, 1, 1, TRUE);
  1139.                 }
  1140.  
  1141.                 return(0);
  1142.  
  1143.         default:
  1144.                 return(1);
  1145.         }
  1146. }
  1147.  
  1148.