home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / flist.zip / flwin.c < prev    next >
C/C++ Source or Header  |  1996-09-11  |  26KB  |  796 lines

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3.  Fast Win (For OS/2)
  4.  
  5.  Original release:
  6.           Russ Weathersby
  7.           August 1996
  8. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  9. */
  10. /*------------------------------Includes-----------------------------------*/
  11. #define INCL_WIN
  12. #define INCL_GPI
  13. #define INCL_DOS
  14. #include <os2.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <process.h>
  19. #include <limits.h>
  20. #include "list.h"
  21. #include "flwin.h"
  22.  
  23. /*-------------------------------Defines-----------------------------------*/
  24.  
  25. /*-------------------------Structs and Typedefs----------------------------*/
  26. typedef struct {
  27.   HWND   wnd;
  28.   ULONG  msg;
  29.   MPARAM mp1;
  30.   MPARAM mp2;
  31. } MSGPARMS;
  32.  
  33. /*--------------------------Function Declarations--------------------------*/
  34. static MRESULT EXPENTRY WndProc( HWND, ULONG, MPARAM, MPARAM );
  35.  
  36. static MRESULT ActMsgCreate( MSGPARMS *, WNDATTR * );
  37. static MRESULT ActMsgDestroy( MSGPARMS *, WNDATTR * );
  38. static MRESULT ActMsgChar( MSGPARMS *, WNDATTR * );
  39. static MRESULT ActMsgPaint( MSGPARMS *, WNDATTR * );
  40. static MRESULT ActMsgSize( MSGPARMS *, WNDATTR * );
  41. static MRESULT ActMsgButton1Click( MSGPARMS *, WNDATTR * );
  42. static MRESULT ActMsgButton1DblClk( MSGPARMS *, WNDATTR * );
  43. static MRESULT ActMsgBeginSelect( MSGPARMS *, WNDATTR * );
  44. static MRESULT ActMsgMouseMove( MSGPARMS *, WNDATTR * );
  45. static MRESULT ActMsgBeginDrag( MSGPARMS *, WNDATTR * );
  46. static MRESULT ActMsgChord( MSGPARMS *, WNDATTR * );
  47. static MRESULT ActMsgPresParamChanged( MSGPARMS *, WNDATTR * );
  48. static MRESULT ActMsgVScroll( MSGPARMS *, WNDATTR * );
  49. static MRESULT ActMsgUser1( MSGPARMS *, WNDATTR * );
  50. static MRESULT ActMsgUser2( MSGPARMS *, WNDATTR * );
  51. static MRESULT ActMsgUser3( MSGPARMS *, WNDATTR * );
  52. static MRESULT ActMsgUser4( MSGPARMS *, WNDATTR * );
  53.  
  54. static void  InvalidateLines( WNDATTR *, int, int );
  55.  
  56. /*-------------------------------Globals-----------------------------------*/
  57.  
  58. /*-----------------------------Start of Code-------------------------------*/
  59.  
  60. /*---------------------------------------------------------------------------
  61.                                FLCreateWindow
  62. ---------------------------------------------------------------------------*/
  63. HWND EXTFUNC FLCreateWindow( CREATEOPS *userops )
  64. {
  65.  HWND  hwndClient,
  66.        hwndFrame;
  67.  
  68.   if (userops == NULL)
  69.      return NULLHANDLE;
  70.  
  71.   WinRegisterClass( userops->hab,
  72.                     "FASTLIST",
  73.                     WndProc,
  74.                     CS_SIZEREDRAW,
  75.                     sizeof( WNDATTR * ) );
  76.  
  77.   hwndFrame = WinCreateStdWindow( HWND_DESKTOP,
  78.                                   0,
  79.                                   &( userops->flags ),
  80.                                   "FASTLIST",
  81.                                   "FastList",
  82.                                   0L,
  83.                                   NULLHANDLE,
  84.                                   ID_FLWIN_RES,
  85.                                   &hwndClient );
  86.  
  87.   WinPostMsg( hwndClient, FLM_SETWINDOW, MPFROMP( userops ), 0 );
  88.  
  89.   return hwndFrame;
  90. }
  91.  
  92. /*---------------------------------------------------------------------------
  93.                                   WndProc
  94. ---------------------------------------------------------------------------*/
  95. MRESULT EXPENTRY WndProc( HWND wnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  96. {
  97.   MSGPARMS  MsgParms;
  98.   WNDATTR  *WndAttr;
  99.   MRESULT   MRes;
  100.  
  101.    MsgParms.wnd = wnd;
  102.    MsgParms.msg = msg;
  103.    MsgParms.mp1 = mp1;
  104.    MsgParms.mp2 = mp2;
  105.    WndAttr = WinQueryWindowPtr( wnd, QWL_USER );
  106.  
  107.    switch (msg) {
  108.      case WM_ERASEBACKGROUND:
  109.            MRes = MRFROMSHORT( TRUE );
  110.            break;
  111.      case WM_CREATE:
  112.            MRes = ActMsgCreate( &MsgParms, WndAttr );
  113.            break;
  114.      case WM_DESTROY :
  115.            MRes = ActMsgDestroy( &MsgParms, WndAttr );
  116.            break;
  117.      case WM_CHAR:
  118.            MRes = ActMsgChar( &MsgParms, WndAttr );
  119.            break;
  120.      case WM_BUTTON1CLICK:
  121.            MRes = ActMsgButton1Click( &MsgParms, WndAttr );
  122.            break;
  123.      case WM_BUTTON1DBLCLK:
  124.            MRes = ActMsgButton1DblClk( &MsgParms, WndAttr );
  125.            break;
  126.      case WM_BEGINSELECT:
  127.            MRes = ActMsgBeginSelect( &MsgParms, WndAttr );
  128.            break;
  129.      case WM_ENDSELECT:
  130.            WndAttr->select = NO_SELECT;
  131.            MRes = MRFROMSHORT( FALSE );
  132.            break;
  133.      case WM_BEGINDRAG:
  134.            MRes = ActMsgBeginDrag( &MsgParms, WndAttr );
  135.            break;
  136.      case WM_CHORD:
  137.            MRes = ActMsgChord( &MsgParms, WndAttr );
  138.            break;
  139.      case WM_MOUSEMOVE :
  140.            MRes = WinDefWindowProc( wnd, msg, mp1, mp2 );
  141.            if (WndAttr->select != NO_SELECT)
  142.               MRes = ActMsgMouseMove( &MsgParms, WndAttr );
  143.            break;
  144.      case WM_SIZE :
  145.            MRes = ActMsgSize( &MsgParms, WndAttr );
  146.            break;
  147.      case WM_VSCROLL:
  148.            MRes = ActMsgVScroll( &MsgParms, WndAttr );
  149.            break;
  150.      case WM_PRESPARAMCHANGED:
  151.            MRes = ActMsgPresParamChanged( &MsgParms, WndAttr );
  152.            break;
  153.      case WM_PAINT:
  154.            MRes = ActMsgPaint( &MsgParms, WndAttr );
  155.            break;
  156.      case FLM_SETWINDOW:
  157.            MRes = ActMsgUser1( &MsgParms, WndAttr );
  158.            break;
  159.      case FLM_CORRECTWINDOW:
  160.            MRes = ActMsgUser2( &MsgParms, WndAttr );
  161.            break;
  162.      case FLM_CLEAR:
  163.            MRes = ActMsgUser3( &MsgParms, WndAttr );
  164.            break;
  165.      case FLM_CLEARMARKED:
  166.            MRes = ActMsgUser4( &MsgParms, WndAttr );
  167.            break;
  168.      default:
  169.            MRes = WinDefWindowProc( wnd, msg, mp1, mp2 );
  170.            break;
  171.    }
  172.  
  173.   return MRes;
  174. }
  175.  
  176. /*-------------------------------------------------------------------------
  177.                                 ActMsgCreate
  178. --------------------------------------------------------------------------*/
  179. MRESULT ActMsgCreate( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  180. {
  181.  WNDATTR  *attr;
  182.  
  183.    attr = ( WNDATTR * ) malloc( sizeof( WNDATTR ) );
  184.  
  185.    if (attr) {
  186.       attr->list = LPListCreate();
  187.       if (attr->list) {
  188.          attr->current = attr->list;
  189.          attr->Frame = WinQueryWindow( MsgParms->wnd, QW_PARENT );
  190.          attr->Client = MsgParms->wnd;
  191.          attr->Scroll = WinWindowFromID( attr->Frame, FID_VERTSCROLL );
  192.          attr->prevscrollpos = attr->scrollpos = 0;
  193.          attr->xpos = 0;
  194.          attr->select = NO_SELECT;
  195.          attr->escape = FALSE;
  196.  
  197.          WinSetWindowPtr( MsgParms->wnd, QWL_USER, attr );
  198.  
  199.          return MRFROMSHORT( FALSE );
  200.       } else {
  201.          free( attr );
  202.       }
  203.    }
  204.  
  205.    return MRFROMSHORT( TRUE );
  206. }
  207. /*-------------------------------------------------------------------------
  208.                                ActMsgDestroy
  209. --------------------------------------------------------------------------*/
  210. MRESULT ActMsgDestroy( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  211. {
  212.    if (WndAttr != ( WNDATTR * )NULL) {
  213.       LPListDestroy( WndAttr->list );
  214.       free( WndAttr );
  215.    }
  216.  
  217.    return MRFROMSHORT( FALSE );
  218. }
  219. /*-------------------------------------------------------------------------
  220.                                 ActMsgChar
  221. --------------------------------------------------------------------------*/
  222. MRESULT ActMsgChar( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  223. {
  224.  RECTL   rect;
  225.  UCHAR   vkey;
  226.  USHORT  flags;
  227.  int     newx, dir, max;
  228.  
  229.    vkey = SHORT2FROMMP( MsgParms->mp2 );
  230.    flags = SHORT1FROMMP( MsgParms->mp1 );
  231.    if (flags & KC_KEYUP)
  232.       return MRFROMSHORT( FALSE );
  233.  
  234.    switch (vkey) {
  235.      case VK_PAGEUP: case VK_PAGEDOWN: case VK_UP: case VK_DOWN:
  236.          WinPostMsg( WndAttr->Scroll, WM_CHAR,
  237.                      MsgParms->mp1, MsgParms->mp2 );
  238.          break;
  239.      case VK_HOME:
  240.          if (WndAttr->scrollpos) {
  241.             WndAttr->scrollpos = 1;
  242.             WinInvalidateRect( MsgParms->wnd, NULL, TRUE );
  243.          }
  244.          break;
  245.      case VK_END:
  246.          max = LPListLines( WndAttr->list ) - WndAttr->winlines + 1;
  247.          WndAttr->scrollpos = max( max, 0 );
  248.          WinInvalidateRect( MsgParms->wnd, NULL, TRUE );
  249.          break;
  250.      case VK_LEFT: case VK_RIGHT:
  251.          newx = WndAttr->xpos;
  252.          dir = (vkey == VK_LEFT) ? 1 : -1;
  253.          WinQueryWindowRect( MsgParms->wnd, &rect );
  254.  
  255.          if (flags & KC_CTRL)
  256.             newx += ( rect.xRight - rect.xLeft ) * dir;
  257.          else
  258.             newx += WndAttr->fontwidth * dir;
  259.  
  260.          newx = min( newx, 0 );
  261.          max = LPListMaxLen( WndAttr->list ) * WndAttr->fontwidth;
  262.          newx = max( newx, -max );
  263.  
  264.          WinScrollWindow( MsgParms->wnd,
  265.                           newx - WndAttr->xpos,
  266.                           0, NULL, NULL, NULLHANDLE, NULL,
  267.                           SW_INVALIDATERGN );
  268.  
  269.          WndAttr->xpos = newx;
  270.          break;
  271.      case VK_ESC:
  272.          WinPostMsg( MsgParms->wnd, WM_QUIT, 0, 0 );
  273.          WndAttr->escape = TRUE;
  274.          break;
  275.      case VK_DELETE:
  276.          if (LPListMarkedLines( WndAttr->list ))
  277.             WinPostMsg( MsgParms->wnd, FLM_CLEARMARKED, 0, 0 );
  278.          break;
  279.      default:
  280.          break;
  281.    }
  282.  
  283.    return MRFROMSHORT( FALSE );
  284. }
  285. /*-------------------------------------------------------------------------
  286.                              ActMsgButton1Click
  287. --------------------------------------------------------------------------*/
  288. MRESULT ActMsgButton1Click( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  289. {
  290.  LPELEM *elem;
  291.  USHORT  y, offset;
  292.  
  293.    y = SHORT2FROMMP( MsgParms->mp1 );
  294.    y /= WndAttr->fontmax;
  295.    offset = WndAttr->winlines - y - 1;
  296.  
  297.    elem = LPElemTrack( WndAttr->list, WndAttr->current, offset );
  298.  
  299.    if (elem != WndAttr->list) {
  300.       if (elem->nextmk)
  301.          LPElemUnmark( WndAttr->list, elem );
  302.       else
  303.          LPElemMark( WndAttr->list, elem );
  304.  
  305.       InvalidateLines( WndAttr, y, y );
  306.    }
  307.  
  308.    return MRFROMSHORT( FALSE );
  309. }
  310. /*-------------------------------------------------------------------------
  311.                            ActMsgButton1DblClk
  312. --------------------------------------------------------------------------*/
  313. MRESULT ActMsgButton1DblClk( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  314. {
  315.  LPELEM *elem;
  316.  USHORT  y, mark;
  317.  
  318.    y = SHORT2FROMMP( MsgParms->mp1 );
  319.    y /= WndAttr->fontmax;
  320.    InvalidateLines( WndAttr, y, 0 );
  321.  
  322.    y = WndAttr->winlines - y - 1;
  323.    elem = LPElemTrack( WndAttr->list, WndAttr->current, y );
  324.  
  325.    mark = (elem->nextmk != NULL);
  326.    elem = elem->next;
  327.  
  328.    while (elem != WndAttr->list) {
  329.       if (mark ^ (elem->nextmk == NULL))
  330.          break;
  331.       if (mark)
  332.          LPElemMark( WndAttr->list, elem );
  333.       else
  334.          LPElemUnmark( WndAttr->list, elem );
  335.       elem = elem->next;
  336.    }
  337.  
  338.    return MRFROMSHORT( FALSE );
  339. }
  340. /*-------------------------------------------------------------------------
  341.                              ActMsgBeginSelect
  342. --------------------------------------------------------------------------*/
  343. MRESULT ActMsgBeginSelect( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  344. {
  345.  USHORT y;
  346.  
  347.    y = SHORT2FROMMP( MsgParms->mp1 );
  348.    WndAttr->select = y / WndAttr->fontmax;
  349.  
  350.    return ActMsgButton1Click( MsgParms, WndAttr );
  351. }
  352. /*-------------------------------------------------------------------------
  353.                              ActMsgMouseMove
  354. --------------------------------------------------------------------------*/
  355. MRESULT ActMsgMouseMove( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  356. {
  357.  USHORT  y, select;
  358.  
  359.    y = SHORT2FROMMP( MsgParms->mp1 );
  360.    select = y / WndAttr->fontmax;
  361.  
  362.    if (!(WinGetKeyState( HWND_DESKTOP, VK_BUTTON1 ) & 0x8000))
  363.       select = WndAttr->select = NO_SELECT;
  364.  
  365.    if (select == WndAttr->select)
  366.       return MRFROMSHORT( FALSE );
  367.  
  368.    WndAttr->select = select;
  369.  
  370.    return ActMsgButton1Click( MsgParms, WndAttr );
  371. }
  372.  
  373. /*-------------------------------------------------------------------------
  374.                                 ActMsgChord
  375. --------------------------------------------------------------------------*/
  376. MRESULT ActMsgChord( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  377. {
  378.  SWP  swp;
  379.  LONG keystate;
  380.  
  381.    WinQueryWindowPos( WndAttr->Frame, &swp );
  382.  
  383.    keystate = WinGetKeyState( HWND_DESKTOP, VK_ALT );
  384.    keystate |= WinGetKeyState( HWND_DESKTOP, VK_CTRL );
  385.  
  386.    if (keystate & 0x8000) {
  387.       swp.fl = SWP_HIDE;
  388.    } else {
  389.       if (swp.fl & SWP_MAXIMIZE)
  390.          swp.fl = SWP_RESTORE;
  391.       else
  392.          swp.fl = SWP_MAXIMIZE;
  393.    }
  394.  
  395.    WinSetWindowPos( WndAttr->Frame, NULLHANDLE, 0, 0, 0, 0, swp.fl );
  396.  
  397.    return MRFROMSHORT( FALSE );
  398. }
  399. /*-------------------------------------------------------------------------
  400.                             ActMsgBeginDrag
  401. --------------------------------------------------------------------------*/
  402. MRESULT ActMsgBeginDrag( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  403. {
  404.  TRACKINFO trinf;
  405.  SWP       swp;
  406.  RECTL     rect;
  407.  LONG      value;
  408.  
  409.    WinQueryWindowPos( WndAttr->Frame, &swp );
  410.    trinf.rclTrack.xLeft = swp.x;
  411.    trinf.rclTrack.xRight = swp.x + swp.cx;
  412.    trinf.rclTrack.yBottom = swp.y;
  413.    trinf.rclTrack.yTop = swp.y + swp.cy;
  414.    trinf.ptlMaxTrackSize.x = trinf.ptlMinTrackSize.x = swp.cx;
  415.    trinf.ptlMaxTrackSize.y = trinf.ptlMinTrackSize.y = swp.cy;
  416.  
  417.    value = WinQuerySysValue( HWND_DESKTOP, SV_CXSIZEBORDER );
  418.    trinf.cxBorder = trinf.cyBorder = value;
  419.    trinf.cxGrid = trinf.cyGrid = 0;
  420.    trinf.cxKeyboard = trinf.cyKeyboard = 8;
  421.  
  422.    WinQueryWindowRect( HWND_DESKTOP, &rect );
  423.    memcpy( &trinf.rclBoundary, &rect, sizeof( RECTL ) );
  424.  
  425.    trinf.fs = TF_MOVE;
  426.  
  427.    WinTrackRect( HWND_DESKTOP, NULLHANDLE, &trinf );
  428.  
  429.    WinSetWindowPos( WndAttr->Frame, NULLHANDLE,
  430.                     trinf.rclTrack.xLeft,
  431.                     trinf.rclTrack.yBottom,
  432.                     0, 0,
  433.                     SWP_MOVE );
  434.  
  435.    return MRFROMSHORT( FALSE );
  436. }
  437. /*-------------------------------------------------------------------------
  438.                                  ActMsgSize
  439. --------------------------------------------------------------------------*/
  440. MRESULT ActMsgSize( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  441. {
  442.  void   CorrectWinSize( HWND, WNDATTR * );
  443.  RECTL  rect;
  444.  USHORT bottomline, listlines;
  445.  int    maxscrollpos;
  446.  
  447.    CorrectWinSize( MsgParms->wnd, WndAttr );
  448.  
  449.    WinQueryWindowRect( MsgParms->wnd, &rect );
  450.    WndAttr->winlines = rect.yTop / WndAttr->fontmax;
  451.  
  452.    listlines = LPListLines( WndAttr->list );
  453.  
  454.    bottomline = WndAttr->scrollpos + WndAttr->winlines - 1;
  455.    maxscrollpos = listlines - WndAttr->winlines + 1;
  456.  
  457.    if (bottomline > listlines && maxscrollpos > 1)
  458.       WndAttr->scrollpos = maxscrollpos;
  459.    if (listlines < WndAttr->winlines && listlines)
  460.       WndAttr->scrollpos = 1;
  461.  
  462.    return MRFROMSHORT( FALSE );
  463. }
  464. /*-------------------------------------------------------------------------
  465.                                CorrectWinSize
  466. --------------------------------------------------------------------------*/
  467. void CorrectWinSize( HWND wnd, WNDATTR *WndAttr )
  468. {
  469.  HPS         hps;
  470.  SWP         swp;
  471.  FONTMETRICS fm;
  472.  int         grain;
  473.  
  474.    hps = WinGetPS( wnd );
  475.    GpiQueryFontMetrics( hps, sizeof( FONTMETRICS ), &fm );
  476.    WndAttr->fontmax = fm.lMaxBaselineExt;
  477.    WndAttr->fontbase = fm.lMaxAscender;
  478.    WndAttr->fontwidth = fm.lAveCharWidth;
  479.  
  480.    WinQueryWindowPos( wnd, &swp );
  481.    grain = swp.cy % WndAttr->fontmax;
  482.    if (grain) {
  483.       WinQueryWindowPos( WndAttr->Frame, &swp );
  484.       swp.y += grain;
  485.       swp.cy -= grain;
  486.       swp.fl |= SWP_MOVE;
  487.       WinSetWindowPos( WndAttr->Frame,
  488.                        swp.hwndInsertBehind,
  489.                        swp.x, swp.y,
  490.                        swp.cx, swp.cy,
  491.                        swp.fl );
  492.    }
  493.    return;
  494. }
  495.  
  496. /*-------------------------------------------------------------------------
  497.                               ActMsgVScroll
  498. --------------------------------------------------------------------------*/
  499. MRESULT ActMsgVScroll( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  500. {
  501.  MRESULT mres;
  502.  int     newpos, minpos, maxpos, delta;
  503.  
  504.    newpos = WndAttr->scrollpos;
  505.  
  506.    switch (SHORT2FROMMP( MsgParms->mp2 )) {
  507.        case  SB_LINEUP :
  508.            newpos -= 1;
  509.            break;
  510.        case  SB_LINEDOWN :
  511.            newpos += 1;
  512.            break;
  513.        case  SB_SLIDERTRACK:
  514.            newpos = SHORT1FROMMP( MsgParms->mp2 );
  515.            break;
  516.        case  SB_PAGEUP :
  517.            newpos -= WndAttr->winlines;
  518.            break;
  519.        case  SB_PAGEDOWN :
  520.            newpos += WndAttr->winlines;
  521.            break;
  522.        default :
  523.            break;
  524.    }
  525.  
  526.    mres = WinSendMsg( WndAttr->Scroll, SBM_QUERYRANGE, 0, 0 );
  527.    minpos = SHORT1FROMMR( mres );
  528.    maxpos = SHORT2FROMMR( mres );
  529.    newpos = max( newpos, minpos );
  530.    newpos = min( newpos, maxpos );
  531.    delta  = newpos - WndAttr->scrollpos;
  532.  
  533.    if (delta) {
  534.       WndAttr->scrollpos = newpos;
  535.       WinScrollWindow( MsgParms->wnd, 0,
  536.                        delta * WndAttr->fontmax,
  537.                        NULL, NULL, NULLHANDLE, NULL,
  538.                        SW_INVALIDATERGN );
  539.    }
  540.  
  541.    return MRFROMSHORT( FALSE );
  542. }
  543.  
  544. /*-------------------------------------------------------------------------
  545.                           ActMsgPresParamChanged
  546. --------------------------------------------------------------------------*/
  547. MRESULT ActMsgPresParamChanged( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  548. {
  549.  SWP   swp;
  550.  
  551.    if (LONGFROMMP( MsgParms->mp1 ) == PP_FONTNAMESIZE) {
  552.       WinQueryWindowPos( MsgParms->wnd, &swp );
  553.       WinPostMsg( MsgParms->wnd, WM_SIZE,
  554.                   MPFROM2SHORT( swp.cx, swp.cx ),
  555.                   MPFROM2SHORT( swp.cy, swp.cy ) );
  556.    }
  557.    WinInvalidateRect( MsgParms->wnd, NULL, TRUE );
  558.  
  559.    WinQueryPresParam( MsgParms->wnd,
  560.                       PP_FONTNAMESIZE,
  561.                       0,
  562.                       NULL,
  563.                       sizeof WndAttr->font,
  564.                       WndAttr->font,
  565.                       0 );
  566.  
  567.    return MRFROMSHORT( FALSE );
  568. }
  569. /*-------------------------------------------------------------------------
  570.                               ActMsgUser1
  571.  
  572. Purpose: Called after WM_CREATE to initialize various window
  573.          parameters.
  574. --------------------------------------------------------------------------*/
  575. MRESULT ActMsgUser1( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  576. {
  577.  CREATEOPS *create;
  578.  ULONG      flags;
  579.  
  580.    create = PVOIDFROMMP( MsgParms->mp1 );
  581.  
  582.    WndAttr->hab = create->hab;
  583.  
  584.    LPListMaxLines( WndAttr->list ) = create->maxlines;
  585.    LPListMaxLen( WndAttr->list ) = create->maxlen;
  586.  
  587.    flags = SWP_SHOW | SWP_SIZE;
  588.  
  589.    if (!( create->flags & FCF_SHELLPOSITION ))
  590.       flags |= SWP_MOVE;
  591.    if (create->maximize)
  592.       flags |= SWP_MAXIMIZE;
  593.  
  594.    WinSetPresParam( MsgParms->wnd,
  595.                     PP_FONTNAMESIZE,
  596.                     sizeof create->font,
  597.                     create->font );
  598.  
  599.    WinSetWindowPos( WndAttr->Frame, NULLHANDLE,
  600.                     create->xpos, create->ypos,
  601.                     create->winwidth, create->winheight,
  602.                     flags );
  603.  
  604.    return MRFROMSHORT( FALSE );
  605. }
  606.  
  607. /*-------------------------------------------------------------------------
  608.                               ActMsgUser2
  609.  
  610. Purpose: Scroll window and reset scrollbar (if necessary)
  611. Context: Called after lines appended.
  612. --------------------------------------------------------------------------*/
  613. MRESULT ActMsgUser2( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  614. {
  615.  USHORT oldpos, newpos, delta, listlines, maxlines, lines_added;
  616.  
  617.    listlines = LPListLines( WndAttr->list );
  618.    maxlines = LPListMaxLines( WndAttr->list );
  619.    lines_added = SHORT1FROMMP( MsgParms->mp1 );
  620.  
  621.    if (listlines > WndAttr->winlines && WndAttr->scrollpos != 0) {
  622.       oldpos = WndAttr->scrollpos;
  623.       newpos = listlines - WndAttr->winlines + 1;
  624.       WndAttr->scrollpos = WndAttr->prevscrollpos = newpos;
  625.       WndAttr->current = LPElemTrack( WndAttr->list, WndAttr->list, newpos );
  626.  
  627.       delta = newpos - oldpos;
  628.       if (delta == 0 && listlines == maxlines)
  629.          delta = lines_added;
  630.  
  631.       WinScrollWindow( MsgParms->wnd, 0,
  632.                        delta * WndAttr->fontmax,
  633.                        NULL, NULL, NULLHANDLE, NULL,
  634.                        SW_INVALIDATERGN );
  635.  
  636.       if ((listlines - lines_added) < WndAttr->winlines)
  637.          InvalidateLines( WndAttr, lines_added, 0 );
  638.  
  639.    } else if (WndAttr->scrollpos != 0) {
  640.       InvalidateLines( WndAttr,
  641.                        WndAttr->winlines - listlines + lines_added,
  642.                        WndAttr->winlines - listlines);
  643.    } else {
  644.       WndAttr->scrollpos = WndAttr->prevscrollpos = 1;
  645.       WndAttr->current = WndAttr->list->next;
  646.       WinInvalidateRect( WndAttr->Client, NULL, TRUE );
  647.    }
  648.  
  649.    return MRFROMSHORT( FALSE );
  650. }
  651. /*-------------------------------------------------------------------------
  652.                               ActMsgUser3
  653. Clear window
  654. --------------------------------------------------------------------------*/
  655. MRESULT ActMsgUser3( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  656. {
  657.    LPListClear( WndAttr->list );
  658.    WndAttr->current = WndAttr->list;
  659.    WndAttr->scrollpos = WndAttr->prevscrollpos = 0;
  660.    WndAttr->xpos = 0;
  661.    WinInvalidateRect( WndAttr->Client, NULL, TRUE );
  662.  
  663.   return MRFROMSHORT( FALSE );
  664. }
  665. /*-------------------------------------------------------------------------
  666.                               ActMsgUser4
  667. Clear Marked Lines and correct window
  668. --------------------------------------------------------------------------*/
  669. MRESULT ActMsgUser4( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  670. {
  671.  int lines, newscrollpos, maxpos;
  672.  LPELEM *elem;
  673.  
  674.    newscrollpos = 0;
  675.    elem = WndAttr->list;
  676.    do {
  677.       elem = elem->next;
  678.       if (elem->nextmk == NULL)
  679.          newscrollpos++;
  680.    } while (elem != WndAttr->current);
  681.  
  682.    LPListClearMarked( WndAttr->list );
  683.  
  684.    lines = LPListLines( WndAttr->list );
  685.  
  686.    maxpos = lines - WndAttr->winlines + 1;
  687.    newscrollpos = min( newscrollpos, maxpos );
  688.  
  689.    if (newscrollpos > 0) {
  690.       WndAttr->scrollpos = newscrollpos;
  691.       WndAttr->prevscrollpos = 1;
  692.       WndAttr->current = WndAttr->list->next;
  693.    } else if (lines) {
  694.       WndAttr->current = WndAttr->list->next;
  695.       WndAttr->scrollpos = WndAttr->prevscrollpos = 1;
  696.    } else {
  697.       WndAttr->current = WndAttr->list;
  698.       WndAttr->scrollpos = WndAttr->prevscrollpos = 0;
  699.    }
  700.  
  701.    WinInvalidateRect( MsgParms->wnd, NULL, TRUE );
  702.  
  703.   return MRFROMSHORT( FALSE );
  704. }
  705. /*-------------------------------------------------------------------------
  706.                               ActMsgPaint
  707. --------------------------------------------------------------------------*/
  708. MRESULT ActMsgPaint( MSGPARMS *MsgParms, WNDATTR *WndAttr )
  709. {
  710.  LPELEM  *elem;
  711.  HPS      hps;
  712.  RECTL    rect;
  713.  POINTL   pos;
  714.  USHORT   range, listlines, invalidoffset;
  715.  UINT     fontsize;
  716.  long     winsize;
  717.  int      shift;
  718.  
  719.    hps = WinBeginPaint( MsgParms->wnd,
  720.                         NULLHANDLE,
  721.                         &rect );
  722.    GpiErase( hps );
  723.  
  724.    shift = WndAttr->scrollpos - WndAttr->prevscrollpos;
  725.  
  726.    WndAttr->current = LPElemRotate( WndAttr->list,
  727.                                     WndAttr->current,
  728.                                     shift );
  729.  
  730.    WndAttr->prevscrollpos = WndAttr->scrollpos;
  731.  
  732.    fontsize = WndAttr->fontmax;
  733.  
  734.    range = rect.yTop - rect.yBottom + fontsize - 1;
  735.    range /= fontsize;
  736.  
  737.    winsize = WndAttr->winlines * fontsize;
  738.  
  739.    invalidoffset = (winsize - rect.yTop) / fontsize;
  740.  
  741.    elem = LPElemTrack( WndAttr->list,
  742.                        WndAttr->current,
  743.                        invalidoffset );
  744.  
  745.    pos.y = winsize;
  746.    pos.y -= invalidoffset * fontsize;
  747.    pos.y -= WndAttr->fontbase;
  748.  
  749.  /* Left margin */
  750.    pos.x = WndAttr->xpos;
  751.  
  752.    while (range-- && elem != WndAttr->list) {
  753.       if (elem->nextmk) {
  754.          rect.yTop = pos.y + WndAttr->fontbase;
  755.          rect.yBottom = rect.yTop - fontsize;
  756.          WinFillRect( hps, &rect, CLR_YELLOW );
  757.       }
  758.       GpiCharStringAt( hps, &pos, strlen( elem->data), elem->data );
  759.       elem = elem->next;
  760.       pos.y -= fontsize;
  761.    }
  762.  
  763.    WinEndPaint( hps );
  764.  
  765.    listlines = LPListLines( WndAttr->list );
  766.    range = listlines - WndAttr->winlines + 1;
  767.  
  768.   /* Post messages to scroll bar in this order so that the buttons */
  769.   /* are updated properly.                                         */
  770.    WinPostMsg( WndAttr->Scroll, SBM_SETSCROLLBAR,
  771.                MPFROMSHORT( WndAttr->scrollpos ),
  772.                MPFROM2SHORT( 1, range ) );
  773.    WinPostMsg( WndAttr->Scroll, SBM_SETTHUMBSIZE,
  774.                MPFROM2SHORT( WndAttr->winlines, listlines ), 0 );
  775.  
  776.    return MRFROMSHORT( FALSE );
  777. }
  778.  
  779. /*-------------------------------------------------------------------------
  780.                             InvalidateLines
  781. --------------------------------------------------------------------------*/
  782. void InvalidateLines( WNDATTR *wndattr, int top, int bottom )
  783. {
  784.  RECTL rect;
  785.  
  786.    WinQueryWindowRect( wndattr->Client, &rect );
  787.  
  788.    top = min( top, wndattr->winlines - 1 );
  789.    bottom = max( 0, bottom );
  790.    rect.yBottom = bottom * wndattr->fontmax;
  791.    rect.yTop = (top + 1) * wndattr->fontmax;
  792.  
  793.    WinInvalidateRect( wndattr->Client, &rect, TRUE );
  794.    return;
  795. }
  796.