|
|
1.1 root 1:
2: /******************************************************************************\
3: * This is a part of the Microsoft Source Code Samples.
4: * Copyright (C) 1993 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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.