tscroll.c

来自「<Win2k系统编程>源码.次数为国人自编,内容丰富,还是不错的.」· C语言 代码 · 共 1,139 行 · 第 1/3 页

C
1,139
字号


/****************************** Module Header *******************************
* Module Name: TSCROLL.C
*
* Scrolling and selection routines.
*
* Functions:
*
* gtab_msg_vscroll()
* gtab_msg_hscroll()
* gtab_dovscroll()
* gtab_dohscroll()
* gtab_linetorow()
* gtab_rowtoline()
* gtab_select()
* gtab_ytoline()
* gtab_xtocol()
* gtab_isborder()
* gtab_enter()
* gtab_trackcol()
* gtab_press()
* gtab_release()
* gtab_move()
* gtab_dblclick()
* gtab_showsel()
* gtab_showsel_middle()
* gtab_changesel()
* gtab_selhome()
* gtab_key()
*
* Comments:
*
* This implementation currently only supports TM_SINGLE, not TM_MANY
* modes of selection.
*
****************************************************************************/

#include <windows.h>
#include <commdlg.h>

#include "gutils.h"
#include "table.h"
#include "tpriv.h"

/***************************************************************************
 * Function: gtab_msg_vscroll
 *
 * Purpose:
 *
 * Handle a vscroll message 
 */
void
gtab_msg_vscroll(HWND hwnd, lpTable ptab, int opcode, int pos)
{
        long change;

        switch(opcode) {
        case SB_THUMBPOSITION:
                change = (pos * ptab->scrollscale) - ptab->toprow;
                break;

        case SB_LINEUP:
                change = -1;
                break;

        case SB_LINEDOWN:
                change = 1;
                break;

        case SB_PAGEUP:
                change = - (ptab->nlines - 3);
                break;

        case SB_PAGEDOWN:
                change = (ptab->nlines - 3);
                break;

        default:
                return;
        }
        gtab_dovscroll(hwnd, ptab, change);
}

/***************************************************************************
 * Function: gtab_msg_hscroll
 *
 * Purpose:
 *
 * Handle a hscroll message 
 */
void
gtab_msg_hscroll(HWND hwnd, lpTable ptab, int opcode, int pos)
{
        int change;

        switch(opcode) {
        case SB_THUMBPOSITION:
                change = pos - ptab->scroll_dx;
                break;

        case SB_LINEUP:
                change = -(ptab->avewidth);
                break;

        case SB_LINEDOWN:
                change = ptab->avewidth;
                break;

        case SB_PAGEUP:
                change = - (ptab->winwidth * 2 / 3);
                break;

        case SB_PAGEDOWN:
                change = (ptab->winwidth * 2 / 3);
                break;

        default:
                return;
        }
        gtab_dohscroll(hwnd, ptab, change);
}



/***************************************************************************
 * Function: gtab_dovscroll
 *
 * Purpose:
 *
 * Set new vertical scroll pos,
 * adjust linedata array
 * set line win-relative start posns & clip top/bottom posns
 * revise display.
 */
void
gtab_dovscroll(HWND hwnd, lpTable ptab, long change)
{
        int cury, i;
        long ncopy;
        lpCellPos cp;
        LineData ldtemp;
        RECT rc, rcpaint;
        long range;
        long newtop;
        int newpos;


        range = ptab->hdr.nrows - (ptab->nlines - 1);
        newtop = ptab->toprow + change;
        if (range < 0) {
                range = 0;
        }
        if (newtop > range) {
                change = range - ptab->toprow;
        } else if (newtop < 0) {
                change = -(ptab->toprow);
        }
        ptab->toprow += change;

        newpos = (int) (newtop / ptab->scrollscale);
        SetScrollPos(hwnd, SB_VERT, newpos, TRUE);

        if (ptab->hdr.sendscroll) {
                gtab_sendtq(hwnd, TQ_SCROLL, ptab->toprow);
        }

        /* adjust data ptrs rather than invalidate, to retain the
         * data we know is still valid
         */
        if (abs(change) >= ptab->nlines) {
                gtab_invallines(hwnd, ptab, ptab->hdr.fixedrows,
                        ptab->nlines - ptab->hdr.fixedrows);
                InvalidateRect(hwnd, NULL, TRUE);
                change = 0;
        } else if (change < 0) {
                /* copy data down */
                ncopy = (ptab->nlines - ptab->hdr.fixedrows) - abs(change);
                for (i =  ptab->nlines - 1;
                  i >= (ptab->hdr.fixedrows + abs(change)); i--) {
                        ldtemp = ptab->pdata[i - abs(change)];
                        ptab->pdata[i - abs(change)] = ptab->pdata[i];
                        ptab->pdata[i] = ldtemp;
                }
                gtab_invallines(hwnd, ptab,
                        ptab->hdr.fixedrows, (int) abs(change));
        } else if (change > 0) {
                ncopy = (ptab->nlines - ptab->hdr.fixedrows) - change;
                for (i = ptab->hdr.fixedrows;
                  i < (ncopy + ptab->hdr.fixedrows); i++) {
                        ldtemp = ptab->pdata[i + change];
                        ptab->pdata[i + change] = ptab->pdata[i];
                        ptab->pdata[i] = ldtemp;
                }
                gtab_invallines(hwnd, ptab,
                        (int) ncopy + ptab->hdr.fixedrows, (int) change);
        }

        /* scroll window */
        GetClientRect(hwnd, &rc);
        rcpaint = rc;
        if (change > 0) {
                rc.top += (int) (change + ptab->hdr.fixedrows) * ptab->rowheight;
                rcpaint.top = (ptab->hdr.fixedrows * ptab->rowheight);
                rcpaint.top += rc.bottom - rc.top;
        } else if (change < 0) {
                rc.top += (ptab->hdr.fixedrows * ptab->rowheight);
                rc.bottom -= (int) (change * ptab->rowheight);
                rcpaint.bottom -= rc.bottom - rc.top;
        }

        /* loop through each line setting relative posn and clipping */

        /* set up all rows  - the fixed/moveable difference for
         * rows is made at fetch-time during painting, when we remember
         * which absolute row nr to ask for, for a given screen line
         */
        cury = 0;
        for (i = 0; i < ptab->nlines; i++) {
                cp = &ptab->pdata[i].linepos;
                cp->start = cury;
                cp->clipstart = cury;
                cp->clipend = cury + cp->size;
                cury += cp->size;
        }

        /* now move and repaint the window */
        if (change != 0) {
                if (rc.top < rc.bottom) {
                        ScrollWindow(hwnd, 0, (int) -(change * ptab->rowheight),
                                &rc, NULL);

                }

                /* force repaint now, not just post message for later,
                 * since we want to repaint that line before the next
                 * scroll down occurs
                 */
                RedrawWindow(hwnd, &rcpaint, NULL,
                        RDW_ERASE | RDW_INVALIDATE|RDW_UPDATENOW);
        }
}

/***************************************************************************
 * Function: gtab_dohscroll
 *
 * Purpose:
 *
 * Set new horizontal scroll pos,
 * set col win-relative start posns & clip left/right posns
 * revise display.
 */
void
gtab_dohscroll(HWND hwnd, lpTable ptab, long change)
{
        int curx, i;
        int moveable;
        lpCellPos cp;
        int newdx, range;


        /* check that the new scroll pos is still within the valid range */
        range = ptab->rowwidth - ptab->winwidth;
        newdx = ptab->scroll_dx + (int) change;
        if (range < 0) {
                range = 0;
        }
        if (newdx > range) {
                change = range - ptab->scroll_dx;
        } else if (newdx < 0) {
                change = -(ptab->scroll_dx);
        }
        ptab->scroll_dx += (int) change;

        SetScrollPos(hwnd, SB_HORZ, ptab->scroll_dx, TRUE);
        InvalidateRect(hwnd, NULL, TRUE);
        
        /* loop through each col setting relative posn and clipping */
        /* clip off 1 pixel left and right (we added 2 on to size for this) */

        /* first set up fixed columns */
        curx = 0;
        for (i = 0; i < ptab->hdr.fixedcols; i++) {
                cp = &ptab->pcellpos[i];
                cp->start = curx + 1;
                cp->clipstart = cp->start;
                cp->clipend = cp->start + cp->size - 2;
                curx += cp->size;
        }

        /* now moveable columns. remember start of moveable cols */
        moveable = curx;
        curx = - ptab->scroll_dx;       /* rel. pos of col */
        for (i = ptab->hdr.fixedcols; i < ptab->hdr.ncols; i++) {
                cp = &ptab->pcellpos[i];
                cp->start = curx + moveable + 1;
                cp->clipstart = max(moveable+1, cp->start);
                cp->clipend = cp->start + cp->size - 2;
                curx += cp->size;
        }
}

/***************************************************************************
 * Function: gtab_linetorow
 *
 * Purpose:
 *
 * Convert screen line nr to table row nr
 */
long
gtab_linetorow(HWND hwnd, lpTable ptab, int line)
{
        if (line < ptab->hdr.fixedrows) {
                return(line);
        }

        return (line + ptab->toprow);
}

/***************************************************************************
 * Function: gtab_rowtoline
 *
 * Purpose:
 *
 * Convert table row nr to screen line nr or -1 if not on screen
 */
int
gtab_rowtoline(HWND hwnd, lpTable ptab, long row)
{
        if (row < ptab->hdr.fixedrows) {
                return( (int) row);
        }

        row -= ptab->toprow;
        if ((row >= ptab->hdr.fixedrows) && (row < ptab->nlines)) {
                return ( (int) row);
        }
        return(-1);
}

/***************************************************************************
 * Function: gtab_select
 *
 * Purpose:
 *
 * Replace old selection with new. Notify owner if bNotify. Change
 * display to reflect new display.
 */
void
gtab_select(
        HWND hwnd,
        lpTable ptab,
        long row,
        long col,
        long nrows,
        long ncells,
        BOOL bNotify)
{
        int line;

        /* if in ROW mode, force col and ncells to reflect the entire row. */
        if (ptab->hdr.selectmode & TM_ROW) {
                col = 0;
                ncells = ptab->hdr.ncols;
        }

        /* clear existing sel if valid and visible */
        if ((ptab->select.nrows > 0) && (ptab->selvisible == TRUE)) {

                /* only clear sel if it is different from the new one */
                if ((ptab->select.startrow != row) ||
                    (ptab->select.startcell != col) ||
                    (ptab->select.nrows != nrows) ||
                    (ptab->select.ncells != ncells)) {
                        line = gtab_rowtoline(hwnd, ptab,
                                ptab->select.startrow);
                        if (line >= 0) {
                                gtab_invertsel(hwnd, ptab, NULL);
                        }
                        ptab->selvisible = FALSE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?