Annotation of pmsdk/samples/fatpel/fatpel.c, revision 1.1

1.1     ! root        1: /************************************************************************
        !             2: *
        !             3: *   fatpel.c -- The Diamond Metric, Theory vs. Practice
        !             4: *
        !             5: *   Created by Microsoft Corporation, 1989
        !             6: *
        !             7: ************************************************************************/
        !             8: 
        !             9: #define INCL_WINFRAMEMGR
        !            10: #define INCL_WINWINDOWMGR
        !            11: #define INCL_WINMESSAGEMGR
        !            12: #define        INCL_WINPOINTERS
        !            13: #define INCL_WINSWITCHLIST
        !            14: #define INCL_WINTRACKRECT
        !            15: #define INCL_WINDIALOGS
        !            16: #define INCL_WINBUTTONS
        !            17: #define INCL_GPILOGCOLORTABLE
        !            18: #define INCL_GPIBITMAPS
        !            19: #define        INCL_GPITRANSFORMS
        !            20: #define INCL_DOSMEMMGR
        !            21: #define INCL_DOSFILEMGR
        !            22: #define INCL_BITMAPFILEFORMAT
        !            23: #define INCL_GPIPRIMITIVES
        !            24: #define INCL_WINMENUS
        !            25: #define INCL_GPIREGIONS
        !            26: #define INCL_WINPOINTERS
        !            27: #define INCL_WININPUT
        !            28: #include <os2.h>
        !            29: 
        !            30: #include <mt\stdio.h>
        !            31: #include <mt\stdlib.h>
        !            32: #include <mt\string.h>
        !            33: 
        !            34: #include "opendlg.h"
        !            35: #include "fatpel.h"
        !            36: 
        !            37: 
        !            38: 
        !            39: 
        !            40: /************************************************************************
        !            41: *
        !            42: *   Function declarations
        !            43: *
        !            44: ************************************************************************/
        !            45: 
        !            46: /* Private functions */
        !            47: 
        !            48: VOID  cdecl main(VOID);
        !            49: BOOL  FAR InitGlobals(VOID);
        !            50: BOOL  FAR InitApp(VOID);
        !            51: VOID  Close(HWND);
        !            52: VOID  Command(HWND, USHORT);
        !            53: VOID  Paint(HPS, USHORT);
        !            54: VOID  EraseBackground(HPS);
        !            55: VOID  DrawGrid(HPS);
        !            56: VOID  DisplayRenderedPels(HPS, USHORT);
        !            57: VOID  DisplayControlPoints(HPS, LONG, PPOINTL, USHORT);
        !            58: VOID  DisplayMathematicalObject(HPS, USHORT);
        !            59: VOID  DrawFatPels(HPS);
        !            60: VOID  DrawOneFatPel(HPS, PPOINTL, COLOR);
        !            61: VOID  GetFatPelFromPt(PPOINTL, PPOINTL);
        !            62: VOID  SetFatPel(PPOINTL, COLOR);
        !            63: VOID  RoundControlPoints(HPS, LONG, PPOINTL, PPOINTL, LONG, LONG);
        !            64: VOID  ComputeTransform(PRECTL, PRECTL);
        !            65: VOID  DrawPrimitive(HPS, LONG, PPOINTL);
        !            66: VOID  UpdateSurfaceDims(VOID);
        !            67: VOID  MySetWindowLong  (HWND, USHORT, LONG);
        !            68: VOID  MySetWindowLongHex(HWND, USHORT, LONG);
        !            69: LONG  MyGetWindowLong  (HWND, USHORT);
        !            70: VOID  MouseMove(HWND, MPARAM);
        !            71: VOID  ButtonUp(HWND, USHORT);
        !            72: VOID  ButtonDown(HWND, USHORT, MPARAM);
        !            73: VOID  DragPelSize(HWND, POINTS);
        !            74: VOID  WriteFile(HWND, HPS);
        !            75: BOOL  WriteBMP(HFILE, HPS, PBITMAPINFOHEADER);
        !            76: VOID  MyMessageBox(HWND, PSZ);
        !            77: VOID  SaveWindowToFile(HWND);
        !            78: SHORT IsPtInList(PPOINTL);
        !            79: SHORT AddPtToList(PPOINTL);
        !            80: BOOL  IsPtCloseToLine(PPOINTL, PPOINTL, PPOINTL);
        !            81: VOID  SwapLong(PLONG, PLONG);
        !            82: 
        !            83: 
        !            84: /* Exported functions */
        !            85: 
        !            86: ULONG CALLBACK WndProc  (HWND, USHORT, MPARAM, MPARAM);
        !            87: ULONG CALLBACK AboutDlg  (HWND, USHORT, MPARAM, MPARAM);
        !            88: ULONG CALLBACK ColorsDlg (HWND, USHORT, MPARAM, MPARAM);
        !            89: ULONG CALLBACK PelSizeDlg(HWND, USHORT, MPARAM, MPARAM);
        !            90: 
        !            91: 
        !            92: 
        !            93: 
        !            94: /************************************************************************
        !            95: *
        !            96: *   Global Variables
        !            97: *
        !            98: ************************************************************************/
        !            99: 
        !           100: /* compute absolute value for arbitrary (in my case, LONG) number */
        !           101: /* this is to avoid compiler warnings about data conversion */
        !           102: #define L_ABS(x)       (((x) > 0) ? (x) : (-(x)))
        !           103: 
        !           104: typedef struct
        !           105: {
        !           106:     HAB      hab;
        !           107:     HMQ      hMsgQ;
        !           108:     HWND     hwndFrame;
        !           109:     HWND     hwnd;
        !           110: 
        !           111:     BOOL     fFirstTime;   /* TRUE --> first time initialization of rcl */
        !           112:     RECTL    rcl;         /* dimensions of client rectangle */
        !           113: 
        !           114:     HPS      hpsFat;
        !           115:     HDC      hdcFat;
        !           116:     HBITMAP  hbmFat;
        !           117:     HPS      hpsFatShadow;
        !           118:     HDC      hdcFatShadow;
        !           119:     HBITMAP  hbmFatShadow;
        !           120: 
        !           121:     RECTL    rclFatBM;    /* dimensions of fatbits bitmap */
        !           122:     RECTL    rclFat;      /* dimensions of active fat bits grid */
        !           123:     LONG     cxFatPel;     /* width of fat pel */
        !           124:     LONG     cyFatPel;     /* height of fat pel */
        !           125:     LONG     cxHalfFatPel;
        !           126:     LONG     cyHalfFatPel;
        !           127:     USHORT   usPelShape;
        !           128: 
        !           129:     MATRIXLF matlf;    /* goes from window coords to fatpel coords */
        !           130: 
        !           131:     BOOL     fRGB;        /* TRUE --> color mode is RGB */
        !           132:     COLOR    clrMathObj;
        !           133:     COLOR    clrRenderedObj;
        !           134:     COLOR    clrField;
        !           135:     COLOR    clrCrossHair;
        !           136:     COLOR    clrInterstice;
        !           137:     COLOR    clrControlPoints;
        !           138: 
        !           139:     COLOR    clrBlackIndex;
        !           140:     COLOR    clrEditPel;
        !           141: 
        !           142:     USHORT   usControlPointSymbol;
        !           143: 
        !           144:     BOOL     fDisplayRenderedObj;
        !           145:     BOOL     fDisplayMathObj;
        !           146:     BOOL     fDisplayControlPoints;
        !           147:     BOOL     fDisplayCrossHairs;
        !           148:     BOOL     fDisplayPelBorder;
        !           149:     BOOL     fRoundControlPoints;
        !           150:     BOOL     fAutoRedraw;
        !           151:     USHORT   usCurPrim;
        !           152:     USHORT   usMix;
        !           153: 
        !           154:     LONG     cptl;
        !           155:     PPOINTL  pptl;
        !           156:     PPOINTL  pptlTmp;
        !           157: 
        !           158:     BOOL     fDraggingPelSize;
        !           159:     HPOINTER hptrDragSize;
        !           160: 
        !           161:     BOOL     fDraggingPelColor;
        !           162:     HPOINTER hptrDragColor;
        !           163: 
        !           164:     SHORT    sPtGrabbed;
        !           165:     BOOL     fDraggingControlPoint;
        !           166:     LONG     lHitPrecision;
        !           167: 
        !           168:     BOOL     fEditPelColors;
        !           169: 
        !           170: } GLOBALDATA;
        !           171: GLOBALDATA global;
        !           172: 
        !           173: 
        !           174: 
        !           175: 
        !           176: /************************************************************************
        !           177: *
        !           178: *   main
        !           179: *
        !           180: *   WinInitialize resizes our ring 2 stack, among other things, so
        !           181: *   we won't GP fault trying to do graphics.  WinCreateMsgQueue defines
        !           182: *   us as a REAL PM app. (WINDOWAPI in .DEF file does also).
        !           183: *   Call a sub to register our window class and create a window.
        !           184: *   Loop over messages.  Exit cleanly.
        !           185: *
        !           186: ************************************************************************/
        !           187: 
        !           188: VOID cdecl
        !           189: main()
        !           190: {
        !           191:     QMSG qMsg;
        !           192:     int iRet = 0;
        !           193: 
        !           194: 
        !           195:     global.hab  = WinInitialize(NULL);
        !           196:     global.hMsgQ = WinCreateMsgQueue(global.hab, 0);
        !           197: 
        !           198:     if (InitApp())
        !           199:        while (WinGetMsg( global.hab, (PQMSG)&qMsg, (HWND)NULL, 0, 0 ))
        !           200:            WinDispatchMsg( global.hab, (PQMSG)&qMsg );
        !           201:     else
        !           202:        iRet = -1;
        !           203: 
        !           204:     WinDestroyWindow( global.hwndFrame );
        !           205:     WinDestroyMsgQueue( global.hMsgQ );
        !           206:     WinTerminate( global.hab );
        !           207:     DosExit(EXIT_PROCESS, iRet);
        !           208: }
        !           209: 
        !           210: 
        !           211: 
        !           212: 
        !           213: /****************************************************************************
        !           214: *
        !           215: *   InitGlobals
        !           216: *
        !           217: *   Initialize global variables.
        !           218: *
        !           219: ****************************************************************************/
        !           220: 
        !           221: BOOL FAR
        !           222: InitGlobals()
        !           223: {
        !           224:     global.fFirstTime           = TRUE;
        !           225: 
        !           226:     global.rcl.xLeft            = 0L;
        !           227:     global.rcl.yBottom          = 0L;
        !           228:     global.rcl.xRight           = 0L;
        !           229:     global.rcl.yTop             = 0L;
        !           230: 
        !           231:     global.hpsFat               = NULL;
        !           232:     global.hdcFat               = NULL;
        !           233:     global.hbmFat               = NULL;
        !           234:     global.hpsFatShadow         = NULL;
        !           235:     global.hdcFatShadow         = NULL;
        !           236:     global.hbmFatShadow         = NULL;
        !           237:     global.rclFatBM.xLeft       = 0L;
        !           238:     global.rclFatBM.yBottom     = 0L;
        !           239:     global.rclFatBM.xRight      = 0L;
        !           240:     global.rclFatBM.yTop        = 0L;
        !           241: 
        !           242:     global.cxFatPel             = 32L;
        !           243:     global.cyFatPel             = 32L;
        !           244:     global.cxHalfFatPel         = global.cxFatPel / 2L;
        !           245:     global.cyHalfFatPel         = global.cyFatPel / 2L;
        !           246:     global.usPelShape           = IDD_CIRCLE;
        !           247: 
        !           248:     global.fRGB                 = FALSE;
        !           249:     global.clrMathObj           = CLR_BLUE;
        !           250:     global.clrRenderedObj       = CLR_NEUTRAL;
        !           251:     global.clrField             = CLR_CYAN;
        !           252:     global.clrCrossHair         = CLR_DARKCYAN;
        !           253:     global.clrInterstice        = CLR_BACKGROUND;
        !           254:     global.clrControlPoints     = CLR_YELLOW;
        !           255: 
        !           256:     global.clrBlackIndex        = CLR_ERROR;
        !           257:     global.clrEditPel           = CLR_ERROR;
        !           258: 
        !           259:     global.usControlPointSymbol  = MARKSYM_SOLIDDIAMOND;
        !           260: 
        !           261:     global.fDisplayRenderedObj  = TRUE;
        !           262:     global.fDisplayMathObj      = TRUE;
        !           263:     global.fDisplayControlPoints = TRUE;
        !           264:     global.fDisplayCrossHairs   = TRUE;
        !           265:     global.fDisplayPelBorder    = TRUE;
        !           266:     global.fRoundControlPoints  = FALSE;
        !           267:     global.fAutoRedraw          = TRUE;
        !           268:     global.usCurPrim            = IDM_POLYLINE;
        !           269:     global.usMix                = FM_OVERPAINT;
        !           270: 
        !           271:     global.fDraggingPelSize     = FALSE;
        !           272:     global.fDraggingPelColor    = FALSE;
        !           273:     global.fDraggingControlPoint = FALSE;
        !           274:     global.sPtGrabbed           = NO_POINT;
        !           275:     global.lHitPrecision        = 0L;
        !           276: 
        !           277:     global.fEditPelColors       = FALSE;
        !           278: 
        !           279: 
        !           280:     global.cptl = 0L;
        !           281:     global.pptl = NULL;
        !           282:     if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
        !           283:                   ((PUSHORT)&global.pptl)+1, 0))
        !           284:        return FALSE;
        !           285:     global.pptlTmp = NULL;
        !           286:     if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
        !           287:                   ((PUSHORT)&global.pptlTmp)+1, 0))
        !           288:        return FALSE;
        !           289: 
        !           290:     return TRUE;
        !           291: }
        !           292: 
        !           293: 
        !           294: 
        !           295: 
        !           296: /****************************************************************************
        !           297: *
        !           298: *   InitApp
        !           299: *
        !           300: *   Register application window class and creates standard window.
        !           301: *
        !           302: ****************************************************************************/
        !           303: 
        !           304: #define INIT_MENU_ITEM(val, var)     \
        !           305:        TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var))
        !           306: 
        !           307: BOOL FAR
        !           308: InitApp()
        !           309: {
        !           310:     char szTitle[24];
        !           311:     ULONG ctldata;
        !           312:     PID pid;
        !           313:     TID tid;
        !           314:     HSWITCH hsw;
        !           315:     static SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE,
        !           316:                             SWL_JUMPABLE, "FatPels", 0 };
        !           317: 
        !           318:     if (!InitGlobals())
        !           319:        return FALSE;
        !           320: 
        !           321: 
        !           322:     /*  Register Application Window Class  */
        !           323: 
        !           324:     WinLoadString( global.hab, NULL, IDS_TITLE, sizeof(szTitle), (PCH)szTitle );
        !           325:     if ( !WinRegisterClass( global.hab, (PCH)szTitle, (PFNWP)WndProc,
        !           326:            CS_SIZEREDRAW, 0 ))
        !           327:        return FALSE;
        !           328: 
        !           329: 
        !           330:     /* Load the pointer to use when dragging pel size. */
        !           331:     if (!(global.hptrDragSize = WinLoadPointer( HWND_DESKTOP, NULL, IDR_DRAGSIZEPTR )))
        !           332:        return FALSE;
        !           333: 
        !           334:     /* Load the pointer to use when dragging pel color. */
        !           335:     if (!(global.hptrDragColor = WinLoadPointer( HWND_DESKTOP, NULL, IDR_DRAGCOLORPTR )))
        !           336:        return FALSE;
        !           337: 
        !           338: 
        !           339:     /* Create a window instance of class "FatPel" */
        !           340: 
        !           341:     ctldata = FCF_STANDARD &
        !           342:      ~(ULONG)(FCF_ICON | FCF_ACCELTABLE | FCF_TASKLIST);
        !           343: 
        !           344:     if (global.hwndFrame = WinCreateStdWindow(
        !           345:        HWND_DESKTOP,              /* specify desktop as parent window      */
        !           346:        WS_VISIBLE,                /* window styles                         */
        !           347:        &ctldata,                  /* frame creation flags                  */
        !           348:        (PCH)szTitle,              /* window class name                     */
        !           349:        (PCH)szTitle,              /* name appearing in window caption      */
        !           350:        0L,                        /*                                       */
        !           351:        (HMODULE)NULL,             /* use current executable module id      */
        !           352:        IDR_FATPEL,                /* menu id                               */
        !           353:        (HWND FAR *)&global.hwnd   /* window handle                         */
        !           354:        ))
        !           355:     {
        !           356:        INIT_MENU_ITEM(IDM_RENDEREDOBJ,  global.fDisplayRenderedObj);
        !           357:        INIT_MENU_ITEM(IDM_MATHOBJ,      global.fDisplayMathObj);
        !           358:        INIT_MENU_ITEM(IDM_CTLPOINTS,    global.fDisplayControlPoints);
        !           359:        INIT_MENU_ITEM(IDM_CROSSHAIRS,   global.fDisplayCrossHairs);
        !           360:        INIT_MENU_ITEM(IDM_PELBORDER,    global.fDisplayPelBorder);
        !           361:        INIT_MENU_ITEM(IDM_ROUNDPOINTS,  global.fRoundControlPoints);
        !           362:        INIT_MENU_ITEM(IDM_AUTOREDRAW,   global.fAutoRedraw);
        !           363:        INIT_MENU_ITEM(IDM_EDITPELCOLORS, global.fEditPelColors);
        !           364: 
        !           365:        CHECK_MENU_ITEM(global.hwndFrame, global.usCurPrim);
        !           366: 
        !           367: 
        !           368:        /* Add ourselves to the switch list. */
        !           369: 
        !           370:        WinQueryWindowProcess(global.hwndFrame, &pid, &tid);
        !           371:        swctl.hwnd      = global.hwndFrame;
        !           372:        swctl.idProcess = pid;
        !           373:        hsw = WinAddSwitchEntry(&swctl);
        !           374: 
        !           375:        return TRUE;
        !           376:     }
        !           377:     return FALSE;
        !           378: }
        !           379: 
        !           380: 
        !           381: 
        !           382: 
        !           383: /*************************************************************************
        !           384: *
        !           385: *   WndProc
        !           386: *
        !           387: *   Process messages for the window class.
        !           388: *
        !           389: ************************************************************************/
        !           390: 
        !           391: ULONG CALLBACK
        !           392: WndProc( hwnd, usMsg, mp1, mp2 )
        !           393: HWND   hwnd;
        !           394: USHORT usMsg;
        !           395: MPARAM  mp1;
        !           396: MPARAM  mp2;
        !           397: {
        !           398:     switch (usMsg)
        !           399:     {
        !           400:     case WM_CLOSE:
        !           401:        Close(hwnd);
        !           402:        break;
        !           403: 
        !           404:     case WM_COMMAND:
        !           405:        Command(hwnd, LOUSHORT(mp1));
        !           406:        break;
        !           407: 
        !           408:     case WM_PAINT:
        !           409:        {
        !           410:            HPS   hps;
        !           411: 
        !           412:            if (global.fFirstTime)
        !           413:            {
        !           414:                SIZEF sizfx;
        !           415: 
        !           416:                hps = WinGetPS(hwnd);
        !           417:                GpiQueryMarkerBox(hps, &sizfx);
        !           418:                global.lHitPrecision = sizfx.cx / 0x20000L + 1L;
        !           419:                WinReleasePS(hps);
        !           420: 
        !           421:                UpdateSurfaceDims();
        !           422:                global.fFirstTime = FALSE;
        !           423:            }
        !           424: 
        !           425:            /* The small bitmap may have been resized since we last
        !           426:             * painted, in which case it will have been initialized to
        !           427:             * the field color.  Therefore, we will render the mathematical
        !           428:             * object to make sure the right fatpels are there.
        !           429:             */
        !           430:            global.usMix = FM_OVERPAINT;
        !           431:            hps = WinBeginPaint(global.hwnd, NULL, NULL);
        !           432:            Paint(hps, CLEAR_BACKGROUND|RENDER_MATH_OBJ);
        !           433:            WinEndPaint(hps);
        !           434:        }
        !           435:        break;
        !           436: 
        !           437:     case WM_BUTTON1DOWN:
        !           438:     case WM_BUTTON2DOWN:
        !           439:        ButtonDown(hwnd, usMsg, mp1);
        !           440:        break;
        !           441: 
        !           442:     case WM_BUTTON1UP:
        !           443:     case WM_BUTTON2UP:
        !           444:        ButtonUp(hwnd, usMsg);
        !           445:        break;
        !           446: 
        !           447:     case WM_MOUSEMOVE:
        !           448:        MouseMove(hwnd, mp1);
        !           449:        break;
        !           450: 
        !           451:     case WM_SIZE:
        !           452:        UpdateSurfaceDims();
        !           453:        return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
        !           454:        break;
        !           455: 
        !           456:     default:
        !           457:        return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
        !           458:        break;
        !           459:     }
        !           460: 
        !           461:     return FALSE;
        !           462: }
        !           463: 
        !           464: 
        !           465: 
        !           466: 
        !           467: /************************************************************************
        !           468: *
        !           469: *   MouseMove
        !           470: *
        !           471: ************************************************************************/
        !           472: 
        !           473: VOID
        !           474: MouseMove(hwnd, mp1)
        !           475: HWND hwnd;
        !           476: MPARAM mp1;
        !           477: {
        !           478:     POINTL ptl;
        !           479:     HPS hps;
        !           480: 
        !           481: 
        !           482:     /* make sure we still have our pointer */
        !           483:     /* notice the hierarchy of pointer modes */
        !           484: 
        !           485:     if (global.fDraggingPelSize)
        !           486:     {
        !           487:        if (global.hptrDragSize)
        !           488:            WinSetPointer(HWND_DESKTOP,global.hptrDragSize);
        !           489:     }
        !           490:     else if (global.fEditPelColors)
        !           491:     {
        !           492:        if (global.hptrDragColor)
        !           493:            WinSetPointer(HWND_DESKTOP,global.hptrDragColor);
        !           494:     }
        !           495:     else
        !           496:        WinSetPointer(HWND_DESKTOP,
        !           497:                  WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
        !           498: 
        !           499: 
        !           500:     if (global.fDraggingPelColor)
        !           501:     {
        !           502:        POINTL ptl, ptlFat;
        !           503:        HPS hps;
        !           504: 
        !           505: 
        !           506:        ptl.x = (LONG) LOUSHORT(mp1);
        !           507:        ptl.y = (LONG) HIUSHORT(mp1);
        !           508: 
        !           509:        /* letting the point go negative causes overflow errors */
        !           510:        if (ptl.x < 0)
        !           511:            ptl.x = 0;
        !           512:        if (ptl.y < 0)
        !           513:            ptl.y = 0;
        !           514: 
        !           515:        GetFatPelFromPt(&ptl, &ptlFat);
        !           516:        SetFatPel(&ptlFat, global.clrEditPel);
        !           517: 
        !           518:        hps = WinGetPS(hwnd);
        !           519:        Paint(hps, OVERRIDE_RENDERED_OBJ);
        !           520:        Paint(hps, IGNORED);    /* this call just copies fatpels to the screen */
        !           521:        WinReleasePS(hps);
        !           522:     }
        !           523:     else if (global.fDraggingControlPoint)
        !           524:     {
        !           525:        ptl.x = (LONG) LOUSHORT(mp1);
        !           526:        ptl.y = (LONG) HIUSHORT(mp1);
        !           527: 
        !           528:        /* letting the point go negative causes overflow errors */
        !           529:        if (ptl.x < 0)
        !           530:            ptl.x = 0;
        !           531:        if (ptl.y < 0)
        !           532:            ptl.y = 0;
        !           533: 
        !           534:        if (global.sPtGrabbed != NO_POINT)
        !           535:        {
        !           536:            hps = WinGetPS(hwnd);
        !           537:            Paint(hps, OVERRIDE_RENDERED_OBJ);
        !           538: 
        !           539:            global.pptl[global.sPtGrabbed] = ptl;
        !           540: 
        !           541:            Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
        !           542:            WinReleasePS(hps);
        !           543:        }
        !           544:     }
        !           545: }
        !           546: 
        !           547: 
        !           548: 
        !           549: 
        !           550: /************************************************************************
        !           551: *
        !           552: *   ButtonUp
        !           553: *
        !           554: ************************************************************************/
        !           555: 
        !           556: VOID
        !           557: ButtonUp(hwnd, usMsg)
        !           558: HWND hwnd;
        !           559: USHORT usMsg;
        !           560: {
        !           561:     SHORT i;
        !           562:     HPS hps;
        !           563: 
        !           564: 
        !           565:     if (global.fDraggingPelColor)
        !           566:     {
        !           567:        global.fDraggingPelColor = FALSE;
        !           568:        WinSetCapture(HWND_DESKTOP, NULL);
        !           569:     }
        !           570:     else if (global.fDraggingControlPoint)
        !           571:     {
        !           572:        global.fDraggingControlPoint = FALSE;
        !           573:        WinSetCapture(HWND_DESKTOP, NULL);
        !           574:        if (global.sPtGrabbed != NO_POINT)
        !           575:        {
        !           576:            if (usMsg == WM_BUTTON2UP)  /* remove point? */
        !           577:            {
        !           578:                hps = WinGetPS(hwnd);
        !           579:                Paint(hps, OVERRIDE_RENDERED_OBJ);
        !           580: 
        !           581:                /* squeeze out selected point */
        !           582:                if ((i = global.sPtGrabbed) < (SHORT)(global.cptl-1))
        !           583:                    while (i < (SHORT)(global.cptl-1))
        !           584:                    {
        !           585:                        global.pptl[i] = global.pptl[i+1];
        !           586:                        ++i;
        !           587:                    }
        !           588: 
        !           589:                --global.cptl;
        !           590:                global.sPtGrabbed = NO_POINT;
        !           591: 
        !           592:                Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
        !           593:                WinReleasePS(hps);
        !           594:            }
        !           595:            else    /* WM_BUTTON1UP */
        !           596:                global.sPtGrabbed = NO_POINT;
        !           597:        }
        !           598:     }
        !           599: }
        !           600: 
        !           601: 
        !           602: 
        !           603: 
        !           604: /************************************************************************
        !           605: *
        !           606: *   ButtonDown
        !           607: *
        !           608: ************************************************************************/
        !           609: 
        !           610: VOID
        !           611: ButtonDown(hwnd, usMsg, mp1)
        !           612: HWND hwnd;
        !           613: USHORT usMsg;
        !           614: MPARAM mp1;
        !           615: {
        !           616:     if (global.fDraggingPelSize)
        !           617:     {
        !           618:        POINTS pt;
        !           619:        HPS hps;
        !           620: 
        !           621:        pt.x = LOUSHORT(mp1);
        !           622:        pt.y = HIUSHORT(mp1);
        !           623:        DragPelSize(hwnd, pt);
        !           624:        global.fDraggingPelSize = FALSE;
        !           625: 
        !           626:        WinSetPointer(HWND_DESKTOP,
        !           627:                      WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
        !           628: 
        !           629:        hps = WinGetPS(hwnd);
        !           630:        global.usMix = FM_OVERPAINT;
        !           631:        Paint(hps, CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
        !           632:        WinReleasePS(hps);
        !           633:     }
        !           634:     else if (global.fEditPelColors)
        !           635:     {
        !           636:        POINTL ptl, ptlFat;
        !           637:        HPS hps;
        !           638: 
        !           639:        global.fDraggingPelColor = TRUE;
        !           640:        WinSetCapture(HWND_DESKTOP, hwnd);
        !           641: 
        !           642:        ptl.x = (LONG) LOUSHORT(mp1);
        !           643:        ptl.y = (LONG) HIUSHORT(mp1);
        !           644: 
        !           645:        if (global.usMix != FM_XOR)
        !           646:        {
        !           647:            hps = WinGetPS(hwnd);
        !           648:            global.usMix = FM_XOR;
        !           649:            Paint(hps, CLEAR_BACKGROUND);
        !           650:            WinReleasePS(hps);
        !           651:        }
        !           652: 
        !           653:        if (usMsg == WM_BUTTON1DOWN)
        !           654:            global.clrEditPel = global.clrRenderedObj;
        !           655:        else
        !           656:            global.clrEditPel = global.clrField;
        !           657: 
        !           658:        GetFatPelFromPt(&ptl, &ptlFat);
        !           659:        SetFatPel(&ptlFat, global.clrEditPel);
        !           660: 
        !           661:        hps = WinGetPS(hwnd);
        !           662:        Paint(hps, OVERRIDE_RENDERED_OBJ);
        !           663:        Paint(hps, IGNORED);    /* this call just copies fatpels to the screen */
        !           664:        WinReleasePS(hps);
        !           665:     }
        !           666:     else if (!global.fDraggingControlPoint)
        !           667:     {
        !           668:        POINTL ptl;
        !           669:        SHORT sNewPtGrabbed;
        !           670:        HPS hps;
        !           671: 
        !           672:        global.fDraggingControlPoint = TRUE;
        !           673:        WinSetCapture(HWND_DESKTOP, hwnd);
        !           674: 
        !           675:        ptl.x = (LONG) LOUSHORT(mp1);
        !           676:        ptl.y = (LONG) HIUSHORT(mp1);
        !           677: 
        !           678:        sNewPtGrabbed = IsPtInList(&ptl);
        !           679: 
        !           680:        if (global.usMix != FM_XOR)
        !           681:        {
        !           682:            hps = WinGetPS(hwnd);
        !           683:            global.usMix = FM_XOR;
        !           684:            Paint(hps, CLEAR_BACKGROUND);
        !           685:            WinReleasePS(hps);
        !           686:        }
        !           687: 
        !           688:        if (usMsg == WM_BUTTON1DOWN)    /* add/move point? */
        !           689:        {
        !           690:            hps = WinGetPS(hwnd);
        !           691: 
        !           692:            if (sNewPtGrabbed != NO_POINT)
        !           693:                global.sPtGrabbed = sNewPtGrabbed;
        !           694:            Paint(hps, OVERRIDE_RENDERED_OBJ);
        !           695: 
        !           696:            if (sNewPtGrabbed == NO_POINT)
        !           697:                global.sPtGrabbed = AddPtToList(&ptl);
        !           698:            else
        !           699:                global.sPtGrabbed = sNewPtGrabbed;
        !           700: 
        !           701:            Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
        !           702:            WinReleasePS(hps);
        !           703: 
        !           704:            if (global.sPtGrabbed == NO_POINT)
        !           705:                MyMessageBox(global.hwnd, "Cannot add any more points.");
        !           706:        }
        !           707:        else if (sNewPtGrabbed != NO_POINT)
        !           708:            global.sPtGrabbed = sNewPtGrabbed;
        !           709:     }
        !           710: }
        !           711: 
        !           712: 
        !           713: 
        !           714: 
        !           715: /************************************************************************
        !           716: *
        !           717: *   GetFatPelFromPt
        !           718: *
        !           719: ************************************************************************/
        !           720: 
        !           721: VOID
        !           722: GetFatPelFromPt(pptl, pptlFat)
        !           723: PPOINTL pptl;
        !           724: PPOINTL pptlFat;
        !           725: {
        !           726:     pptlFat->x = pptl->x / global.cxFatPel;
        !           727:     pptlFat->y = pptl->y / global.cyFatPel;
        !           728: }
        !           729: 
        !           730: 
        !           731: 
        !           732: 
        !           733: /************************************************************************
        !           734: *
        !           735: *   SetFatPel
        !           736: *
        !           737: ************************************************************************/
        !           738: 
        !           739: VOID
        !           740: SetFatPel(pptl, clr)
        !           741: PPOINTL pptl;
        !           742: COLOR clr;
        !           743: {
        !           744:     LINEBUNDLE lb;
        !           745: 
        !           746:     if (global.hpsFat)
        !           747:     {
        !           748:        lb.lColor = clr;
        !           749:        GpiSetAttrs(global.hpsFat, PRIM_LINE, LBB_COLOR, 0L, &lb);
        !           750:        GpiSetPel(global.hpsFat, pptl);
        !           751:     }
        !           752: }
        !           753: 
        !           754: 
        !           755: 
        !           756: 
        !           757: /************************************************************************
        !           758: *
        !           759: *   IsPtInList
        !           760: *
        !           761: ************************************************************************/
        !           762: 
        !           763: SHORT
        !           764: IsPtInList(pptl)
        !           765: PPOINTL pptl;
        !           766: {
        !           767:     SHORT i;
        !           768: 
        !           769: 
        !           770:     /* try to find pptl in the points we already have */
        !           771:     for (i = 0; i < (SHORT)global.cptl; ++i)
        !           772:        if (((L_ABS(pptl->x - global.pptl[i].x)) <= global.lHitPrecision) &&
        !           773:            ((L_ABS(pptl->y - global.pptl[i].y)) <= global.lHitPrecision))
        !           774:                return i;
        !           775: 
        !           776:     /* couldn't find it */
        !           777:     return NO_POINT;
        !           778: }
        !           779: 
        !           780: 
        !           781: 
        !           782: 
        !           783: /************************************************************************
        !           784: *
        !           785: *   AddPtToList
        !           786: *
        !           787: ************************************************************************/
        !           788: 
        !           789: SHORT
        !           790: AddPtToList(pptl)
        !           791: PPOINTL pptl;
        !           792: {
        !           793:     SHORT i, j;
        !           794: 
        !           795:     if (global.cptl < CPTLMAX)
        !           796:     {
        !           797:        /* check for new points lying on a line segment */
        !           798:        for (i = 0; i < (SHORT)(global.cptl-1L); ++i)
        !           799:            if (IsPtCloseToLine(&global.pptl[i], &global.pptl[i+1], pptl))
        !           800:            {
        !           801:                /* insert point between endpoints of nearest line segment */
        !           802:                for (j = (SHORT)global.cptl; j > i+1; --j)
        !           803:                    global.pptl[j] = global.pptl[j - 1];
        !           804:                global.pptl[i+1] = *pptl;
        !           805:                ++global.cptl;
        !           806:                return i+1;
        !           807:            }
        !           808: 
        !           809:        /* append the point */
        !           810: 
        !           811:        i = (SHORT) global.cptl;
        !           812:        global.pptl[i] = *pptl;
        !           813:        ++global.cptl;
        !           814:        return i;
        !           815:     }
        !           816: 
        !           817:     return NO_POINT;
        !           818: }
        !           819: 
        !           820: 
        !           821: 
        !           822: 
        !           823: /************************************************************************
        !           824: *
        !           825: *   IsPtCloseToLine
        !           826: *
        !           827: ************************************************************************/
        !           828: 
        !           829: BOOL
        !           830: IsPtCloseToLine(pptl1, pptl2, pptlTest)
        !           831: PPOINTL pptl1;
        !           832: PPOINTL pptl2;
        !           833: PPOINTL pptlTest;
        !           834: {
        !           835:     POINTL ptlLL, ptlUR;
        !           836:     LONG dx, dy, yIntercept, error;
        !           837:     LONG lBoxAdjustment;
        !           838: 
        !           839: 
        !           840:     /* find the bounding box of the line segment */
        !           841: 
        !           842:     ptlLL = *pptl1;    /* assume line goes lower left to upper right */
        !           843:     ptlUR = *pptl2;
        !           844:     if (pptl1->x > pptl2->x)
        !           845:        SwapLong(&ptlLL.x, &ptlUR.x);
        !           846:     if (pptl1->y > pptl2->y)
        !           847:        SwapLong(&ptlLL.y, &ptlUR.y);
        !           848: 
        !           849: 
        !           850:     /* adjust the bounding box if it's too narrow */
        !           851: 
        !           852:     lBoxAdjustment = global.lHitPrecision/2L;
        !           853: 
        !           854:     dx = pptl2->x - pptl1->x;
        !           855:     if (L_ABS(dx) <= global.lHitPrecision)
        !           856:     {
        !           857:        ptlLL.x -= lBoxAdjustment;
        !           858:        ptlUR.x += lBoxAdjustment;
        !           859:     }
        !           860:     dy = pptl2->y - pptl1->y;
        !           861:     if (L_ABS(dy) <= global.lHitPrecision)
        !           862:     {
        !           863:        ptlLL.y -= lBoxAdjustment;
        !           864:        ptlUR.y += lBoxAdjustment;
        !           865:     }
        !           866: 
        !           867: 
        !           868:     /* see if the test point is in the bounding box of the line segment */
        !           869: 
        !           870:     if ((pptlTest->x >= ptlLL.x) &&
        !           871:        (pptlTest->x <= ptlUR.x) &&
        !           872:        (pptlTest->y >= ptlLL.y) &&
        !           873:        (pptlTest->y <= ptlUR.y))
        !           874:     {
        !           875:        /* test for special cases */
        !           876: 
        !           877:        if (dx == 0)    /* vertical line */
        !           878:        {
        !           879:            return (L_ABS(pptlTest->x - pptl1->x) <= global.lHitPrecision);
        !           880:        }
        !           881: 
        !           882:        if (dy == 0)    /* horizontal line */
        !           883:        {
        !           884:            return (L_ABS(pptlTest->y - pptl1->y) <= global.lHitPrecision);
        !           885:        }
        !           886: 
        !           887: 
        !           888:        /* test for general case */
        !           889: 
        !           890:        yIntercept = pptl1->y - (pptl1->x * dy) / dx;
        !           891: 
        !           892:        error = pptlTest->y - (pptlTest->x * dy / dx) - yIntercept;
        !           893:        if (L_ABS(error) <= global.lHitPrecision)
        !           894:            return TRUE;
        !           895:     }
        !           896: 
        !           897:     return FALSE;
        !           898: }
        !           899: 
        !           900: 
        !           901: 
        !           902: 
        !           903: /************************************************************************
        !           904: *
        !           905: *   SwapLong
        !           906: *
        !           907: ************************************************************************/
        !           908: 
        !           909: VOID
        !           910: SwapLong(pl1, pl2)
        !           911: PLONG pl1, pl2;
        !           912: {
        !           913:     LONG lTmp;
        !           914: 
        !           915:     lTmp = *pl1;
        !           916:     *pl1 = *pl2;
        !           917:     *pl2 = lTmp;
        !           918: }
        !           919: 
        !           920: 
        !           921: 
        !           922: 
        !           923: /************************************************************************
        !           924: *
        !           925: *   DragPelSize
        !           926: *
        !           927: *   Set the dimensions of a fat pel by dragging a rectangle
        !           928: *   on the screen.
        !           929: *
        !           930: ************************************************************************/
        !           931: 
        !           932: VOID
        !           933: DragPelSize(hwnd, pt)
        !           934: HWND hwnd;
        !           935: POINTS pt;
        !           936: {
        !           937:     TRACKINFO ti;
        !           938: 
        !           939:     WinSendMsg(global.hwndFrame, WM_QUERYTRACKINFO, (MPARAM)TF_MOVE, (MPARAM)&ti);
        !           940: 
        !           941:     ti.cxBorder   = 1;
        !           942:     ti.cyBorder   = 1;
        !           943:     ti.rclTrack.xLeft  = (LONG)pt.x;
        !           944:     ti.rclTrack.yBottom = (LONG)pt.y;
        !           945:     ti.rclTrack.xRight = (LONG)pt.x;
        !           946:     ti.rclTrack.yTop   = (LONG)pt.y;
        !           947:     ti.fs = TF_RIGHT | TF_TOP;
        !           948:     ti.ptlMinTrackSize.x = 1L;
        !           949:     ti.ptlMinTrackSize.y = 1L;
        !           950: 
        !           951:     if (WinTrackRect(hwnd, NULL, &ti))
        !           952:     {
        !           953:        global.cxFatPel = (ti.rclTrack.xRight - ti.rclTrack.xLeft)  ;
        !           954:        global.cyFatPel = (ti.rclTrack.yTop   - ti.rclTrack.yBottom);
        !           955: 
        !           956:        if (global.cxFatPel < 1L)
        !           957:            global.cxFatPel = 1L;
        !           958: 
        !           959:        if (global.cyFatPel < 1L)
        !           960:            global.cyFatPel = 1L;
        !           961: 
        !           962:        global.cxHalfFatPel = global.cxFatPel / 2L;
        !           963:        global.cyHalfFatPel = global.cyFatPel / 2L;
        !           964: 
        !           965:        UpdateSurfaceDims();
        !           966:     }
        !           967: }
        !           968: 
        !           969: 
        !           970: 
        !           971: 
        !           972: /************************************************************************
        !           973: *
        !           974: *   Close
        !           975: *
        !           976: ************************************************************************/
        !           977: 
        !           978: VOID
        !           979: Close(hwnd)
        !           980: HWND hwnd;
        !           981: {
        !           982:     if (global.hptrDragSize)
        !           983:        WinDestroyPointer(global.hptrDragSize);
        !           984:     WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
        !           985: }
        !           986: 
        !           987: 
        !           988: 
        !           989: 
        !           990: /************************************************************************
        !           991: *
        !           992: *   Command
        !           993: *
        !           994: *   Dispatches menu commands to the proper handlers.
        !           995: *
        !           996: ************************************************************************/
        !           997: 
        !           998: #define UPDATE_MENU_BOOL(var, val)                             \
        !           999:        {                                                       \
        !          1000:            TOGGLE_BOOL((var));                                 \
        !          1001:            TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var));   \
        !          1002:        }
        !          1003: 
        !          1004: #define UPDATE_MENU_LIST(var, val)                             \
        !          1005:        {                                                       \
        !          1006:            UNCHECK_MENU_ITEM(global.hwndFrame, (var));         \
        !          1007:            (var) = (val);                                      \
        !          1008:            CHECK_MENU_ITEM(global.hwndFrame, (var));           \
        !          1009:        }
        !          1010: 
        !          1011: VOID
        !          1012: Command(hwnd, id)
        !          1013: HWND hwnd;
        !          1014: USHORT id;
        !          1015: {
        !          1016:     BOOL fRedraw = FALSE;
        !          1017:     USHORT fsCmd = IGNORED;
        !          1018: 
        !          1019: 
        !          1020:     switch (id)
        !          1021:     {
        !          1022:     case IDM_SAVE:
        !          1023:        SaveWindowToFile(hwnd);
        !          1024:        break;
        !          1025: 
        !          1026:     case IDM_ABOUT:
        !          1027:        WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)AboutDlg, NULL,
        !          1028:                       IDR_ABOUTDLG, NULL );
        !          1029:        break;
        !          1030: 
        !          1031:     case IDM_REDRAW:
        !          1032:        fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
        !          1033:        break;
        !          1034: 
        !          1035:     case IDM_SETPELSIZE:
        !          1036:        {
        !          1037:            LONG cxFatPel, cyFatPel;
        !          1038: 
        !          1039:            cxFatPel = global.cxFatPel;
        !          1040:            cyFatPel = global.cyFatPel;
        !          1041: 
        !          1042:            if (WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)PelSizeDlg, NULL,
        !          1043:                           IDR_PELSIZEDLG, NULL ))
        !          1044:            {
        !          1045:                if ((cxFatPel == global.cxFatPel) &&
        !          1046:                    (cyFatPel == global.cyFatPel))
        !          1047:                    fsCmd = CLEAR_BACKGROUND;
        !          1048:                else
        !          1049:                    fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
        !          1050:                fRedraw = TRUE;
        !          1051:            }
        !          1052:        }
        !          1053:        break;
        !          1054: 
        !          1055:     case IDM_DRAGPELSIZE:
        !          1056:        global.fDraggingPelSize = TRUE;
        !          1057:        break;
        !          1058: 
        !          1059:     case IDM_RENDEREDOBJ:
        !          1060:        UPDATE_MENU_BOOL(global.fDisplayRenderedObj, IDM_RENDEREDOBJ);
        !          1061:        fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
        !          1062:        fRedraw = TRUE;
        !          1063:        break;
        !          1064: 
        !          1065:     case IDM_MATHOBJ:
        !          1066:        UPDATE_MENU_BOOL(global.fDisplayMathObj, IDM_MATHOBJ);
        !          1067:        fsCmd = CLEAR_BACKGROUND;
        !          1068:        fRedraw = TRUE;
        !          1069:        break;
        !          1070: 
        !          1071:     case IDM_CTLPOINTS:
        !          1072:        UPDATE_MENU_BOOL(global.fDisplayControlPoints, IDM_CTLPOINTS);
        !          1073:        fsCmd = CLEAR_BACKGROUND;
        !          1074:        fRedraw = TRUE;
        !          1075:        break;
        !          1076: 
        !          1077:     case IDM_CROSSHAIRS:
        !          1078:        UPDATE_MENU_BOOL(global.fDisplayCrossHairs, IDM_CROSSHAIRS);
        !          1079:        fsCmd = CLEAR_BACKGROUND;
        !          1080:        fRedraw = TRUE;
        !          1081:        break;
        !          1082: 
        !          1083:     case IDM_PELBORDER:
        !          1084:        UPDATE_MENU_BOOL(global.fDisplayPelBorder, IDM_PELBORDER);
        !          1085:        fsCmd = CLEAR_BACKGROUND;
        !          1086:        fRedraw = TRUE;
        !          1087:        break;
        !          1088: 
        !          1089:     case IDM_ROUNDPOINTS:
        !          1090:        UPDATE_MENU_BOOL(global.fRoundControlPoints, IDM_ROUNDPOINTS);
        !          1091:        fsCmd = CLEAR_BACKGROUND;
        !          1092:        fRedraw = TRUE;
        !          1093:        break;
        !          1094: 
        !          1095:     case IDM_AUTOREDRAW:
        !          1096:        UPDATE_MENU_BOOL(global.fAutoRedraw, IDM_AUTOREDRAW);
        !          1097:        break;
        !          1098: 
        !          1099:     case IDM_NOPRIM:
        !          1100:     case IDM_POLYLINE:
        !          1101:     case IDM_POLYFILLET:
        !          1102:     case IDM_POLYSPLINE:
        !          1103:     case IDM_POINTARC:
        !          1104:        UPDATE_MENU_LIST(global.usCurPrim, id);
        !          1105:        fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
        !          1106:        fRedraw = TRUE;
        !          1107:        break;
        !          1108: 
        !          1109:     case IDM_SETCOLORS:
        !          1110:        if (WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)ColorsDlg, NULL,
        !          1111:                       IDR_COLORSDLG, NULL ))
        !          1112:        {
        !          1113:            fsCmd = CLEAR_BACKGROUND|RENDER_MATH_OBJ;
        !          1114:            fRedraw = TRUE;
        !          1115:        }
        !          1116:        break;
        !          1117: 
        !          1118:     case IDM_EDITPELCOLORS:
        !          1119:        UPDATE_MENU_BOOL(global.fEditPelColors, IDM_EDITPELCOLORS);
        !          1120:        break;
        !          1121: 
        !          1122:     case IDM_CLEARALL:
        !          1123:        global.cptl = 0L;
        !          1124:        fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
        !          1125:        fRedraw = TRUE;
        !          1126:        break;
        !          1127:     }
        !          1128: 
        !          1129:     if ((global.fAutoRedraw && fRedraw) || (id == IDM_REDRAW))
        !          1130:     {
        !          1131:        HPS hps;
        !          1132: 
        !          1133:        hps = WinGetPS(hwnd);
        !          1134:        global.usMix = FM_OVERPAINT;
        !          1135:        Paint(hps, fsCmd);
        !          1136:        WinReleasePS(hps);
        !          1137:     }
        !          1138: }
        !          1139: 
        !          1140: 
        !          1141: 
        !          1142: 
        !          1143: /************************************************************************
        !          1144: *
        !          1145: *   Paint
        !          1146: *
        !          1147: ************************************************************************/
        !          1148: 
        !          1149: VOID
        !          1150: Paint(hps, fsCmd)
        !          1151: HPS  hps;
        !          1152: USHORT fsCmd;
        !          1153: {
        !          1154:     HRGN hrgn, hrgnClipOld, hrgnT;
        !          1155: 
        !          1156: 
        !          1157:     /* Clear the unused part of the client rectangle to a hatch pattern. */
        !          1158:     if (fsCmd & CLEAR_BACKGROUND)
        !          1159:        EraseBackground(hps);
        !          1160: 
        !          1161: 
        !          1162:     /* Set up the color mode as the user has requested */
        !          1163: 
        !          1164:     if (global.fRGB)
        !          1165:     {
        !          1166:        GpiCreateLogColorTable(hps, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
        !          1167:        if (global.hpsFat)
        !          1168:        {
        !          1169:            GpiCreateLogColorTable(global.hpsFat, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
        !          1170:            GpiCreateLogColorTable(global.hpsFatShadow, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
        !          1171:        }
        !          1172:     }
        !          1173:     else
        !          1174:        if (global.hpsFat)
        !          1175:        {
        !          1176:            GpiCreateLogColorTable(global.hpsFat, LCOL_RESET, LCOLF_INDRGB, 0L, 0L, NULL);
        !          1177:            GpiCreateLogColorTable(global.hpsFatShadow, LCOL_RESET, LCOLF_INDRGB, 0L, 0L, NULL);
        !          1178:            global.clrBlackIndex = GpiQueryColorIndex(hps, 0L, 0x000000L);
        !          1179:        }
        !          1180: 
        !          1181: 
        !          1182:     if (global.usPelShape == IDD_CIRCLE)
        !          1183:     {
        !          1184:        ARCPARAMS arcp;
        !          1185: 
        !          1186:        arcp.lP = global.cxFatPel / 2L;
        !          1187:        arcp.lQ = global.cyFatPel / 2L;
        !          1188:        arcp.lR = 0L;
        !          1189:        arcp.lS = 0L;
        !          1190: 
        !          1191:        GpiSetArcParams(hps, &arcp);
        !          1192:     }
        !          1193: 
        !          1194: 
        !          1195:     /* set clipping rectangle to the fatbit surface */
        !          1196: 
        !          1197:     if ((hrgn = GpiCreateRegion(hps, 1L, &global.rcl)) != HRGN_ERROR)
        !          1198:        GpiSetClipRegion(hps, hrgn, &hrgnClipOld);
        !          1199: 
        !          1200: 
        !          1201:     if (fsCmd & CLEAR_BACKGROUND)
        !          1202:     {
        !          1203:        DrawGrid(hps);
        !          1204: 
        !          1205:        if (global.hpsFatShadow)
        !          1206:        {
        !          1207:            AREABUNDLE ab;
        !          1208: 
        !          1209:            /* clear shadow fatpel surface to background color */
        !          1210:            ab.lColor = global.clrField;
        !          1211:            GpiSetAttrs(global.hpsFatShadow, PRIM_AREA, ABB_COLOR, 0L, &ab);
        !          1212:            GpiBitBlt(global.hpsFatShadow, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
        !          1213:        }
        !          1214:     }
        !          1215: 
        !          1216:     if (global.fDisplayRenderedObj && !(fsCmd & OVERRIDE_RENDERED_OBJ))
        !          1217:        DisplayRenderedPels(hps, fsCmd);
        !          1218: 
        !          1219:     if (global.fDisplayControlPoints)
        !          1220:     {
        !          1221:        /* when rubberbanding with the rendered obj, newly drawn fatpels
        !          1222:         * can wipe out stationary control point markers, so we have to
        !          1223:         * redraw them all each time
        !          1224:         */
        !          1225: 
        !          1226:        if (global.fDisplayRenderedObj || (fsCmd & CLEAR_BACKGROUND))
        !          1227:            DisplayControlPoints(hps, global.cptl, global.pptl, global.usMix);
        !          1228:        else if (global.sPtGrabbed != NO_POINT)
        !          1229:            /* draw just the control point that moved */
        !          1230:            DisplayControlPoints(hps, 1L, global.pptl+global.sPtGrabbed, global.usMix);
        !          1231:     }
        !          1232: 
        !          1233:     if (global.fDisplayMathObj)
        !          1234:        DisplayMathematicalObject(hps, global.usMix);
        !          1235: 
        !          1236:     /* delete the clip region we set up */
        !          1237: 
        !          1238:     if (hrgnClipOld != HRGN_ERROR)
        !          1239:        GpiSetClipRegion(hps, hrgnClipOld, &hrgnT);
        !          1240:     if (hrgn != HRGN_ERROR)
        !          1241:        GpiDestroyRegion(hps, hrgn);
        !          1242: }
        !          1243: 
        !          1244: 
        !          1245: 
        !          1246: 
        !          1247: /************************************************************************
        !          1248: *
        !          1249: *   DisplayMathematicalObject
        !          1250: *
        !          1251: ************************************************************************/
        !          1252: 
        !          1253: VOID
        !          1254: DisplayMathematicalObject(hps, usMix)
        !          1255: HPS hps;
        !          1256: USHORT usMix;
        !          1257: {
        !          1258:     PPOINTL pptl;
        !          1259:     LINEBUNDLE lb;
        !          1260: 
        !          1261:     if (global.cptl > 0)
        !          1262:     {
        !          1263:        if (global.fRoundControlPoints)
        !          1264:        {
        !          1265:            RoundControlPoints(hps, global.cptl, global.pptl, global.pptlTmp,
        !          1266:                               global.cxFatPel, global.cyFatPel);
        !          1267:            pptl = global.pptlTmp;
        !          1268:        }
        !          1269:        else
        !          1270:            pptl = global.pptl;
        !          1271: 
        !          1272:        /* draw line */
        !          1273:        lb.lColor    = global.clrMathObj;
        !          1274:        lb.usMixMode = usMix;
        !          1275:        GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR|LBB_MIX_MODE, 0L, &lb);
        !          1276:        DrawPrimitive(hps, global.cptl, pptl);
        !          1277:     }
        !          1278: }
        !          1279: 
        !          1280: 
        !          1281: 
        !          1282: 
        !          1283: /************************************************************************
        !          1284: *
        !          1285: *   DisplayControlPoints
        !          1286: *
        !          1287: ************************************************************************/
        !          1288: 
        !          1289: VOID
        !          1290: DisplayControlPoints(hps, cptl, pptl, usMix)
        !          1291: HPS hps;
        !          1292: LONG cptl;
        !          1293: PPOINTL pptl;
        !          1294: USHORT usMix;
        !          1295: {
        !          1296:     PPOINTL pptlT;
        !          1297:     MARKERBUNDLE mb;
        !          1298: 
        !          1299:     if (cptl > 0)
        !          1300:     {
        !          1301:        if (global.fRoundControlPoints)
        !          1302:        {
        !          1303:            RoundControlPoints(hps, cptl, pptl, global.pptlTmp,
        !          1304:                               global.cxFatPel, global.cyFatPel);
        !          1305:            pptlT = global.pptlTmp;
        !          1306:        }
        !          1307:        else
        !          1308:            pptlT = pptl;
        !          1309: 
        !          1310: 
        !          1311:        mb.lColor    = global.clrControlPoints;
        !          1312:        mb.usMixMode = usMix;
        !          1313:        mb.usSymbol  = global.usControlPointSymbol;
        !          1314:        GpiSetAttrs(hps, PRIM_MARKER, MBB_COLOR|MBB_MIX_MODE|MBB_SYMBOL, 0L, &mb);
        !          1315: 
        !          1316:        GpiPolyMarker(hps, cptl, pptlT);
        !          1317:     }
        !          1318: }
        !          1319: 
        !          1320: 
        !          1321: 
        !          1322: 
        !          1323: /************************************************************************
        !          1324: *
        !          1325: *   EraseBackground
        !          1326: *
        !          1327: *   Erase the unused part of the window to a hatch pattern.
        !          1328: *
        !          1329: ************************************************************************/
        !          1330: 
        !          1331: VOID
        !          1332: EraseBackground(hps)
        !          1333: HPS hps;
        !          1334: {
        !          1335:     RECTL rclClient, rclT;
        !          1336:     AREABUNDLE ab;
        !          1337: 
        !          1338: 
        !          1339:     WinQueryWindowRect(global.hwnd, &rclClient);
        !          1340: 
        !          1341:     ab.lColor    = CLR_BLACK;
        !          1342:     ab.lBackColor = CLR_WHITE;
        !          1343:     ab.usSymbol   = PATSYM_DIAG1;
        !          1344:     GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR|ABB_BACK_COLOR|ABB_SYMBOL,
        !          1345:                0L, (PBUNDLE)&ab);
        !          1346: 
        !          1347:     if (global.rcl.yTop < rclClient.yTop)
        !          1348:     {
        !          1349:        rclT.xLeft   = rclClient.xLeft;
        !          1350:        rclT.yBottom = global.rcl.yBottom;
        !          1351:        rclT.xRight  = rclClient.xRight;
        !          1352:        rclT.yTop    = rclClient.yTop;
        !          1353:        GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, NULL);
        !          1354:     }
        !          1355: 
        !          1356:     if (global.rcl.xRight < rclClient.xRight)
        !          1357:     {
        !          1358:        rclT.xLeft   = global.rcl.xRight;
        !          1359:        rclT.yBottom = rclClient.yBottom;
        !          1360:        rclT.xRight  = rclClient.xRight;
        !          1361:        rclT.yTop    = global.rcl.yTop;
        !          1362:        GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, NULL);
        !          1363:     }
        !          1364: 
        !          1365:     ab.usSymbol   = PATSYM_SOLID;
        !          1366:     GpiSetAttrs(hps, PRIM_AREA, ABB_SYMBOL, 0L, (PBUNDLE)&ab);
        !          1367: }
        !          1368: 
        !          1369: 
        !          1370: 
        !          1371: 
        !          1372: /************************************************************************
        !          1373: *
        !          1374: *   DrawGrid
        !          1375: *
        !          1376: ************************************************************************/
        !          1377: 
        !          1378: VOID
        !          1379: DrawGrid(hps)
        !          1380: HPS  hps;
        !          1381: {
        !          1382:     AREABUNDLE ab;
        !          1383:     POINTL ptl;
        !          1384:     POINTL aptl[3];
        !          1385: 
        !          1386: 
        !          1387:     /* clear fatpel surface to background color */
        !          1388:     ab.lColor = global.clrInterstice;
        !          1389:     GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, &ab);
        !          1390:     GpiBitBlt(hps, NULL, 2L, (PPOINTL)&global.rcl, ROP_PATCOPY, NULL);
        !          1391: 
        !          1392: 
        !          1393:     /* draw one pel in lower left corner */
        !          1394: 
        !          1395:     ptl.x = global.cxFatPel / 2L;
        !          1396:     ptl.y = global.cyFatPel / 2L;
        !          1397:     DrawOneFatPel(hps, &ptl, global.clrField);
        !          1398: 
        !          1399: 
        !          1400:     /* blt up first column then across -- we don't have to worry
        !          1401:      * about the edges because a clip region has been setup to do that.
        !          1402:      */
        !          1403: 
        !          1404:     aptl[0].x = 0L;
        !          1405:     aptl[0].y = global.cyFatPel;
        !          1406:     aptl[1].x = global.cxFatPel;
        !          1407:     aptl[2].x = 0L;
        !          1408:     aptl[2].y = 0L;
        !          1409: 
        !          1410:     while (aptl[0].y <= global.rcl.yTop)
        !          1411:     {
        !          1412:        aptl[1].y  = aptl[0].y + aptl[0].y;
        !          1413:        GpiBitBlt(hps, hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
        !          1414:        aptl[0].y += aptl[1].y - aptl[0].y;
        !          1415:     }
        !          1416: 
        !          1417:     aptl[0].x = global.cxFatPel;
        !          1418:     aptl[0].y = 0L;
        !          1419:     aptl[1].y = global.rcl.yTop;
        !          1420:     aptl[2].x = 0L;
        !          1421:     aptl[2].y = 0L;
        !          1422: 
        !          1423:     while (aptl[0].x <= global.rcl.xRight)
        !          1424:     {
        !          1425:        aptl[1].x  = aptl[0].x + aptl[0].x;
        !          1426:        GpiBitBlt(hps, hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
        !          1427:        aptl[0].x += aptl[1].x - aptl[0].x;
        !          1428:     }
        !          1429: }
        !          1430: 
        !          1431: 
        !          1432: 
        !          1433: 
        !          1434: /************************************************************************
        !          1435: *
        !          1436: *   DisplayRenderedPels
        !          1437: *
        !          1438: ************************************************************************/
        !          1439: 
        !          1440: VOID
        !          1441: DisplayRenderedPels(hps, fsCmd)
        !          1442: HPS hps;
        !          1443: USHORT fsCmd;
        !          1444: {
        !          1445:     LINEBUNDLE lb;
        !          1446:     AREABUNDLE ab;
        !          1447:     POINTL aptl[3];
        !          1448: 
        !          1449:     /* Call GPI to draw the current primitive into the small bitmap,
        !          1450:      * then fatbit it to the display.
        !          1451:      */
        !          1452: 
        !          1453:     if (global.hbmFat)
        !          1454:     {
        !          1455:        if (fsCmd & CLEAR_FAT_BITMAP)
        !          1456:        {
        !          1457:            /* clear fatpel surface to background color */
        !          1458:            ab.lColor = global.clrField;
        !          1459:            GpiSetAttrs(global.hpsFat, PRIM_AREA, ABB_COLOR, 0L, &ab);
        !          1460:            GpiBitBlt(global.hpsFat, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
        !          1461:        }
        !          1462: 
        !          1463:        if (fsCmd & RENDER_MATH_OBJ)
        !          1464:        {
        !          1465:            if (global.cptl > 0)
        !          1466:            {
        !          1467:                /* draw line */
        !          1468:                lb.lColor = global.clrRenderedObj;
        !          1469:                GpiSetAttrs(global.hpsFat, PRIM_LINE, LBB_COLOR, 0L, &lb);
        !          1470:                GpiSetModelTransformMatrix(global.hpsFat, 9L,
        !          1471:                                          &global.matlf, TRANSFORM_REPLACE);
        !          1472:                DrawPrimitive(global.hpsFat, global.cptl, global.pptl);
        !          1473:                GpiSetModelTransformMatrix(global.hpsFat, 0L, NULL, TRANSFORM_REPLACE);
        !          1474:            }
        !          1475:        }
        !          1476: 
        !          1477:        /* xor the new rendered bitmap into the shadow bitmap */
        !          1478:        *((PRECTL)&aptl[0]) = global.rclFat;
        !          1479:        aptl[2].x = 0L;
        !          1480:        aptl[2].y = 0L;
        !          1481:        GpiBitBlt(global.hpsFatShadow, global.hpsFat, 3L, aptl, ROP_SRCINVERT, NULL);
        !          1482: 
        !          1483:        /* fatbit object to the display */
        !          1484:        DrawFatPels(hps);
        !          1485: 
        !          1486:        /* get the new shadow bitmap */
        !          1487:        GpiBitBlt(global.hpsFatShadow, global.hpsFat, 3L, aptl, ROP_SRCCOPY, NULL);
        !          1488:     }
        !          1489: }
        !          1490: 
        !          1491: 
        !          1492: 
        !          1493: 
        !          1494: /************************************************************************
        !          1495: *
        !          1496: *   DrawFatPels
        !          1497: *
        !          1498: ************************************************************************/
        !          1499: 
        !          1500: VOID
        !          1501: DrawFatPels(hps)
        !          1502: HPS hps;
        !          1503: {
        !          1504:     POINTL ptl, ptlCenter;
        !          1505:     LONG i, j;
        !          1506:     COLOR clr;
        !          1507: 
        !          1508: 
        !          1509:     /* if the pel size is 1,1, then just blt the small bitmap to the
        !          1510:      * display.
        !          1511:      */
        !          1512: 
        !          1513:     if ((global.cxFatPel == 1L) && (global.cyFatPel == 1L))
        !          1514:     {
        !          1515:        POINTL aptl[3];
        !          1516: 
        !          1517:        *((PRECTL)&aptl[0]) = global.rcl;
        !          1518:        aptl[2].x = 0L;
        !          1519:        aptl[2].y = 0L;
        !          1520:        GpiBitBlt(hps, global.hpsFat, 3L, aptl, ROP_SRCCOPY, 0L);
        !          1521: 
        !          1522:        return;
        !          1523:     }
        !          1524: 
        !          1525:     for (i = 0; i < global.rclFat.xRight; ++i)
        !          1526:        for (j = 0; j < global.rclFat.yTop; ++j)
        !          1527:        {
        !          1528:            ptl.x = i;
        !          1529:            ptl.y = j;
        !          1530: 
        !          1531:            clr = GpiQueryPel(global.hpsFatShadow, &ptl);
        !          1532:            if ((global.fRGB && (clr != 0x000000L)) ||
        !          1533:               (!global.fRGB && (clr != global.clrBlackIndex)))
        !          1534:            {
        !          1535:                clr = GpiQueryPel(global.hpsFat, &ptl);
        !          1536:                ptlCenter.x = (i * global.cxFatPel) + global.cxHalfFatPel;
        !          1537:                ptlCenter.y = (j * global.cyFatPel) + global.cyHalfFatPel;
        !          1538:                DrawOneFatPel(hps, &ptlCenter, clr);
        !          1539:            }
        !          1540:        }
        !          1541: }
        !          1542: 
        !          1543: 
        !          1544: 
        !          1545: 
        !          1546: /************************************************************************
        !          1547: *
        !          1548: *   DrawOneFatPel
        !          1549: *
        !          1550: ************************************************************************/
        !          1551: 
        !          1552: VOID
        !          1553: DrawOneFatPel(hps, pptl, clr)
        !          1554: HPS hps;
        !          1555: PPOINTL pptl;
        !          1556: COLOR clr;
        !          1557: {
        !          1558:     POINTL ptl;
        !          1559:     LINEBUNDLE lb;
        !          1560:     AREABUNDLE ab;
        !          1561: 
        !          1562: 
        !          1563:     if (global.fDisplayPelBorder || global.fDisplayCrossHairs)
        !          1564:     {
        !          1565:        lb.lColor = global.clrCrossHair;
        !          1566:        GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
        !          1567:     }
        !          1568: 
        !          1569:     ab.lColor = clr;
        !          1570:     GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, &ab);
        !          1571: 
        !          1572: 
        !          1573:     switch (global.usPelShape)
        !          1574:     {
        !          1575:     case IDD_SQUARE:
        !          1576:        {
        !          1577:            POINTL ptlT;
        !          1578:            ULONG flCmd;
        !          1579: 
        !          1580:            if (global.fDisplayPelBorder)
        !          1581:                flCmd = DRO_OUTLINEFILL;
        !          1582:            else
        !          1583:                flCmd = DRO_FILL;
        !          1584: 
        !          1585:            ptlT.x = pptl->x - global.cxHalfFatPel;
        !          1586:            ptlT.y = pptl->y - global.cyHalfFatPel;
        !          1587:            GpiSetCurrentPosition(hps, &ptlT);
        !          1588:            ptlT.x = pptl->x + global.cxHalfFatPel;
        !          1589:            ptlT.y = pptl->y + global.cyHalfFatPel;
        !          1590:            GpiBox(hps, flCmd, &ptlT, 0L, 0L);
        !          1591:        }
        !          1592:        break;
        !          1593: 
        !          1594:     case IDD_DIAMOND:
        !          1595:        {
        !          1596:            POINTL aptlT[4];
        !          1597:            ULONG flCmd;
        !          1598: 
        !          1599:            if (global.fDisplayPelBorder)
        !          1600:                flCmd = BA_BOUNDARY;
        !          1601:            else
        !          1602:                flCmd = 0L;
        !          1603: 
        !          1604:            aptlT[0].x = pptl->x;
        !          1605:            aptlT[0].y = pptl->y - global.cyHalfFatPel;
        !          1606:            aptlT[1].x = pptl->x - global.cxHalfFatPel;
        !          1607:            aptlT[1].y = pptl->y;
        !          1608:            aptlT[2].x = pptl->x;
        !          1609:            aptlT[2].y = pptl->y + global.cyHalfFatPel;
        !          1610:            aptlT[3].x = pptl->x + global.cxHalfFatPel;
        !          1611:            aptlT[3].y = pptl->y;
        !          1612: 
        !          1613:            GpiSetCurrentPosition(hps, &aptlT[3]);
        !          1614:            GpiBeginArea(hps, flCmd);
        !          1615:            GpiPolyLine(hps, 4L, aptlT);
        !          1616:            GpiEndArea(hps);
        !          1617:        }
        !          1618: 
        !          1619:        break;
        !          1620: 
        !          1621:     case IDD_CIRCLE:
        !          1622:        {
        !          1623:            ULONG flCmd;
        !          1624: 
        !          1625:            if (global.fDisplayPelBorder)
        !          1626:                flCmd = DRO_OUTLINEFILL;
        !          1627:            else
        !          1628:                flCmd = DRO_FILL;
        !          1629: 
        !          1630:            GpiSetCurrentPosition(hps, pptl);
        !          1631:            GpiFullArc(hps, flCmd, 0x10000L);
        !          1632:        }
        !          1633:        break;
        !          1634:     }
        !          1635: 
        !          1636: 
        !          1637:     if (global.fDisplayCrossHairs)
        !          1638:     {
        !          1639:        /* draw cross in center of pel */
        !          1640: 
        !          1641:        ptl.x = pptl->x - global.cxHalfFatPel;
        !          1642:        ptl.y = pptl->y;
        !          1643:        GpiSetCurrentPosition(hps, &ptl);
        !          1644:        ptl.x = pptl->x + global.cxHalfFatPel;
        !          1645:        GpiPolyLine(hps, 1L, &ptl);
        !          1646: 
        !          1647:        ptl.x = pptl->x;
        !          1648:        ptl.y = pptl->y - global.cyHalfFatPel;
        !          1649:        GpiSetCurrentPosition(hps, &ptl);
        !          1650:        ptl.y = pptl->y + global.cyHalfFatPel;
        !          1651:        GpiPolyLine(hps, 1L, &ptl);
        !          1652:     }
        !          1653: }
        !          1654: 
        !          1655: 
        !          1656: 
        !          1657: 
        !          1658: /************************************************************************
        !          1659: *
        !          1660: *   RoundControlPoints
        !          1661: *
        !          1662: ************************************************************************/
        !          1663: 
        !          1664: VOID
        !          1665: RoundControlPoints(hps, cptl, pptl1, pptl2, cx, cy)
        !          1666: HPS hps;
        !          1667: LONG cptl;
        !          1668: PPOINTL pptl1;
        !          1669: PPOINTL pptl2;
        !          1670: LONG cx;
        !          1671: LONG cy;
        !          1672: {
        !          1673:     LONG cx2, cy2;
        !          1674:     LONG i;
        !          1675:     MATRIXLF matlf;
        !          1676: 
        !          1677: 
        !          1678:     /* copy the input buffer to the output/scratch buffer */
        !          1679:     for (i = 0; i < cptl; ++i)
        !          1680:        pptl2[i] = pptl1[i];
        !          1681: 
        !          1682: 
        !          1683:     /* set the transform, transform the points to device space (i.e. to
        !          1684:      * hpsFat dimensions), then restore the original transform
        !          1685:      */
        !          1686:     GpiQueryModelTransformMatrix(hps, 9L, &matlf);
        !          1687:     GpiSetModelTransformMatrix(hps, 9L, &global.matlf, TRANSFORM_REPLACE);
        !          1688:     GpiConvert(hps, CVTC_WORLD, CVTC_DEVICE, cptl, pptl2);
        !          1689:     GpiSetModelTransformMatrix(hps, 9L, &matlf, TRANSFORM_REPLACE);
        !          1690: 
        !          1691: 
        !          1692:     /* position each point in the center of its fatpel */
        !          1693: 
        !          1694:     cx2 = cx / 2L;
        !          1695:     cy2 = cy / 2L;
        !          1696: 
        !          1697:     for (i = 0; i < cptl; ++i, ++pptl2)
        !          1698:     {
        !          1699:        pptl2->x = pptl2->x * cx + cx2;
        !          1700:        pptl2->y = pptl2->y * cy + cy2;
        !          1701:     }
        !          1702: }
        !          1703: 
        !          1704: 
        !          1705: 
        !          1706: 
        !          1707: /************************************************************************
        !          1708: *
        !          1709: *   ComputeTransform
        !          1710: *
        !          1711: ************************************************************************/
        !          1712: 
        !          1713: VOID
        !          1714: ComputeTransform(prcl1, prcl2)
        !          1715: PRECTL prcl1;
        !          1716: PRECTL prcl2;
        !          1717: {
        !          1718:     LONG xExt1, yExt1;
        !          1719:     LONG xExt2, yExt2;
        !          1720:     FIXED xScale, yScale;
        !          1721: 
        !          1722: 
        !          1723:     xExt1 = prcl1->xRight - prcl1->xLeft;
        !          1724:     yExt1 = prcl1->yTop   - prcl1->yBottom;
        !          1725:     xExt2 = prcl2->xRight - prcl2->xLeft;
        !          1726:     yExt2 = prcl2->yTop   - prcl2->yBottom;
        !          1727: 
        !          1728: 
        !          1729:     /* If the rectangles are of exactly the same dimensions, then
        !          1730:      * set the unity transform.  If not, compute the x and y scale
        !          1731:      * factors.  Note that in world coordinates rectangles are
        !          1732:      * inclusive-inclusive, whereas in device coordinates they are
        !          1733:      * inclusive-exclusive.  The extents of the destination are
        !          1734:      * therefore one pel too large as computed, so we subtract one
        !          1735:      * in the scale factor computation.
        !          1736:      */
        !          1737: 
        !          1738:     if (xExt1 == xExt2)
        !          1739:        xScale = 0x10000L;
        !          1740:     else
        !          1741:        xScale = ((xExt2-1L) * 0x10000L) / xExt1;
        !          1742: 
        !          1743:     if (yExt1 == yExt2)
        !          1744:        yScale = 0x10000L;
        !          1745:     else
        !          1746:        yScale = ((yExt2-1L) * 0x10000L) / yExt1;
        !          1747: 
        !          1748: 
        !          1749:     /* store the transform matrix for easy access */
        !          1750: 
        !          1751:     global.matlf.fxM11 = xScale;
        !          1752:     global.matlf.fxM12 = 0L;
        !          1753:     global.matlf. lM13 = 0L;
        !          1754:     global.matlf.fxM21 = 0L;
        !          1755:     global.matlf.fxM22 = yScale;
        !          1756:     global.matlf. lM23 = 0L;
        !          1757:     global.matlf. lM31 = 0L;
        !          1758:     global.matlf. lM32 = 0L;
        !          1759:     global.matlf. lM33 = 1L;
        !          1760: }
        !          1761: 
        !          1762: 
        !          1763: 
        !          1764: 
        !          1765: /************************************************************************
        !          1766: *
        !          1767: *   DrawPrimitive
        !          1768: *
        !          1769: ************************************************************************/
        !          1770: 
        !          1771: VOID
        !          1772: DrawPrimitive(hps, cptl, pptl)
        !          1773: HPS hps;
        !          1774: LONG cptl;
        !          1775: PPOINTL pptl;
        !          1776: {
        !          1777:     switch (global.usCurPrim)
        !          1778:     {
        !          1779:     case IDM_NOPRIM:
        !          1780:        break;
        !          1781: 
        !          1782:     case IDM_POLYLINE:
        !          1783:        GpiSetCurrentPosition(hps, pptl);
        !          1784:        GpiPolyLine(hps, cptl-1L, pptl + 1);
        !          1785:        break;
        !          1786: 
        !          1787:     case IDM_POLYFILLET:
        !          1788:        if (cptl >= 3L)
        !          1789:        {
        !          1790:            GpiSetCurrentPosition(hps, pptl);
        !          1791:            GpiPolyFillet(hps, cptl-1L, pptl + 1);
        !          1792:        }
        !          1793:        break;
        !          1794: 
        !          1795:     case IDM_POLYSPLINE:
        !          1796:        if (cptl >= 4L)
        !          1797:        {
        !          1798:            LONG cptSlack;    /* # points in pptl not usable by PolySpline */
        !          1799: 
        !          1800:            cptSlack = ((cptl-1L) % 3) + 1;
        !          1801:            GpiSetCurrentPosition( hps, pptl );
        !          1802:            GpiPolySpline( hps, cptl-cptSlack, pptl+1 );
        !          1803:        }
        !          1804:        break;
        !          1805: 
        !          1806:     case IDM_POINTARC:
        !          1807:        if (cptl >= 3L)
        !          1808:        {
        !          1809:            GpiSetCurrentPosition( hps, pptl );
        !          1810:            GpiPointArc( hps, pptl+1 );
        !          1811:        }
        !          1812:        break;
        !          1813:     }
        !          1814: }
        !          1815: 
        !          1816: 
        !          1817: 
        !          1818: 
        !          1819: /************************************************************************
        !          1820: *
        !          1821: *   UpdateSurfaceDims
        !          1822: *
        !          1823: ************************************************************************/
        !          1824: 
        !          1825: VOID
        !          1826: UpdateSurfaceDims()
        !          1827: {
        !          1828:     SIZEL size;
        !          1829:     BITMAPINFOHEADER bminfo;
        !          1830:     AREABUNDLE ab;
        !          1831: 
        !          1832: 
        !          1833:     WinQueryWindowRect(global.hwnd, &global.rcl);
        !          1834: 
        !          1835:     /* compute size of small surface */
        !          1836:     global.rclFat.xLeft   = 0L;
        !          1837:     global.rclFat.yBottom = 0L;
        !          1838:     global.rclFat.xRight  = global.rcl.xRight / global.cxFatPel;
        !          1839:     global.rclFat.yTop   = global.rcl.yTop   / global.cyFatPel;
        !          1840: 
        !          1841:     /* compute size of fatpel version of small surface */
        !          1842:     global.rcl.xLeft   = 0L;
        !          1843:     global.rcl.yBottom = 0L;
        !          1844:     global.rcl.xRight  = global.rclFat.xRight * global.cxFatPel;
        !          1845:     global.rcl.yTop    = global.rclFat.yTop   * global.cyFatPel;
        !          1846: 
        !          1847:     ComputeTransform(&global.rcl, &global.rclFat);
        !          1848: 
        !          1849:     if ((global.rclFat.xRight <= global.rclFatBM.xRight) &&
        !          1850:        (global.rclFat.yTop   <= global.rclFatBM.yTop))
        !          1851:        return;
        !          1852: 
        !          1853: 
        !          1854: 
        !          1855:     /* The new fatbits surface doesn't fit in the bitmap, so we
        !          1856:      * have to make a new one. If we don't have a DC or PS, make
        !          1857:      * those before making the bitmap. If we do have a bitmap,
        !          1858:      * delete it before making the new one.
        !          1859:      */
        !          1860: 
        !          1861:     global.rclFatBM = global.rclFat;
        !          1862: 
        !          1863:     if (global.hbmFat)
        !          1864:     {
        !          1865:        GpiSetBitmap(global.hpsFat, NULL);
        !          1866:        GpiDeleteBitmap(global.hbmFat);
        !          1867:        GpiSetBitmap(global.hpsFatShadow, NULL);
        !          1868:        GpiDeleteBitmap(global.hbmFatShadow);
        !          1869:     }
        !          1870: 
        !          1871:     if (!global.hdcFat)
        !          1872:     {
        !          1873:        global.hdcFat = DevOpenDC(global.hab, OD_MEMORY, "*", 0L, NULL, NULL);
        !          1874:        if (!global.hdcFat)
        !          1875:            goto usd_error;
        !          1876: 
        !          1877:        global.hdcFatShadow = DevOpenDC(global.hab, OD_MEMORY, "*", 0L, NULL, NULL);
        !          1878:        if (!global.hdcFatShadow)
        !          1879:            goto usd_error;
        !          1880:     }
        !          1881: 
        !          1882:     if (!global.hpsFat)
        !          1883:     {
        !          1884:        size.cx = 0L;
        !          1885:        size.cy = 0L;
        !          1886:        global.hpsFat = GpiCreatePS(global.hab, global.hdcFat, &size,
        !          1887:                                 PU_PELS|GPIT_MICRO|GPIA_ASSOC);
        !          1888:        if (!global.hpsFat)
        !          1889:            goto usd_error;
        !          1890: 
        !          1891:        global.hpsFatShadow = GpiCreatePS(global.hab, global.hdcFatShadow, &size,
        !          1892:                                 PU_PELS|GPIT_MICRO|GPIA_ASSOC);
        !          1893:        if (!global.hpsFatShadow)
        !          1894:            goto usd_error;
        !          1895:     }
        !          1896: 
        !          1897:     /* create bitmap with maximum color resolution (24-bit color) */
        !          1898:     bminfo.cbFix = sizeof(BITMAPINFOHEADER);
        !          1899:     bminfo.cx = (USHORT) (global.rclFatBM.xRight - global.rclFatBM.xLeft);
        !          1900:     bminfo.cy = (USHORT) (global.rclFatBM.yTop  - global.rclFatBM.yBottom);
        !          1901:     bminfo.cPlanes   = 1L;
        !          1902:     bminfo.cBitCount = 24L;
        !          1903:     global.hbmFat = GpiCreateBitmap(global.hpsFat, &bminfo, 0L, 0L, 0L);
        !          1904:     if (!global.hbmFat)
        !          1905:        goto usd_error;
        !          1906:     GpiSetBitmap(global.hpsFat, global.hbmFat);
        !          1907: 
        !          1908:     /* create a shadow bitmap of the one we just created */
        !          1909:     bminfo.cbFix = sizeof(BITMAPINFOHEADER);
        !          1910:     bminfo.cx = (USHORT) (global.rclFatBM.xRight - global.rclFatBM.xLeft);
        !          1911:     bminfo.cy = (USHORT) (global.rclFatBM.yTop  - global.rclFatBM.yBottom);
        !          1912:     bminfo.cPlanes   = 1L;
        !          1913:     bminfo.cBitCount = 24L;
        !          1914:     global.hbmFatShadow = GpiCreateBitmap(global.hpsFatShadow, &bminfo, 0L, 0L, 0L);
        !          1915:     if (!global.hbmFat)
        !          1916:        goto usd_error;
        !          1917:     GpiSetBitmap(global.hpsFatShadow, global.hbmFatShadow);
        !          1918: 
        !          1919:     /* clear bitmap surface to field color */
        !          1920:     ab.lColor = global.clrField;
        !          1921:     GpiSetAttrs(global.hpsFat, PRIM_AREA, ABB_COLOR, 0L, &ab);
        !          1922:     GpiBitBlt(global.hpsFat, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
        !          1923: 
        !          1924:     return;
        !          1925: 
        !          1926: 
        !          1927: /* error exit point */
        !          1928: 
        !          1929: usd_error:
        !          1930:     if (global.hpsFat)
        !          1931:        GpiDestroyPS(global.hpsFat);
        !          1932:     if (global.hpsFatShadow)
        !          1933:        GpiDestroyPS(global.hpsFatShadow);
        !          1934:     if (global.hdcFat)
        !          1935:        DevCloseDC(global.hdcFat);
        !          1936:     if (global.hdcFatShadow)
        !          1937:        DevCloseDC(global.hdcFatShadow);
        !          1938: 
        !          1939:     global.hpsFat      = NULL;
        !          1940:     global.hdcFat      = NULL;
        !          1941:     global.hpsFatShadow = NULL;
        !          1942:     global.hdcFatShadow = NULL;
        !          1943: }
        !          1944: 
        !          1945: 
        !          1946: 
        !          1947: 
        !          1948: /************************************************************************
        !          1949: *
        !          1950: *   AboutDlg
        !          1951: *
        !          1952: *   Process messages for the About box.
        !          1953: *
        !          1954: ************************************************************************/
        !          1955: 
        !          1956: ULONG CALLBACK
        !          1957: AboutDlg(hwnd, usMsg, mp1, mp2)
        !          1958: HWND   hwnd;
        !          1959: USHORT usMsg;
        !          1960: MPARAM mp1;
        !          1961: MPARAM mp2;
        !          1962: {
        !          1963:     switch (usMsg)
        !          1964:     {
        !          1965:     case WM_COMMAND:
        !          1966:        if (SHORT1FROMMP(mp1) == DID_OK)
        !          1967:            WinDismissDlg(hwnd, TRUE);
        !          1968:        else
        !          1969:            return FALSE;
        !          1970:        break;
        !          1971: 
        !          1972:     default:
        !          1973:        return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
        !          1974:     }
        !          1975:     return FALSE;
        !          1976: }
        !          1977: 
        !          1978: 
        !          1979: 
        !          1980: 
        !          1981: /************************************************************************
        !          1982: *
        !          1983: *   PelSizeDlg
        !          1984: *
        !          1985: *   Process messages for the Pel Size dialog box.
        !          1986: *
        !          1987: ************************************************************************/
        !          1988: 
        !          1989: ULONG CALLBACK
        !          1990: PelSizeDlg(hwnd, usMsg, mp1, mp2)
        !          1991: HWND   hwnd;
        !          1992: USHORT usMsg;
        !          1993: MPARAM mp1;
        !          1994: MPARAM mp2;
        !          1995: {
        !          1996:     BOOL fRet = FALSE;
        !          1997: 
        !          1998:     switch (usMsg)
        !          1999:     {
        !          2000:     case WM_INITDLG:
        !          2001:        MySetWindowLong(hwnd, IDD_PELWIDTH,  global.cxFatPel);
        !          2002:        MySetWindowLong(hwnd, IDD_PELHEIGHT, global.cyFatPel);
        !          2003:        WinSendDlgItemMsg(hwnd, global.usPelShape,
        !          2004:                          BM_SETCHECK, (MPARAM)TRUE, 0L);
        !          2005:        return FALSE;
        !          2006:        break;
        !          2007: 
        !          2008:     case WM_COMMAND:
        !          2009:        switch (SHORT1FROMMP(mp1))
        !          2010:        {
        !          2011:        case IDD_OK:
        !          2012:            global.cxFatPel = MyGetWindowLong(hwnd, IDD_PELWIDTH);
        !          2013:            global.cyFatPel = MyGetWindowLong(hwnd, IDD_PELHEIGHT);
        !          2014: 
        !          2015:            if (global.cxFatPel < 1L)
        !          2016:                global.cxFatPel = 1L;
        !          2017: 
        !          2018:            if (global.cyFatPel < 1L)
        !          2019:                global.cyFatPel = 1L;
        !          2020: 
        !          2021:            global.cxHalfFatPel = global.cxFatPel / 2L;
        !          2022:            global.cyHalfFatPel = global.cyFatPel / 2L;
        !          2023: 
        !          2024:            global.usPelShape = (USHORT) WinSendDlgItemMsg(hwnd, IDD_SQUARE,
        !          2025:                                   BM_QUERYCHECKINDEX, 0L, 0L) + IDD_SQUARE;
        !          2026: 
        !          2027: 
        !          2028:            UpdateSurfaceDims();
        !          2029: 
        !          2030:            fRet = TRUE;
        !          2031: 
        !          2032:            /* fall through to some common code */
        !          2033: 
        !          2034:        case IDD_CANCEL:
        !          2035:            WinDismissDlg(hwnd, fRet);
        !          2036:            break;
        !          2037: 
        !          2038:        default:
        !          2039:            return FALSE;
        !          2040:        }
        !          2041:        break;
        !          2042: 
        !          2043:     default:
        !          2044:        return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
        !          2045:     }
        !          2046:     return FALSE;
        !          2047: }
        !          2048: 
        !          2049: 
        !          2050: 
        !          2051: 
        !          2052: /************************************************************************
        !          2053: *
        !          2054: *   ColorsDlg
        !          2055: *
        !          2056: *   Process messages for the Set Colors dialog box.
        !          2057: *
        !          2058: ************************************************************************/
        !          2059: 
        !          2060: ULONG CALLBACK
        !          2061: ColorsDlg(hwnd, usMsg, mp1, mp2)
        !          2062: HWND   hwnd;
        !          2063: USHORT usMsg;
        !          2064: MPARAM mp1;
        !          2065: MPARAM mp2;
        !          2066: {
        !          2067:     BOOL fRet = FALSE;
        !          2068:     BOOL fRGB;
        !          2069:     COLOR clrMathObj;
        !          2070:     COLOR clrRenderedObj;
        !          2071:     COLOR clrField;
        !          2072:     COLOR clrCrossHair;
        !          2073:     COLOR clrInterstice;
        !          2074:     COLOR clrControlPoints;
        !          2075: 
        !          2076:     switch (usMsg)
        !          2077:     {
        !          2078:     case WM_INITDLG:
        !          2079:        if (global.fRGB)
        !          2080:        {
        !          2081:            MySetWindowLongHex(hwnd, IDD_MATHOBJ,     global.clrMathObj);
        !          2082:            MySetWindowLongHex(hwnd, IDD_RENDEREDOBJ, global.clrRenderedObj);
        !          2083:            MySetWindowLongHex(hwnd, IDD_FIELD,      global.clrField);
        !          2084:            MySetWindowLongHex(hwnd, IDD_CROSSHAIRS,  global.clrCrossHair);
        !          2085:            MySetWindowLongHex(hwnd, IDD_INTERSTICE,  global.clrInterstice);
        !          2086:            MySetWindowLongHex(hwnd, IDD_CTLPOINTS,   global.clrControlPoints);
        !          2087:        }
        !          2088:        else
        !          2089:        {
        !          2090:            MySetWindowLong   (hwnd, IDD_MATHOBJ,     global.clrMathObj);
        !          2091:            MySetWindowLong   (hwnd, IDD_RENDEREDOBJ, global.clrRenderedObj);
        !          2092:            MySetWindowLong   (hwnd, IDD_FIELD,      global.clrField);
        !          2093:            MySetWindowLong   (hwnd, IDD_CROSSHAIRS,  global.clrCrossHair);
        !          2094:            MySetWindowLong   (hwnd, IDD_INTERSTICE,  global.clrInterstice);
        !          2095:            MySetWindowLong   (hwnd, IDD_CTLPOINTS,   global.clrControlPoints);
        !          2096:        }
        !          2097:        WinSendDlgItemMsg(hwnd, IDD_RGB, BM_SETCHECK, MPFROM2SHORT(global.fRGB,0), 0L);
        !          2098:        return FALSE;
        !          2099:        break;
        !          2100: 
        !          2101:     case WM_CONTROL:
        !          2102:        if ((SHORT1FROMMP(mp1) == IDD_RGB) && (SHORT2FROMMP(mp1)== BN_CLICKED))
        !          2103:        {
        !          2104:            fRGB = !(SHORT)WinSendDlgItemMsg(hwnd, IDD_RGB, BM_QUERYCHECK, 0L, 0L);
        !          2105:            WinSendDlgItemMsg(hwnd, IDD_RGB, BM_SETCHECK, MPFROM2SHORT(fRGB,0), 0L);
        !          2106: 
        !          2107:            clrMathObj       = MyGetWindowLong(hwnd, IDD_MATHOBJ);
        !          2108:            clrRenderedObj   = MyGetWindowLong(hwnd, IDD_RENDEREDOBJ);
        !          2109:            clrField         = MyGetWindowLong(hwnd, IDD_FIELD);
        !          2110:            clrCrossHair     = MyGetWindowLong(hwnd, IDD_CROSSHAIRS);
        !          2111:            clrInterstice    = MyGetWindowLong(hwnd, IDD_INTERSTICE);
        !          2112:            clrControlPoints = MyGetWindowLong(hwnd, IDD_CTLPOINTS);
        !          2113: 
        !          2114:            if (fRGB)
        !          2115:            {
        !          2116:                HPS hps;
        !          2117: 
        !          2118:                /* for each color, get rgb value from index */
        !          2119: 
        !          2120:                hps = WinGetPS(hwnd);
        !          2121: 
        !          2122:                clrMathObj       = GpiQueryRGBColor(hps, 0L, clrMathObj);
        !          2123:                clrRenderedObj   = GpiQueryRGBColor(hps, 0L, clrRenderedObj);
        !          2124:                clrField         = GpiQueryRGBColor(hps, 0L, clrField);
        !          2125:                clrCrossHair     = GpiQueryRGBColor(hps, 0L, clrCrossHair);
        !          2126:                clrInterstice    = GpiQueryRGBColor(hps, 0L, clrInterstice);
        !          2127:                clrControlPoints = GpiQueryRGBColor(hps, 0L, clrControlPoints);
        !          2128: 
        !          2129:                WinReleasePS(hps);
        !          2130: 
        !          2131:                MySetWindowLongHex(hwnd, IDD_MATHOBJ,    clrMathObj);
        !          2132:                MySetWindowLongHex(hwnd, IDD_RENDEREDOBJ, clrRenderedObj);
        !          2133:                MySetWindowLongHex(hwnd, IDD_FIELD,      clrField);
        !          2134:                MySetWindowLongHex(hwnd, IDD_CROSSHAIRS,  clrCrossHair);
        !          2135:                MySetWindowLongHex(hwnd, IDD_INTERSTICE,  clrInterstice);
        !          2136:                MySetWindowLongHex(hwnd, IDD_CTLPOINTS,  clrControlPoints);
        !          2137:            }
        !          2138:            else
        !          2139:            {
        !          2140:                HPS hps;
        !          2141: 
        !          2142:                /* for each color, get nearest index value from rgb */
        !          2143: 
        !          2144:                hps = WinGetPS(hwnd);
        !          2145: 
        !          2146:                clrMathObj       = GpiQueryColorIndex(hps, 0L, clrMathObj);
        !          2147:                clrRenderedObj   = GpiQueryColorIndex(hps, 0L, clrRenderedObj);
        !          2148:                clrField         = GpiQueryColorIndex(hps, 0L, clrField);
        !          2149:                clrCrossHair     = GpiQueryColorIndex(hps, 0L, clrCrossHair);
        !          2150:                clrInterstice    = GpiQueryColorIndex(hps, 0L, clrInterstice);
        !          2151:                clrControlPoints = GpiQueryColorIndex(hps, 0L, clrControlPoints);
        !          2152: 
        !          2153:                WinReleasePS(hps);
        !          2154: 
        !          2155:                MySetWindowLong   (hwnd, IDD_MATHOBJ,    clrMathObj);
        !          2156:                MySetWindowLong   (hwnd, IDD_RENDEREDOBJ, clrRenderedObj);
        !          2157:                MySetWindowLong   (hwnd, IDD_FIELD,      clrField);
        !          2158:                MySetWindowLong   (hwnd, IDD_CROSSHAIRS,  clrCrossHair);
        !          2159:                MySetWindowLong   (hwnd, IDD_INTERSTICE,  clrInterstice);
        !          2160:                MySetWindowLong   (hwnd, IDD_CTLPOINTS,  clrControlPoints);
        !          2161:            }
        !          2162:        }
        !          2163:        return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
        !          2164:        break;
        !          2165: 
        !          2166:     case WM_COMMAND:
        !          2167:        switch (SHORT1FROMMP(mp1))
        !          2168:        {
        !          2169:        case IDD_OK:
        !          2170:            global.clrMathObj       = MyGetWindowLong(hwnd, IDD_MATHOBJ);
        !          2171:            global.clrRenderedObj   = MyGetWindowLong(hwnd, IDD_RENDEREDOBJ);
        !          2172:            global.clrField         = MyGetWindowLong(hwnd, IDD_FIELD);
        !          2173:            global.clrCrossHair     = MyGetWindowLong(hwnd, IDD_CROSSHAIRS);
        !          2174:            global.clrInterstice    = MyGetWindowLong(hwnd, IDD_INTERSTICE);
        !          2175:            global.clrControlPoints = MyGetWindowLong(hwnd, IDD_CTLPOINTS);
        !          2176: 
        !          2177:            global.fRGB = (SHORT)WinSendDlgItemMsg(hwnd, IDD_RGB, BM_QUERYCHECK, 0L, 0L);
        !          2178: 
        !          2179:            fRet = TRUE;
        !          2180: 
        !          2181:            /* fall through to some common code */
        !          2182: 
        !          2183:        case IDD_CANCEL:
        !          2184:            WinDismissDlg(hwnd, fRet);
        !          2185:            break;
        !          2186: 
        !          2187:        default:
        !          2188:            return FALSE;
        !          2189:        }
        !          2190:        break;
        !          2191: 
        !          2192:     default:
        !          2193:        return (ULONG) WinDefDlgProc(hwnd, usMsg, mp1, mp2);
        !          2194:     }
        !          2195:     return FALSE;
        !          2196: }
        !          2197: 
        !          2198: 
        !          2199: 
        !          2200: 
        !          2201: /************************************************************************
        !          2202: *
        !          2203: *   MySetWindowLong
        !          2204: *
        !          2205: *   Sets the given control id to the value specified.
        !          2206: *
        !          2207: ************************************************************************/
        !          2208: 
        !          2209: VOID
        !          2210: MySetWindowLong(hWnd, id, num)
        !          2211: HWND hWnd;
        !          2212: USHORT id;
        !          2213: LONG num;
        !          2214: {
        !          2215:     char szStr[CCHSTR];
        !          2216: 
        !          2217:     sprintf((NPCH)szStr, "%ld", num);
        !          2218:     WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
        !          2219: }
        !          2220: 
        !          2221: 
        !          2222: 
        !          2223: 
        !          2224: /************************************************************************
        !          2225: *
        !          2226: *   MySetWindowLongHex
        !          2227: *
        !          2228: *   Sets the given control id to the value specified, in hexadecimal
        !          2229: *   notation.
        !          2230: *
        !          2231: ************************************************************************/
        !          2232: 
        !          2233: VOID
        !          2234: MySetWindowLongHex(hWnd, id, num)
        !          2235: HWND hWnd;
        !          2236: USHORT id;
        !          2237: LONG num;
        !          2238: {
        !          2239:     char szStr[CCHSTR];
        !          2240: 
        !          2241:     sprintf((NPCH)szStr, "0x%06lX", num);
        !          2242:     WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
        !          2243: }
        !          2244: 
        !          2245: 
        !          2246: 
        !          2247: 
        !          2248: /************************************************************************
        !          2249: *
        !          2250: *   MyGetWindowLong
        !          2251: *
        !          2252: *   Returns the value from the given control id.
        !          2253: *
        !          2254: ************************************************************************/
        !          2255: 
        !          2256: LONG
        !          2257: MyGetWindowLong(hWnd, id)
        !          2258: HWND hWnd;
        !          2259: USHORT id;
        !          2260: {
        !          2261:     char szStr[CCHSTR];
        !          2262:     LONG num;
        !          2263: 
        !          2264:     WinQueryWindowText(WinWindowFromID(hWnd, id), CCHSTR, (PCH)szStr);
        !          2265: 
        !          2266:     if (strchr(szStr, 'x'))
        !          2267:        sscanf((NPCH)szStr, "0x%lx", &num);
        !          2268:     else if (strchr(szStr, 'X'))
        !          2269:        sscanf((NPCH)szStr, "0X%lx", &num);
        !          2270:     else
        !          2271:        sscanf((NPCH)szStr, "%ld", &num);
        !          2272: 
        !          2273:     return num;
        !          2274: }
        !          2275: 
        !          2276: 
        !          2277: 
        !          2278: 
        !          2279: /************************************************************************
        !          2280: *
        !          2281: *   SaveWindowToFile
        !          2282: *
        !          2283: *   Copy the bits from the client rectangle (actually, just the fatpel
        !          2284: *   area) into a bitmap, then save that bitmap.
        !          2285: *
        !          2286: ************************************************************************/
        !          2287: 
        !          2288: VOID
        !          2289: SaveWindowToFile(hwnd)
        !          2290: HWND hwnd;
        !          2291: {
        !          2292:     BITMAPINFOHEADER bminfo;
        !          2293:     HBITMAP hbm;
        !          2294:     HPS hps;
        !          2295:     POINTL aptl[3];
        !          2296: 
        !          2297:     /* create bitmap in display's favorite format */
        !          2298:     bminfo.cbFix = sizeof(BITMAPINFOHEADER);
        !          2299:     bminfo.cx = (USHORT) (global.rcl.xRight - global.rcl.xLeft);
        !          2300:     bminfo.cy = (USHORT) (global.rcl.yTop   - global.rcl.yBottom);
        !          2301:     bminfo.cPlanes   = 0L;
        !          2302:     bminfo.cBitCount = 0L;
        !          2303:     if (hbm = GpiCreateBitmap(global.hpsFat, &bminfo, 0L, 0L, 0L))
        !          2304:     {
        !          2305:        /* select it into the small bitmap's PS */
        !          2306:        GpiSetBitmap(global.hpsFat, hbm);
        !          2307: 
        !          2308:        /* GpiBitBlt from the window to the bitmap */
        !          2309:        hps = WinGetPS(hwnd);
        !          2310: 
        !          2311:        *((PRECTL)&aptl[0]) = global.rcl;
        !          2312:        aptl[2].x = 0L;
        !          2313:        aptl[2].y = 0L;
        !          2314:        GpiBitBlt(global.hpsFat, hps, 3L, aptl, ROP_SRCCOPY, 0L);
        !          2315: 
        !          2316:        WinReleasePS(hps);
        !          2317: 
        !          2318:        /* save the bitmap */
        !          2319:        WriteFile(hwnd, global.hpsFat);
        !          2320:     }
        !          2321: 
        !          2322:     /* deselect the bitmap and delete it */
        !          2323:     GpiSetBitmap(global.hpsFat, global.hbmFat);
        !          2324:     if (hbm)
        !          2325:        GpiDeleteBitmap(hbm);
        !          2326: }
        !          2327: 
        !          2328: 
        !          2329: 
        !          2330: 
        !          2331: /************************************************************************
        !          2332: *
        !          2333: *   WriteFile
        !          2334: *
        !          2335: *   Calls the OpenDlg's DlgFile function to ask the user what file name to
        !          2336: *   save under.
        !          2337: *
        !          2338: ************************************************************************/
        !          2339: 
        !          2340: VOID
        !          2341: WriteFile(hwnd, hps)
        !          2342: HWND hwnd;
        !          2343: HPS hps;
        !          2344: {
        !          2345:     HFILE hfile;
        !          2346:     DLF dlf;
        !          2347:     BITMAPINFOHEADER bmih;
        !          2348: 
        !          2349:     dlf.rgbAction      = DLG_SAVEDLG;
        !          2350:     dlf.rgbFlags       = 0;
        !          2351:     dlf.phFile         = &hfile;
        !          2352:     dlf.pszExt         = "";
        !          2353:     dlf.pszAppName     = "FatPel";
        !          2354:     dlf.pszInstructions = NULL;
        !          2355:     dlf.szFileName[0]  = '\0';
        !          2356:     dlf.szOpenFile[0]  = '\0';
        !          2357:     dlf.pszTitle       = "Save Bitmap";
        !          2358: 
        !          2359: 
        !          2360:     switch (DlgFile(hwnd,&dlf))
        !          2361:     {
        !          2362:     case TDF_ERRMEM:
        !          2363:     case TDF_INVALID:
        !          2364:        MyMessageBox(hwnd, "Error opening file.");
        !          2365:        break;
        !          2366: 
        !          2367:     case TDF_NOSAVE:
        !          2368:        break;
        !          2369: 
        !          2370:     default:
        !          2371:        bmih.cbFix     = sizeof(BITMAPINFOHEADER);
        !          2372:        bmih.cx        = (USHORT) global.rcl.xRight;
        !          2373:        bmih.cy        = (USHORT) global.rcl.yTop;
        !          2374:        bmih.cPlanes   = 0L;
        !          2375:        bmih.cBitCount = 0L;
        !          2376: 
        !          2377:        if (!WriteBMP(hfile, hps, &bmih))
        !          2378:            MyMessageBox(hwnd, "Error writing file.");
        !          2379:     }
        !          2380: }
        !          2381: 
        !          2382: 
        !          2383: 
        !          2384: 
        !          2385: /************************************************************************
        !          2386: *
        !          2387: *   WriteBMP
        !          2388: *
        !          2389: *   Write the bitmap out to a BMP format file. Write the file
        !          2390: *   header first, then the bitmap bits.  Space for the header
        !          2391: *   and the bits is allocated. Huge bitmaps are supported.
        !          2392: *   Free up memory and close the file before leaving.  The file
        !          2393: *   will have been opened by the time this function is called,
        !          2394: *   and the file handle will be in the *pdlf structure.
        !          2395: *
        !          2396: ************************************************************************/
        !          2397: 
        !          2398: BOOL
        !          2399: WriteBMP(hfile, hps, pbmih)
        !          2400: HFILE hfile;
        !          2401: HPS hps;                /* hps from which to get bitmap bits.     */
        !          2402: PBITMAPINFOHEADER pbmih; /* Bitmap information.                   */
        !          2403: {
        !          2404:     ULONG cScans;
        !          2405:     ULONG ulSize;       /* Number of bytes occupied by bitmap bits.         */
        !          2406:     USHORT cSegs;       /* Number of 64K segments in ulSize.                */
        !          2407:     USHORT cbExtra;     /* Bytes in last segment of ulSize.                 */
        !          2408:     SEL selBits;        /* Base selector to bitmap bits.                    */
        !          2409:     USHORT hugeshift;   /* Segment index shift value.                       */
        !          2410:     USHORT cbBMHdr;     /* Size of bitmap header.                           */
        !          2411:     PBITMAPFILEHEADER pbfh; /* Pointer to private copy of bitmap info data.    */
        !          2412:     USHORT cbWrite1;    /* Number of bytes to write first call to DosWrite  */
        !          2413:     USHORT cbWrite2;    /* Number of bytes to write second call to DosWrite */
        !          2414:     USHORT cbWritten;   /* Number of bytes written by DosWrite.             */
        !          2415:     BOOL fRet = FALSE;  /* Function return code.                            */
        !          2416:     int i;              /* Generic loop index.                              */
        !          2417:     struct
        !          2418:     {
        !          2419:        LONG cPlanes;
        !          2420:        LONG cBitCount;
        !          2421:     } bmFmt;
        !          2422: 
        !          2423: 
        !          2424:     /*******************************************************************
        !          2425:     * If the bitmap was created with either 0 planes or 0 bits per
        !          2426:     * pixel, then query the format to write with.  By asking for just
        !          2427:     * one format (two LONGs, or one instance of structure of bmFmt),
        !          2428:     * we'll get the device's favored format.
        !          2429:     *******************************************************************/
        !          2430: 
        !          2431:     if ((pbmih->cPlanes == 0) || (pbmih->cBitCount == 0))
        !          2432:     {
        !          2433:        if (!GpiQueryDeviceBitmapFormats(hps, 2L, (PLONG)&bmFmt))
        !          2434:            goto lfwrite_error_close_file;
        !          2435:     }
        !          2436:     else
        !          2437:     {
        !          2438:        bmFmt.cPlanes   = pbmih->cPlanes;
        !          2439:        bmFmt.cBitCount = pbmih->cBitCount;
        !          2440:     }
        !          2441: 
        !          2442: 
        !          2443:     /*******************************************************************
        !          2444:     * Determine size of bitmap header. The header consists of a
        !          2445:     * a fixed-size part and a variable-length color table.  The
        !          2446:     * latter has  2^cBitCount  entries, each of which is sizeof(RGB)
        !          2447:     * bytes long.  The exception is when cBitCount is 24, in which
        !          2448:     * case the color table is omitted because the pixels are direct
        !          2449:     * rgb values.
        !          2450:     *******************************************************************/
        !          2451: 
        !          2452:     i = (int) bmFmt.cBitCount;
        !          2453:     if (i == 24)
        !          2454:        cbBMHdr = 0;
        !          2455:     else
        !          2456:        for (cbBMHdr = sizeof(RGB); i > 0; --i)
        !          2457:            cbBMHdr *= 2;
        !          2458:     cbBMHdr += sizeof(BITMAPFILEHEADER);
        !          2459: 
        !          2460: 
        !          2461:     /*******************************************************************
        !          2462:     * Copy structure from input to work buffer.  The call to
        !          2463:     * GpiQueryBitmapBits will have write-access to this, so we won't
        !          2464:     * let it have the user's data.
        !          2465:     *******************************************************************/
        !          2466: 
        !          2467:     pbfh = 0;
        !          2468:     if (DosAllocSeg(cbBMHdr, ((PUSHORT)&pbfh)+1, 0))
        !          2469:        goto lfwrite_error_close_file;
        !          2470:     pbfh->bmp = *pbmih;
        !          2471:     if ((pbmih->cPlanes == 0) || (pbmih->cBitCount))
        !          2472:     {
        !          2473:        pbfh->bmp.cPlanes   = (USHORT) bmFmt.cPlanes;
        !          2474:        pbfh->bmp.cBitCount = (USHORT) bmFmt.cBitCount;
        !          2475:     }
        !          2476: 
        !          2477: 
        !          2478:     /*******************************************************************
        !          2479:     * Allocate space for the bitmap bits -- all of them at once.
        !          2480:     * The extra ULONG casts are there to force all the arithmetic
        !          2481:     * to be done in 32 bits.
        !          2482:     *******************************************************************/
        !          2483: 
        !          2484:     ulSize = (
        !          2485:               (
        !          2486:                 (
        !          2487:                   (ULONG)pbfh->bmp.cBitCount
        !          2488:                   * (ULONG)pbfh->bmp.cx
        !          2489:                   + 31L
        !          2490:                 ) / 32L
        !          2491:               ) * (ULONG)pbfh->bmp.cPlanes * 4L
        !          2492:             ) * (ULONG)pbfh->bmp.cy;
        !          2493: 
        !          2494:     cSegs   = (USHORT)(ulSize/0x10000L);
        !          2495:     cbExtra = (USHORT)(ulSize%0x10000L);
        !          2496:     if (DosAllocHuge(cSegs, cbExtra, (PSEL)&selBits, 0, 0))
        !          2497:        goto lfwrite_error_free_header;
        !          2498:     if (DosGetHugeShift(&hugeshift))
        !          2499:        goto lfwrite_error_free_bits;
        !          2500: 
        !          2501: 
        !          2502:     /*******************************************************************
        !          2503:     * Tell GPI to give us the bits. The function returns the number
        !          2504:     * of scan lines of the bitmap that were copied.  We want all of
        !          2505:     * them at once.
        !          2506:     *******************************************************************/
        !          2507: 
        !          2508:     cScans = GpiQueryBitmapBits( hps
        !          2509:                               , 0L
        !          2510:                               , (ULONG)pbfh->bmp.cy
        !          2511:                               , (PBYTE)MAKEP(selBits, 0)
        !          2512:                               , (PBITMAPINFO)&pbfh->bmp);
        !          2513:     if (cScans != pbfh->bmp.cy)  /* compare with original number of scans */
        !          2514:        goto lfwrite_error_free_bits;
        !          2515: 
        !          2516: 
        !          2517:     /*******************************************************************
        !          2518:     * Fill in the extra header fields and write the header out to
        !          2519:     * the file.
        !          2520:     *******************************************************************/
        !          2521: 
        !          2522:     pbfh->usType    = 0x4D42;            /* 'MB' */
        !          2523:     pbfh->cbSize    = ulSize + cbBMHdr;
        !          2524:     pbfh->xHotspot  = pbfh->bmp.cx / 2;
        !          2525:     pbfh->yHotspot  = pbfh->bmp.cy / 2;
        !          2526:     pbfh->offBits   = cbBMHdr;
        !          2527: 
        !          2528:     if (DosWrite( hfile
        !          2529:                , (PVOID)pbfh
        !          2530:                , cbBMHdr
        !          2531:                , &cbWritten))
        !          2532:        goto lfwrite_error_free_bits;
        !          2533:     if (cbWritten != cbBMHdr)
        !          2534:        goto lfwrite_error_free_bits;
        !          2535: 
        !          2536: 
        !          2537:     /*******************************************************************
        !          2538:     * Write the bits out to the file. The DosWrite function allows a
        !          2539:     * maximum of 64K-1 bytes written at a time.  We get around this
        !          2540:     * by writing two 32K chunks for each 64K segment, and writing the
        !          2541:     * last segment in one piece.
        !          2542:     *******************************************************************/
        !          2543: 
        !          2544:     for (i = 0; i <= cSegs; ++i)
        !          2545:     {
        !          2546:        if (i < cSegs)
        !          2547:        {
        !          2548:            /* This segment is 64K bytes long, so split it up. */
        !          2549:            cbWrite1 = 0x8000;
        !          2550:            cbWrite2 = 0x8000;
        !          2551:        }
        !          2552:        else
        !          2553:        {
        !          2554:            /* This segment is less than 64K bytes long, so write it all. */
        !          2555:            cbWrite1 = cbExtra;
        !          2556:            cbWrite2 = 0;
        !          2557:        }
        !          2558: 
        !          2559:        /* There's a possibility that cbExtra will be 0, so check
        !          2560:         * to avoid an unnecessary system call.
        !          2561:         */
        !          2562:        if (cbWrite1 > 0)
        !          2563:        {
        !          2564:            if (DosWrite( hfile
        !          2565:                        , (PVOID)MAKEP(selBits+(i<<hugeshift), 0)
        !          2566:                        , cbWrite1
        !          2567:                        , &cbWritten))
        !          2568:                goto lfwrite_error_free_bits;
        !          2569:            if (cbWrite1 != cbWritten)
        !          2570:                goto lfwrite_error_free_bits;
        !          2571:        }
        !          2572: 
        !          2573:        /* This will always be skipped on the last partial segment. */
        !          2574:        if (cbWrite2 > 0)
        !          2575:        {
        !          2576:            if (DosWrite( hfile
        !          2577:                        , (PVOID)MAKEP(selBits+(i<<hugeshift), cbWrite1)
        !          2578:                        , cbWrite2
        !          2579:                        , &cbWritten))
        !          2580:                goto lfwrite_error_free_bits;
        !          2581:            if (cbWrite2 != cbWritten)
        !          2582:                goto lfwrite_error_free_bits;
        !          2583:        }
        !          2584:     }
        !          2585: 
        !          2586:     fRet = TRUE;     /* The bits are on the disk. */
        !          2587: 
        !          2588: 
        !          2589:     /*******************************************************************
        !          2590:     * Close the file, free the buffer space and leave. This is a
        !          2591:     * common exit point from the function.  Since the same cleanup
        !          2592:     * operations need to be performed for such a large number of
        !          2593:     * possible error conditions, this is concise way to do the right
        !          2594:     * thing.
        !          2595:     *******************************************************************/
        !          2596: 
        !          2597: lfwrite_error_free_bits:
        !          2598:     DosFreeSeg(selBits);
        !          2599: lfwrite_error_free_header:
        !          2600:     DosFreeSeg(*((PUSHORT)&pbfh+1));
        !          2601: lfwrite_error_close_file:
        !          2602:     DosClose(hfile);
        !          2603:     return fRet;
        !          2604: }
        !          2605: 
        !          2606: 
        !          2607: 
        !          2608: 
        !          2609: /************************************************************************
        !          2610: *
        !          2611: *   MyMessageBox
        !          2612: *
        !          2613: *   Displays a message box with the given string.  To simplify matters,
        !          2614: *   the box will always have the same title ("FatPel"), will always
        !          2615: *   have a single button ("Ok"), will always have an exclamation point
        !          2616: *   icon, and will always be application modal.
        !          2617: *
        !          2618: ************************************************************************/
        !          2619: 
        !          2620: VOID
        !          2621: MyMessageBox(hWnd, sz)
        !          2622: HWND hWnd;
        !          2623: PSZ sz;
        !          2624: {
        !          2625:     static char *szTitle = "FatPel Application";
        !          2626: 
        !          2627:     WinMessageBox(HWND_DESKTOP, hWnd, sz, szTitle, NULL,
        !          2628:                  MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
        !          2629: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.